dolibarr 21.0.0-beta
html.form.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13 * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18 * Copyright (C) 2014-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
27 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
28 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 3 of the License, or
32 * (at your option) any later version.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program. If not, see <https://www.gnu.org/licenses/>.
41 */
42
56class Form
57{
61 public $db;
62
66 public $error = '';
67
71 public $errors = array();
72
73 // Some properties used to return data by some methods
75 public $result;
77 public $num;
78
79 // Cache arrays
80 public $cache_types_paiements = array();
81 public $cache_conditions_paiements = array();
82 public $cache_transport_mode = array();
83 public $cache_availability = array();
84 public $cache_demand_reason = array();
85 public $cache_types_fees = array();
86 public $cache_vatrates = array();
87 public $cache_invoice_subtype = array();
88
89
95 public function __construct($db)
96 {
97 $this->db = $db;
98 }
99
116 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
117 {
118 global $langs;
119
120 $ret = '';
121
122 // TODO change for compatibility
123 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
124 if (!empty($perm)) {
125 $tmp = explode(':', $typeofdata);
126 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
127 if ($fieldrequired) {
128 $ret .= '<span class="fieldrequired">';
129 }
130 if ($help) {
131 $ret .= $this->textwithpicto($langs->trans($text), $help);
132 } else {
133 $ret .= $langs->trans($text);
134 }
135 if ($fieldrequired) {
136 $ret .= '</span>';
137 }
138 $ret .= '</div>' . "\n";
139 } else {
140 if ($fieldrequired) {
141 $ret .= '<span class="fieldrequired">';
142 }
143 if ($help) {
144 $ret .= $this->textwithpicto($langs->trans($text), $help);
145 } else {
146 $ret .= $langs->trans($text);
147 }
148 if ($fieldrequired) {
149 $ret .= '</span>';
150 }
151 }
152 } else {
153 if (empty($notabletag) && $perm) {
154 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
155 }
156 if ($fieldrequired) {
157 $ret .= '<span class="fieldrequired">';
158 }
159 if ($help) {
160 $ret .= $this->textwithpicto($langs->trans($text), $help);
161 } else {
162 $ret .= $langs->trans($text);
163 }
164 if ($fieldrequired) {
165 $ret .= '</span>';
166 }
167 if (!empty($notabletag)) {
168 $ret .= ' ';
169 }
170 if (empty($notabletag) && $perm) {
171 $ret .= '</td>';
172 }
173 if (empty($notabletag) && $perm) {
174 $ret .= '<td class="right">';
175 }
176 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
177 $ret .= '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=edit' . $htmlname . '&token=' . newToken() . '&' . $paramid . '=' . $object->id . $moreparam . '">' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . '</a>';
178 }
179 if (!empty($notabletag) && $notabletag == 1) {
180 if ($text) {
181 $ret .= ' : ';
182 } else {
183 $ret .= ' ';
184 }
185 }
186 if (!empty($notabletag) && $notabletag == 3) {
187 $ret .= ' ';
188 }
189 if (empty($notabletag) && $perm) {
190 $ret .= '</td>';
191 }
192 if (empty($notabletag) && $perm) {
193 $ret .= '</tr></table>';
194 }
195 }
196
197 return $ret;
198 }
199
223 public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '')
224 {
225 global $conf, $langs;
226
227 $ret = '';
228
229 // Check parameters
230 if (empty($typeofdata)) {
231 return 'ErrorBadParameter typeofdata is empty';
232 }
233 // Clean parameter $typeofdata
234 if ($typeofdata == 'datetime') {
235 $typeofdata = 'dayhour';
236 }
237 $reg = array();
238 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
239 if ($reg[1] == 'varchar') {
240 $typeofdata = 'string';
241 } elseif ($reg[1] == 'int') {
242 $typeofdata = 'numeric';
243 } else {
244 return 'ErrorBadParameter ' . $typeofdata;
245 }
246 }
247
248 // When option to edit inline is activated
249 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
250 $ret .= $this->editInPlace($object, $value, $htmlname, ($perm ? 1 : 0), $typeofdata, $editvalue, $extObject, $custommsg);
251 } else {
252 if ($editaction == '') {
253 $editaction = GETPOST('action', 'aZ09');
254 }
255 $editmode = ($editaction == 'edit' . $htmlname);
256 if ($editmode) { // edit mode
257 $ret .= "<!-- formeditfieldval -->\n";
258 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
259 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
260 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
261 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
262 if (empty($notabletag)) {
263 $ret .= '<table class="nobordernopadding centpercent">';
264 }
265 if (empty($notabletag)) {
266 $ret .= '<tr><td>';
267 }
268 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
269 $tmp = explode(':', $typeofdata);
270 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
271 } elseif (preg_match('/^(integer)/', $typeofdata)) {
272 $tmp = explode(':', $typeofdata);
273 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
274 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
275 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
276 $tmp = explode(':', $typeofdata);
277 $valuetoshow = price2num($editvalue ? $editvalue : $value);
278 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
279 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
280 $tmp = explode(':', $typeofdata);
281 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
282 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
283 $tmp = explode(':', $typeofdata);
284 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
285 $morealt = '';
286 if (preg_match('/%/', $cols)) {
287 $morealt = ' style="width: ' . $cols . '"';
288 $cols = '';
289 }
290 $valuetoshow = ($editvalue ? $editvalue : $value);
291 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
292 // textarea convert automatically entities chars into simple chars.
293 // So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwyg is off.
294 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
295 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
296 $ret .= '</textarea><div class="clearboth"></div>';
297 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
298 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
299 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
300 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
301 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
302 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
303 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
304 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
305 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
306 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
307 } elseif (preg_match('/^select;/', $typeofdata)) {
308 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
309 $arraylist = array();
310 foreach ($arraydata as $val) {
311 $tmp = explode(':', $val);
312 $tmpkey = str_replace('|', ':', $tmp[0]);
313 $arraylist[$tmpkey] = $tmp[1];
314 }
315 $ret .= $this->selectarray($htmlname, $arraylist, $value);
316 } elseif (preg_match('/^link/', $typeofdata)) {
317 // TODO Not yet implemented. See code for extrafields
318 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
319 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
320 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
321 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? 100 : (int) $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? false : (bool) $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? 20 : (int) $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
322 $ret .= $doleditor->Create(1);
323 } elseif ($typeofdata == 'asis') {
324 $ret .= ($editvalue ? $editvalue : $value);
325 }
326 if (empty($notabletag)) {
327 $ret .= '</td>';
328 }
329
330 // Button save-cancel
331 if (empty($notabletag)) {
332 $ret .= '<td>';
333 }
334 //else $ret.='<div class="clearboth"></div>';
335 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
336 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
337 $ret .= '<br>' . "\n";
338 }
339 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
340 if (empty($notabletag)) {
341 $ret .= '</td>';
342 }
343
344 if (empty($notabletag)) {
345 $ret .= '</tr></table>' . "\n";
346 }
347 $ret .= '</form>' . "\n";
348 } else { // view mode
349 if (preg_match('/^email/', $typeofdata)) {
350 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
351 } elseif (preg_match('/^phone/', $typeofdata)) {
352 $ret .= dol_print_phone($value, '_blank', 32, 1);
353 } elseif (preg_match('/^url/', $typeofdata)) {
354 $ret .= dol_print_url($value, '_blank', 32, 1);
355 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
356 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
357 } elseif (preg_match('/^checkbox/', $typeofdata)) {
358 $tmp = explode(':', $typeofdata);
359 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
360 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
362 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
364 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
365 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
366 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
367 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
368 } elseif (preg_match('/^select;/', $typeofdata)) {
369 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
370 $arraylist = array();
371 foreach ($arraydata as $val) {
372 $tmp = explode(':', $val);
373 $arraylist[$tmp[0]] = $tmp[1];
374 }
375 $ret .= $arraylist[$value];
376 if ($htmlname == 'fk_product_type') {
377 if ($value == 0) {
378 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
379 } else {
380 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
381 }
382 }
383 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
384 $tmpcontent = dol_htmlentitiesbr($value);
385 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
386 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
387 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
388 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
389 }
390 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
391 // clean data from some dangerous html
393 } else {
394 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
395 $ret .= dol_escape_htmltag($value);
396 } else {
397 $ret .= $value; // $value must be already html escaped.
398 }
399 }
400
401 // Custom format if parameter $formatfunc has been provided
402 if ($formatfunc && method_exists($object, $formatfunc)) {
403 $ret = $object->$formatfunc($ret);
404 }
405 }
406 }
407 return $ret;
408 }
409
421 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
422 {
423 global $conf, $langs, $extralanguages;
424
425 $result = '';
426
427 // List of extra languages
428 $arrayoflangcode = array();
429 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
430 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
431 }
432
433 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
434 if (!is_object($extralanguages)) {
435 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
436 $extralanguages = new ExtraLanguages($this->db);
437 }
438 $extralanguages->fetch_name_extralanguages('societe');
439
440 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
441 return ''; // No extralang field to show
442 }
443
444 $result .= '<!-- Widget for translation -->' . "\n";
445 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
446 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', 0, 0, 0, '', 'fa-15 editfieldlang');
447 $result .= $s;
448 $result .= '</div>';
449
450 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
451
452 $resultforextrlang = '';
453 foreach ($arrayoflangcode as $langcode) {
454 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
455 if (empty($valuetoshow)) {
456 $object->fetchValuesForExtraLanguages();
457 //var_dump($object->array_languages);
458 $valuetoshow = $object->array_languages[$fieldname][$langcode];
459 }
460
461 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
462 $resultforextrlang .= $s;
463
464 // TODO Use the showInputField() method of ExtraLanguages object
465 if ($typeofdata == 'textarea') {
466 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
467 $resultforextrlang .= $valuetoshow;
468 $resultforextrlang .= '</textarea>';
469 } else {
470 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
471 }
472 }
473 $result .= $resultforextrlang;
474
475 $result .= '</div>';
476 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
477 }
478
479 return $result;
480 }
481
495 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
496 {
497 $out = '';
498
499 // Check parameters
500 if (preg_match('/^text/', $inputType)) {
501 $value = dol_nl2br($value);
502 } elseif (preg_match('/^numeric/', $inputType)) {
503 $value = price($value);
504 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
505 $value = dol_print_date($value, 'day');
506 }
507
508 if ($condition) {
509 $element = false;
510 $table_element = false;
511 $fk_element = false;
512 $loadmethod = false;
513 $savemethod = false;
514 $ext_element = false;
515 $button_only = false;
516 $inputOption = '';
517 $rows = '';
518 $cols = '';
519
520 if (is_object($object)) {
521 $element = $object->element;
522 $table_element = $object->table_element;
523 $fk_element = $object->id;
524 }
525
526 if (is_object($extObject)) {
527 $ext_element = $extObject->element;
528 }
529
530 if (preg_match('/^(string|email|numeric)/', $inputType)) {
531 $tmp = explode(':', $inputType);
532 $inputType = $tmp[0];
533 if (!empty($tmp[1])) {
534 $inputOption = $tmp[1];
535 }
536 if (!empty($tmp[2])) {
537 $savemethod = $tmp[2];
538 }
539 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
540 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
541 $tmp = explode(':', $inputType);
542 $inputType = $tmp[0];
543 if (!empty($tmp[1])) {
544 $inputOption = $tmp[1];
545 }
546 if (!empty($tmp[2])) {
547 $savemethod = $tmp[2];
548 }
549
550 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
551 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
552 $tmp = explode(':', $inputType);
553 $inputType = $tmp[0];
554 $loadmethod = $tmp[1];
555 if (!empty($tmp[2])) {
556 $savemethod = $tmp[2];
557 }
558 if (!empty($tmp[3])) {
559 $button_only = true;
560 }
561 } elseif (preg_match('/^textarea/', $inputType)) {
562 $tmp = explode(':', $inputType);
563 $inputType = $tmp[0];
564 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
565 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
566 } elseif (preg_match('/^ckeditor/', $inputType)) {
567 $tmp = explode(':', $inputType);
568 $inputType = $tmp[0];
569 $toolbar = $tmp[1];
570 if (!empty($tmp[2])) {
571 $width = $tmp[2];
572 }
573 if (!empty($tmp[3])) {
574 $height = $tmp[3];
575 }
576 if (!empty($tmp[4])) {
577 $savemethod = $tmp[4];
578 }
579
580 if (isModEnabled('fckeditor')) {
581 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
582 } else {
583 $inputType = 'textarea';
584 }
585 }
586
587 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
588 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
589 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
590 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
591 if (!empty($savemethod)) {
592 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
593 }
594 if (!empty($ext_element)) {
595 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
596 }
597 if (!empty($custommsg)) {
598 if (is_array($custommsg)) {
599 if (!empty($custommsg['success'])) {
600 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
601 }
602 if (!empty($custommsg['error'])) {
603 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
604 }
605 } else {
606 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
607 }
608 }
609 if ($inputType == 'textarea') {
610 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
611 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
612 }
613 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
614 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
615 } else {
616 $out = $value;
617 }
618
619 return $out;
620 }
621
640 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
641 {
642 if ($incbefore) {
643 $text = $incbefore . $text;
644 }
645 if (!$htmltext) {
646 return $text;
647 }
648 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
649
650 $tag = 'td';
651 if ($notabs == 2) {
652 $tag = 'div';
653 }
654 if ($notabs == 3) {
655 $tag = 'span';
656 }
657 // Sanitize tooltip
658 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
659
660 $extrastyle = '';
661 if ($direction < 0) {
662 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
663 $extrastyle = 'padding: 0px; padding-left: 2px;';
664 }
665 if ($direction > 0) {
666 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
667 $extrastyle = 'padding: 0px; padding-right: 2px;';
668 }
669
670 $classfortooltip = 'classfortooltip';
671
672 $s = '';
673 $textfordialog = '';
674
675 if ($tooltiptrigger == '') {
676 $htmltext = str_replace('"', '&quot;', $htmltext);
677 } else {
678 $classfortooltip = 'classfortooltiponclick';
679 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
680 }
681 if ($tooltipon == 2 || $tooltipon == 3) {
682 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
683 if ($tooltiptrigger == '') {
684 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
685 } else {
686 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
687 }
688 } else {
689 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
690 }
691 if ($tooltipon == 1 || $tooltipon == 3) {
692 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ($tag != 'td' ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
693 if ($tooltiptrigger == '') {
694 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
695 } else {
696 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
697 }
698 } else {
699 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
700 }
701 if (empty($notabs)) {
702 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
703 } elseif ($notabs == 2) {
704 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
705 }
706 // Define value if value is before
707 if ($direction < 0) {
708 $s .= '<' . $tag . $paramfortooltipimg;
709 if ($tag == 'td') {
710 $s .= ' class="valigntop" width="14"';
711 }
712 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
713 }
714 // Use another method to help avoid having a space in value in order to use this value with jquery
715 // Define label
716 if ((string) $text != '') {
717 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
718 }
719 // Define value if value is after
720 if ($direction > 0) {
721 $s .= '<' . $tag . $paramfortooltipimg;
722 if ($tag == 'td') {
723 $s .= ' class="valignmiddle" width="14"';
724 }
725 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
726 }
727 if (empty($notabs)) {
728 $s .= '</tr></table>';
729 } elseif ($notabs == 2) {
730 $s .= '</div>';
731 }
732
733 return $s;
734 }
735
750 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = 'valignmiddle', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
751 {
752 global $conf, $langs;
753
754 //For backwards compatibility
755 if ($type == '0') {
756 $type = 'info';
757 } elseif ($type == '1') {
758 $type = 'help';
759 }
760 // Clean parameters
761 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
762
763 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
764 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
765 }
766 $alt = '';
767 if ($tooltiptrigger) {
768 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
769 }
770
771 // If info or help with no javascript, show only text
772 if (empty($conf->use_javascript_ajax)) {
773 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
774 return $text;
775 } else {
776 $alt = $htmltext;
777 $htmltext = '';
778 }
779 }
780
781 // If info or help with smartphone, show only text (tooltip hover can't works)
782 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
783 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
784 return $text;
785 }
786 }
787 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
788 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
789 //{
790 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
791 //}
792
793 $img = '';
794 if ($type == 'info') {
795 $img = img_help(0, $alt);
796 } elseif ($type == 'help') {
797 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
798 } elseif ($type == 'helpclickable') {
799 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
800 } elseif ($type == 'superadmin') {
801 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
802 $img = img_picto($alt, 'redstar');
803 } elseif ($type == 'admin') {
804 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
805 $img = img_picto($alt, 'star');
806 } elseif ($type == 'warning') {
807 $img = img_warning($alt);
808 } elseif ($type != 'none') {
809 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
810 $img = img_picto($alt, $type); // $type can be an image path
811 }
812
813 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
814 }
815
826 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
827 {
828 global $conf, $langs, $hookmanager;
829
830 $disabled = 0;
831 $ret = '<div class="centpercent center">';
832 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
833
834 // Complete list with data from external modules. THe module can use $_SERVER['PHP_SELF'] to know on which page we are, or use the $parameters['currentcontext'] completed by executeHooks.
835 $parameters = array();
836 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
837 // check if there is a mass action
838
839 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
840 return;
841 }
842 if (empty($reshook)) {
843 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
844 if (is_array($arrayofaction)) {
845 foreach ($arrayofaction as $code => $label) {
846 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
847 }
848 }
849 }
850 $ret .= $hookmanager->resPrint;
851
852 $ret .= '</select>';
853
854 if (empty($conf->dol_optimize_smallscreen)) {
855 $ret .= ajax_combobox('.' . $name . 'select');
856 }
857
858 // Warning: if you set submit button to disabled, post using 'Enter' will no more work if there is no another input submit. So we add a hidden button
859 $ret .= '<input type="submit" name="confirmmassactioninvisible" style="display: none" tabindex="-1">'; // Hidden button BEFORE so it is the one used when we submit with ENTER.
860 $ret .= '<input type="submit" disabled name="confirmmassaction"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display: none"') . ' class="reposition button smallpaddingimp' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'confirmed" value="' . dol_escape_htmltag($langs->trans("Confirm")) . '">';
861 $ret .= '</div>';
862
863 if (!empty($conf->use_javascript_ajax)) {
864 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
865 <script nonce="' . getNonce() . '">
866 function initCheckForSelect(mode, name, cssclass) /* mode is 0 during init of page or click all, 1 when we click on 1 checkboxi, "name" refers to the class of the massaction button, "cssclass" to the class of the checkfor select boxes */
867 {
868 atleastoneselected=0;
869 jQuery("."+cssclass).each(function( index ) {
870 /* console.log( index + ": " + $( this ).text() ); */
871 if ($(this).is(\':checked\')) atleastoneselected++;
872 });
873
874 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
875
876 if (atleastoneselected || ' . $alwaysvisible . ')
877 {
878 jQuery("."+name).show();
879 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
880 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
881 }
882 else
883 {
884 jQuery("."+name).hide();
885 jQuery("."+name+"other").hide();
886 }
887 }
888
889 jQuery(document).ready(function () {
890 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
891 jQuery(".' . $cssclass . '").click(function() {
892 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
893 });
894 jQuery(".' . $name . 'select").change(function() {
895 var massaction = $( this ).val();
896 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
897 if (massaction == "builddoc") {
898 urlform = urlform + "#show_files";
899 }
900 $( this ).closest("form").attr("action", urlform);
901 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
902 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
903 if ($(this).val() != \'0\') {
904 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
905 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
906 jQuery(".' . $name . '"+massaction).show();
907 } else {
908 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
909 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
910 }
911 });
912 });
913 </script>
914 ';
915 }
916
917 return $ret;
918 }
919
920 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
921
938 public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0)
939 {
940 // phpcs:enable
941 global $conf, $langs, $mysoc;
942
943 $langs->load("dict");
944
945 $out = '';
946 $countryArray = array();
947 $favorite = array();
948 $label = array();
949 $atleastonefavorite = 0;
950
951 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
952 $sql .= " FROM " . $this->db->prefix() . "c_country";
953 $sql .= " WHERE active > 0";
954 //$sql.= " ORDER BY code ASC";
955
956 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
957 $resql = $this->db->query($sql);
958 if ($resql) {
959 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
960 $num = $this->db->num_rows($resql);
961 $i = 0;
962 if ($num) {
963 while ($i < $num) {
964 $obj = $this->db->fetch_object($resql);
965
966 $countryArray[$i]['rowid'] = $obj->rowid;
967 $countryArray[$i]['code_iso'] = $obj->code_iso;
968 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
969 $countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
970 $countryArray[$i]['favorite'] = $obj->favorite;
971 $countryArray[$i]['eec'] = $obj->eec;
972 $favorite[$i] = $obj->favorite;
973 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
974 $i++;
975 }
976
977 if (empty($disablefavorites)) {
978 $array1_sort_order = SORT_DESC;
979 $array2_sort_order = SORT_ASC;
980 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
981 } else {
982 $countryArray = dol_sort_array($countryArray, 'label');
983 }
984
985 if ($showempty) {
986 if (is_numeric($showempty)) {
987 $out .= '<option value="">&nbsp;</option>' . "\n";
988 } else {
989 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
990 }
991 }
992
993 if ($addspecialentries) { // Add dedicated entries for groups of countries
994 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
995 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
996 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
997 if ($mysoc->isInEEC()) {
998 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
999 }
1000 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1001 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1002 }
1003
1004 foreach ($countryArray as $row) {
1005 //if (empty($showempty) && empty($row['rowid'])) continue;
1006 if (empty($row['rowid'])) {
1007 continue;
1008 }
1009 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1010 continue; // exclude some countries
1011 }
1012
1013 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1014 $atleastonefavorite++;
1015 }
1016 if (empty($row['favorite']) && $atleastonefavorite) {
1017 $atleastonefavorite = 0;
1018 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1019 }
1020
1021 $labeltoshow = '';
1022 if ($row['label']) {
1023 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1024 } else {
1025 $labeltoshow .= '&nbsp;';
1026 }
1027 if ($row['code_iso']) {
1028 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1029 if (empty($hideflags)) {
1030 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1031 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1032 }
1033 }
1034
1035 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1036 $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1037 } else {
1038 $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1039 }
1040 $out .= $labeltoshow;
1041 $out .= '</option>' . "\n";
1042 }
1043 }
1044 $out .= '</select>';
1045 } else {
1046 dol_print_error($this->db);
1047 }
1048
1049 // Make select dynamic
1050 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1051 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1052
1053 return $out;
1054 }
1055
1056 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1057
1071 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1072 {
1073 // phpcs:enable
1074 global $conf, $langs;
1075
1076 $langs->load("dict");
1077
1078 $out = '';
1079 $moreattrib = '';
1080 $incotermArray = array();
1081
1082 $sql = "SELECT rowid, code";
1083 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1084 $sql .= " WHERE active > 0";
1085 $sql .= " ORDER BY code ASC";
1086
1087 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1088 $resql = $this->db->query($sql);
1089 if ($resql) {
1090 if ($conf->use_javascript_ajax && !$forcecombo) {
1091 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1092 $out .= ajax_combobox($htmlname, $events);
1093 }
1094
1095 if (!empty($page)) {
1096 $out .= '<form method="post" action="' . $page . '">';
1097 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1098 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1099 }
1100
1101 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1102 $out .= '<option value="0">&nbsp;</option>';
1103 $num = $this->db->num_rows($resql);
1104 $i = 0;
1105 if ($num) {
1106 while ($i < $num) {
1107 $obj = $this->db->fetch_object($resql);
1108 $incotermArray[$i]['rowid'] = $obj->rowid;
1109 $incotermArray[$i]['code'] = $obj->code;
1110 $i++;
1111 }
1112
1113 foreach ($incotermArray as $row) {
1114 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1115 $out .= '<option value="' . $row['rowid'] . '" selected>';
1116 } else {
1117 $out .= '<option value="' . $row['rowid'] . '">';
1118 }
1119
1120 if ($row['code']) {
1121 $out .= $row['code'];
1122 }
1123
1124 $out .= '</option>';
1125 }
1126 }
1127 $out .= '</select>';
1128 $out .= ajax_combobox($htmlname);
1129
1130 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1131 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1132 $moreattrib .= ' autocomplete="off"';
1133 }
1134 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1135
1136 if (!empty($page)) {
1137 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1138 }
1139 } else {
1140 dol_print_error($this->db);
1141 }
1142
1143 return $out;
1144 }
1145
1146 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1147
1161 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "", $useajaxcombo = 1)
1162 {
1163 // phpcs:enable
1164 global $langs;
1165
1166 // If product & services are enabled or both disabled.
1167 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1168 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1169 if (empty($hidetext)) {
1170 print $langs->trans("Type").'...';
1171 }
1172 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1173 if ($showempty) {
1174 print '<option value="-1" class="opacitymedium"'.($useajaxcombo ? '' : ' disabled="disabled"');
1175 if ($selected == -1) {
1176 print ' selected';
1177 }
1178 print '>';
1179 if (is_numeric($showempty)) {
1180 print '&nbsp;';
1181 } else {
1182 print $showempty;
1183 }
1184 print '</option>';
1185 }
1186
1187 print '<option value="0"';
1188 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1189 print ' selected';
1190 }
1191 print '>' . $langs->trans("Product");
1192
1193 print '<option value="1"';
1194 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1195 print ' selected';
1196 }
1197 print '>' . $langs->trans("Service");
1198
1199 print '</select>';
1200
1201 if ($useajaxcombo) {
1202 print ajax_combobox('select_' . $htmlname);
1203 }
1204 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1205 }
1206 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1207 print $langs->trans("Service");
1208 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1209 }
1210 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1211 print $langs->trans("Product");
1212 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1213 }
1214 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1215 print '<input type="hidden" name="' . $htmlname . '" value="1">'; // By default we set on service for contract. If CONTRACT_SUPPORT_PRODUCTS is set, forceall should be 1 not -1
1216 }
1217 }
1218
1219 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1220
1226 public function load_cache_types_fees()
1227 {
1228 // phpcs:enable
1229 global $langs;
1230
1231 $num = count($this->cache_types_fees);
1232 if ($num > 0) {
1233 return 0; // Cache already loaded
1234 }
1235
1236 dol_syslog(__METHOD__, LOG_DEBUG);
1237
1238 $langs->load("trips");
1239
1240 $sql = "SELECT c.code, c.label";
1241 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1242 $sql .= " WHERE active > 0";
1243
1244 $resql = $this->db->query($sql);
1245 if ($resql) {
1246 $num = $this->db->num_rows($resql);
1247 $i = 0;
1248
1249 while ($i < $num) {
1250 $obj = $this->db->fetch_object($resql);
1251
1252 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1253 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1254 $this->cache_types_fees[$obj->code] = $label;
1255 $i++;
1256 }
1257
1258 asort($this->cache_types_fees);
1259
1260 return $num;
1261 } else {
1262 dol_print_error($this->db);
1263 return -1;
1264 }
1265 }
1266
1267 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1268
1277 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1278 {
1279 // phpcs:enable
1280 global $user, $langs;
1281
1282 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1283
1284 $this->load_cache_types_fees();
1285
1286 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1287 if ($showempty) {
1288 print '<option value="-1"';
1289 if ($selected == -1) {
1290 print ' selected';
1291 }
1292 print '>&nbsp;</option>';
1293 }
1294
1295 foreach ($this->cache_types_fees as $key => $value) {
1296 print '<option value="' . $key . '"';
1297 if ($key == $selected) {
1298 print ' selected';
1299 }
1300 print '>';
1301 print $value;
1302 print '</option>';
1303 }
1304
1305 print '</select>';
1306 if ($user->admin) {
1307 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1308 }
1309 }
1310
1311
1312 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1313
1336 public function select_company($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $limit = 0, $morecss = 'minwidth100', $moreparam = '', $selected_input_value = '', $hidelabel = 1, $ajaxoptions = array(), $multiple = false, $excludeids = array(), $showcode = 0)
1337 {
1338 // phpcs:enable
1339 global $conf, $langs;
1340
1341 $out = '';
1342
1343 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1344 if (is_null($ajaxoptions)) {
1345 $ajaxoptions = array();
1346 }
1347
1348 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1349
1350 // No immediate load of all database
1351 $placeholder = '';
1352 if ($selected && empty($selected_input_value)) {
1353 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1354 $societetmp = new Societe($this->db);
1355 $societetmp->fetch($selected);
1356 $selected_input_value = $societetmp->name;
1357 unset($societetmp);
1358 }
1359
1360 // mode 1
1361 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($excludeids) ? '' : '&excludeids=' . implode(',', $excludeids)) . ($showtype ? '&showtype=' . urlencode((string) ($showtype)) : '') . ($showcode ? '&showcode=' . urlencode((string) ($showcode)) : '');
1362
1363 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1364 if (empty($hidelabel)) {
1365 $out .= $langs->trans("RefOrLabel") . ' : ';
1366 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1367 $placeholder = $langs->trans($showempty);
1368 } elseif ($hidelabel > 1) {
1369 $placeholder = $langs->trans("RefOrLabel");
1370 if ($hidelabel == 2) {
1371 $out .= img_picto($langs->trans("Search"), 'search');
1372 }
1373 }
1374 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('THIRDPARTY_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1375 if ($hidelabel == 3) {
1376 $out .= img_picto($langs->trans("Search"), 'search');
1377 }
1378
1379 $out .= ajax_event($htmlname, $events);
1380
1381 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1382 } else {
1383 // Immediate load of all database
1384 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1385 }
1386
1387 return $out;
1388 }
1389
1390
1391 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1392
1418 public function select_contact($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $nokeyifsocid = true, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $selected_input_value = '', $filter = '')
1419 {
1420 // phpcs:enable
1421
1422 global $conf, $langs;
1423
1424 $out = '';
1425
1426 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1427 if ($nokeyifsocid && $socid > 0) {
1428 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1429 }
1430
1431 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1432 if (is_null($events)) {
1433 $events = array();
1434 }
1435
1436 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1437
1438 // No immediate load of all database
1439 $placeholder = '';
1440 if ($selected && empty($selected_input_value)) {
1441 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1442 $contacttmp = new Contact($this->db);
1443 $contacttmp->fetch($selected);
1444 $selected_input_value = $contacttmp->getFullName($langs);
1445 unset($contacttmp);
1446 }
1447 if (!is_numeric($showempty)) {
1448 $placeholder = $showempty;
1449 }
1450
1451 // mode 1
1452 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1453
1454 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1455
1456 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('CONTACT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1457
1458 $out .= ajax_event($htmlname, $events);
1459
1460 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1461 } else {
1462 // Immediate load of all database
1463 $multiple = false;
1464 $disableifempty = 0;
1465 $options_only = 0;
1466 $limitto = '';
1467
1468 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1469 }
1470
1471 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1472
1473 return $out;
1474 }
1475
1476
1477 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1478
1503 public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false, $excludeids = array(), $showcode = 0)
1504 {
1505 // phpcs:enable
1506 global $user, $langs;
1507 global $hookmanager;
1508
1509 $langs->loadLangs(array("companies", "suppliers"));
1510
1511 $out = '';
1512 $num = 0;
1513 $outarray = array();
1514
1515 if ($selected === '') {
1516 $selected = array();
1517 } elseif (!is_array($selected)) {
1518 $selected = array($selected);
1519 }
1520
1521 // Clean $filter that may contains sql conditions so sql code
1522 if (function_exists('testSqlAndScriptInject')) {
1523 if (testSqlAndScriptInject($filter, 3) > 0) {
1524 $filter = '';
1525 return 'SQLInjectionTryDetected';
1526 }
1527 }
1528
1529 if ($filter != '') { // If a filter was provided
1530 if (preg_match('/[\‍(\‍)]/', $filter)) {
1531 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1532 $errormsg = '';
1533 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1534
1535 // Redo clean $filter that may contains sql conditions so sql code
1536 if (function_exists('testSqlAndScriptInject')) {
1537 if (testSqlAndScriptInject($filter, 3) > 0) {
1538 $filter = '';
1539 return 'SQLInjectionTryDetected';
1540 }
1541 }
1542 } else {
1543 // If not, we do nothing. We already know that there is no parenthesis
1544 // TODO Disallow this case in a future.
1545 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1546 }
1547 }
1548
1549 // We search companies
1550 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1551 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1552 $sql .= ", s.address, s.zip, s.town";
1553 $sql .= ", dictp.code as country_code";
1554 }
1555 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1556 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1557 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1558 }
1559 if (!$user->hasRight('societe', 'client', 'voir')) {
1560 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1561 }
1562 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1563 if (!empty($user->socid)) {
1564 $sql .= " AND s.rowid = " . ((int) $user->socid);
1565 }
1566 if ($filter) {
1567 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1568 // if not, by testSqlAndScriptInject() only.
1569 $sql .= " AND (" . $filter . ")";
1570 }
1571 if (!$user->hasRight('societe', 'client', 'voir')) {
1572 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1573 }
1574 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1575 $sql .= " AND s.status <> 0";
1576 }
1577 if (!empty($excludeids)) {
1578 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1579 }
1580 // Add where from hooks
1581 $parameters = array();
1582 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1583 $sql .= $hookmanager->resPrint;
1584 // Add criteria
1585 if ($filterkey && $filterkey != '') {
1586 $sql .= " AND (";
1587 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1588 // For natural search
1589 $search_crit = explode(' ', $filterkey);
1590 $i = 0;
1591 if (count($search_crit) > 1) {
1592 $sql .= "(";
1593 }
1594 foreach ($search_crit as $crit) {
1595 if ($i > 0) {
1596 $sql .= " AND ";
1597 }
1598 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1599 $i++;
1600 }
1601 if (count($search_crit) > 1) {
1602 $sql .= ")";
1603 }
1604 if (isModEnabled('barcode')) {
1605 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1606 }
1607 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1608 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1609 $sql .= ")";
1610 }
1611 $sql .= $this->db->order("nom", "ASC");
1612 $sql .= $this->db->plimit($limit, 0);
1613
1614 // Build output string
1615 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1616 $resql = $this->db->query($sql);
1617 if ($resql) {
1618 // Construct $out and $outarray
1619 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1620
1621 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1622 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1623 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1624 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1625 if ($showempty && !is_numeric($showempty)) {
1626 $textifempty = $langs->trans($showempty);
1627 } else {
1628 $textifempty .= $langs->trans("All");
1629 }
1630 }
1631 if ($showempty) {
1632 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1633 }
1634
1635 $companytemp = new Societe($this->db);
1636
1637 $num = $this->db->num_rows($resql);
1638 $i = 0;
1639 if ($num) {
1640 while ($i < $num) {
1641 $obj = $this->db->fetch_object($resql);
1642 $label = '';
1643 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1644 if (($obj->client) && (!empty($obj->code_client))) {
1645 $label = $obj->code_client . ' - ';
1646 }
1647 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1648 $label .= $obj->code_fournisseur . ' - ';
1649 }
1650 $label .= ' ' . $obj->name;
1651 } else {
1652 $label = $obj->name;
1653 }
1654
1655 if (!empty($obj->name_alias)) {
1656 $label .= ' (' . $obj->name_alias . ')';
1657 }
1658
1659 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1660 $label .= ' - '.$obj->tva_intra;
1661 }
1662
1663 $labelhtml = $label;
1664
1665 if ($showtype) {
1666 $companytemp->id = $obj->rowid;
1667 $companytemp->client = $obj->client;
1668 $companytemp->fournisseur = $obj->fournisseur;
1669 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1670 if ($tmptype) {
1671 $labelhtml .= ' ' . $tmptype;
1672 }
1673
1674 if ($obj->client || $obj->fournisseur) {
1675 $label .= ' (';
1676 }
1677 if ($obj->client == 1 || $obj->client == 3) {
1678 $label .= $langs->trans("Customer");
1679 }
1680 if ($obj->client == 2 || $obj->client == 3) {
1681 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1682 }
1683 if ($obj->fournisseur) {
1684 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1685 }
1686 if ($obj->client || $obj->fournisseur) {
1687 $label .= ')';
1688 }
1689 }
1690
1691 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1692 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1693 if (!empty($obj->country_code)) {
1694 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1695 }
1696 $label .= $s;
1697 $labelhtml .= $s;
1698 }
1699
1700 if (empty($outputmode)) {
1701 if (in_array($obj->rowid, $selected)) {
1702 $out .= '<option value="' . $obj->rowid . '" selected data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1703 } else {
1704 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1705 }
1706 } else {
1707 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1708 }
1709
1710 $i++;
1711 if (($i % 10) == 0) {
1712 $out .= "\n";
1713 }
1714 }
1715 }
1716 $out .= '</select>' . "\n";
1717 if (!$forcecombo) {
1718 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1719 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1720 }
1721 } else {
1722 dol_print_error($this->db);
1723 }
1724
1725 $this->result = array('nbofthirdparties' => $num);
1726
1727 if ($outputmode) {
1728 return $outarray;
1729 }
1730 return $out;
1731 }
1732
1733
1759 public function selectcontacts($socid, $selected = array(), $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = 0, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0, $filter = '')
1760 {
1761 global $conf, $user, $langs, $hookmanager, $action;
1762
1763 $langs->load('companies');
1764
1765 if (empty($htmlid)) {
1766 $htmlid = $htmlname;
1767 }
1768 $num = 0;
1769 $out = '';
1770 $outarray = array();
1771
1772 if ($selected === '') {
1773 $selected = array();
1774 } elseif (!is_array($selected)) {
1775 $selected = array((int) $selected);
1776 }
1777
1778 // Clean $filter that may contains sql conditions so sql code
1779 if (function_exists('testSqlAndScriptInject')) {
1780 if (testSqlAndScriptInject($filter, 3) > 0) {
1781 $filter = '';
1782 return 'SQLInjectionTryDetected';
1783 }
1784 }
1785
1786 if ($filter != '') { // If a filter was provided
1787 if (preg_match('/[\‍(\‍)]/', $filter)) {
1788 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1789 $errormsg = '';
1790 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1791
1792 // Redo clean $filter that may contains sql conditions so sql code
1793 if (function_exists('testSqlAndScriptInject')) {
1794 if (testSqlAndScriptInject($filter, 3) > 0) {
1795 $filter = '';
1796 return 'SQLInjectionTryDetected';
1797 }
1798 }
1799 } else {
1800 // If not, we do nothing. We already know that there is no parenthesis
1801 // TODO Disallow this case in a future by returning an error here.
1802 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1803 }
1804 }
1805
1806 if (!is_object($hookmanager)) {
1807 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1808 $hookmanager = new HookManager($this->db);
1809 }
1810
1811 // We search third parties
1812 $sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste, sp.email, sp.phone, sp.phone_perso, sp.phone_mobile, sp.town AS contact_town";
1813 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1814 $sql .= ", s.nom as company, s.town AS company_town";
1815 }
1816 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1817 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1818 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1819 }
1820 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1821 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1822 if ($socid > 0 || $socid == -1) {
1823 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1824 }
1825 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1826 $sql .= " AND sp.statut <> 0";
1827 }
1828 if ($filter) {
1829 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1830 // if not, by testSqlAndScriptInject() only.
1831 $sql .= " AND (" . $filter . ")";
1832 }
1833 // Add where from hooks
1834 $parameters = array();
1835 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1836 $sql .= $hookmanager->resPrint;
1837 $sql .= " ORDER BY sp.lastname ASC";
1838
1839 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1840 $resql = $this->db->query($sql);
1841 if ($resql) {
1842 $num = $this->db->num_rows($resql);
1843
1844 if ($htmlname != 'none' && !$options_only) {
1845 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1846 }
1847
1848 if ($showempty && !is_numeric($showempty)) {
1849 $textforempty = $showempty;
1850 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1851 } else {
1852 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1853 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1854 }
1855 if ($showempty == 2) {
1856 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1857 }
1858 }
1859
1860 $i = 0;
1861 if ($num) {
1862 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1863 $contactstatic = new Contact($this->db);
1864
1865 while ($i < $num) {
1866 $obj = $this->db->fetch_object($resql);
1867
1868 // Set email (or phones) and town extended infos
1869 $extendedInfos = '';
1870 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1871 $extendedInfos = array();
1872 $email = trim($obj->email);
1873 if (!empty($email)) {
1874 $extendedInfos[] = $email;
1875 } else {
1876 $phone = trim($obj->phone);
1877 $phone_perso = trim($obj->phone_perso);
1878 $phone_mobile = trim($obj->phone_mobile);
1879 if (!empty($phone)) {
1880 $extendedInfos[] = $phone;
1881 }
1882 if (!empty($phone_perso)) {
1883 $extendedInfos[] = $phone_perso;
1884 }
1885 if (!empty($phone_mobile)) {
1886 $extendedInfos[] = $phone_mobile;
1887 }
1888 }
1889 $contact_town = trim($obj->contact_town);
1890 $company_town = trim($obj->company_town);
1891 if (!empty($contact_town)) {
1892 $extendedInfos[] = $contact_town;
1893 } elseif (!empty($company_town)) {
1894 $extendedInfos[] = $company_town;
1895 }
1896 $extendedInfos = implode(' - ', $extendedInfos);
1897 if (!empty($extendedInfos)) {
1898 $extendedInfos = ' - ' . $extendedInfos;
1899 }
1900 }
1901
1902 $contactstatic->id = $obj->rowid;
1903 $contactstatic->lastname = $obj->lastname;
1904 $contactstatic->firstname = $obj->firstname;
1905 if ($obj->statut == 1) {
1906 $tmplabel = '';
1907 if ($htmlname != 'none') {
1908 $disabled = 0;
1909 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1910 $disabled = 1;
1911 }
1912 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1913 $disabled = 1;
1914 }
1915 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1916 $out .= '<option value="' . $obj->rowid . '"';
1917 if ($disabled) {
1918 $out .= ' disabled';
1919 }
1920 $out .= ' selected>';
1921
1922 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1923 if ($showfunction && $obj->poste) {
1924 $tmplabel .= ' (' . $obj->poste . ')';
1925 }
1926 if (($showsoc > 0) && $obj->company) {
1927 $tmplabel .= ' - (' . $obj->company . ')';
1928 }
1929
1930 $out .= $tmplabel;
1931 $out .= '</option>';
1932 } else {
1933 $out .= '<option value="' . $obj->rowid . '"';
1934 if ($disabled) {
1935 $out .= ' disabled';
1936 }
1937 $out .= '>';
1938
1939 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1940 if ($showfunction && $obj->poste) {
1941 $tmplabel .= ' (' . $obj->poste . ')';
1942 }
1943 if (($showsoc > 0) && $obj->company) {
1944 $tmplabel .= ' - (' . $obj->company . ')';
1945 }
1946
1947 $out .= $tmplabel;
1948 $out .= '</option>';
1949 }
1950 } else {
1951 if (in_array($obj->rowid, $selected)) {
1952 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1953 if ($showfunction && $obj->poste) {
1954 $tmplabel .= ' (' . $obj->poste . ')';
1955 }
1956 if (($showsoc > 0) && $obj->company) {
1957 $tmplabel .= ' - (' . $obj->company . ')';
1958 }
1959
1960 $out .= $tmplabel;
1961 }
1962 }
1963
1964 if ($tmplabel != '') {
1965 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1966 }
1967 }
1968 $i++;
1969 }
1970 } else {
1971 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1972 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1973 $out .= $labeltoshow;
1974 $out .= '</option>';
1975 }
1976
1977 $parameters = array(
1978 'socid' => $socid,
1979 'htmlname' => $htmlname,
1980 'resql' => $resql,
1981 'out' => &$out,
1982 'showfunction' => $showfunction,
1983 'showsoc' => $showsoc,
1984 );
1985
1986 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1987
1988 if ($htmlname != 'none' && !$options_only) {
1989 $out .= '</select>';
1990 }
1991
1992 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1993 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1994 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
1995 }
1996
1997 $this->num = $num;
1998
1999 if ($options_only === 2) {
2000 // Return array of options
2001 return $outarray;
2002 } else {
2003 return $out;
2004 }
2005 } else {
2006 dol_print_error($this->db);
2007 return -1;
2008 }
2009 }
2010
2011
2012 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2013
2024 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2025 {
2026 // phpcs:enable
2027 global $langs, $conf;
2028
2029 // On recherche les remises
2030 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2031 $sql .= " re.description, re.fk_facture_source";
2032 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2033 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2034 $sql .= " AND re.entity = " . $conf->entity;
2035 if ($filter) {
2036 $sql .= " AND " . $filter;
2037 }
2038 $sql .= " ORDER BY re.description ASC";
2039
2040 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2041 $resql = $this->db->query($sql);
2042 if ($resql) {
2043 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2044 $num = $this->db->num_rows($resql);
2045
2046 $qualifiedlines = $num;
2047
2048 $i = 0;
2049 if ($num) {
2050 print '<option value="0">&nbsp;</option>';
2051 while ($i < $num) {
2052 $obj = $this->db->fetch_object($resql);
2053 $desc = dol_trunc($obj->description, 40);
2054 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2055 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2056 }
2057 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2058 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2059 }
2060 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2061 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2062 }
2063 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2064 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2065 }
2066
2067 $selectstring = '';
2068 if ($selected > 0 && $selected == $obj->rowid) {
2069 $selectstring = ' selected';
2070 }
2071
2072 $disabled = '';
2073 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2074 $qualifiedlines--;
2075 $disabled = ' disabled';
2076 }
2077
2078 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2079 $tmpfac = new Facture($this->db);
2080 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2081 $desc = $desc . ' - ' . $tmpfac->ref;
2082 }
2083 }
2084
2085 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2086 $i++;
2087 }
2088 }
2089 print '</select>';
2090 print ajax_combobox('select_' . $htmlname);
2091
2092 return $qualifiedlines;
2093 } else {
2094 dol_print_error($this->db);
2095 return -1;
2096 }
2097 }
2098
2099
2100 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2101
2117 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2118 {
2119 // phpcs:enable
2120 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2121 }
2122
2123 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2124
2149 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2150 {
2151 // phpcs:enable
2152 global $conf, $user, $langs, $hookmanager;
2153 global $action;
2154
2155 // If no preselected user defined, we take current user
2156 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2157 $selected = $user->id;
2158 }
2159
2160 if ($selected === '') {
2161 $selected = array();
2162 } elseif (!is_array($selected)) {
2163 $selected = array($selected);
2164 }
2165
2166 $excludeUsers = null;
2167 $includeUsers = null;
2168
2169 // Exclude some users
2170 if (is_array($exclude)) {
2171 $excludeUsers = implode(",", $exclude);
2172 }
2173 // Include some uses
2174 if (is_array($include)) {
2175 $includeUsers = implode(",", $include);
2176 } elseif ($include == 'hierarchy') {
2177 // Build list includeUsers to have only hierarchy
2178 $includeUsers = implode(",", $user->getAllChildIds(0));
2179 } elseif ($include == 'hierarchyme') {
2180 // Build list includeUsers to have only hierarchy and current user
2181 $includeUsers = implode(",", $user->getAllChildIds(1));
2182 }
2183
2184 $num = 0;
2185
2186 $out = '';
2187 $outarray = array();
2188 $outarray2 = array();
2189
2190 // Do we want to show the label of entity into the combo list ?
2191 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2192 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2193
2194 // Forge request to select users
2195 $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.gender, u.photo";
2196 if ($showlabelofentity) {
2197 $sql .= ", e.label";
2198 }
2199 $sql .= " FROM " . $this->db->prefix() . "user as u";
2200 if ($showlabelofentity) {
2201 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2202 }
2203 // Condition here should be the same than into societe->getSalesRepresentatives().
2204 if ($userissuperadminentityone && $force_entity != 'default') {
2205 if (!empty($force_entity)) {
2206 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2207 } else {
2208 $sql .= " WHERE u.entity IS NOT NULL";
2209 }
2210 } else {
2211 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2212 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2213 } else {
2214 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2215 }
2216 }
2217
2218 if (!empty($user->socid)) {
2219 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2220 }
2221 if (is_array($exclude) && $excludeUsers) {
2222 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2223 }
2224 if ($includeUsers) {
2225 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2226 }
2227 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2228 $sql .= " AND u.statut <> 0";
2229 }
2230 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2231 $sql .= " AND u.employee <> 0";
2232 }
2233 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2234 $sql .= " AND u.fk_soc IS NULL";
2235 }
2236 if (!empty($morefilter)) {
2237 $errormessage = '';
2238 $sql .= forgeSQLFromUniversalSearchCriteria($morefilter, $errormessage);
2239 if ($errormessage) {
2240 $this->errors[] = $errormessage;
2241 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2242 if ($outputmode == 0) {
2243 return 'Error bad param $morefilter';
2244 } else {
2245 return array();
2246 }
2247 }
2248 }
2249
2250 //Add hook to filter on user (for example on usergroup define in custom modules)
2251 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2252 if (!empty($reshook)) {
2253 $sql .= $hookmanager->resPrint;
2254 }
2255
2256 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2257 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2258 } else {
2259 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2260 }
2261
2262 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2263
2264 $resql = $this->db->query($sql);
2265 if ($resql) {
2266 $num = $this->db->num_rows($resql);
2267 $i = 0;
2268 if ($num) {
2269 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2270 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2271 if ($show_empty && !$multiple) {
2272 $textforempty = ' ';
2273 if (!empty($conf->use_javascript_ajax)) {
2274 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2275 }
2276 if (!is_numeric($show_empty)) {
2277 $textforempty = $show_empty;
2278 }
2279 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2280
2281 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2282 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2283 'id' => ($show_empty < 0 ? $show_empty : -1),
2284 'label' => $textforempty,
2285 'labelhtml' => $textforempty,
2286 'color' => '',
2287 'picto' => ''
2288 );
2289 }
2290 if ($show_every) {
2291 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2292
2293 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2294 $outarray2[-2] = array(
2295 'id' => -2,
2296 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2297 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2298 'color' => '',
2299 'picto' => ''
2300 );
2301 }
2302
2303 $userstatic = new User($this->db);
2304
2305 while ($i < $num) {
2306 $obj = $this->db->fetch_object($resql);
2307
2308 $userstatic->id = $obj->rowid;
2309 $userstatic->lastname = $obj->lastname;
2310 $userstatic->firstname = $obj->firstname;
2311 $userstatic->photo = $obj->photo;
2312 $userstatic->status = $obj->status;
2313 $userstatic->entity = $obj->entity;
2314 $userstatic->admin = $obj->admin;
2315 $userstatic->gender = $obj->gender;
2316
2317 $disableline = '';
2318 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2319 $disableline = ($enableonlytext ? $enableonlytext : '1');
2320 }
2321
2322 $labeltoshow = '';
2323 $labeltoshowhtml = '';
2324
2325 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2326 $fullNameMode = 0;
2327 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2328 $fullNameMode = 1; //Firstname+lastname
2329 }
2330 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2331 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2332 if (empty($obj->firstname) && empty($obj->lastname)) {
2333 $labeltoshow .= $obj->login;
2334 $labeltoshowhtml .= $obj->login;
2335 }
2336
2337 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2338 $moreinfo = '';
2339 $moreinfohtml = '';
2340 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2341 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2342 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2343 $moreinfo .= $obj->login;
2344 $moreinfohtml .= $obj->login;
2345 }
2346 if ($showstatus >= 0) {
2347 if ($obj->status == 1 && $showstatus == 1) {
2348 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2349 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2350 }
2351 if ($obj->status == 0 && $showstatus == 1) {
2352 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2353 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2354 }
2355 }
2356 if ($showlabelofentity) {
2357 if (empty($obj->entity)) {
2358 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2359 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2360 } else {
2361 if ($obj->entity != $conf->entity) {
2362 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2363 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2364 }
2365 }
2366 }
2367 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2368 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2369 if (!empty($disableline) && $disableline != '1') {
2370 // Add text from $enableonlytext parameter
2371 $moreinfo .= ' - ' . $disableline;
2372 $moreinfohtml .= ' - ' . $disableline;
2373 }
2374 $labeltoshow .= $moreinfo;
2375 $labeltoshowhtml .= $moreinfohtml;
2376
2377 $out .= '<option value="' . $obj->rowid . '"';
2378 if (!empty($disableline)) {
2379 $out .= ' disabled';
2380 }
2381 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2382 $out .= ' selected';
2383 }
2384 $out .= ' data-html="';
2385
2386 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2387 if ($showstatus >= 0 && $obj->status == 0) {
2388 $outhtml .= '<strike class="opacitymediumxxx">';
2389 }
2390 $outhtml .= $labeltoshowhtml;
2391 if ($showstatus >= 0 && $obj->status == 0) {
2392 $outhtml .= '</strike>';
2393 }
2394 $labeltoshowhtml = $outhtml;
2395
2396 $out .= dol_escape_htmltag($outhtml);
2397 $out .= '">';
2398 $out .= $labeltoshow;
2399 $out .= '</option>';
2400
2401 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2402 $outarray2[$userstatic->id] = array(
2403 'id' => $userstatic->id,
2404 'label' => $labeltoshow,
2405 'labelhtml' => $labeltoshowhtml,
2406 'color' => '',
2407 'picto' => ''
2408 );
2409
2410 $i++;
2411 }
2412 } else {
2413 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2414 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2415 }
2416 $out .= '</select>';
2417
2418 if ($num && !$forcecombo) {
2419 // Enhance with select2
2420 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2421 $out .= ajax_combobox($htmlname);
2422 }
2423 } else {
2424 dol_print_error($this->db);
2425 }
2426
2427 $this->num = $num;
2428
2429 if ($outputmode == 2) {
2430 return $outarray2;
2431 } elseif ($outputmode) {
2432 return $outarray;
2433 }
2434
2435 return $out;
2436 }
2437
2438
2439 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2463 public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array(), $canremoveowner = 1)
2464 {
2465 // phpcs:enable
2466 global $langs, $user;
2467
2468 $userstatic = new User($this->db);
2469 $out = '';
2470
2471 if (!empty($_SESSION['assignedtouser'])) {
2472 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2473 if (!is_array($assignedtouser)) {
2474 $assignedtouser = array();
2475 }
2476 } else {
2477 $assignedtouser = array();
2478 }
2479 $nbassignetouser = count($assignedtouser);
2480
2481 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2482 if ($nbassignetouser) {
2483 $out .= '<ul class="attendees">';
2484 }
2485 $i = 0;
2486 $ownerid = 0;
2487 foreach ($assignedtouser as $key => $value) {
2488 if ($value['id'] == $ownerid) {
2489 continue;
2490 }
2491
2492 $out .= '<li>';
2493 $userstatic->fetch($value['id']);
2494 $out .= $userstatic->getNomUrl(-1);
2495 if ($i == 0) {
2496 $ownerid = $value['id'];
2497 $out .= ' (' . $langs->trans("Owner") . ')';
2498 }
2499 // Add picto to delete owner/assignee
2500 if ($nbassignetouser > 1 && $action != 'view') {
2501 $canremoveassignee = 1;
2502 if ($i == 0) {
2503 // We are on the owner of the event
2504 if (!$canremoveowner) {
2505 $canremoveassignee = 0;
2506 }
2507 if (!$user->hasRight('agenda', 'allactions', 'create')) {
2508 $canremoveassignee = 0; // Can't remove the owner
2509 }
2510 } else {
2511 // We are not on the owner of the event but on a secondary assignee
2512 }
2513 if ($canremoveassignee) {
2514 // If user has all permission, he should be ableto remove a assignee.
2515 // If user has not all permission, he can onlyremove assignee of other (he can't remove itself)
2516 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $userstatic->id . '" class="removedassigned reposition" id="removedassigned_' . $userstatic->id . '" name="removedassigned_' . $userstatic->id . '">';
2517 }
2518 }
2519 // Show my availability
2520 if ($showproperties) {
2521 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2522 $out .= '<div class="myavailability inline-block">';
2523 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparency" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofuserid[$ownerid]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2524 $out .= '</div>';
2525 }
2526 }
2527 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2528 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2529
2530 $out .= '</li>';
2531 $i++;
2532 }
2533 if ($nbassignetouser) {
2534 $out .= '</ul>';
2535 }
2536
2537 // Method with no ajax
2538 if ($action != 'view') {
2539 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2540 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2541 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2542 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2543 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2544 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2545 $out .= '});';
2546 $out .= '})</script>';
2547 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2548 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2549 $out .= '<br>';
2550 }
2551
2552 return $out;
2553 }
2554
2555 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2575 public function select_dolresources_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofresourceid = array())
2576 {
2577 // phpcs:enable
2578 global $langs;
2579
2580 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2581 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2582 $formresources = new FormResource($this->db);
2583 $resourcestatic = new Dolresource($this->db);
2584
2585 $out = '';
2586 if (!empty($_SESSION['assignedtoresource'])) {
2587 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2588 if (!is_array($assignedtoresource)) {
2589 $assignedtoresource = array();
2590 }
2591 } else {
2592 $assignedtoresource = array();
2593 }
2594 $nbassignetoresource = count($assignedtoresource);
2595
2596 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2597 if ($nbassignetoresource) {
2598 $out .= '<ul class="attendees">';
2599 }
2600 $i = 0;
2601
2602 foreach ($assignedtoresource as $key => $value) {
2603 $out .= '<li>';
2604 $resourcestatic->fetch($value['id']);
2605 $out .= $resourcestatic->getNomUrl(-1);
2606 if ($nbassignetoresource >= 1 && $action != 'view') {
2607 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassignedresource reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2608 }
2609 // Show my availability
2610 if ($showproperties) {
2611 if (is_array($listofresourceid) && count($listofresourceid)) {
2612 $out .= '<div class="myavailability inline-block">';
2613 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparencyresource" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2614 $out .= '</div>';
2615 }
2616 }
2617 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2618 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2619
2620 $out .= '</li>';
2621 $i++;
2622 }
2623 if ($nbassignetoresource) {
2624 $out .= '</ul>';
2625 }
2626
2627 // Method with no ajax
2628 if ($action != 'view') {
2629 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2630 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2631 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2632 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2633 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2634 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2635 $out .= '});';
2636 $out .= '})</script>';
2637
2638 $events = array();
2639 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2640 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2641 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2642 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2643 $out .= '<br>';
2644 }
2645
2646 return $out;
2647 }
2648
2649 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2650
2680 public function select_produits($selected = 0, $htmlname = 'productid', $filtertype = '', $limit = 0, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = null, $nooutput = 0, $status_purchase = -1, $warehouseId = 0)
2681 {
2682 // phpcs:enable
2683 global $langs, $conf;
2684
2685 $out = '';
2686
2687 // check parameters
2688 $price_level = (!empty($price_level) ? $price_level : 0);
2689 if (is_null($ajaxoptions)) {
2690 $ajaxoptions = array();
2691 }
2692
2693 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2694 if (isModEnabled("product") && !isModEnabled('service')) {
2695 $filtertype = '0';
2696 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2697 $filtertype = '1';
2698 }
2699 }
2700
2701 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2702 $placeholder = (is_numeric($showempty) ? '' : 'placeholder="'.dolPrintHTML($showempty).'"');
2703
2704 if ($selected && empty($selected_input_value)) {
2705 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2706 $producttmpselect = new Product($this->db);
2707 $producttmpselect->fetch($selected);
2708 $selected_input_value = $producttmpselect->ref;
2709 unset($producttmpselect);
2710 }
2711 // handle case where product or service module is disabled + no filter specified
2712 if ($filtertype == '') {
2713 if (!isModEnabled('product')) { // when product module is disabled, show services only
2714 $filtertype = 1;
2715 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2716 $filtertype = 0;
2717 }
2718 }
2719 // mode=1 means customers products
2720 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=1&status=' . $status . '&status_purchase=' . $status_purchase . '&finished=' . $finished . '&hidepriceinlabel=' . $hidepriceinlabel . '&warehousestatus=' . $warehouseStatus;
2721 if ((int) $warehouseId > 0) {
2722 $urloption .= '&warehouseid=' . (int) $warehouseId;
2723 }
2724
2725 $out .= ajax_autocompleter((string) $selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), getDolGlobalInt('PRODUCT_SEARCH_AUTO_SELECT_IF_ONLY_ONE', 1), $ajaxoptions);
2726
2727 if (isModEnabled('variants') && is_array($selected_combinations)) {
2728 // Code to automatically insert with javascript the select of attributes under the select of product
2729 // when a parent of variant has been selected.
2730 $out .= '
2731 <!-- script to auto show attributes select tags if a variant was selected -->
2732 <script nonce="' . getNonce() . '">
2733 // auto show attributes fields
2734 selected = ' . json_encode($selected_combinations) . ';
2735 combvalues = {};
2736
2737 jQuery(document).ready(function () {
2738
2739 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2740 if (jQuery(this).val() == \'free\') {
2741 jQuery(\'div#attributes_box\').empty();
2742 }
2743 });
2744
2745 jQuery("input#' . $htmlname . '").change(function () {
2746
2747 if (!jQuery(this).val()) {
2748 jQuery(\'div#attributes_box\').empty();
2749 return;
2750 }
2751
2752 console.log("A change has started. We get variants fields to inject html select");
2753
2754 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2755 id: jQuery(this).val()
2756 }, function (data) {
2757 jQuery(\'div#attributes_box\').empty();
2758
2759 jQuery.each(data, function (key, val) {
2760
2761 combvalues[val.id] = val.values;
2762
2763 var span = jQuery(document.createElement(\'div\')).css({
2764 \'display\': \'table-row\'
2765 });
2766
2767 span.append(
2768 jQuery(document.createElement(\'div\')).text(val.label).css({
2769 \'font-weight\': \'bold\',
2770 \'display\': \'table-cell\'
2771 })
2772 );
2773
2774 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2775 \'margin-left\': \'15px\',
2776 \'white-space\': \'pre\'
2777 }).append(
2778 jQuery(document.createElement(\'option\')).val(\'\')
2779 );
2780
2781 jQuery.each(combvalues[val.id], function (key, val) {
2782 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2783
2784 if (selected[val.fk_product_attribute] == val.id) {
2785 tag.attr(\'selected\', \'selected\');
2786 }
2787
2788 html.append(tag);
2789 });
2790
2791 span.append(html);
2792 jQuery(\'div#attributes_box\').append(span);
2793 });
2794 })
2795 });
2796
2797 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2798 });
2799 </script>
2800 ';
2801 }
2802
2803 if (empty($hidelabel)) {
2804 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2805 } elseif ($hidelabel > 1) {
2806 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2807 if ($hidelabel == 2) {
2808 $out .= img_picto($langs->trans("Search"), 'search');
2809 }
2810 }
2811
2812 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2813 if ($hidelabel == 3) {
2814 $out .= img_picto($langs->trans("Search"), 'search');
2815 }
2816 } else {
2817 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2818 }
2819
2820 if (empty($nooutput)) {
2821 print $out;
2822 } else {
2823 return $out;
2824 }
2825 }
2826
2827 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2828
2844 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2845 {
2846 // phpcs:enable
2847 global $db;
2848
2849 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2850
2851 $error = 0;
2852 $out = '';
2853
2854 if (!$forcecombo) {
2855 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2856 $events = array();
2857 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2858 }
2859
2860 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2861
2862 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2863 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2864 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2865 if (!empty($status)) {
2866 $sql .= ' AND status = ' . (int) $status;
2867 }
2868 if (!empty($type)) {
2869 $sql .= ' AND bomtype = ' . (int) $type;
2870 }
2871 if (!empty($TProducts)) {
2872 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2873 }
2874 if (!empty($limit)) {
2875 $sql .= ' LIMIT ' . (int) $limit;
2876 }
2877 $resql = $db->query($sql);
2878 if ($resql) {
2879 if ($showempty) {
2880 $out .= '<option value="-1"';
2881 if (empty($selected)) {
2882 $out .= ' selected';
2883 }
2884 $out .= '>&nbsp;</option>';
2885 }
2886 while ($obj = $db->fetch_object($resql)) {
2887 $product = new Product($db);
2888 $res = $product->fetch($obj->fk_product);
2889 $out .= '<option value="' . $obj->rowid . '"';
2890 if ($obj->rowid == $selected) {
2891 $out .= 'selected';
2892 }
2893 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2894 }
2895 } else {
2896 $error++;
2897 dol_print_error($db);
2898 }
2899 $out .= '</select>';
2900 if (empty($nooutput)) {
2901 print $out;
2902 } else {
2903 return $out;
2904 }
2905 }
2906
2907 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2908
2935 public function select_produits_list($selected = 0, $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = 'maxwidth500', $hidepriceinlabel = 0, $warehouseStatus = '', $status_purchase = -1, $warehouseId = 0)
2936 {
2937 // phpcs:enable
2938 global $langs;
2939 global $hookmanager;
2940
2941 $out = '';
2942 $outarray = array();
2943
2944 // Units
2945 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2946 $langs->load('other');
2947 }
2948
2949 $warehouseStatusArray = array();
2950 if (!empty($warehouseStatus)) {
2951 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2952 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2953 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2954 }
2955 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2956 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2957 }
2958 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2959 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2960 }
2961 }
2962
2963 $selectFields = " p.rowid, p.ref, p.label, p.description, p.barcode, p.fk_country, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.default_vat_code, p.duration, p.fk_price_expression";
2964 if (count($warehouseStatusArray)) {
2965 $selectFieldsGrouped = ", sum(" . $this->db->ifsql("e.statut IS NULL", "0", "ps.reel") . ") as stock"; // e.statut is null if there is no record in stock
2966 } else {
2967 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2968 }
2969
2970 $sql = "SELECT ";
2971
2972 // Add select from hooks
2973 $parameters = array();
2974 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2975 if (empty($reshook)) {
2976 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2977 } else {
2978 $sql .= $hookmanager->resPrint;
2979 }
2980
2981 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2982 //Product category
2983 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2984 FROM " . $this->db->prefix() . "categorie_product
2985 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2986 LIMIT 1
2987 ) AS categorie_product_id ";
2988 }
2989
2990 //Price by customer
2991 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
2992 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2993 $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.default_vat_code as custdefault_vat_code, pcp.ref_customer as custref';
2994 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2995 }
2996 // Units
2997 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2998 $sql .= ", u.label as unit_long, u.short_label as unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units";
2999 $selectFields .= ', unit_long, unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units';
3000 }
3001
3002 // Multilang : we add translation
3003 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3004 $sql .= ", pl.label as label_translated";
3005 $sql .= ", pl.description as description_translated";
3006 $selectFields .= ", label_translated";
3007 $selectFields .= ", description_translated";
3008 }
3009 // Price by quantity
3010 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3011 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
3012 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3013 $sql .= " AND price_level = " . ((int) $price_level);
3014 }
3015 $sql .= " ORDER BY date_price";
3016 $sql .= " DESC LIMIT 1) as price_rowid";
3017 $sql .= ", (SELECT pp.price_by_qty FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid"; // price_by_qty is 1 if some prices by qty exists in subtable
3018 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3019 $sql .= " AND price_level = " . ((int) $price_level);
3020 }
3021 $sql .= " ORDER BY date_price";
3022 $sql .= " DESC LIMIT 1) as price_by_qty";
3023 $selectFields .= ", price_rowid, price_by_qty";
3024 }
3025
3026 $sql .= " FROM ".$this->db->prefix()."product as p";
3027
3028 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
3029 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
3030 }
3031
3032 // Add from (left join) from hooks
3033 $parameters = array();
3034 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3035 $sql .= $hookmanager->resPrint;
3036
3037 if (count($warehouseStatusArray)) {
3038 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
3039 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3040 $sql .= ' AND e.statut IN (' . $this->db->sanitize($this->db->escape(implode(',', $warehouseStatusArray))) . ')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0.
3041 }
3042
3043 // include search in supplier ref
3044 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3045 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3046 }
3047
3048 //Price by customer
3049 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3050 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
3051 }
3052 // Units
3053 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3054 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3055 }
3056 // Multilang : we add translation
3057 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3058 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3059 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3060 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3061 $soc = new Societe($this->db);
3062 $result = $soc->fetch($socid);
3063 if ($result > 0 && !empty($soc->default_lang)) {
3064 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3065 } else {
3066 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3067 }
3068 } else {
3069 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3070 }
3071 }
3072
3073 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3074 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3075 }
3076
3077 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3078
3079 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3080 $sql .= " AND pac.rowid IS NULL";
3081 }
3082
3083 if ($finished == 0) {
3084 $sql .= " AND p.finished = " . ((int) $finished);
3085 } elseif ($finished == 1) {
3086 $sql .= " AND p.finished = ".((int) $finished);
3087 }
3088 if ($status >= 0) {
3089 $sql .= " AND p.tosell = ".((int) $status);
3090 }
3091 if ($status_purchase >= 0) {
3092 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3093 }
3094 // Filter by product type
3095 if (strval($filtertype) != '') {
3096 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3097 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3098 $sql .= " AND p.fk_product_type = 1";
3099 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3100 $sql .= " AND p.fk_product_type = 0";
3101 }
3102
3103 if ((int) $warehouseId > 0) {
3104 $sql .= " AND EXISTS (SELECT psw.fk_product FROM " . $this->db->prefix() . "product_stock as psw WHERE psw.reel>0 AND psw.fk_entrepot=".(int) $warehouseId." AND psw.fk_product = p.rowid)";
3105 }
3106
3107 // Add where from hooks
3108 $parameters = array();
3109 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3110 $sql .= $hookmanager->resPrint;
3111 // Add criteria on ref/label
3112 if ($filterkey != '') {
3113 $sql .= ' AND (';
3114 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3115 // For natural search
3116 $search_crit = explode(' ', $filterkey);
3117 $i = 0;
3118 if (count($search_crit) > 1) {
3119 $sql .= "(";
3120 }
3121 foreach ($search_crit as $crit) {
3122 if ($i > 0) {
3123 $sql .= " AND ";
3124 }
3125 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3126 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3127 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3128 }
3129 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3130 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3131 }
3132 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3133 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3134 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3135 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3136 }
3137 }
3138 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3139 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3140 }
3141 $sql .= ")";
3142 $i++;
3143 }
3144 if (count($search_crit) > 1) {
3145 $sql .= ")";
3146 }
3147 if (isModEnabled('barcode')) {
3148 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3149 }
3150 $sql .= ')';
3151 }
3152 if (count($warehouseStatusArray)) {
3153 $sql .= " GROUP BY " . $selectFields;
3154 }
3155
3156 //Sort by category
3157 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3158 $sql .= " ORDER BY categorie_product_id ";
3159 //ASC OR DESC order
3160 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3161 } else {
3162 $sql .= $this->db->order("p.ref");
3163 }
3164
3165 $sql .= $this->db->plimit($limit, 0);
3166
3167 // Build output string
3168 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3169 $result = $this->db->query($sql);
3170 if ($result) {
3171 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3172 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3173 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3174
3175 $num = $this->db->num_rows($result);
3176
3177 $events = array();
3178
3179 if (!$forcecombo) {
3180 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3181 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3182 }
3183
3184 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3185
3186 $textifempty = '';
3187 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3188 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3189 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3190 if ($showempty && !is_numeric($showempty)) {
3191 $textifempty = $langs->trans($showempty);
3192 } else {
3193 $textifempty .= $langs->trans("All");
3194 }
3195 } else {
3196 if ($showempty && !is_numeric($showempty)) {
3197 $textifempty = $langs->trans($showempty);
3198 }
3199 }
3200 if ($showempty) {
3201 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3202 }
3203
3204 $i = 0;
3205 while ($num && $i < $num) {
3206 $opt = '';
3207 $optJson = array();
3208 $objp = $this->db->fetch_object($result);
3209
3210 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product
3211 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3212 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3213 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3214 $sql .= " ORDER BY quantity ASC";
3215
3216 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3217 $result2 = $this->db->query($sql);
3218 if ($result2) {
3219 $nb_prices = $this->db->num_rows($result2);
3220 $j = 0;
3221 while ($nb_prices && $j < $nb_prices) {
3222 $objp2 = $this->db->fetch_object($result2);
3223
3224 $objp->price_by_qty_rowid = $objp2->rowid;
3225 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3226 $objp->price_by_qty_quantity = $objp2->quantity;
3227 $objp->price_by_qty_unitprice = $objp2->unitprice;
3228 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3229 // For backward compatibility
3230 $objp->quantity = $objp2->quantity;
3231 $objp->price = $objp2->price;
3232 $objp->unitprice = $objp2->unitprice;
3233 $objp->remise_percent = $objp2->remise_percent;
3234
3235 //$objp->tva_tx is not overwritten by $objp2 value
3236 //$objp->default_vat_code is not overwritten by $objp2 value
3237
3238 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3239 '@phan-var-force array{key:string,value:string,label:string,label2:string,desc:string,type:string,price_ht:string,price_ttc:string,price_ht_locale:string,price_ttc_locale:string,pricebasetype:string,tva_tx:string,default_vat_code:string,qty:string,discount:string,duration_value:string,duration_unit:string,pbq:string,labeltrans:string,desctrans:string,ref_customer:string} $optJson';
3240 $j++;
3241
3242 // Add new entry
3243 // "key" value of json key array is used by jQuery automatically as selected value
3244 // "label" value of json key array is used by jQuery automatically as text for combo box
3245 $out .= $opt;
3246 array_push($outarray, $optJson);
3247 }
3248 }
3249 } else {
3250 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3251 $price_product = new Product($this->db);
3252 $price_product->fetch($objp->rowid, '', '', 1);
3253
3254 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3255 $priceparser = new PriceParser($this->db);
3256 $price_result = $priceparser->parseProduct($price_product);
3257 if ($price_result >= 0) {
3258 $objp->price = $price_result;
3259 $objp->unitprice = $price_result;
3260 //Calculate the VAT
3261 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3262 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3263 }
3264 }
3265 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3266 $price_level = '';
3267 }
3268 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3269 // Add new entry
3270 // "key" value of json key array is used by jQuery automatically as selected value
3271 // "label" value of json key array is used by jQuery automatically as text for combo box
3272 $out .= $opt;
3273 array_push($outarray, $optJson);
3274 }
3275
3276 $i++;
3277 }
3278
3279 $out .= '</select>';
3280
3281 $this->db->free($result);
3282
3283 if (empty($outputmode)) {
3284 return $out;
3285 }
3286
3287 return $outarray;
3288 } else {
3289 dol_print_error($this->db);
3290 }
3291
3292 return '';
3293 }
3294
3310 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3311 {
3312 global $langs, $conf, $user;
3313 global $hookmanager;
3314
3315 $outkey = '';
3316 $outval = '';
3317 $outref = '';
3318 $outlabel = '';
3319 $outlabel_translated = '';
3320 $outdesc = '';
3321 $outdesc_translated = '';
3322 $outbarcode = '';
3323 $outorigin = '';
3324 $outtype = '';
3325 $outprice_ht = '';
3326 $outprice_ttc = '';
3327 $outpricebasetype = '';
3328 $outtva_tx = '';
3329 $outdefault_vat_code = '';
3330 $outqty = 1;
3331 $outdiscount = 0;
3332
3333 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3334
3335 $label = $objp->label;
3336 if (!empty($objp->label_translated)) {
3337 $label = $objp->label_translated;
3338 }
3339 if (!empty($filterkey) && $filterkey != '') {
3340 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3341 }
3342
3343 $outkey = $objp->rowid;
3344 $outref = $objp->ref;
3345 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3346 $outlabel = $objp->label;
3347 $outdesc = $objp->description;
3348 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3349 $outlabel_translated = $objp->label_translated;
3350 $outdesc_translated = $objp->description_translated;
3351 }
3352 $outbarcode = $objp->barcode;
3353 $outorigin = $objp->fk_country;
3354 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3355
3356 $outtype = $objp->fk_product_type;
3357 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3358 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3359
3360 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3361 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3362 }
3363
3364 // Units
3365 $outvalUnits = '';
3366 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3367 if (!empty($objp->unit_short)) {
3368 $outvalUnits .= ' - ' . $objp->unit_short;
3369 }
3370 }
3371 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3372 if (!empty($objp->weight) && $objp->weight_units !== null) {
3373 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3374 $outvalUnits .= ' - ' . $unitToShow;
3375 }
3376 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3377 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3378 $outvalUnits .= ' - ' . $unitToShow;
3379 }
3380 if (!empty($objp->surface) && $objp->surface_units !== null) {
3381 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3382 $outvalUnits .= ' - ' . $unitToShow;
3383 }
3384 if (!empty($objp->volume) && $objp->volume_units !== null) {
3385 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3386 $outvalUnits .= ' - ' . $unitToShow;
3387 }
3388 }
3389 if ($outdurationvalue && $outdurationunit) {
3390 $da = array(
3391 'h' => $langs->trans('Hour'),
3392 'd' => $langs->trans('Day'),
3393 'w' => $langs->trans('Week'),
3394 'm' => $langs->trans('Month'),
3395 'y' => $langs->trans('Year')
3396 );
3397 if (isset($da[$outdurationunit])) {
3398 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3399 }
3400 }
3401
3402 // Set stocktag (stock too low or not or unknown)
3403 $stocktag = 0;
3404 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3405 if ($user->hasRight('stock', 'lire')) {
3406 if ($objp->stock > 0) {
3407 $stocktag = 1;
3408 } elseif ($objp->stock <= 0) {
3409 $stocktag = -1;
3410 }
3411 }
3412 }
3413
3414 // Set $labeltoshow
3415 $labeltoshow = '';
3416 $labeltoshow .= $objp->ref;
3417 if (!empty($objp->custref)) {
3418 $labeltoshow .= ' (' . $objp->custref . ')';
3419 }
3420 if ($outbarcode) {
3421 $labeltoshow .= ' (' . $outbarcode . ')';
3422 }
3423 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3424 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3425 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3426 }
3427
3428 // Set $labltoshowhtml
3429 $labeltoshowhtml = '';
3430 $labeltoshowhtml .= $objp->ref;
3431 if (!empty($objp->custref)) {
3432 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3433 }
3434 if (!empty($filterkey) && $filterkey != '') {
3435 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3436 }
3437 if ($outbarcode) {
3438 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3439 }
3440 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3441 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3442 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3443 }
3444
3445 // Stock
3446 $labeltoshowstock = '';
3447 $labeltoshowhtmlstock = '';
3448 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3449 if ($user->hasRight('stock', 'lire')) {
3450 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3451
3452 if ($objp->stock > 0) {
3453 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3454 } elseif ($objp->stock <= 0) {
3455 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3456 }
3457 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3458 $labeltoshowhtmlstock .= '</span>';
3459
3460 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3461 $langs->load("stocks");
3462
3463 $tmpproduct = new Product($this->db);
3464 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3465 $tmpproduct->load_virtual_stock();
3466 $virtualstock = $tmpproduct->stock_theorique;
3467
3468 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3469
3470 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3471 if ($virtualstock > 0) {
3472 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3473 } elseif ($virtualstock <= 0) {
3474 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3475 }
3476 $labeltoshowhtmlstock .= $virtualstock;
3477 $labeltoshowhtmlstock .= '</span>';
3478
3479 unset($tmpproduct);
3480 }
3481 }
3482 }
3483
3484 // Price
3485 $found = 0;
3486 $labeltoshowprice = '';
3487 $labeltoshowhtmlprice = '';
3488 // If we need a particular price level (from 1 to n)
3489 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3490 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3491 $sql .= " FROM " . $this->db->prefix() . "product_price";
3492 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3493 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3494 $sql .= " AND price_level = " . ((int) $price_level);
3495 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3496 $sql .= " LIMIT 1";
3497
3498 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3499 $result2 = $this->db->query($sql);
3500 if ($result2) {
3501 $objp2 = $this->db->fetch_object($result2);
3502 if ($objp2) {
3503 $found = 1;
3504 if ($objp2->price_base_type == 'HT') {
3505 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3506 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3507 } else {
3508 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3509 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3510 }
3511 $outprice_ht = price($objp2->price);
3512 $outprice_ttc = price($objp2->price_ttc);
3513 $outpricebasetype = $objp2->price_base_type;
3514 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3515 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3516 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3517 } else {
3518 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3519 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3520 }
3521 }
3522 } else {
3523 dol_print_error($this->db);
3524 }
3525 }
3526
3527 // Price by quantity
3528 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3529 $found = 1;
3530 $outqty = $objp->quantity;
3531 $outdiscount = $objp->remise_percent;
3532 if ($objp->quantity == 1) {
3533 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3534 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3535 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3536 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3537 } else {
3538 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3539 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3540 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3541 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3542 }
3543
3544 $outprice_ht = price($objp->unitprice);
3545 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3546 $outpricebasetype = $objp->price_base_type;
3547 $outtva_tx = $objp->tva_tx; // This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3548 $outdefault_vat_code = $objp->default_vat_code; // This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3549 }
3550 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3551 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3552 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3553 }
3554 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3555 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3556 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3557 }
3558
3559 // Price by customer
3560 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3561 if (!empty($objp->idprodcustprice)) {
3562 $found = 1;
3563
3564 if ($objp->custprice_base_type == 'HT') {
3565 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3566 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3567 } else {
3568 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3569 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3570 }
3571
3572 $outprice_ht = price($objp->custprice);
3573 $outprice_ttc = price($objp->custprice_ttc);
3574 $outpricebasetype = $objp->custprice_base_type;
3575 $outtva_tx = $objp->custtva_tx;
3576 $outdefault_vat_code = $objp->custdefault_vat_code;
3577 }
3578 }
3579
3580 // If level no defined or multiprice not found, we used the default price
3581 if (empty($hidepriceinlabel) && !$found) {
3582 if ($objp->price_base_type == 'HT') {
3583 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3584 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3585 } else {
3586 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3587 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3588 }
3589 $outprice_ht = price($objp->price);
3590 $outprice_ttc = price($objp->price_ttc);
3591 $outpricebasetype = $objp->price_base_type;
3592 $outtva_tx = $objp->tva_tx;
3593 $outdefault_vat_code = $objp->default_vat_code;
3594 }
3595
3596 // Build options
3597 $opt = '<option value="' . $objp->rowid . '"';
3598 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3599 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3600 $opt .= ' pbq="' . $objp->price_by_qty_rowid . '" data-pbq="' . $objp->price_by_qty_rowid . '" data-pbqup="' . $objp->price_by_qty_unitprice . '" data-pbqbase="' . $objp->price_by_qty_price_base_type . '" data-pbqqty="' . $objp->price_by_qty_quantity . '" data-pbqpercent="' . $objp->price_by_qty_remise_percent . '"';
3601 }
3602 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3603 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3604 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3605 }
3606
3607 if ($stocktag == 1) {
3608 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3609 //$opt .= ' class="product_line_stock_ok"';
3610 }
3611 if ($stocktag == -1) {
3612 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3613 //$opt .= ' class="product_line_stock_too_low"';
3614 }
3615
3616 $opt .= '>';
3617
3618 // Ref, barcode, country
3619 $opt .= $labeltoshow;
3620 $outval .= $labeltoshowhtml;
3621
3622 // Units
3623 $opt .= $outvalUnits;
3624 $outval .= $outvalUnits;
3625
3626 // Price
3627 $opt .= $labeltoshowprice;
3628 $outval .= $labeltoshowhtmlprice;
3629
3630 // Stock
3631 $opt .= $labeltoshowstock;
3632 $outval .= $labeltoshowhtmlstock;
3633
3634
3635 $parameters = array('objp' => $objp);
3636 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3637 if (empty($reshook)) {
3638 $opt .= $hookmanager->resPrint;
3639 } else {
3640 $opt = $hookmanager->resPrint;
3641 }
3642
3643 $opt .= "</option>\n";
3644 $optJson = array(
3645 'key' => $outkey,
3646 'value' => $outref,
3647 'label' => $outval,
3648 'label2' => $outlabel,
3649 'desc' => $outdesc,
3650 'type' => $outtype,
3651 'price_ht' => price2num($outprice_ht),
3652 'price_ttc' => price2num($outprice_ttc),
3653 'price_ht_locale' => price(price2num($outprice_ht)),
3654 'price_ttc_locale' => price(price2num($outprice_ttc)),
3655 'pricebasetype' => $outpricebasetype,
3656 'tva_tx' => $outtva_tx,
3657 'default_vat_code' => $outdefault_vat_code,
3658 'qty' => $outqty,
3659 'discount' => $outdiscount,
3660 'duration_value' => $outdurationvalue,
3661 'duration_unit' => $outdurationunit,
3662 'pbq' => $outpbq,
3663 'labeltrans' => $outlabel_translated,
3664 'desctrans' => $outdesc_translated,
3665 'ref_customer' => $outrefcust
3666 );
3667 }
3668
3669 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3670
3686 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3687 {
3688 // phpcs:enable
3689 global $langs, $conf;
3690 global $price_level, $status, $finished;
3691
3692 if (!isset($status)) {
3693 $status = 1;
3694 }
3695
3696 $selected_input_value = '';
3697 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3698 if ($selected > 0) {
3699 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3700 $producttmpselect = new Product($this->db);
3701 $producttmpselect->fetch($selected);
3702 $selected_input_value = $producttmpselect->ref;
3703 unset($producttmpselect);
3704 }
3705
3706 // mode=2 means suppliers products
3707 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3708 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3709
3710 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3711 } else {
3712 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3713 }
3714 }
3715
3716 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3717
3736 public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '', $showstockinlist = 0, $placeholder = '')
3737 {
3738 // phpcs:enable
3739 global $langs, $conf, $user;
3740 global $hookmanager;
3741
3742 $out = '';
3743 $outarray = array();
3744
3745 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3746
3747 $langs->load('stocks');
3748 // Units
3749 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3750 $langs->load('other');
3751 }
3752
3753 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock, p.tva_tx as tva_tx_sale, p.default_vat_code as default_vat_code_sale,";
3754 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3755 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3756 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3757 $sql .= ", pfp.supplier_reputation";
3758 // if we use supplier description of the products
3759 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3760 $sql .= ", pfp.desc_fourn as description";
3761 } else {
3762 $sql .= ", p.description";
3763 }
3764 // Units
3765 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3766 $sql .= ", u.label as unit_long, u.short_label as unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units";
3767 }
3768 $sql .= " FROM " . $this->db->prefix() . "product as p";
3769 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3770 if ($socid > 0) {
3771 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3772 }
3773 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3774 // Units
3775 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3776 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3777 }
3778 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3779 if ($statut != -1) {
3780 $sql .= " AND p.tobuy = " . ((int) $statut);
3781 }
3782 if (strval($filtertype) != '') {
3783 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3784 }
3785 if (!empty($filtre)) {
3786 $sql .= " " . $filtre;
3787 }
3788 // Add where from hooks
3789 $parameters = array();
3790 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3791 $sql .= $hookmanager->resPrint;
3792 // Add criteria on ref/label
3793 if ($filterkey != '') {
3794 $sql .= ' AND (';
3795 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3796 // For natural search
3797 $search_crit = explode(' ', $filterkey);
3798 $i = 0;
3799 if (count($search_crit) > 1) {
3800 $sql .= "(";
3801 }
3802 foreach ($search_crit as $crit) {
3803 if ($i > 0) {
3804 $sql .= " AND ";
3805 }
3806 $sql .= "(pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3807 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3808 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3809 }
3810 $sql .= ")";
3811 $i++;
3812 }
3813 if (count($search_crit) > 1) {
3814 $sql .= ")";
3815 }
3816 if (isModEnabled('barcode')) {
3817 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3818 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3819 }
3820 $sql .= ')';
3821 }
3822 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3823 $sql .= $this->db->plimit($limit, 0);
3824
3825 // Build output string
3826
3827 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3828 $result = $this->db->query($sql);
3829 if ($result) {
3830 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3831 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3832
3833 $num = $this->db->num_rows($result);
3834
3835 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3836 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3837 if (!$selected) {
3838 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3839 } else {
3840 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3841 }
3842
3843 $i = 0;
3844 while ($i < $num) {
3845 $objp = $this->db->fetch_object($result);
3846
3847 if (is_null($objp->idprodfournprice)) {
3848 // There is no supplier price found, we will use the vat rate for sale
3849 $objp->tva_tx = $objp->tva_tx_sale;
3850 $objp->default_vat_code = $objp->default_vat_code_sale;
3851 }
3852
3853 $outkey = $objp->idprodfournprice; // id in table of price
3854 if (!$outkey && $alsoproductwithnosupplierprice) {
3855 $outkey = 'idprod_' . $objp->rowid; // id of product
3856 }
3857
3858 $outref = $objp->ref;
3859 $outbarcode = $objp->barcode;
3860 $outqty = 1;
3861 $outdiscount = 0;
3862 $outtype = $objp->fk_product_type;
3863 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3864 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3865
3866 // Units
3867 $outvalUnits = '';
3868 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3869 if (!empty($objp->unit_short)) {
3870 $outvalUnits .= ' - ' . $objp->unit_short;
3871 }
3872 if (!empty($objp->weight) && $objp->weight_units !== null) {
3873 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3874 $outvalUnits .= ' - ' . $unitToShow;
3875 }
3876 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3877 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3878 $outvalUnits .= ' - ' . $unitToShow;
3879 }
3880 if (!empty($objp->surface) && $objp->surface_units !== null) {
3881 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3882 $outvalUnits .= ' - ' . $unitToShow;
3883 }
3884 if (!empty($objp->volume) && $objp->volume_units !== null) {
3885 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3886 $outvalUnits .= ' - ' . $unitToShow;
3887 }
3888 if ($outdurationvalue && $outdurationunit) {
3889 $da = array(
3890 'h' => $langs->trans('Hour'),
3891 'd' => $langs->trans('Day'),
3892 'w' => $langs->trans('Week'),
3893 'm' => $langs->trans('Month'),
3894 'y' => $langs->trans('Year')
3895 );
3896 if (isset($da[$outdurationunit])) {
3897 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3898 }
3899 }
3900 }
3901
3902 $objRef = $objp->ref;
3903 if ($filterkey && $filterkey != '') {
3904 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3905 }
3906 $objRefFourn = $objp->ref_fourn;
3907 if ($filterkey && $filterkey != '') {
3908 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3909 }
3910 $label = $objp->label;
3911 if ($filterkey && $filterkey != '') {
3912 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3913 }
3914
3915 switch ($objp->fk_product_type) {
3917 $picto = 'product';
3918 break;
3920 $picto = 'service';
3921 break;
3922 default:
3923 $picto = '';
3924 break;
3925 }
3926
3927 if (empty($picto)) {
3928 $optlabel = '';
3929 } else {
3930 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3931 }
3932
3933 $optlabel .= $objp->ref;
3934 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3935 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3936 }
3937 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3938 $optlabel .= ' (' . $outbarcode . ')';
3939 }
3940 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3941
3942 $outvallabel = $objRef;
3943 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3944 $outvallabel .= ' (' . $objRefFourn . ')';
3945 }
3946 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3947 $outvallabel .= ' (' . $outbarcode . ')';
3948 }
3949 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3950
3951 // Units
3952 $optlabel .= $outvalUnits;
3953 $outvallabel .= $outvalUnits;
3954
3955 if (!empty($objp->idprodfournprice)) {
3956 $outqty = $objp->quantity;
3957 $outdiscount = $objp->remise_percent;
3958 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3959 $prod_supplier = new ProductFournisseur($this->db);
3960 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3961 $prod_supplier->id = $objp->fk_product;
3962 $prod_supplier->fourn_qty = $objp->quantity;
3963 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3964 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3965
3966 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3967 $priceparser = new PriceParser($this->db);
3968 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3969 if ($price_result >= 0) {
3970 $objp->fprice = $price_result;
3971 if ($objp->quantity >= 1) {
3972 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3973 }
3974 }
3975 }
3976 if ($objp->quantity == 1) {
3977 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3978 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3979 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3980 $outvallabel .= $langs->transnoentities("Unit");
3981 } else {
3982 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3983 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3984 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3985 $outvallabel .= ' ' . $langs->transnoentities("Units");
3986 }
3987
3988 if ($objp->quantity > 1) {
3989 $optlabel .= " (" . price($objp->unitprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3990 $outvallabel .= " (" . price($objp->unitprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3991 }
3992 if ($objp->remise_percent >= 1) {
3993 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3994 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3995 }
3996 if ($objp->duration) {
3997 $optlabel .= " - " . $objp->duration;
3998 $outvallabel .= " - " . $objp->duration;
3999 }
4000 if (!$socid) {
4001 $optlabel .= " - " . dol_trunc($objp->name, 8);
4002 $outvallabel .= " - " . dol_trunc($objp->name, 8);
4003 }
4004 if ($objp->supplier_reputation) {
4005 //TODO dictionary
4006 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
4007
4008 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
4009 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
4010 }
4011 } else {
4012 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
4013 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
4014 }
4015
4016 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
4017 $novirtualstock = ($showstockinlist == 2);
4018
4019 if ($user->hasRight('stock', 'lire')) {
4020 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
4021
4022 if ($objp->stock > 0) {
4023 $optlabel .= ' - <span class="product_line_stock_ok">';
4024 } elseif ($objp->stock <= 0) {
4025 $optlabel .= ' - <span class="product_line_stock_too_low">';
4026 }
4027 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
4028 $optlabel .= '</span>';
4029 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
4030 $langs->load("stocks");
4031
4032 $tmpproduct = new Product($this->db);
4033 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
4034 $tmpproduct->load_virtual_stock();
4035 $virtualstock = $tmpproduct->stock_theorique;
4036
4037 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4038
4039 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4040 if ($virtualstock > 0) {
4041 $optlabel .= '<span class="product_line_stock_ok">';
4042 } elseif ($virtualstock <= 0) {
4043 $optlabel .= '<span class="product_line_stock_too_low">';
4044 }
4045 $optlabel .= $virtualstock;
4046 $optlabel .= '</span>';
4047
4048 unset($tmpproduct);
4049 }
4050 }
4051 }
4052
4053 $optstart = '<option value="' . $outkey . '"';
4054 if ($selected && $selected == $objp->idprodfournprice) {
4055 $optstart .= ' selected';
4056 }
4057 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4058 $optstart .= ' disabled';
4059 }
4060
4061 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4062 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4063 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4064 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4065 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
4066 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
4067 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
4068 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
4069 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
4070 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4071 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4072 if (isModEnabled('multicurrency')) {
4073 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4074 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
4075 }
4076 }
4077 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4078
4079 // set $parameters to call hook
4080 $outarrayentry = array(
4081 'key' => $outkey,
4082 'value' => $outref,
4083 'label' => $outvallabel,
4084 'labelhtml' => $optlabel,
4085 'qty' => $outqty,
4086 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4087 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4088 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4089 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4090 'tva_tx' => price2num($objp->tva_tx),
4091 'default_vat_code' => $objp->default_vat_code,
4092 'supplier_ref' => $objp->ref_fourn,
4093 'discount' => $outdiscount,
4094 'type' => $outtype,
4095 'duration_value' => $outdurationvalue,
4096 'duration_unit' => $outdurationunit,
4097 'disabled' => empty($objp->idprodfournprice),
4098 'description' => $objp->description
4099 );
4100 if (isModEnabled('multicurrency')) {
4101 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4102 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4103 }
4104 $parameters = array(
4105 'objp' => &$objp,
4106 'optstart' => &$optstart,
4107 'optlabel' => &$optlabel,
4108 'outvallabel' => &$outvallabel,
4109 'outarrayentry' => &$outarrayentry,
4110 'fk_soc' => $socid
4111 );
4112 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4113
4114
4115 // Add new entry
4116 // "key" value of json key array is used by jQuery automatically as selected value. Example: 'type' = product or service, 'price_ht' = unit price without tax
4117 // "label" value of json key array is used by jQuery automatically as text for combo box
4118 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4119 $outarraypush = array(
4120 'key' => $outkey,
4121 'value' => $outref,
4122 'label' => $outvallabel,
4123 'labelhtml' => $optlabel,
4124 'qty' => $outqty,
4125 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4126 'price_qty_ht_locale' => price($objp->fprice),
4127 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4128 'price_unit_ht_locale' => price($objp->unitprice),
4129 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4130 'tva_tx_formated' => price($objp->tva_tx),
4131 'tva_tx' => price2num($objp->tva_tx),
4132 'default_vat_code' => $objp->default_vat_code,
4133 'supplier_ref' => $objp->ref_fourn,
4134 'discount' => $outdiscount,
4135 'type' => $outtype,
4136 'duration_value' => $outdurationvalue,
4137 'duration_unit' => $outdurationunit,
4138 'disabled' => empty($objp->idprodfournprice),
4139 'description' => $objp->description
4140 );
4141 if (isModEnabled('multicurrency')) {
4142 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4143 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4144 }
4145 array_push($outarray, $outarraypush);
4146
4147 // Example of var_dump $outarray
4148 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4149 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4150 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4151 //}
4152 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4153 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4154 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4155
4156 $i++;
4157 }
4158 $out .= '</select>';
4159
4160 $this->db->free($result);
4161
4162 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4163 $out .= ajax_combobox($htmlname);
4164 } else {
4165 dol_print_error($this->db);
4166 }
4167
4168 if (empty($outputmode)) {
4169 return $out;
4170 }
4171 return $outarray;
4172 }
4173
4174 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4175
4184 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4185 {
4186 // phpcs:enable
4187 global $langs, $conf;
4188
4189 $langs->load('stocks');
4190
4191 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4192 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4193 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4194 $sql .= " FROM " . $this->db->prefix() . "product as p";
4195 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4196 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4197 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4198 $sql .= " AND p.tobuy = 1";
4199 $sql .= " AND s.fournisseur = 1";
4200 $sql .= " AND p.rowid = " . ((int) $productid);
4201 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4202 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4203 } else {
4204 $sql .= " ORDER BY pfp.unitprice ASC";
4205 }
4206
4207 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4208 $result = $this->db->query($sql);
4209
4210 if ($result) {
4211 $num = $this->db->num_rows($result);
4212
4213 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4214
4215 if (!$num) {
4216 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4217 } else {
4218 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4219 $form .= '<option value="0">&nbsp;</option>';
4220
4221 $i = 0;
4222 while ($i < $num) {
4223 $objp = $this->db->fetch_object($result);
4224
4225 $opt = '<option value="' . $objp->idprodfournprice . '"';
4226 //if there is only one supplier, preselect it
4227 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4228 $opt .= ' selected';
4229 }
4230 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4231
4232 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4233 $prod_supplier = new ProductFournisseur($this->db);
4234 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4235 $prod_supplier->id = $productid;
4236 $prod_supplier->fourn_qty = $objp->quantity;
4237 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4238 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4239
4240 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4241 $priceparser = new PriceParser($this->db);
4242 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4243 if ($price_result >= 0) {
4244 $objp->fprice = $price_result;
4245 if ($objp->quantity >= 1) {
4246 $objp->unitprice = $objp->fprice / $objp->quantity;
4247 }
4248 }
4249 }
4250 if ($objp->quantity == 1) {
4251 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4252 }
4253
4254 $opt .= $objp->quantity . ' ';
4255
4256 if ($objp->quantity == 1) {
4257 $opt .= $langs->trans("Unit");
4258 } else {
4259 $opt .= $langs->trans("Units");
4260 }
4261 if ($objp->quantity > 1) {
4262 $opt .= " - ";
4263 $opt .= price($objp->unitprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit");
4264 }
4265 if ($objp->duration) {
4266 $opt .= " - " . $objp->duration;
4267 }
4268 $opt .= "</option>\n";
4269
4270 $form .= $opt;
4271 $i++;
4272 }
4273 }
4274
4275 $form .= '</select>';
4276 $this->db->free($result);
4277 return $form;
4278 } else {
4279 dol_print_error($this->db);
4280 return '';
4281 }
4282 }
4283
4284
4285 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4292 {
4293 // phpcs:enable
4294 global $langs;
4295
4296 $num = count($this->cache_conditions_paiements);
4297 if ($num > 0) {
4298 return 0; // Cache already loaded
4299 }
4300
4301 dol_syslog(__METHOD__, LOG_DEBUG);
4302
4303 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4304 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4305 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4306 $sql .= " AND active > 0";
4307 $sql .= " ORDER BY sortorder";
4308
4309 $resql = $this->db->query($sql);
4310 if ($resql) {
4311 $num = $this->db->num_rows($resql);
4312 $i = 0;
4313 while ($i < $num) {
4314 $obj = $this->db->fetch_object($resql);
4315
4316 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4317 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4318 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4319 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4320 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4321 $i++;
4322 }
4323
4324 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4325
4326 return $num;
4327 } else {
4328 dol_print_error($this->db);
4329 return -1;
4330 }
4331 }
4332
4333 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4334
4340 public function load_cache_availability()
4341 {
4342 // phpcs:enable
4343 global $langs;
4344
4345 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4346 if ($num > 0) {
4347 return 0; // Cache already loaded
4348 }
4349
4350 dol_syslog(__METHOD__, LOG_DEBUG);
4351
4352 $langs->load('propal');
4353
4354 $sql = "SELECT rowid, code, label, position";
4355 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4356 $sql .= " WHERE active > 0";
4357
4358 $resql = $this->db->query($sql);
4359 if ($resql) {
4360 $num = $this->db->num_rows($resql);
4361 $i = 0;
4362 while ($i < $num) {
4363 $obj = $this->db->fetch_object($resql);
4364
4365 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4366 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4367 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4368 $this->cache_availability[$obj->rowid]['label'] = $label;
4369 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4370 $i++;
4371 }
4372
4373 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4374
4375 return $num;
4376 } else {
4377 dol_print_error($this->db);
4378 return -1;
4379 }
4380 }
4381
4392 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4393 {
4394 global $langs, $user;
4395
4396 $this->load_cache_availability();
4397
4398 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4399
4400 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4401 if ($addempty) {
4402 print '<option value="0">&nbsp;</option>';
4403 }
4404 foreach ($this->cache_availability as $id => $arrayavailability) {
4405 if ($selected == $id) {
4406 print '<option value="' . $id . '" selected>';
4407 } else {
4408 print '<option value="' . $id . '">';
4409 }
4410 print dol_escape_htmltag($arrayavailability['label']);
4411 print '</option>';
4412 }
4413 print '</select>';
4414 if ($user->admin) {
4415 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4416 }
4417 print ajax_combobox($htmlname);
4418 }
4419
4425 public function loadCacheInputReason()
4426 {
4427 global $langs;
4428
4429 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4430 if ($num > 0) {
4431 return 0; // Cache already loaded
4432 }
4433
4434 $sql = "SELECT rowid, code, label";
4435 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4436 $sql .= " WHERE active > 0";
4437
4438 $resql = $this->db->query($sql);
4439 if ($resql) {
4440 $num = $this->db->num_rows($resql);
4441 $i = 0;
4442 $tmparray = array();
4443 while ($i < $num) {
4444 $obj = $this->db->fetch_object($resql);
4445
4446 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4447 $label = ($obj->label != '-' ? $obj->label : '');
4448 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4449 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4450 }
4451 if ($langs->trans($obj->code) != $obj->code) {
4452 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4453 }
4454
4455 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4456 $tmparray[$obj->rowid]['code'] = $obj->code;
4457 $tmparray[$obj->rowid]['label'] = $label;
4458 $i++;
4459 }
4460
4461 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4462
4463 unset($tmparray);
4464 return $num;
4465 } else {
4466 dol_print_error($this->db);
4467 return -1;
4468 }
4469 }
4470
4483 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4484 {
4485 global $langs, $user;
4486
4487 $this->loadCacheInputReason();
4488
4489 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4490 if ($addempty) {
4491 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4492 }
4493 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4494 if ($arraydemandreason['code'] == $exclude) {
4495 continue;
4496 }
4497
4498 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4499 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4500 } else {
4501 print '<option value="' . $arraydemandreason['id'] . '">';
4502 }
4503 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4504 print $langs->trans($label);
4505 print '</option>';
4506 }
4507 print '</select>';
4508 if ($user->admin && empty($notooltip)) {
4509 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4510 }
4511 print ajax_combobox('select_' . $htmlname);
4512 }
4513
4514 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4515
4522 {
4523 // phpcs:enable
4524 global $langs;
4525
4526 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4527 if ($num > 0) {
4528 return $num; // Cache already loaded
4529 }
4530
4531 dol_syslog(__METHOD__, LOG_DEBUG);
4532
4533 $this->cache_types_paiements = array();
4534
4535 $sql = "SELECT id, code, libelle as label, type, active";
4536 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4537 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4538
4539 $resql = $this->db->query($sql);
4540 if ($resql) {
4541 $num = $this->db->num_rows($resql);
4542 $i = 0;
4543 while ($i < $num) {
4544 $obj = $this->db->fetch_object($resql);
4545
4546 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4547 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4548 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4549 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4550 $this->cache_types_paiements[$obj->id]['label'] = $label;
4551 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4552 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4553 $i++;
4554 }
4555
4556 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4557
4558 return $num;
4559 } else {
4560 dol_print_error($this->db);
4561 return -1;
4562 }
4563 }
4564
4565
4566 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4567
4586 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4587 {
4588 // phpcs:enable
4589 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4590 if (empty($noprint)) {
4591 print $out;
4592 } else {
4593 return $out;
4594 }
4595 }
4596
4597
4614 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4615 {
4616 global $langs, $user, $conf;
4617
4618 $out = '';
4619 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4620
4622
4623 // Set default value if not already set by caller
4624 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4625 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4626 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4627 }
4628
4629 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4630 if ($addempty) {
4631 $out .= '<option value="0">&nbsp;</option>';
4632 }
4633
4634 $selectedDepositPercent = null;
4635
4636 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4637 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4638 continue;
4639 }
4640
4641 if ($selected == $id) {
4642 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4643 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4644 } else {
4645 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4646 }
4647 $label = $arrayconditions['label'];
4648
4649 if (!empty($arrayconditions['deposit_percent'])) {
4650 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4651 }
4652
4653 $out .= $label;
4654 $out .= '</option>';
4655 }
4656 $out .= '</select>';
4657 if ($user->admin && empty($noinfoadmin)) {
4658 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4659 }
4660 $out .= ajax_combobox($htmlname);
4661
4662 if ($deposit_percent >= 0) {
4663 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4664 $out .= $langs->trans('DepositPercent') . ' : ';
4665 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4666 $out .= '</span>';
4667 $out .= '
4668 <script nonce="' . getNonce() . '">
4669 $(document).ready(function () {
4670 $("#' . $htmlname . '").change(function () {
4671 let $selected = $(this).find("option:selected");
4672 let depositPercent = $selected.attr("data-deposit_percent");
4673
4674 if (depositPercent.length > 0) {
4675 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4676 } else {
4677 $("#' . $htmlname . '_deposit_percent_container").hide();
4678 }
4679
4680 return true;
4681 });
4682 });
4683 </script>';
4684 }
4685
4686 return $out;
4687 }
4688
4689
4690 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4691
4708 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4709 {
4710 // phpcs:enable
4711 global $langs, $user, $conf;
4712
4713 $out = '';
4714
4715 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4716
4717 $filterarray = array();
4718 if ($filtertype == 'CRDT') {
4719 $filterarray = array(0, 2, 3);
4720 } elseif ($filtertype == 'DBIT') {
4721 $filterarray = array(1, 2, 3);
4722 } elseif ($filtertype != '' && $filtertype != '-1') {
4723 $filterarray = explode(',', $filtertype);
4724 }
4725
4727
4728 // Set default value if not already set by caller
4729 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4730 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4731 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4732 }
4733
4734 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4735 if ($empty) {
4736 $out .= '<option value="">&nbsp;</option>';
4737 }
4738 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4739 // If not good status
4740 if ($active >= 0 && $arraytypes['active'] != $active) {
4741 continue;
4742 }
4743
4744 // We skip of the user requested to filter on specific payment methods
4745 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4746 continue;
4747 }
4748
4749 // We discard empty lines if showempty is on because an empty line has already been output.
4750 if ($empty && empty($arraytypes['code'])) {
4751 continue;
4752 }
4753
4754 if ($format == 0) {
4755 $out .= '<option value="' . $id . '" data-code="'.$arraytypes['code'].'"';
4756 } elseif ($format == 1) {
4757 $out .= '<option value="' . $arraytypes['code'] . '"';
4758 } elseif ($format == 2) {
4759 $out .= '<option value="' . $arraytypes['code'] . '"';
4760 } elseif ($format == 3) {
4761 $out .= '<option value="' . $id . '"';
4762 }
4763 // Print attribute selected or not
4764 if ($format == 1 || $format == 2) {
4765 if ($selected == $arraytypes['code']) {
4766 $out .= ' selected';
4767 }
4768 } else {
4769 if ($selected == $id) {
4770 $out .= ' selected';
4771 }
4772 }
4773 $out .= '>';
4774 $value = '';
4775 if ($format == 0) {
4776 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4777 } elseif ($format == 1) {
4778 $value = $arraytypes['code'];
4779 } elseif ($format == 2) {
4780 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4781 } elseif ($format == 3) {
4782 $value = $arraytypes['code'];
4783 }
4784 $out .= $value ? $value : '&nbsp;';
4785 $out .= '</option>';
4786 }
4787 $out .= '</select>';
4788 if ($user->admin && !$noadmininfo) {
4789 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4790 }
4791 $out .= ajax_combobox('select' . $htmlname);
4792
4793 if (empty($nooutput)) {
4794 print $out;
4795 } else {
4796 return $out;
4797 }
4798 }
4799
4800
4809 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4810 {
4811 global $langs;
4812
4813 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4814 $options = array(
4815 'HT' => $langs->trans("HT"),
4816 'TTC' => $langs->trans("TTC")
4817 );
4818 foreach ($options as $id => $value) {
4819 if ($selected == $id) {
4820 $return .= '<option value="' . $id . '" selected>' . $value;
4821 } else {
4822 $return .= '<option value="' . $id . '">' . $value;
4823 }
4824 $return .= '</option>';
4825 }
4826 $return .= '</select>';
4827 if ($addjscombo) {
4828 $return .= ajax_combobox('select_' . $htmlname);
4829 }
4830
4831 return $return;
4832 }
4833
4834 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4835
4842 {
4843 // phpcs:enable
4844 global $langs;
4845
4846 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4847 if ($num > 0) {
4848 return $num; // Cache already loaded
4849 }
4850
4851 dol_syslog(__METHOD__, LOG_DEBUG);
4852
4853 $this->cache_transport_mode = array();
4854
4855 $sql = "SELECT rowid, code, label, active";
4856 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4857 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4858
4859 $resql = $this->db->query($sql);
4860 if ($resql) {
4861 $num = $this->db->num_rows($resql);
4862 $i = 0;
4863 while ($i < $num) {
4864 $obj = $this->db->fetch_object($resql);
4865
4866 // If traduction exist, we use it else we take the default label
4867 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4868 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4869 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4870 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4871 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4872 $i++;
4873 }
4874
4875 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4876
4877 return $num;
4878 } else {
4879 dol_print_error($this->db);
4880 return -1;
4881 }
4882 }
4883
4897 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4898 {
4899 global $langs, $user;
4900
4901 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4902
4904
4905 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4906 if ($empty) {
4907 print '<option value="">&nbsp;</option>';
4908 }
4909 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4910 // If not good status
4911 if ($active >= 0 && $arraytypes['active'] != $active) {
4912 continue;
4913 }
4914
4915 // We discard empty line if showempty is on because an empty line has already been output.
4916 if ($empty && empty($arraytypes['code'])) {
4917 continue;
4918 }
4919
4920 if ($format == 0) {
4921 print '<option value="' . $id . '"';
4922 } elseif ($format == 1) {
4923 print '<option value="' . $arraytypes['code'] . '"';
4924 } elseif ($format == 2) {
4925 print '<option value="' . $arraytypes['code'] . '"';
4926 } elseif ($format == 3) {
4927 print '<option value="' . $id . '"';
4928 }
4929 // If text is selected, we compare with code, else with id
4930 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4931 print ' selected';
4932 } elseif ($selected == $id) {
4933 print ' selected';
4934 }
4935 print '>';
4936 $value = '';
4937 if ($format == 0) {
4938 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4939 } elseif ($format == 1) {
4940 $value = $arraytypes['code'];
4941 } elseif ($format == 2) {
4942 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4943 } elseif ($format == 3) {
4944 $value = $arraytypes['code'];
4945 }
4946 print $value ? $value : '&nbsp;';
4947 print '</option>';
4948 }
4949 print '</select>';
4950
4951 print ajax_combobox("select".$htmlname);
4952
4953 if ($user->admin && !$noadmininfo) {
4954 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4955 }
4956 }
4957
4970 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4971 {
4972 global $langs, $user;
4973
4974 $langs->load("admin");
4975 $langs->load("deliveries");
4976
4977 $sql = "SELECT rowid, code, libelle as label";
4978 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4979 $sql .= " WHERE active > 0";
4980 if ($filtre) {
4981 $sql .= " AND " . $filtre;
4982 }
4983 $sql .= " ORDER BY libelle ASC";
4984
4985 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4986 $result = $this->db->query($sql);
4987 if ($result) {
4988 $num = $this->db->num_rows($result);
4989 $i = 0;
4990 if ($num) {
4991 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4992 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4993 print '<option value="-1">&nbsp;</option>';
4994 }
4995 while ($i < $num) {
4996 $obj = $this->db->fetch_object($result);
4997 if ($selected == $obj->rowid) {
4998 print '<option value="' . $obj->rowid . '" selected>';
4999 } else {
5000 print '<option value="' . $obj->rowid . '">';
5001 }
5002 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
5003 print '</option>';
5004 $i++;
5005 }
5006 print "</select>";
5007 if ($user->admin && empty($noinfoadmin)) {
5008 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5009 }
5010
5011 print ajax_combobox('select' . $htmlname);
5012 } else {
5013 print $langs->trans("NoShippingMethodDefined");
5014 }
5015 } else {
5016 dol_print_error($this->db);
5017 }
5018 }
5019
5029 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
5030 {
5031 global $langs;
5032
5033 $langs->load("deliveries");
5034
5035 if ($htmlname != "none") {
5036 print '<form method="POST" action="' . $page . '">';
5037 print '<input type="hidden" name="action" value="setshippingmethod">';
5038 print '<input type="hidden" name="token" value="' . newToken() . '">';
5039 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5040 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5041 print '</form>';
5042 } else {
5043 if ($selected) {
5044 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5045 print $langs->trans("SendingMethod" . strtoupper($code));
5046 } else {
5047 print "&nbsp;";
5048 }
5049 }
5050 }
5051
5060 public function selectSituationInvoices($selected = '', $socid = 0)
5061 {
5062 global $langs;
5063
5064 $langs->load('bills');
5065
5066 $opt = '<option value="" selected></option>';
5067 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5068 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5069 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5070 $sql .= ' AND situation_counter >= 1';
5071 $sql .= ' AND fk_soc = ' . (int) $socid;
5072 $sql .= ' AND type <> 2';
5073 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5074 $resql = $this->db->query($sql);
5075
5076 if ($resql && $this->db->num_rows($resql) > 0) {
5077 // Last seen cycle
5078 $ref = 0;
5079 while ($obj = $this->db->fetch_object($resql)) {
5080 //Same cycle ?
5081 if ($obj->situation_cycle_ref != $ref) {
5082 // Just seen this cycle
5083 $ref = $obj->situation_cycle_ref;
5084 //not final ?
5085 if ($obj->situation_final != 1) {
5086 //Not prov?
5087 if (substr($obj->ref, 1, 4) != 'PROV') {
5088 if ($selected == $obj->rowid) {
5089 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5090 } else {
5091 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5092 }
5093 }
5094 }
5095 }
5096 }
5097 } else {
5098 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5099 }
5100 if ($opt == '<option value ="" selected></option>') {
5101 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5102 }
5103 return $opt;
5104 }
5105
5115 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5116 {
5117 global $langs;
5118
5119 $langs->load('products');
5120
5121 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5122
5123 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5124 $sql .= ' WHERE active > 0';
5125 if (!empty($unit_type)) {
5126 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5127 }
5128 $sql .= " ORDER BY sortorder";
5129
5130 $resql = $this->db->query($sql);
5131 if ($resql && $this->db->num_rows($resql) > 0) {
5132 if ($showempty) {
5133 $return .= '<option value="-1"></option>';
5134 }
5135
5136 while ($res = $this->db->fetch_object($resql)) {
5137 $unitLabel = $res->label;
5138 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5139 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5140 }
5141
5142 if ($selected == $res->rowid) {
5143 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5144 } else {
5145 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5146 }
5147 }
5148 $return .= '</select>';
5149
5150 $return .= ajax_combobox($htmlname);
5151 }
5152 return $return;
5153 }
5154
5155 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5156
5171 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5172 {
5173 // phpcs:enable
5174 global $langs;
5175
5176 $out = '';
5177
5178 $langs->loadLangs(array("admin", "banks"));
5179 $num = 0;
5180
5181 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5182 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5183 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5184 if ($status != 2) {
5185 $sql .= " AND clos = " . (int) $status;
5186 }
5187 if ($filtre) { // TODO Support USF
5188 $sql .= " AND " . $filtre;
5189 }
5190 $sql .= " ORDER BY label";
5191
5192 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5193 $result = $this->db->query($sql);
5194 if ($result) {
5195 $num = $this->db->num_rows($result);
5196 $i = 0;
5197
5198 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5199
5200 if ($num == 0) {
5201 if ($status == 0) {
5202 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5203 } else {
5204 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5205 }
5206 } else {
5207 if (!empty($useempty) && !is_numeric($useempty)) {
5208 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5209 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5210 $out .= '<option value="-1">&nbsp;</option>';
5211 }
5212 }
5213
5214 while ($i < $num) {
5215 $obj = $this->db->fetch_object($result);
5216
5217 $labeltoshow = trim($obj->label);
5218 $labeltoshowhtml = trim($obj->label);
5219 if ($showcurrency) {
5220 $labeltoshow .= ' (' . $obj->currency_code . ')';
5221 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5222 }
5223 if ($status == 2 && $obj->status == 1) {
5224 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5225 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5226 }
5227
5228 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5229 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5230 } else {
5231 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5232 }
5233 $out .= $labeltoshow;
5234 $out .= '</option>';
5235 $i++;
5236 }
5237 $out .= "</select>";
5238 $out .= ajax_combobox('select' . $htmlname);
5239 } else {
5240 dol_print_error($this->db);
5241 }
5242
5243 // Output or return
5244 if (empty($nooutput)) {
5245 print $out;
5246 } else {
5247 return $out;
5248 }
5249
5250 return $num;
5251 }
5252
5266 public function selectRib($selected = '', $htmlname = 'ribcompanyid', $filtre = '', $useempty = 0, $moreattrib = '', $showibanbic = 0, $morecss = '', $nooutput = 0)
5267 {
5268 // phpcs:enable
5269 global $langs;
5270
5271 $out = '';
5272
5273 $langs->loadLangs(array("admin", "banks"));
5274 $num = 0;
5275
5276 $sql = "SELECT rowid, label, bank, status, iban_prefix, bic";
5277 $sql .= " FROM " . $this->db->prefix() . "societe_rib";
5278 $sql.= " WHERE type = 'ban'";
5279 if ($filtre) { // TODO Support USF
5280 $sql .= " AND " . $filtre;
5281 }
5282 $sql .= " ORDER BY label";
5283 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5284 $result = $this->db->query($sql);
5285 if ($result) {
5286 $num = $this->db->num_rows($result);
5287 $i = 0;
5288
5289 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5290
5291 if ($num == 0) {
5292 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5293 } else {
5294 if (!empty($useempty) && !is_numeric($useempty)) {
5295 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5296 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5297 $out .= '<option value="-1">&nbsp;</option>';
5298 }
5299 }
5300
5301 while ($i < $num) {
5302 $obj = $this->db->fetch_object($result);
5303 $iban = dolDecrypt($obj->iban_prefix);
5304 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5305 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '" selected>';
5306 } else {
5307 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '">';
5308 }
5309 $out .= trim($obj->label);
5310 if ($showibanbic) {
5311 $out .= ' (' . $iban . '/' .$obj->bic. ')';
5312 }
5313 $out .= '</option>';
5314 $i++;
5315 }
5316 $out .= "</select>";
5317 $out .= ajax_combobox('select' . $htmlname);
5318 } else {
5319 dol_print_error($this->db);
5320 }
5321
5322 // Output or return
5323 if (empty($nooutput)) {
5324 print $out;
5325 } else {
5326 return $out;
5327 }
5328
5329 return $num;
5330 }
5331
5343 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5344 {
5345 global $langs;
5346
5347 $langs->load("admin");
5348 $num = 0;
5349
5350 $sql = "SELECT rowid, name, fk_country, status, entity";
5351 $sql .= " FROM " . $this->db->prefix() . "establishment";
5352 $sql .= " WHERE 1=1";
5353 if ($status != 2) {
5354 $sql .= " AND status = " . (int) $status;
5355 }
5356 if ($filtre) { // TODO Support USF
5357 $sql .= " AND " . $filtre;
5358 }
5359 $sql .= " ORDER BY name";
5360
5361 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5362 $result = $this->db->query($sql);
5363 if ($result) {
5364 $num = $this->db->num_rows($result);
5365 $i = 0;
5366 if ($num) {
5367 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5368 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5369 print '<option value="-1">&nbsp;</option>';
5370 }
5371
5372 while ($i < $num) {
5373 $obj = $this->db->fetch_object($result);
5374 if ($selected == $obj->rowid) {
5375 print '<option value="' . $obj->rowid . '" selected>';
5376 } else {
5377 print '<option value="' . $obj->rowid . '">';
5378 }
5379 print trim($obj->name);
5380 if ($status == 2 && $obj->status == 1) {
5381 print ' (' . $langs->trans("Closed") . ')';
5382 }
5383 print '</option>';
5384 $i++;
5385 }
5386 print "</select>";
5387 } else {
5388 if ($status == 0) {
5389 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5390 } else {
5391 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5392 }
5393 }
5394
5395 return $num;
5396 } else {
5397 dol_print_error($this->db);
5398 return -1;
5399 }
5400 }
5401
5411 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5412 {
5413 global $langs;
5414 if ($htmlname != "none") {
5415 print '<form method="POST" action="' . $page . '">';
5416 print '<input type="hidden" name="action" value="setbankaccount">';
5417 print '<input type="hidden" name="token" value="' . newToken() . '">';
5418 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5419 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5420 if ($nbaccountfound > 0) {
5421 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5422 }
5423 print '</form>';
5424 } else {
5425 $langs->load('banks');
5426
5427 if ($selected) {
5428 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5429 $bankstatic = new Account($this->db);
5430 $result = $bankstatic->fetch($selected);
5431 if ($result) {
5432 print $bankstatic->getNomUrl(1);
5433 }
5434 } else {
5435 print "&nbsp;";
5436 }
5437 }
5438 }
5439
5451 public function formRib($page, $selected = '', $htmlname = 'ribcompanyid', $filtre = '', $addempty = 0, $showibanbic = 0)
5452 {
5453 global $langs;
5454 if ($htmlname != "none") {
5455 print '<form method="POST" action="' . $page . '">';
5456 print '<input type="hidden" name="action" value="setbankaccountcustomer">';
5457 print '<input type="hidden" name="token" value="' . newToken() . '">';
5458 $nbaccountfound = $this->selectRib($selected, $htmlname, $filtre, $addempty, '', $showibanbic);
5459 if ($nbaccountfound > 0) {
5460 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5461 }
5462 print '</form>';
5463 } else {
5464 $langs->load('banks');
5465
5466 if ($selected) {
5467 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
5468 $bankstatic = new CompanyBankAccount($this->db);
5469 $result = $bankstatic->fetch($selected);
5470 if ($result) {
5471 print $bankstatic->label;
5472 if ($showibanbic) print ' (' . $bankstatic->iban . '/' .$bankstatic->bic. ')';
5473 }
5474 } else {
5475 print "&nbsp;";
5476 }
5477 }
5478 }
5479
5480 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5481
5501 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5502 {
5503 // phpcs:enable
5504 global $conf, $langs;
5505 $langs->load("categories");
5506
5507 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5508
5509 // For backward compatibility
5510 if (is_numeric($type)) {
5511 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5512 }
5513
5514 if ($type === Categorie::TYPE_BANK_LINE) {
5515 // TODO Move this into common category feature after migration of llx_category_bankline into llx_categorie_bankline
5516 $cat = new Categorie($this->db);
5517 $cate_arbo = array();
5518 $sql = "SELECT c.label, c.rowid";
5519 $sql .= " FROM " . $this->db->prefix() . "categorie as c";
5520 $sql .= " WHERE entity = " . $conf->entity . " AND type = " . ((int) $cat->getMapId()[$type]);
5521 $sql .= " ORDER BY c.label";
5522 $result = $this->db->query($sql);
5523 if ($result) {
5524 $num = $this->db->num_rows($result);
5525 $i = 0;
5526 while ($i < $num) {
5527 $objp = $this->db->fetch_object($result);
5528 if ($objp) {
5529 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5530 }
5531 $i++;
5532 }
5533 $this->db->free($result);
5534 } else {
5535 dol_print_error($this->db);
5536 }
5537 } else {
5538 $cat = new Categorie($this->db);
5539 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5540 }
5541
5542 $outarray = array();
5543 $outarrayrichhtml = array();
5544
5545
5546 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5547 if (is_array($cate_arbo)) {
5548 $num = count($cate_arbo);
5549
5550 if (!$num) {
5551 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5552 } else {
5553 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5554 $output .= '<option value="-1">&nbsp;</option>';
5555 }
5556 foreach ($cate_arbo as $key => $value) {
5557 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5558 $add = 'selected ';
5559 } else {
5560 $add = '';
5561 }
5562
5563 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5564 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5565
5566 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5567
5568 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5569
5570 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5571 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5572 $output .= '>';
5573 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5574 $output .= '</option>';
5575
5576 $cate_arbo[$key]['data-html'] = $labeltoshow;
5577 }
5578 }
5579 }
5580 $output .= '</select>';
5581 $output .= "\n";
5582
5583 if ($outputmode == 2) {
5584 // TODO: handle error when $cate_arbo is not an array
5585 return $cate_arbo;
5586 } elseif ($outputmode == 1) {
5587 return $outarray;
5588 } elseif ($outputmode == 3) {
5589 return $outarrayrichhtml;
5590 }
5591 return $output;
5592 }
5593
5594 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5595
5614 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5615 {
5616 // phpcs:enable
5617 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5618 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5619 }
5620
5648 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5649 {
5650 global $langs, $conf;
5651
5652 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5653 $formconfirm = '';
5654 $inputok = array();
5655 $inputko = array();
5656
5657 // Clean parameters
5658 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5659 if ($conf->browser->layout == 'phone') {
5660 $width = '95%';
5661 }
5662
5663 // Set height automatically if not defined
5664 if (empty($height)) {
5665 $height = 220;
5666 if (is_array($formquestion) && count($formquestion) > 2) {
5667 $height += ((count($formquestion) - 2) * 24);
5668 }
5669 }
5670
5671 if (is_array($formquestion) && !empty($formquestion)) {
5672 // First add hidden fields and value
5673 foreach ($formquestion as $key => $input) {
5674 if (is_array($input) && !empty($input)) {
5675 if ($input['type'] == 'hidden') {
5676 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5677 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5678
5679 $more .= '<input type="hidden" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '" value="' . dol_escape_htmltag($input['value']) . '" class="' . $morecss . '"' . $moreattr . '>' . "\n";
5680 }
5681 }
5682 }
5683
5684 // Now add questions
5685 $moreonecolumn = '';
5686 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5687 foreach ($formquestion as $key => $input) {
5688 if (is_array($input) && !empty($input)) {
5689 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5690 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5691 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5692
5693 if ($input['type'] == 'text') {
5694 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div><div class="tagtd"><input type="text" class="flat' . $morecss . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $size . ' value="' . (empty($input['value']) ? '' : $input['value']) . '"' . $moreattr . ' /></div></div>' . "\n";
5695 } elseif ($input['type'] == 'password') {
5696 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div><div class="tagtd"><input type="password" class="flat' . $morecss . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $size . ' value="' . (empty($input['value']) ? '' : $input['value']) . '"' . $moreattr . ' /></div></div>' . "\n";
5697 } elseif ($input['type'] == 'textarea') {
5698 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5699 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5700 $more .= $input['value'];
5701 $more .= '</textarea>';
5702 $more .= '</div></div>'."\n";*/
5703 $moreonecolumn .= '<div class="margintoponly">';
5704 $moreonecolumn .= $input['label'] . '<br>';
5705 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5706 $moreonecolumn .= $input['value'];
5707 $moreonecolumn .= '</textarea>';
5708 $moreonecolumn .= '</div>';
5709 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5710 if (empty($morecss)) {
5711 $morecss = 'minwidth100';
5712 }
5713
5714 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5715 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5716 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5717 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5718 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5719 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5720 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5721
5722 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5723 if (!empty($input['label'])) {
5724 $more .= $input['label'] . '</div><div class="tagtd left">';
5725 }
5726 if ($input['type'] == 'select') {
5727 $more .= $this->selectarray($input['name'], $input['values'], isset($input['default']) ? $input['default'] : '-1', $show_empty, $key_in_label, $value_as_key, $moreattr, $translate, $maxlen, $disabled, $sort, $morecss);
5728 } else {
5729 $more .= $this->multiselectarray($input['name'], $input['values'], is_array($input['default']) ? $input['default'] : [$input['default']], $key_in_label, $value_as_key, $morecss, $translate, $maxlen, $moreattr);
5730 }
5731 $more .= '</div></div>' . "\n";
5732 } elseif ($input['type'] == 'checkbox') {
5733 $more .= '<div class="tagtr">';
5734 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5735 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5736 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5737 $more .= ' checked';
5738 }
5739 if (is_bool($input['value']) && $input['value']) {
5740 $more .= ' checked';
5741 }
5742 if (isset($input['disabled'])) {
5743 $more .= ' disabled';
5744 }
5745 $more .= ' /></div>';
5746 $more .= '</div>' . "\n";
5747 } elseif ($input['type'] == 'radio') {
5748 $i = 0;
5749 foreach ($input['values'] as $selkey => $selval) {
5750 $more .= '<div class="tagtr">';
5751 if (isset($input['label'])) {
5752 if ($i == 0) {
5753 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5754 } else {
5755 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5756 }
5757 }
5758 $more .= '<div class="tagtd' . ($i == 0 ? ' tdtop' : '') . '"><input type="radio" class="flat' . $morecss . '" id="' . dol_escape_htmltag($input['name'] . $selkey) . '" name="' . dol_escape_htmltag($input['name']) . '" value="' . $selkey . '"' . $moreattr;
5759 if (!empty($input['disabled'])) {
5760 $more .= ' disabled';
5761 }
5762 if (isset($input['default']) && $input['default'] === $selkey) {
5763 $more .= ' checked="checked"';
5764 }
5765 $more .= ' /> ';
5766 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5767 $more .= '</div></div>' . "\n";
5768 $i++;
5769 }
5770 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5771 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5772 $more .= '<div class="tagtd">';
5773 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5774 $h = $m = 0;
5775 if ($input['type'] == 'datetime') {
5776 $h = isset($input['hours']) ? $input['hours'] : 1;
5777 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5778 }
5779 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5780 $more .= '</div></div>'."\n";
5781 $formquestion[] = array('name' => $input['name'].'day');
5782 $formquestion[] = array('name' => $input['name'].'month');
5783 $formquestion[] = array('name' => $input['name'].'year');
5784 $formquestion[] = array('name' => $input['name'].'hour');
5785 $formquestion[] = array('name' => $input['name'].'min');
5786 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5787 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5788 if (!empty($input['label'])) {
5789 $more .= $input['label'] . '</div><div class="tagtd">';
5790 }
5791 $more .= $input['value'];
5792 $more .= '</div></div>' . "\n";
5793 } elseif ($input['type'] == 'onecolumn') {
5794 $moreonecolumn .= '<div class="margintoponly">';
5795 $moreonecolumn .= $input['value'];
5796 $moreonecolumn .= '</div>' . "\n";
5797 } elseif ($input['type'] == 'hidden') {
5798 // Do nothing more, already added by a previous loop
5799 } elseif ($input['type'] == 'separator') {
5800 $more .= '<br>';
5801 } else {
5802 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5803 }
5804 }
5805 }
5806 $more .= '</div>' . "\n";
5807 $more .= $moreonecolumn;
5808 }
5809
5810 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5811 // Note: When using dol_use_jmobile or no js, you must also check code for button use a GET url with action=xxx and check that you also output the confirm code when action=xxx
5812 // See page product/card.php for example
5813 if (!empty($conf->dol_use_jmobile)) {
5814 $useajax = 0;
5815 }
5816 if (empty($conf->use_javascript_ajax)) {
5817 $useajax = 0;
5818 }
5819
5820 if ($useajax) {
5821 $autoOpen = true;
5822 $dialogconfirm = 'dialog-confirm';
5823 $button = '';
5824 if (!is_numeric($useajax)) {
5825 $button = $useajax;
5826 $useajax = 1;
5827 $autoOpen = false;
5828 $dialogconfirm .= '-' . $button;
5829 }
5830 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5831 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5832
5833 // Add input fields into list of fields to read during submit (inputok and inputko)
5834 if (is_array($formquestion)) {
5835 foreach ($formquestion as $key => $input) {
5836 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5837 // Add name of fields to propagate with the GET when submitting the form with button OK.
5838 if (is_array($input) && isset($input['name'])) {
5839 if (strpos($input['name'], ',') > 0) {
5840 $inputok = array_merge($inputok, explode(',', $input['name']));
5841 } else {
5842 array_push($inputok, $input['name']);
5843 }
5844 }
5845 // Add name of fields to propagate with the GET when submitting the form with button KO.
5846 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5847 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5848 array_push($inputko, $input['name']);
5849 }
5850 }
5851 }
5852
5853 // Show JQuery confirm box.
5854 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5855 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5856 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5857 }
5858 if (!empty($more)) {
5859 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5860 }
5861 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5862 $formconfirm .= '</div>' . "\n";
5863
5864 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5865 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5866 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5867 $formconfirm .= 'jQuery(document).ready(function() {
5868 $(function() {
5869 $( "#' . $dialogconfirm . '" ).dialog(
5870 {
5871 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5872 if ($newselectedchoice == 'no') {
5873 $formconfirm .= '
5874 open: function() {
5875 $(this).parent().find("button.ui-button:eq(2)").focus();
5876 },';
5877 }
5878
5879 $jsforcursor = '';
5880 if ($useajax == 1) {
5881 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5882 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5883 }
5884
5885 $postconfirmas = 'GET';
5886
5887 $formconfirm .= '
5888 resizable: false,
5889 height: "' . $height . '",
5890 width: "' . $width . '",
5891 modal: true,
5892 closeOnEscape: false,
5893 buttons: {
5894 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5895 var options = "token=' . urlencode(newToken()) . '";
5896 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5897 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5898 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5899
5900 if (inputok.length > 0) {
5901 $.each(inputok, function(i, inputname) {
5902 var more = "";
5903 var inputvalue;
5904 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5905 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5906 } else {
5907 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5908 inputvalue = $("#" + inputname + more).val();
5909 }
5910 if (typeof inputvalue == "undefined") { inputvalue=""; }
5911 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5912 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5913 });
5914 }
5915 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5916 if (pageyes.length > 0) {';
5917 if ($postconfirmas == 'GET') {
5918 $formconfirm .= 'location.href = urljump;';
5919 } else {
5920 $formconfirm .= $jsforcursor;
5921 $formconfirm .= 'var post = $.post(
5922 pageyes,
5923 options,
5924 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5925 );';
5926 }
5927 $formconfirm .= '
5928 console.log("after post ok");
5929 }
5930 $(this).dialog("close");
5931 },
5932 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5933 var options = "token=' . urlencode(newToken()) . '";
5934 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5935 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5936 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5937 if (inputko.length > 0) {
5938 $.each(inputko, function(i, inputname) {
5939 var more = "";
5940 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5941 var inputvalue = $("#" + inputname + more).val();
5942 if (typeof inputvalue == "undefined") { inputvalue=""; }
5943 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5944 });
5945 }
5946 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5947 //alert(urljump);
5948 if (pageno.length > 0) {';
5949 if ($postconfirmas == 'GET') {
5950 $formconfirm .= 'location.href = urljump;';
5951 } else {
5952 $formconfirm .= $jsforcursor;
5953 $formconfirm .= 'var post = $.post(
5954 pageno,
5955 options,
5956 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5957 );';
5958 }
5959 $formconfirm .= '
5960 console.log("after post ko");
5961 }
5962 $(this).dialog("close");
5963 }
5964 }
5965 }
5966 );
5967
5968 var button = "' . $button . '";
5969 if (button.length > 0) {
5970 $( "#" + button ).click(function() {
5971 $("#' . $dialogconfirm . '").dialog("open");
5972 });
5973 }
5974 });
5975 });
5976 </script>';
5977 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5978 } else {
5979 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5980
5981 if (empty($disableformtag)) {
5982 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
5983 }
5984
5985 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5986 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5987
5988 $formconfirm .= '<table class="valid centpercent">' . "\n";
5989
5990 // Line title
5991 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5992 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5993 $formconfirm .= '</td></tr>' . "\n";
5994
5995 // Line text
5996 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5997 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5998 }
5999
6000 // Line form fields
6001 if ($more) {
6002 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
6003 $formconfirm .= $more;
6004 $formconfirm .= '</td></tr>' . "\n";
6005 }
6006
6007 // Line with question
6008 $formconfirm .= '<tr class="valid">';
6009 $formconfirm .= '<td class="valid">' . $question . '</td>';
6010 $formconfirm .= '<td class="valid center">';
6011 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
6012 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
6013 $formconfirm .= '</td>';
6014 $formconfirm .= '</tr>' . "\n";
6015
6016 $formconfirm .= '</table>' . "\n";
6017
6018 if (empty($disableformtag)) {
6019 $formconfirm .= "</form>\n";
6020 }
6021 $formconfirm .= '<br>';
6022
6023 if (!empty($conf->use_javascript_ajax)) {
6024 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
6025 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6026 $formconfirm .= '
6027 $(document).ready(function () {
6028 $(".confirmvalidatebutton").on("click", function() {
6029 console.log("We click on button confirmvalidatebutton");
6030 $(this).attr("disabled", "disabled");
6031 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
6032 //console.log($(this).closest("form"));
6033 $(this).closest("form").submit();
6034 });
6035 });
6036 ';
6037 $formconfirm .= '</script>' . "\n";
6038 }
6039
6040 $formconfirm .= "<!-- end formconfirm -->\n";
6041 }
6042
6043 return $formconfirm;
6044 }
6045
6046
6047 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6048
6064 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
6065 {
6066 // phpcs:enable
6067 global $langs;
6068
6069 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
6070 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
6071
6072 $out = '';
6073
6074 $formproject = new FormProjets($this->db);
6075
6076 $langs->load("project");
6077 if ($htmlname != "none") {
6078 $out .= '<form method="post" action="' . $page . '">';
6079 $out .= '<input type="hidden" name="action" value="classin">';
6080 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6081 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
6082 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6083 $out .= '</form>';
6084 } else {
6085 $out .= '<span class="project_head_block">';
6086 if ($selected) {
6087 $projet = new Project($this->db);
6088 $projet->fetch($selected);
6089 $out .= $projet->getNomUrl(0, '', 1);
6090 } else {
6091 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
6092 }
6093 $out .= '</span>';
6094 }
6095
6096 if (empty($nooutput)) {
6097 print $out;
6098 return '';
6099 }
6100 return $out;
6101 }
6102
6103 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6104
6120 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
6121 {
6122 // phpcs:enable
6123 global $langs;
6124
6125 $out = '';
6126
6127 if ($htmlname != "none") {
6128 $out .= '<form method="POST" action="' . $page . '">';
6129 $out .= '<input type="hidden" name="action" value="setconditions">';
6130 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6131 if ($type) {
6132 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6133 }
6134 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6135 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6136 $out .= '</form>';
6137 } else {
6138 if ($selected) {
6140 if (isset($this->cache_conditions_paiements[$selected])) {
6141 $label = $this->cache_conditions_paiements[$selected]['label'];
6142
6143 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6144 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6145 }
6146
6147 $out .= $label;
6148 } else {
6149 $langs->load('errors');
6150 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6151 }
6152 } else {
6153 $out .= '&nbsp;';
6154 }
6155 }
6156
6157 if (empty($nooutput)) {
6158 print $out;
6159 return '';
6160 }
6161 return $out;
6162 }
6163
6164 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6165
6175 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
6176 {
6177 // phpcs:enable
6178 global $langs;
6179 if ($htmlname != "none") {
6180 print '<form method="post" action="' . $page . '">';
6181 print '<input type="hidden" name="action" value="setavailability">';
6182 print '<input type="hidden" name="token" value="' . newToken() . '">';
6183 $this->selectAvailabilityDelay($selected, $htmlname, '', $addempty);
6184 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6185 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
6186 print '</form>';
6187 } else {
6188 if ($selected) {
6189 $this->load_cache_availability();
6190 print $this->cache_availability[$selected]['label'];
6191 } else {
6192 print "&nbsp;";
6193 }
6194 }
6195 }
6196
6207 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
6208 {
6209 global $langs;
6210 if ($htmlname != "none") {
6211 print '<form method="post" action="' . $page . '">';
6212 print '<input type="hidden" name="action" value="setdemandreason">';
6213 print '<input type="hidden" name="token" value="' . newToken() . '">';
6214 $this->selectInputReason($selected, $htmlname, '-1', $addempty);
6215 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6216 print '</form>';
6217 } else {
6218 if ($selected) {
6219 $this->loadCacheInputReason();
6220 foreach ($this->cache_demand_reason as $key => $val) {
6221 if ($val['id'] == $selected) {
6222 print $val['label'];
6223 break;
6224 }
6225 }
6226 } else {
6227 print "&nbsp;";
6228 }
6229 }
6230 }
6231
6232 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6233
6247 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6248 {
6249 // phpcs:enable
6250 global $langs;
6251
6252 $ret = '';
6253
6254 if ($htmlname != "none") {
6255 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6256 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6257 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6258 if ($type) {
6259 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6260 }
6261 $ret .= '<table class="nobordernopadding">';
6262 $ret .= '<tr><td>';
6263 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6264 $ret .= '</td>';
6265 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6266 $ret .= '</tr></table></form>';
6267 } else {
6268 if ($displayhour) {
6269 $ret .= dol_print_date($selected, 'dayhour');
6270 } else {
6271 $ret .= dol_print_date($selected, 'day');
6272 }
6273 }
6274
6275 if (empty($nooutput)) {
6276 print $ret;
6277 }
6278 return $ret;
6279 }
6280
6281
6282 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6283
6294 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6295 {
6296 // phpcs:enable
6297 global $langs;
6298
6299 if ($htmlname != "none") {
6300 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6301 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6302 print '<input type="hidden" name="token" value="' . newToken() . '">';
6303 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6304 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6305 print '</form>';
6306 } else {
6307 if ($selected) {
6308 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6309 $theuser = new User($this->db);
6310 $theuser->fetch($selected);
6311 print $theuser->getNomUrl(1);
6312 } else {
6313 print "&nbsp;";
6314 }
6315 }
6316 }
6317
6318
6319 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6320
6334 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6335 {
6336 // phpcs:enable
6337 global $langs;
6338
6339 $out = '';
6340 if ($htmlname != "none") {
6341 $out .= '<form method="POST" action="' . $page . '">';
6342 $out .= '<input type="hidden" name="action" value="setmode">';
6343 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6344 if ($type) {
6345 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6346 }
6347 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6348 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6349 $out .= '</form>';
6350 } else {
6351 if ($selected) {
6353 $out .= $this->cache_types_paiements[$selected]['label'];
6354 } else {
6355 $out .= "&nbsp;";
6356 }
6357 }
6358
6359 if ($nooutput) {
6360 return $out;
6361 } else {
6362 print $out;
6363 }
6364 return '';
6365 }
6366
6377 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6378 {
6379 global $langs;
6380 if ($htmlname != "none") {
6381 print '<form method="POST" action="' . $page . '">';
6382 print '<input type="hidden" name="action" value="settransportmode">';
6383 print '<input type="hidden" name="token" value="' . newToken() . '">';
6384 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6385 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6386 print '</form>';
6387 } else {
6388 if ($selected) {
6390 print $this->cache_transport_mode[$selected]['label'];
6391 } else {
6392 print "&nbsp;";
6393 }
6394 }
6395 }
6396
6397 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6398
6407 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6408 {
6409 // phpcs:enable
6410 global $langs;
6411 if ($htmlname != "none") {
6412 print '<form method="POST" action="' . $page . '">';
6413 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6414 print '<input type="hidden" name="token" value="' . newToken() . '">';
6415 print $this->selectMultiCurrency($selected, $htmlname, 0);
6416 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6417 print '</form>';
6418 } else {
6419 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6420 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6421 }
6422 }
6423
6424 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6425
6435 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6436 {
6437 // phpcs:enable
6438 global $langs, $mysoc, $conf;
6439
6440 if ($htmlname != "none") {
6441 print '<form method="POST" action="' . $page . '">';
6442 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6443 print '<input type="hidden" name="token" value="' . newToken() . '">';
6444 print '<input type="text" class="maxwidth75" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6445 print '<select name="calculation_mode" id="calculation_mode">';
6446 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6447 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6448 print '</select> ';
6449 print ajax_combobox("calculation_mode");
6450 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6451 print '</form>';
6452 } else {
6453 if (!empty($rate)) {
6454 print price($rate, 1, $langs, 0, 0);
6455 if ($currency && $rate != 1) {
6456 print ' &nbsp; <span class="opacitymedium">(' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')</span>';
6457 }
6458 } else {
6459 print 1;
6460 }
6461 }
6462 }
6463
6464 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6465
6481 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6482 {
6483 // phpcs:enable
6484 global $conf, $langs;
6485 if ($htmlname != "none") {
6486 print '<form method="post" action="' . $page . '">';
6487 print '<input type="hidden" name="action" value="setabsolutediscount">';
6488 print '<input type="hidden" name="token" value="' . newToken() . '">';
6489 print '<div class="inline-block">';
6490 if (!empty($discount_type)) {
6491 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6492 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6493 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6494 } else {
6495 $translationKey = 'HasCreditNoteFromSupplier';
6496 }
6497 } else {
6498 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6499 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6500 } else {
6501 $translationKey = 'HasCreditNoteFromSupplier';
6502 }
6503 }
6504 } else {
6505 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6506 if (!$filter || $filter == "fk_facture_source IS NULL") {
6507 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6508 } else {
6509 $translationKey = 'CompanyHasCreditNote';
6510 }
6511 } else {
6512 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6513 $translationKey = 'CompanyHasAbsoluteDiscount';
6514 } else {
6515 $translationKey = 'CompanyHasCreditNote';
6516 }
6517 }
6518 }
6519 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6520 if (empty($hidelist)) {
6521 print ' ';
6522 }
6523 print '</div>';
6524 if (empty($hidelist)) {
6525 print '<div class="inline-block" style="padding-right: 10px">';
6526 $newfilter = 'discount_type=' . intval($discount_type);
6527 if (!empty($discount_type)) {
6528 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6529 } else {
6530 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6531 }
6532 if ($filter) {
6533 $newfilter .= ' AND (' . $filter . ')';
6534 }
6535 // output the combo of discounts
6536 $nbqualifiedlines = $this->select_remises((string) $selected, $htmlname, $newfilter, $socid, $maxvalue);
6537 if ($nbqualifiedlines > 0) {
6538 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6539 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6540 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6541 }
6542 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6543 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6544 }
6545
6546 print '>';
6547 }
6548 print '</div>';
6549 }
6550 if ($more) {
6551 print '<div class="inline-block">';
6552 print $more;
6553 print '</div>';
6554 }
6555 print '</form>';
6556 } else {
6557 if ($selected) {
6558 print $selected;
6559 } else {
6560 print "0";
6561 }
6562 }
6563 }
6564
6565
6566 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6567
6577 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6578 {
6579 // phpcs:enable
6580 global $langs;
6581
6582 if ($htmlname != "none") {
6583 print '<form method="post" action="' . $page . '">';
6584 print '<input type="hidden" name="action" value="set_contact">';
6585 print '<input type="hidden" name="token" value="' . newToken() . '">';
6586 print '<table class="nobordernopadding">';
6587 print '<tr><td>';
6588 print $this->selectcontacts($societe->id, $selected, $htmlname);
6589 $num = $this->num;
6590 if ($num == 0) {
6591 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6592 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&amp;action=create&amp;backtoreferer=1">' . $addcontact . '</a>';
6593 }
6594 print '</td>';
6595 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6596 print '</tr></table></form>';
6597 } else {
6598 if ($selected) {
6599 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6600 $contact = new Contact($this->db);
6601 $contact->fetch($selected);
6602 print $contact->getFullName($langs);
6603 } else {
6604 print "&nbsp;";
6605 }
6606 }
6607 }
6608
6609 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6610
6627 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6628 {
6629 // phpcs:enable
6630 global $langs;
6631
6632 $out = '';
6633 if ($htmlname != "none") {
6634 $out .= '<form method="post" action="' . $page . '">';
6635 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6636 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6637 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6638 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6639 $out .= '</form>';
6640 } else {
6641 if ($selected) {
6642 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6643 $soc = new Societe($this->db);
6644 $soc->fetch($selected);
6645 $out .= $soc->getNomUrl(0, '');
6646 } else {
6647 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6648 }
6649 }
6650
6651 if ($nooutput) {
6652 return $out;
6653 } else {
6654 print $out;
6655 }
6656
6657 return '';
6658 }
6659
6660 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6661
6670 public function select_currency($selected = '', $htmlname = 'currency_id')
6671 {
6672 // phpcs:enable
6673 print $this->selectCurrency($selected, $htmlname);
6674 }
6675
6685 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6686 {
6687 global $langs, $user;
6688
6689 $langs->loadCacheCurrencies('');
6690
6691 $out = '';
6692
6693 if ($selected == 'euro' || $selected == 'euros') {
6694 $selected = 'EUR'; // Pour compatibilite
6695 }
6696
6697 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6698 if ($useempty) {
6699 $out .= '<option value="-1" selected></option>';
6700 }
6701 foreach ($langs->cache_currencies as $code_iso => $currency) {
6702 $labeltoshow = $currency['label'];
6703 if ($mode == 1) {
6704 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6705 } else {
6706 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6707 }
6708
6709 if ($selected && $selected == $code_iso) {
6710 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6711 } else {
6712 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6713 }
6714 $out .= $labeltoshow;
6715 $out .= '</option>';
6716 }
6717 $out .= '</select>';
6718 if ($user->admin) {
6719 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6720 }
6721
6722 // Make select dynamic
6723 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6724 $out .= ajax_combobox($htmlname);
6725
6726 return $out;
6727 }
6728
6741 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6742 {
6743 global $conf, $langs;
6744
6745 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6746
6747 $TCurrency = array();
6748
6749 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6750 $sql .= " WHERE entity IN ('" . getEntity('mutlicurrency') . "')";
6751 if ($filter) {
6752 $sql .= " AND " . $filter;
6753 }
6754 $resql = $this->db->query($sql);
6755 if ($resql) {
6756 while ($obj = $this->db->fetch_object($resql)) {
6757 $TCurrency[$obj->code] = $obj->code;
6758 }
6759 }
6760
6761 $out = '';
6762 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6763 if ($useempty) {
6764 $out .= '<option value="">&nbsp;</option>';
6765 }
6766 // If company current currency not in table, we add it into list. Should always be available.
6767 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6768 $TCurrency[$conf->currency] = $conf->currency;
6769 }
6770 if (count($TCurrency) > 0) {
6771 foreach ($langs->cache_currencies as $code_iso => $currency) {
6772 if (isset($TCurrency[$code_iso])) {
6773 if (!empty($selected) && $selected == $code_iso) {
6774 $out .= '<option value="' . $code_iso . '" selected="selected">';
6775 } else {
6776 $out .= '<option value="' . $code_iso . '">';
6777 }
6778
6779 $out .= $currency['label'];
6780 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6781 $out .= '</option>';
6782 }
6783 }
6784 }
6785
6786 $out .= '</select>';
6787
6788 // Make select dynamic
6789 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6790 $out .= ajax_combobox($htmlname);
6791
6792 return $out;
6793 }
6794
6795 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6796
6803 public function load_cache_vatrates($country_code)
6804 {
6805 // phpcs:enable
6806 global $langs, $user;
6807
6808 $num = count($this->cache_vatrates);
6809 if ($num > 0) {
6810 return $num; // Cache already loaded
6811 }
6812
6813 dol_syslog(__METHOD__, LOG_DEBUG);
6814
6815 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6816 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6817 $sql .= " WHERE t.fk_pays = c.rowid";
6818 $sql .= " AND t.active > 0";
6819 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6820 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6821 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6822
6823 $resql = $this->db->query($sql);
6824 if ($resql) {
6825 $num = $this->db->num_rows($resql);
6826 if ($num) {
6827 for ($i = 0; $i < $num; $i++) {
6828 $obj = $this->db->fetch_object($resql);
6829
6830 $tmparray = array();
6831 $tmparray['rowid'] = $obj->rowid;
6832 $tmparray['type_vat'] = $obj->type_vat;
6833 $tmparray['code'] = $obj->code;
6834 $tmparray['txtva'] = $obj->taux;
6835 $tmparray['nprtva'] = $obj->recuperableonly;
6836 $tmparray['localtax1'] = $obj->localtax1;
6837 $tmparray['localtax1_type'] = $obj->localtax1_type;
6838 $tmparray['localtax2'] = $obj->localtax2;
6839 $tmparray['localtax2_type'] = $obj->localtax1_type;
6840 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6841 $tmparray['labelallrates'] = $obj->taux . '/' . ($obj->localtax1 ? $obj->localtax1 : '0') . '/' . ($obj->localtax2 ? $obj->localtax2 : '0') . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6842 $positiverates = '';
6843 if ($obj->taux) {
6844 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6845 }
6846 if ($obj->localtax1) {
6847 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6848 }
6849 if ($obj->localtax2) {
6850 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6851 }
6852 if (empty($positiverates)) {
6853 $positiverates = '0';
6854 }
6855 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6856
6857 $this->cache_vatrates[$obj->rowid] = $tmparray;
6858 }
6859
6860 return $num;
6861 } else {
6862 $this->error = '<span class="error">';
6863 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6864 $reg = array();
6865 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6866 $langs->load("errors");
6867 $new_country_code = $reg[1];
6868 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid');
6869 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6870 }
6871 $this->error .= '</span>';
6872 return -1;
6873 }
6874 } else {
6875 $this->error = '<span class="error">' . $this->db->error() . '</span>';
6876 return -2;
6877 }
6878 }
6879
6880 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6881
6904 public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = null, $societe_acheteuse = null, $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0, $type_vat = 0)
6905 {
6906 // phpcs:enable
6907 global $langs, $mysoc;
6908
6909 $langs->load('errors');
6910
6911 $return = '';
6912
6913 // Define defaultnpr, defaultttx and defaultcode
6914 $defaultnpr = ($info_bits & 0x01);
6915 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6916 $defaulttx = str_replace('*', '', $selectedrate);
6917 $defaultcode = '';
6918 $reg = array();
6919 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6920 $defaultcode = $reg[1];
6921 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6922 }
6923 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6924
6925 // Check parameters
6926 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6927 if ($societe_vendeuse->id == $mysoc->id) {
6928 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6929 } else {
6930 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6931 }
6932 return $return;
6933 }
6934
6935 //var_dump($societe_acheteuse);
6936 //print "name=$name, selectedrate=$selectedrate, seller=".$societe_vendeuse->country_code." buyer=".$societe_acheteuse->country_code." buyer is company=".$societe_acheteuse->isACompany()." idprod=$idprod, info_bits=$info_bits type=$type";
6937 //exit;
6938
6939 // Define list of countries to use to search VAT rates to show
6940 // First we defined code_country to use to find list
6941 if (is_object($societe_vendeuse)) {
6942 $code_country = "'" . $societe_vendeuse->country_code . "'";
6943 } else {
6944 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6945 }
6946 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
6947 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6948 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
6949 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
6950 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
6951 if (isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
6952 // We also add the buyer country code
6953 if (is_numeric($type)) {
6954 if ($type == 1) { // We know product is a service
6955 switch ($selectVatComboMode) {
6956 case '1':
6957 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6958 break;
6959 case '2':
6960 $code_country = "'" . $societe_acheteuse->country_code . "'";
6961 break;
6962 }
6963 }
6964 } elseif (!$idprod) { // We don't know type of product
6965 switch ($selectVatComboMode) {
6966 case '1':
6967 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6968 break;
6969 case '2':
6970 $code_country = "'" . $societe_acheteuse->country_code . "'";
6971 break;
6972 }
6973 } else {
6974 $prodstatic = new Product($this->db);
6975 $prodstatic->fetch($idprod);
6976 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6977 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6978 }
6979 }
6980 }
6981 }
6982
6983 // Now we load the list of VAT
6984 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6985
6986 // Keep only the VAT qualified for $type_vat
6987 $arrayofvatrates = array();
6988 foreach ($this->cache_vatrates as $cachevalue) {
6989 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] != $type_vat) {
6990 $arrayofvatrates[] = $cachevalue;
6991 }
6992 }
6993
6994 $num = count($arrayofvatrates);
6995
6996 if ($num > 0) {
6997 // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6998 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6999 $tmpthirdparty = new Societe($this->db);
7000
7001 $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7002 $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7003
7004 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7005 $defaultcode = $reg[1];
7006 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7007 }
7008 if (empty($defaulttx)) {
7009 $defaultnpr = 0;
7010 }
7011 }
7012
7013 // If we fails to find a default vat rate, we take the last one in list
7014 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
7015 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7016 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
7017 // We take the last one found in list
7018 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
7019 } else {
7020 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
7021 $defaulttx = '';
7022 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
7023 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
7024 }
7025 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7026 $defaultcode = $reg[1];
7027 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7028 }
7029 }
7030 }
7031
7032 // Disabled if seller is not subject to VAT
7033 $disabled = false;
7034 $title = '';
7035 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
7036 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
7037 // of using supplier invoices (this is a very bad idea !)
7038 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
7039 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
7040 $disabled = true;
7041 }
7042 }
7043
7044 if (!$options_only) {
7045 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
7046 }
7047
7048 $selectedfound = false;
7049 foreach ($arrayofvatrates as $rate) {
7050 // Keep only 0 if seller is not subject to VAT
7051 if ($disabled && $rate['txtva'] != 0) {
7052 continue;
7053 }
7054
7055 // Define key to use into select list
7056 $key = $rate['txtva'];
7057 $key .= $rate['nprtva'] ? '*' : '';
7058 if ($mode > 0 && $rate['code']) {
7059 $key .= ' (' . $rate['code'] . ')';
7060 }
7061 if ($mode < 0) {
7062 $key = $rate['rowid'];
7063 }
7064
7065 $return .= '<option value="' . $key . '"';
7066 if (!$selectedfound) {
7067 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
7068 if ($defaultcode == $rate['code']) {
7069 $return .= ' selected';
7070 $selectedfound = true;
7071 }
7072 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
7073 $return .= ' selected';
7074 $selectedfound = true;
7075 }
7076 }
7077 $return .= '>';
7078
7079 // Show label of VAT
7080 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
7081 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
7082 $return .= $rate['labelpositiverates'];
7083 } else {
7084 // Simple label
7085 $return .= vatrate($rate['label']);
7086 }
7087
7088 //$return.=($rate['code']?' '.$rate['code']:'');
7089 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
7090
7091 $return .= '</option>';
7092 }
7093
7094 if (!$options_only) {
7095 $return .= '</select>';
7096 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
7097 }
7098 } else {
7099 $return .= $this->error;
7100 }
7101
7102 $this->num = $num;
7103 return $return;
7104 }
7105
7106
7107 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7108
7133 public function select_date($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $nooutput = 0, $disabled = 0, $fullday = 0, $addplusone = '', $adddateof = '')
7134 {
7135 // phpcs:enable
7136 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
7137 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
7138 if (!empty($nooutput)) {
7139 return $retstring;
7140 }
7141 print $retstring;
7142
7143 return '';
7144 }
7145
7161 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
7162 {
7163 global $langs;
7164
7165 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
7166 if ($forcenewline) {
7167 $ret .= '<br>';
7168 }
7169 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
7170 return $ret;
7171 }
7172
7201 public function selectDate($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '', $openinghours = '', $stepminutes = 1, $labeladddateof = '', $placeholder = '', $gm = 'auto', $calendarpicto = '')
7202 {
7203 global $conf, $langs;
7204
7205 if ($gm === 'auto') {
7206 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7207 }
7208
7209 $retstring = '';
7210
7211 if ($prefix == '') {
7212 $prefix = 're';
7213 }
7214 if ($h == '') {
7215 $h = 0;
7216 }
7217 if ($m == '') {
7218 $m = 0;
7219 }
7220 $emptydate = 0;
7221 $emptyhours = 0;
7222 if ($stepminutes <= 0 || $stepminutes > 30) {
7223 $stepminutes = 1;
7224 }
7225 if ($empty == 1) {
7226 $emptydate = 1;
7227 $emptyhours = 1;
7228 }
7229 if ($empty == 2) {
7230 $emptydate = 0;
7231 $emptyhours = 1;
7232 }
7233 $orig_set_time = $set_time;
7234
7235 if ($set_time === '' && $emptydate == 0) {
7236 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7237 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7238 $set_time = dol_now($gm);
7239 } else {
7240 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7241 }
7242 }
7243
7244 // Analysis of the pre-selection date
7245 $reg = array();
7246 $shour = '';
7247 $smin = '';
7248 $ssec = '';
7249 if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
7250 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7251 $syear = (!empty($reg[1]) ? $reg[1] : '');
7252 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7253 $sday = (!empty($reg[3]) ? $reg[3] : '');
7254 $shour = (!empty($reg[4]) ? $reg[4] : '');
7255 $smin = (!empty($reg[5]) ? $reg[5] : '');
7256 } elseif (strval($set_time) != '' && $set_time != -1) {
7257 // set_time est un timestamps (0 possible)
7258 $syear = dol_print_date($set_time, "%Y", $gm);
7259 $smonth = dol_print_date($set_time, "%m", $gm);
7260 $sday = dol_print_date($set_time, "%d", $gm);
7261 if ($orig_set_time != '') {
7262 $shour = dol_print_date($set_time, "%H", $gm);
7263 $smin = dol_print_date($set_time, "%M", $gm);
7264 $ssec = dol_print_date($set_time, "%S", $gm);
7265 }
7266 } else {
7267 // Date est '' ou vaut -1
7268 $syear = '';
7269 $smonth = '';
7270 $sday = '';
7271 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7272 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7273 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7274 }
7275 if ($h == 3 || $h == 4) {
7276 $shour = '';
7277 }
7278 if ($m == 3) {
7279 $smin = '';
7280 }
7281
7282 $nowgmt = dol_now('gmt');
7283 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7284
7285 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7286 $usecalendar = 'combo';
7287 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7288 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
7289 }
7290 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7291 // If we use a text browser or screen reader, we use the 'combo' date selector
7292 $usecalendar = 'html';
7293 }
7294
7295 if ($d) {
7296 // Show date with popup
7297 if ($usecalendar != 'combo') {
7298 $formated_date = '';
7299 //print "e".$set_time." t ".$conf->format_date_short;
7300 if (strval($set_time) != '' && $set_time != -1) {
7301 //$formated_date=dol_print_date($set_time,$conf->format_date_short);
7302 $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7303 }
7304
7305 // Calendrier popup version eldy
7306 if ($usecalendar == "eldy") {
7307 // Input area to enter date manually
7308 $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formated_date . '"';
7309 $retstring .= ($disabled ? ' disabled' : '');
7310 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7311 $retstring .= ' autocomplete="off">';
7312
7313 // Icon calendar
7314 $retstringbuttom = '';
7315 if (!$disabled) {
7316 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7317 $base = DOL_URL_ROOT . '/core/';
7318 $retstringbuttom .= ' onClick="showDP(\'' . $base . '\',\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\',\'' . $langs->defaultlang . '\');"';
7319 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
7320 } else {
7321 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7322 }
7323 $retstring = $retstringbuttom . $retstring;
7324
7325 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7326 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7327 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7328 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7329 if (!$disabled && $usecalendar != 'html') {
7330 // Output javascript for datepicker
7331 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7332 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7333
7334 $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
7335 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7336 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7337 autoclose: true,
7338 todayHighlight: true,
7339 yearRange: '" . $minYear . ":" . $maxYear . "',";
7340 if (!empty($conf->dol_use_jmobile)) {
7341 $retstring .= "
7342 beforeShow: function (input, datePicker) {
7343 input.disabled = true;
7344 },
7345 onClose: function (dateText, datePicker) {
7346 this.disabled = false;
7347 },
7348 ";
7349 }
7350 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7351 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7352 $buttonImage = $calendarpicto ?: DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png";
7353 $retstring .= "
7354 showOn: 'button', /* both has problem with autocompletion */
7355 buttonImage: '" . $buttonImage . "',
7356 buttonImageOnly: true";
7357 }
7358 $retstring .= "
7359 }) });";
7360 $retstring .= "</script>";
7361 }
7362
7363 // Input area to enter date manually
7364 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7365 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate center" maxlength="11" value="'.$formated_date.'"';
7366 $retstring .= ($disabled ? ' disabled' : '');
7367 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7368 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7369 $retstring .= ' autocomplete="off">';
7370
7371 // Icone calendrier
7372 if ($disabled) {
7373 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7374 $retstring = $retstringbutton . $retstring;
7375 }
7376
7377 $retstring .= '</div>';
7378 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7379 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7380 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7381 } else {
7382 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7383 }
7384 } else {
7385 // Show date with combo selects
7386 // Day
7387 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7388
7389 if ($emptydate || $set_time == -1) {
7390 $retstring .= '<option value="0" selected>&nbsp;</option>';
7391 }
7392
7393 for ($day = 1; $day <= 31; $day++) {
7394 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7395 }
7396
7397 $retstring .= "</select>";
7398
7399 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7400 if ($emptydate || $set_time == -1) {
7401 $retstring .= '<option value="0" selected>&nbsp;</option>';
7402 }
7403
7404 // Month
7405 for ($month = 1; $month <= 12; $month++) {
7406 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7407 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7408 $retstring .= "</option>";
7409 }
7410 $retstring .= "</select>";
7411
7412 // Year
7413 if ($emptydate || $set_time == -1) {
7414 $retstring .= '<input' . ($disabled ? ' disabled' : '') . ' placeholder="' . dol_escape_htmltag($langs->trans("Year")) . '" class="flat maxwidth50imp valignmiddle" type="number" min="0" max="3000" maxlength="4" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">';
7415 } else {
7416 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7417
7418 $syear = (int) $syear;
7419 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7420 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7421 }
7422 $retstring .= "</select>\n";
7423 }
7424 }
7425 }
7426
7427 if ($d && $h) {
7428 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7429 $retstring .= '<span class="nowraponall">';
7430 }
7431
7432 if ($h) {
7433 $hourstart = 0;
7434 $hourend = 24;
7435 if ($openinghours != '') {
7436 $openinghours = explode(',', $openinghours);
7437 $hourstart = $openinghours[0];
7438 $hourend = $openinghours[1];
7439 if ($hourend < $hourstart) {
7440 $hourend = $hourstart;
7441 }
7442 }
7443
7444 // Show hour
7445 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7446 if ($emptyhours) {
7447 $retstring .= '<option value="-1">&nbsp;</option>';
7448 }
7449 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7450 if (strlen($hour) < 2) {
7451 $hour = "0" . $hour;
7452 }
7453 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7454 //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
7455 $retstring .= '</option>';
7456 }
7457 $retstring .= '</select>';
7458 //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
7459 if ($m) {
7460 $retstring .= ":";
7461 }
7462 }
7463
7464 if ($m) {
7465 // Show minutes
7466 $retstring .= '<select ' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7467 if ($emptyhours) {
7468 $retstring .= '<option value="-1">&nbsp;</option>';
7469 }
7470 for ($min = 0; $min < 60; $min += $stepminutes) {
7471 $min_str = sprintf("%02d", $min);
7472 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7473 }
7474 $retstring .= '</select>';
7475
7476 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7477 }
7478
7479 if ($d && $h) {
7480 $retstring .= '</span>';
7481 }
7482
7483 // Add a "Now" link
7484 if (!empty($conf->use_javascript_ajax) && $addnowlink && !$disabled) {
7485 // Script which will be inserted in the onClick of the "Now" link
7486 $reset_scripts = "";
7487 if ($addnowlink == 2) { // local computer time
7488 // pad add leading 0 on numbers
7489 $reset_scripts .= "Number.prototype.pad = function(size) {
7490 var s = String(this);
7491 while (s.length < (size || 2)) {s = '0' + s;}
7492 return s;
7493 };
7494 var d = new Date();";
7495 }
7496
7497 // Generate the date part, depending on the use or not of the javascript calendar
7498 if ($addnowlink == 1) { // server time expressed in user time setup
7499 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7500 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7501 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7502 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7503 } elseif ($addnowlink == 2) {
7504 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7505 * This break application for foreign languages.
7506 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7507 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7508 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7509 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7510 */
7511 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7512 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7513 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7514 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7515 }
7516 /*if ($usecalendar == "eldy")
7517 {
7518 $base=DOL_URL_ROOT.'/core/';
7519 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7520 }
7521 else
7522 {
7523 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7524 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7525 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7526 }*/
7527 // Update the hour part
7528 if ($h) {
7529 if ($fullday) {
7530 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7531 }
7532 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7533 if ($addnowlink == 1) {
7534 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7535 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7536 } elseif ($addnowlink == 2) {
7537 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7538 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7539 }
7540
7541 if ($fullday) {
7542 $reset_scripts .= ' } ';
7543 }
7544 }
7545 // Update the minute part
7546 if ($m) {
7547 if ($fullday) {
7548 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7549 }
7550 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7551 if ($addnowlink == 1) {
7552 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7553 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7554 } elseif ($addnowlink == 2) {
7555 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7556 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7557 }
7558 if ($fullday) {
7559 $reset_scripts .= ' } ';
7560 }
7561 }
7562 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7563 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7564 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7565 $retstring .= $langs->trans("Now");
7566 $retstring .= '</button> ';
7567 }
7568 }
7569
7570 // Add a "Plus one hour" link
7571 if ($conf->use_javascript_ajax && $addplusone && !$disabled) {
7572 // Script which will be inserted in the onClick of the "Add plusone" link
7573 $reset_scripts = "";
7574
7575 // Generate the date part, depending on the use or not of the javascript calendar
7576 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7577 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7578 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7579 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7580 // Update the hour part
7581 if ($h) {
7582 if ($fullday) {
7583 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7584 }
7585 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7586 if ($fullday) {
7587 $reset_scripts .= ' } ';
7588 }
7589 }
7590 // Update the minute part
7591 if ($m) {
7592 if ($fullday) {
7593 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7594 }
7595 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7596 if ($fullday) {
7597 $reset_scripts .= ' } ';
7598 }
7599 }
7600 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7601 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7602 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7603 $retstring .= $langs->trans("DateStartPlusOne");
7604 $retstring .= '</button> ';
7605 }
7606 }
7607
7608 // Add a link to set data
7609 if ($conf->use_javascript_ajax && !empty($adddateof) && !$disabled) {
7610 if (!is_array($adddateof)) {
7611 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
7612 } else {
7613 $arrayofdateof = $adddateof;
7614 }
7615 foreach ($arrayofdateof as $valuedateof) {
7616 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
7617 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
7618 $tmparray = dol_getdate($tmpadddateof);
7619 if (empty($tmplabeladddateof)) {
7620 $tmplabeladddateof = $langs->trans("DateInvoice");
7621 }
7622 $reset_scripts = 'console.log(\'Click on now link\'); ';
7623 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7624 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7625 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7626 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7627 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7628 }
7629 }
7630
7631 return $retstring;
7632 }
7633
7642 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7643 {
7644 global $langs;
7645
7646 $TDurationTypes = array(
7647 'y' => $langs->trans('Years'),
7648 'm' => $langs->trans('Month'),
7649 'w' => $langs->trans('Weeks'),
7650 'd' => $langs->trans('Days'),
7651 'h' => $langs->trans('Hours'),
7652 'i' => $langs->trans('Minutes')
7653 );
7654
7655 // Removed undesired duration types
7656 foreach ($excludetypes as $value) {
7657 unset($TDurationTypes[$value]);
7658 }
7659
7660 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7661 foreach ($TDurationTypes as $key => $typeduration) {
7662 $retstring .= '<option value="' . $key . '"';
7663 if ($key == $selected) {
7664 $retstring .= " selected";
7665 }
7666 $retstring .= ">" . $typeduration . "</option>";
7667 }
7668 $retstring .= "</select>";
7669
7670 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7671
7672 return $retstring;
7673 }
7674
7675 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7676
7690 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7691 {
7692 // phpcs:enable
7693 global $langs;
7694
7695 $retstring = '<span class="nowraponall">';
7696
7697 $hourSelected = '';
7698 $minSelected = '';
7699
7700 // Hours
7701 if ($iSecond != '') {
7702 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7703
7704 $hourSelected = convertSecondToTime($iSecond, 'allhour');
7705 $minSelected = convertSecondToTime($iSecond, 'min');
7706 }
7707
7708 if ($typehour == 'select') {
7709 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7710 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7711 $retstring .= '<option value="' . $hour . '"';
7712 if (is_numeric($hourSelected) && $hourSelected == $hour) {
7713 $retstring .= " selected";
7714 }
7715 $retstring .= ">" . $hour . "</option>";
7716 }
7717 $retstring .= "</select>";
7718 } elseif ($typehour == 'text' || $typehour == 'textselect') {
7719 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7720 } else {
7721 return 'BadValueForParameterTypeHour';
7722 }
7723
7724 if ($typehour != 'text') {
7725 $retstring .= ' ' . $langs->trans('HourShort');
7726 } else {
7727 $retstring .= '<span class="">:</span>';
7728 }
7729
7730 // Minutes
7731 if ($minunderhours) {
7732 $retstring .= '<br>';
7733 } else {
7734 if ($typehour != 'text') {
7735 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7736 }
7737 }
7738
7739 if ($typehour == 'select' || $typehour == 'textselect') {
7740 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7741 for ($min = 0; $min <= 55; $min += 5) {
7742 $retstring .= '<option value="' . $min . '"';
7743 if (is_numeric($minSelected) && $minSelected == $min) {
7744 $retstring .= ' selected';
7745 }
7746 $retstring .= '>' . $min . '</option>';
7747 }
7748 $retstring .= "</select>";
7749 } elseif ($typehour == 'text') {
7750 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7751 }
7752
7753 if ($typehour != 'text') {
7754 $retstring .= ' ' . $langs->trans('MinuteShort');
7755 }
7756
7757 $retstring .= "</span>";
7758
7759 if (!empty($nooutput)) {
7760 return $retstring;
7761 }
7762
7763 print $retstring;
7764
7765 return '';
7766 }
7767
7787 public function selectTickets($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7788 {
7789 global $langs, $conf;
7790
7791 $out = '';
7792
7793 // check parameters
7794 if (is_null($ajaxoptions)) {
7795 $ajaxoptions = array();
7796 }
7797
7798 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7799 $placeholder = '';
7800
7801 if ($selected && empty($selected_input_value)) {
7802 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7803 $tickettmpselect = new Ticket($this->db);
7804 $tickettmpselect->fetch($selected);
7805 $selected_input_value = $tickettmpselect->ref;
7806 unset($tickettmpselect);
7807 }
7808
7809 $urloption = '';
7810 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7811
7812 if (empty($hidelabel)) {
7813 $out .= $langs->trans("RefOrLabel") . ' : ';
7814 } elseif ($hidelabel > 1) {
7815 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7816 if ($hidelabel == 2) {
7817 $out .= img_picto($langs->trans("Search"), 'search');
7818 }
7819 }
7820 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7821 if ($hidelabel == 3) {
7822 $out .= img_picto($langs->trans("Search"), 'search');
7823 }
7824 } else {
7825 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7826 }
7827
7828 if (empty($nooutput)) {
7829 print $out;
7830 } else {
7831 return $out;
7832 }
7833 return '';
7834 }
7835
7836
7853 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7854 {
7855 global $langs, $conf;
7856
7857 $out = '';
7858 $outarray = array();
7859
7860 $selectFields = " p.rowid, p.ref, p.message";
7861
7862 $sql = "SELECT ";
7863 $sql .= $selectFields;
7864 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7865 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7866
7867 // Add criteria on ref/label
7868 if ($filterkey != '') {
7869 $sql .= ' AND (';
7870 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7871 // For natural search
7872 $search_crit = explode(' ', $filterkey);
7873 $i = 0;
7874 if (count($search_crit) > 1) {
7875 $sql .= "(";
7876 }
7877 foreach ($search_crit as $crit) {
7878 if ($i > 0) {
7879 $sql .= " AND ";
7880 }
7881 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7882 $sql .= ")";
7883 $i++;
7884 }
7885 if (count($search_crit) > 1) {
7886 $sql .= ")";
7887 }
7888 $sql .= ')';
7889 }
7890
7891 $sql .= $this->db->plimit($limit, 0);
7892
7893 // Build output string
7894 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7895 $result = $this->db->query($sql);
7896 if ($result) {
7897 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7898 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7899
7900 $num = $this->db->num_rows($result);
7901
7902 $events = array();
7903
7904 if (!$forcecombo) {
7905 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7906 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('TICKET_USE_SEARCH_TO_SELECT'));
7907 }
7908
7909 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7910
7911 $textifempty = '';
7912 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7913 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7914 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7915 if ($showempty && !is_numeric($showempty)) {
7916 $textifempty = $langs->trans($showempty);
7917 } else {
7918 $textifempty .= $langs->trans("All");
7919 }
7920 } else {
7921 if ($showempty && !is_numeric($showempty)) {
7922 $textifempty = $langs->trans($showempty);
7923 }
7924 }
7925 if ($showempty) {
7926 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7927 }
7928
7929 $i = 0;
7930 while ($num && $i < $num) {
7931 $opt = '';
7932 $optJson = array();
7933 $objp = $this->db->fetch_object($result);
7934
7935 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7936 '@phan-var-force array{key:string,value:mixed,type:int} $optJson';
7937 // Add new entry
7938 // "key" value of json key array is used by jQuery automatically as selected value
7939 // "label" value of json key array is used by jQuery automatically as text for combo box
7940 $out .= $opt;
7941 array_push($outarray, $optJson);
7942
7943 $i++;
7944 }
7945
7946 $out .= '</select>';
7947
7948 $this->db->free($result);
7949
7950 if (empty($outputmode)) {
7951 return $out;
7952 }
7953 return $outarray;
7954 } else {
7955 dol_print_error($this->db);
7956 }
7957
7958 return array();
7959 }
7960
7972 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7973 {
7974 $outkey = '';
7975 $outref = '';
7976 $outtype = '';
7977
7978 $outkey = $objp->rowid;
7979 $outref = $objp->ref;
7980
7981 $opt = '<option value="' . $objp->rowid . '"';
7982 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7983 $opt .= '>';
7984 $opt .= $objp->ref;
7985 $objRef = $objp->ref;
7986 if (!empty($filterkey) && $filterkey != '') {
7987 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7988 }
7989
7990 $opt .= "</option>\n";
7991 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7992 }
7993
8013 public function selectProjects($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
8014 {
8015 global $langs, $conf;
8016
8017 $out = '';
8018
8019 // check parameters
8020 if (is_null($ajaxoptions)) {
8021 $ajaxoptions = array();
8022 }
8023
8024 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8025 $placeholder = '';
8026
8027 if ($selected && empty($selected_input_value)) {
8028 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8029 $projecttmpselect = new Project($this->db);
8030 $projecttmpselect->fetch($selected);
8031 $selected_input_value = $projecttmpselect->ref;
8032 unset($projecttmpselect);
8033 }
8034
8035 $urloption = '';
8036 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8037
8038 if (empty($hidelabel)) {
8039 $out .= $langs->trans("RefOrLabel") . ' : ';
8040 } elseif ($hidelabel > 1) {
8041 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8042 if ($hidelabel == 2) {
8043 $out .= img_picto($langs->trans("Search"), 'search');
8044 }
8045 }
8046 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8047 if ($hidelabel == 3) {
8048 $out .= img_picto($langs->trans("Search"), 'search');
8049 }
8050 } else {
8051 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8052 }
8053
8054 if (empty($nooutput)) {
8055 print $out;
8056 } else {
8057 return $out;
8058 }
8059 return '';
8060 }
8061
8078 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8079 {
8080 global $langs, $conf;
8081
8082 $out = '';
8083 $outarray = array();
8084
8085 $selectFields = " p.rowid, p.ref";
8086
8087 $sql = "SELECT ";
8088 $sql .= $selectFields;
8089 $sql .= " FROM " . $this->db->prefix() . "projet as p";
8090 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
8091
8092 // Add criteria on ref/label
8093 if ($filterkey != '') {
8094 $sql .= ' AND (';
8095 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8096 // For natural search
8097 $search_crit = explode(' ', $filterkey);
8098 $i = 0;
8099 if (count($search_crit) > 1) {
8100 $sql .= "(";
8101 }
8102 foreach ($search_crit as $crit) {
8103 if ($i > 0) {
8104 $sql .= " AND ";
8105 }
8106 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8107 $sql .= "";
8108 $i++;
8109 }
8110 if (count($search_crit) > 1) {
8111 $sql .= ")";
8112 }
8113 $sql .= ')';
8114 }
8115
8116 $sql .= $this->db->plimit($limit, 0);
8117
8118 // Build output string
8119 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
8120 $result = $this->db->query($sql);
8121 if ($result) {
8122 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8123 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
8124
8125 $num = $this->db->num_rows($result);
8126
8127 $events = array();
8128
8129 if (!$forcecombo) {
8130 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8131 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8132 }
8133
8134 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8135
8136 $textifempty = '';
8137 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8138 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8139 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8140 if ($showempty && !is_numeric($showempty)) {
8141 $textifempty = $langs->trans($showempty);
8142 } else {
8143 $textifempty .= $langs->trans("All");
8144 }
8145 } else {
8146 if ($showempty && !is_numeric($showempty)) {
8147 $textifempty = $langs->trans($showempty);
8148 }
8149 }
8150 if ($showempty) {
8151 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8152 }
8153
8154 $i = 0;
8155 while ($num && $i < $num) {
8156 $opt = '';
8157 $optJson = array();
8158 $objp = $this->db->fetch_object($result);
8159
8160 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
8161 // Add new entry
8162 // "key" value of json key array is used by jQuery automatically as selected value
8163 // "label" value of json key array is used by jQuery automatically as text for combo box
8164 $out .= $opt;
8165 array_push($outarray, $optJson);
8166
8167 $i++;
8168 }
8169
8170 $out .= '</select>';
8171
8172 $this->db->free($result);
8173
8174 if (empty($outputmode)) {
8175 return $out;
8176 }
8177 return $outarray;
8178 } else {
8179 dol_print_error($this->db);
8180 }
8181
8182 return array();
8183 }
8184
8196 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8197 {
8198 $outkey = '';
8199 $outref = '';
8200 $outtype = '';
8201
8202 $label = $objp->label;
8203
8204 $outkey = $objp->rowid;
8205 $outref = $objp->ref;
8206 $outlabel = $objp->label;
8207 $outtype = $objp->fk_product_type;
8208
8209 $opt = '<option value="' . $objp->rowid . '"';
8210 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8211 $opt .= '>';
8212 $opt .= $objp->ref;
8213 $objRef = $objp->ref;
8214 if (!empty($filterkey) && $filterkey != '') {
8215 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8216 }
8217
8218 $opt .= "</option>\n";
8219 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8220 }
8221
8222
8242 public function selectMembers($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
8243 {
8244 global $langs, $conf;
8245
8246 $out = '';
8247
8248 // check parameters
8249 if (is_null($ajaxoptions)) {
8250 $ajaxoptions = array();
8251 }
8252
8253 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8254 $placeholder = '';
8255
8256 if ($selected && empty($selected_input_value)) {
8257 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8258 $adherenttmpselect = new Adherent($this->db);
8259 $adherenttmpselect->fetch($selected);
8260 $selected_input_value = $adherenttmpselect->ref;
8261 unset($adherenttmpselect);
8262 }
8263
8264 $urloption = '';
8265
8266 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8267
8268 if (empty($hidelabel)) {
8269 $out .= $langs->trans("RefOrLabel") . ' : ';
8270 } elseif ($hidelabel > 1) {
8271 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8272 if ($hidelabel == 2) {
8273 $out .= img_picto($langs->trans("Search"), 'search');
8274 }
8275 }
8276 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8277 if ($hidelabel == 3) {
8278 $out .= img_picto($langs->trans("Search"), 'search');
8279 }
8280 } else {
8281 $filterkey = '';
8282
8283 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8284 }
8285
8286 if (empty($nooutput)) {
8287 print $out;
8288 } else {
8289 return $out;
8290 }
8291 return '';
8292 }
8293
8310 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8311 {
8312 global $langs, $conf;
8313
8314 $out = '';
8315 $outarray = array();
8316
8317 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8318
8319 $sql = "SELECT ";
8320 $sql .= $selectFields;
8321 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8322 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8323
8324 // Add criteria on ref/label
8325 if ($filterkey != '') {
8326 $sql .= ' AND (';
8327 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8328 // For natural search
8329 $search_crit = explode(' ', $filterkey);
8330 $i = 0;
8331 if (count($search_crit) > 1) {
8332 $sql .= "(";
8333 }
8334 foreach ($search_crit as $crit) {
8335 if ($i > 0) {
8336 $sql .= " AND ";
8337 }
8338 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8339 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8340 $i++;
8341 }
8342 if (count($search_crit) > 1) {
8343 $sql .= ")";
8344 }
8345 $sql .= ')';
8346 }
8347 if ($status != -1) {
8348 $sql .= ' AND statut = ' . ((int) $status);
8349 }
8350 $sql .= $this->db->plimit($limit, 0);
8351
8352 // Build output string
8353 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8354 $result = $this->db->query($sql);
8355 if ($result) {
8356 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8357 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8358
8359 $num = $this->db->num_rows($result);
8360
8361 $events = array();
8362
8363 if (!$forcecombo) {
8364 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8365 $out .= ajax_combobox($htmlname, $events, getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT') ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
8366 }
8367
8368 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8369
8370 $textifempty = '';
8371 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8372 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8373 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8374 if ($showempty && !is_numeric($showempty)) {
8375 $textifempty = $langs->trans($showempty);
8376 } else {
8377 $textifempty .= $langs->trans("All");
8378 }
8379 } else {
8380 if ($showempty && !is_numeric($showempty)) {
8381 $textifempty = $langs->trans($showempty);
8382 }
8383 }
8384 if ($showempty) {
8385 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8386 }
8387
8388 $i = 0;
8389 while ($num && $i < $num) {
8390 $opt = '';
8391 $optJson = array();
8392 $objp = $this->db->fetch_object($result);
8393
8394 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8395
8396 // Add new entry
8397 // "key" value of json key array is used by jQuery automatically as selected value
8398 // "label" value of json key array is used by jQuery automatically as text for combo box
8399 $out .= $opt;
8400 array_push($outarray, $optJson);
8401
8402 $i++;
8403 }
8404
8405 $out .= '</select>';
8406
8407 $this->db->free($result);
8408
8409 if (empty($outputmode)) {
8410 return $out;
8411 }
8412 return $outarray;
8413 } else {
8414 dol_print_error($this->db);
8415 }
8416
8417 return array();
8418 }
8419
8431 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8432 {
8433 $outkey = '';
8434 $outlabel = '';
8435 $outtype = '';
8436
8437 $outkey = $objp->rowid;
8438 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8439 $outtype = $objp->fk_adherent_type;
8440
8441 $opt = '<option value="' . $objp->rowid . '"';
8442 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8443 $opt .= '>';
8444 if (!empty($filterkey) && $filterkey != '') {
8445 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8446 }
8447 $opt .= $outlabel;
8448 $opt .= "</option>\n";
8449
8450 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8451 }
8452
8473 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8474 {
8475 global $conf, $extrafields, $user;
8476
8477 // Example of common usage for a link to a thirdparty
8478
8479 // We got this in a modulebuilder form of "MyObject" of module "mymodule".
8480 // ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8481 // $objectdesc = 'Societe'
8482 // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc'])
8483
8484 // We got this when showing an extrafields on resource that is a link to societe
8485 // extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)'
8486 // $objectdesc = 'Societe'
8487 // $objectfield = 'resource:options_link_to_societe'
8488
8489 // With old usage:
8490 // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))'
8491 // $objectfield = ''
8492
8493 //var_dump($objectdesc.' '.$objectfield);
8494 //debug_print_backtrace();
8495
8496 $objectdescorig = $objectdesc;
8497 $objecttmp = null;
8498 $InfoFieldList = array();
8499 $classname = '';
8500 $filter = ''; // Ensure filter has value (for static analysis)
8501 $sortfield = ''; // Ensure filter has value (for static analysis)
8502
8503 if ($objectfield) { // We must retrieve the objectdesc from the field or extrafield
8504 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8505 $tmparray = explode(':', $objectfield);
8506
8507 // Get instance of object from $element
8508 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8509
8510 if (is_object($objectforfieldstmp)) {
8511 $objectdesc = '';
8512
8513 $reg = array();
8514 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8515 // For a property in extrafields
8516 $key = $reg[1];
8517 // fetch optionals attributes and labels
8518 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8519
8520 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8521 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8522 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8523 $objectdesc = $tmpextrafields[0];
8524 }
8525 }
8526 } else {
8527 // For a property in ->fields
8528 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8529 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8530 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8531 }
8532 }
8533 }
8534 }
8535
8536 if ($objectdesc) {
8537 // Example of value for $objectdesc:
8538 // Bom:bom/class/bom.class.php:0:t.status=1
8539 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8540 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8541 $InfoFieldList = explode(":", $objectdesc, 4);
8542 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8543 $reg = array();
8544 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8545 $InfoFieldList[4] = $reg[1]; // take the sort field
8546 }
8547 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8548
8549 $classname = $InfoFieldList[0];
8550 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8551 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8552 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8553 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8554
8555 // Load object according to $id and $element
8556 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8557
8558 // Fallback to another solution to get $objecttmp
8559 if (empty($objecttmp) && !empty($classpath)) {
8560 dol_include_once($classpath);
8561
8562 if ($classname && class_exists($classname)) {
8563 $objecttmp = new $classname($this->db);
8564 }
8565 }
8566 }
8567
8568 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
8569 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
8570 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
8571 $filter = str_replace(
8572 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
8573 array($conf->entity, $sharedentities, $user->id),
8574 $filter
8575 );
8576
8577 if (!is_object($objecttmp)) {
8578 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc, LOG_WARNING);
8579 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc;
8580 }
8581 '@phan-var-force CommonObject $objecttmp';
8583 //var_dump($filter);
8584 $prefixforautocompletemode = $objecttmp->element;
8585 if ($prefixforautocompletemode == 'societe') {
8586 $prefixforautocompletemode = 'company';
8587 }
8588 if ($prefixforautocompletemode == 'product') {
8589 $prefixforautocompletemode = 'produit';
8590 }
8591 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8592
8593 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
8594
8595 // Generate the combo HTML component
8596 $out = '';
8597 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
8598 // No immediate load of all database
8599 $placeholder = '';
8600
8601 if ($preSelectedValue && empty($selected_input_value)) {
8602 $objecttmp->fetch($preSelectedValue);
8603 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
8604
8605 $oldValueForShowOnCombobox = 0;
8606 foreach ($objecttmp->fields as $fieldK => $fielV) {
8607 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
8608 continue;
8609 }
8610
8611 if (!$oldValueForShowOnCombobox) {
8612 $selected_input_value = '';
8613 }
8614
8615 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
8616 $selected_input_value .= $objecttmp->$fieldK;
8617 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
8618 }
8619 }
8620
8621 // Set url and param to call to get json of the search results
8622 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
8623 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . '&objectfield='.urlencode($objectfield) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
8624
8625 // Activate the auto complete using ajax call.
8626 $out .= ajax_autocompleter((string) $preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalInt($confkeyforautocompletemode), 0);
8627 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
8628 $out .= '<input type="text" class="' . $morecss . '"' . ($disabled ? ' disabled="disabled"' : '') . ' name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' />';
8629 } else {
8630 // Immediate load of table record.
8631 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
8632 }
8633
8634 return $out;
8635 }
8636
8637
8658 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
8659 {
8660 global $langs, $user, $hookmanager;
8661
8662 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
8663
8664 $prefixforautocompletemode = $objecttmp->element;
8665 if ($prefixforautocompletemode == 'societe') {
8666 $prefixforautocompletemode = 'company';
8667 }
8668 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8669
8670 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
8671 $tmpfieldstoshow = '';
8672 foreach ($objecttmp->fields as $key => $val) {
8673 if (! (int) dol_eval($val['enabled'], 1, 1, '1')) {
8674 continue;
8675 }
8676 if (!empty($val['showoncombobox'])) {
8677 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8678 }
8679 }
8680 if ($tmpfieldstoshow) {
8681 $fieldstoshow = $tmpfieldstoshow;
8682 }
8683 } else {
8684 // For backward compatibility
8685 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8686 }
8687
8688 if (empty($fieldstoshow)) {
8689 if (!empty($objecttmp->parent_element)) {
8690 $fieldstoshow = 'o.ref';
8691 if (empty($sortfield)) {
8692 $sortfield = 'o.ref';
8693 }
8694 if (in_array($objecttmp->element, ['commandedet', 'propaldet', 'facturedet', 'expeditiondet'])) {
8695 $fieldstoshow .= ',p.ref AS p_ref,p.label,t.description';
8696 $sortfield .= ', p.ref';
8697 }
8698 } elseif (isset($objecttmp->fields['ref'])) {
8699 $fieldstoshow = 't.ref';
8700 } else {
8701 $langs->load("errors");
8702 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8703 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8704 }
8705 }
8706
8707 $out = '';
8708 $outarray = array();
8709 $tmparray = array();
8710
8711 $num = 0;
8712
8713 // Search data
8714 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . " as t";
8715 if (!empty($objecttmp->isextrafieldmanaged)) {
8716 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . "_extrafields as e ON t.rowid = e.fk_object";
8717 }
8718 if (!empty($objecttmp->parent_element)) {
8719 $parent_properties = getElementProperties($objecttmp->parent_element);
8720 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($parent_properties['table_element']) . " as o ON o.rowid = t.".$objecttmp->fk_parent_attribute;
8721 }
8722 if (in_array($objecttmp->parent_element, ['commande', 'propal', 'facture', 'expedition'])) {
8723 $sql .= " LEFT JOIN " . $this->db->prefix() . "product as p ON p.rowid = t.fk_product";
8724 }
8725 if (isset($objecttmp->ismultientitymanaged)) {
8726 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8727 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8728 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($tmparray[1]) . " as parenttable ON parenttable.rowid = t." . $this->db->sanitize($tmparray[0]);
8729 }
8730 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8731 if (!$user->hasRight('societe', 'client', 'voir')) {
8732 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8733 }
8734 }
8735 }
8736
8737 // Add where from hooks
8738 $parameters = array(
8739 'object' => $objecttmp,
8740 'htmlname' => $htmlname,
8741 'filter' => $filter,
8742 'searchkey' => $searchkey
8743 );
8744
8745 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8746 if (!empty($hookmanager->resPrint)) {
8747 $sql .= $hookmanager->resPrint;
8748 } else {
8749 $sql .= " WHERE 1=1";
8750 if (isset($objecttmp->ismultientitymanaged)) {
8751 if ($objecttmp->ismultientitymanaged == 1) {
8752 $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8753 }
8754 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8755 $sql .= " AND parenttable.entity = t." . $this->db->sanitize($tmparray[0]);
8756 }
8757 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8758 if ($objecttmp->element == 'societe') {
8759 $sql .= " AND t.rowid = " . ((int) $user->socid);
8760 } else {
8761 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8762 }
8763 }
8764 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8765 if (!$user->hasRight('societe', 'client', 'voir')) {
8766 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8767 }
8768 }
8769 }
8770 $splittedfieldstoshow = explode(',', $fieldstoshow);
8771 foreach ($splittedfieldstoshow as &$field2) {
8772 if (is_numeric($pos=strpos($field2, ' '))) {
8773 $field2 = substr($field2, 0, $pos);
8774 }
8775 }
8776 if ($searchkey != '') {
8777 $sql .= natural_search($splittedfieldstoshow, $searchkey);
8778 }
8779
8780 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8781 $errormessage = '';
8782 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8783 if ($errormessage) {
8784 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8785 }
8786 }
8787 }
8788 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8789 //$sql.=$this->db->plimit($limit, 0);
8790 //print $sql;
8791
8792 // Build output string
8793 $resql = $this->db->query($sql);
8794 if ($resql) {
8795 // Construct $out and $outarray
8796 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8797
8798 // Warning: Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'. Seems it is no more true with selec2 v4
8799 $textifempty = '&nbsp;';
8800
8801 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8802 if (getDolGlobalInt($confkeyforautocompletemode)) {
8803 if ($showempty && !is_numeric($showempty)) {
8804 $textifempty = $langs->trans($showempty);
8805 } else {
8806 $textifempty .= $langs->trans("All");
8807 }
8808 }
8809 if ($showempty) {
8810 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8811 }
8812
8813 $num = $this->db->num_rows($resql);
8814 $i = 0;
8815 if ($num) {
8816 while ($i < $num) {
8817 $obj = $this->db->fetch_object($resql);
8818 $label = '';
8819 $labelhtml = '';
8820 $tmparray = explode(',', $fieldstoshow);
8821 $oldvalueforshowoncombobox = 0;
8822 foreach ($tmparray as $key => $val) {
8823 $val = preg_replace('/(t|p|o)\./', '', $val);
8824 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8825 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8826 $label .= $obj->$val;
8827 $labelhtml .= $obj->$val;
8828
8829 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8830 }
8831 if (empty($outputmode)) {
8832 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8833 $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>';
8834 } else {
8835 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8836 }
8837 } else {
8838 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8839 }
8840
8841 $i++;
8842 if (($i % 10) == 0) {
8843 $out .= "\n";
8844 }
8845 }
8846 }
8847
8848 $out .= '</select>' . "\n";
8849
8850 if (!$forcecombo) {
8851 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8852 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
8853 }
8854 } else {
8855 dol_print_error($this->db);
8856 }
8857
8858 $this->result = array('nbofelement' => $num);
8859
8860 if ($outputmode) {
8861 return $outarray;
8862 }
8863 return $out;
8864 }
8865
8866
8890 public static function selectarray($htmlname, $array, $id = '', $show_empty = 0, $key_in_label = 0, $value_as_key = 0, $moreparam = '', $translate = 0, $maxlen = 0, $disabled = 0, $sort = '', $morecss = 'minwidth75', $addjscombo = 1, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
8891 {
8892 global $conf, $langs;
8893
8894 // Do we want a multiselect ?
8895 //$jsbeautify = 0;
8896 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8897 $jsbeautify = 1;
8898
8899 if ($value_as_key) {
8900 $array = array_combine($array, $array);
8901 }
8902
8903 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
8904
8905 $out = '';
8906
8907 if ($addjscombo < 0) {
8908 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8909 $addjscombo = 1;
8910 } else {
8911 $addjscombo = 0;
8912 }
8913 }
8914 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8915 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8916 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8917 $out .= '>'."\n";
8918
8919 if ($show_empty) {
8920 $textforempty = ' ';
8921 if (!empty($conf->use_javascript_ajax)) {
8922 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8923 }
8924 if (!is_numeric($show_empty)) {
8925 $textforempty = $show_empty;
8926 }
8927 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8928 }
8929 if (is_array($array)) {
8930 // Translate
8931 if ($translate) {
8932 foreach ($array as $key => $value) {
8933 if (!is_array($value)) {
8934 $array[$key] = $langs->trans($value);
8935 } else {
8936 $array[$key]['label'] = $langs->trans($value['label']);
8937 }
8938 }
8939 }
8940 // Sort
8941 if ($sort == 'ASC') {
8942 asort($array);
8943 } elseif ($sort == 'DESC') {
8944 arsort($array);
8945 }
8946
8947 foreach ($array as $key => $tmpvalue) {
8948 if (is_array($tmpvalue)) {
8949 $value = $tmpvalue['label'];
8950 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
8951 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8952 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8953 } else {
8954 $value = $tmpvalue;
8955 //$valuehtml = $tmpvalue;
8956 $disabled = '';
8957 $style = '';
8958 }
8959 if (!empty($disablebademail)) {
8960 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8961 || ($disablebademail == 2 && preg_match('/---/', $value))) {
8962 $disabled = ' disabled';
8963 $style = ' class="warning"';
8964 }
8965 }
8966 if ($key_in_label) {
8967 if (empty($nohtmlescape)) {
8968 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8969 } else {
8970 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8971 }
8972 } else {
8973 if (empty($nohtmlescape)) {
8974 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
8975 } else {
8976 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8977 }
8978 if ($value == '' || $value == '-') {
8979 $selectOptionValue = '&nbsp;';
8980 }
8981 }
8982 $out .= '<option value="' . $key . '"';
8983 $out .= $style . $disabled;
8984 if (is_array($id)) {
8985 if (in_array($key, $id) && !$disabled) {
8986 $out .= ' selected'; // To preselect a value
8987 }
8988 } else {
8989 $id = (string) $id; // if $id = 0, then $id = '0'
8990 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8991 $out .= ' selected'; // To preselect a value
8992 }
8993 }
8994 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
8995 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
8996 }
8997
8998 if (is_array($tmpvalue)) {
8999 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
9000 if ($keyforvalue == 'labelhtml') {
9001 $keyforvalue = 'data-html';
9002 }
9003 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
9004 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
9005 }
9006 }
9007 }
9008 $out .= '>';
9009 $out .= $selectOptionValue;
9010 $out .= "</option>\n";
9011 }
9012 }
9013 $out .= "</select>";
9014
9015 // Add code for jquery to use multiselect
9016 if ($addjscombo && $jsbeautify) {
9017 // Enhance with select2
9018 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9019 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
9020 }
9021
9022 return $out;
9023 }
9024
9043 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
9044 {
9045 global $conf, $langs;
9046 global $delayedhtmlcontent; // Will be used later outside of this function
9047
9048 // TODO Use an internal dolibarr component instead of select2
9049 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9050 return '';
9051 }
9052
9053 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
9054
9055 $outdelayed = '';
9056 if (!empty($conf->use_javascript_ajax)) {
9057 $tmpplugin = 'select2';
9058 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9059 <script nonce="' . getNonce() . '">
9060 $(document).ready(function () {
9061
9062 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
9063
9064 $(".' . $htmlname . '").select2({
9065 ajax: {
9066 dir: "ltr",
9067 url: "' . $url . '",
9068 dataType: \'json\',
9069 delay: 250,
9070 data: function (params) {
9071 return {
9072 q: params.term, // search term
9073 page: params.page
9074 }
9075 },
9076 processResults: function (data) {
9077 // parse the results into the format expected by Select2.
9078 // since we are using custom formatting functions we do not need to alter the remote JSON data
9079 //console.log(data);
9080 saveRemoteData = data;
9081 /* format json result for select2 */
9082 result = []
9083 $.each( data, function( key, value ) {
9084 result.push({id: key, text: value.text});
9085 });
9086 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
9087 //console.log(result);
9088 return {results: result, more: false}
9089 },
9090 cache: true
9091 },
9092 language: select2arrayoflanguage,
9093 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9094 placeholder: "' . dol_escape_js($placeholder) . '",
9095 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9096 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9097 formatResult: function (result, container, query, escapeMarkup) {
9098 return escapeMarkup(result.text);
9099 },
9100 });
9101
9102 ' . ($callurlonselect ? '
9103 /* Code to execute a GET when we select a value */
9104 $(".' . $htmlname . '").change(function() {
9105 var selected = $(".' . $htmlname . '").val();
9106 console.log("We select in selectArrayAjax the entry "+selected)
9107 $(".' . $htmlname . '").val(""); /* reset visible combo value */
9108 $.each( saveRemoteData, function( key, value ) {
9109 if (key == selected)
9110 {
9111 console.log("selectArrayAjax - Do a redirect to "+value.url)
9112 location.assign(value.url);
9113 }
9114 });
9115 });' : '') . '
9116
9117 });
9118 </script>';
9119 }
9120
9121 if ($acceptdelayedhtml) {
9122 $delayedhtmlcontent .= $outdelayed;
9123 } else {
9124 $out .= $outdelayed;
9125 }
9126 return $out;
9127 }
9128
9148 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
9149 {
9150 global $conf, $langs;
9151 global $delayedhtmlcontent; // Will be used later outside of this function
9152
9153 // TODO Use an internal dolibarr component instead of select2
9154 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9155 return '';
9156 }
9157
9158 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
9159
9160 $formattedarrayresult = array();
9161
9162 foreach ($array as $key => $value) {
9163 $o = new stdClass();
9164 $o->id = $key;
9165 $o->text = $value['text'];
9166 $o->url = $value['url'];
9167 $formattedarrayresult[] = $o;
9168 }
9169
9170 $outdelayed = '';
9171 if (!empty($conf->use_javascript_ajax)) {
9172 $tmpplugin = 'select2';
9173 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9174 <script nonce="' . getNonce() . '">
9175 $(document).ready(function () {
9176 var data = ' . json_encode($formattedarrayresult) . ';
9177
9178 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
9179
9180 $(".' . $htmlname . '").select2({
9181 data: data,
9182 language: select2arrayoflanguage,
9183 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9184 placeholder: "' . dol_escape_js($placeholder) . '",
9185 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9186 minimumInputLength: ' . $minimumInputLength . ',
9187 formatResult: function (result, container, query, escapeMarkup) {
9188 return escapeMarkup(result.text);
9189 },
9190 matcher: function (params, data) {
9191
9192 if(! data.id) return null;';
9193
9194 if ($callurlonselect) {
9195 // We forge the url with 'sall='
9196 $outdelayed .= '
9197
9198 var urlBase = data.url;
9199 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
9200 /* console.log("params.term="+params.term); */
9201 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
9202 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
9203 }
9204
9205 if (!$disableFiltering) {
9206 $outdelayed .= '
9207
9208 if(data.text.match(new RegExp(params.term))) {
9209 return data;
9210 }
9211
9212 return null;';
9213 } else {
9214 $outdelayed .= '
9215
9216 return data;';
9217 }
9218
9219 $outdelayed .= '
9220 }
9221 });
9222
9223 ' . ($callurlonselect ? '
9224 /* Code to execute a GET when we select a value */
9225 $(".' . $htmlname . '").change(function() {
9226 var selected = $(".' . $htmlname . '").val();
9227 console.log("We select "+selected)
9228
9229 $(".' . $htmlname . '").val(""); /* reset visible combo value */
9230 $.each( saveRemoteData, function( key, value ) {
9231 if (key == selected)
9232 {
9233 console.log("selectArrayFilter - Do a redirect to "+value.url)
9234 location.assign(value.url);
9235 }
9236 });
9237 });' : '') . '
9238
9239 });
9240 </script>';
9241 }
9242
9243 if ($acceptdelayedhtml) {
9244 $delayedhtmlcontent .= $outdelayed;
9245 } else {
9246 $out .= $outdelayed;
9247 }
9248 return $out;
9249 }
9250
9269 public static function multiselectarray($htmlname, $array, $selected = array(), $key_in_label = 0, $value_as_key = 0, $morecss = '', $translate = 0, $width = 0, $moreattrib = '', $elemtype = '', $placeholder = '', $addjscombo = -1)
9270 {
9271 global $conf, $langs;
9272 $out = '';
9273
9274 if ($addjscombo < 0) {
9275 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9276 $addjscombo = 1;
9277 } else {
9278 $addjscombo = 0;
9279 }
9280 }
9281
9282 $useenhancedmultiselect = 0;
9283 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9284 if ($addjscombo) {
9285 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9286 }
9287 }
9288
9289 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9290 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9291 // submitted to nothing.
9292 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9293 // Output select component
9294 $out .= '<select id="' . $htmlname . '" class="multiselect' . ($useenhancedmultiselect ? ' multiselectononeline' : '') . ($morecss ? ' ' . $morecss : '') . '" multiple name="' . $htmlname . '[]"' . ($moreattrib ? ' ' . $moreattrib : '') . ($width ? ' style="width: ' . (preg_match('/%/', (string) $width) ? $width : $width . 'px') . '"' : '') . '>' . "\n";
9295 if (is_array($array) && !empty($array)) {
9296 if ($value_as_key) {
9297 $array = array_combine($array, $array);
9298 }
9299
9300 if (!empty($array)) {
9301 foreach ($array as $key => $value) {
9302 $tmpkey = $key;
9303 $tmpvalue = $value;
9304 $tmpcolor = '';
9305 $tmppicto = '';
9306 $tmplabelhtml = '';
9307 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9308 $tmpkey = $value['id'];
9309 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9310 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9311 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9312 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']) : $value['labelhtml'];
9313 }
9314 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9315 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9316
9317 $out .= '<option value="' . $tmpkey . '"';
9318 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9319 $out .= ' selected';
9320 }
9321 if (!empty($tmplabelhtml)) {
9322 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9323 } else {
9324 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9325 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9326 }
9327 $out .= '>';
9328 $out .= dol_htmlentitiesbr($newval);
9329 $out .= '</option>' . "\n";
9330 }
9331 }
9332 }
9333 $out .= '</select>' . "\n";
9334
9335 // Add code for jquery to use multiselect
9336 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9337 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9338 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9339 if ($addjscombo == 1) {
9340 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
9341 $out .= 'function formatResult(record, container) {' . "\n";
9342 // If property data-html set, we decode html entities and use this.
9343 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9344 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9345 //$out .= ' console.log("aaa");';
9346 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9347 $out .= ' }'."\n";
9348 $out .= ' return record.text;';
9349 $out .= '}' . "\n";
9350 $out .= 'function formatSelection(record) {' . "\n";
9351 if ($elemtype == 'category') {
9352 $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
9353 } else {
9354 $out .= 'return record.text;';
9355 }
9356 $out .= '}' . "\n";
9357 $out .= '$(document).ready(function () {
9358 $(\'#' . $htmlname . '\').' . $tmpplugin . '({';
9359 if ($placeholder) {
9360 $out .= '
9361 placeholder: {
9362 id: \'-1\',
9363 text: \'' . dol_escape_js($placeholder) . '\'
9364 },';
9365 }
9366 $out .= ' dir: \'ltr\',
9367 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9368 dropdownCssClass: \'' . $morecss . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
9369 // Specify format function for dropdown item
9370 formatResult: formatResult,
9371 templateResult: formatResult, /* For 4.0 */
9372 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9373 // Specify format function for selected item
9374 formatSelection: formatSelection,
9375 templateSelection: formatSelection /* For 4.0 */
9376 });
9377
9378 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
9379 the size only if component is not hidden by default on load */
9380 $(\'#' . $htmlname . ' + .select2\').addClass(\'' . $morecss . '\');
9381 });' . "\n";
9382 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9383 // Add other js lib
9384 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9385 // ...
9386 $out .= 'console.log(\'addjscombo=2 for htmlname=' . $htmlname . '\');';
9387 $out .= '$(document).ready(function () {
9388 $(\'#' . $htmlname . '\').multiSelect({
9389 containerHTML: \'<div class="multi-select-container">\',
9390 menuHTML: \'<div class="multi-select-menu">\',
9391 buttonHTML: \'<span class="multi-select-button ' . $morecss . '">\',
9392 menuItemHTML: \'<label class="multi-select-menuitem">\',
9393 activeClass: \'multi-select-container--open\',
9394 noneText: \'' . $placeholder . '\'
9395 });
9396 })';
9397 }
9398 $out .= '</script>';
9399 }
9400
9401 return $out;
9402 }
9403
9404
9416 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9417 {
9418 global $langs, $user;
9419
9420 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9421 return '';
9422 }
9423 if (empty($array)) {
9424 return '';
9425 }
9426
9427 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9428
9429 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9430 $tmparray = explode(',', $user->conf->$tmpvar);
9431 foreach ($array as $key => $val) {
9432 //var_dump($key);
9433 //var_dump($tmparray);
9434 if (in_array($key, $tmparray)) {
9435 $array[$key]['checked'] = 1;
9436 } else {
9437 $array[$key]['checked'] = 0;
9438 }
9439 }
9440 } else { // There is no list of fields already customized for user
9441 foreach ($array as $key => $val) {
9442 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9443 $array[$key]['checked'] = 0;
9444 }
9445 }
9446 }
9447
9448 $listoffieldsforselection = '';
9449 $listcheckedstring = '';
9450
9451 foreach ($array as $key => $val) {
9452 // var_dump($val);
9453 // var_dump(array_key_exists('enabled', $val));
9454 // var_dump(!$val['enabled']);
9455 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9456 unset($array[$key]); // We don't want this field
9457 continue;
9458 }
9459 if (!empty($val['type']) && $val['type'] == 'separate') {
9460 // Field remains in array but we don't add it into $listoffieldsforselection
9461 //$listoffieldsforselection .= '<li>-----</li>';
9462 continue;
9463 }
9464 if (!empty($val['label']) && $val['label']) {
9465 if (!empty($val['langfile']) && is_object($langs)) {
9466 $langs->load($val['langfile']);
9467 }
9468
9469 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9470 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((!array_key_exists('checked', $val) || empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . '/><label for="checkbox' . $key . '">' . dol_escape_htmltag($langs->trans($val['label'])) . '</label></li>';
9471 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9472 }
9473 }
9474
9475 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9476
9477 <dl class="dropdown">
9478 <dt>
9479 <a href="#' . $htmlname . '">
9480 ' . img_picto('', 'list') . '
9481 </a>
9482 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9483 </dt>
9484 <dd class="dropdowndd">
9485 <div class="multiselectcheckbox'.$htmlname.'">
9486 <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
9487 <li class="liinputsearch"><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
9488 '.$listoffieldsforselection.'
9489 </ul>
9490 </div>
9491 </dd>
9492 </dl>
9493
9494 <script nonce="' . getNonce() . '" type="text/javascript">
9495 jQuery(document).ready(function () {
9496 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
9497 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9498
9499 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9500
9501 var title = $(this).val() + ",";
9502 if ($(this).is(\':checked\')) {
9503 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9504 }
9505 else {
9506 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9507 }
9508 // Now, we submit page
9509 //$(this).parents(\'form:first\').submit();
9510 });
9511 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9512 var value = $(this).val().toLowerCase();
9513 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9514 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9515 });
9516 });
9517
9518
9519 });
9520 </script>
9521
9522 ';
9523 return $out;
9524 }
9525
9535 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
9536 {
9537 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
9538
9539 $cat = new Categorie($this->db);
9540 $categories = $cat->containing($id, $type);
9541
9542 if ($rendermode == 1) {
9543 $toprint = array();
9544 foreach ($categories as $c) {
9545 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
9546 foreach ($ways as $way) {
9547 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
9548 }
9549 }
9550 if (empty($toprint)) {
9551 return '';
9552 } else {
9553 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
9554 }
9555 }
9556
9557 if ($rendermode == 0) {
9558 $arrayselected = array();
9559 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
9560 foreach ($categories as $c) {
9561 $arrayselected[] = $c->id;
9562 }
9563
9564 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
9565 }
9566
9567 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
9568 }
9569
9579 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
9580 {
9581 global $conf, $langs, $hookmanager;
9582 global $action;
9583
9584 $object->fetchObjectLinked();
9585
9586 // Bypass the default method
9587 $hookmanager->initHooks(array('commonobject'));
9588 $parameters = array(
9589 'morehtmlright' => $morehtmlright,
9590 'compatibleImportElementsList' => &$compatibleImportElementsList,
9591 );
9592 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9593
9594 $nbofdifferenttypes = count($object->linkedObjects);
9595
9596 if (empty($reshook)) {
9597 print '<!-- showLinkedObjectBlock -->';
9598 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, '', 'showlinkedobjectblock');
9599
9600
9601 print '<div class="div-table-responsive-no-min">';
9602 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
9603
9604 print '<tr class="liste_titre">';
9605 print '<td>' . $langs->trans("Type") . '</td>';
9606 print '<td>' . $langs->trans("Ref") . '</td>';
9607 print '<td class="center"></td>';
9608 print '<td class="center">' . $langs->trans("Date") . '</td>';
9609 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9610 print '<td class="right">' . $langs->trans("Status") . '</td>';
9611 print '<td></td>';
9612 print '</tr>';
9613
9614 $nboftypesoutput = 0;
9615
9616 foreach ($object->linkedObjects as $objecttype => $objects) {
9617 $tplpath = $element = $subelement = $objecttype;
9618
9619 // to display import button on tpl
9620 $showImportButton = false;
9621 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
9622 $showImportButton = true;
9623 }
9624
9625 $regs = array();
9626 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
9627 $element = $regs[1];
9628 $subelement = $regs[2];
9629 $tplpath = $element . '/' . $subelement;
9630 }
9631 $tplname = 'linkedobjectblock';
9632
9633 // To work with non standard path
9634 if ($objecttype == 'facture') {
9635 $tplpath = 'compta/' . $element;
9636 if (!isModEnabled('invoice')) {
9637 continue; // Do not show if module disabled
9638 }
9639 } elseif ($objecttype == 'facturerec') {
9640 $tplpath = 'compta/facture';
9641 $tplname = 'linkedobjectblockForRec';
9642 if (!isModEnabled('invoice')) {
9643 continue; // Do not show if module disabled
9644 }
9645 } elseif ($objecttype == 'propal') {
9646 $tplpath = 'comm/' . $element;
9647 if (!isModEnabled('propal')) {
9648 continue; // Do not show if module disabled
9649 }
9650 } elseif ($objecttype == 'supplier_proposal') {
9651 if (!isModEnabled('supplier_proposal')) {
9652 continue; // Do not show if module disabled
9653 }
9654 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
9655 $tplpath = 'expedition';
9656 if (!isModEnabled('shipping')) {
9657 continue; // Do not show if module disabled
9658 }
9659 } elseif ($objecttype == 'reception') {
9660 $tplpath = 'reception';
9661 if (!isModEnabled('reception')) {
9662 continue; // Do not show if module disabled
9663 }
9664 } elseif ($objecttype == 'delivery') {
9665 $tplpath = 'delivery';
9666 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
9667 continue; // Do not show if sub module disabled
9668 }
9669 } elseif ($objecttype == 'ficheinter') {
9670 $tplpath = 'fichinter';
9671 if (!isModEnabled('intervention')) {
9672 continue; // Do not show if module disabled
9673 }
9674 } elseif ($objecttype == 'invoice_supplier') {
9675 $tplpath = 'fourn/facture';
9676 } elseif ($objecttype == 'order_supplier') {
9677 $tplpath = 'fourn/commande';
9678 } elseif ($objecttype == 'expensereport') {
9679 $tplpath = 'expensereport';
9680 } elseif ($objecttype == 'subscription') {
9681 $tplpath = 'adherents';
9682 } elseif ($objecttype == 'conferenceorbooth') {
9683 $tplpath = 'eventorganization';
9684 } elseif ($objecttype == 'conferenceorboothattendee') {
9685 $tplpath = 'eventorganization';
9686 } elseif ($objecttype == 'mo') {
9687 $tplpath = 'mrp';
9688 if (!isModEnabled('mrp')) {
9689 continue; // Do not show if module disabled
9690 }
9691 } elseif ($objecttype == 'project_task') {
9692 $tplpath = 'projet/tasks';
9693 }
9694
9695 global $linkedObjectBlock;
9696 $linkedObjectBlock = $objects;
9697
9698 // Output template part (modules that overwrite templates must declare this into descriptor)
9699 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
9700 foreach ($dirtpls as $reldir) {
9701 $reldir = rtrim($reldir, '/');
9702 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
9703 global $noMoreLinkedObjectBlockAfter;
9704 $noMoreLinkedObjectBlockAfter = 1;
9705 }
9706
9707 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
9708 if ($res) {
9709 $nboftypesoutput++;
9710 break;
9711 }
9712 }
9713 }
9714
9715 if (!$nboftypesoutput) {
9716 print '<tr><td colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9717 }
9718
9719 print '</table>';
9720
9721 if (!empty($compatibleImportElementsList)) {
9722 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9723 }
9724
9725 print '</div>';
9726 }
9727
9728 return $nbofdifferenttypes;
9729 }
9730
9740 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array(), $nooutput = 0)
9741 {
9742 global $conf, $langs, $hookmanager, $form;
9743 global $action;
9744
9745 if (empty($form)) {
9746 $form = new Form($this->db);
9747 }
9748
9749 $linktoelem = '';
9750 $linktoelemlist = '';
9751 $listofidcompanytoscan = '';
9752
9753 if (!is_object($object->thirdparty)) {
9754 $object->fetch_thirdparty();
9755 }
9756
9757 $possiblelinks = array();
9758
9759 $dontIncludeCompletedItems = getDolGlobalString('DONT_INCLUDE_COMPLETED_ELEMENTS_LINKS');
9760
9761 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9762 $listofidcompanytoscan = (int) $object->thirdparty->id;
9763 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
9764 $listofidcompanytoscan .= ',' . (int) $object->thirdparty->parent;
9765 }
9766 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
9767 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9768 $tmpproject = new Project($this->db);
9769 $tmpproject->fetch($object->fk_project);
9770 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9771 $listofidcompanytoscan .= ',' . (int) $tmpproject->socid;
9772 }
9773 unset($tmpproject);
9774 }
9775
9776 $possiblelinks = array(
9777 'propal' => array(
9778 'enabled' => isModEnabled('propal'),
9779 'perms' => 1,
9780 'label' => 'LinkToProposal',
9781 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('propal') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 4' : ''),
9782 ),
9783 'shipping' => array(
9784 'enabled' => isModEnabled('shipping'),
9785 'perms' => 1,
9786 'label' => 'LinkToExpedition',
9787 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "expedition as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('shipping') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 2' : ''),
9788 ),
9789 'order' => array(
9790 'enabled' => isModEnabled('order'),
9791 'perms' => 1,
9792 'label' => 'LinkToOrder',
9793 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('commande') . ')'.($dontIncludeCompletedItems ? ' AND t.facture < 1' : ''),
9794 'linkname' => 'commande',
9795 ),
9796 'invoice' => array(
9797 'enabled' => isModEnabled('invoice'),
9798 'perms' => 1,
9799 'label' => 'LinkToInvoice',
9800 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('invoice') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : ''),
9801 'linkname' => 'facture',
9802 ),
9803 'invoice_template' => array(
9804 'enabled' => isModEnabled('invoice'),
9805 'perms' => 1,
9806 'label' => 'LinkToTemplateInvoice',
9807 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('invoice') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : ''),
9808 ),
9809 'contrat' => array(
9810 'enabled' => isModEnabled('contract'),
9811 'perms' => 1,
9812 'label' => 'LinkToContract',
9813 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_customer as ref_client, t.ref_supplier, SUM(td.total_ht) as total_ht
9814 FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "contrat as t, " . $this->db->prefix() . "contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('contract') . ') GROUP BY s.rowid, s.nom, s.client, t.rowid, t.ref, t.ref_customer, t.ref_supplier',
9815 ),
9816 'fichinter' => array(
9817 'enabled' => isModEnabled('intervention'),
9818 'perms' => 1,
9819 'label' => 'LinkToIntervention',
9820 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('intervention') . ')',
9821 ),
9822 'supplier_proposal' => array(
9823 'enabled' => isModEnabled('supplier_proposal'),
9824 'perms' => 1,
9825 'label' => 'LinkToSupplierProposal',
9826 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('supplier_proposal') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 4' : ''),
9827 ),
9828 'order_supplier' => array(
9829 'enabled' => isModEnabled("supplier_order"),
9830 'perms' => 1,
9831 'label' => 'LinkToSupplierOrder',
9832 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('commande_fournisseur') . ')'.($dontIncludeCompletedItems ? ' AND t.billed < 1' : ''),
9833 ),
9834 'invoice_supplier' => array(
9835 'enabled' => isModEnabled("supplier_invoice"),
9836 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9837 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('facture_fourn') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : ''),
9838 ),
9839 'ticket' => array(
9840 'enabled' => isModEnabled('ticket'),
9841 'perms' => 1,
9842 'label' => 'LinkToTicket',
9843 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('ticket') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 8' : ''),
9844 ),
9845 'mo' => array(
9846 'enabled' => isModEnabled('mrp'),
9847 'perms' => 1,
9848 'label' => 'LinkToMo',
9849 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM " . $this->db->prefix() . "societe as s INNER JOIN " . $this->db->prefix() . "mrp_mo as t ON t.fk_soc = s.rowid WHERE t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('mo') . ')'.($dontIncludeCompletedItems ? ' AND t.status < 3' : ''),
9850 ),
9851 );
9852 }
9853
9854 if ($object->table_element == 'commande_fournisseur') {
9855 $possiblelinks['mo']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM ".$this->db->prefix()."societe as s INNER JOIN ".$this->db->prefix().'mrp_mo as t ON t.fk_soc = s.rowid WHERE t.entity IN ('.getEntity('mo').')'.($dontIncludeCompletedItems ? ' AND t.status < 3' : '');
9856 } elseif ($object->table_element == 'mrp_mo') {
9857 $possiblelinks['order_supplier']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix().'commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.entity IN ('.getEntity('commande_fournisseur').')'.($dontIncludeCompletedItems ? ' AND t.billed < 1' : '');
9858 }
9859
9860 $reshook = 0; // Ensure $reshook is defined for static analysis
9861 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9862 // Can complete the possiblelink array
9863 $hookmanager->initHooks(array('commonobject'));
9864 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9865 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9866 }
9867
9868 if (empty($reshook)) {
9869 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9870 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9871 }
9872 } elseif ($reshook > 0) {
9873 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9874 $possiblelinks = $hookmanager->resArray;
9875 }
9876 }
9877
9878 if (!empty($possiblelinks)) {
9879 $object->fetchObjectLinked();
9880 }
9881
9882 // Build the html part with possible suggested links
9883 $htmltoenteralink = '';
9884 foreach ($possiblelinks as $key => $possiblelink) {
9885 $num = 0;
9886 if (empty($possiblelink['enabled'])) {
9887 continue;
9888 }
9889
9890 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9891 $htmltoenteralink .= '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9892
9893 // Section for free ref input
9894 if (!getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9895 $htmltoenteralink .= '<br>'."\n";
9896 $htmltoenteralink .= '<!-- form to add a link from anywhere -->'."\n";
9897 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9898 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9899 $htmltoenteralink .= '<input type="hidden" name="action" value="addlinkbyref">';
9900 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9901 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9902 $htmltoenteralink .= '<table class="noborder">';
9903 $htmltoenteralink .= '<tr class="liste_titre">';
9904 //print '<td>' . $langs->trans("Ref") . '</td>';
9905 $htmltoenteralink .= '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9906 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9907 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9908 $htmltoenteralink .= '</tr>';
9909 $htmltoenteralink .= '</table>';
9910 $htmltoenteralink .= '</form>';
9911 }
9912
9913 $sql = $possiblelink['sql'];
9914
9915 $resqllist = $this->db->query($sql);
9916 if ($resqllist) {
9917 $num = $this->db->num_rows($resqllist);
9918 $i = 0;
9919
9920 if ($num > 0) {
9921 // Section for free predefined list
9922 if (getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9923 $htmltoenteralink .= '<br>';
9924 }
9925 $htmltoenteralink .= '<!-- form to add a link from object to same thirdparty -->'."\n";
9926 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9927 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9928 $htmltoenteralink .= '<input type="hidden" name="action" value="addlink">';
9929 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9930 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9931 $htmltoenteralink .= '<table class="noborder">';
9932 $htmltoenteralink .= '<tr class="liste_titre">';
9933 $htmltoenteralink .= '<td class="nowrap"></td>';
9934 $htmltoenteralink .= '<td>' . $langs->trans("Ref") . '</td>';
9935 $htmltoenteralink .= '<td>' . $langs->trans("RefCustomer") . '</td>';
9936 $htmltoenteralink .= '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9937 $htmltoenteralink .= '<td>' . $langs->trans("Company") . '</td>';
9938 $htmltoenteralink .= '</tr>';
9939 while ($i < $num) {
9940 $objp = $this->db->fetch_object($resqllist);
9941 $alreadylinked = false;
9942 if (!empty($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key])) {
9943 if (in_array($objp->rowid, array_values($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key]))) {
9944 $alreadylinked = true;
9945 }
9946 }
9947 $htmltoenteralink .= '<tr class="oddeven">';
9948 $htmltoenteralink .= '<td>';
9949 if ($alreadylinked) {
9950 $htmltoenteralink .= img_picto('', 'link');
9951 } else {
9952 $htmltoenteralink .= '<input type="checkbox" name="idtolinkto[' . $key . '_' . $objp->rowid . ']" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9953 }
9954 $htmltoenteralink .= '</td>';
9955 $htmltoenteralink .= '<td><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9956 $htmltoenteralink .= '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9957 $htmltoenteralink .= '<td class="right">';
9958 if ($possiblelink['label'] == 'LinkToContract') {
9959 $htmltoenteralink .= $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9960 }
9961 $htmltoenteralink .= '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9962 $htmltoenteralink .= '</td>';
9963 $htmltoenteralink .= '<td>' . $objp->name . '</td>';
9964 $htmltoenteralink .= '</tr>';
9965 $i++;
9966 }
9967 $htmltoenteralink .= '</table>';
9968 $htmltoenteralink .= '<div class="center">';
9969 if ($num) {
9970 $htmltoenteralink .= '<input type="submit" class="button valignmiddle marginleftonly marginrightonly smallpaddingimp" value="' . $langs->trans('ToLink') . '">';
9971 }
9972 if (empty($conf->use_javascript_ajax)) {
9973 $htmltoenteralink .= '<input type="submit" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9974 } else {
9975 $htmltoenteralink .= '<input type="submit" onclick="jQuery(\'#' . $key . 'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9976 }
9977 $htmltoenteralink .= '</form>';
9978 }
9979
9980 $this->db->free($resqllist);
9981 } else {
9982 dol_print_error($this->db);
9983 }
9984 $htmltoenteralink .= '</div>';
9985
9986
9987 // Complete the list for the combo box
9988 if ($num > 0 || !getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9989 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
9990 // } else $linktoelem.=$langs->trans($possiblelink['label']);
9991 } else {
9992 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
9993 }
9994 }
9995 }
9996
9997 if ($linktoelemlist) {
9998 $linktoelem = '
9999 <dl class="dropdown" id="linktoobjectname">
10000 ';
10001 if (!empty($conf->use_javascript_ajax)) {
10002 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
10003 }
10004 $linktoelem .= '<dd>
10005 <div class="multiselectlinkto">
10006 <ul class="ulselectedfields">' . $linktoelemlist . '
10007 </ul>
10008 </div>
10009 </dd>
10010 </dl>';
10011 } else {
10012 $linktoelem = '';
10013 }
10014
10015 if (!empty($conf->use_javascript_ajax)) {
10016 print '<!-- Add js to show linkto box -->
10017 <script nonce="' . getNonce() . '">
10018 jQuery(document).ready(function() {
10019 jQuery(".linkto").click(function() {
10020 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
10021 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
10022 });
10023 });
10024 </script>
10025 ';
10026 }
10027
10028 if ($nooutput) {
10029 return array('linktoelem' => $linktoelem, 'htmltoenteralink' => $htmltoenteralink);
10030 } else {
10031 print $htmltoenteralink;
10032 }
10033
10034 return $linktoelem;
10035 }
10036
10051 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'width75', $labelyes = 'Yes', $labelno = 'No')
10052 {
10053 global $langs;
10054
10055 $yes = "yes";
10056 $no = "no";
10057 if ($option) {
10058 $yes = "1";
10059 $no = "0";
10060 }
10061
10062 $disabled = ($disabled ? ' disabled' : '');
10063
10064 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
10065 if ($useempty) {
10066 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10067 }
10068 if (("$value" == 'yes') || ($value == 1)) {
10069 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
10070 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
10071 } else {
10072 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
10073 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
10074 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
10075 }
10076 $resultyesno .= '</select>' . "\n";
10077
10078 if ($addjscombo) {
10079 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
10080 }
10081
10082 return $resultyesno;
10083 }
10084
10085 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10086
10096 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
10097 {
10098 // phpcs:enable
10099 $sql = "SELECT rowid, label";
10100 $sql .= " FROM " . $this->db->prefix() . "export_model";
10101 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
10102 $sql .= " ORDER BY rowid";
10103 $result = $this->db->query($sql);
10104 if ($result) {
10105 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
10106 if ($useempty) {
10107 print '<option value="-1">&nbsp;</option>';
10108 }
10109
10110 $num = $this->db->num_rows($result);
10111 $i = 0;
10112 while ($i < $num) {
10113 $obj = $this->db->fetch_object($result);
10114 if ($selected == $obj->rowid) {
10115 print '<option value="' . $obj->rowid . '" selected>';
10116 } else {
10117 print '<option value="' . $obj->rowid . '">';
10118 }
10119 print $obj->label;
10120 print '</option>';
10121 $i++;
10122 }
10123 print "</select>";
10124 } else {
10125 dol_print_error($this->db);
10126 }
10127 }
10128
10147 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
10148 {
10149 global $conf, $langs, $hookmanager, $extralanguages;
10150
10151 $ret = '';
10152 if (empty($fieldid)) {
10153 $fieldid = 'rowid';
10154 }
10155 if (empty($fieldref)) {
10156 $fieldref = 'ref';
10157 }
10158
10159 // Preparing gender's display if there is one
10160 $addgendertxt = '';
10161 if (property_exists($object, 'gender') && !empty($object->gender)) {
10162 $addgendertxt = ' ';
10163 switch ($object->gender) {
10164 case 'man':
10165 $addgendertxt .= '<i class="fas fa-mars valignmiddle"></i>';
10166 break;
10167 case 'woman':
10168 $addgendertxt .= '<i class="fas fa-venus valignmiddle"></i>';
10169 break;
10170 case 'other':
10171 $addgendertxt .= '<i class="fas fa-transgender valignmiddle"></i>';
10172 break;
10173 }
10174 }
10175
10176 // Add where from hooks
10177 if (is_object($hookmanager)) {
10178 $parameters = array('showrefnav' => true);
10179 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
10180 $object->next_prev_filter .= $hookmanager->resPrint;
10181 }
10182
10183 $previous_ref = $next_ref = '';
10184 if ($shownav) {
10185 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
10186 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
10187
10188 $navurl = $_SERVER["PHP_SELF"];
10189 // Special case for project/task page
10190 if ($paramid == 'project_ref') {
10191 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
10192 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
10193 $paramid = 'ref';
10194 }
10195 }
10196
10197 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
10198 // accesskey is for Mac: CTRL + key for all browsers
10199 $stringforfirstkey = $langs->trans("KeyboardShortcut");
10200 if ($conf->browser->name == 'chrome') {
10201 $stringforfirstkey .= ' ALT +';
10202 } elseif ($conf->browser->name == 'firefox') {
10203 $stringforfirstkey .= ' ALT + SHIFT +';
10204 } else {
10205 $stringforfirstkey .= ' CTL +';
10206 }
10207
10208 $previous_ref = $object->ref_previous ? '<a accesskey="p" alt="'.dol_escape_htmltag($langs->trans("Previous")).'" title="' . $stringforfirstkey . ' p" class="classfortooltip" href="' . $navurl . '?' . $paramid . '=' . urlencode($object->ref_previous) . $moreparam . '"><i class="fa fa-chevron-left"></i></a>' : '<span class="inactive"><i class="fa fa-chevron-left opacitymedium"></i></span>';
10209 $next_ref = $object->ref_next ? '<a accesskey="n" alt="'.dol_escape_htmltag($langs->trans("Next")).'" title="' . $stringforfirstkey . ' n" class="classfortooltip" href="' . $navurl . '?' . $paramid . '=' . urlencode($object->ref_next) . $moreparam . '"><i class="fa fa-chevron-right"></i></a>' : '<span class="inactive"><i class="fa fa-chevron-right opacitymedium"></i></span>';
10210 }
10211
10212 //print "xx".$previous_ref."x".$next_ref;
10213 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
10214
10215 // Right part of banner
10216 if ($morehtmlright) {
10217 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
10218 }
10219
10220 if ($previous_ref || $next_ref || $morehtml) {
10221 $ret .= '<div class="pagination paginationref"><ul class="right">';
10222 }
10223 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
10224 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
10225 }
10226 if ($shownav && ($previous_ref || $next_ref)) {
10227 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
10228 $ret .= '<li class="pagination">' . $next_ref . '</li>';
10229 }
10230 if ($previous_ref || $next_ref || $morehtml) {
10231 $ret .= '</ul></div>';
10232 }
10233
10234 // Status
10235 $parameters = array('morehtmlstatus' => $morehtmlstatus);
10236 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
10237 if (empty($reshook)) {
10238 $morehtmlstatus .= $hookmanager->resPrint;
10239 } else {
10240 $morehtmlstatus = $hookmanager->resPrint;
10241 }
10242 if ($morehtmlstatus) {
10243 $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
10244 }
10245
10246 $parameters = array();
10247 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
10248 if (empty($reshook)) {
10249 $morehtmlref .= $hookmanager->resPrint;
10250 } elseif ($reshook > 0) {
10251 $morehtmlref = $hookmanager->resPrint;
10252 }
10253
10254 // Left part of banner
10255 if ($morehtmlleft) {
10256 if ($conf->browser->layout == 'phone') {
10257 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
10258 } else {
10259 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
10260 }
10261 }
10262
10263 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
10264 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
10265
10266 // For thirdparty, contact, user, member, the ref is the id, so we show something else
10267 if ($object->element == 'societe') {
10268 $ret .= dol_htmlentities($object->name);
10269
10270 // List of extra languages
10271 $arrayoflangcode = array();
10272 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
10273 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
10274 }
10275
10276 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
10277 if (!is_object($extralanguages)) {
10278 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
10279 $extralanguages = new ExtraLanguages($this->db);
10280 }
10281 $extralanguages->fetch_name_extralanguages('societe');
10282
10283 if (!empty($extralanguages->attributes['societe']['name'])) {
10284 $object->fetchValuesForExtraLanguages();
10285
10286 $htmltext = '';
10287 // If there is extra languages
10288 foreach ($arrayoflangcode as $extralangcode) {
10289 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
10290 if ($object->array_languages['name'][$extralangcode]) {
10291 $htmltext .= $object->array_languages['name'][$extralangcode];
10292 } else {
10293 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
10294 }
10295 }
10296 $ret .= '<!-- Show translations of name -->' . "\n";
10297 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
10298 }
10299 }
10300 } elseif ($object->element == 'member') {
10301 '@phan-var-force Adherent $object';
10302 $ret .= $object->ref . '<br>';
10303 $fullname = $object->getFullName($langs);
10304 if ($object->morphy == 'mor' && $object->societe) {
10305 $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
10306 } else {
10307 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
10308 }
10309 } elseif (in_array($object->element, array('contact', 'user'))) {
10310 $ret .= '<span class="valignmiddle">'.dol_htmlentities($object->getFullName($langs)).'</span>'.$addgendertxt;
10311 } elseif ($object->element == 'usergroup') {
10312 $ret .= dol_htmlentities($object->name);
10313 } elseif (in_array($object->element, array('action', 'agenda'))) {
10314 '@phan-var-force ActionComm $object';
10315 $ret .= $object->ref . '<br>' . $object->label;
10316 } elseif (in_array($object->element, array('adherent_type'))) {
10317 $ret .= $object->label;
10318 } elseif ($object->element == 'ecm_directories') {
10319 $ret .= '';
10320 } elseif ($fieldref != 'none') {
10321 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
10322 }
10323 if ($morehtmlref) {
10324 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
10325 if (substr($morehtmlref, 0, 4) != '<div') {
10326 $ret .= ' ';
10327 }
10328
10329 $ret .= '<!-- morehtmlref -->'.$morehtmlref;
10330 }
10331
10332 $ret .= '</div>';
10333
10334 $ret .= '</div><!-- End banner content -->';
10335
10336 return $ret;
10337 }
10338
10339
10348 public function showbarcode(&$object, $width = 100, $morecss = '')
10349 {
10350 global $conf;
10351
10352 //Check if barcode is filled in the card
10353 if (empty($object->barcode)) {
10354 return '';
10355 }
10356
10357 // Complete object if not complete
10358 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10359 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10360 $result = $object->fetchBarCode();
10361 //Check if fetchBarCode() failed
10362 if ($result < 1) {
10363 return '<!-- ErrorFetchBarcode -->';
10364 }
10365 }
10366
10367 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10368 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10369 $out = '<!-- url barcode = ' . $url . ' -->';
10370 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10371
10372 return $out;
10373 }
10374
10392 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10393 {
10394 global $conf, $langs;
10395
10396 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10397 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10398
10399 $dir = '';
10400 $file = '';
10401 $originalfile = '';
10402 $altfile = '';
10403 $email = '';
10404 $capture = '';
10405 if ($modulepart == 'societe') {
10406 $dir = $conf->societe->multidir_output[$entity];
10407 if (!empty($object->logo)) {
10408 if (dolIsAllowedForPreview($object->logo)) {
10409 if ((string) $imagesize == 'mini') {
10410 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10411 } elseif ((string) $imagesize == 'small') {
10412 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10413 } else {
10414 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10415 }
10416 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10417 }
10418 }
10419 $email = $object->email;
10420 } elseif ($modulepart == 'contact') {
10421 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10422 if (!empty($object->photo)) {
10423 if (dolIsAllowedForPreview($object->photo)) {
10424 if ((string) $imagesize == 'mini') {
10425 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10426 } elseif ((string) $imagesize == 'small') {
10427 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10428 } else {
10429 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10430 }
10431 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10432 }
10433 }
10434 $email = $object->email;
10435 $capture = 'user';
10436 } elseif ($modulepart == 'userphoto') {
10437 $dir = $conf->user->dir_output;
10438 if (!empty($object->photo)) {
10439 if (dolIsAllowedForPreview($object->photo)) {
10440 if ((string) $imagesize == 'mini') {
10441 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10442 } elseif ((string) $imagesize == 'small') {
10443 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10444 } else {
10445 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10446 }
10447 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10448 }
10449 }
10450 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10451 $altfile = $object->id . ".jpg"; // For backward compatibility
10452 }
10453 $email = $object->email;
10454 $capture = 'user';
10455 } elseif ($modulepart == 'memberphoto') {
10456 $dir = $conf->adherent->dir_output;
10457 if (!empty($object->photo)) {
10458 if (dolIsAllowedForPreview($object->photo)) {
10459 if ((string) $imagesize == 'mini') {
10460 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10461 } elseif ((string) $imagesize == 'small') {
10462 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10463 } else {
10464 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10465 }
10466 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10467 }
10468 }
10469 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10470 $altfile = $object->id . ".jpg"; // For backward compatibility
10471 }
10472 $email = $object->email;
10473 $capture = 'user';
10474 } else {
10475 // Generic case to show photos
10476 // TODO Implement this method in previous objects so we can always use this generic method.
10477 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10478 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10479
10480 $dir = $tmpdata['dir'];
10481 $file = $tmpdata['file'];
10482 $originalfile = $tmpdata['originalfile'];
10483 $altfile = $tmpdata['altfile'];
10484 $email = $tmpdata['email'];
10485 $capture = $tmpdata['capture'];
10486 }
10487 }
10488
10489 if ($forcecapture) {
10490 $capture = $forcecapture;
10491 }
10492
10493 $ret = '';
10494
10495 if ($dir) {
10496 if ($file && file_exists($dir . "/" . $file)) {
10497 if ($addlinktofullsize) {
10498 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10499 if ($urladvanced) {
10500 $ret .= '<a href="' . $urladvanced . '">';
10501 } else {
10502 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10503 }
10504 }
10505 $ret .= '<img alt="" class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . ' photologo' . (preg_replace('/[^a-z]/i', '_', $file)) . '" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($file) . '&cache=' . $cache . '">';
10506 if ($addlinktofullsize) {
10507 $ret .= '</a>';
10508 }
10509 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
10510 if ($addlinktofullsize) {
10511 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10512 if ($urladvanced) {
10513 $ret .= '<a href="' . $urladvanced . '">';
10514 } else {
10515 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10516 }
10517 }
10518 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="Photo alt" id="photologo' . (preg_replace('/[^a-z]/i', '_', $file)) . '" class="' . $cssclass . '" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($altfile) . '&cache=' . $cache . '">';
10519 if ($addlinktofullsize) {
10520 $ret .= '</a>';
10521 }
10522 } else {
10523 $nophoto = '/public/theme/common/nophoto.png';
10524 $defaultimg = 'identicon'; // For gravatar
10525 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
10526 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
10527 $nophoto = 'company';
10528 } else {
10529 $nophoto = '/public/theme/common/user_anonymous.png';
10530 if (!empty($object->gender) && $object->gender == 'man') {
10531 $nophoto = '/public/theme/common/user_man.png';
10532 }
10533 if (!empty($object->gender) && $object->gender == 'woman') {
10534 $nophoto = '/public/theme/common/user_woman.png';
10535 }
10536 }
10537 }
10538
10539 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
10540 // see https://gravatar.com/site/implement/images/php/
10541 $ret .= '<!-- Put link to gravatar -->';
10542 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" title="' . $email . ' Gravatar avatar" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="https://www.gravatar.com/avatar/' . dol_hash(strtolower(trim($email)), 'sha256', 1) . '?s=' . $width . '&d=' . $defaultimg . '">'; // gravatar need md5 hash
10543 } else {
10544 if ($nophoto == 'company') {
10545 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
10546 //$ret .= '<div class="difforspanimgright"></div>';
10547 } else {
10548 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
10549 }
10550 }
10551 }
10552
10553 if ($caneditfield) {
10554 if ($object->photo) {
10555 $ret .= "<br>\n";
10556 }
10557 $ret .= '<table class="nobordernopadding centpercent">';
10558 if ($object->photo) {
10559 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
10560 }
10561 $ret .= '<tr><td class="tdoverflow">';
10562 $maxfilesizearray = getMaxFileSizeArray();
10563 $maxmin = $maxfilesizearray['maxmin'];
10564 if ($maxmin > 0) {
10565 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
10566 }
10567 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
10568 $ret .= '</td></tr>';
10569 $ret .= '</table>';
10570 }
10571 }
10572
10573 return $ret;
10574 }
10575
10576 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10577
10594 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
10595 {
10596 // phpcs:enable
10597 global $conf, $user, $langs;
10598
10599 // Allow excluding groups
10600 $excludeGroups = null;
10601 if (is_array($exclude)) {
10602 $excludeGroups = implode(",", $exclude);
10603 }
10604 // Allow including groups
10605 $includeGroups = null;
10606 if (is_array($include)) {
10607 $includeGroups = implode(",", $include);
10608 }
10609
10610 if (!is_array($selected)) {
10611 $selected = array($selected);
10612 }
10613
10614 $out = '';
10615
10616 // Build sql to search groups
10617 $sql = "SELECT ug.rowid, ug.nom as name";
10618 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10619 $sql .= ", e.label";
10620 }
10621 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
10622 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10623 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
10624 if ($force_entity) {
10625 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
10626 } else {
10627 $sql .= " WHERE ug.entity IS NOT NULL";
10628 }
10629 } else {
10630 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
10631 }
10632 if (is_array($exclude) && $excludeGroups) {
10633 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
10634 }
10635 if (is_array($include) && $includeGroups) {
10636 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
10637 }
10638 $sql .= " ORDER BY ug.nom ASC";
10639
10640 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
10641 $resql = $this->db->query($sql);
10642 if ($resql) {
10643 // Enhance with select2
10644 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10645
10646 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
10647
10648 $num = $this->db->num_rows($resql);
10649 $i = 0;
10650 if ($num) {
10651 if ($show_empty && !$multiple) {
10652 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10653 }
10654
10655 while ($i < $num) {
10656 $obj = $this->db->fetch_object($resql);
10657 $disableline = 0;
10658 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
10659 $disableline = 1;
10660 }
10661
10662 $label = $obj->name;
10663 $labelhtml = $obj->name;
10664 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
10665 $label .= " (" . $obj->label . ")";
10666 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
10667 }
10668
10669 $out .= '<option value="' . $obj->rowid . '"';
10670 if ($disableline) {
10671 $out .= ' disabled';
10672 }
10673 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
10674 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
10675 $out .= ' selected';
10676 }
10677 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
10678 $out .= '>';
10679 $out .= $label;
10680 $out .= '</option>';
10681 $i++;
10682 }
10683 } else {
10684 if ($show_empty) {
10685 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
10686 }
10687 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
10688 }
10689 $out .= '</select>';
10690
10691 $out .= ajax_combobox($htmlname);
10692 } else {
10693 dol_print_error($this->db);
10694 }
10695
10696 return $out;
10697 }
10698
10699
10706 public function showFilterButtons($pos = '')
10707 {
10708 $out = '<div class="nowraponall">';
10709 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
10710 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
10711 $out .= '</div>';
10712
10713 return $out;
10714 }
10715
10724 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10725 {
10726 global $conf;
10727
10728 $out = '';
10729
10730 if (!empty($conf->use_javascript_ajax)) {
10731 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
10732 }
10733 $out .= '<script nonce="' . getNonce() . '">
10734 $(document).ready(function() {
10735 $("#' . $cssclass . 's").click(function() {
10736 if($(this).is(\':checked\')){
10737 console.log("We check all ' . $cssclass . ' and trigger the change method");
10738 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
10739 }
10740 else
10741 {
10742 console.log("We uncheck all");
10743 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
10744 }' . "\n";
10745 if ($calljsfunction) {
10746 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
10747 }
10748 $out .= ' });
10749 $(".' . $cssclass . '").change(function() {
10750 $(this).closest("tr").toggleClass("highlight", this.checked);
10751 });
10752 });
10753 </script>';
10754
10755 return $out;
10756 }
10757
10767 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10768 {
10769 $out = $this->showFilterButtons();
10770 if ($addcheckuncheckall) {
10771 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10772 }
10773 return $out;
10774 }
10775
10789 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10790 {
10791 global $langs, $user;
10792
10793 $out = '';
10794 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10795 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10796 if (!empty($excludeid)) {
10797 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10798 }
10799 $sql .= " ORDER BY label";
10800
10801 $resql = $this->db->query($sql);
10802 if ($resql) {
10803 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10804 if ($useempty) {
10805 $out .= '<option value="0">&nbsp;</option>';
10806 }
10807
10808 while ($obj = $this->db->fetch_object($resql)) {
10809 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10810 }
10811 $out .= '</select>';
10812 $out .= ajax_combobox('select_' . $htmlname);
10813
10814 if (!empty($htmlname) && $user->admin && $info_admin) {
10815 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10816 }
10817
10818 if (!empty($target)) {
10819 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10820 $resql = $this->db->query($sql);
10821 if ($resql) {
10822 if ($this->db->num_rows($resql) > 0) {
10823 $obj = $this->db->fetch_object($resql);
10824 $out .= '<script nonce="' . getNonce() . '">
10825 $(function() {
10826 $("select[name=' . $target . ']").on("change", function() {
10827 var current_val = $(this).val();
10828 if (current_val == ' . $obj->id . ') {';
10829 if (!empty($default_selected) || !empty($selected)) {
10830 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10831 }
10832
10833 $out .= '
10834 $("select[name=' . $htmlname . ']").change();
10835 }
10836 });
10837
10838 $("select[name=' . $htmlname . ']").change(function() {
10839
10840 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10841 // get price of kilometer to fill the unit price
10842 $.ajax({
10843 method: "POST",
10844 dataType: "json",
10845 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10846 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
10847 }).done(function( data, textStatus, jqXHR ) {
10848 console.log(data);
10849 if (typeof data.up != "undefined") {
10850 $("input[name=value_unit]").val(data.up);
10851 $("select[name=' . $htmlname . ']").attr("title", data.title);
10852 } else {
10853 $("input[name=value_unit]").val("");
10854 $("select[name=' . $htmlname . ']").attr("title", "");
10855 }
10856 });
10857 }
10858 });
10859 });
10860 </script>';
10861 }
10862 }
10863 }
10864 } else {
10865 dol_print_error($this->db);
10866 }
10867
10868 return $out;
10869 }
10870
10879 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10880 {
10881 global $conf, $langs;
10882
10883 $out = '';
10884 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10885 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10886
10887 $resql = $this->db->query($sql);
10888 if ($resql) {
10889 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10890 if ($useempty) {
10891 $out .= '<option value="0"></option>';
10892 }
10893
10894 while ($obj = $this->db->fetch_object($resql)) {
10895 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10896 }
10897 $out .= '</select>';
10898 } else {
10899 dol_print_error($this->db);
10900 }
10901
10902 return $out;
10903 }
10904
10915 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10916 {
10917 global $langs;
10918
10919 $out = '';
10920 $sql = "SELECT id, code, label";
10921 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
10922 $sql .= " WHERE active = 1";
10923
10924 $resql = $this->db->query($sql);
10925 if ($resql) {
10926 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10927 if ($useempty) {
10928 $out .= '<option value="0"></option>';
10929 }
10930 if ($allchoice) {
10931 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10932 }
10933
10934 $field = 'code';
10935 if ($useid) {
10936 $field = 'id';
10937 }
10938
10939 while ($obj = $this->db->fetch_object($resql)) {
10940 $key = $langs->trans($obj->code);
10941 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10942 }
10943 $out .= '</select>';
10944
10945 $out .= ajax_combobox('select_'.$htmlname);
10946 } else {
10947 dol_print_error($this->db);
10948 }
10949
10950 return $out;
10951 }
10952
10971 public function selectInvoice($socid = -1, $selected = '', $htmlname = 'invoiceid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500', $projectsListId = '', $showproject = 'all', $usertofilter = null)
10972 {
10973 global $user, $conf, $langs;
10974
10975 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10976
10977 if (is_null($usertofilter)) {
10978 $usertofilter = $user;
10979 }
10980
10981 $out = '';
10982
10983 $hideunselectables = false;
10984 if (getDolGlobalString('PROJECT_HIDE_UNSELECTABLES')) {
10985 $hideunselectables = true;
10986 }
10987
10988 if (empty($projectsListId)) {
10989 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
10990 $projectstatic = new Project($this->db);
10991 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10992 }
10993 }
10994
10995 // Search all projects
10996 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10997 p.title, p.fk_soc, p.fk_statut, p.public,";
10998 $sql .= ' s.nom as name';
10999 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
11000 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
11001 $sql .= ' ' . $this->db->prefix() . 'facture as f';
11002 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
11003 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
11004 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
11005 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
11006 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
11007 $sql .= " ORDER BY p.ref, f.ref ASC";
11008
11009 $resql = $this->db->query($sql);
11010 if ($resql) {
11011 // Use select2 selector
11012 if (!empty($conf->use_javascript_ajax)) {
11013 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11014 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11015 $out .= $comboenhancement;
11016 $morecss = 'minwidth200imp maxwidth500';
11017 }
11018
11019 if (empty($option_only)) {
11020 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11021 }
11022 if (!empty($show_empty)) {
11023 $out .= '<option value="0" class="optiongrey">';
11024 if (!is_numeric($show_empty)) {
11025 $out .= $show_empty;
11026 } else {
11027 $out .= '&nbsp;';
11028 }
11029 $out .= '</option>';
11030 }
11031 $num = $this->db->num_rows($resql);
11032 $i = 0;
11033 if ($num) {
11034 while ($i < $num) {
11035 $obj = $this->db->fetch_object($resql);
11036 // If we ask to filter on a company and user has no permission to see all companies and project is linked to another company, we hide project.
11037 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
11038 // Do nothing
11039 } else {
11040 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11041 $i++;
11042 continue;
11043 }
11044
11045 $labeltoshow = '';
11046
11047 if ($showproject == 'all') {
11048 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
11049 if ($obj->name) {
11050 $labeltoshow .= ' - ' . $obj->name; // Soc name
11051 }
11052
11053 $disabled = 0;
11054 if ($obj->fk_statut == Project::STATUS_DRAFT) {
11055 $disabled = 1;
11056 $labeltoshow .= ' - ' . $langs->trans("Draft");
11057 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
11058 if ($discard_closed == 2) {
11059 $disabled = 1;
11060 }
11061 $labeltoshow .= ' - ' . $langs->trans("Closed");
11062 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
11063 $disabled = 1;
11064 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
11065 }
11066 }
11067
11068 if (!empty($selected) && $selected == $obj->rowid) {
11069 $out .= '<option value="' . $obj->rowid . '" selected';
11070 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11071 $out .= '>' . $labeltoshow . '</option>';
11072 } else {
11073 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11074 $resultat = '';
11075 } else {
11076 $resultat = '<option value="' . $obj->rowid . '"';
11077 if ($disabled) {
11078 $resultat .= ' disabled';
11079 }
11080 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11081 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11082 $resultat .= '>';
11083 $resultat .= $labeltoshow;
11084 $resultat .= '</option>';
11085 }
11086 $out .= $resultat;
11087 }
11088 }
11089 $i++;
11090 }
11091 }
11092 if (empty($option_only)) {
11093 $out .= '</select>';
11094 }
11095
11096 $this->db->free($resql);
11097
11098 return $out;
11099 } else {
11100 dol_print_error($this->db);
11101 return '';
11102 }
11103 }
11104
11118 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11119 {
11120 global $conf, $langs;
11121
11122 $out = '';
11123
11124 dol_syslog('FactureRec::fetch', LOG_DEBUG);
11125
11126 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
11127 //$sql.= ', el.fk_source';
11128 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
11129 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
11130 $sql .= " ORDER BY f.titre ASC";
11131
11132 $resql = $this->db->query($sql);
11133 if ($resql) {
11134 // Use select2 selector
11135 if (!empty($conf->use_javascript_ajax)) {
11136 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11137 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11138 $out .= $comboenhancement;
11139 $morecss = 'minwidth200imp maxwidth500';
11140 }
11141
11142 if (empty($option_only)) {
11143 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11144 }
11145 if (!empty($show_empty)) {
11146 $out .= '<option value="0" class="optiongrey">';
11147 if (!is_numeric($show_empty)) {
11148 $out .= $show_empty;
11149 } else {
11150 $out .= '&nbsp;';
11151 }
11152 $out .= '</option>';
11153 }
11154 $num = $this->db->num_rows($resql);
11155 if ($num) {
11156 while ($obj = $this->db->fetch_object($resql)) {
11157 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
11158
11159 $disabled = 0;
11160 if (!empty($obj->suspended)) {
11161 $disabled = 1;
11162 $labeltoshow .= ' - ' . $langs->trans("Closed");
11163 }
11164
11165
11166 if (!empty($selected) && $selected == $obj->rowid) {
11167 $out .= '<option value="' . $obj->rowid . '" selected';
11168 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11169 $out .= '>' . $labeltoshow . '</option>';
11170 } else {
11171 if ($disabled && ($selected != $obj->rowid)) {
11172 $resultat = '';
11173 } else {
11174 $resultat = '<option value="' . $obj->rowid . '"';
11175 if ($disabled) {
11176 $resultat .= ' disabled';
11177 }
11178 $resultat .= '>';
11179 $resultat .= $labeltoshow;
11180 $resultat .= '</option>';
11181 }
11182 $out .= $resultat;
11183 }
11184 }
11185 }
11186 if (empty($option_only)) {
11187 $out .= '</select>';
11188 }
11189
11190 print $out;
11191
11192 $this->db->free($resql);
11193 return $num;
11194 } else {
11195 $this->errors[] = $this->db->lasterror;
11196 return -1;
11197 }
11198 }
11199
11210 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '', $arrayoffiltercriterias = array())
11211 {
11212 // TODO: Use $arrayoffiltercriterias param instead of $arrayofcriterias to include linked object fields in search
11213 global $langs, $form;
11214
11215 require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
11216 $formother = new FormOther($this->db);
11217
11218 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
11219 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
11220 }
11221
11222 $ret = '';
11223
11224 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
11225 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
11226 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
11227 $ret .= '</a>';
11228
11229 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
11230
11231 // Show select fields as tags.
11232 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
11233
11234 if ($search_component_params_hidden) {
11235 // Split the criteria on each AND
11236 //var_dump($search_component_params_hidden);
11237
11238 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
11239
11240 // $arrayofandtags is now array( '...' , '...', ...)
11241 // Show each AND part
11242 foreach ($arrayofandtags as $tmpkey => $tmpval) {
11243 $errormessage = '';
11244 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
11245 if ($errormessage) {
11246 $this->error = 'ERROR in parsing search string: '.$errormessage;
11247 }
11248 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
11249 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
11250 $searchtags = removeGlobalParenthesis($searchtags);
11251
11252 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
11253 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
11254 $ret .= dol_escape_htmltag($searchtags);
11255 $ret .= '</span>';
11256 }
11257 }
11258
11259 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
11260
11261 //$ret .= search_component_params
11262 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
11263 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
11264
11265 $show_search_component_params_hidden = 1;
11266 if ($show_search_component_params_hidden) {
11267 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
11268 }
11269 $ret .= "<!-- We store the full Universal Search String into this field. For example: (t.ref:like:'SO-%') AND ((t.ref:like:'CO-%') OR (t.ref:like:'AA%')) -->";
11270 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
11271 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
11272
11273 // TODO : Use $arrayoffiltercriterias instead of $arrayofcriterias
11274 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
11275 foreach ($arrayofcriterias as $criteria) {
11276 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
11277 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
11278 continue;
11279 }
11280 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
11281 continue;
11282 }
11283 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
11284 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
11285 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
11286 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
11287 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
11288 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
11289 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
11290 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
11291 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
11292 } else {
11293 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
11294 }
11295 }
11296 }
11297
11298 $ret .= '</div>';
11299
11300 $ret .= "<!-- Field to enter a generic filter string: t.ref:like:'SO-%', t.date_creation:<:'20160101', t.date_creation:<:'2016-01-01 12:30:00', t.nature:is:NULL, t.field2:isnot:NULL -->\n";
11301 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
11302
11303 $ret .= '</div>';
11304 $ret .= '</div>';
11305
11306 $ret .= '<script>
11307 jQuery(".tagsearchdelete").click(function(e) {
11308 var filterid = $(this).parents().attr("data-ufilterid");
11309 console.log("We click to delete the criteria nb "+filterid);
11310
11311 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
11312 var newparamstring = \'\';
11313 $(\'.tagsearch\').each(function(index, element) {
11314 tmpfilterid = $(this).attr("data-ufilterid");
11315 if (tmpfilterid != filterid) {
11316 // We keep this criteria
11317 if (newparamstring == \'\') {
11318 newparamstring = $(this).attr("data-ufilter");
11319 } else {
11320 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
11321 }
11322 }
11323 });
11324 console.log("newparamstring = "+newparamstring);
11325
11326 jQuery("#search_component_params_hidden").val(newparamstring);
11327
11328 // We repost the form
11329 $(this).closest(\'form\').submit();
11330 });
11331
11332 jQuery("#search_component_params_input").keydown(function(e) {
11333 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
11334 console.log(e.which);
11335 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
11336 /* We click on back when the input field is already empty */
11337 event.preventDefault();
11338 jQuery("#divsearch_component_params .tagsearch").last().remove();
11339 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
11340 var s = "";
11341 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
11342 if (s != "") {
11343 s = s + " AND ";
11344 }
11345 s = s + $(this).attr("data-ufilter");
11346 });
11347 console.log("New value for search_component_params_hidden = "+s);
11348 jQuery("#search_component_params_hidden").val(s);
11349 }
11350 });
11351
11352 </script>
11353 ';
11354
11355 // Convert $arrayoffiltercriterias into a json object that can be used in jquery to build the search component dynamically
11356 $arrayoffiltercriterias_json = json_encode($arrayoffiltercriterias);
11357 $ret .= '<script>
11358 var arrayoffiltercriterias = ' . $arrayoffiltercriterias_json . ';
11359 </script>';
11360
11361
11362 $arrayoffilterfieldslabel = array();
11363 foreach ($arrayoffiltercriterias as $key => $val) {
11364 $arrayoffilterfieldslabel[$key]['label'] = $val['label'];
11365 $arrayoffilterfieldslabel[$key]['data-type'] = $val['type'];
11366 }
11367
11368 // Adding the div for search assistance
11369 $ret .= '<div class="search-component-assistance">';
11370 $ret .= '<div>';
11371
11372 $ret .= '<p class="assistance-title">' . img_picto('', 'filter') . ' ' . $langs->trans('FilterAssistance') . ' </p>';
11373
11374 $ret .= '<p class="assistance-errors error" style="display:none">' . $langs->trans('AllFieldsRequired') . ' </p>';
11375
11376 $ret .= '<div class="operand">';
11377 $ret .= $form->selectarray('search_filter_field', $arrayoffilterfieldslabel, '', $langs->trans("Fields"), 0, 0, '', 0, 0, 0, '', 'width250', 1);
11378 $ret .= '</div>';
11379
11380 $ret .= '<span class="separator"></span>';
11381
11382 // Operator selector (will be populated dynamically)
11383 $ret .= '<div class="operator">';
11384 $ret .= '<select class="operator-selector width150" id="operator-selector"">';
11385 $ret .= '</select>';
11386 $ret .= '<script>$(document).ready(function() {';
11387 $ret .= ' $(".operator-selector").select2({';
11388 $ret .= ' placeholder: \'' . dol_escape_js($langs->trans('Operator')) . '\'';
11389 $ret .= ' });';
11390 $ret .= '});</script>';
11391 $ret .= '</div>';
11392
11393 $ret .= '<span class="separator"></span>';
11394
11395 $ret .= '<div class="value">';
11396 // Input field for entering values
11397 $ret .= '<input type="text" class="flat width100 value-input" placeholder="' . dolPrintHTML($langs->trans('Value')) . '">';
11398
11399 // Date selector
11400 $dateOne = '';
11401 $ret .= '<span class="date-one" style="display:none">';
11402 $ret .= $form->selectDate(($dateOne ? $dateOne : -1), 'dateone', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '');
11403 $ret .= '</span>';
11404
11405 // Value selector (will be populated dynamically) based on search_filter_field value if a selected value has an array of values
11406 $ret .= '<select class="value-selector width150" id="value-selector" style="display:none">';
11407 $ret .= '</select>';
11408 $ret .= '<script>
11409 $(document).ready(function() {
11410 $("#value-selector").select2({
11411 placeholder: "' . dol_escape_js($langs->trans('Value')) . '"
11412 });
11413 $("#value-selector").hide();
11414 $("#value-selector").next(".select2-container").hide();
11415 });
11416 </script>';
11417
11418 $ret .= '</div>';
11419
11420 $ret .= '<div class="btn-div">';
11421 $ret .= '<button class="button buttongen button-save add-filter-btn" type="button">' . $langs->trans("addToFilter") . '</button>';
11422 $ret .= '</div>';
11423
11424 $ret .= '</div>';
11425 //$ret .= '</tbody></table>';
11426
11427 // End of the assistance div
11428 $ret .= '</div>';
11429
11430 // Script jQuery to show/hide the floating assistance
11431 $ret .= '<script>
11432 $(document).ready(function() {
11433 $("#search_component_params_input").on("click", function() {
11434 const inputPosition = $(this).offset();
11435 const inputHeight = $(this).outerHeight();
11436 $(".search-component-assistance").css({
11437 top: inputPosition.top + inputHeight + 5 + "px",
11438 left: $("#divsearch_component_params").position().left
11439 }).slideToggle(200);
11440 });
11441 $(document).on("click", function(e) {
11442 if (!$(e.target).closest("#search_component_params_input, .search-component-assistance, #ui-datepicker-div").length) {
11443 $(".search-component-assistance").hide();
11444 }
11445 });
11446 });
11447 </script>';
11448
11449 $ret .= '<script>
11450 $(document).ready(function() {
11451 $(".search_filter_field").on("change", function() {
11452 let maybenull = 0;
11453 const selectedField = $(this).find(":selected");
11454 let fieldType = selectedField.data("type");
11455 const selectedFieldValue = selectedField.val();
11456
11457 // If the selected field has an array of values then ask toshow the value selector instead of the value input
11458 if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
11459 fieldType = "select";
11460 }
11461
11462 // If the selected field may be null then ask to append the "IsDefined" and "IsNotDefined" operators
11463 if (arrayoffiltercriterias[selectedFieldValue]["maybenull"] !== undefined) {
11464 maybenull = 1;
11465 }
11466 const operators = getOperatorsForFieldType(fieldType, maybenull);
11467 const operatorSelector = $(".operator-selector");
11468
11469 // Clear existing options
11470 operatorSelector.empty();
11471
11472 // Populate operators
11473 Object.entries(operators).forEach(function([operator, label]) {
11474 operatorSelector.append("<option value=\'" + operator + "\'>" + label + "</option>");
11475 });
11476
11477 operatorSelector.trigger("change.select2");
11478
11479 // Clear and hide all input elements initially
11480 $(".value-input, .dateone, .datemonth, .dateyear").val("").hide();
11481 $("#datemonth, #dateyear").val(null).trigger("change.select2");
11482 $("#dateone").datepicker("setDate", null);
11483 $(".date-one, .date-month, .date-year").hide();
11484 $("#value-selector").val("").hide();
11485 $("#value-selector").next(".select2-container").hide();
11486 $("#value-selector").val(null).trigger("change.select2");
11487
11488 if (fieldType === "date" || fieldType === "datetime" || fieldType === "timestamp") {
11489 $(".date-one").show();
11490 } else if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
11491 var arrayofkeyval = arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"];
11492 var valueSelector = $("#value-selector");
11493 valueSelector.empty();
11494 Object.entries(arrayofkeyval).forEach(function([key, val]) {
11495 valueSelector.append("<option value=\'" + key + "\'>" + val + "</option>");
11496 });
11497 valueSelector.trigger("change.select2");
11498
11499 $("#value-selector").show();
11500 $("#value-selector").next(".select2-container").show();
11501 } else {
11502 $(".value-input").show();
11503 }
11504 });
11505
11506 $("#operator-selector").on("change", function() {
11507 const selectedOperator = $(this).find(":selected").val();
11508 if (selectedOperator === "IsDefined" || selectedOperator === "IsNotDefined") {
11509 // Disable all value input elements
11510 $(".value-input, .dateone, .datemonth, .dateyear").val("").prop("disabled", true);
11511 $("#datemonth, #dateyear").val(null).trigger("change.select2");
11512 $("#dateone").datepicker("setDate", null).datepicker("option", "disabled", true);
11513 $(".date-one, .date-month, .date-year").prop("disabled", true);
11514 $("#value-selector").val("").prop("disabled", true);
11515 $("#value-selector").val(null).trigger("change.select2");
11516 } else {
11517 // Enable all value input elements
11518 $(".value-input, .dateone, .datemonth, .dateyear").prop("disabled", false);
11519 $(".date-one, .date-month, .date-year").prop("disabled", false);
11520 $("#dateone").datepicker("option", "disabled", false);
11521 $("#value-selector").prop("disabled", false);
11522 }
11523 });
11524
11525 $(".add-filter-btn").on("click", function(event) {
11526 event.preventDefault();
11527
11528 const field = $(".search_filter_field").val();
11529 const operator = $(".operator-selector").val();
11530 let value = $(".value-input").val();
11531 const fieldType = $(".search_filter_field").find(":selected").data("type");
11532
11533 if (["date", "datetime", "timestamp"].includes(fieldType)) {
11534 const parsedDate = new Date($("#dateone").val());
11535 if (!isNaN(parsedDate)) {
11536 const year = parsedDate.getFullYear();
11537 const month = String(parsedDate.getMonth() + 1).padStart(2, "0");
11538 const day = String(parsedDate.getDate()).padStart(2, "0");
11539 value = `${year}-${month}-${day}`;
11540 }
11541 }
11542
11543 // If the selected field has an array of values then take the selected value
11544 if (arrayoffiltercriterias[field]["arrayofkeyval"] !== undefined) {
11545 value = $("#value-selector").val();
11546 }
11547
11548 // If the operator is "IsDefined" or "IsNotDefined" then set the value to 1 (it will not be used)
11549 if (operator === "IsDefined" || operator === "IsNotDefined") {
11550 value = "1";
11551 }
11552
11553 const filterString = generateFilterString(field, operator, value, fieldType);
11554
11555 // Submit the form
11556 if (filterString !== "" && field !== "" && operator !== "" && value !== "") {
11557 $("#search_component_params_input").val($("#search_component_params_input").val() + " " + filterString);
11558 $("#search_component_params_input").closest("form").submit();
11559 } else {
11560 $(".assistance-errors").show();
11561 }
11562 });
11563 });
11564 </script>';
11565
11566 return $ret;
11567 }
11568
11579 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0, $selected = '')
11580 {
11581 global $langs, $user;
11582
11583 $retstring = '';
11584
11585 $TModels = array();
11586
11587 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
11588 $formmail = new FormMail($this->db);
11589 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
11590
11591 if ($default) {
11592 $TModels[0] = $langs->trans('DefaultMailModel');
11593 }
11594 if ($result > 0) {
11595 foreach ($formmail->lines_model as $model) {
11596 $TModels[$model->id] = $model->label;
11597 }
11598 }
11599
11600 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
11601
11602 foreach ($TModels as $id_model => $label_model) {
11603 $retstring .= '<option value="' . $id_model . '"';
11604 if (!empty($selected) && $selected == $id_model) {
11605 $retstring .= "selected";
11606 }
11607 $retstring .= ">" . $label_model . "</option>";
11608 }
11609
11610 $retstring .= "</select>";
11611
11612 if ($addjscombo) {
11613 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
11614 }
11615
11616 return $retstring;
11617 }
11618
11630 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
11631 {
11632 global $langs;
11633
11634 $buttons = array();
11635
11636 $save = array(
11637 'name' => 'save',
11638 'label_key' => $save_label,
11639 );
11640
11641 if ($save_label == 'Create' || $save_label == 'Add') {
11642 $save['name'] = 'add';
11643 } elseif ($save_label == 'Modify') {
11644 $save['name'] = 'edit';
11645 }
11646
11647 $cancel = array(
11648 'name' => 'cancel',
11649 'label_key' => 'Cancel',
11650 );
11651
11652 !empty($save_label) ? $buttons[] = $save : '';
11653
11654 if (!empty($morebuttons)) {
11655 $buttons[] = $morebuttons;
11656 }
11657
11658 !empty($cancel_label) ? $buttons[] = $cancel : '';
11659
11660 $retstring = $withoutdiv ? '' : '<div class="center">';
11661
11662 foreach ($buttons as $button) {
11663 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
11664 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
11665 }
11666 $retstring .= $withoutdiv ? '' : '</div>';
11667
11668 if ($dol_openinpopup) {
11669 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
11670 $retstring .= '<script nonce="' . getNonce() . '">';
11671 $retstring .= 'jQuery(".button-cancel").click(function(e) {
11672 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
11673 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
11674 });';
11675 $retstring .= '</script>';
11676 }
11677
11678 return $retstring;
11679 }
11680
11681
11682 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11683
11690 {
11691 // phpcs:enable
11692 global $langs;
11693
11694 $num = count($this->cache_invoice_subtype);
11695 if ($num > 0) {
11696 return 0; // Cache already loaded
11697 }
11698
11699 dol_syslog(__METHOD__, LOG_DEBUG);
11700
11701 $sql = "SELECT rowid, code, label as label";
11702 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
11703 $sql .= " WHERE active = 1";
11704
11705 $resql = $this->db->query($sql);
11706 if ($resql) {
11707 $num = $this->db->num_rows($resql);
11708 $i = 0;
11709 while ($i < $num) {
11710 $obj = $this->db->fetch_object($resql);
11711
11712 // If translation exists, we use it, otherwise we take the default wording
11713 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
11714 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
11715 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
11716 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
11717 $i++;
11718 }
11719
11720 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
11721
11722 return $num;
11723 } else {
11724 dol_print_error($this->db);
11725 return -1;
11726 }
11727 }
11728
11729
11740 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
11741 {
11742 global $langs, $user;
11743
11744 $out = '';
11745 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
11746
11748
11749 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
11750 if ($addempty) {
11751 $out .= '<option value="0">&nbsp;</option>';
11752 }
11753
11754 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
11755 $label = $subtype['label'];
11756 $out .= '<option value="' . $subtype['rowid'] . '"';
11757 if ($selected == $subtype['rowid']) {
11758 $out .= ' selected="selected"';
11759 }
11760 $out .= '>';
11761 $out .= $label;
11762 $out .= '</option>';
11763 }
11764
11765 $out .= '</select>';
11766 if ($user->admin && empty($noinfoadmin)) {
11767 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11768 }
11769 $out .= ajax_combobox($htmlname);
11770
11771 return $out;
11772 }
11773}
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to transform a common input text or select field into ...
Definition ajax.lib.php:49
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:459
ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
Generic function that return javascript to add to a page to transform a common input text field into ...
Definition ajax.lib.php:308
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:562
$object ref
Definition info.php:89
Class to manage bank accounts.
Class to manage categories.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage bank accounts description of third parties.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
DAO Resource object.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array(), $nooutput=0)
Show block with links "to link to" other objects.
showFilterButtons($pos='')
Return HTML to show the search and clear search button.
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array(), $canremoveowner=1)
Return select list of users.
load_cache_vatrates($country_code)
Load into the cache ->cache_vatrates, all the vat rates of a country.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=array(), $title='RelatedObjects')
Show linked object block.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
select_dolresources_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofresourceid=array())
Return select list of resources.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
formRib($page, $selected='', $htmlname='ribcompanyid', $filtre='', $addempty=0, $showibanbic=0)
Display form to select bank customer account.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party This call select_thirdparty_list() or ajax depending on setu...
select_produits($selected=0, $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1, $warehouseId=0)
Return list of products for customer.
select_dolgroups($selected=0, $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly=array(), $force_entity='0', $multiple=false, $morecss='minwidth200')
Return select list of user groups.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
select_contact($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $nokeyifsocid=true, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $selected_input_value='', $filter='')
Output html form to select a contact This call select_contacts() or ajax depending on setup.
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="", $useajaxcombo=1)
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
selectRib($selected='', $htmlname='ribcompanyid', $filtre='', $useempty=0, $moreattrib='', $showibanbic=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts customer.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
getSelectInvoiceSubtype($selected=0, $htmlname='subtypeid', $addempty=0, $noinfoadmin=0, $morecss='')
Return list of invoice subtypes.
select_produits_list($selected=0, $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='maxwidth500', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1, $warehouseId=0)
Return list of products for a customer.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse=null, $societe_acheteuse=null, $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0, $type_vat=0)
Output an HTML select vat rate.
form_multicurrency_rate($page, $rate=0.0, $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
load_cache_availability()
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
selectcontacts($socid, $selected=array(), $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=0, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0, $filter='')
Return HTML code of the SELECT of list of all contacts (for a third party or all).
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
selectMembersList($selected='', $htmlname='adherentid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of adherents.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
selectTicketsList($selected='', $htmlname='ticketid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of tickets.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=false, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
selectProjectsList($selected='', $htmlname='projectid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of projects.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0, $selected='')
selectModelMail
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1, $noprint=0)
print list of payment modes.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
form_confirm($page, $title, $question, $action, $formquestion=array(), $selectedchoice="", $useajax=0, $height=170, $width=500)
load_cache_conditions_paiements()
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier=0)
Return list of suppliers prices for a product.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='width75', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0)
Return combo list of activated countries, into language of user.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly=array(), $force_entity='0')
Return the HTML select list of users.
selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='', $openinghours='', $stepminutes=1, $labeladddateof='', $placeholder='', $gm='auto', $calendarpicto='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
static selectArrayFilter($htmlname, $array, $id='', $moreparam='', $disableFiltering=0, $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0, $textfortitle='')
Return a HTML select string, built from an array of key+value, but content returned into select is de...
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday=0, $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
load_cache_invoice_subtype()
Load into cache list of invoice subtypes.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $elemtype='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
textwithpicto($text, $htmltext, $direction=1, $type='help', $extracss='valignmiddle', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
load_cache_types_paiements()
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Return the list of type of delay available.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='', $arrayoffiltercriterias=array())
Output the component to make advanced search criteries.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class permettant la generation de composants html autre Only common components are here.
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage hooks.
Class for MyObject.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
currency_name($code_iso, $withcode=0, $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dolPrintHTMLForAttribute($s)
Return a string ready to be output on an HTML attribute (alt, title, data-html, .....
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0, $morecss='paddingrightonly')
Show EMail link formatted for HTML output.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0, $allowscript=0, $allowstyle=0, $allowphp=0)
Clean a string to keep only desirable HTML tags.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
a disabled
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition main.inc.php:123
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
measuringUnitString($unitid, $measuring_style='', $unitscale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:149
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:152
getMaxFileSizeArray()
Return the max allowed for file upload.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.