dolibarr 23.0.3
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-2026 Alexandre Spangaro <alexandre@inovea-conseil.com>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2025 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-2025 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;
76
78 public $num;
79
80 // Cache arrays
82 public $cache_types_paiements = array();
84 public $cache_conditions_paiements = array();
86 public $cache_transport_mode = array();
88 public $cache_availability = array();
90 public $cache_demand_reason = array();
92 public $cache_types_fees = array();
94 public $cache_vatrates = array();
96 public $cache_invoice_subtype = array();
98 public $cache_rule_for_lines_dates = array();
99
100
106 public function __construct($db)
107 {
108 $this->db = $db;
109 }
110
119 public function getDurationTypes(Translate $langs, $plurial = true, $reverse = false)
120 {
121 if ($plurial) {
122 $arrayoftypes = [
123 'y' => $langs->trans('Years'),
124 'm' => $langs->trans('Month'),
125 'w' => $langs->trans('Weeks'),
126 'd' => $langs->trans('Days'),
127 'h' => $langs->trans('Hours'),
128 'i' => $langs->trans('Minutes'),
129 's' => $langs->trans('Seconds'),
130 ];
131 } else {
132 $arrayoftypes = [
133 "y" => $langs->trans("Year"),
134 "m" => $langs->trans("Month"),
135 "w" => $langs->trans("Week"),
136 "d" => $langs->trans("Day"),
137 "h" => $langs->trans("Hour"),
138 "i" => $langs->trans("Minute"),
139 's' => $langs->trans('Second'),
140 ];
141 }
142 if ($reverse) {
143 return array_reverse($arrayoftypes);
144 } else {
145 return $arrayoftypes;
146 }
147 }
148
165 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
166 {
167 global $langs;
168
169 $ret = '';
170
171 // TODO change for compatibility
172 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
173 if ($perm) {
174 $tmp = explode(':', $typeofdata);
175 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
176 if ($fieldrequired) {
177 $ret .= '<span class="fieldrequired">';
178 }
179 if ($help) {
180 $ret .= $this->textwithpicto($langs->trans($text), $help);
181 } else {
182 $ret .= $langs->trans($text);
183 }
184 if ($fieldrequired) {
185 $ret .= '</span>';
186 }
187 $ret .= '</div>' . "\n";
188 } else {
189 if ($fieldrequired) {
190 $ret .= '<span class="fieldrequired">';
191 }
192 if ($help) {
193 $ret .= $this->textwithpicto($langs->trans($text), $help);
194 } else {
195 $ret .= $langs->trans($text);
196 }
197 if ($fieldrequired) {
198 $ret .= '</span>';
199 }
200 }
201 } else {
202 if (empty($notabletag) && $perm) {
203 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
204 }
205 if ($fieldrequired) {
206 $ret .= '<span class="fieldrequired">';
207 }
208 if ($help) {
209 $ret .= $this->textwithpicto($langs->trans($text), $help);
210 } else {
211 $ret .= $langs->trans($text);
212 }
213 if ($fieldrequired) {
214 $ret .= '</span>';
215 }
216 if (!empty($notabletag)) {
217 $ret .= ' ';
218 }
219 if (empty($notabletag) && $perm) {
220 $ret .= '</td>';
221 }
222 if (empty($notabletag) && $perm) {
223 $ret .= '<td class="right">';
224 }
225 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm && is_object($object)) {
226 $ret .= '<a class="editfielda reposition" href="' . dolBuildUrl($_SERVER["PHP_SELF"], ['action' => 'edit' . $htmlname, $paramid => $object->id], true) . $moreparam . '">';
227 $ret .= img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1));
228 $ret .= '</a>';
229 }
230 if (!empty($notabletag) && $notabletag == 1) {
231 if ($text) {
232 $ret .= ' : ';
233 } else {
234 $ret .= ' ';
235 }
236 }
237 if (!empty($notabletag) && $notabletag == 3) {
238 $ret .= ' ';
239 }
240 if (empty($notabletag) && $perm) {
241 $ret .= '</td>';
242 }
243 if (empty($notabletag) && $perm) {
244 $ret .= '</tr></table>';
245 }
246 }
247
248 return $ret;
249 }
250
274 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 = '')
275 {
276 global $conf, $langs;
277
278 $ret = '';
279
280 // Check parameters
281 if (empty($typeofdata)) {
282 return 'ErrorBadParameter typeofdata is empty';
283 }
284 // Clean parameter $typeofdata
285 if ($typeofdata == 'datetime') {
286 $typeofdata = 'dayhour';
287 }
288 $reg = array();
289 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
290 if ($reg[1] == 'varchar') {
291 $typeofdata = 'string';
292 } elseif ($reg[1] == 'int') {
293 $typeofdata = 'numeric';
294 } else {
295 return 'ErrorBadParameter ' . $typeofdata;
296 }
297 }
298
299 // When option to edit inline is activated
300 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) {
301 $ret .= $this->editInPlace($object, $value, $htmlname, ($perm ? 1 : 0), $typeofdata, $editvalue, $extObject, $custommsg);
302 } else {
303 if ($editaction == '') {
304 $editaction = GETPOST('action', 'aZ09');
305 }
306 $editmode = ($editaction == 'edit' . $htmlname);
307 if ($editmode) { // edit mode
308 $ret .= "<!-- formeditfieldval -->\n";
309 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
310 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
311 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
312 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
313 if (empty($notabletag)) {
314 $ret .= '<table class="nobordernopadding centpercent">';
315 }
316 if (empty($notabletag)) {
317 $ret .= '<tr><td>';
318 }
319 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
320 $tmp = explode(':', $typeofdata);
321 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus spellcheck="false">';
322 } elseif (preg_match('/^(integer)/', $typeofdata)) {
323 $tmp = explode(':', $typeofdata);
324 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
325 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
326 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
327 $tmp = explode(':', $typeofdata);
328 $valuetoshow = price2num($editvalue ? $editvalue : $value);
329 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
330 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
331 $tmp = explode(':', $typeofdata);
332 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
333 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
334 $tmp = explode(':', $typeofdata);
335 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
336 $morealt = '';
337 if (preg_match('/%/', $cols)) {
338 $morealt = ' style="width: ' . $cols . '"';
339 $cols = '';
340 }
341 $valuetoshow = ($editvalue ? $editvalue : $value);
342 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
343 // textarea convert automatically entities chars into simple chars.
344 // 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.
345 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
346 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
347 $ret .= '</textarea><div class="clearboth"></div>';
348 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
349 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
350 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
351 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
352 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
353 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
354 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
355 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
356 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
357 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
358 } elseif (preg_match('/^select;/', $typeofdata)) {
359 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
360 $arraylist = array();
361 foreach ($arraydata as $val) {
362 $tmp = explode(':', $val);
363 $tmpkey = str_replace('|', ':', $tmp[0]);
364 $arraylist[$tmpkey] = $tmp[1];
365 }
366 $ret .= $this->selectarray($htmlname, $arraylist, $value);
367 } elseif (preg_match('/^link/', $typeofdata)) {
368 // TODO Not yet implemented. See code for extrafields
369 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
370 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
371 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
372 $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]));
373 $ret .= $doleditor->Create(1);
374 } elseif ($typeofdata == 'asis') {
375 $ret .= ($editvalue ? $editvalue : $value);
376 }
377 if (empty($notabletag)) {
378 $ret .= '</td>';
379 }
380
381 // Button save-cancel
382 if (empty($notabletag)) {
383 $ret .= '<td>';
384 }
385 //else $ret.='<div class="clearboth"></div>';
386 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Save") . '">';
387 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
388 $ret .= '<br>' . "\n";
389 }
390 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
391 if (empty($notabletag)) {
392 $ret .= '</td>';
393 }
394
395 if (empty($notabletag)) {
396 $ret .= '</tr></table>' . "\n";
397 }
398 $ret .= '</form>' . "\n";
399 } else { // view mode
400 if (preg_match('/^email/', $typeofdata)) {
401 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
402 } elseif (preg_match('/^phone/', $typeofdata)) {
403 $ret .= dol_print_phone($value, '_blank', 32, 1);
404 } elseif (preg_match('/^url/', $typeofdata)) {
405 $ret .= dol_print_url($value, '_blank', 32, 1);
406 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
407 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
408 } elseif (preg_match('/^checkbox/', $typeofdata)) {
409 $tmp = explode(':', $typeofdata);
410 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
411 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
413 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
415 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
416 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
417 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
418 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
419 } elseif (preg_match('/^select;/', $typeofdata)) {
420 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
421 $arraylist = array();
422 foreach ($arraydata as $val) {
423 $tmp = explode(':', $val);
424 $arraylist[$tmp[0]] = $tmp[1];
425 }
426 $ret .= $arraylist[$value];
427 if ($htmlname == 'fk_product_type') {
428 if ($value == 0) {
429 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
430 } else {
431 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
432 }
433 }
434 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
435 $tmpcontent = dol_htmlentitiesbr($value);
436 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
437 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
438 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
439 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
440 }
441 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
442 // clean data from some dangerous html
444 } else {
445 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
446 $ret .= dol_escape_htmltag($value);
447 } else {
448 $ret .= $value; // $value must be already html escaped.
449 }
450 }
451
452 // Custom format if parameter $formatfunc has been provided
453 if ($formatfunc && method_exists($object, $formatfunc)) {
454 $ret = $object->$formatfunc($ret);
455 }
456 }
457 }
458 return $ret;
459 }
460
472 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
473 {
474 global $conf, $langs, $extralanguages;
475
476 $result = '';
477
478 // List of extra languages
479 $arrayoflangcode = array();
480 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
481 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
482 }
483
484 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
485 if (!is_object($extralanguages)) {
486 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
487 $extralanguages = new ExtraLanguages($this->db);
488 }
489 $extralanguages->fetch_name_extralanguages('societe');
490
491 // ExtraLanguages::fetch_name_extralanguages() leaves $this->attributes empty
492 // when MAIN_USE_ALTERNATE_TRANSLATION_FOR is not configured, so PHP 8 raises
493 // 'Undefined array key' on the read below if we do not guard it (issue #34596).
494 if (empty($extralanguages->attributes[$object->element]) || !is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
495 return ''; // No extralang field to show
496 }
497
498 $result .= '<!-- Widget for translation -->' . "\n";
499 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
500 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', 0, 0, 0, '', 'fa-15 editfieldlang');
501 $result .= $s;
502 $result .= '</div>';
503
504 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
505
506 $resultforextrlang = '';
507 foreach ($arrayoflangcode as $langcode) {
508 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
509 if (empty($valuetoshow)) {
510 $object->fetchValuesForExtraLanguages();
511 //var_dump($object->array_languages);
512 $valuetoshow = $object->array_languages[$fieldname][$langcode];
513 }
514
515 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
516 $resultforextrlang .= $s;
517
518 // TODO Use the showInputField() method of ExtraLanguages object
519 if ($typeofdata == 'textarea') {
520 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
521 $resultforextrlang .= $valuetoshow;
522 $resultforextrlang .= '</textarea>';
523 } else {
524 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
525 }
526 }
527 $result .= $resultforextrlang;
528
529 $result .= '</div>';
530 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
531 }
532
533 return $result;
534 }
535
549 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
550 {
551 $out = '';
552
553 // Check parameters
554 if (preg_match('/^text/', $inputType)) {
555 $value = dol_nl2br($value);
556 } elseif (preg_match('/^numeric/', $inputType)) {
557 $value = price($value);
558 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
559 $value = dol_print_date($value, 'day');
560 }
561
562 if ($condition) {
563 $element = false;
564 $table_element = false;
565 $fk_element = false;
566 $loadmethod = false;
567 $savemethod = false;
568 $ext_element = false;
569 $button_only = false;
570 $inputOption = '';
571 $rows = '';
572 $cols = '';
573
574 if (is_object($object)) {
575 $element = $object->element;
576 $table_element = $object->table_element;
577 $fk_element = $object->id;
578 }
579
580 if (is_object($extObject)) {
581 $ext_element = $extObject->element;
582 }
583
584 if (preg_match('/^(string|email|numeric)/', $inputType)) {
585 $tmp = explode(':', $inputType);
586 $inputType = $tmp[0];
587 if (!empty($tmp[1])) {
588 $inputOption = $tmp[1];
589 }
590 if (!empty($tmp[2])) {
591 $savemethod = $tmp[2];
592 }
593 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
594 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
595 $tmp = explode(':', $inputType);
596 $inputType = $tmp[0];
597 if (!empty($tmp[1])) {
598 $inputOption = $tmp[1];
599 }
600 if (!empty($tmp[2])) {
601 $savemethod = $tmp[2];
602 }
603
604 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
605 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
606 $tmp = explode(':', $inputType);
607 $inputType = $tmp[0];
608 $loadmethod = $tmp[1];
609 if (!empty($tmp[2])) {
610 $savemethod = $tmp[2];
611 }
612 if (!empty($tmp[3])) {
613 $button_only = true;
614 }
615 } elseif (preg_match('/^textarea/', $inputType)) {
616 $tmp = explode(':', $inputType);
617 $inputType = $tmp[0];
618 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
619 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
620 } elseif (preg_match('/^ckeditor/', $inputType)) {
621 $tmp = explode(':', $inputType);
622 $inputType = $tmp[0];
623 $toolbar = $tmp[1];
624 if (!empty($tmp[2])) {
625 $width = $tmp[2];
626 }
627 if (!empty($tmp[3])) {
628 $height = $tmp[3];
629 }
630 if (!empty($tmp[4])) {
631 $savemethod = $tmp[4];
632 }
633
634 if (isModEnabled('fckeditor')) {
635 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
636 } else {
637 $inputType = 'textarea';
638 }
639 }
640
641 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
642 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
643 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
644 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
645 if (!empty($savemethod)) {
646 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
647 }
648 if (!empty($ext_element)) {
649 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
650 }
651 if (!empty($custommsg)) {
652 if (is_array($custommsg)) {
653 if (!empty($custommsg['success'])) {
654 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
655 }
656 if (!empty($custommsg['error'])) {
657 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
658 }
659 } else {
660 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
661 }
662 }
663 if ($inputType == 'textarea') {
664 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
665 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
666 }
667 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
668 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
669 } else {
670 $out = $value;
671 }
672
673 return $out;
674 }
675
694 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
695 {
696 if ($incbefore) {
697 $text = $incbefore . $text;
698 }
699 if (!$htmltext) {
700 return $text;
701 }
702 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
703
704 $tag = 'td';
705 if ($notabs == 2) {
706 $tag = 'div';
707 }
708 if ($notabs == 3) {
709 $tag = 'span';
710 }
711 // Sanitize tooltip
712 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
713
714 $extrastyle = '';
715 if ($direction < 0) {
716 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
717 $extrastyle = 'padding: 0px; padding-left: 2px;';
718 }
719 if ($direction > 0) {
720 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
721 $extrastyle = 'padding: 0px; padding-right: 2px;';
722 }
723
724 $classfortooltip = 'classfortooltip';
725
726 $s = '';
727 $textfordialog = '';
728
729 if ($tooltiptrigger == '') {
730 $htmltext = str_replace('"', '&quot;', $htmltext);
731 } else {
732 $classfortooltip = 'classfortooltiponclick';
733 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext"';
734 // Set default title of dialog
735 global $langs;
736 if ($langs instanceof Translate) {
737 $textfordialog .= ' title="'.$langs->trans("Note").'"';
738 }
739 $textfordialog .= '>' . $htmltext . '</div>';
740 }
741 if ($tooltipon == 2 || $tooltipon == 3) {
742 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
743 if ($tooltiptrigger == '') {
744 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1, 0, 'span', 0, 1)) . '"'; // Attribute to put on img tag to store tooltip
745 } else {
746 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
747 }
748 } else {
749 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
750 }
751 if ($tooltipon == 1 || $tooltipon == 3) {
752 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ($tag != 'td' ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
753 if ($tooltiptrigger == '') {
754 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1, 0, 'span', 0, 1)) . '"'; // Attribute to put on td tag to store tooltip
755 } else {
756 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
757 }
758 } else {
759 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
760 }
761 if (empty($notabs)) {
762 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
763 } elseif ($notabs == 2) {
764 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
765 }
766 // Define value if value is before
767 if ($direction < 0) {
768 $s .= '<' . $tag . $paramfortooltipimg;
769 if ($tag == 'td') {
770 $s .= ' class="valigntop" width="14"';
771 }
772 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
773 }
774 // Use another method to help avoid having a space in value in order to use this value with jquery
775 // Define label
776 if ((string) $text != '') {
777 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
778 }
779 // Define value if value is after
780 if ($direction > 0) {
781 $s .= '<' . $tag . $paramfortooltipimg;
782 if ($tag == 'td') {
783 $s .= ' class="valignmiddle" width="14"';
784 }
785 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
786 }
787 if (empty($notabs)) {
788 $s .= '</tr></table>';
789 } elseif ($notabs == 2) {
790 $s .= '</div>';
791 }
792
793 return $s;
794 }
795
810 public function textwithpicto($text, $htmltooltip, $direction = 1, $type = 'help', $extracss = 'valignmiddle', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
811 {
812 global $conf, $langs;
813
814 //For backwards compatibility
815 if ($type == '0') {
816 $type = 'info';
817 } elseif ($type == '1') {
818 $type = 'help';
819 }
820 // Clean parameters
821 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
822
823 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
824 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
825 }
826 $alt = '';
827 if ($tooltiptrigger) {
828 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
829 }
830
831 // If info or help with no javascript, show only text
832 if (empty($conf->use_javascript_ajax)) {
833 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
834 return $text;
835 } else {
836 $alt = $htmltooltip;
837 $htmltooltip = '';
838 }
839 }
840
841 // If info or help with smartphone, show only text (tooltip hover can't works)
842 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
843 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
844 return $text;
845 }
846 }
847 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
848 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
849 //{
850 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
851 //}
852
853 $img = '';
854 if ($type == 'info') {
855 $img = img_help(($tooltiptrigger != '' ? 2 : 0), $alt);
856 } elseif ($type == 'help') {
857 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
858 } elseif ($type == 'helpclickable') {
859 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
860 } elseif ($type == 'warning') {
861 $img = img_warning($alt);
862 } elseif ($type != 'none') {
863 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
864 $img = img_picto($alt, $type); // $type can be an image path
865 }
866
867 $tooltipon = ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2);
868
869 return $this->textwithtooltip($text, $htmltooltip, $tooltipon, $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
870 }
871
882 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
883 {
884 global $conf, $langs, $hookmanager;
885
886 $disabled = 0;
887 $ret = '<div class="centpercent center">';
888 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
889
890 // 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.
891 $parameters = array();
892 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
893 // check if there is a mass action
894
895 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
896 return;
897 }
898 if (empty($reshook)) {
899 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
900 if (is_array($arrayofaction)) {
901 foreach ($arrayofaction as $code => $label) {
902 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
903 }
904 }
905 }
906 $ret .= $hookmanager->resPrint;
907
908 $ret .= '</select>';
909
910 if (empty($conf->dol_optimize_smallscreen)) {
911 $ret .= ajax_combobox('.' . $name . 'select');
912 }
913
914 // 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
915 $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.
916 $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")) . '">';
917 $ret .= '</div>';
918
919 if (!empty($conf->use_javascript_ajax)) {
920 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
921 <script nonce="' . getNonce() . '">
922 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 check for select boxes */
923 atleastoneselected=0;
924 jQuery("."+cssclass).each(function( index ) {
925 /* console.log( index + ": " + $( this ).text() ); */
926 if ($(this).is(\':checked\')) atleastoneselected++;
927 });
928
929 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
930
931 if (atleastoneselected || ' . ((int) $alwaysvisible) . ') {
932 jQuery("."+name).show();
933 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
934 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
935 } else {
936 jQuery("."+name).hide();
937 jQuery("."+name+"other").hide();
938 }
939 }
940
941 jQuery(document).ready(function () {
942 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
943 jQuery(".' . $cssclass . '").change(function() {
944 console.log("A change was done on .' . $cssclass . '");
945 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
946 });
947 jQuery(".' . $name . 'select").change(function() {
948 var massaction = $( this ).val();
949 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
950 if (massaction == "builddoc") {
951 urlform = urlform + "#show_files";
952 }
953 $( this ).closest("form").attr("action", urlform);
954 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
955 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
956 if ($(this).val() != \'0\') {
957 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
958 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
959 jQuery(".' . $name . '"+massaction).show();
960 } else {
961 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
962 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
963 }
964 });
965 });
966 </script>
967 ';
968 }
969
970 return $ret;
971 }
972
973 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
974
992 public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0, $forcecombo = 0)
993 {
994 // phpcs:enable
995 global $langs, $mysoc;
996
997 $langs->load("dict");
998
999 $selected = (string) $selected;
1000
1001 $out = '';
1003 $countryArray = array();
1004 $favorite = array();
1005 $label = array();
1006 $atleastonefavorite = 0;
1007
1008 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
1009 $sql .= " FROM " . $this->db->prefix() . "c_country";
1010 $sql .= " WHERE active > 0";
1011 //$sql.= " ORDER BY code ASC";
1012
1013 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
1014
1015 $resql = $this->db->query($sql);
1016 if ($resql) {
1017 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
1018 $num = $this->db->num_rows($resql);
1019 $i = 0;
1020 if ($num) {
1021 while ($i < $num) {
1022 $obj = $this->db->fetch_object($resql);
1023
1024 $countryArray[$i]
1025 = array(
1026 'rowid' => (int) $obj->rowid,
1027 'code_iso' => (string) $obj->code_iso,
1028 'code_iso3' => (string) $obj->code_iso3,
1029 'label' => (string) ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : '')),
1030 'favorite' => (string) $obj->favorite,
1031 'eec' => (string) $obj->eec,
1032 );
1033 $favorite[$i] = $obj->favorite;
1034 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
1035 $i++;
1036 }
1037
1038 if (empty($disablefavorites)) {
1039 $array1_sort_order = SORT_DESC;
1040 $array2_sort_order = SORT_ASC;
1041 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
1042 } else {
1043 $countryArray = dol_sort_array($countryArray, 'label');
1044 }
1045
1046 if ($showempty) {
1047 if (is_numeric($showempty)) {
1048 $out .= '<option value="">&nbsp;</option>' . "\n";
1049 } else {
1050 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
1051 }
1052 }
1053
1054 if ($addspecialentries) { // Add dedicated entries for groups of countries
1055 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
1056 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1057 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
1058 if ($mysoc->isInEEC()) {
1059 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1060 }
1061 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1062 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1063 }
1064
1065 foreach ($countryArray as $row) {
1066 //if (empty($showempty) && empty($row['rowid'])) continue;
1067 if (empty($row['rowid'])) {
1068 continue;
1069 }
1070 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1071 continue; // exclude some countries
1072 }
1073
1074 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1075 $atleastonefavorite++;
1076 }
1077 if (empty($row['favorite']) && $atleastonefavorite) {
1078 $atleastonefavorite = 0;
1079 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1080 }
1081
1082 $labeltoshow = '';
1083 if ($row['label']) {
1084 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1085 } else {
1086 $labeltoshow .= '&nbsp;';
1087 }
1088 if ($row['code_iso']) {
1089 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1090 if (empty($hideflags)) {
1091 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1092 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1093 }
1094 }
1095
1096 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1097 $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']) . '">';
1098 } else {
1099 $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']) . '">';
1100 }
1101 $out .= dol_string_nohtmltag($labeltoshow);
1102 $out .= '</option>' . "\n";
1103 }
1104 }
1105 $out .= '</select>';
1106 } else {
1107 dol_print_error($this->db);
1108 }
1109
1110 // Make select dynamic
1111 if (empty($forcecombo)) {
1112 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1113 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1114 }
1115
1116 return $out;
1117 }
1118
1119 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1120
1134 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1135 {
1136 // phpcs:enable
1137 global $conf, $langs;
1138
1139 $langs->load("dict");
1140
1141 $out = '';
1142 //$moreattrib = '';
1143 $incotermArray = array();
1144
1145 $sql = "SELECT rowid, code";
1146 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1147 $sql .= " WHERE active > 0";
1148 $sql .= " ORDER BY code ASC";
1149
1150 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1151 $resql = $this->db->query($sql);
1152 if ($resql) {
1153 if ($conf->use_javascript_ajax && !$forcecombo) {
1154 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1155 $out .= ajax_combobox($htmlname, $events);
1156 }
1157
1158 if (!empty($page)) {
1159 $out .= '<form method="post" action="' . $page . '">';
1160 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1161 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1162 }
1163
1164 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1165 $out .= '<option value="0">&nbsp;</option>';
1166 $num = $this->db->num_rows($resql);
1167 $i = 0;
1168 if ($num) {
1169 while ($i < $num) {
1170 $obj = $this->db->fetch_object($resql);
1171 $incotermArray[$i]['rowid'] = $obj->rowid;
1172 $incotermArray[$i]['code'] = $obj->code;
1173 $i++;
1174 }
1175
1176 foreach ($incotermArray as $row) {
1177 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1178 $out .= '<option value="' . $row['rowid'] . '" selected>';
1179 } else {
1180 $out .= '<option value="' . $row['rowid'] . '">';
1181 }
1182
1183 if ($row['code']) {
1184 $out .= $row['code'];
1185 }
1186
1187 $out .= '</option>';
1188 }
1189 }
1190 $out .= '</select>';
1191 $out .= ajax_combobox($htmlname);
1192
1193 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1194 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1195 //$moreattrib .= ' autocomplete="off"';
1196 }
1197 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone heightofcombo" type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1198
1199 if (!empty($page)) {
1200 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1201 }
1202 } else {
1203 dol_print_error($this->db);
1204 }
1205
1206 return $out;
1207 }
1208
1209 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1210
1224 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "", $useajaxcombo = 1)
1225 {
1226 // phpcs:enable
1227 global $langs;
1228
1229 // If product & services are enabled or both disabled.
1230 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1231 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1232 if (empty($hidetext)) {
1233 print $langs->trans("Type").'...';
1234 }
1235
1236 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1237 if ($showempty) {
1238 print '<option value="-1" class="opacitymedium"'.($useajaxcombo ? '' : ' disabled="disabled"');
1239 if ($selected == -1) {
1240 print ' selected';
1241 }
1242 print '>';
1243 if (is_numeric($showempty)) {
1244 print '&nbsp;';
1245 } else {
1246 print $showempty;
1247 }
1248 print '</option>';
1249 }
1250
1251 print '<option value="0"';
1252 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1253 print ' selected';
1254 }
1255 print '>' . $langs->trans("Product");
1256 print '</option>';
1257
1258 print '<option value="1"';
1259 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1260 print ' selected';
1261 }
1262 print '>' . $langs->trans("Service");
1263 print '</option>';
1264
1265 print '</select>';
1266
1267 if ($useajaxcombo) {
1268 print ajax_combobox('select_' . $htmlname);
1269 }
1270 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1271 }
1272 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1273 print $langs->trans("Service");
1274 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1275 }
1276 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1277 print $langs->trans("Product");
1278 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1279 }
1280 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1281 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
1282 }
1283 }
1284
1285 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1286
1292 public function load_cache_types_fees()
1293 {
1294 // phpcs:enable
1295 global $langs;
1296
1297 $num = count($this->cache_types_fees);
1298 if ($num > 0) {
1299 return 0; // Cache already loaded
1300 }
1301
1302 dol_syslog(__METHOD__, LOG_DEBUG);
1303
1304 $langs->load("trips");
1305
1306 $sql = "SELECT c.code, c.label";
1307 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1308 $sql .= " WHERE active > 0";
1309
1310 $resql = $this->db->query($sql);
1311 if ($resql) {
1312 $num = $this->db->num_rows($resql);
1313 $i = 0;
1314
1315 while ($i < $num) {
1316 $obj = $this->db->fetch_object($resql);
1317
1318 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1319 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1320 $this->cache_types_fees[$obj->code] = $label;
1321 $i++;
1322 }
1323
1324 asort($this->cache_types_fees);
1325
1326 return $num;
1327 } else {
1328 dol_print_error($this->db);
1329 return -1;
1330 }
1331 }
1332
1333 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1334
1343 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1344 {
1345 // phpcs:enable
1346 global $user, $langs;
1347
1348 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1349
1350 $this->load_cache_types_fees();
1351
1352 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1353 if ($showempty) {
1354 print '<option value="-1"';
1355 if ($selected == -1) {
1356 print ' selected';
1357 }
1358 print '>&nbsp;</option>';
1359 }
1360
1361 foreach ($this->cache_types_fees as $key => $value) {
1362 print '<option value="' . $key . '"';
1363 if ($key == $selected) {
1364 print ' selected';
1365 }
1366 print '>';
1367 print $value;
1368 print '</option>';
1369 }
1370
1371 print '</select>';
1372 if ($user->admin) {
1373 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1374 }
1375 }
1376
1377
1378 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1379
1402 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)
1403 {
1404 // phpcs:enable
1405 global $conf, $langs;
1406
1407 $out = '';
1408
1409 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1410 if (is_null($ajaxoptions)) {
1411 $ajaxoptions = array();
1412 }
1413
1414 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1415
1416 // No immediate load of all database
1417 $placeholder = '';
1418 if ($selected && empty($selected_input_value)) {
1419 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1420 $societetmp = new Societe($this->db);
1421 $societetmp->fetch($selected);
1422 $selected_input_value = $societetmp->name;
1423 unset($societetmp);
1424 }
1425
1426 // mode 1
1427 $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)) : '');
1428
1429 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1430 if (empty($hidelabel)) {
1431 $out .= $langs->trans("RefOrLabel") . ' : ';
1432 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1433 $placeholder = $langs->trans($showempty);
1434 } elseif ($hidelabel > 1) {
1435 $placeholder = $langs->trans("RefOrLabel");
1436 if ($hidelabel == 2) {
1437 $out .= img_picto($langs->trans("Search"), 'search');
1438 }
1439 }
1440 $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' : '') . ' />';
1441 if ($hidelabel == 3) {
1442 $out .= img_picto($langs->trans("Search"), 'search');
1443 }
1444
1445 $out .= ajax_event($htmlname, $events);
1446
1447 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1448 } else {
1449 // Immediate load of all database
1450 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1451 }
1452
1453 return $out;
1454 }
1455
1456
1457 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1458
1484 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 = '')
1485 {
1486 // phpcs:enable
1487
1488 global $conf, $langs;
1489
1490 $out = '';
1491
1492 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1493 if ($nokeyifsocid && $socid > 0) {
1494 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1495 }
1496
1497 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1498 if (is_null($events)) {
1499 $events = array();
1500 }
1501
1502 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1503
1504 // No immediate load of all database
1505 $placeholder = '';
1506 if ($selected && empty($selected_input_value)) {
1507 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1508 $contacttmp = new Contact($this->db);
1509 $contacttmp->fetch($selected);
1510 $selected_input_value = $contacttmp->getFullName($langs);
1511 unset($contacttmp);
1512 }
1513 if (!is_numeric($showempty)) {
1514 $placeholder = $showempty;
1515 }
1516
1517 // mode 1
1518 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1519
1520 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1521
1522 $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' : '') . ' />';
1523
1524 $out .= ajax_event($htmlname, $events);
1525
1526 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1527 } else {
1528 // Immediate load of all database
1529 $multiple = false;
1530 $disableifempty = 0;
1531 $options_only = 0;
1532 $limitto = '';
1533
1534 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1535 }
1536
1537 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1538
1539 return $out;
1540 }
1541
1542
1543 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1544
1570 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)
1571 {
1572 // phpcs:enable
1573 global $user, $langs;
1574 global $hookmanager;
1575
1576 $langs->loadLangs(array("companies", "suppliers"));
1577
1578 $out = '';
1579 $num = 0;
1580 $outarray = array();
1581
1582 if ($selected === '') {
1583 $selected = array();
1584 } elseif (!is_array($selected)) {
1585 $selected = array($selected);
1586 }
1587
1588 // Clean $filter that may contains sql conditions so sql code
1589 if (function_exists('testSqlAndScriptInject')) {
1590 if (testSqlAndScriptInject($filter, 3) > 0) {
1591 $filter = '';
1592 return 'SQLInjectionTryDetected';
1593 }
1594 }
1595
1596 if ($filter != '') { // If a filter was provided
1597 if (preg_match('/[\‍(\‍)]/', $filter)) {
1598 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1599 $errormsg = '';
1600 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1601
1602 // Redo clean $filter that may contains sql conditions so sql code
1603 if (function_exists('testSqlAndScriptInject')) {
1604 if (testSqlAndScriptInject($filter, 3) > 0) {
1605 $filter = '';
1606 return 'SQLInjectionTryDetected';
1607 }
1608 }
1609 } else {
1610 // If not, we do nothing. We already know that there is no parenthesis
1611 // TODO Disallow this case in a future.
1612 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1613 }
1614 }
1615
1616 // We search companies
1617 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1618 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1619 $sql .= ", s.address, s.zip, s.town";
1620 $sql .= ", dictp.code as country_code";
1621 }
1622 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1623 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1624 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1625 }
1626 if (!$user->hasRight('societe', 'client', 'voir')) {
1627 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1628 }
1629 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1630 if (!empty($user->socid)) {
1631 $sql .= " AND s.rowid = " . ((int) $user->socid);
1632 }
1633 if ($filter) {
1634 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1635 // if not, by testSqlAndScriptInject() only.
1636 $sql .= " AND (" . $filter . ")";
1637 }
1638 if (!$user->hasRight('societe', 'client', 'voir')) {
1639 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1640 }
1641 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1642 $sql .= " AND s.status <> 0";
1643 }
1644 if (!empty($excludeids)) {
1645 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1646 }
1647 // Add where from hooks
1648 $parameters = array();
1649 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1650 $sql .= $hookmanager->resPrint;
1651 // Add criteria
1652 if ($filterkey && $filterkey != '') {
1653 $sql .= " AND (";
1654 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1655 // For natural search
1656 $search_crit = explode(' ', $filterkey);
1657 $i = 0;
1658 if (count($search_crit) > 1) {
1659 $sql .= "(";
1660 }
1661 foreach ($search_crit as $crit) {
1662 if ($i > 0) {
1663 $sql .= " AND ";
1664 }
1665 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1666 $i++;
1667 }
1668 if (count($search_crit) > 1) {
1669 $sql .= ")";
1670 }
1671 if (isModEnabled('barcode')) {
1672 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1673 }
1674 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1675 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1676 $sql .= ")";
1677 }
1678 $sql .= $this->db->order("nom", "ASC");
1679 $sql .= $this->db->plimit($limit, 0);
1680
1681 // Build output string
1682 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1683 $resql = $this->db->query($sql);
1684 if ($resql) {
1685 // Construct $out and $outarray
1686 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '"' . ($multiple ? ' multiple' : '') . '>' . "\n";
1687
1688 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1689 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1690 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1691 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1692 if ($showempty && !is_numeric($showempty)) {
1693 $textifempty = $langs->trans($showempty);
1694 } else {
1695 $textifempty .= $langs->trans("All");
1696 }
1697 }
1698 if ($showempty) {
1699 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1700 }
1701
1702 $companytemp = new Societe($this->db);
1703
1704 $num = $this->db->num_rows($resql);
1705 $i = 0;
1706 if ($num) {
1707 while ($i < $num) {
1708 $obj = $this->db->fetch_object($resql);
1709 $label = '';
1710 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1711 if (($obj->client) && (!empty($obj->code_client))) {
1712 $label = $obj->code_client . ' - ';
1713 }
1714 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1715 $label .= $obj->code_fournisseur . ' - ';
1716 }
1717 $label .= ' ' . $obj->name;
1718 } else {
1719 $label = $obj->name;
1720 }
1721
1722 if (!empty($obj->name_alias)) {
1723 $label .= ' (' . $obj->name_alias . ')';
1724 }
1725
1726 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1727 $label .= ' - '.$obj->tva_intra;
1728 }
1729
1730 $labelhtml = $label;
1731
1732 if ($showtype) {
1733 $companytemp->id = $obj->rowid;
1734 $companytemp->client = $obj->client;
1735 $companytemp->fournisseur = $obj->fournisseur;
1736 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1737 if ($tmptype) {
1738 $labelhtml .= ' ' . $tmptype;
1739 }
1740
1741 if ($obj->client || $obj->fournisseur) {
1742 $label .= ' (';
1743 }
1744 if ($obj->client == 1 || $obj->client == 3) {
1745 $label .= $langs->trans("Customer");
1746 }
1747 if ($obj->client == 2 || $obj->client == 3) {
1748 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1749 }
1750 if ($obj->fournisseur) {
1751 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1752 }
1753 if ($obj->client || $obj->fournisseur) {
1754 $label .= ')';
1755 }
1756 }
1757
1758 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1759 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1760 if (!empty($obj->country_code)) {
1761 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1762 }
1763 $label .= $s;
1764 $labelhtml .= $s;
1765 }
1766
1767 if (empty($outputmode)) {
1768 if (in_array($obj->rowid, $selected)) {
1769 $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>';
1770 } else {
1771 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1772 }
1773 } else {
1774 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1775 }
1776
1777 $i++;
1778 if (($i % 10) == 0) {
1779 $out .= "\n";
1780 }
1781 }
1782 }
1783 $out .= '</select>' . "\n";
1784 if (!$forcecombo) {
1785 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1786 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1787 }
1788 } else {
1789 dol_print_error($this->db);
1790 }
1791
1792 $this->result = array('nbofthirdparties' => $num);
1793
1794 if ($outputmode) {
1795 return $outarray;
1796 }
1797 return $out;
1798 }
1799
1800
1826 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 = '')
1827 {
1828 global $conf, $user, $langs, $hookmanager, $action;
1829
1830 $langs->load('companies');
1831
1832 if (empty($htmlid)) {
1833 $htmlid = $htmlname;
1834 }
1835 $num = 0;
1836 $out = '';
1837 $outarray = array();
1838
1839 if ($selected === '') {
1840 $selected = array();
1841 } elseif (!is_array($selected)) {
1842 $selected = array((int) $selected);
1843 }
1844
1845 // Clean $filter that may contains sql conditions so sql code
1846 if (function_exists('testSqlAndScriptInject')) {
1847 if (testSqlAndScriptInject($filter, 3) > 0) {
1848 $filter = '';
1849 return 'SQLInjectionTryDetected';
1850 }
1851 }
1852
1853 if ($filter != '') { // If a filter was provided
1854 if (preg_match('/[\‍(\‍)]/', $filter)) {
1855 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1856 $errormsg = '';
1857 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1858
1859 // Redo clean $filter that may contains sql conditions so sql code
1860 if (function_exists('testSqlAndScriptInject')) {
1861 if (testSqlAndScriptInject($filter, 3) > 0) {
1862 $filter = '';
1863 return 'SQLInjectionTryDetected';
1864 }
1865 }
1866 } else {
1867 // If not, we do nothing. We already know that there is no parenthesis
1868 // TODO Disallow this case in a future by returning an error here.
1869 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1870 }
1871 }
1872
1873 if (!is_object($hookmanager)) {
1874 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1875 $hookmanager = new HookManager($this->db);
1876 }
1877
1878 // We search third parties
1879 $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";
1880 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1881 $sql .= ", s.nom as company, s.town AS company_town";
1882 }
1883 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1884 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1885 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON s.rowid = sp.fk_soc";
1886 }
1887 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1888 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1889 if ($socid > 0 || $socid == -1) {
1890 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1891 }
1892 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1893 $sql .= " AND sp.statut <> 0";
1894 }
1895 // filter user access
1896 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
1897 $sql .= " AND EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = sp.fk_soc AND sc.fk_user = ".(int) $user->id .")";
1898 }
1899 if ($user->socid > 0) {
1900 $sql .= " AND sp.fk_soc = ".((int) $user->socid);
1901 }
1902 if ($filter) {
1903 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1904 // if not, by testSqlAndScriptInject() only.
1905 $sql .= " AND (" . $filter . ")";
1906 }
1907 // Add where from hooks
1908 $parameters = array();
1909 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1910 $sql .= $hookmanager->resPrint;
1911 $sql .= " ORDER BY sp.lastname ASC";
1912
1913 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1914 $resql = $this->db->query($sql);
1915 if ($resql) {
1916 $num = $this->db->num_rows($resql);
1917
1918 if ($htmlname != 'none' && !$options_only) {
1919 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1920 }
1921
1922 if ($showempty && !is_numeric($showempty)) {
1923 $textforempty = $showempty;
1924 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1925 } else {
1926 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1927 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1928 }
1929 if ($showempty == 2) {
1930 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1931 }
1932 }
1933
1934 $i = 0;
1935 if ($num) {
1936 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1937 $contactstatic = new Contact($this->db);
1938
1939 while ($i < $num) {
1940 $obj = $this->db->fetch_object($resql);
1941
1942 // Set email (or phones) and town extended infos
1943 $extendedInfos = '';
1944 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1945 $extendedInfos = array();
1946 $email = trim($obj->email);
1947 if (!empty($email)) {
1948 $extendedInfos[] = $email;
1949 } else {
1950 $phone = trim($obj->phone);
1951 $phone_perso = trim($obj->phone_perso);
1952 $phone_mobile = trim($obj->phone_mobile);
1953 if (!empty($phone)) {
1954 $extendedInfos[] = $phone;
1955 }
1956 if (!empty($phone_perso)) {
1957 $extendedInfos[] = $phone_perso;
1958 }
1959 if (!empty($phone_mobile)) {
1960 $extendedInfos[] = $phone_mobile;
1961 }
1962 }
1963 $contact_town = trim($obj->contact_town);
1964 $company_town = trim($obj->company_town);
1965 if (!empty($contact_town)) {
1966 $extendedInfos[] = $contact_town;
1967 } elseif (!empty($company_town)) {
1968 $extendedInfos[] = $company_town;
1969 }
1970 $extendedInfos = implode(' - ', $extendedInfos);
1971 if (!empty($extendedInfos)) {
1972 $extendedInfos = ' - ' . $extendedInfos;
1973 }
1974 }
1975
1976 $contactstatic->id = $obj->rowid;
1977 $contactstatic->lastname = $obj->lastname;
1978 $contactstatic->firstname = $obj->firstname;
1979 if ($obj->statut == 1) {
1980 $tmplabel = '';
1981 if ($htmlname != 'none') {
1982 $disabled = 0;
1983 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1984 $disabled = 1;
1985 }
1986 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1987 $disabled = 1;
1988 }
1989 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1990 $out .= '<option value="' . $obj->rowid . '"';
1991 if ($disabled) {
1992 $out .= ' disabled';
1993 }
1994 $out .= ' selected>';
1995
1996 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1997 if ($showfunction && $obj->poste) {
1998 $tmplabel .= ' (' . $obj->poste . ')';
1999 }
2000 if (($showsoc > 0) && $obj->company) {
2001 $tmplabel .= ' - (' . $obj->company . ')';
2002 }
2003
2004 $out .= $tmplabel;
2005 $out .= '</option>';
2006 } else {
2007 $out .= '<option value="' . $obj->rowid . '"';
2008 if ($disabled) {
2009 $out .= ' disabled';
2010 }
2011 $out .= '>';
2012
2013 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
2014 if ($showfunction && $obj->poste) {
2015 $tmplabel .= ' (' . $obj->poste . ')';
2016 }
2017 if (($showsoc > 0) && $obj->company) {
2018 $tmplabel .= ' - (' . $obj->company . ')';
2019 }
2020
2021 $out .= $tmplabel;
2022 $out .= '</option>';
2023 }
2024 } else {
2025 if (in_array($obj->rowid, $selected)) {
2026 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
2027 if ($showfunction && $obj->poste) {
2028 $tmplabel .= ' (' . $obj->poste . ')';
2029 }
2030 if (($showsoc > 0) && $obj->company) {
2031 $tmplabel .= ' - (' . $obj->company . ')';
2032 }
2033
2034 $out .= $tmplabel;
2035 }
2036 }
2037
2038 if ($tmplabel != '') {
2039 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
2040 }
2041 }
2042 $i++;
2043 }
2044 } else {
2045 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
2046 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
2047 $out .= $labeltoshow;
2048 $out .= '</option>';
2049 }
2050
2051 $parameters = array(
2052 'socid' => $socid,
2053 'htmlname' => $htmlname,
2054 'resql' => $resql,
2055 'out' => &$out,
2056 'showfunction' => $showfunction,
2057 'showsoc' => $showsoc,
2058 );
2059
2060 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2061
2062 if ($htmlname != 'none' && !$options_only) {
2063 $out .= '</select>';
2064 }
2065
2066 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
2067 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2068 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
2069 }
2070
2071 $this->num = $num;
2072
2073 if ($options_only === 2) {
2074 // Return array of options
2075 return $outarray;
2076 } else {
2077 return $out;
2078 }
2079 } else {
2080 dol_print_error($this->db);
2081 return -1;
2082 }
2083 }
2084
2085
2086 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2087
2098 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2099 {
2100 // phpcs:enable
2101 global $langs, $conf;
2102
2103 // On recherche les remises
2104 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2105 $sql .= " re.description, re.fk_facture_source";
2106 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2107 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2108 $sql .= " AND re.entity = " . $conf->entity;
2109 if ($filter) {
2110 $sql .= " AND " . $filter;
2111 }
2112 $sql .= " ORDER BY re.description ASC";
2113
2114 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2115 $resql = $this->db->query($sql);
2116 if ($resql) {
2117 print '<select id="select_' . $htmlname . '" class="flat maxwidth200onsmartphone" name="' . $htmlname . '">';
2118 $num = $this->db->num_rows($resql);
2119
2120 $qualifiedlines = $num;
2121
2122 $i = 0;
2123 if ($num) {
2124 print '<option value="0">&nbsp;</option>';
2125 while ($i < $num) {
2126 $obj = $this->db->fetch_object($resql);
2127 $desc = dol_trunc($obj->description, 40);
2128 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2129 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2130 }
2131 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2132 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2133 }
2134 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2135 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2136 }
2137 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2138 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2139 }
2140
2141 $selectstring = '';
2142 if ($selected > 0 && $selected == $obj->rowid) {
2143 $selectstring = ' selected';
2144 }
2145
2146 $disabled = '';
2147 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2148 $qualifiedlines--;
2149 $disabled = ' disabled';
2150 }
2151
2152 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2153 $tmpfac = new Facture($this->db);
2154 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2155 $desc = $desc . ' - ' . $tmpfac->ref;
2156 }
2157 }
2158
2159 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2160 $i++;
2161 }
2162 }
2163 print '</select>';
2164 print ajax_combobox('select_' . $htmlname);
2165
2166 return $qualifiedlines;
2167 } else {
2168 dol_print_error($this->db);
2169 return -1;
2170 }
2171 }
2172
2173
2174 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2175
2191 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2192 {
2193 // phpcs:enable
2194 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2195 }
2196
2197 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2198
2223 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '', $maxlength = 0, $showstatus = 0, $morefilter = '', $showalso = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2224 {
2225 // phpcs:enable
2226 global $conf, $user, $langs, $hookmanager;
2227 global $action;
2228
2229 // If no preselected user defined, we take current user
2230 if ((is_numeric($selected) && ($selected < -4 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2231 $selected = $user->id;
2232 }
2233
2234 if ($selected === '') {
2235 $selected = array();
2236 } elseif (!is_array($selected)) {
2237 $selected = array($selected);
2238 }
2239
2240 // Exclude some users in $excludeUsers string
2241 $excludeUsers = null;
2242 if (is_array($exclude)) {
2243 $excludeUsers = implode(",", $exclude);
2244 }
2245
2246 // Include some users in $includeUsers string
2247 $includeUsers = null;
2248 $includeUsersArray = array();
2249 if (is_array($include)) {
2250 $includeUsersArray = $include;
2251 } elseif ($include == 'hierarchy') {
2252 // Build list includeUsersArray to have only hierarchy
2253 $includeUsersArray = $user->getAllChildIds(0);
2254 } elseif ($include == 'hierarchyme') {
2255 // Build list includeUsersArray to have only hierarchy and current user
2256 $includeUsersArray = $user->getAllChildIds(1);
2257 }
2258 // Get list of allowed users
2259 /* We do not limit list of users. Because we should limit this only for combo list into HR features where we may be allowed to
2260 * see all other users and element in other. For example in agenda, we can have permission to read all event of otherusers.
2261 * So we disable this.
2262 if (!$user->hasRight('user', 'user', 'lire')) {
2263 if (empty($includeUsersArray)) {
2264 $includeUsers = implode(",", $user->getAllChildIds(1));
2265 } else {
2266 $includeUsers = implode(",", array_intersect($includeUsersArray, $user->getAllChildIds(1)));
2267 }
2268 } else {
2269 $includeUsers = implode(",", $includeUsersArray);
2270 } */
2271 $includeUsers = implode(",", $includeUsersArray);
2272
2273 $num = 0;
2274
2275 $out = '';
2276 $outarray = array();
2277 $outarray2 = array();
2278
2279 // Do we want to show the label of entity into the combo list ?
2280 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity) && !preg_match('/^search_/', $htmlname);
2281 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2282
2283 // Forge request to select users
2284 $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";
2285 if ($showlabelofentity) {
2286 $sql .= ", e.label";
2287 }
2288 $sql .= " FROM " . $this->db->prefix() . "user as u";
2289 if ($showlabelofentity) {
2290 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2291 }
2292 // Condition here should be the same than into societe->getSalesRepresentatives().
2293 if ($userissuperadminentityone && $force_entity !== 'default') {
2294 if (!empty($force_entity)) {
2295 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2296 } else {
2297 $sql .= " WHERE u.entity IS NOT NULL";
2298 }
2299 } else {
2300 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2301 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2302 } else {
2303 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2304 }
2305 }
2306
2307 if (!empty($user->socid)) {
2308 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2309 }
2310 if (is_array($exclude) && $excludeUsers) {
2311 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2312 }
2313 if ($includeUsers) {
2314 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2315 }
2316 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2317 $sql .= " AND u.statut <> 0";
2318 }
2319 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2320 $sql .= " AND u.employee <> 0";
2321 }
2322 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2323 $sql .= " AND u.fk_soc IS NULL";
2324 }
2325 if (!empty($morefilter)) {
2326 $errormessage = '';
2327 $sql .= forgeSQLFromUniversalSearchCriteria($morefilter, $errormessage);
2328 if ($errormessage) {
2329 $this->errors[] = $errormessage;
2330 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2331 if ($outputmode == 0) {
2332 return 'Error bad param $morefilter';
2333 } else {
2334 return array();
2335 }
2336 }
2337 }
2338
2339 //Add hook to filter on user (for example on usergroup define in custom modules)
2340 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2341 if (!empty($reshook)) {
2342 $sql .= $hookmanager->resPrint;
2343 }
2344
2345 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2346 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2347 } else {
2348 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2349 }
2350
2351 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2352
2353 $resql = $this->db->query($sql);
2354 if ($resql) {
2355 $num = $this->db->num_rows($resql);
2356 $i = 0;
2357 if ($num) {
2358 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2359 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2360 if ($show_empty && !$multiple) {
2361 $textforempty = ' ';
2362 if (!empty($conf->use_javascript_ajax)) {
2363 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2364 }
2365 if (!is_numeric($show_empty)) {
2366 $textforempty = $show_empty;
2367 }
2368 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2369
2370 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2371 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2372 'id' => ($show_empty < 0 ? $show_empty : -1),
2373 'label' => $textforempty,
2374 'labelhtml' => $textforempty,
2375 'color' => '',
2376 'picto' => ''
2377 );
2378 }
2379 if ($showalso == 2 || $showalso == 3) {
2380 $out .= '<option value="-3"' . ((in_array(-3, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("MyTeam") . ' --</option>' . "\n";
2381
2382 $hasAtLeastOneSubordinate = (count($user->getAllChildIds(1)) > 1);
2383 if ($hasAtLeastOneSubordinate) {
2384 //$sql = "SELECT rowid FROM".MAIN_DB_PREFIX."user "
2385 $outarray[-3] = '-- ' . $langs->trans("MyTeam") . ' --';
2386 $outarray2[-3] = array(
2387 'id' => -3,
2388 'label' => '-- ' . $langs->trans("MyTeam") . ' --',
2389 'labelhtml' => '-- ' . $langs->trans("MyTeam") . ' --',
2390 'color' => '',
2391 'picto' => ''
2392 );
2393 }
2394 }
2395 if ($showalso == 1 || $showalso == 3) {
2396 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2397
2398 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2399 $outarray2[-2] = array(
2400 'id' => -2,
2401 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2402 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2403 'color' => '',
2404 'picto' => ''
2405 );
2406 }
2407 if ($showalso == 4) {
2408 $out .= '<option value="-4"' . ((in_array(-4, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("AllProjectContacts") . ' --</option>' . "\n";
2409
2410 $outarray[-4] = '-- ' . $langs->trans("AllProjectContacts") . ' --';
2411 $outarray2[-4] = array(
2412 'id' => -4,
2413 'label' => '-- ' . $langs->trans("AllProjectContacts") . ' --',
2414 'labelhtml' => '-- ' . $langs->trans("AllProjectContacts") . ' --',
2415 'color' => '',
2416 'picto' => ''
2417 );
2418 }
2419
2420 $userstatic = new User($this->db);
2421
2422 while ($i < $num) {
2423 $obj = $this->db->fetch_object($resql);
2424
2425 $userstatic->id = $obj->rowid;
2426 $userstatic->lastname = $obj->lastname;
2427 $userstatic->firstname = $obj->firstname;
2428 $userstatic->photo = $obj->photo;
2429 $userstatic->status = $obj->status;
2430 $userstatic->entity = $obj->entity;
2431 $userstatic->admin = $obj->admin;
2432 $userstatic->gender = $obj->gender;
2433
2434 $disableline = '';
2435 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2436 $disableline = ($enableonlytext ? $enableonlytext : '1');
2437 }
2438
2439 $labeltoshow = '';
2440 $labeltoshowhtml = '';
2441
2442 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2443 $fullNameMode = 0;
2444 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2445 $fullNameMode = 1; //Firstname+lastname
2446 }
2447 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2448 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2449 if (empty($obj->firstname) && empty($obj->lastname)) {
2450 $labeltoshow .= $obj->login;
2451 $labeltoshowhtml .= $obj->login;
2452 }
2453
2454 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2455 $moreinfo = '';
2456 $moreinfohtml = '';
2457 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2458 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2459 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2460 $moreinfo .= $obj->login;
2461 $moreinfohtml .= $obj->login;
2462 }
2463 if ($showstatus >= 0) {
2464 if ($obj->status == 1 && $showstatus == 1) {
2465 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2466 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2467 }
2468 if ($obj->status == 0 && $showstatus == 1) {
2469 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2470 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2471 }
2472 }
2473 if ($showlabelofentity) {
2474 if (empty($obj->entity)) {
2475 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2476 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2477 } else {
2478 if ($obj->entity != $conf->entity) {
2479 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2480 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2481 }
2482 }
2483 }
2484 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2485 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2486 if (!empty($disableline) && $disableline != '1') {
2487 // Add text from $enableonlytext parameter
2488 $moreinfo .= ' - ' . $disableline;
2489 $moreinfohtml .= ' - ' . $disableline;
2490 }
2491 $labeltoshow .= $moreinfo;
2492 $labeltoshowhtml .= $moreinfohtml;
2493
2494 $out .= '<option value="' . $obj->rowid . '"';
2495 if (!empty($disableline)) {
2496 $out .= ' disabled';
2497 }
2498 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2499 $out .= ' selected';
2500 }
2501 $out .= ' data-html="';
2502
2503 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2504 if ($showstatus >= 0 && $obj->status == 0) {
2505 $outhtml .= '<strike class="opacitymediumxxx">';
2506 }
2507 $outhtml .= $labeltoshowhtml;
2508 if ($showstatus >= 0 && $obj->status == 0) {
2509 $outhtml .= '</strike>';
2510 }
2511 $labeltoshowhtml = $outhtml;
2512
2513 $out .= dol_escape_htmltag($outhtml);
2514 $out .= '">';
2515 $out .= $labeltoshow;
2516 $out .= '</option>';
2517
2518 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2519 $outarray2[$userstatic->id] = array(
2520 'id' => $userstatic->id,
2521 'label' => $labeltoshow,
2522 'labelhtml' => $labeltoshowhtml,
2523 'color' => '',
2524 'picto' => ''
2525 );
2526
2527 $i++;
2528 }
2529 } else {
2530 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2531 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2532 }
2533 $out .= '</select>';
2534
2535 if ($num && !$forcecombo) {
2536 // Enhance with select2
2537 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2538 $out .= ajax_combobox($htmlname);
2539 }
2540 } else {
2541 dol_print_error($this->db);
2542 }
2543
2544 $this->num = $num;
2545
2546 if ($outputmode == 2) {
2547 return $outarray2;
2548 } elseif ($outputmode) {
2549 return $outarray;
2550 }
2551
2552 return $out;
2553 }
2554
2555
2556 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2580 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)
2581 {
2582 // phpcs:enable
2583 global $langs, $user;
2584
2585 $userstatic = new User($this->db);
2586 $out = '';
2587
2588 if (!empty($_SESSION['assignedtouser'])) {
2589 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2590 if (!is_array($assignedtouser)) {
2591 $assignedtouser = array();
2592 }
2593 } else {
2594 $assignedtouser = array();
2595 }
2596 $nbassignetouser = count($assignedtouser);
2597
2598 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2599 if ($nbassignetouser) {
2600 $out .= '<ul class="attendees">';
2601 }
2602 $i = 0;
2603 $ownerid = 0;
2604 foreach ($assignedtouser as $key => $value) {
2605 if ($value['id'] == $ownerid) {
2606 continue;
2607 }
2608
2609 $out .= '<li>';
2610
2611 $userstatic->fetch($value['id']);
2612 $out .= $userstatic->getNomUrl(-4);
2613
2614 if ($i == 0) {
2615 $ownerid = $value['id'];
2616 $out .= ' (' . $langs->trans("Owner") . ')';
2617 }
2618 // Add picto to delete owner/assignee
2619 if ($nbassignetouser > 1 && $action != 'view') {
2620 $canremoveassignee = 1;
2621 if ($i == 0) {
2622 // We are on the owner of the event
2623 if (!$canremoveowner) {
2624 $canremoveassignee = 0;
2625 }
2626 if (!$user->hasRight('agenda', 'allactions', 'create')) {
2627 $canremoveassignee = 0; // Can't remove the owner
2628 }
2629 } else {
2630 // We are not on the owner of the event but on a secondary assignee
2631 }
2632 if ($canremoveassignee) {
2633 // If user has all permission, he should be ableto remove a assignee.
2634 // If user has not all permission, he can onlyremove assignee of other (he can't remove itself)
2635 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $userstatic->id . '" class="noborderfocus removedassigned reposition" id="removedassigned_' . $userstatic->id . '" name="removedassigned_' . $userstatic->id . '">';
2636 }
2637 }
2638 // Show my availability
2639 if ($showproperties) {
2640 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2641 $out .= '<div class="myavailability inline-block">';
2642 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;';
2643 //$out .= '<span class="opacitymedium">' . $langs->trans("Availability") . ':</span>';
2644 $out .= '</span>';
2645 $out .= ' <input title="'.$langs->trans("Availability").'" id="transparency" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofuserid[$ownerid]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2646 $out .= '</div>';
2647 }
2648 }
2649 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2650 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2651
2652 $out .= '</li>';
2653 $i++;
2654 }
2655 if ($nbassignetouser) {
2656 $out .= '</ul>';
2657 }
2658
2659 // Method with no ajax
2660 if ($action != 'view') {
2661 // Section to add another user
2662 $out .= '<div class="divadduser'.$htmlname.'">';
2663 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2664 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2665 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2666 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2667 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2668 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2669 $out .= '});';
2670 $out .= '})</script>';
2671 $out .= img_picto('', 'user', 'class="pictofixedwidth"');
2672 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter, 0, '', 'minwidth200');
2673 $out .= ' <button type="submit" disabled class="button valignmiddle smallpaddingimp reposition butActionAdd" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2674 $out .= $langs->trans("Add").'</button>';
2675 $out .= '</div>';
2676 //$out .= '<br>';
2677 }
2678
2679 return $out;
2680 }
2681
2682 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2702 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())
2703 {
2704 // phpcs:enable
2705 global $langs;
2706
2707 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2708 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2709 $formresources = new FormResource($this->db);
2710 $resourcestatic = new Dolresource($this->db);
2711
2712 $out = '';
2713 if (!empty($_SESSION['assignedtoresource'])) {
2714 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2715 if (!is_array($assignedtoresource)) {
2716 $assignedtoresource = array();
2717 }
2718 } else {
2719 $assignedtoresource = array();
2720 }
2721 $nbassignetoresource = count($assignedtoresource);
2722
2723 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2724 if ($nbassignetoresource) {
2725 $out .= '<ul class="attendees">';
2726 }
2727 $i = 0;
2728
2729 foreach ($assignedtoresource as $key => $value) {
2730 $out .= '<li>';
2731 $resourcestatic->fetch($value['id']);
2732 $out .= $resourcestatic->getNomUrl(-1);
2733 if ($nbassignetoresource >= 1 && $action != 'view') {
2734 $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 . '">';
2735 }
2736 // Show my availability
2737 if ($showproperties) {
2738 if (is_array($listofresourceid) && count($listofresourceid)) {
2739 $out .= '<div class="myavailability inline-block">';
2740 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;';
2741 //$out .= '<span class="opacitymedium">' . $langs->trans("Availability") . ': </span>';
2742 $out .= '</span>';
2743 $out .= ' <input title="'.$langs->trans("Availability").'" id="transparencyresource'.$value['id'].'" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparencyresource'.$value['id'].'">' . $langs->trans("Busy") . '</label>';
2744 $out .= '</div>';
2745 }
2746 }
2747 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2748 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2749
2750 $out .= '</li>';
2751 $i++;
2752 }
2753 if ($nbassignetoresource) {
2754 $out .= '</ul>';
2755 }
2756
2757 // Method with no ajax
2758 if ($action != 'view') {
2759 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2760 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2761 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2762 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2763 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2764 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2765 $out .= '});';
2766 $out .= '})</script>';
2767
2768 $events = array();
2769 if ($nbassignetoresource) {
2770 //$out .= img_picto('', 'add', 'class="pictofixedwidth"');
2771 } else {
2772 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2773 }
2774 $out .= $formresources->select_resource_list(0, $htmlname, '', 1, 1, 0, $events, '', 2, 0, 'minwidth200');
2775 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2776 $out .= ' <button type="submit" disabled class="button valignmiddle smallpaddingimp reposition butActionAdd" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2777 $out .= $langs->trans("Add");
2778 $out .= '</button>';
2779 $out .= '<br>';
2780 }
2781
2782 return $out;
2783 }
2784
2785 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2786
2816 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)
2817 {
2818 // phpcs:enable
2819 global $langs, $conf;
2820
2821 $out = '';
2822
2823 // check parameters
2824 $price_level = (!empty($price_level) ? $price_level : 0);
2825 if (is_null($ajaxoptions)) {
2826 $ajaxoptions = array();
2827 }
2828
2829 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2830 if (isModEnabled("product") && !isModEnabled('service')) {
2831 $filtertype = '0';
2832 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2833 $filtertype = '1';
2834 }
2835 }
2836
2837 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2838 $placeholder = (is_numeric($showempty) ? '' : 'placeholder="'.dolPrintHTML($showempty).'"');
2839
2840 if ($selected && empty($selected_input_value)) {
2841 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2842 $producttmpselect = new Product($this->db);
2843 $producttmpselect->fetch($selected);
2844 $selected_input_value = $producttmpselect->ref;
2845 unset($producttmpselect);
2846 }
2847 // handle case where product or service module is disabled + no filter specified
2848 if ($filtertype == '') {
2849 if (!isModEnabled('product')) { // when product module is disabled, show services only
2850 $filtertype = 1;
2851 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2852 $filtertype = 0;
2853 }
2854 }
2855 // mode=1 means customers products
2856 $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;
2857 if ((int) $warehouseId > 0) {
2858 $urloption .= '&warehouseid=' . (int) $warehouseId;
2859 }
2860
2861 if (isModEnabled('variants') && is_array($selected_combinations)) {
2862 // Code to automatically insert with javascript the select of attributes under the select of product
2863 // when a parent of variant has been selected.
2864 // Note: Samecode than for product input using select
2865 $htmltag = 'input';
2866 $out .= '
2867 <!-- script to auto show attributes select tags if a variant was selected -->
2868 <script nonce="' . getNonce() . '">
2869 // auto show attributes fields
2870 selected = ' . json_encode($selected_combinations) . ';
2871 combvalues = {};
2872
2873 jQuery(document).ready(function () {
2874
2875 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2876 if (jQuery(this).val() == \'free\') {
2877 jQuery(\'div#attributes_box\').empty();
2878 }
2879 });
2880
2881 jQuery("'.$htmltag.'#' . $htmlname . '").change(function () {
2882
2883 if (!jQuery(this).val()) {
2884 jQuery(\'div#attributes_box\').empty();
2885 return;
2886 }
2887
2888 console.log("A change has started. We get variants fields to inject html select");
2889
2890 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2891 id: jQuery(this).val()
2892 }, function (data) {
2893 jQuery(\'div#attributes_box\').empty();
2894
2895 jQuery.each(data, function (key, val) {
2896
2897 combvalues[val.id] = val.values;
2898
2899 var span = jQuery(document.createElement(\'div\')).css({
2900 \'display\': \'table-row\'
2901 });
2902
2903 span.append(
2904 jQuery(document.createElement(\'div\')).text(val.label).css({
2905 \'font-weight\': \'bold\',
2906 \'display\': \'table-cell\'
2907 })
2908 );
2909
2910 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2911 \'margin-left\': \'15px\',
2912 \'white-space\': \'pre\'
2913 }).append(
2914 jQuery(document.createElement(\'option\')).val(\'\')
2915 );
2916
2917 jQuery.each(combvalues[val.id], function (key, val) {
2918 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2919
2920 if (selected[val.fk_product_attribute] == val.id) {
2921 tag.attr(\'selected\', \'selected\');
2922 }
2923
2924 html.append(tag);
2925 });
2926
2927 span.append(html);
2928 jQuery(\'div#attributes_box\').append(span);
2929 });
2930 })
2931 });
2932
2933 ' . ($selected ? 'jQuery("'.$htmltag.'#' . $htmlname . '").change();' : '') . '
2934 });
2935 </script>
2936 ';
2937 }
2938
2939 if (empty($hidelabel)) {
2940 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2941 } elseif ($hidelabel > 1) {
2942 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2943 if ($hidelabel == 2) {
2944 $out .= img_picto($langs->trans("Search"), 'search');
2945 }
2946 }
2947
2948 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' spellcheck="false" />';
2949 if ($hidelabel == 3) {
2950 $out .= img_picto($langs->trans("Search"), 'search');
2951 }
2952
2953 $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);
2954 } else {
2955 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2956
2957 if (isModEnabled('variants') && is_array($selected_combinations)) {
2958 // Code to automatically insert with javascript the select of attributes under the select of product
2959 // when a parent of variant has been selected.
2960 // Note: Samecode than for product input using Ajax
2961 $htmltag = 'select';
2962 $out .= '
2963 <!-- script to auto show attributes select tags if a variant was selected -->
2964 <script nonce="' . getNonce() . '">
2965 // auto show attributes fields
2966 selected = ' . json_encode($selected_combinations) . ';
2967 combvalues = {};
2968
2969 jQuery(document).ready(function () {
2970
2971 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2972 if (jQuery(this).val() == \'free\') {
2973 jQuery(\'div#attributes_box\').empty();
2974 }
2975 });
2976
2977 jQuery("'.$htmltag.'#' . $htmlname . '").change(function () {
2978
2979 if (!jQuery(this).val()) {
2980 jQuery(\'div#attributes_box\').empty();
2981 return;
2982 }
2983
2984 console.log("A change has started. We get variants fields to inject html select");
2985
2986 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2987 id: jQuery(this).val()
2988 }, function (data) {
2989 jQuery(\'div#attributes_box\').empty();
2990
2991 jQuery.each(data, function (key, val) {
2992
2993 combvalues[val.id] = val.values;
2994
2995 var span = jQuery(document.createElement(\'div\')).css({
2996 \'display\': \'table-row\'
2997 });
2998
2999 span.append(
3000 jQuery(document.createElement(\'div\')).text(val.label).css({
3001 \'font-weight\': \'bold\',
3002 \'display\': \'table-cell\'
3003 })
3004 );
3005
3006 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
3007 \'margin-left\': \'15px\',
3008 \'white-space\': \'pre\'
3009 }).append(
3010 jQuery(document.createElement(\'option\')).val(\'\')
3011 );
3012
3013 jQuery.each(combvalues[val.id], function (key, val) {
3014 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
3015
3016 if (selected[val.fk_product_attribute] == val.id) {
3017 tag.attr(\'selected\', \'selected\');
3018 }
3019
3020 html.append(tag);
3021 });
3022
3023 span.append(html);
3024 jQuery(\'div#attributes_box\').append(span);
3025 });
3026 })
3027 });
3028
3029 ' . ($selected ? 'jQuery("'.$htmltag.'#' . $htmlname . '").change();' : '') . '
3030 });
3031 </script>
3032 ';
3033 }
3034 }
3035
3036 if (empty($nooutput)) {
3037 print $out;
3038 } else {
3039 return $out;
3040 }
3041 }
3042
3043 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3044
3060 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
3061 {
3062 // phpcs:enable
3063
3064 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3065
3066 $error = 0;
3067 $out = '';
3068
3069 if (!$forcecombo) {
3070 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3071 $events = array();
3072 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("BOM_USE_SEARCH_TO_SELECT"));
3073 }
3074
3075 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3076
3077 $sql = 'SELECT b.rowid, b.ref, b.label as bomLabel, p.label as productLabel';
3078 $sql .= ' FROM ' . $this->db->prefix() . 'bom_bom as b';
3079 $sql .= ' INNER JOIN ' . $this->db->prefix() . 'product as p ON b.fk_product = p.rowid';
3080 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
3081 if (!empty($status)) {
3082 $sql .= ' AND status = ' . (int) $status;
3083 }
3084 if (!empty($type)) {
3085 $sql .= ' AND bomtype = ' . (int) $type;
3086 }
3087 if (!empty($TProducts)) {
3088 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
3089 }
3090 if (!empty($limit)) {
3091 $sql .= ' LIMIT ' . (int) $limit;
3092 }
3093 $resql = $this->db->query($sql);
3094 if ($resql) {
3095 if ($showempty) {
3096 $out .= '<option value="-1"';
3097 if (empty($selected)) {
3098 $out .= ' selected';
3099 }
3100 $out .= '>&nbsp;</option>';
3101 }
3102 while ($obj = $this->db->fetch_object($resql)) {
3103 $out .= '<option value="' . $obj->rowid . '"';
3104 if ($obj->rowid == $selected) {
3105 $out .= 'selected';
3106 }
3107 $out .= '>' . $obj->ref . ' - ' . $obj->productLabel . ' - ' . $obj->bomLabel . '</option>';
3108 }
3109 } else {
3110 $error++;
3111 dol_print_error($this->db);
3112 }
3113 $out .= '</select>';
3114 if (empty($nooutput)) {
3115 print $out;
3116 } else {
3117 return $out;
3118 }
3119 }
3120
3121 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3122
3149 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)
3150 {
3151 // phpcs:enable
3152 global $langs;
3153 global $hookmanager;
3154
3155 $out = '';
3156 $outarray = array();
3157
3158 // Units
3159 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3160 $langs->load('other');
3161 }
3162
3163 $warehouseStatusArray = array();
3164 if (!empty($warehouseStatus)) {
3165 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
3166 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
3167 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
3168 }
3169 if (preg_match('/warehouseopen/', $warehouseStatus)) {
3170 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
3171 }
3172 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
3173 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
3174 }
3175 }
3176
3177 $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";
3178 if (count($warehouseStatusArray)) {
3179 $selectFieldsGrouped = ", SUM(" . $this->db->ifsql("e.statut IS NULL", "0", "ps.reel") . ") as stock"; // e.statut is null if there is no record in a qualified stock
3180 } else {
3181 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", '0', "p.stock") . " AS stock";
3182 }
3183
3184 $sql = "SELECT ";
3185
3186 // Add select from hooks
3187 $parameters = array();
3188 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
3189 if (empty($reshook)) {
3190 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
3191 } else {
3192 $sql .= $hookmanager->resPrint;
3193 }
3194
3195 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3196 // Take randomly the first category of product to allow a sort on it. Bugged feature !
3197 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
3198 FROM " . $this->db->prefix() . "categorie_product
3199 WHERE " . $this->db->prefix() . "categorie_product.fk_product = p.rowid
3200 LIMIT 1
3201 ) AS categorie_product_id";
3202 }
3203
3204 // Price by customer
3205 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3206 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
3207 $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, pcp.discount_percent as custdiscount_percent';
3208 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref, custdiscount_percent";
3209 }
3210 // Units
3211 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3212 $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";
3213 $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';
3214 }
3215
3216 // Multilang : we add translation
3217 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3218 $sql .= ", pl.label as label_translated";
3219 $sql .= ", pl.description as description_translated";
3220 $selectFields .= ", label_translated";
3221 $selectFields .= ", description_translated";
3222 }
3223 // Price by quantity
3224 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3225 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
3226 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3227 $sql .= " AND price_level = " . ((int) $price_level);
3228 }
3229 $sql .= " ORDER BY date_price";
3230 $sql .= " DESC LIMIT 1) as price_rowid";
3231 $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
3232 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3233 $sql .= " AND price_level = " . ((int) $price_level);
3234 }
3235 $sql .= " ORDER BY date_price";
3236 $sql .= " DESC LIMIT 1) as price_by_qty";
3237 $selectFields .= ", price_rowid, price_by_qty";
3238 }
3239
3240 //$sqlfields = $sql; // $sql fields to remove for count total
3241
3242 $sql .= " FROM ".$this->db->prefix()."product as p";
3243
3244 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
3245 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
3246 }
3247
3248 // Add from (left join) from hooks
3249 $parameters = array(
3250 'socid' => $socid,
3251 );
3252 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3253 $sql .= $hookmanager->resPrint;
3254
3255 if (count($warehouseStatusArray)) {
3256 // Return line if product is inside the selected stock. If not, e.* and p.* will be null so we will count 0.
3257 // Replace this with a AND EXISTS ? Not possible as we need the ps.reel field for the SUM or 0 if no link.
3258 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps ON ps.fk_product = p.rowid";
3259 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e ON ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3260 $sql .= ' AND e.statut IN (' . $this->db->sanitize($this->db->escape(implode(',', $warehouseStatusArray))) . ')';
3261 }
3262
3263 // Price by customer (Add field pcp for the older price for couple product/thirdparty.
3264 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3265 $now = dol_now();
3266 $sql .= " LEFT JOIN (";
3267 $sql .= " SELECT pcp1.*";
3268 $sql .= " FROM " . $this->db->prefix() . "product_customer_price AS pcp1";
3269 $sql .= " LEFT JOIN (";
3270 $sql .= " SELECT fk_soc, fk_product, MIN(date_begin) AS date_begin";
3271 $sql .= " FROM " . $this->db->prefix() . "product_customer_price";
3272 $sql .= " WHERE fk_soc = " . ((int) $socid);
3273 $sql .= " AND date_begin <= '" . $this->db->idate($now) . "'";
3274 $sql .= " AND (date_end IS NULL OR '" . $this->db->idate($now) . "' <= date_end)";
3275 $sql .= " GROUP BY fk_soc, fk_product";
3276 $sql .= " ) AS pcp2 ON pcp1.fk_soc = pcp2.fk_soc AND pcp1.fk_product = pcp2.fk_product AND pcp1.date_begin = pcp2.date_begin";
3277 $sql .= " WHERE pcp2.fk_soc IS NOT NULL";
3278 $sql .= " ) AS pcp ON pcp.fk_soc = " . ((int) $socid) . " AND pcp.fk_product = p.rowid";
3279 }
3280 // Units : we add unit properties with a link on the primary key of unit
3281 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3282 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units as u ON u.rowid = p.fk_unit";
3283 }
3284 // Multilang : we add translation fields with a link on unique key fk_product/lang.
3285 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3286 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid";
3287 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3288 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3289 $soc = new Societe($this->db);
3290 $result = $soc->fetch($socid);
3291 if ($result > 0 && !empty($soc->default_lang)) {
3292 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3293 } else {
3294 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3295 }
3296 } else {
3297 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3298 }
3299 }
3300
3301 // Add WHERE conditions
3302 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3303 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3304 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD_BUT_ALLOW_SEARCH_IN_EAN13')) {
3305 if (strlen($filterkey) != 13) {
3306 $sql .= " AND NOT EXISTS (SELECT pac.rowid FROM ".$this->db->prefix()."product_attribute_combination as pac WHERE pac.fk_product_child = p.rowid)";
3307 }
3308 } else {
3309 $sql .= " AND NOT EXISTS (SELECT pac.rowid FROM ".$this->db->prefix()."product_attribute_combination as pac WHERE pac.fk_product_child = p.rowid)";
3310 }
3311 }
3312 if ($finished == 0) {
3313 $sql .= " AND p.finished = " . ((int) $finished);
3314 } elseif ($finished == 1) {
3315 $sql .= " AND p.finished = ".((int) $finished);
3316 }
3317 if ($status >= 0) {
3318 $sql .= " AND p.tosell = ".((int) $status);
3319 }
3320 if ($status_purchase >= 0) {
3321 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3322 }
3323 // Filter by product type
3324 if (strval($filtertype) != '') {
3325 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3326 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3327 $sql .= " AND p.fk_product_type = 1";
3328 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3329 $sql .= " AND p.fk_product_type = 0";
3330 }
3331
3332 if ((int) $warehouseId > 0) {
3333 $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)";
3334 }
3335
3336 // Add where from hooks
3337 $parameters = array(
3338 'filterkey' => &$filterkey,
3339 'socid' => $socid,
3340 );
3341 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3342 $sql .= $hookmanager->resPrint;
3343 // Add criteria on ref/label
3344 if ($filterkey != '') {
3345 $sqlSupplierSearch = '';
3346
3347 $sql .= ' AND (';
3348 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3349 // For natural search
3350 $search_crit = explode(' ', $filterkey);
3351 $i = 0;
3352 if (count($search_crit) > 1) {
3353 $sql .= "(";
3354 }
3355 foreach ($search_crit as $crit) {
3356 if ($i > 0) {
3357 $sql .= " AND ";
3358 }
3359 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3360 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3361 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3362 }
3363 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3364 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3365 }
3366 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3367 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3368 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3369 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3370 }
3371 }
3372
3373 // include search in supplier ref
3374 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3375 $sqlSupplierSearch .= !empty($sqlSupplierSearch) ? ' AND ' : '';
3376 $sqlSupplierSearch .= " pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3377 }
3378 $sql .= ")";
3379 $i++;
3380 }
3381 if (count($search_crit) > 1) {
3382 $sql .= ")";
3383 }
3384 if (isModEnabled('barcode')) {
3385 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3386 }
3387
3388 // include search in supplier ref
3389 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3390 $sql .= " OR EXISTS (SELECT pfp.fk_product FROM " . $this->db->prefix() . "product_fournisseur_price as pfp WHERE p.rowid = pfp.fk_product";
3391 $sql .= " AND (";
3392 $sql .= $sqlSupplierSearch;
3393 $sql .= "))";
3394 }
3395
3396 $sql .= ')';
3397 }
3398 if (count($warehouseStatusArray)) {
3399 $sql .= " GROUP BY " . $selectFields; // To have the SUM on ps.reel working in the select.
3400 }
3401
3402 // Sort by category
3403 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3404 $sql .= " ORDER BY categorie_product_id ".(getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1 ? "ASC" : "DESC");
3405 } else {
3406 $sql .= $this->db->order("p.ref");
3407 }
3408
3409 $limit = getDolGlobalInt('SEARCH_LIMIT_AJAX') ?: $limit;
3410 $sql .= $this->db->plimit($limit, 0);
3411
3412 /* The fast and low memory method to get and count full list converts the sql into a sql count */
3413 /*
3414 $nbtotalofrecords = 0;
3415 $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql);
3416 $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount);
3417
3418 $resql = $this->db->query($sqlforcount);
3419 if ($resql) {
3420 $objforcount = $this->db->fetch_object($resql);
3421 $nbtotalofrecords = $objforcount->nbtotalofrecords;
3422 } else {
3423 dol_print_error($this->db);
3424 }
3425 */
3426
3427 // Build output string
3428 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3429
3430 // If we have no $limit parameter, this request may hang dur to high number of lines returned.
3431 // This should not happen because this method should not be called directly, iIt is called by select_produit() that always add a $limit parameter.
3432 $result = $this->db->query($sql);
3433
3434 if ($result) {
3435 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3436 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3437 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3438
3439 $num = $this->db->num_rows($result);
3440
3441 $events = array();
3442
3443 if (!$forcecombo) {
3444 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3445 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3446 }
3447
3448 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3449
3450 $textifempty = '';
3451 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3452 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3453 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3454 if ($showempty && !is_numeric($showempty)) {
3455 $textifempty = $langs->trans($showempty);
3456 } else {
3457 $textifempty .= $langs->trans("All");
3458 }
3459 } else {
3460 if ($showempty && !is_numeric($showempty)) {
3461 $textifempty = $langs->trans($showempty);
3462 }
3463 }
3464 if ($showempty) {
3465 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3466 }
3467
3468 $i = 0;
3469 while ($num && $i < $num) {
3470 $opt = '';
3471 $optJson = array();
3472 $objp = $this->db->fetch_object($result);
3473
3474 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
3475 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3476 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3477 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3478 $sql .= " ORDER BY quantity ASC";
3479
3480 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3481 $result2 = $this->db->query($sql);
3482 if ($result2) {
3483 $nb_prices = $this->db->num_rows($result2);
3484 $j = 0;
3485 while ($nb_prices && $j < $nb_prices) {
3486 $objp2 = $this->db->fetch_object($result2);
3487
3488 $objp->price_by_qty_rowid = $objp2->rowid;
3489 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3490 $objp->price_by_qty_quantity = $objp2->quantity;
3491 $objp->price_by_qty_unitprice = $objp2->unitprice;
3492 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3493 // For backward compatibility
3494 $objp->quantity = $objp2->quantity;
3495 $objp->price = $objp2->price;
3496 $objp->unitprice = $objp2->unitprice;
3497 $objp->remise_percent = $objp2->remise_percent;
3498
3499 //$objp->tva_tx is not overwritten by $objp2 value
3500 //$objp->default_vat_code is not overwritten by $objp2 value
3501
3502 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3503 '@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';
3504 $j++;
3505
3506 // Add new entry
3507 // "key" value of json key array is used by jQuery automatically as selected value
3508 // "label" value of json key array is used by jQuery automatically as text for combo box
3509 $out .= $opt;
3510 array_push($outarray, $optJson);
3511 }
3512 }
3513 } else {
3514 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3515 $price_product = new Product($this->db);
3516 $price_product->fetch($objp->rowid, '', '', '1');
3517
3518 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3519 $priceparser = new PriceParser($this->db);
3520 $price_result = $priceparser->parseProduct($price_product);
3521 if ($price_result >= 0) {
3522 $objp->price = $price_result;
3523 $objp->unitprice = $price_result;
3524 //Calculate the VAT
3525 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3526 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3527 }
3528 }
3529 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3530 $price_level = '';
3531 }
3532 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3533 // Add new entry
3534 // "key" value of json key array is used by jQuery automatically as selected value
3535 // "label" value of json key array is used by jQuery automatically as text for combo box
3536 $out .= $opt;
3537 array_push($outarray, $optJson);
3538 }
3539
3540 $i++;
3541 }
3542
3543 $out .= '</select>';
3544
3545 $this->db->free($result);
3546
3547 if (empty($outputmode)) {
3548 return $out;
3549 }
3550
3551 return $outarray;
3552 } else {
3553 dol_print_error($this->db);
3554 }
3555
3556 return '';
3557 }
3558
3574 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3575 {
3576 global $langs, $conf, $user;
3577 global $hookmanager;
3578
3579 $outkey = '';
3580 $outval = '';
3581 $outref = '';
3582 $outlabel = '';
3583 $outlabel_translated = '';
3584 $outdesc = '';
3585 $outdesc_translated = '';
3586 $outbarcode = '';
3587 $outorigin = '';
3588 $outtype = '';
3589 $outprice_ht = '';
3590 $outprice_ttc = '';
3591 $outpricebasetype = '';
3592 $outtva_tx = '';
3593 $outdefault_vat_code = '';
3594 $outqty = 1;
3595 $outdiscount = '0';
3596
3597 $maxlengtharticle = getDolGlobalInt('PRODUCT_MAX_LENGTH_COMBO', 48);
3598
3599 $label = $objp->label;
3600 if (!empty($objp->label_translated)) {
3601 $label = $objp->label_translated;
3602 }
3603 if (!empty($filterkey) && $filterkey != '') {
3604 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3605 }
3606
3607 $outkey = $objp->rowid;
3608 $outref = $objp->ref;
3609 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3610 $outlabel = $objp->label;
3611 $outdesc = $objp->description;
3612 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3613 $outlabel_translated = $objp->label_translated;
3614 $outdesc_translated = $objp->description_translated;
3615 }
3616 $outbarcode = $objp->barcode;
3617 $outorigin = $objp->fk_country;
3618 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3619
3620 $outtype = $objp->fk_product_type;
3621 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3622 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3623
3624 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3625 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3626 }
3627
3628 // Units
3629 $outvalUnits = '';
3630 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3631 if (!empty($objp->unit_short)) {
3632 $outvalUnits .= ' - ' . $objp->unit_short;
3633 }
3634 }
3635 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3636 if (!empty($objp->weight) && $objp->weight_units !== null) {
3637 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3638 $outvalUnits .= ' - ' . $unitToShow;
3639 }
3640 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3641 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3642 $outvalUnits .= ' - ' . $unitToShow;
3643 }
3644 if (!empty($objp->surface) && $objp->surface_units !== null) {
3645 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3646 $outvalUnits .= ' - ' . $unitToShow;
3647 }
3648 if (!empty($objp->volume) && $objp->volume_units !== null) {
3649 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3650 $outvalUnits .= ' - ' . $unitToShow;
3651 }
3652 }
3653 if ($outdurationvalue && $outdurationunit) {
3654 $da = array(
3655 'h' => $langs->trans('Hour'),
3656 'd' => $langs->trans('Day'),
3657 'w' => $langs->trans('Week'),
3658 'm' => $langs->trans('Month'),
3659 'y' => $langs->trans('Year')
3660 );
3661 if (isset($da[$outdurationunit])) {
3662 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3663 }
3664 }
3665
3666 // Set stocktag (stock too low or not or unknown)
3667 $stocktag = 0;
3668 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3669 if ($user->hasRight('stock', 'lire')) {
3670 if ($objp->stock > 0) {
3671 $stocktag = 1;
3672 } elseif ($objp->stock <= 0) {
3673 $stocktag = -1;
3674 }
3675 }
3676 }
3677
3678 // Set $labeltoshow
3679 $labeltoshow = '';
3680 $labeltoshow .= $objp->ref;
3681 if (!empty($objp->custref)) {
3682 $labeltoshow .= ' (' . $objp->custref . ')';
3683 }
3684 if ($outbarcode) {
3685 $labeltoshow .= ' (' . $outbarcode . ')';
3686 }
3687 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3688 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3689 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3690 }
3691
3692 // Set $labltoshowhtml
3693 $labeltoshowhtml = '';
3694 $labeltoshowhtml .= $objp->ref;
3695 if (!empty($objp->custref)) {
3696 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3697 }
3698 if (!empty($filterkey) && $filterkey != '') {
3699 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3700 }
3701 if ($outbarcode) {
3702 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3703 }
3704 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3705 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3706 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3707 }
3708
3709 // Stock
3710 $labeltoshowstock = '';
3711 $labeltoshowhtmlstock = '';
3712 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3713 if ($user->hasRight('stock', 'lire')) {
3714 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3715
3716 if ($objp->stock > 0) {
3717 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3718 } elseif ($objp->stock <= 0) {
3719 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3720 }
3721 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3722 $labeltoshowhtmlstock .= '</span>';
3723
3724 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3725 $langs->load("stocks");
3726
3727 $tmpproduct = new Product($this->db);
3728 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3729 $tmpproduct->load_virtual_stock();
3730 $virtualstock = $tmpproduct->stock_theorique;
3731
3732 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3733
3734 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3735 if ($virtualstock > 0) {
3736 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3737 } elseif ($virtualstock <= 0) {
3738 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3739 }
3740 $labeltoshowhtmlstock .= $virtualstock;
3741 $labeltoshowhtmlstock .= '</span>';
3742
3743 unset($tmpproduct);
3744 }
3745 }
3746 }
3747
3748 // Price
3749 $found = 0;
3750 $labeltoshowprice = '';
3751 $labeltoshowhtmlprice = '';
3752 // If we need a particular price level (from 1 to n)
3753 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3754 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3755 $sql .= " FROM " . $this->db->prefix() . "product_price";
3756 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3757 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3758 $sql .= " AND price_level = " . ((int) $price_level);
3759 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3760 $sql .= " LIMIT 1";
3761
3762 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3763 $result2 = $this->db->query($sql);
3764 if ($result2) {
3765 $objp2 = $this->db->fetch_object($result2);
3766 if ($objp2) {
3767 $found = 1;
3768 if ($objp2->price_base_type == 'HT') {
3769 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3770 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3771 } else {
3772 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3773 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3774 }
3775 $outprice_ht = price($objp2->price);
3776 $outprice_ttc = price($objp2->price_ttc);
3777 $outpricebasetype = $objp2->price_base_type;
3778 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3779 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3780 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3781 } else {
3782 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3783 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3784 }
3785 }
3786 } else {
3787 dol_print_error($this->db);
3788 }
3789 }
3790
3791 // Price by quantity
3792 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3793 $found = 1;
3794 $outqty = $objp->quantity;
3795 $outdiscount = $objp->remise_percent;
3796 if ($objp->quantity == 1) {
3797 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3798 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3799 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3800 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3801 } else {
3802 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3803 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3804 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3805 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3806 }
3807
3808 $outprice_ht = price($objp->unitprice);
3809 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3810 $outpricebasetype = $objp->price_base_type;
3811 $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
3812 $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
3813 }
3814 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3815 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3816 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3817 }
3818 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3819 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3820 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3821 }
3822
3823 // Price by customer
3824 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3825 if (!empty($objp->idprodcustprice)) {
3826 $found = 1;
3827
3828 if ($objp->custprice_base_type == 'HT') {
3829 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3830 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3831 } else {
3832 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3833 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3834 }
3835
3836 $outprice_ht = price($objp->custprice);
3837 $outprice_ttc = price($objp->custprice_ttc);
3838 $outpricebasetype = $objp->custprice_base_type;
3839 $outtva_tx = $objp->custtva_tx;
3840 $outdefault_vat_code = $objp->custdefault_vat_code;
3841 $outdiscount = $objp->custdiscount_percent;
3842 }
3843 }
3844
3845 // If level no defined or multiprice not found, we used the default price
3846 if (empty($hidepriceinlabel) && !$found) {
3847 if ($objp->price_base_type == 'HT') {
3848 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3849 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3850 } else {
3851 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3852 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3853 }
3854 $outprice_ht = price($objp->price);
3855 $outprice_ttc = price($objp->price_ttc);
3856 $outpricebasetype = $objp->price_base_type;
3857 $outtva_tx = $objp->tva_tx;
3858 $outdefault_vat_code = $objp->default_vat_code;
3859 }
3860
3861 // Build options
3862 $opt = '<option value="' . $objp->rowid . '"';
3863 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3864 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3865 $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 . '"';
3866 }
3867 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3868 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3869 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3870 }
3871
3872 if ($stocktag == 1) {
3873 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3874 //$opt .= ' class="product_line_stock_ok"';
3875 }
3876 if ($stocktag == -1) {
3877 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3878 //$opt .= ' class="product_line_stock_too_low"';
3879 }
3880
3881 $opt .= '>';
3882
3883 // Ref, barcode, country
3884 $opt .= $labeltoshow;
3885 $outval .= $labeltoshowhtml;
3886
3887 // Units
3888 $opt .= $outvalUnits;
3889 $outval .= $outvalUnits;
3890
3891 // Price
3892 $opt .= $labeltoshowprice;
3893 $outval .= $labeltoshowhtmlprice;
3894
3895 // Stock
3896 $opt .= $labeltoshowstock;
3897 $outval .= $labeltoshowhtmlstock;
3898
3899
3900 $parameters = array('objp' => $objp);
3901 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3902 if (empty($reshook)) {
3903 $opt .= $hookmanager->resPrint;
3904 } else {
3905 $opt = $hookmanager->resPrint;
3906 }
3907
3908 $opt .= "</option>\n";
3909 $optJson = array(
3910 'key' => $outkey,
3911 'value' => $outref,
3912 'label' => $outval,
3913 'label2' => $outlabel,
3914 'desc' => $outdesc,
3915 'type' => $outtype,
3916 'price_ht' => price2num($outprice_ht),
3917 'price_ttc' => price2num($outprice_ttc),
3918 'price_ht_locale' => price(price2num($outprice_ht)),
3919 'price_ttc_locale' => price(price2num($outprice_ttc)),
3920 'pricebasetype' => $outpricebasetype,
3921 'tva_tx' => $outtva_tx,
3922 'default_vat_code' => $outdefault_vat_code,
3923 'qty' => $outqty,
3924 'discount' => $outdiscount,
3925 'duration_value' => $outdurationvalue,
3926 'duration_unit' => $outdurationunit,
3927 'pbq' => $outpbq,
3928 'labeltrans' => $outlabel_translated,
3929 'desctrans' => $outdesc_translated,
3930 'ref_customer' => $outrefcust
3931 );
3932 }
3933
3934 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3935
3952 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '', $nooutput = 0)
3953 {
3954 // phpcs:enable
3955 global $langs, $conf;
3956 global $price_level, $status, $finished;
3957
3958 if (!isset($status)) {
3959 $status = 1;
3960 }
3961
3962 $selected_input_value = '';
3963 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3964 if ((int) $selected > 0) {
3965 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3966 $producttmpselect = new Product($this->db);
3967 $producttmpselect->fetch((int) $selected);
3968 $selected_input_value = $producttmpselect->ref;
3969 unset($producttmpselect);
3970 }
3971
3972 // mode=2 means suppliers products
3973 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3974
3975 $s = ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3976
3977 $s .= ($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3978 } else {
3979 $s = $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, getDolGlobalInt('SUPPLIER_SHOW_STOCK_IN_PRODUCTS_COMBO'), $placeholder);
3980 }
3981
3982 if ($nooutput) {
3983 return $s;
3984 } else {
3985 print $s;
3986 }
3987 }
3988
3989 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3990
4009 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 = '')
4010 {
4011 // phpcs:enable
4012 global $langs, $conf, $user;
4013 global $hookmanager;
4014
4015 $out = '';
4016 $outarray = array();
4017
4018 $maxlengtharticle = getDolGlobalInt('PRODUCT_MAX_LENGTH_COMBO', 48);
4019
4020 $langs->load('stocks');
4021 // Units
4022 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
4023 $langs->load('other');
4024 }
4025
4026 $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,";
4027 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
4028 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
4029 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
4030 $sql .= ", pfp.supplier_reputation";
4031 // if we use supplier description of the products
4032 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
4033 $sql .= ", pfp.desc_fourn as description";
4034 } else {
4035 $sql .= ", p.description";
4036 }
4037 // Units
4038 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
4039 $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";
4040 }
4041
4042 // Add select from hooks
4043 $parameters = [];
4044 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
4045 $sql .= $hookmanager->resPrint;
4046
4047 $sql .= " FROM " . $this->db->prefix() . "product as p";
4048
4049 // Add join from hooks
4050 $parameters = [];
4051 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
4052 $sql .= $hookmanager->resPrint;
4053
4054 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
4055 if ($socid > 0) {
4056 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
4057 }
4058 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4059 // Units
4060 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
4061 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
4062 }
4063 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
4064 if ($statut != -1) {
4065 $sql .= " AND p.tobuy = " . ((int) $statut);
4066 }
4067 if (strval($filtertype) != '') {
4068 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
4069 }
4070 if (!empty($filtre)) {
4071 $sql .= " " . $filtre;
4072 }
4073 // Add where from hooks
4074 $parameters = array();
4075 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
4076 $sql .= $hookmanager->resPrint;
4077 // Add criteria on ref/label
4078 if ($filterkey != '') {
4079 $sql .= ' AND (';
4080 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
4081 // For natural search
4082 $search_crit = explode(' ', $filterkey);
4083 $i = 0;
4084 if (count($search_crit) > 1) {
4085 $sql .= "(";
4086 }
4087 foreach ($search_crit as $crit) {
4088 if ($i > 0) {
4089 $sql .= " AND ";
4090 }
4091 $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) . "%'";
4092 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
4093 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
4094 }
4095 $sql .= ")";
4096 $i++;
4097 }
4098 if (count($search_crit) > 1) {
4099 $sql .= ")";
4100 }
4101 if (isModEnabled('barcode')) {
4102 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
4103 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
4104 }
4105 $sql .= ')';
4106 }
4107 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
4108 $sql .= $this->db->plimit($limit, 0);
4109
4110 // Build output string
4111
4112 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
4113 $result = $this->db->query($sql);
4114 if ($result) {
4115 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4116 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
4117
4118 $num = $this->db->num_rows($result);
4119
4120 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
4121 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
4122 if (!$selected) {
4123 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
4124 } else {
4125 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
4126 }
4127
4128 $i = 0;
4129 while ($i < $num) {
4130 $objp = $this->db->fetch_object($result);
4131
4132 if (is_null($objp->idprodfournprice)) {
4133 // There is no supplier price found, we will use the vat rate for sale
4134 $objp->tva_tx = $objp->tva_tx_sale;
4135 $objp->default_vat_code = $objp->default_vat_code_sale;
4136 }
4137
4138 $outkey = $objp->idprodfournprice; // id in table of price
4139 if (!$outkey && $alsoproductwithnosupplierprice) {
4140 $outkey = 'idprod_' . $objp->rowid; // id of product
4141 }
4142
4143 $outref = $objp->ref;
4144 $outbarcode = $objp->barcode;
4145 $outqty = 1;
4146 $outdiscount = 0;
4147 $outtype = $objp->fk_product_type;
4148 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
4149 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
4150
4151 // Units
4152 $outvalUnits = '';
4153 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
4154 if (!empty($objp->unit_short)) {
4155 $outvalUnits .= ' - ' . $objp->unit_short;
4156 }
4157 if (!empty($objp->weight) && $objp->weight_units !== null) {
4158 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
4159 $outvalUnits .= ' - ' . $unitToShow;
4160 }
4161 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
4162 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
4163 $outvalUnits .= ' - ' . $unitToShow;
4164 }
4165 if (!empty($objp->surface) && $objp->surface_units !== null) {
4166 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
4167 $outvalUnits .= ' - ' . $unitToShow;
4168 }
4169 if (!empty($objp->volume) && $objp->volume_units !== null) {
4170 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
4171 $outvalUnits .= ' - ' . $unitToShow;
4172 }
4173 if ($outdurationvalue && $outdurationunit) {
4174 $da = array(
4175 'h' => $langs->trans('Hour'),
4176 'd' => $langs->trans('Day'),
4177 'w' => $langs->trans('Week'),
4178 'm' => $langs->trans('Month'),
4179 'y' => $langs->trans('Year')
4180 );
4181 if (isset($da[$outdurationunit])) {
4182 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
4183 }
4184 }
4185 }
4186
4187 $objRef = $objp->ref;
4188 if ($filterkey && $filterkey != '') {
4189 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
4190 }
4191 $objRefFourn = $objp->ref_fourn;
4192 if ($filterkey && $filterkey != '') {
4193 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
4194 }
4195 $label = $objp->label;
4196 if ($filterkey && $filterkey != '') {
4197 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
4198 }
4199
4200 switch ($objp->fk_product_type) {
4202 $picto = 'product';
4203 break;
4205 $picto = 'service';
4206 break;
4207 default:
4208 $picto = '';
4209 break;
4210 }
4211
4212 if (empty($picto)) {
4213 $optlabel = '';
4214 } else {
4215 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
4216 }
4217
4218 $optlabel .= $objp->ref;
4219 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
4220 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
4221 }
4222 if (isModEnabled('barcode') && !empty($objp->barcode)) {
4223 $optlabel .= ' (' . $outbarcode . ')';
4224 }
4225 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
4226
4227 $outvallabel = $objRef;
4228 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
4229 $outvallabel .= ' (' . $objRefFourn . ')';
4230 }
4231 if (isModEnabled('barcode') && !empty($objp->barcode)) {
4232 $outvallabel .= ' (' . $outbarcode . ')';
4233 }
4234 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
4235
4236 // Units
4237 $optlabel .= $outvalUnits;
4238 $outvallabel .= $outvalUnits;
4239
4240 if (!empty($objp->idprodfournprice)) {
4241 $outqty = $objp->quantity;
4242 $outdiscount = $objp->remise_percent;
4243 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4244 $prod_supplier = new ProductFournisseur($this->db);
4245 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4246 $prod_supplier->id = $objp->fk_product;
4247 $prod_supplier->fourn_qty = $objp->quantity;
4248 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4249 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4250
4251 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4252 $priceparser = new PriceParser($this->db);
4253 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4254 if ($price_result >= 0) {
4255 $objp->fprice = $price_result;
4256 if ($objp->quantity >= 1) {
4257 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
4258 }
4259 }
4260 }
4261 if ($objp->quantity == 1) {
4262 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4263 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
4264 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
4265 $outvallabel .= $langs->transnoentities("Unit");
4266 } else {
4267 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
4268 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
4269 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
4270 $outvallabel .= ' ' . $langs->transnoentities("Units");
4271 }
4272
4273 if ($objp->quantity != 1) {
4274 $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
4275 $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
4276 }
4277 if ($objp->remise_percent >= 1) {
4278 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4279 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4280 }
4281 if ($objp->duration) {
4282 $optlabel .= " - " . $objp->duration;
4283 $outvallabel .= " - " . $objp->duration;
4284 }
4285 if (!$socid) {
4286 $optlabel .= " - " . dol_trunc($objp->name, 8);
4287 $outvallabel .= " - " . dol_trunc($objp->name, 8);
4288 }
4289 if ($objp->supplier_reputation) {
4290 //TODO dictionary
4291 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
4292
4293 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
4294 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
4295 }
4296 } else {
4297 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
4298 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
4299 }
4300
4301 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
4302 $novirtualstock = ($showstockinlist == 2);
4303
4304 if ($user->hasRight('stock', 'lire')) {
4305 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
4306
4307 if ($objp->stock > 0) {
4308 $optlabel .= ' - <span class="product_line_stock_ok">';
4309 } elseif ($objp->stock <= 0) {
4310 $optlabel .= ' - <span class="product_line_stock_too_low">';
4311 }
4312 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
4313 $optlabel .= '</span>';
4314 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
4315 $langs->load("stocks");
4316
4317 $tmpproduct = new Product($this->db);
4318 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
4319 $tmpproduct->load_virtual_stock();
4320 $virtualstock = $tmpproduct->stock_theorique;
4321
4322 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4323
4324 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4325 if ($virtualstock > 0) {
4326 $optlabel .= '<span class="product_line_stock_ok">';
4327 } elseif ($virtualstock <= 0) {
4328 $optlabel .= '<span class="product_line_stock_too_low">';
4329 }
4330 $optlabel .= $virtualstock;
4331 $optlabel .= '</span>';
4332
4333 unset($tmpproduct);
4334 }
4335 }
4336 }
4337
4338 $optstart = '<option value="' . $outkey . '"';
4339 if ($selected && preg_match('/^idprod_/', (string) $selected) && (string) $selected == 'idprod_'.$objp->rowid) {
4340 $optstart .= ' selected';
4341 } elseif ($selected && (string) $selected == (string) $objp->idprodfournprice) {
4342 $optstart .= ' selected';
4343 }
4344
4345 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4346 $optstart .= ' disabled';
4347 }
4348
4349 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4350 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4351 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4352 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4353 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"'; // the price with numeric international format
4354 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"'; // the price formatted in user language
4355 $optstart .= ' data-discount="' . dol_escape_htmltag((string) $outdiscount) . '"';
4356 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"'; // the rate with numeric international format
4357 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"'; // the rate formatted in user language
4358 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4359 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4360 if (isModEnabled('multicurrency')) {
4361 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4362 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag(price2num($objp->multicurrency_unitprice)) . '"'; // the price with numeric international format
4363 }
4364 }
4365 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4366
4367 // set $parameters to call hook
4368 $outarrayentry = array(
4369 'key' => $outkey,
4370 'value' => $outref,
4371 'label' => $outvallabel,
4372 'labelhtml' => $optlabel,
4373 'qty' => $outqty,
4374 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4375 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4376 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4377 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4378 'tva_tx' => price2num($objp->tva_tx),
4379 'default_vat_code' => $objp->default_vat_code,
4380 'supplier_ref' => $objp->ref_fourn,
4381 'discount' => $outdiscount,
4382 'type' => $outtype,
4383 'duration_value' => $outdurationvalue,
4384 'duration_unit' => $outdurationunit,
4385 'disabled' => empty($objp->idprodfournprice),
4386 'description' => $objp->description
4387 );
4388 if (isModEnabled('multicurrency')) {
4389 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4390 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4391 }
4392 $parameters = array(
4393 'objp' => &$objp,
4394 'optstart' => &$optstart,
4395 'optlabel' => &$optlabel,
4396 'outvallabel' => &$outvallabel,
4397 'outarrayentry' => &$outarrayentry,
4398 'fk_soc' => $socid
4399 );
4400 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4401
4402
4403 // Add new entry
4404 // "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
4405 // "label" value of json key array is used by jQuery automatically as text for combo box
4406 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4407 $outarraypush = array(
4408 'key' => $outkey,
4409 'value' => $outref,
4410 'label' => $outvallabel,
4411 'labelhtml' => $optlabel,
4412 'qty' => $outqty,
4413 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4414 'price_qty_ht_locale' => price($objp->fprice),
4415 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4416 'price_unit_ht_locale' => price($objp->unitprice),
4417 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4418 'tva_tx_formated' => price($objp->tva_tx),
4419 'tva_tx' => price2num($objp->tva_tx),
4420 'default_vat_code' => $objp->default_vat_code,
4421 'supplier_ref' => $objp->ref_fourn,
4422 'discount' => $outdiscount,
4423 'type' => $outtype,
4424 'duration_value' => $outdurationvalue,
4425 'duration_unit' => $outdurationunit,
4426 'disabled' => empty($objp->idprodfournprice),
4427 'description' => $objp->description
4428 );
4429 if (isModEnabled('multicurrency')) {
4430 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4431 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4432 }
4433 array_push($outarray, $outarraypush);
4434
4435 // Example of var_dump $outarray
4436 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4437 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4438 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4439 //}
4440 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4441 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4442 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4443
4444 $i++;
4445 }
4446 $out .= '</select>';
4447
4448 $this->db->free($result);
4449
4450 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4451 $out .= ajax_combobox($htmlname);
4452 } else {
4453 dol_print_error($this->db);
4454 }
4455
4456 if (empty($outputmode)) {
4457 return $out;
4458 }
4459 return $outarray;
4460 }
4461
4462 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4463
4472 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4473 {
4474 // phpcs:enable
4475 global $langs, $conf;
4476
4477 $langs->load('stocks');
4478
4479 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4480 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4481 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4482 $sql .= " FROM " . $this->db->prefix() . "product as p";
4483 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4484 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4485 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4486 $sql .= " AND p.tobuy = 1";
4487 $sql .= " AND s.fournisseur = 1";
4488 $sql .= " AND p.rowid = " . ((int) $productid);
4489 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4490 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4491 } else {
4492 $sql .= " ORDER BY pfp.unitprice ASC";
4493 }
4494
4495 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4496 $result = $this->db->query($sql);
4497
4498 if ($result) {
4499 $num = $this->db->num_rows($result);
4500
4501 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4502
4503 if (!$num) {
4504 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4505 } else {
4506 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4507 $form .= '<option value="0">&nbsp;</option>';
4508
4509 $i = 0;
4510 while ($i < $num) {
4511 $objp = $this->db->fetch_object($result);
4512
4513 $opt = '<option value="' . $objp->idprodfournprice . '"';
4514 //if there is only one supplier, preselect it
4515 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4516 $opt .= ' selected';
4517 }
4518 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4519
4520 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4521 $prod_supplier = new ProductFournisseur($this->db);
4522 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4523 $prod_supplier->id = $productid;
4524 $prod_supplier->fourn_qty = $objp->quantity;
4525 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4526 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4527
4528 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4529 $priceparser = new PriceParser($this->db);
4530 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4531 if ($price_result >= 0) {
4532 $objp->fprice = $price_result;
4533 if ($objp->quantity >= 1) {
4534 $objp->unitprice = $objp->fprice / $objp->quantity;
4535 }
4536 }
4537 }
4538 if ($objp->quantity == 1) {
4539 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4540 }
4541
4542 $opt .= $objp->quantity . ' ';
4543
4544 if ($objp->quantity == 1) {
4545 $opt .= $langs->trans("Unit");
4546 } else {
4547 $opt .= $langs->trans("Units");
4548 }
4549 if ($objp->quantity > 1) {
4550 $opt .= " - ";
4551 $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");
4552 }
4553 if ($objp->duration) {
4554 $opt .= " - " . $objp->duration;
4555 }
4556 $opt .= "</option>\n";
4557
4558 $form .= $opt;
4559 $i++;
4560 }
4561 }
4562
4563 $form .= '</select>';
4564 $this->db->free($result);
4565 return $form;
4566 } else {
4567 dol_print_error($this->db);
4568 return '';
4569 }
4570 }
4571
4572
4573 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4580 {
4581 // phpcs:enable
4582 global $langs, $hookmanager;
4583
4584 $num = count($this->cache_conditions_paiements);
4585 if ($num > 0) {
4586 return 0; // Cache already loaded
4587 }
4588
4589 dol_syslog(__METHOD__, LOG_DEBUG);
4590
4591 $this->cache_conditions_paiements = array();
4592
4593 $sql = "SELECT rowid, code, libelle as label, deposit_percent, entity";
4594 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4595 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4596 $sql .= " AND active > 0";
4597 $sql .= " ORDER BY sortorder";
4598
4599 $resql = $this->db->query($sql);
4600 if ($resql) {
4601 $num = $this->db->num_rows($resql);
4602 $i = 0;
4603 while ($i < $num) {
4604 $obj = $this->db->fetch_object($resql);
4605
4606 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4607 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4608 $this->cache_conditions_paiements[$obj->rowid]['code'] = (string) $obj->code;
4609 $this->cache_conditions_paiements[$obj->rowid]['label'] = (string) $label;
4610 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = (string) $obj->deposit_percent;
4611 $this->cache_conditions_paiements[$obj->rowid]['entity'] = (int) $obj->entity;
4612 $i++;
4613 }
4614
4615 $parameters = array('context' => 'paymentterm');
4616 $reshook = $hookmanager->executeHooks('loadDictionaryCache', $parameters, $this); // Note that $action and $object may have been modified by hook
4617 if (empty($reshook)) {
4618 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
4619 $this->cache_conditions_paiements = array_merge($this->cache_conditions_paiements, $hookmanager->resArray);
4620 }
4621 } else {
4622 $this->cache_conditions_paiements = $hookmanager->resArray;
4623 }
4624
4625 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4626
4627 return $num;
4628 } else {
4629 dol_print_error($this->db);
4630 return -1;
4631 }
4632 }
4633
4634 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4635
4642 {
4643 // phpcs:enable
4644 $factureRec = new FactureRec($this->db);
4645
4646 $this->cache_rule_for_lines_dates = $factureRec->fields['rule_for_lines_dates']['arrayofkeyval'];
4647
4648 if (empty($this->cache_rule_for_lines_dates)) {
4649 return -1;
4650 }
4651
4652 return 1;
4653 }
4654
4655 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4656
4662 public function load_cache_availability()
4663 {
4664 // phpcs:enable
4665 global $langs;
4666
4667 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4668 if ($num > 0) {
4669 return 0; // Cache already loaded
4670 }
4671
4672 dol_syslog(__METHOD__, LOG_DEBUG);
4673
4674 $this->cache_availability = array();
4675
4676 $langs->load('propal');
4677
4678 $sql = "SELECT rowid, code, label, position";
4679 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4680 $sql .= " WHERE active > 0";
4681
4682 $resql = $this->db->query($sql);
4683 if ($resql) {
4684 $num = $this->db->num_rows($resql);
4685 $i = 0;
4686 while ($i < $num) {
4687 $obj = $this->db->fetch_object($resql);
4688
4689 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4690 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4691 $this->cache_availability[$obj->rowid]['code'] = (string) $obj->code;
4692 $this->cache_availability[$obj->rowid]['label'] = (string) $label;
4693 $this->cache_availability[$obj->rowid]['position'] = (int) $obj->position;
4694 $i++;
4695 }
4696
4697 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4698
4699 return $num;
4700 } else {
4701 dol_print_error($this->db);
4702 return -1;
4703 }
4704 }
4705
4716 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4717 {
4718 global $langs, $user;
4719
4720 $this->load_cache_availability();
4721
4722 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4723
4724 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4725 if ($addempty) {
4726 print '<option value="0">&nbsp;</option>';
4727 }
4728 foreach ($this->cache_availability as $id => $arrayavailability) {
4729 if ($selected == $id) {
4730 print '<option value="' . $id . '" selected>';
4731 } else {
4732 print '<option value="' . $id . '">';
4733 }
4734 print dol_escape_htmltag($arrayavailability['label']);
4735 print '</option>';
4736 }
4737 print '</select>';
4738 if ($user->admin) {
4739 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4740 }
4741 print ajax_combobox($htmlname);
4742 }
4743
4749 public function loadCacheInputReason()
4750 {
4751 global $langs;
4752
4753 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4754 if ($num > 0) {
4755 return 0; // Cache already loaded
4756 }
4757
4758 $sql = "SELECT rowid, code, label";
4759 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4760 $sql .= " WHERE active > 0";
4761
4762 $resql = $this->db->query($sql);
4763 if ($resql) {
4764 $num = $this->db->num_rows($resql);
4765 $i = 0;
4767 $tmparray = array();
4768 while ($i < $num) {
4769 $obj = $this->db->fetch_object($resql);
4770
4771 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4772 $label = ($obj->label != '-' ? (string) $obj->label : '');
4773 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4774 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4775 }
4776 if ($langs->trans($obj->code) != $obj->code) {
4777 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4778 }
4779
4780 $tmparray[(int) $obj->rowid]
4781 = array(
4782 'id' => (int) $obj->rowid,
4783 'code' => (string) $obj->code,
4784 'label' => $label,
4785 );
4786 $i++;
4787 }
4788
4789 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4790
4791 unset($tmparray);
4792 return $num;
4793 } else {
4794 dol_print_error($this->db);
4795 return -1;
4796 }
4797 }
4798
4811 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4812 {
4813 global $langs, $user;
4814
4815 $this->loadCacheInputReason();
4816
4817 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4818 if ($addempty) {
4819 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4820 }
4821 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4822 if ($arraydemandreason['code'] == $exclude) {
4823 continue;
4824 }
4825
4826 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4827 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4828 } else {
4829 print '<option value="' . $arraydemandreason['id'] . '">';
4830 }
4831 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4832 print $langs->trans($label);
4833 print '</option>';
4834 }
4835 print '</select>';
4836 if ($user->admin && empty($notooltip)) {
4837 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4838 }
4839 print ajax_combobox('select_' . $htmlname);
4840 }
4841
4842 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4843
4850 {
4851 // phpcs:enable
4852 global $langs, $hookmanager;
4853
4854 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4855 if ($num > 0) {
4856 return $num; // Cache already loaded
4857 }
4858
4859 dol_syslog(__METHOD__, LOG_DEBUG);
4860
4861 $this->cache_types_paiements = array();
4862
4863 $sql = "SELECT id, code, libelle as label, type, entity, active";
4864 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4865 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4866
4867 $resql = $this->db->query($sql);
4868 if ($resql) {
4869 $num = $this->db->num_rows($resql);
4870 $i = 0;
4871 while ($i < $num) {
4872 $obj = $this->db->fetch_object($resql);
4873
4874 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4875 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4876 $this->cache_types_paiements[$obj->id]['id'] = (int) $obj->id;
4877 $this->cache_types_paiements[$obj->id]['code'] = (string) $obj->code;
4878 $this->cache_types_paiements[$obj->id]['label'] = (string) $label;
4879 $this->cache_types_paiements[$obj->id]['type'] = (int) $obj->type;
4880 $this->cache_types_paiements[$obj->id]['entity'] = (int) $obj->entity;
4881 $this->cache_types_paiements[$obj->id]['active'] = (int) $obj->active;
4882 $i++;
4883 }
4884
4885 $parameters = array('context' => 'paymenttype');
4886 $reshook = $hookmanager->executeHooks('loadDictionaryCache', $parameters, $this); // Note that $action and $object may have been modified by hook
4887 if (empty($reshook)) {
4888 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
4889 $this->cache_types_paiements = array_merge($this->cache_types_paiements, $hookmanager->resArray);
4890 }
4891 } else {
4892 $this->cache_types_paiements = $hookmanager->resArray;
4893 }
4894
4895 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4896
4897 return $num;
4898 } else {
4899 dol_print_error($this->db);
4900 return -1;
4901 }
4902 }
4903
4904
4905 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4906
4925 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4926 {
4927 // phpcs:enable
4928 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4929 if (empty($noprint)) {
4930 print $out;
4931 } else {
4932 return $out;
4933 }
4934 }
4935
4936
4953 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4954 {
4955 global $langs, $user, $conf;
4956
4957 $out = '';
4958 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4959
4961
4962 // Set default value if not already set by caller
4963 if (empty($selected) && strpos($htmlname, 'search_') !== 0 && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4964 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4965 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4966 }
4967
4968 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4969 if ($addempty) {
4970 $out .= '<option value="0">&nbsp;</option>';
4971 }
4972
4973 $selectedDepositPercent = null;
4974
4975 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4976 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4977 continue;
4978 }
4979
4980 if ($selected == $id) {
4981 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4982 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4983 } else {
4984 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4985 }
4986 $label = $arrayconditions['label'];
4987
4988 if (!empty($arrayconditions['deposit_percent'])) {
4989 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4990 }
4991
4992 $out .= $label;
4993 $out .= '</option>';
4994 }
4995 $out .= '</select>';
4996 if ($user->admin && empty($noinfoadmin)) {
4997 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4998 }
4999 $out .= ajax_combobox($htmlname);
5000
5001 if ($deposit_percent >= 0) {
5002 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
5003 $out .= $langs->trans('DepositPercent') . ' : ';
5004 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
5005 $out .= '</span>';
5006 $out .= '
5007 <script nonce="' . getNonce() . '">
5008 $(document).ready(function () {
5009 $("#' . $htmlname . '").change(function () {
5010 let $selected = $(this).find("option:selected");
5011 let depositPercent = $selected.attr("data-deposit_percent");
5012
5013 if (depositPercent.length > 0) {
5014 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
5015 } else {
5016 $("#' . $htmlname . '_deposit_percent_container").hide();
5017 }
5018
5019 return true;
5020 });
5021 });
5022 </script>';
5023 }
5024
5025 return $out;
5026 }
5027
5028
5037 public function getSelectRuleForLinesDates($selected = '', $htmlname = 'rule_for_lines_dates', $addempty = 0)
5038 {
5039 global $langs;
5040
5041 $out = '';
5042
5044
5045 $out .= '<select id="' . $htmlname . '" class="flat selectbillingterm" name="' . $htmlname . '">';
5046 if ($addempty) {
5047 $out .= '<option value="-1">&nbsp;</option>';
5048 }
5049
5050
5051 foreach ($this->cache_rule_for_lines_dates as $rule_for_lines_dates_key => $rule_for_lines_dates_name) {
5052 if ($selected == $rule_for_lines_dates_key) {
5053 $out .= '<option value="' . $rule_for_lines_dates_key . '" selected>';
5054 } else {
5055 $out .= '<option value="' . $rule_for_lines_dates_key . '">';
5056 }
5057
5058 $out .= $langs->trans($rule_for_lines_dates_name);
5059 $out .= '</option>';
5060 }
5061 $out .= '</select>';
5062
5063 $out .= ajax_combobox($htmlname);
5064
5065 return $out;
5066 }
5067
5068
5069 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5070
5087 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
5088 {
5089 // phpcs:enable
5090 global $langs, $user, $conf;
5091
5092 $out = '';
5093
5094 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
5095
5096 $filterarray = array();
5097 if ($filtertype == 'CRDT') {
5098 $filterarray = array(0, 2, 3);
5099 } elseif ($filtertype == 'DBIT') {
5100 $filterarray = array(1, 2, 3);
5101 } elseif ($filtertype != '' && $filtertype != '-1') {
5102 $filterarray = explode(',', $filtertype);
5103 }
5104
5106
5107 // Set default value if not already set by caller
5108 if (empty($selected) && strpos($htmlname, 'search_') !== 0 && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
5109 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
5110 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
5111 }
5112
5113 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
5114 if ($empty) {
5115 $out .= '<option value="">&nbsp;</option>';
5116 }
5117 foreach ($this->cache_types_paiements as $id => $arraytypes) {
5118 // If not good status
5119 if ($active >= 0 && $arraytypes['active'] != $active) {
5120 continue;
5121 }
5122
5123 // We skip of the user requested to filter on specific payment methods
5124 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
5125 continue;
5126 }
5127
5128 // We discard empty lines if showempty is on because an empty line has already been output.
5129 if ($empty && empty($arraytypes['code'])) {
5130 continue;
5131 }
5132
5133 if ($format == 0) {
5134 $out .= '<option value="' . $id . '" data-code="'.$arraytypes['code'].'"';
5135 } elseif ($format == 1) {
5136 $out .= '<option value="' . $arraytypes['code'] . '"';
5137 } elseif ($format == 2) {
5138 $out .= '<option value="' . $arraytypes['code'] . '"';
5139 } elseif ($format == 3) {
5140 $out .= '<option value="' . $id . '"';
5141 }
5142 // Print attribute selected or not
5143 if ($format == 1 || $format == 2) {
5144 if ($selected == $arraytypes['code']) {
5145 $out .= ' selected';
5146 }
5147 } else {
5148 if ($selected == $id) {
5149 $out .= ' selected';
5150 }
5151 }
5152 $out .= '>';
5153 $value = '';
5154 if ($format == 0) {
5155 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5156 } elseif ($format == 1) {
5157 $value = $arraytypes['code'];
5158 } elseif ($format == 2) {
5159 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5160 } elseif ($format == 3) {
5161 $value = $arraytypes['code'];
5162 }
5163 $out .= $value ? $value : '&nbsp;';
5164 $out .= '</option>';
5165 }
5166 $out .= '</select>';
5167 if ($user->admin && !$noadmininfo) {
5168 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5169 }
5170 $out .= ajax_combobox('select' . $htmlname);
5171
5172 if (empty($nooutput)) {
5173 print $out;
5174 } else {
5175 return $out;
5176 }
5177 }
5178
5179
5188 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
5189 {
5190 global $langs;
5191
5192 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
5193 $options = array(
5194 'HT' => $langs->trans("HT"),
5195 'TTC' => $langs->trans("TTC")
5196 );
5197 foreach ($options as $id => $value) {
5198 if ($selected == $id) {
5199 $return .= '<option value="' . $id . '" selected>' . $value;
5200 } else {
5201 $return .= '<option value="' . $id . '">' . $value;
5202 }
5203 $return .= '</option>';
5204 }
5205 $return .= '</select>';
5206 if ($addjscombo) {
5207 $return .= ajax_combobox('select_' . $htmlname);
5208 }
5209
5210 return $return;
5211 }
5212
5213 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5214
5221 {
5222 // phpcs:enable
5223 global $langs;
5224
5225 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
5226 if ($num > 0) {
5227 return $num; // Cache already loaded
5228 }
5229
5230 dol_syslog(__METHOD__, LOG_DEBUG);
5231
5232 $this->cache_transport_mode = array();
5233
5234 $sql = "SELECT rowid, code, label, active";
5235 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
5236 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
5237
5238 $resql = $this->db->query($sql);
5239 if ($resql) {
5240 $num = $this->db->num_rows($resql);
5241 $i = 0;
5242 while ($i < $num) {
5243 $obj = $this->db->fetch_object($resql);
5244
5245 // If traduction exist, we use it else we take the default label
5246 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
5247 $this->cache_transport_mode[(int) $obj->rowid]
5248 = array(
5249 'rowid' => (int) $obj->rowid,
5250 'code' => (string) $obj->code,
5251 'label' => (string) $label,
5252 'active' => (int) $obj->active,
5253 );
5254 $i++;
5255 }
5256
5257 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
5258
5259 return $num;
5260 } else {
5261 dol_print_error($this->db);
5262 return -1;
5263 }
5264 }
5265
5279 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
5280 {
5281 global $langs, $user;
5282
5283 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
5284
5286
5287 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
5288 if ($empty) {
5289 print '<option value="">&nbsp;</option>';
5290 }
5291 foreach ($this->cache_transport_mode as $id => $arraytypes) {
5292 // If not good status
5293 if ($active >= 0 && $arraytypes['active'] != $active) {
5294 continue;
5295 }
5296
5297 // We discard empty line if showempty is on because an empty line has already been output.
5298 if ($empty && empty($arraytypes['code'])) {
5299 continue;
5300 }
5301
5302 if ($format == 0) {
5303 print '<option value="' . $id . '"';
5304 } elseif ($format == 1) {
5305 print '<option value="' . $arraytypes['code'] . '"';
5306 } elseif ($format == 2) {
5307 print '<option value="' . $arraytypes['code'] . '"';
5308 } elseif ($format == 3) {
5309 print '<option value="' . $id . '"';
5310 }
5311 // If text is selected, we compare with code, else with id
5312 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
5313 print ' selected';
5314 } elseif ($selected == $id) {
5315 print ' selected';
5316 }
5317 print '>';
5318 $value = '';
5319 if ($format == 0) {
5320 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5321 } elseif ($format == 1) {
5322 $value = $arraytypes['code'];
5323 } elseif ($format == 2) {
5324 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5325 } elseif ($format == 3) {
5326 $value = $arraytypes['code'];
5327 }
5328 print $value ? $value : '&nbsp;';
5329 print '</option>';
5330 }
5331 print '</select>';
5332
5333 print ajax_combobox("select".$htmlname);
5334
5335 if ($user->admin && !$noadmininfo) {
5336 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5337 }
5338 }
5339
5352 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
5353 {
5354 global $langs, $user;
5355
5356 $langs->loadLangs(array("admin", "sendings"));
5357
5358 $sql = "SELECT rowid, code, libelle as label";
5359 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
5360 $sql .= " WHERE active > 0";
5361 if ($filtre) {
5362 $sql .= " AND " . $filtre;
5363 }
5364 $sql .= " ORDER BY libelle ASC";
5365
5366 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
5367 $result = $this->db->query($sql);
5368 if ($result) {
5369 $num = $this->db->num_rows($result);
5370 $i = 0;
5371 if ($num) {
5372 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5373 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5374 print '<option value="-1">&nbsp;</option>';
5375 }
5376 while ($i < $num) {
5377 $obj = $this->db->fetch_object($result);
5378 if ($selected == $obj->rowid) {
5379 print '<option value="' . $obj->rowid . '" selected>';
5380 } else {
5381 print '<option value="' . $obj->rowid . '">';
5382 }
5383 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
5384 print '</option>';
5385 $i++;
5386 }
5387 print "</select>";
5388 if ($user->admin && empty($noinfoadmin)) {
5389 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5390 }
5391
5392 print ajax_combobox('select' . $htmlname);
5393 } else {
5394 print $langs->trans("NoShippingMethodDefined");
5395 }
5396 } else {
5397 dol_print_error($this->db);
5398 }
5399 }
5400
5410 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
5411 {
5412 global $langs;
5413
5414 $langs->load("sendings");
5415
5416 if ($htmlname != "none") {
5417 print '<form method="POST" action="' . $page . '">';
5418 print '<input type="hidden" name="action" value="setshippingmethod">';
5419 print '<input type="hidden" name="token" value="' . newToken() . '">';
5420 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5421 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5422 print '</form>';
5423 } else {
5424 if ($selected) {
5425 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5426 print $langs->trans("SendingMethod" . strtoupper($code));
5427 } else {
5428 print "&nbsp;";
5429 }
5430 }
5431 }
5432
5441 public function selectSituationInvoices($selected = '', $socid = 0)
5442 {
5443 global $langs;
5444
5445 $langs->load('bills');
5446
5447 $opt = '';
5448
5449 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5450 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5451 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5452 $sql .= ' AND situation_counter >= 1';
5453 $sql .= ' AND fk_soc = ' . (int) $socid;
5454 $sql .= ' AND type <> 2';
5455 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5456 $resql = $this->db->query($sql);
5457
5458 $nbSituationInvoiceForThirdparty = 0;
5459
5460 if ($resql && $this->db->num_rows($resql) > 0) {
5461 // Last seen cycle
5462 $ref = 0;
5463 while ($obj = $this->db->fetch_object($resql)) {
5464 //Same cycle ?
5465 if ($obj->situation_cycle_ref != $ref) {
5466 // Just seen this cycle
5467 $ref = $obj->situation_cycle_ref;
5468 //not final ?
5469 if ($obj->situation_final != 1) {
5470 //Not prov?
5471 if (substr($obj->ref, 1, 4) != 'PROV') {
5472 $nbSituationInvoiceForThirdparty++;
5473
5474 if ($selected == $obj->rowid) {
5475 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5476 } else {
5477 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5478 }
5479 }
5480 }
5481 }
5482 }
5483 } else {
5484 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5485 }
5486
5487 if ($nbSituationInvoiceForThirdparty > 0) {
5488 $opt = '<option class="minwidth100" value="" selected>&nbsp;</option>'.$opt;
5489 } else {
5490 $opt = '<option class="minwidth100" value="-1" selected>'.$langs->trans('NoSituations').'</option>';
5491 }
5492
5493 return $opt;
5494 }
5495
5505 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5506 {
5507 global $langs;
5508
5509 $langs->load('products');
5510
5511 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5512
5513 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5514 $sql .= ' WHERE active > 0';
5515 if (!empty($unit_type)) {
5516 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5517 }
5518 $sql .= " ORDER BY sortorder";
5519
5520 $resql = $this->db->query($sql);
5521 if ($resql && $this->db->num_rows($resql) > 0) {
5522 if ($showempty) {
5523 $return .= '<option value="-1"></option>';
5524 }
5525
5526 while ($res = $this->db->fetch_object($resql)) {
5527 $unitLabel = $res->label;
5528 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5529 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5530 }
5531
5532 if ($selected == $res->rowid) {
5533 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5534 } else {
5535 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5536 }
5537 }
5538 $return .= '</select>';
5539
5540 $return .= ajax_combobox($htmlname);
5541 }
5542 return $return;
5543 }
5544
5545 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5546
5562 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0, $addentrynone = 0)
5563 {
5564 // phpcs:enable
5565 global $langs;
5566
5567 $out = '';
5568
5569 $langs->loadLangs(array("admin", "banks"));
5570 $num = 0;
5571
5572 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5573 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5574 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5575 if ($status != 2) {
5576 $sql .= " AND clos = " . (int) $status;
5577 }
5578 if ($filtre) { // TODO Support USF
5579 $sql .= " AND " . $filtre;
5580 }
5581 $sql .= " ORDER BY label";
5582
5583 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5584 $result = $this->db->query($sql);
5585 if ($result) {
5586 $num = $this->db->num_rows($result);
5587 $i = 0;
5588
5589 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5590
5591 if ($num == 0) {
5592 if ($status == 0) {
5593 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5594 } else {
5595 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5596 }
5597 } else {
5598 if (!empty($useempty) && !is_numeric($useempty)) {
5599 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5600 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5601 $out .= '<option value="-1">&nbsp;</option>';
5602 }
5603 }
5604
5605 while ($i < $num) {
5606 $obj = $this->db->fetch_object($result);
5607
5608 $labeltoshow = trim($obj->label);
5609 $labeltoshowhtml = trim($obj->label);
5610 if ($showcurrency) {
5611 $labeltoshow .= ' (' . $obj->currency_code . ')';
5612 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5613 }
5614 if ($status == 2 && $obj->status == 1) {
5615 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5616 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5617 }
5618
5619 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5620 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5621 } else {
5622 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5623 }
5624 $out .= $labeltoshow;
5625 $out .= '</option>';
5626 $i++;
5627 }
5628
5629 if (!empty($addentrynone)) {
5630 $out .= '<option value="-2"'.($selected == -2 ? ' selected="selected"': '').' data-html="'.dolPrintHTMLForAttribute('<span class="opacitymedium">'.$langs->trans("None").'</span>').'">'.$langs->trans("None").'</option>';
5631 }
5632
5633 $out .= "</select>";
5634 $out .= ajax_combobox('select' . $htmlname);
5635 } else {
5636 dol_print_error($this->db);
5637 }
5638
5639 // Output or return
5640 if (empty($nooutput)) {
5641 print $out;
5642 } else {
5643 return $out;
5644 }
5645
5646 return $num;
5647 }
5648
5662 public function selectRib($selected = '', $htmlname = 'ribcompanyid', $filtre = '', $useempty = 0, $moreattrib = '', $showibanbic = 0, $morecss = '', $nooutput = 0)
5663 {
5664 // phpcs:enable
5665 global $langs;
5666
5667 $out = '';
5668
5669 $langs->loadLangs(array("admin", "banks"));
5670 $num = 0;
5671
5672 $sql = "SELECT rowid, label, bank, status, iban_prefix, bic";
5673 $sql .= " FROM " . $this->db->prefix() . "societe_rib";
5674 $sql .= " WHERE type = 'ban'";
5675 if ($filtre) { // TODO Support USF
5676 $sql .= " AND " . $filtre;
5677 }
5678 $sql .= " ORDER BY label";
5679 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5680 $result = $this->db->query($sql);
5681 if ($result) {
5682 $num = $this->db->num_rows($result);
5683 $i = 0;
5684
5685 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5686
5687 if ($num == 0) {
5688 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5689 } else {
5690 if (!empty($useempty) && !is_numeric($useempty)) {
5691 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5692 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5693 $out .= '<option value="-1">&nbsp;</option>';
5694 }
5695 }
5696
5697 while ($i < $num) {
5698 $obj = $this->db->fetch_object($result);
5699 $iban = dolDecrypt($obj->iban_prefix);
5700 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5701 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '" selected>';
5702 } else {
5703 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '">';
5704 }
5705 $out .= trim($obj->label);
5706 if ($showibanbic) {
5707 $out .= ' (' . $iban . '/' .$obj->bic. ')';
5708 }
5709 $out .= '</option>';
5710 $i++;
5711 }
5712 $out .= "</select>";
5713 $out .= ajax_combobox('select' . $htmlname);
5714 } else {
5715 dol_print_error($this->db);
5716 }
5717
5718 // Output or return
5719 if (empty($nooutput)) {
5720 print $out;
5721 } else {
5722 return $out;
5723 }
5724
5725 return $num;
5726 }
5727
5739 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5740 {
5741 global $langs;
5742
5743 $langs->load("admin");
5744 $num = 0;
5745
5746 $sql = "SELECT rowid, name, fk_country, status, entity";
5747 $sql .= " FROM " . $this->db->prefix() . "establishment";
5748 $sql .= " WHERE 1=1";
5749 if ($status != 2) {
5750 $sql .= " AND status = " . (int) $status;
5751 }
5752 if ($filtre) { // TODO Support USF
5753 $sql .= " AND " . $filtre;
5754 }
5755 $sql .= " ORDER BY name";
5756
5757 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5758 $result = $this->db->query($sql);
5759 if ($result) {
5760 $num = $this->db->num_rows($result);
5761 $i = 0;
5762 if ($num) {
5763 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5764 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5765 print '<option value="-1">&nbsp;</option>';
5766 }
5767
5768 while ($i < $num) {
5769 $obj = $this->db->fetch_object($result);
5770 if ($selected == $obj->rowid) {
5771 print '<option value="' . $obj->rowid . '" selected>';
5772 } else {
5773 print '<option value="' . $obj->rowid . '">';
5774 }
5775 print trim($obj->name);
5776 if ($status == 2 && $obj->status == 1) {
5777 print ' (' . $langs->trans("Closed") . ')';
5778 }
5779 print '</option>';
5780 $i++;
5781 }
5782 print "</select>";
5783 } else {
5784 if ($status == 0) {
5785 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5786 } else {
5787 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5788 }
5789 }
5790
5791 return $num;
5792 } else {
5793 dol_print_error($this->db);
5794 return -1;
5795 }
5796 }
5797
5807 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5808 {
5809 global $langs;
5810 if ($htmlname != "none") {
5811 print '<form method="POST" action="' . $page . '">';
5812 print '<input type="hidden" name="action" value="setbankaccount">';
5813 print '<input type="hidden" name="token" value="' . newToken() . '">';
5814 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5815 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5816 if ($nbaccountfound > 0) {
5817 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5818 }
5819 print '</form>';
5820 } else {
5821 $langs->load('banks');
5822
5823 if ($selected) {
5824 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5825 $bankstatic = new Account($this->db);
5826 $result = $bankstatic->fetch((int) $selected);
5827 if ($result) {
5828 print $bankstatic->getNomUrl(1);
5829 }
5830 } else {
5831 print "&nbsp;";
5832 }
5833 }
5834 }
5835
5847 public function formRib($page, $selected = '', $htmlname = 'ribcompanyid', $filtre = '', $addempty = 0, $showibanbic = 0)
5848 {
5849 global $langs;
5850 if ($htmlname != "none") {
5851 print '<form method="POST" action="' . $page . '">';
5852 print '<input type="hidden" name="action" value="setbankaccountcustomer">';
5853 print '<input type="hidden" name="token" value="' . newToken() . '">';
5854 $nbaccountfound = $this->selectRib($selected, $htmlname, $filtre, $addempty, '', $showibanbic);
5855 if ($nbaccountfound > 0) {
5856 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5857 }
5858 print '</form>';
5859 } else {
5860 $langs->load('banks');
5861
5862 if ($selected) {
5863 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
5864 $bankstatic = new CompanyBankAccount($this->db);
5865 $result = $bankstatic->fetch((int) $selected);
5866 if ($result) {
5867 print $bankstatic->label;
5868 if ($showibanbic) {
5869 print ' (' . $bankstatic->iban . '/' .$bankstatic->bic. ')';
5870 }
5871 }
5872 } else {
5873 print "&nbsp;";
5874 }
5875 }
5876 }
5877
5887 public function selectCategories($categtype, $htmlname, $object = null)
5888 {
5889 global $langs;
5890
5891 $out = '';
5892
5893 $cate_arbo = $this->select_all_categories($categtype, '', '', 64, 0, 3);
5894
5895 $arrayselected = array();
5896 if (GETPOSTISARRAY($htmlname)) {
5897 $arrayselected = GETPOST($htmlname, 'array:int');
5898 } elseif (is_object($object) && $object->id > 0) {
5899 $c = new Categorie($this->db);
5900 $cats = $c->containing($object->id, $categtype);
5901 $arrayselected = array();
5902 foreach ($cats as $cat) {
5903 $arrayselected[] = $cat->id;
5904 }
5905 }
5906
5907 $out .= img_picto('', 'category', 'class="pictofixedwidth"');
5908 $out .= $this->multiselectarray($htmlname, $cate_arbo, $arrayselected, 0, 0, 'minwidth100 widthcentpercentminusxx', 0, 0);
5909
5910 if (!getDolGlobalString('CATEGORY_EDIT_IN_MENU_NOT_IN_POPUP')) {
5911 // Add html code to add the edit button and go back
5912 $jsonclose = 'doJsCodeAfterPopupClose'.$htmlname.'()';
5913 $urltoopen = '/categories/categorie_list.php?type='.urlencode($categtype).'&nosearch=1';
5914
5915 $s = dolButtonToOpenUrlInDialogPopup($htmlname, $langs->transnoentitiesnoconv("Categories"), img_picto('', 'add', 'class="editfielda"'), $urltoopen, '', '', '', $jsonclose);
5916 $out .= $s;
5917 // Add js code to add the edit button and go back
5918 $out .= '<!-- Add js code to open the popup for category/edit/add -->'."\n";
5919 $out .= '<script>function doJsCodeAfterPopupClose'.$htmlname.'() {
5920 console.log("doJsCodeAfterPopupClose'.$htmlname.' has been called, we refresh the combo content + refresh select2...");
5921
5922 // Call an ajax to reload values and update the select
5923 // $("#'.dol_escape_js($htmlname).'").append(new Option("Option 4", "4"));
5924
5925 // Refresh select2 to take account of new values (enough for small change)
5926
5927 $.ajax({
5928 url: \''.DOL_URL_ROOT.'/core/ajax/fetchCategories.php\',
5929 data: {
5930 action: \'getCategories\',
5931 type: \''.dol_escape_htmltag($categtype).'\'
5932 },
5933 type: \'GET\',
5934 dataType: \'json\',
5935 success: function (data) {
5936 var $select = $(\'#'.dol_escape_js($htmlname).'\');
5937 var selectedValues = $select.val(); // This is an array of selected values
5938 console.log(selectedValues);
5939 $select.empty();
5940 $.each(data, function (index, item) {
5941 $select.append(\'<option value="\' + item.id + \'" data-html="\' + item.htmlforattribute + \'">\' + item.htmlforoption + \'</option>\');
5942 });
5943 $select.val(selectedValues);
5944 },
5945 error: function (xhr, status, error) {
5946 console.log("Error when loading ajax page : " + error);
5947 }
5948 });
5949
5950 $("#'.dol_escape_js($htmlname).'").trigger("change");
5951 // Alternative if change in select is complex
5952 /*
5953 $("#'.dol_escape_js($htmlname).'").select2("destroy");
5954 $("#'.dol_escape_js($htmlname).'").select2();
5955 */
5956 }</script>';
5957 }
5958
5959 return $out;
5960 }
5961
5962
5963 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5983 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5984 {
5985 // phpcs:enable
5986 global $langs;
5987
5988 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5989
5990 $cat = new Categorie($this->db);
5991
5992 if (is_numeric($type)) {
5993 $type = array_search($type, $cat->MAP_ID); // For backward compatibility
5994 }
5995
5996 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5997
5998 $outarray = array();
5999 $outarrayrichhtml = array();
6000
6001
6002 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6003 if (is_array($cate_arbo)) {
6004 $num = count($cate_arbo);
6005
6006 if (!$num) {
6007 $langs->load("categories");
6008 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
6009 } else {
6010 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
6011 $output .= '<option value="-1">&nbsp;</option>';
6012 }
6013 foreach ($cate_arbo as $key => $value) {
6014 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
6015 $add = 'selected ';
6016 } else {
6017 $add = '';
6018 }
6019
6020 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth"'.(empty($cate_arbo[$key]['color']) ? '' : ' style="color: #' . $cate_arbo[$key]['color'] . '"'));
6021 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
6022
6023 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
6024
6025 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
6026
6027 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
6028 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
6029 $output .= '>';
6030 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
6031 $output .= '</option>';
6032
6033 $cate_arbo[$key]['data-html'] = $labeltoshow;
6034 }
6035 }
6036 }
6037 $output .= '</select>';
6038 $output .= "\n";
6039
6040 $this->num = count($cate_arbo);
6041
6042 if ($outputmode == 2) {
6043 // TODO: handle error when $cate_arbo is not an array
6044 return $cate_arbo;
6045 } elseif ($outputmode == 1) {
6046 return $outarray;
6047 } elseif ($outputmode == 3) {
6048 return $outarrayrichhtml;
6049 }
6050 return $output;
6051 }
6052
6053 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6054
6073 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
6074 {
6075 // phpcs:enable
6076 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
6077 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
6078 }
6079
6106 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
6107 {
6108 global $langs, $conf;
6109
6110 $more = '';
6111 $formconfirm = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
6112
6113 $inputok = array();
6114 $inputko = array();
6115
6116 // Clean parameters
6117 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
6118 if ($conf->browser->layout == 'phone') {
6119 $width = '95%';
6120 }
6121
6122 // Set height automatically if not defined
6123 if (empty($height)) {
6124 $height = 250;
6125 if (is_array($formquestion) && count($formquestion) > 2) {
6126 $height += ((count($formquestion) - 2) * 24) + 5;
6127 }
6128 }
6129
6130 if (is_array($formquestion) && !empty($formquestion)) {
6131 // First add hidden fields and value
6132 foreach ($formquestion as $key => $input) {
6133 if (is_array($input) && !empty($input)) {
6134 if ($input['type'] == 'hidden') {
6135 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
6136 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
6137
6138 $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";
6139 }
6140 }
6141 }
6142
6143 // Now add questions
6144 $moreonecolumn = '';
6145 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
6146 foreach ($formquestion as $key => $input) {
6147 if (is_array($input) && !empty($input)) {
6148 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
6149 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
6150 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
6151
6152 if ($input['type'] == 'text' || $input['type'] == 'input') { // traditional input
6153 $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 . ' spellcheck="false" /></div></div>' . "\n";
6154 } elseif ($input['type'] == 'password') {
6155 $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";
6156 } elseif ($input['type'] == 'textarea') {
6157 $moreonecolumn .= '<div class="margintoponly">';
6158 $moreonecolumn .= $input['label'] . '<br>';
6159 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
6160 $moreonecolumn .= $input['value'];
6161 $moreonecolumn .= '</textarea>';
6162 $moreonecolumn .= '</div>';
6163 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
6164 if (empty($morecss)) {
6165 $morecss = 'minwidth100';
6166 }
6167
6168 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
6169 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
6170 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
6171 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
6172 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
6173 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
6174 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
6175
6176 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
6177 if (!empty($input['label'])) {
6178 $more .= $input['label'] . '</div><div class="tagtd left">';
6179 }
6180 if ($input['type'] == 'select') {
6181 $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);
6182 } else {
6183 $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);
6184 }
6185 $more .= '</div></div>' . "\n";
6186 } elseif ($input['type'] == 'checkbox') {
6187 $more .= '<div class="tagtr">';
6188 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
6189 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
6190 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
6191 $more .= ' checked';
6192 }
6193 if (is_bool($input['value']) && $input['value']) {
6194 $more .= ' checked';
6195 }
6196 if (isset($input['disabled'])) {
6197 $more .= ' disabled';
6198 }
6199 $more .= ' /></div>';
6200 $more .= '</div>' . "\n";
6201 } elseif ($input['type'] == 'radio') {
6202 $i = 0;
6203 foreach ($input['values'] as $selkey => $selval) {
6204 $more .= '<div class="tagtr">';
6205 if (isset($input['label'])) {
6206 if ($i == 0) {
6207 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
6208 } else {
6209 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
6210 }
6211 }
6212 $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;
6213 if (!empty($input['disabled'])) {
6214 $more .= ' disabled';
6215 }
6216 if (isset($input['default']) && $input['default'] === $selkey) {
6217 $more .= ' checked="checked"';
6218 }
6219 $more .= ' /> ';
6220 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
6221 $more .= '</div></div>' . "\n";
6222 $i++;
6223 }
6224 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
6225 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
6226 $more .= '<div class="tagtd">';
6227 $addnowlink = (empty($input['datenow']) ? 0 : 1);
6228 $h = $m = 0;
6229 if ($input['type'] == 'datetime') {
6230 $h = isset($input['hours']) ? $input['hours'] : 1;
6231 $m = isset($input['minutes']) ? $input['minutes'] : 1;
6232 }
6233 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
6234 $more .= '</div></div>'."\n";
6235 $formquestion[] = array('name' => $input['name'].'day');
6236 $formquestion[] = array('name' => $input['name'].'month');
6237 $formquestion[] = array('name' => $input['name'].'year');
6238 $formquestion[] = array('name' => $input['name'].'hour');
6239 $formquestion[] = array('name' => $input['name'].'min');
6240 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
6241 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
6242 if (!empty($input['label'])) {
6243 $more .= $input['label'] . '</div><div class="tagtd">';
6244 }
6245 if (!empty($input['value'])) {
6246 $more .= $input['value'];
6247 }
6248 $more .= '</div></div>' . "\n";
6249 } elseif ($input['type'] == 'onecolumn') {
6250 $moreonecolumn .= '<div class="margintoponly">';
6251 $moreonecolumn .= $input['value'];
6252 $moreonecolumn .= '</div>' . "\n";
6253 } elseif ($input['type'] == 'hidden') {
6254 // Do nothing more, already added by a previous loop
6255 } elseif ($input['type'] == 'separator') {
6256 $more .= '<br>';
6257 } else {
6258 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
6259 }
6260 }
6261 }
6262 $more .= '</div>' . "\n";
6263 $more .= $moreonecolumn;
6264 }
6265
6266 // JQUERY method dialog is broken with smartphone, we use standard HTML.
6267 // 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
6268 // See page product/card.php for example
6269 if (!empty($conf->dol_use_jmobile)) {
6270 $useajax = 0;
6271 }
6272 if (empty($conf->use_javascript_ajax)) {
6273 $useajax = 0;
6274 }
6275
6276 if ($useajax) {
6277 $autoOpen = true;
6278 $dialogconfirm = 'dialog-confirm';
6279 $button = '';
6280 if (!is_numeric($useajax)) {
6281 $button = $useajax;
6282 $useajax = 1;
6283 $autoOpen = false;
6284 $dialogconfirm .= '-' . $button;
6285 }
6286 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
6287 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
6288
6289 // Add input fields into list of fields to read during submit (inputok and inputko)
6290 if (is_array($formquestion)) {
6291 foreach ($formquestion as $key => $input) {
6292 //print "xx ".$key." rr ".is_array($input)."<br>\n";
6293 // Add name of fields to propagate with the GET when submitting the form with button OK.
6294 if (is_array($input) && isset($input['name'])) {
6295 if (strpos($input['name'], ',') > 0) {
6296 $inputok = array_merge($inputok, explode(',', $input['name']));
6297 } else {
6298 array_push($inputok, $input['name']);
6299 }
6300 }
6301 // Add name of fields to propagate with the GET when submitting the form with button KO.
6302 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
6303 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
6304 array_push($inputko, $input['name']);
6305 }
6306 }
6307 }
6308
6309 // Show JQuery confirm box.
6310 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
6311 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
6312 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
6313 }
6314 if (!empty($more)) {
6315 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
6316 }
6317 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
6318 $formconfirm .= '</div>' . "\n";
6319
6320 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
6321 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6322 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
6323 $formconfirm .= 'jQuery(document).ready(function() {
6324 $(function() {
6325 $( "#' . $dialogconfirm . '" ).dialog({
6326 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
6327 if ($newselectedchoice == 'no') {
6328 $formconfirm .= '
6329 open: function() {
6330 $(this).parent().find("button.ui-button:eq(2)").focus();
6331 },';
6332 }
6333
6334 $jsforcursor = '';
6335 if ($useajax == 1) {
6336 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
6337 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
6338 }
6339
6340 $postconfirmas = 'GET';
6341
6342 $formconfirm .= '
6343 resizable: false,
6344 height: \'' . dol_escape_js($height) . '\',
6345 width: \'' . dol_escape_js($width) . '\',
6346 modal: true,
6347 closeOnEscape: false,
6348 buttons: {
6349 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
6350 var options = "token=' . urlencode(newToken()) . '";
6351 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
6352 var page = \'' . dol_escape_js(!empty($page) ? $page : '') . '\';
6353 var pageyes = \'' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '\';
6354
6355 if (inputok.length > 0) {
6356 $.each(inputok, function(i, inputname) {
6357 var more = "";
6358 var inputvalue;
6359 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
6360 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
6361 } else {
6362 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
6363 inputvalue = $("#" + inputname + more).val();
6364 }
6365 if (typeof inputvalue == "undefined") { inputvalue=""; }
6366 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
6367 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
6368 });
6369 }
6370 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
6371 if (pageyes.length > 0) {';
6372 if ($postconfirmas == 'GET') {
6373 $formconfirm .= 'location.href = urljump;';
6374 } else {
6375 $formconfirm .= $jsforcursor;
6376 $formconfirm .= 'var post = $.post(
6377 pageyes,
6378 options,
6379 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
6380 );';
6381 }
6382 $formconfirm .= '
6383 console.log("after post ok");
6384 }
6385 $(this).dialog("close");
6386 },
6387 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
6388 var options = "token=' . urlencode(newToken()) . '";
6389 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
6390 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
6391 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
6392 if (inputko.length > 0) {
6393 $.each(inputko, function(i, inputname) {
6394 var more = "";
6395 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
6396 var inputvalue = $("#" + inputname + more).val();
6397 if (typeof inputvalue == "undefined") { inputvalue=""; }
6398 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
6399 });
6400 }
6401 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
6402 //alert(urljump);
6403 if (pageno.length > 0) {';
6404 if ($postconfirmas == 'GET') {
6405 $formconfirm .= 'location.href = urljump;';
6406 } else {
6407 $formconfirm .= $jsforcursor;
6408 $formconfirm .= 'var post = $.post(
6409 pageno,
6410 options,
6411 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
6412 );';
6413 }
6414 $formconfirm .= '
6415 console.log("after post ko");
6416 }
6417 $(this).dialog("close");
6418 }
6419 }
6420 }
6421 );
6422
6423 var button = "' . $button . '";
6424 if (button.length > 0) {
6425 $( "#" + button ).click(function() {
6426 $("#' . $dialogconfirm . '").dialog("open");
6427 });
6428 }
6429 });
6430 });
6431 </script>';
6432 $formconfirm .= "<!-- end ajax formconfirm -->\n";
6433 } else {
6434 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
6435
6436 if (empty($disableformtag)) {
6437 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
6438 }
6439
6440 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
6441 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
6442
6443 $formconfirm .= '<table class="valid centpercent">' . "\n";
6444
6445 // Line title
6446 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
6447 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
6448 $formconfirm .= '</td></tr>' . "\n";
6449
6450 // Line text
6451 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
6452 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
6453 }
6454
6455 // Line form fields
6456 if ($more) {
6457 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
6458 $formconfirm .= $more;
6459 $formconfirm .= '</td></tr>' . "\n";
6460 }
6461
6462 // Line with question
6463 $formconfirm .= '<tr class="valid">';
6464 $formconfirm .= '<td class="valid">' . $question . '</td>';
6465 $formconfirm .= '<td class="valid center">';
6466 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
6467 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
6468 $formconfirm .= '</td>';
6469 $formconfirm .= '</tr>' . "\n";
6470
6471 $formconfirm .= '</table>' . "\n";
6472
6473 if (empty($disableformtag)) {
6474 $formconfirm .= "</form>\n";
6475 }
6476 $formconfirm .= '<br>';
6477
6478 if (!empty($conf->use_javascript_ajax)) {
6479 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
6480 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6481 $formconfirm .= '
6482 $(document).ready(function () {
6483 $(".confirmvalidatebutton").on("click", function() {
6484 console.log("We click on button confirmvalidatebutton");
6485 $(this).attr("disabled", "disabled");
6486 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
6487 //console.log($(this).closest("form"));
6488 $(this).closest("form").submit();
6489 });
6490 });
6491 ';
6492 $formconfirm .= '</script>' . "\n";
6493 }
6494
6495 $formconfirm .= "<!-- end formconfirm -->\n";
6496 }
6497
6498 return $formconfirm;
6499 }
6500
6501
6502 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6503
6519 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
6520 {
6521 // phpcs:enable
6522 global $langs;
6523
6524 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
6525 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
6526
6527 $out = '';
6528
6529 $formproject = new FormProjets($this->db);
6530
6531 $langs->load("project");
6532 if ($htmlname != "none") {
6533 $out .= '<form method="post" action="' . $page . '">';
6534 $out .= '<input type="hidden" name="action" value="classin">';
6535 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6536 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
6537 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6538 $out .= '</form>';
6539 } else {
6540 $out .= '<span class="project_head_block">';
6541 if ($selected instanceof Project) {
6542 $out .= $selected->getNomUrl(0, '', 1);
6543 } elseif (is_numeric($selected)) {
6544 $projet = new Project($this->db);
6545 $projet->fetch((int) $selected);
6546 $out .= $projet->getNomUrl(0, '', 1);
6547 } else {
6548 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
6549 }
6550 $out .= '</span>';
6551 }
6552
6553 if (empty($nooutput)) {
6554 print $out;
6555 return '';
6556 }
6557 return $out;
6558 }
6559
6560 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6561
6577 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
6578 {
6579 // phpcs:enable
6580 global $langs;
6581
6582 $out = '';
6583
6584 if ($htmlname != "none") {
6585 $out .= '<form method="POST" action="' . $page . '">';
6586 $out .= '<input type="hidden" name="action" value="setconditions">';
6587 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6588 if ($type) {
6589 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6590 }
6591 $out .= $this->getSelectConditionsPaiements((int) $selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6592 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6593 $out .= '</form>';
6594 } else {
6595 if ($selected) {
6596 $this->load_cache_conditions_paiements();
6597 if (isset($this->cache_conditions_paiements[$selected])) {
6598 $label = $this->cache_conditions_paiements[$selected]['label'];
6599
6600 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6601 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6602 }
6603
6604 $out .= $label;
6605 } else {
6606 $langs->load('errors');
6607 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6608 }
6609 } else {
6610 $out .= '&nbsp;';
6611 }
6612 }
6613
6614 if (empty($nooutput)) {
6615 print $out;
6616 return '';
6617 }
6618 return $out;
6619 }
6620
6621 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6622
6633 public function form_rule_for_lines_dates($page, $selected = '', $htmlname = 'rule_for_lines_dates', $addempty = 0, $nooutput = 0): string
6634 {
6635 // phpcs:enable
6636 global $langs;
6637
6638 $out = '';
6639
6640 if ($htmlname != 'none') {
6641 $out .= '<form method="POST" action="' . $page . '">';
6642 $out .= '<input type="hidden" name="action" value="setruleforlinesdates">';
6643 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6644 $out .= $this->getSelectRuleForLinesDates($selected, $htmlname, $addempty);
6645 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6646 $out .= '</form>';
6647 } else {
6648 if (isset($selected)) {
6649 $this->load_cache_rule_for_lines_dates();
6650 if (isset($this->cache_rule_for_lines_dates[$selected])) {
6651 $label = $this->cache_rule_for_lines_dates[$selected];
6652 $out .= $langs->trans($label);
6653 }
6654 } else {
6655 $out .= '&nbsp;';
6656 }
6657 }
6658
6659 if (empty($nooutput)) {
6660 print $out;
6661 return '';
6662 }
6663
6664 return $out;
6665 }
6666
6667 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6668
6678 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
6679 {
6680 // phpcs:enable
6681 global $langs;
6682 if ($htmlname != "none") {
6683 print '<form method="post" action="' . $page . '">';
6684 print '<input type="hidden" name="action" value="setavailability">';
6685 print '<input type="hidden" name="token" value="' . newToken() . '">';
6686 $this->selectAvailabilityDelay($selected, $htmlname, '', $addempty);
6687 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6688 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
6689 print '</form>';
6690 } else {
6691 if ($selected) {
6692 $this->load_cache_availability();
6693 if (isset($this->cache_availability[$selected])) {
6694 print $this->cache_availability[$selected]['label'];
6695 } else {
6696 print "&nbsp;";
6697 }
6698 } else {
6699 print "&nbsp;";
6700 }
6701 }
6702 }
6703
6715 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0, $morecss = '')
6716 {
6717 global $langs;
6718 if ($htmlname != "none") {
6719 print '<form method="post" action="' . $page . '">';
6720 print '<input type="hidden" name="action" value="setdemandreason">';
6721 print '<input type="hidden" name="token" value="' . newToken() . '">';
6722 $this->selectInputReason($selected, $htmlname, '-1', $addempty, $morecss);
6723 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6724 print '</form>';
6725 } else {
6726 if ($selected) {
6727 $this->loadCacheInputReason();
6728 foreach ($this->cache_demand_reason as $key => $val) {
6729 if ($val['id'] == $selected) {
6730 print $val['label'];
6731 break;
6732 }
6733 }
6734 } else {
6735 print "&nbsp;";
6736 }
6737 }
6738 }
6739
6740 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6741
6755 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6756 {
6757 // phpcs:enable
6758 global $langs;
6759
6760 $ret = '';
6761
6762 if ($htmlname != "none") {
6763 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6764 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6765 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6766 if ($type) {
6767 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6768 }
6769 $ret .= '<table class="nobordernopadding">';
6770 $ret .= '<tr><td>';
6771 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6772 $ret .= '</td>';
6773 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6774 $ret .= '</tr></table></form>';
6775 } else {
6776 if ($displayhour) {
6777 $ret .= dol_print_date($selected, 'dayhour');
6778 } else {
6779 $ret .= dol_print_date($selected, 'day');
6780 }
6781 }
6782
6783 if (empty($nooutput)) {
6784 print $ret;
6785 }
6786 return $ret;
6787 }
6788
6789
6790 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6791
6802 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6803 {
6804 // phpcs:enable
6805 global $langs;
6806
6807 if ($htmlname != "none") {
6808 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6809 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6810 print '<input type="hidden" name="token" value="' . newToken() . '">';
6811 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6812 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6813 print '</form>';
6814 } else {
6815 if ($selected) {
6816 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6817 $theuser = new User($this->db);
6818 $theuser->fetch((int) $selected);
6819 print $theuser->getNomUrl(1);
6820 } else {
6821 print "&nbsp;";
6822 }
6823 }
6824 }
6825
6826
6827 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6828
6842 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6843 {
6844 // phpcs:enable
6845 global $langs;
6846
6847 $out = '';
6848 if ($htmlname != "none") {
6849 $out .= '<form method="POST" action="' . $page . '">';
6850 $out .= '<input type="hidden" name="action" value="setmode">';
6851 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6852 if ($type) {
6853 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6854 }
6855 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6856 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6857 $out .= '</form>';
6858 } else {
6859 if ($selected) {
6860 $this->load_cache_types_paiements();
6861 $out .= $this->cache_types_paiements[$selected]['label'];
6862 } else {
6863 $out .= "&nbsp;";
6864 }
6865 }
6866
6867 if ($nooutput) {
6868 return $out;
6869 } else {
6870 print $out;
6871 }
6872 return '';
6873 }
6874
6885 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6886 {
6887 global $langs;
6888 if ($htmlname != "none") {
6889 print '<form method="POST" action="' . $page . '">';
6890 print '<input type="hidden" name="action" value="settransportmode">';
6891 print '<input type="hidden" name="token" value="' . newToken() . '">';
6892 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6893 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6894 print '</form>';
6895 } else {
6896 if ($selected) {
6897 $this->load_cache_transport_mode();
6898 print $this->cache_transport_mode[$selected]['label'];
6899 } else {
6900 print "&nbsp;";
6901 }
6902 }
6903 }
6904
6905 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6906
6915 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6916 {
6917 // phpcs:enable
6918 global $langs;
6919 if ($htmlname != "none") {
6920 print '<form method="POST" action="' . $page . '">';
6921 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6922 print '<input type="hidden" name="token" value="' . newToken() . '">';
6923 print $this->selectMultiCurrency($selected, $htmlname, 0);
6924 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6925 print '</form>';
6926 } else {
6927 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6928 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6929 }
6930 }
6931
6932 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6933
6943 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6944 {
6945 // phpcs:enable
6946 global $langs, $conf;
6947
6948 if ($htmlname != "none") {
6949 print '<form method="POST" action="' . $page . '">';
6950 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6951 print '<input type="hidden" name="token" value="' . newToken() . '">';
6952 print '<input type="text" class="maxwidth75" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" spellcheck="false" /> ';
6953 print '<select name="calculation_mode" id="calculation_mode">';
6954 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6955 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6956 print '</select> ';
6957 print ajax_combobox("calculation_mode");
6958 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6959 print '</form>';
6960 } else {
6961 if (!empty($rate)) {
6962 print price($rate, 1, $langs, 0, 0);
6963 if ($currency && $rate != 1) {
6964 print ' &nbsp; <span class="opacitymedium">(' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')</span>';
6965 }
6966 } else {
6967 print 1;
6968 }
6969 }
6970 }
6971
6972 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6973
6989 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6990 {
6991 // phpcs:enable
6992 global $conf, $langs;
6993
6994 if ($htmlname != "none") {
6995 print '<form method="post" action="' . $page . '" class="inline-block">';
6996 print '<input type="hidden" name="action" value="setabsolutediscount">';
6997 print '<input type="hidden" name="token" value="' . newToken() . '">';
6998 print '<div class="inline-block">';
6999 if (!empty($discount_type)) {
7000 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
7001 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
7002 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
7003 } else {
7004 $translationKey = 'HasCreditNoteFromSupplier';
7005 }
7006 } else {
7007 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
7008 $translationKey = 'HasAbsoluteDiscountFromSupplier';
7009 } else {
7010 $translationKey = 'HasCreditNoteFromSupplier';
7011 }
7012 }
7013 } else {
7014 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
7015 if (!$filter || $filter == "fk_facture_source IS NULL") {
7016 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
7017 } else {
7018 $translationKey = 'CompanyHasCreditNote';
7019 }
7020 } else {
7021 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
7022 $translationKey = 'CompanyHasAbsoluteDiscount';
7023 } else {
7024 $translationKey = 'CompanyHasCreditNote';
7025 }
7026 }
7027 }
7028 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
7029 if (empty($hidelist)) {
7030 print ' ';
7031 }
7032 print '</div>';
7033 if (empty($hidelist)) {
7034 print '<div class="inline-block" style="padding-right: 10px">';
7035 $newfilter = 'discount_type=' . intval($discount_type);
7036 if (!empty($discount_type)) {
7037 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
7038 } else {
7039 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
7040 }
7041 if ($filter) {
7042 $newfilter .= ' AND (' . $filter . ')';
7043 }
7044 // output the combo of discounts
7045 $nbqualifiedlines = $this->select_remises((string) $selected, $htmlname, $newfilter, $socid, $maxvalue);
7046 if ($nbqualifiedlines > 0) {
7047 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
7048 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
7049 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
7050 }
7051 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
7052 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
7053 }
7054
7055 print '>';
7056 }
7057 print '</div>';
7058 }
7059 if ($more) {
7060 print '<div class="inline-block">';
7061 print $more;
7062 print '</div>';
7063 }
7064 print '</form>';
7065 } else {
7066 if ($selected) {
7067 print $selected;
7068 } else {
7069 print "0";
7070 }
7071 }
7072 }
7073
7074
7075 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7076
7086 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
7087 {
7088 // phpcs:enable
7089 global $langs;
7090
7091 if ($htmlname != "none") {
7092 print '<form method="post" action="' . $page . '">';
7093 print '<input type="hidden" name="action" value="set_contact">';
7094 print '<input type="hidden" name="token" value="' . newToken() . '">';
7095 print '<table class="nobordernopadding">';
7096 print '<tr><td>';
7097 print $this->selectcontacts($societe->id, $selected, $htmlname);
7098 $num = $this->num;
7099 if ($num == 0) {
7100 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
7101 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&action=create&backtoreferer=1">' . $addcontact . '</a>';
7102 }
7103 print '</td>';
7104 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
7105 print '</tr></table></form>';
7106 } else {
7107 if ($selected) {
7108 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
7109 $contact = new Contact($this->db);
7110 $contact->fetch((int) $selected);
7111 print $contact->getFullName($langs);
7112 } else {
7113 print "&nbsp;";
7114 }
7115 }
7116 }
7117
7118 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7119
7136 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
7137 {
7138 // phpcs:enable
7139 global $langs;
7140
7141 $out = '';
7142 if ($htmlname != "none") {
7143 $out .= '<form method="post" action="' . $page . '">';
7144 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
7145 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
7146 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
7147 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
7148 $out .= '</form>';
7149 } else {
7150 if ($selected) {
7151 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
7152 $soc = new Societe($this->db);
7153 $soc->fetch((int) $selected);
7154 $out .= $soc->getNomUrl(0, '');
7155 } else {
7156 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
7157 }
7158 }
7159
7160 if ($nooutput) {
7161 return $out;
7162 } else {
7163 print $out;
7164 }
7165
7166 return '';
7167 }
7168
7169 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7170
7179 public function select_currency($selected = '', $htmlname = 'currency_id')
7180 {
7181 // phpcs:enable
7182 print $this->selectCurrency($selected, $htmlname);
7183 }
7184
7194 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
7195 {
7196 global $langs, $user;
7197
7198 $langs->loadCacheCurrencies('');
7199
7200 $out = '';
7201
7202 if ($selected == 'euro' || $selected == 'euros') {
7203 $selected = 'EUR'; // Pour compatibilite
7204 }
7205
7206 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
7207 if ($useempty) {
7208 $out .= '<option value="-1" selected></option>';
7209 }
7210 foreach ($langs->cache_currencies as $code_iso => $currency) {
7211 $labeltoshow = $currency['label'];
7212 if ($mode == 1) {
7213 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
7214 } elseif ($mode == 2) {
7215 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso.' - '.$langs->getCurrencySymbol($code_iso) . ')</span>';
7216 } else {
7217 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
7218 }
7219
7220 if ($selected && $selected == $code_iso) {
7221 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
7222 } else {
7223 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
7224 }
7225 $out .= dol_string_nohtmltag($labeltoshow);
7226 $out .= '</option>';
7227 }
7228 $out .= '</select>';
7229 if ($user->admin) {
7230 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
7231 }
7232
7233 // Make select dynamic
7234 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7235 $out .= ajax_combobox($htmlname);
7236
7237 return $out;
7238 }
7239
7252 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = 'maxwidth200 widthcentpercentminusx')
7253 {
7254 global $conf, $langs;
7255
7256 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
7257
7258 $TCurrency = array();
7259
7260 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
7261 $sql .= " WHERE entity IN ('" . getEntity('multicurrency') . "')";
7262 if ($filter) {
7263 $sql .= " AND " . $filter;
7264 }
7265 $resql = $this->db->query($sql);
7266 if ($resql) {
7267 while ($obj = $this->db->fetch_object($resql)) {
7268 $TCurrency[$obj->code] = $obj->code;
7269 }
7270 }
7271
7272 $out = '';
7273 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7274 if ($useempty) {
7275 $out .= '<option value="">&nbsp;</option>';
7276 }
7277 // If company current currency not in table, we add it into list. Should always be available.
7278 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
7279 $TCurrency[$conf->currency] = $conf->currency;
7280 }
7281 if (count($TCurrency) > 0) {
7282 foreach ($langs->cache_currencies as $code_iso => $currency) {
7283 if (isset($TCurrency[$code_iso])) {
7284 if (!empty($selected) && $selected == $code_iso) {
7285 $out .= '<option value="' . $code_iso . '" selected="selected">';
7286 } else {
7287 $out .= '<option value="' . $code_iso . '">';
7288 }
7289
7290 $out .= $currency['label'];
7291 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
7292 $out .= '</option>';
7293 }
7294 }
7295 }
7296
7297 $out .= '</select>';
7298
7299 // Make select dynamic
7300 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7301 $out .= ajax_combobox($htmlname);
7302
7303 return $out;
7304 }
7305
7306 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7307
7314 public function load_cache_vatrates($country_code)
7315 {
7316 // phpcs:enable
7317 global $langs, $user;
7318
7319 $num = count($this->cache_vatrates);
7320 if ($num > 0) {
7321 return $num; // Cache already loaded
7322 }
7323
7324 dol_syslog(__METHOD__, LOG_DEBUG);
7325
7326 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
7327 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
7328 $sql .= " WHERE t.fk_pays = c.rowid";
7329 $sql .= " AND t.active > 0";
7330 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
7331 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
7332 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
7333
7334 $resql = $this->db->query($sql);
7335 if ($resql) {
7336 $num = $this->db->num_rows($resql);
7337 if ($num) {
7338 for ($i = 0; $i < $num; $i++) {
7339 $obj = $this->db->fetch_object($resql);
7340
7341 $tmparray = array();
7342 $tmparray['rowid'] = (int) $obj->rowid;
7343 $tmparray['type_vat'] = ($obj->type_vat <= 0 ? 0 : $obj->type_vat); // Some version have type_vat corrupted with value -1
7344 $tmparray['code'] = $obj->code;
7345 $tmparray['txtva'] = $obj->taux;
7346 $tmparray['nprtva'] = $obj->recuperableonly;
7347 $tmparray['localtax1'] = $obj->localtax1;
7348 $tmparray['localtax1_type'] = $obj->localtax1_type;
7349 $tmparray['localtax2'] = $obj->localtax2;
7350 $tmparray['localtax2_type'] = $obj->localtax1_type;
7351 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
7352 $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
7353 $positiverates = '';
7354 if ($obj->taux) {
7355 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
7356 }
7357 if ($obj->localtax1) {
7358 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
7359 }
7360 if ($obj->localtax2) {
7361 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
7362 }
7363 if (empty($positiverates)) {
7364 $positiverates = '0';
7365 }
7366 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
7367
7368 $this->cache_vatrates[$obj->rowid] = $tmparray;
7369 }
7370
7371 return $num;
7372 } else {
7373 $this->error = '<span class="error">';
7374 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
7375 $reg = array();
7376 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
7377 $langs->load("errors");
7378 $new_country_code = $reg[1];
7379 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid');
7380 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
7381 }
7382 $this->error .= '</span>';
7383 return -1;
7384 }
7385 } else {
7386 $this->error = '<span class="error">' . $this->db->error() . '</span>';
7387 return -2;
7388 }
7389 }
7390
7391 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7392
7415 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)
7416 {
7417 // phpcs:enable
7418 global $langs, $mysoc, $hookmanager;
7419
7420 $langs->load('errors');
7421
7422 $return = '';
7423 // Bypass the default method
7424 $hookmanager->initHooks(array('commonobject'));
7425 $info_bits == 1 ? $is_npr = 1 : $is_npr = 0;
7426 $parameters = array(
7427 'htmlname' => $htmlname,
7428 'selectedrate' => $selectedrate,
7429 'seller' => $societe_vendeuse,
7430 'buyer' => $societe_acheteuse,
7431 'idprod' => $idprod,
7432 'is_npr' => $is_npr,
7433 'type' => $type,
7434 'options_only' => $options_only,
7435 'mode' => $mode,
7436 'type_vat' => $type_vat
7437 );
7438 $reshook = $hookmanager->executeHooks('load_tva', $parameters);
7439 if ($reshook > 0) {
7440 return $hookmanager->resPrint;
7441 } elseif ($reshook === 0) {
7442 $return .= $hookmanager->resPrint;
7443 }
7444
7445 // Define defaultnpr, defaultttx and defaultcode
7446 $defaultnpr = ($info_bits & 0x01);
7447 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
7448 $defaulttx = str_replace('*', '', $selectedrate);
7449 $defaultcode = '';
7450 $reg = array();
7451 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7452 $defaultcode = $reg[1];
7453 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7454 }
7455 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
7456
7457 // Check parameters
7458 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
7459 if ($societe_vendeuse->id == $mysoc->id) {
7460 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
7461 } else {
7462 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
7463 }
7464 return $return;
7465 }
7466
7467 //var_dump($societe_acheteuse);
7468 //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";
7469 //exit;
7470
7471 // Define list of countries to use to search VAT rates to show
7472 // First we defined code_country to use to find list
7473 if (is_object($societe_vendeuse)) {
7474 $code_country = "'" . $societe_vendeuse->country_code . "'";
7475 } else {
7476 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
7477 }
7478
7479 if ($societe_vendeuse == $mysoc && getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
7480 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
7481 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
7482 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
7483 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
7484 if (is_object($societe_vendeuse) && is_object($societe_acheteuse) && isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
7485 // We also add the buyer country code
7486 if (is_numeric($type)) {
7487 if ($type == 1) { // We know product is a service
7488 switch ($selectVatComboMode) {
7489 case '1':
7490 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7491 break;
7492 case '2':
7493 $code_country = "'" . $societe_acheteuse->country_code . "'";
7494 break;
7495 }
7496 }
7497 } elseif (!$idprod) { // We don't know type of product
7498 switch ($selectVatComboMode) {
7499 case '1':
7500 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7501 break;
7502 case '2':
7503 $code_country = "'" . $societe_acheteuse->country_code . "'";
7504 break;
7505 }
7506 } else {
7507 $prodstatic = new Product($this->db);
7508 $prodstatic->fetch($idprod);
7509 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
7510 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7511 }
7512 }
7513 }
7514 }
7515
7516 // Now we load the list of VAT
7517 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
7518
7519 // Keep only the VAT qualified for $type_vat
7520 $arrayofvatrates = array();
7521 foreach ($this->cache_vatrates as $cachevalue) {
7522 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] == $type_vat) {
7523 $arrayofvatrates[] = $cachevalue;
7524 }
7525 }
7526
7527 $num = count($arrayofvatrates);
7528 if ($num > 0) {
7529 // Define the vat rate to pre-select (if defaulttx not forced so is -1 or '')
7530 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7531 // Define a default thirdparty to use if the seller or buyer is not defined
7532 $tmpthirdparty = new Societe($this->db);
7533 $tmpthirdparty->country_code = $mysoc->country_code;
7534
7535 $defaulttx = get_default_tva(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7536 $defaultnpr = get_default_npr(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7537
7538 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7539 $defaultcode = $reg[1];
7540 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7541 }
7542 if (empty($defaulttx)) {
7543 $defaultnpr = 0;
7544 }
7545 }
7546
7547 // If we fails to find a default vat rate, we take the last one in list
7548 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
7549 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7550 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
7551 // We take the last one found in list
7552 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
7553 } else {
7554 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
7555 $defaulttx = '';
7556 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
7557 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
7558 }
7559 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7560 $defaultcode = $reg[1];
7561 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7562 }
7563 }
7564 }
7565
7566 // Disabled is true if the seller is not subject to VAT
7567 $disabled = false;
7568 $title = '';
7569 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && empty($societe_vendeuse->tva_assuj)) {
7570 // When we are seller and we do not use VAT, we want to force to disable VAT selection, except if EXPENSEREPORT_OVERRIDE_VAT is set
7571 // EXPENSEREPORT_OVERRIDE_VAT is a strange option that allow to override/enable VAT regardless of sellet vat option - needed for expense report if
7572 // expense report used for business expenses instead of using supplier invoices (but this is a very bad idea !)
7573 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
7574 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
7575 $disabled = true;
7576 }
7577 }
7578
7579 if (!$options_only) {
7580 $return .= '<select class="flat valignmiddle minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
7581 }
7582
7583 $selectedfound = false;
7584 foreach ($arrayofvatrates as $rate) {
7585 // Keep only 0 if seller is not subject to VAT
7586 if ($disabled && $rate['txtva'] != 0) {
7587 continue;
7588 }
7589
7590 // Define key to use into select list
7591 $key = $rate['txtva'];
7592 $key .= $rate['nprtva'] ? '*' : '';
7593 if ($mode > 0 && $rate['code']) {
7594 $key .= ' (' . $rate['code'] . ')';
7595 }
7596 if ($mode < 0) {
7597 $key = $rate['rowid'];
7598 }
7599
7600 $return .= '<option value="' . $key . '" data-vatid="'.$rate['rowid'].'"';
7601 if (!$selectedfound) {
7602 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
7603 if ($defaultcode == $rate['code']) {
7604 $return .= ' selected';
7605 $selectedfound = true;
7606 }
7607 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
7608 $return .= ' selected';
7609 $selectedfound = true;
7610 }
7611 }
7612 $return .= '>';
7613
7614 // Show label of VAT
7615 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
7616 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
7617 $return .= $rate['labelpositiverates'];
7618 } else {
7619 // Simple label
7620 $return .= vatrate($rate['label']);
7621 }
7622
7623 //$return.=($rate['code']?' '.$rate['code']:'');
7624 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
7625
7626 $return .= '</option>';
7627 }
7628
7629 if (!$options_only) {
7630 $return .= '</select>';
7631 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
7632 }
7633 } else {
7634 $return .= $this->error;
7635 }
7636
7637 $this->num = $num;
7638 return $return;
7639 }
7640
7641
7642 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7643
7668 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 = '')
7669 {
7670 // phpcs:enable
7671 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
7672 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
7673 if (!empty($nooutput)) {
7674 return $retstring;
7675 }
7676 print $retstring;
7677
7678 return '';
7679 }
7680
7696 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
7697 {
7698 global $langs;
7699
7700 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
7701 if ($forcenewline) {
7702 $ret .= '<br>';
7703 }
7704 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
7705 return $ret;
7706 }
7707
7736 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 = '')
7737 {
7738 global $conf, $langs;
7739
7740 if ($gm === 'auto') {
7741 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7742 }
7743
7744 $retstring = '';
7745
7746 if ($prefix == '') {
7747 $prefix = 're';
7748 }
7749 if ($h == '') {
7750 $h = 0;
7751 }
7752 if ($m == '') {
7753 $m = 0;
7754 }
7755 $emptydate = 0;
7756 $emptyhours = 0;
7757 if ($stepminutes <= 0 || $stepminutes > 30) {
7758 $stepminutes = 1;
7759 }
7760 if ($empty == 1) {
7761 $emptydate = 1;
7762 $emptyhours = 1;
7763 }
7764 if ($empty == 2) {
7765 $emptydate = 0;
7766 $emptyhours = 1;
7767 }
7768 $orig_set_time = $set_time;
7769
7770 if ($set_time === '' && $emptydate == 0) {
7771 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7772 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7773 $set_time = dol_now($gm);
7774 } else {
7775 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7776 }
7777 }
7778
7779 // Analysis of the pre-selection date
7780 $reg = array();
7781 $shour = '';
7782 $smin = '';
7783 $ssec = '';
7784 if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', (string) $set_time, $reg)) { // deprecated usage
7785 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7786 $syear = (!empty($reg[1]) ? $reg[1] : '');
7787 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7788 $sday = (!empty($reg[3]) ? $reg[3] : '');
7789 $shour = (!empty($reg[4]) ? $reg[4] : '');
7790 $smin = (!empty($reg[5]) ? $reg[5] : '');
7791 } elseif (strval($set_time) != '' && $set_time != -1) {
7792 // set_time est un timestamps (0 possible)
7793 $syear = dol_print_date($set_time, "%Y", $gm);
7794 $smonth = dol_print_date($set_time, "%m", $gm);
7795 $sday = dol_print_date($set_time, "%d", $gm);
7796 if ($orig_set_time != '') {
7797 $shour = dol_print_date($set_time, "%H", $gm);
7798 $smin = dol_print_date($set_time, "%M", $gm);
7799 $ssec = dol_print_date($set_time, "%S", $gm);
7800 }
7801 } else {
7802 // Date est '' ou vaut -1
7803 $syear = '';
7804 $smonth = '';
7805 $sday = '';
7806 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7807 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7808 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7809 }
7810 if ($h == 3 || $h == 4) {
7811 $shour = '';
7812 }
7813 if ($m == 3) {
7814 $smin = '';
7815 }
7816
7817 $nowgmt = dol_now('gmt');
7818 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7819
7820 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7821 $usecalendar = 'combo';
7822 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7823 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : getDolGlobalString("MAIN_POPUP_CALENDAR"));
7824 }
7825 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7826 // If we use a text browser or screen reader, we use the 'combo' date selector
7827 $usecalendar = 'html';
7828 }
7829
7830 if ($d) {
7831 // Show date with popup
7832 if ($usecalendar != 'combo') {
7833 // Set $format and $formatjs and $formatjquery
7834 $reduceformat = (!empty($conf->dol_optimize_smallscreen) ? 1 : 0); // Test on original $format param.
7835 if ($reduceformat) {
7836 $format = str_replace('%Y', '%y', $langs->transnoentitiesnoconv("FormatDateShortInput")); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7837 $formatjslong = $langs->transnoentitiesnoconv("FormatDateShortJavaInput"); // don't trust the name
7838 $formatjs = str_replace('yyyy', 'yy', $langs->transnoentitiesnoconv("FormatDateShortJavaInput"));
7839 $formatjquery = str_replace('yyyy', 'yy', $langs->trans("FormatDateShortJQueryInput"));
7840 } else {
7841 $format = $langs->transnoentitiesnoconv("FormatDateShortInput"); // FormatDateShortInput for dol_print_date is same than FormatDateShortJavaInput for javascript
7842 $formatjslong = $langs->transnoentitiesnoconv("FormatDateShortJavaInput"); // don't trust the name
7843 $formatjs = $langs->transnoentitiesnoconv("FormatDateShortJavaInput"); // FormatDateShortInput for dol_print_date is same than FormatDateShortJavaInput for javascript
7844 $formatjquery = $langs->trans("FormatDateShortJQueryInput");
7845 }
7846
7847 // Set formatted_date (for example: '%d/%m/%Y', '%m-%d-%y', ...
7848 $formatted_date = '';
7849 if (strval($set_time) != '' && $set_time != -1) {
7850 $formatted_date = dol_print_date($set_time, $format, $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7851 }
7852
7853 // Calendrier popup version eldy
7854 if ($usecalendar == "eldy") {
7855 // To have this manager working back, you must retrieve all functions showDP child found into the lib_head.js of v4 for example
7856 // and load the js that contains them so the call of showDP will works.
7857 /*
7858 // Input area to enter date manually
7859 $retstring .= '<!-- datepicker usecalendar=eldy --><input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formatted_date . '"';
7860 $retstring .= ($disabled ? ' disabled' : '');
7861 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($formatjslong")) . '\'); "'; // FormatDateShortInput for dol_print_date is same than FormatDateShortJavaInput for javascript
7862 $retstring .= ' autocomplete="off">';
7863
7864 // Icon calendar
7865 $retstringbuttom = '';
7866 if (!$disabled) {
7867 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7868 $base = DOL_URL_ROOT . '/core/';
7869 $retstringbuttom .= ' onClick="showDP(\'' . dol_escape_js($base) . '\',\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\',\'' . dol_escape_js($langs->defaultlang) . '\');"';
7870 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink paddingright"') . '</button>';
7871 } else {
7872 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink paddingright"') . '</button>';
7873 }
7874 $retstring = $retstringbuttom . $retstring;
7875
7876 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7877 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7878 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7879 */
7880 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7881 if (!$disabled && $usecalendar != 'html') {
7882 // Output javascript for datepicker
7883 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7884 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7885
7886 $retstring .= '<!-- datepicker usecalendar='.$usecalendar.' --><script nonce="' . getNonce() . '" type="text/javascript">';
7887 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7888 dateFormat: '" . dol_escape_js($formatjquery) . "',
7889 autoclose: true,
7890 todayHighlight: true,
7891 yearRange: '" . $minYear . ":" . $maxYear . "',";
7892 if (!empty($conf->dol_use_jmobile)) {
7893 $retstring .= "
7894 beforeShow: function (input, datePicker) {
7895 input.disabled = true;
7896 },
7897 onClose: function (dateText, datePicker) {
7898 this.disabled = false;
7899 },
7900 ";
7901 }
7902 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7903 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7904 $buttonImage = $calendarpicto ?: DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png";
7905 $retstring .= "
7906 showOn: 'button', /* both has problem with autocompletion */
7907 buttonImage: '" . $buttonImage . "',
7908 buttonImageOnly: true";
7909 }
7910 $retstring .= "
7911 }) });";
7912 $retstring .= "</script>";
7913 }
7914
7915 // Input area to enter date manually
7916 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7917 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="'.($usecalendar == 'html' ? "date" : "text").'" class="maxwidthdate'.(getDolUserString('MAIN_OPTIMIZEFORTEXTBROWSER') ? ' textbrowser' : '').' center" maxlength="11" value="'.$formatted_date.'"';
7918 $retstring .= ($disabled ? ' disabled' : '');
7919 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7920 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($usecalendar == 'html' ? 'yyyy-mm-dd' : $formatjslong) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7921 $retstring .= ' autocomplete="off">';
7922
7923 // Icon calendar
7924 if ($disabled) {
7925 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink ui-datepicker-notrigger"') . '</button>';
7926 $retstring .= $retstringbutton;
7927 }
7928
7929 $retstring .= '</div>';
7930 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7931 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7932 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7933 } else {
7934 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7935 }
7936 } else {
7937 // Show date with combo selects
7938 // Day
7939 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7940
7941 if ($emptydate || $set_time == -1) {
7942 $retstring .= '<option value="0" selected>&nbsp;</option>';
7943 }
7944
7945 for ($day = 1; $day <= 31; $day++) {
7946 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7947 }
7948
7949 $retstring .= "</select>";
7950
7951 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7952 if ($emptydate || $set_time == -1) {
7953 $retstring .= '<option value="0" selected>&nbsp;</option>';
7954 }
7955
7956 // Month
7957 for ($month = 1; $month <= 12; $month++) {
7958 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7959 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7960 $retstring .= "</option>";
7961 }
7962 $retstring .= "</select>";
7963
7964 // Year
7965 if ($emptydate || $set_time == -1) {
7966 $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 . '">';
7967 } else {
7968 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7969
7970 $syear = (int) $syear;
7971 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7972 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7973 }
7974 $retstring .= "</select>\n";
7975 }
7976 }
7977 }
7978
7979 if ($d && $h) {
7980 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7981 $retstring .= '<span class="nowraponall">';
7982 }
7983
7984 if ($h) {
7985 $hourstart = 0;
7986 $hourend = 24;
7987 if ($openinghours != '') {
7988 $openinghours = explode(',', $openinghours);
7989 $hourstart = $openinghours[0];
7990 $hourend = $openinghours[1];
7991 if ($hourend < $hourstart) {
7992 $hourend = $hourstart;
7993 }
7994 }
7995
7996 // Show hour
7997 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75 '; // Note maxwidth50 generates truncated number on some desktops even with same version of chrome that works on others
7998 $retstring .= ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7999 if ($emptyhours) {
8000 $retstring .= '<option value="-1">&nbsp;</option>';
8001 }
8002 for ($hour = $hourstart; $hour < $hourend; $hour++) {
8003 if (strlen($hour) < 2) {
8004 $hour = "0" . $hour;
8005 }
8006 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
8007 $retstring .= '</option>';
8008 }
8009 $retstring .= '</select>';
8010
8011 if ($disabled) {
8012 $retstring .= '<input type="hidden" id="' . $prefix . 'hour" name="' . $prefix . 'hour" value="' . $shour . '">' . "\n";
8013 }
8014 if ($m) {
8015 $retstring .= ":";
8016 }
8017 }
8018
8019 if ($m) {
8020 // Show minutes
8021 $retstring .= '<select ' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75 '; // Note maxwidth50 generates truncated number on some desktops even with same version of chrome that works on others
8022 $retstring .= ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
8023 if ($emptyhours) {
8024 $retstring .= '<option value="-1">&nbsp;</option>';
8025 }
8026 for ($min = 0; $min < 60; $min += $stepminutes) {
8027 $min_str = sprintf("%02d", $min);
8028 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
8029 }
8030 $retstring .= '</select>';
8031 if ($disabled) {
8032 $retstring .= '<input type="hidden" id="' . $prefix . 'min" name="' . $prefix . 'min" value="' . $smin . '">' . "\n";
8033 }
8034 // Add also seconds
8035 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
8036 }
8037
8038 if ($d && $h) {
8039 $retstring .= '</span>';
8040 }
8041
8042 // Add a "Now" link
8043 if (!empty($conf->use_javascript_ajax) && $addnowlink && !$disabled) {
8044 // Script which will be inserted in the onClick of the "Now" link
8045 $reset_scripts = "";
8046 if ($addnowlink == 2) { // local computer time
8047 // pad add leading 0 on numbers
8048 $reset_scripts .= "Number.prototype.pad = function(size) {
8049 var s = String(this);
8050 while (s.length < (size || 2)) {s = '0' + s;}
8051 return s;
8052 };
8053 var d = new Date();";
8054 }
8055
8056 // Generate the date part, depending on the use or not of the javascript calendar
8057 if ($addnowlink == 1) { // server time expressed in user time setup
8058 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
8059 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
8060 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
8061 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
8062 } elseif ($addnowlink == 2) {
8063 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
8064 * This break application for foreign languages.
8065 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
8066 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
8067 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
8068 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
8069 */
8070 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
8071 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
8072 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
8073 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
8074 }
8075 /*if ($usecalendar == "eldy")
8076 {
8077 $base=DOL_URL_ROOT.'/core/';
8078 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
8079 }
8080 else
8081 {
8082 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
8083 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
8084 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
8085 }*/
8086 // Update the hour part
8087 if ($h) {
8088 if ($fullday) {
8089 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
8090 }
8091 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
8092 if ($addnowlink == 1) {
8093 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
8094 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
8095 } elseif ($addnowlink == 2) {
8096 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
8097 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
8098 }
8099
8100 if ($fullday) {
8101 $reset_scripts .= ' } ';
8102 }
8103 }
8104 // Update the minute part
8105 if ($m) {
8106 if ($fullday) {
8107 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
8108 }
8109 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
8110 if ($addnowlink == 1) {
8111 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
8112 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
8113 } elseif ($addnowlink == 2) {
8114 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
8115 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
8116 }
8117 if ($fullday) {
8118 $reset_scripts .= ' } ';
8119 }
8120 }
8121 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
8122 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8123 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
8124 $retstring .= $langs->trans("Now");
8125 $retstring .= '</button> ';
8126 }
8127 }
8128
8129 // Add a "Plus one hour" link
8130 if ($conf->use_javascript_ajax && $addplusone && !$disabled) {
8131 // Script which will be inserted in the onClick of the "Add plusone" link
8132 $reset_scripts = "";
8133
8134 // Generate the date part, depending on the use or not of the javascript calendar
8135 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
8136 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
8137 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
8138 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
8139 // Update the hour part
8140 if ($h) {
8141 if ($fullday) {
8142 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
8143 }
8144 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
8145 if ($fullday) {
8146 $reset_scripts .= ' } ';
8147 }
8148 }
8149 // Update the minute part
8150 if ($m) {
8151 if ($fullday) {
8152 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
8153 }
8154 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
8155 if ($fullday) {
8156 $reset_scripts .= ' } ';
8157 }
8158 }
8159 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
8160 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
8161 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
8162 $retstring .= $langs->trans("DateStartPlusOne");
8163 $retstring .= '</button> ';
8164 }
8165 }
8166
8167 // Add a link to set data
8168 if ($conf->use_javascript_ajax && !empty($adddateof) && !$disabled) {
8169 if (!is_array($adddateof)) {
8170 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
8171 } else {
8172 $arrayofdateof = $adddateof;
8173 }
8174 foreach ($arrayofdateof as $valuedateof) {
8175 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
8176 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
8177 $tmparray = dol_getdate($tmpadddateof);
8178 if (empty($tmplabeladddateof)) {
8179 $tmplabeladddateof = $langs->trans("DateInvoice");
8180 }
8181 $reset_scripts = 'console.log(\'Click on now link\'); ';
8182 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
8183 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
8184 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
8185 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
8186 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
8187 }
8188 }
8189
8190 return $retstring;
8191 }
8192
8202 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array(), $morecss = 'minwidth75 maxwidth100')
8203 {
8204 global $langs;
8205
8206 $TDurationTypes = $this->getDurationTypes($langs);
8207
8208 // Removed undesired duration types
8209 foreach ($excludetypes as $value) {
8210 unset($TDurationTypes[$value]);
8211 }
8212
8213 $retstring = '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
8214 foreach ($TDurationTypes as $key => $typeduration) {
8215 $retstring .= '<option value="' . $key . '"';
8216 if ($key == $selected) {
8217 $retstring .= " selected";
8218 }
8219 $retstring .= ">" . $typeduration . "</option>";
8220 }
8221 $retstring .= "</select>";
8222
8223 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
8224
8225 return $retstring;
8226 }
8227
8228 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8229
8243 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
8244 {
8245 // phpcs:enable
8246 global $langs;
8247
8248 $retstring = '<span class="nowraponall">';
8249
8250 $hourSelected = '';
8251 $minSelected = '';
8252
8253 // Hours
8254 if ($iSecond != '') {
8255 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
8256
8257 $hourSelected = convertSecondToTime($iSecond, 'allhour');
8258 $minSelected = convertSecondToTime($iSecond, 'min');
8259 }
8260
8261 if ($typehour == 'select') {
8262 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
8263 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
8264 $retstring .= '<option value="' . $hour . '"';
8265 if (is_numeric($hourSelected) && $hourSelected == $hour) {
8266 $retstring .= " selected";
8267 }
8268 $retstring .= ">" . $hour . "</option>";
8269 }
8270 $retstring .= "</select>";
8271 } elseif ($typehour == 'text' || $typehour == 'textselect') {
8272 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
8273 } else {
8274 return 'BadValueForParameterTypeHour';
8275 }
8276
8277 if ($typehour != 'text') {
8278 $retstring .= ' ' . $langs->trans('HourShort');
8279 } else {
8280 $retstring .= '<span class="">:</span>';
8281 }
8282
8283 // Minutes
8284 if ($minunderhours) {
8285 $retstring .= '<br>';
8286 } else {
8287 if ($typehour != 'text') {
8288 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
8289 }
8290 }
8291
8292 if ($typehour == 'select' || $typehour == 'textselect') {
8293 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
8294 $step = getDolGlobalInt('MAIN_DURATION_STEP');
8295 $duration_step = ($step > 0) ? $step : 5;
8296 for ($min = 0; $min <= 59; $min += $duration_step) {
8297 $retstring .= '<option value="' . $min . '"';
8298 if (is_numeric($minSelected) && $minSelected == $min) {
8299 $retstring .= ' selected';
8300 }
8301 $retstring .= '>' . $min . '</option>';
8302 }
8303 $retstring .= "</select>";
8304 } elseif ($typehour == 'text') {
8305 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
8306 }
8307
8308 if ($typehour != 'text') {
8309 $retstring .= ' ' . $langs->trans('MinuteShort');
8310 }
8311
8312 $retstring .= "</span>";
8313
8314 if (!empty($nooutput)) {
8315 return $retstring;
8316 }
8317
8318 print $retstring;
8319
8320 return '';
8321 }
8322
8342 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)
8343 {
8344 global $langs, $conf;
8345
8346 $out = '';
8347
8348 // check parameters
8349 if (is_null($ajaxoptions)) {
8350 $ajaxoptions = array();
8351 }
8352
8353 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8354 $placeholder = '';
8355
8356 if ($selected && empty($selected_input_value)) {
8357 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
8358 $tickettmpselect = new Ticket($this->db);
8359 $tickettmpselect->fetch((int) $selected);
8360 $selected_input_value = $tickettmpselect->ref;
8361 unset($tickettmpselect);
8362 }
8363
8364 $urloption = '';
8365 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8366
8367 if (empty($hidelabel)) {
8368 $out .= $langs->trans("RefOrLabel") . ' : ';
8369 } elseif ($hidelabel > 1) {
8370 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8371 if ($hidelabel == 2) {
8372 $out .= img_picto($langs->trans("Search"), 'search');
8373 }
8374 }
8375 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8376 if ($hidelabel == 3) {
8377 $out .= img_picto($langs->trans("Search"), 'search');
8378 }
8379 } else {
8380 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8381 }
8382
8383 if (empty($nooutput)) {
8384 print $out;
8385 } else {
8386 return $out;
8387 }
8388 return '';
8389 }
8390
8391
8408 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8409 {
8410 global $langs;
8411
8412 $out = '';
8413 $outarray = array();
8414
8415 $selectFields = " p.rowid, p.ref, p.message";
8416
8417 $sql = "SELECT ";
8418 $sql .= $selectFields;
8419 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
8420 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
8421
8422 // Add criteria on ref/label
8423 if ($filterkey != '') {
8424 $sql .= ' AND (';
8425 $prefix = getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if TICKET_DONOTSEARCH_ANYWHERE is on
8426 // For natural search
8427 $search_crit = explode(' ', $filterkey);
8428 $i = 0;
8429 if (count($search_crit) > 1) {
8430 $sql .= "(";
8431 }
8432 foreach ($search_crit as $crit) {
8433 if ($i > 0) {
8434 $sql .= " AND ";
8435 }
8436 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8437 $sql .= ")";
8438 $i++;
8439 }
8440 if (count($search_crit) > 1) {
8441 $sql .= ")";
8442 }
8443 $sql .= ')';
8444 }
8445
8446 $sql .= $this->db->plimit($limit, 0);
8447
8448 // Build output string
8449 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
8450 $result = $this->db->query($sql);
8451 if ($result) {
8452 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
8453 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
8454
8455 $num = $this->db->num_rows($result);
8456
8457 $events = array();
8458
8459 if (!$forcecombo) {
8460 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8461 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('TICKET_USE_SEARCH_TO_SELECT'));
8462 }
8463
8464 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8465
8466 $textifempty = '';
8467 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8468 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8469 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8470 if ($showempty && !is_numeric($showempty)) {
8471 $textifempty = $langs->trans($showempty);
8472 } else {
8473 $textifempty .= $langs->trans("All");
8474 }
8475 } else {
8476 if ($showempty && !is_numeric($showempty)) {
8477 $textifempty = $langs->trans($showempty);
8478 }
8479 }
8480 if ($showempty) {
8481 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8482 }
8483
8484 $i = 0;
8485 while ($num && $i < $num) {
8486 $opt = '';
8487 $optJson = array();
8488 $objp = $this->db->fetch_object($result);
8489
8490 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
8491 '@phan-var-force array{key:string,value:mixed,type:int} $optJson';
8492 // Add new entry
8493 // "key" value of json key array is used by jQuery automatically as selected value
8494 // "label" value of json key array is used by jQuery automatically as text for combo box
8495 $out .= $opt;
8496 array_push($outarray, $optJson);
8497
8498 $i++;
8499 }
8500
8501 $out .= '</select>';
8502
8503 $this->db->free($result);
8504
8505 if (empty($outputmode)) {
8506 return $out;
8507 }
8508 return $outarray;
8509 } else {
8510 dol_print_error($this->db);
8511 }
8512
8513 return array();
8514 }
8515
8527 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8528 {
8529 $outkey = '';
8530 $outref = '';
8531 $outtype = '';
8532
8533 $outkey = $objp->rowid;
8534 $outref = $objp->ref;
8535
8536 $opt = '<option value="' . $objp->rowid . '"';
8537 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8538 $opt .= '>';
8539 $opt .= $objp->ref;
8540 $objRef = $objp->ref;
8541 if (!empty($filterkey) && $filterkey != '') {
8542 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8543 }
8544
8545 $opt .= "</option>\n";
8546 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8547 }
8548
8568 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)
8569 {
8570 global $langs, $conf;
8571
8572 $out = '';
8573
8574 // check parameters
8575 if (is_null($ajaxoptions)) {
8576 $ajaxoptions = array();
8577 }
8578
8579 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8580 $placeholder = '';
8581
8582 if ($selected && empty($selected_input_value)) {
8583 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8584 $projecttmpselect = new Project($this->db);
8585 $projecttmpselect->fetch((int) $selected);
8586 $selected_input_value = $projecttmpselect->ref;
8587 unset($projecttmpselect);
8588 }
8589
8590 $urloption = '';
8591 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8592
8593 if (empty($hidelabel)) {
8594 $out .= $langs->trans("RefOrLabel") . ' : ';
8595 } elseif ($hidelabel > 1) {
8596 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8597 if ($hidelabel == 2) {
8598 $out .= img_picto($langs->trans("Search"), 'search');
8599 }
8600 }
8601 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8602 if ($hidelabel == 3) {
8603 $out .= img_picto($langs->trans("Search"), 'search');
8604 }
8605 } else {
8606 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8607 }
8608
8609 if (empty($nooutput)) {
8610 print $out;
8611 } else {
8612 return $out;
8613 }
8614 return '';
8615 }
8616
8633 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8634 {
8635 global $langs, $conf;
8636
8637 $out = '';
8638 $outarray = array();
8639
8640 $selectFields = " p.rowid, p.ref";
8641
8642 $sql = "SELECT ";
8643 $sql .= $selectFields;
8644 $sql .= " FROM " . $this->db->prefix() . "projet as p";
8645 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
8646
8647 // Add criteria on ref/label
8648 if ($filterkey != '') {
8649 $sql .= ' AND (';
8650 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8651 // For natural search
8652 $search_crit = explode(' ', $filterkey);
8653 $i = 0;
8654 if (count($search_crit) > 1) {
8655 $sql .= "(";
8656 }
8657 foreach ($search_crit as $crit) {
8658 if ($i > 0) {
8659 $sql .= " AND ";
8660 }
8661 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8662 $sql .= "";
8663 $i++;
8664 }
8665 if (count($search_crit) > 1) {
8666 $sql .= ")";
8667 }
8668 $sql .= ')';
8669 }
8670
8671 $sql .= $this->db->plimit($limit, 0);
8672
8673 // Build output string
8674 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
8675 $result = $this->db->query($sql);
8676 if ($result) {
8677 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8678 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
8679
8680 $num = $this->db->num_rows($result);
8681
8682 $events = array();
8683
8684 if (!$forcecombo) {
8685 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8686 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8687 }
8688
8689 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8690
8691 $textifempty = '';
8692 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8693 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8694 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8695 if ($showempty && !is_numeric($showempty)) {
8696 $textifempty = $langs->trans($showempty);
8697 } else {
8698 $textifempty .= $langs->trans("All");
8699 }
8700 } else {
8701 if ($showempty && !is_numeric($showempty)) {
8702 $textifempty = $langs->trans($showempty);
8703 }
8704 }
8705 if ($showempty) {
8706 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8707 }
8708
8709 $i = 0;
8710 while ($num && $i < $num) {
8711 $opt = '';
8712 $optJson = array();
8713 $objp = $this->db->fetch_object($result);
8714
8715 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
8716 // Add new entry
8717 // "key" value of json key array is used by jQuery automatically as selected value
8718 // "label" value of json key array is used by jQuery automatically as text for combo box
8719 $out .= $opt;
8720 array_push($outarray, $optJson);
8721
8722 $i++;
8723 }
8724
8725 $out .= '</select>';
8726
8727 $this->db->free($result);
8728
8729 if (empty($outputmode)) {
8730 return $out;
8731 }
8732 return $outarray;
8733 } else {
8734 dol_print_error($this->db);
8735 }
8736
8737 return array();
8738 }
8739
8753 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8754 {
8755 $outkey = '';
8756 $outref = '';
8757 $outtype = '';
8758
8759 $label = $objp->label;
8760
8761 $outkey = $objp->rowid;
8762 $outref = $objp->ref;
8763 $outlabel = $objp->label;
8764 $outtype = $objp->fk_product_type;
8765
8766 $opt = '<option value="' . $objp->rowid . '"';
8767 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8768 $opt .= '>';
8769 $opt .= $objp->ref;
8770 $objRef = $objp->ref;
8771 if (!empty($filterkey) && $filterkey != '') {
8772 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8773 }
8774
8775 $opt .= "</option>\n";
8776 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8777 }
8778
8779
8800 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, $excludeids = array())
8801 {
8802 global $langs, $conf;
8803
8804 $out = '';
8805
8806 // check parameters
8807 if (is_null($ajaxoptions)) {
8808 $ajaxoptions = array();
8809 }
8810
8811 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8812 $placeholder = '';
8813
8814 if ($selected && empty($selected_input_value)) {
8815 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8816 $adherenttmpselect = new Adherent($this->db);
8817 $adherenttmpselect->fetch((int) $selected);
8818 $selected_input_value = $adherenttmpselect->ref;
8819 unset($adherenttmpselect);
8820 }
8821
8822 $urloption = '';
8823
8824 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8825
8826 if (empty($hidelabel)) {
8827 $out .= $langs->trans("RefOrLabel") . ' : ';
8828 } elseif ($hidelabel > 1) {
8829 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8830 if ($hidelabel == 2) {
8831 $out .= img_picto($langs->trans("Search"), 'search');
8832 }
8833 }
8834 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8835 if ($hidelabel == 3) {
8836 $out .= img_picto($langs->trans("Search"), 'search');
8837 }
8838 } else {
8839 $filterkey = '';
8840
8841 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss, $excludeids);
8842 }
8843
8844 if (empty($nooutput)) {
8845 print $out;
8846 } else {
8847 return $out;
8848 }
8849 return '';
8850 }
8851
8869 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $excludeids = array())
8870 {
8871 global $langs, $conf;
8872
8873 $out = '';
8874 $outarray = array();
8875
8876 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8877
8878 $sql = "SELECT ";
8879 $sql .= $selectFields;
8880 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8881 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8882
8883 // Add criteria on ref/label
8884 if ($filterkey != '') {
8885 $sql .= ' AND (';
8886 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8887 // For natural search
8888 $search_crit = explode(' ', $filterkey);
8889 $i = 0;
8890 if (count($search_crit) > 1) {
8891 $sql .= "(";
8892 }
8893 foreach ($search_crit as $crit) {
8894 if ($i > 0) {
8895 $sql .= " AND ";
8896 }
8897 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8898 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8899 $i++;
8900 }
8901 if (count($search_crit) > 1) {
8902 $sql .= ")";
8903 }
8904 $sql .= ')';
8905 }
8906 if ($status != -1) {
8907 $sql .= ' AND statut = ' . ((int) $status);
8908 }
8909 if (!empty($excludeids)) {
8910 $sql .= " AND p.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
8911 }
8912 $sql .= $this->db->plimit($limit, 0);
8913
8914 // Build output string
8915 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8916 $result = $this->db->query($sql);
8917 if ($result) {
8918 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8919 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8920
8921 $num = $this->db->num_rows($result);
8922
8923 $events = array();
8924
8925 if (!$forcecombo) {
8926 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8927 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8928 }
8929
8930 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8931
8932 $textifempty = '';
8933 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8934 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8935 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8936 if ($showempty && !is_numeric($showempty)) {
8937 $textifempty = $langs->trans($showempty);
8938 } else {
8939 $textifempty .= $langs->trans("All");
8940 }
8941 } else {
8942 if ($showempty && !is_numeric($showempty)) {
8943 $textifempty = $langs->trans($showempty);
8944 }
8945 }
8946 if ($showempty) {
8947 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8948 }
8949
8950 $i = 0;
8951 while ($num && $i < $num) {
8952 $opt = '';
8953 $optJson = array();
8954 $objp = $this->db->fetch_object($result);
8955
8956 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8957
8958 // Add new entry
8959 // "key" value of json key array is used by jQuery automatically as selected value
8960 // "label" value of json key array is used by jQuery automatically as text for combo box
8961 $out .= $opt;
8962 array_push($outarray, $optJson);
8963
8964 $i++;
8965 }
8966
8967 $out .= '</select>';
8968
8969 $this->db->free($result);
8970
8971 if (empty($outputmode)) {
8972 return $out;
8973 }
8974 return $outarray;
8975 } else {
8976 dol_print_error($this->db);
8977 }
8978
8979 return array();
8980 }
8981
8993 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8994 {
8995 $outkey = '';
8996 $outlabel = '';
8997 $outtype = '';
8998
8999 $outkey = $objp->rowid;
9000 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
9001 $outtype = $objp->fk_adherent_type;
9002
9003 $opt = '<option value="' . $objp->rowid . '"';
9004 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
9005 $opt .= '>';
9006 if (!empty($filterkey) && $filterkey != '') {
9007 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
9008 }
9009 $opt .= $outlabel;
9010 $opt .= "</option>\n";
9011
9012 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
9013 }
9014
9036 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
9037 {
9038 global $conf, $extrafields, $user;
9039
9040 // Example of common usage for a link to a thirdparty
9041
9042 // We got this in a modulebuilder form of "MyObject" of module "mymodule".
9043 // When ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...), we have
9044 // $objectdesc = 'Societe'
9045 // $objectfield = Method 1: 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc'])
9046 // Method 2 recommended (it can be the array): array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
9047
9048 // We got this when showing an extrafields on resource that is a link to societe
9049 // When extrafields 'link_to_societe' for object Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))', we have
9050 // $objectdesc = 'Societe'
9051 // $objectfield = Method 1: 'resource:options_link_to_societe'
9052 // Method 2 recommended (it can be the array): array("type"=>'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
9053
9054 // With old usage:
9055 // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))'
9056 // $objectfield = ''
9057
9058 //var_dump($objectdesc.' '.$objectfield);
9059 //debug_print_backtrace();
9060
9061 $objectdescorig = $objectdesc;
9062 $objecttmp = null;
9063 $InfoFieldList = array();
9064 $classname = '';
9065 $filter = ''; // Ensure filter has value (for static analysis)
9066 $sortfield = ''; // Ensure filter has value (for static analysis)
9067
9068 if (is_array($objectfield)) { // objectfield is an array
9069 $objectdesc = $objectfield['type'];
9070 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
9071 } elseif ($objectfield) { // objectfield is a string. We must retrieve the objectdesc from the field or extrafield. Deprecated, it is better to provide the array record directly.
9072 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
9073 $tmparray = explode(':', $objectfield);
9074
9075 // Get instance of object from $element
9076 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
9077
9078 if (is_object($objectforfieldstmp)) {
9079 $objectdesc = '';
9080
9081 $reg = array();
9082 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
9083 // For a property in extrafields
9084 $key = $reg[1];
9085 // fetch optionals attributes and labels
9086 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
9087
9088 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
9089 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
9090 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
9091 $objectdesc = $tmpextrafields[0];
9092 }
9093 }
9094 } else {
9095 // For a property in ->fields
9096 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
9097 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
9098 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
9099 }
9100 }
9101 }
9102 }
9103
9104 if ($objectdesc) {
9105 // Example of value for $objectdesc:
9106 // Bom:bom/class/bom.class.php:0:t.status=1
9107 // Bom:bom/class/bom.class.php:0:t.status=1:ref
9108 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
9109 $InfoFieldList = explode(":", $objectdesc, 4);
9110 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
9111 $reg = array();
9112 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
9113 $InfoFieldList[4] = $reg[1]; // take the sort field
9114 }
9115 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
9116
9117 $classname = $InfoFieldList[0];
9118 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
9119 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
9120 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
9121 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
9122
9123 // Load object according to $id and $element
9124 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
9125
9126 // Fallback to another solution to get $objecttmp
9127 if (empty($objecttmp) && !empty($classpath)) {
9128 dol_include_once($classpath);
9129
9130 if ($classname && class_exists($classname)) {
9131 $objecttmp = new $classname($this->db);
9132 }
9133 }
9134 }
9135
9136 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
9137 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
9138 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
9139 $filter = str_replace(
9140 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
9141 array($conf->entity, $sharedentities, $user->id),
9142 $filter
9143 );
9144
9145 if (!is_object($objecttmp)) {
9146 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.(is_array($objectfield) ? 'array' : $objectfield).', objectdesc='.$objectdesc, LOG_WARNING);
9147 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.(is_array($objectfield) ? 'array' : $objectfield).', objectdesc='.$objectdesc;
9148 }
9149 '@phan-var-force CommonObject $objecttmp';
9151 //var_dump($filter);
9152 $prefixforautocompletemode = $objecttmp->element;
9153 if ($prefixforautocompletemode == 'societe') {
9154 $prefixforautocompletemode = 'company';
9155 }
9156 if ($prefixforautocompletemode == 'product') {
9157 $prefixforautocompletemode = 'produit';
9158 }
9159
9160 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
9161
9162 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
9163
9164 // Generate the combo HTML component
9165 $out = '';
9166 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
9167 // No immediate load of all database
9168 $placeholder = '';
9169
9170 if ($preSelectedValue && empty($selected_input_value)) {
9171 $objecttmp->fetch($preSelectedValue);
9172 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
9173
9174 $oldValueForShowOnCombobox = 0;
9175 foreach ($objecttmp->fields as $fieldK => $fielV) {
9176 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
9177 continue;
9178 }
9179
9180 if (!$oldValueForShowOnCombobox) {
9181 $selected_input_value = '';
9182 }
9183
9184 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
9185 $selected_input_value .= $objecttmp->$fieldK;
9186 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
9187 }
9188 }
9189
9190 // Set url and param to call to get json of the search results
9191 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
9192 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . (is_scalar($objectfield) ? '&objectfield='.urlencode($objectfield) : '') . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
9193 //$urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1'.(is_scalar($objectfield) ? '&objectfield='.urlencode($objectfield) : '') . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
9194
9195 // Activate the auto complete using ajax call.
9196 $out .= ajax_autocompleter((string) $preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalInt($confkeyforautocompletemode), 0);
9197 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
9198 $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) . '"' : '') . ' />';
9199 } else {
9200 // Immediate load of table record.
9201 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
9202 }
9203
9204 return $out;
9205 }
9206
9207
9229 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '', $sortorder = 'ASC')
9230 {
9231 global $langs, $user, $hookmanager;
9232
9233 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
9234
9235 $prefixforautocompletemode = $objecttmp->element;
9236 if ($prefixforautocompletemode == 'societe') {
9237 $prefixforautocompletemode = 'company';
9238 }
9239 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
9240
9241 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
9242 $tmpfieldstoshow = '';
9243 foreach ($objecttmp->fields as $key => $val) {
9244 if (! (int) dol_eval((string) $val['enabled'], 1, 1, '1')) {
9245 continue;
9246 }
9247 if (!empty($val['showoncombobox'])) {
9248 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
9249 }
9250 }
9251 if ($tmpfieldstoshow) {
9252 $fieldstoshow = $tmpfieldstoshow;
9253 }
9254 } elseif ($objecttmp->element === 'category') {
9255 $fieldstoshow = 't.label';
9256 } else {
9257 // For backward compatibility
9258 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'enabled' => 1, 'position' => 10, 'visible' => 4, 'showoncombobox' => 1);
9259 }
9260
9261 if (empty($fieldstoshow)) {
9262 if (!empty($objecttmp->parent_element)) {
9263 $fieldstoshow = 'o.ref';
9264 if (empty($sortfield)) {
9265 $sortfield = 'o.ref';
9266 }
9267 if (in_array($objecttmp->element, ['commandedet', 'propaldet', 'facturedet', 'expeditiondet'])) {
9268 $fieldstoshow .= ',p.ref AS p_ref,p.label,t.description';
9269 $sortfield .= ', p.ref';
9270 }
9271 } elseif (isset($objecttmp->fields['ref'])) {
9272 $fieldstoshow = 't.ref';
9273 } else {
9274 $langs->load("errors");
9275 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
9276 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
9277 }
9278 }
9279
9280 $out = '';
9281 $outarray = array();
9282 $tmparray = array();
9283
9284 $num = 0;
9285
9286 // Search data
9287 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . " as t";
9288 if (!empty($objecttmp->isextrafieldmanaged)) {
9289 $extrafieldTable = $objecttmp->table_element;
9290 if ($extrafieldTable == 'categorie') {
9291 $extrafieldTable = 'categories'; // For compatibility
9292 }
9293 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($extrafieldTable) . "_extrafields as e ON t.rowid = e.fk_object";
9294 }
9295 if (!empty($objecttmp->parent_element)) { // If parent_element is defined
9296 '@phan-var-force CommonObjectLine $objecttmp';
9297 $parent_properties = getElementProperties($objecttmp->parent_element);
9298 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($parent_properties['table_element']) . " as o ON o.rowid = t.".$objecttmp->fk_parent_attribute;
9299 }
9300 if (!empty($objecttmp->parent_element) && in_array($objecttmp->parent_element, ['commande', 'propal', 'facture', 'expedition'])) {
9301 $sql .= " LEFT JOIN " . $this->db->prefix() . "product as p ON p.rowid = t.fk_product";
9302 }
9303 if (!empty($objecttmp->ismultientitymanaged)) {
9304 if ($objecttmp->ismultientitymanaged == 1) { // @phan-suppress-current-line PhanPluginEmptyStatementIf
9305 // No need to join/link another table
9306 }
9307 if (!is_numeric($objecttmp->ismultientitymanaged)) {
9308 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
9309 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($tmparray[1]) . " as parenttable ON parenttable.rowid = t." . $this->db->sanitize($tmparray[0]);
9310 }
9311 }
9312
9313 // Add where from hooks
9314 $parameters = array(
9315 'object' => $objecttmp,
9316 'htmlname' => $htmlname,
9317 'filter' => $filter,
9318 'searchkey' => $searchkey
9319 );
9320
9321 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
9322 if (!empty($hookmanager->resPrint)) {
9323 $sql .= $hookmanager->resPrint;
9324 } else {
9325 $sql .= " WHERE 1=1";
9326
9327 // If table need a multientity restriction
9328 if (!empty($objecttmp->ismultientitymanaged)) {
9329 if ($objecttmp->ismultientitymanaged == 1) {
9330 $sql .= " AND t.entity IN (" . getEntity($objecttmp->element) . ")";
9331 }
9332 if (!is_numeric($objecttmp->ismultientitymanaged)) {
9333 $sql .= " AND parenttable.entity = t." . $this->db->sanitize($tmparray[0]);
9334 }
9335 // If the parent table is llx_societe and user is not an external user (a more robust test done later for external users),
9336 // then we must also check that user has permissions
9337 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
9338 if (!$user->hasRight('societe', 'client', 'voir') && empty($user->socid)) {
9339 $sql .= " AND EXISTS (SELECT sc.rowid FROM ".$this->db->prefix() . "societe_commerciaux as sc";
9340 $sql .= " WHERE sc.fk_soc = t.fk_soc AND sc.fk_user = ".((int) $user->id).")";
9341 }
9342 }
9343 }
9344
9345 // If user is external user, we must also make a test on llx_societe_commerciaux
9346 if (!empty($user->socid)) {
9347 if ($objecttmp->element == 'societe') {
9348 $sql .= " AND t.rowid = " . ((int) $user->socid);
9349 } elseif (!empty($objecttmp->fields['fk_soc']) || !empty($objecttmp->fields['t.fk_soc']) || property_exists($objecttmp, 'fk_soc') || property_exists($objecttmp, 'socid')) {
9350 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
9351 }
9352 }
9353
9354 $splittedfieldstoshow = explode(',', $fieldstoshow);
9355 foreach ($splittedfieldstoshow as &$field2) {
9356 if (is_numeric($pos = strpos($field2, ' '))) {
9357 $field2 = substr($field2, 0, $pos);
9358 }
9359 }
9360 if ($searchkey != '') {
9361 $sql .= natural_search($splittedfieldstoshow, $searchkey);
9362 }
9363
9364 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
9365 $errormessage = '';
9366 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
9367 if ($errormessage) {
9368 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
9369 }
9370 }
9371 }
9372 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, $sortorder);
9373 //$sql.=$this->db->plimit($limit, 0);
9374 //print $sql;
9375
9376 // Build output string
9377 $resql = $this->db->query($sql);
9378 if ($resql) {
9379 // Construct $out and $outarray
9380 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
9381
9382 // 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
9383 $textifempty = '&nbsp;';
9384
9385 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
9386 if (getDolGlobalInt($confkeyforautocompletemode)) {
9387 if ($showempty && !is_numeric($showempty)) {
9388 $textifempty = $langs->trans($showempty);
9389 } else {
9390 $textifempty .= $langs->trans("All");
9391 }
9392 }
9393 if ($showempty) {
9394 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
9395 }
9396
9397 $num = $this->db->num_rows($resql);
9398 $i = 0;
9399 if ($num) {
9400 while ($i < $num) {
9401 $obj = $this->db->fetch_object($resql);
9402 $label = '';
9403 $labelhtml = '';
9404 $tmparray = explode(',', $fieldstoshow);
9405 $oldvalueforshowoncombobox = 0;
9406 foreach ($tmparray as $key => $val) {
9407 $val = preg_replace('/(t|p|o)\./', '', $val);
9408 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
9409 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
9410 $label .= $obj->$val;
9411 $labelhtml .= $obj->$val;
9412
9413 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
9414 }
9415 if (empty($outputmode)) {
9416 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
9417 $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>';
9418 } else {
9419 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
9420 }
9421 } else {
9422 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
9423 }
9424
9425 $i++;
9426 if (($i % 10) == 0) {
9427 $out .= "\n";
9428 }
9429 }
9430 }
9431
9432 $out .= '</select>' . "\n";
9433
9434 if (!$forcecombo) {
9435 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9436 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
9437 }
9438 } else {
9439 dol_print_error($this->db);
9440 }
9441
9442 $this->result = array('nbofelement' => $num);
9443
9444 if ($outputmode) {
9445 return $outarray;
9446 }
9447 return $out;
9448 }
9449
9460 public static function radio($htmlName, $radioItems, $selected = '', $moreGlobalParams = [])
9461 {
9462 // Default parameters for each radio input
9463 $defaultParams = [
9464 'disabled' => false,
9465 'attr' => [
9466 'type' => 'radio',
9467 'name' => $htmlName,
9468 ],
9469 'unescapedAttr' => [],
9470 'attrLabel' => [],
9471 'unescapedAttrLabel' => [],
9472 'labelIsHtml' => false
9473 ];
9474
9475 // Merge global parameters with defaults
9476 $params = array_merge_recursive_distinct($defaultParams, $moreGlobalParams);
9477
9478 $out = '';
9479 if (!empty($radioItems)) {
9480 foreach ($radioItems as $key => $item) {
9481 // Normalize item to array structure if it's a simple string
9482 if (!is_array($item)) {
9483 $item = [
9484 'attr' => [
9485 'value' => $key,
9486 ],
9487 'label' => $item
9488 ];
9489 }
9490
9491 // Default properties for individual item
9492 $defaultItem = [
9493 'attr' => [
9494 'value' => !isset($item['attr']['value']) ? $key : '',
9495 ],
9496 'label' => '',
9497 ];
9498
9499 // Merge defaults with global params and item-specific properties
9500 $defaultItem = array_merge_recursive_distinct($params, $defaultItem);
9501 $item = array_merge_recursive_distinct($defaultItem, $item);
9502
9503 // Determine if this radio should be checked
9504 if ((is_array($selected) && in_array($item['attr']['value'], $selected, true)) || $selected === $item['attr']['value']) {
9505 $item['attr']['checked'] = true;
9506 }
9507
9508 // Build HTML attributes for input and label
9509 $inputAttributes = implode(' ', commonHtmlAttributeBuilder($item['attr'], $item['unescapedAttr']));
9510 $labelAttributes = implode(' ', commonHtmlAttributeBuilder($item['attrLabel'], $item['unescapedAttrLabel']));
9511
9512 // prevent accidental Xss todo : escape $item['label'] but html friendly compatible
9513 $text = $item['labelIsHtml'] ? $item['label'] : htmlspecialchars($item['label'], ENT_QUOTES | ENT_SUBSTITUTE);
9514
9515 // Generate HTML
9516 $out .= '<label ' . $labelAttributes . '><input ' . $inputAttributes . ' /> ' . $text . '</label> ';
9517 }
9518 }
9519
9520 return $out;
9521 }
9522
9523
9547 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)
9548 {
9549 global $conf, $langs;
9550
9551 // Do we want a multiselect ?
9552 //$jsbeautify = 0;
9553 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
9554 $jsbeautify = 1;
9555
9556 if ($value_as_key) {
9557 $array = array_combine($array, $array);
9558 }
9559
9560 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
9561
9562 $out = '';
9563
9564 if ($addjscombo < 0) {
9565 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9566 $addjscombo = 1;
9567 } else {
9568 $addjscombo = 0;
9569 }
9570 }
9571 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
9572 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
9573 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
9574 $out .= '>'."\n";
9575
9576 if ($show_empty) {
9577 $textforempty = ' ';
9578 if (!empty($conf->use_javascript_ajax)) {
9579 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
9580 }
9581 if (!is_numeric($show_empty)) {
9582 $textforempty = $show_empty;
9583 }
9584 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
9585 }
9586 if (is_array($array)) {
9587 // Translate
9588 if ($translate) {
9589 foreach ($array as $key => $value) {
9590 if (!is_array($value)) {
9591 $array[$key] = $langs->trans($value);
9592 } else {
9593 $array[$key]['label'] = $langs->trans($value['label']);
9594 }
9595 }
9596 }
9597 // Sort
9598 if ($sort == 'ASC') {
9599 asort($array);
9600 } elseif ($sort == 'DESC') {
9601 arsort($array);
9602 }
9603
9604 foreach ($array as $key => $tmpvalue) {
9605 if (is_array($tmpvalue)) {
9606 $value = $tmpvalue['label'];
9607 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
9608 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
9609 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
9610 } else {
9611 $value = $tmpvalue;
9612 //$valuehtml = $tmpvalue;
9613 $disabled = '';
9614 $style = '';
9615 }
9616 if (!empty($disablebademail)) {
9617 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
9618 || ($disablebademail == 2 && preg_match('/---/', $value))) {
9619 $disabled = ' disabled';
9620 $style = ' class="warning"';
9621 }
9622 }
9623 if ($key_in_label) {
9624 if (empty($nohtmlescape)) {
9625 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
9626 } else {
9627 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
9628 }
9629 } else {
9630 if (empty($nohtmlescape)) {
9631 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
9632 } else {
9633 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
9634 }
9635 if ($value == '' || $value == '-') {
9636 $selectOptionValue = '&nbsp;';
9637 }
9638 }
9639 $out .= '<option value="' . $key . '"';
9640 $out .= $style . $disabled;
9641 $out .= is_array($tmpvalue) && !empty($tmpvalue['parent']) ? ' parent="' . dolPrintHTMLForAttribute($tmpvalue['parent']) . '"' : '';
9642 if (is_array($id)) {
9643 if (in_array($key, $id) && !$disabled) {
9644 $out .= ' selected'; // To preselect a value
9645 }
9646 } else {
9647 $id = (string) $id; // if $id = 0, then $id = '0'
9648 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
9649 $out .= ' selected'; // To preselect a value
9650 }
9651 }
9652
9653 if (is_array($tmpvalue)) {
9654 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
9655 if ($keyforvalue == 'labelhtml') {
9656 $keyforvalue = 'data-html';
9657 }
9658 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
9659 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
9660 }
9661 }
9662 } elseif (!empty($nohtmlescape)) { // deprecated. Use instead the previous cas, an array with 'data-html', 'data-xxx' ... to use HTML content in the select
9663 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
9664 }
9665
9666 $out .= '>';
9667 $out .= $selectOptionValue;
9668 $out .= "</option>\n";
9669 }
9670 }
9671 $out .= "</select>";
9672
9673 // Add code for jquery to use multiselect
9674 if ($addjscombo && $jsbeautify) {
9675 // Enhance with select2
9676 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9677 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
9678 }
9679
9680 return $out;
9681 }
9682
9701 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
9702 {
9703 global $conf;
9704 global $delayedhtmlcontent; // Will be used later outside of this function
9705
9706 // TODO Use an internal dolibarr component instead of select2
9707 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9708 return '';
9709 }
9710
9711 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
9712
9713 $outdelayed = '';
9714 if (!empty($conf->use_javascript_ajax)) {
9715 $tmpplugin = 'select2';
9716 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9717 <script nonce="' . getNonce() . '">
9718 $(document).ready(function () {
9719
9720 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
9721
9722 $(".' . $htmlname . '").select2({
9723 ajax: {
9724 dir: "ltr",
9725 url: "' . $url . '",
9726 dataType: \'json\',
9727 delay: 250,
9728 data: function (params) {
9729 return {
9730 q: params.term, // search term
9731 page: params.page
9732 }
9733 },
9734 processResults: function (data) {
9735 // parse the results into the format expected by Select2.
9736 // since we are using custom formatting functions we do not need to alter the remote JSON data
9737 //console.log(data);
9738 saveRemoteData = data;
9739 /* format json result for select2 */
9740 result = []
9741 $.each( data, function( key, value ) {
9742 result.push({id: key, text: value.text});
9743 });
9744 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
9745 //console.log(result);
9746 return {results: result, more: false}
9747 },
9748 cache: true
9749 },
9750 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9751 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9752 placeholder: \'' . dol_escape_js($placeholder) . '\',
9753 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9754 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9755 formatResult: function (result, container, query, escapeMarkup) {
9756 return escapeMarkup(result.text);
9757 },
9758 });
9759
9760 ' . ($callurlonselect ? '
9761 /* Code to execute a GET when we select a value */
9762 $(".' . $htmlname . '").change(function() {
9763 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9764 console.log("We select in selectArrayAjax the entry "+selected)
9765 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9766 $.each( saveRemoteData, function( key, value ) {
9767 if (key == selected)
9768 {
9769 console.log("selectArrayAjax - Do a redirect to "+value.url)
9770 location.assign(value.url);
9771 }
9772 });
9773 });' : '') . '
9774
9775 });
9776 </script>';
9777 }
9778
9779 if ($acceptdelayedhtml) {
9780 $delayedhtmlcontent .= $outdelayed;
9781 } else {
9782 $out .= $outdelayed;
9783 }
9784 return $out;
9785 }
9786
9806 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
9807 {
9808 global $conf;
9809 global $delayedhtmlcontent; // Will be used later outside of this function
9810
9811 // TODO Use an internal dolibarr component instead of select2
9812 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9813 return '';
9814 }
9815
9816 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
9817
9818 $formattedarrayresult = array();
9819
9820 foreach ($array as $key => $value) {
9821 $o = new stdClass();
9822 $o->id = $key;
9823 $o->text = $value['text'];
9824 $o->url = $value['url'];
9825 $formattedarrayresult[] = $o;
9826 }
9827
9828 $outdelayed = '';
9829 if (!empty($conf->use_javascript_ajax)) {
9830 $tmpplugin = 'select2';
9831 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9832 <script nonce="' . getNonce() . '">
9833 $(document).ready(function () {
9834 var data = ' . json_encode($formattedarrayresult) . ';
9835
9836 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
9837
9838 $(\'.' . dol_escape_js($htmlname) . '\').select2({
9839 data: data,
9840 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9841 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9842 placeholder: \'' . dol_escape_js($placeholder) . '\',
9843 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9844 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9845 formatResult: function (result, container, query, escapeMarkup) {
9846 return escapeMarkup(result.text);
9847 },
9848 matcher: function (params, data) {
9849
9850 if(! data.id) return null;';
9851
9852 if ($callurlonselect) {
9853 // We forge the url with 'sall='
9854 $outdelayed .= '
9855
9856 var urlBase = data.url;
9857 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
9858 /* console.log("params.term="+params.term); */
9859 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
9860 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
9861 }
9862
9863 if (!$disableFiltering) {
9864 $outdelayed .= '
9865
9866 if(data.text.match(new RegExp(params.term))) {
9867 return data;
9868 }
9869
9870 return null;';
9871 } else {
9872 $outdelayed .= '
9873
9874 return data;';
9875 }
9876
9877 $outdelayed .= '
9878 }
9879 });
9880
9881 ' . ($callurlonselect ? '
9882 /* Code to execute a GET when we select a value */
9883 $(\'.' . dol_escape_js($htmlname) . '\').change(function() {
9884 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9885 console.log("We select "+selected)
9886
9887 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9888 $.each( saveRemoteData, function( key, value ) {
9889 if (key == selected)
9890 {
9891 console.log("selectArrayFilter - Do a redirect to "+value.url)
9892 location.assign(value.url);
9893 }
9894 });
9895 });' : '') . '
9896
9897 });
9898 </script>';
9899 }
9900
9901 if ($acceptdelayedhtml) {
9902 $delayedhtmlcontent .= $outdelayed;
9903 } else {
9904 $out .= $outdelayed;
9905 }
9906 return $out;
9907 }
9908
9927 public static function multiselectarray($htmlname, $array, $selected = array(), $key_in_label = 0, $value_as_key = 0, $morecss = '', $translate = 0, $width = 0, $moreattrib = '', $nu = '', $placeholder = '', $addjscombo = -1)
9928 {
9929 global $conf, $langs;
9930 $out = '';
9931
9932 if ($addjscombo < 0) {
9933 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9934 $addjscombo = 1;
9935 } else {
9936 $addjscombo = 0;
9937 }
9938 }
9939
9940 $useenhancedmultiselect = 0;
9941 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9942 if ($addjscombo) {
9943 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9944 }
9945 }
9946
9947 $out .= '<span class="multiselectarray'.$htmlname.'">';
9948
9949 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9950 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9951 // submitted to nothing.
9952 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9953 // Output select component
9954 $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";
9955 if (is_array($array) && !empty($array)) {
9956 if ($value_as_key) {
9957 $array = array_combine($array, $array);
9958 }
9959
9960 if (!empty($array)) {
9961 foreach ($array as $key => $value) {
9962 $tmpkey = $key;
9963 $tmplabel = $value;
9964 $tmplabelhtml = '';
9965 $tmpcolor = '';
9966 $tmppicto = '';
9967 $tmpdisabled = '';
9968 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9969 $tmpkey = $value['id'];
9970 $tmplabel = empty($value['label']) ? '' : $value['label'];
9971 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']) : $value['labelhtml'];
9972 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9973 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9974 $tmpdisabled = empty($value['disabled']) ? '' : $value['disabled'];
9975 }
9976 $newval = ($translate ? $langs->trans($tmplabel) : $tmplabel);
9977 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9978
9979 $tmplabelhtml = ($translate ? $langs->trans($tmplabelhtml) : $tmplabelhtml);
9980 $tmplabelhtml = ($key_in_label ? $tmpkey . ' - ' . $tmplabelhtml : $tmplabelhtml);
9981
9982 $out .= '<option value="' . $tmpkey . '"';
9983 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9984 $out .= ' selected';
9985 }
9986 $out .= is_array($value) && array_key_exists('parent', $value) && !empty($value['parent']) ? ' parent="' . dolPrintHTMLForAttribute($value['parent']) . '"' : '';
9987 if ($tmpdisabled) {
9988 $out .= ' disabled="disabled"';
9989 }
9990 if (!empty($tmplabelhtml)) {
9991 $out .= ' data-html="' . dolPrintHTMLForAttribute($tmplabelhtml) . '"';
9992 } else {
9993 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9994 $out .= ' data-html="' . dolPrintHTMLForAttribute($tmplabelhtml) . '"';
9995 }
9996 $out .= '>';
9997 $out .= dol_htmlentitiesbr($newval);
9998 $out .= '</option>' . "\n";
9999 }
10000 }
10001 }
10002 $out .= '</select>' . "\n";
10003
10004 $out .= '</span>';
10005
10006 // Add code for jquery to use multiselect
10007 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
10008 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
10009 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
10010 if ($addjscombo == 1) {
10011 $tmpplugin = getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT', (defined('REQUIRE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : 'select2'));
10012
10013 // If property data-html set, we decode html entities and use this.
10014 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
10015 // TODO Move this into common js ?
10016 $out .= 'function formatResult(record, container) {' . "\n";
10017 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
10018 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
10019 $out .= ' }'."\n";
10020 $out .= ' return record.text;';
10021 $out .= '}' . "\n";
10022
10023 $out .= 'function formatSelection(record) {' . "\n";
10024 $out .= ' return record.text;';
10025 $out .= '}' . "\n";
10026
10027 // Load the select2 enhancer
10028 //$out .= 'console.log(\'addjscombo=1 for htmlname=' . dol_escape_js($htmlname) . '\');';
10029 $out .= '$(document).ready(function () {
10030 $(\'#' . dol_escape_js($htmlname) . '\').' . $tmpplugin . '({';
10031 if ($placeholder) {
10032 $out .= '
10033 placeholder: {
10034 id: \'-1\',
10035 text: \''.dol_escape_js($placeholder).'\'
10036 },';
10037 }
10038 $out .= ' dir: \'ltr\',
10039 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
10040 dropdownCssClass: \'' . dol_escape_js($morecss) . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
10041 // Specify format function for dropdown item
10042 formatResult: formatResult,
10043 templateResult: formatResult, /* For 4.0 */
10044 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
10045 // Specify format function for selected item
10046 formatSelection: formatSelection,
10047 templateSelection: formatSelection, /* For 4.0 */
10048 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage
10049 });
10050
10051 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are shown dynamically after load, because select2 set
10052 the size only if component is not hidden by default on load */
10053 $(\'#' . dol_escape_js($htmlname) . ' + .select2\').addClass(\'' . dol_escape_js($morecss) . '\');
10054 });' . "\n";
10055 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
10056 // Add other js lib
10057 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
10058 // ...
10059 $out .= 'console.log(\'addjscombo=2 for htmlname=' . dol_escape_js($htmlname) . '\');';
10060 $out .= '$(document).ready(function () {
10061 $(\'#' . dol_escape_js($htmlname) . '\').multiSelect({
10062 containerHTML: \'<div class="multi-select-container">\',
10063 menuHTML: \'<div class="multi-select-menu">\',
10064 buttonHTML: \'<span class="multi-select-button ' . dol_escape_js($morecss) . '">\',
10065 menuItemHTML: \'<label class="multi-select-menuitem">\',
10066 activeClass: \'multi-select-container--open\',
10067 noneText: \'' . dol_escape_js($placeholder) . '\'
10068 });
10069 })';
10070 }
10071 $out .= '</script>';
10072 }
10073
10074 return $out;
10075 }
10076
10077
10089 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
10090 {
10091 global $conf, $langs, $user;
10092
10093 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
10094 return '';
10095 }
10096 if (empty($array)) {
10097 return '';
10098 }
10099
10100 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
10101
10102 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
10103 $tmparray = explode(',', $user->conf->$tmpvar);
10104 foreach ($array as $key => $val) {
10105 //var_dump($key);
10106 //var_dump($tmparray);
10107 if (in_array($key, $tmparray)) {
10108 $array[$key]['checked'] = 1;
10109 } else {
10110 $array[$key]['checked'] = 0;
10111 }
10112 }
10113 } else { // There is no list of fields already customized for user
10114 foreach ($array as $key => $val) {
10115 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
10116 $array[$key]['checked'] = 0;
10117 }
10118 }
10119 }
10120
10121 $listoffieldsforselection = '';
10122 $listcheckedstring = '';
10123
10124 foreach ($array as $key => $val) {
10125 // var_dump($val);
10126 // var_dump(array_key_exists('enabled', $val));
10127 // var_dump(!$val['enabled']);
10128 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
10129 unset($array[$key]); // We don't want this field
10130 continue;
10131 }
10132 if (!empty($val['type']) && $val['type'] == 'separate') {
10133 // Field remains in array but we don't add it into $listoffieldsforselection
10134 //$listoffieldsforselection .= '<li>-----</li>';
10135 continue;
10136 }
10137 if (!empty($val['label']) && $val['label']) {
10138 if (!empty($val['langfile']) && is_object($langs)) {
10139 $langs->load($val['langfile']);
10140 }
10141
10142 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
10143 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((!array_key_exists('checked', $val) || empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . ' data-position="'.(empty($val['position']) ? '' : $val['position']).'" />';
10144 $listoffieldsforselection .= '<label for="checkbox' . $key . '" class="paddingleft">';
10145 $listoffieldsforselection .= dolPrintHTML(dol_string_nohtmltag($langs->trans($val['label'])));
10146 $listoffieldsforselection .= '</label></li>';
10147 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
10148 }
10149 }
10150
10151 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
10152
10153 <dl class="dropdown">
10154 <dt>
10155 <a href="#' . $htmlname . '" class="multiselectpicto">
10156 ' . img_picto('', 'list') . '
10157 </a>
10158 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
10159 </dt>
10160 <dd class="dropdowndd">
10161 <div class="multiselectcheckbox'.$htmlname.'">
10162 <ul class="'.$htmlname.(((string) $pos == '1' || (string) $pos == 'left') ? 'left' : '').'">
10163 <li class="liinputsearch">
10164 <input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'">
10165 </li>
10166 '.$listoffieldsforselection.'
10167 </ul>
10168 </div>
10169 </dd>
10170 </dl>
10171
10172 <script nonce="' . getNonce() . '" type="text/javascript">
10173 jQuery(document).ready(function () {
10174 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on("click", function () {
10175 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
10176
10177 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
10178
10179 var title = $(this).val() + ",";
10180 if ($(this).is(\':checked\')) {
10181 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
10182 }
10183 else {
10184 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
10185 }
10186 // Now, we submit page
10187 //$(this).parents(\'form:first\').submit();
10188 });
10189
10190 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
10191 console.log("keyup on inputsearch_dropdownselectedfields");
10192 var value = $(this).val().toLowerCase();
10193 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
10194 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
10195 });
10196 });
10197 ';
10198 if (empty($conf->browser->layout) || $conf->browser->layout != 'phone') {
10199 $out .= '
10200 $(".dropdown dt a").on("click", function () {
10201 console.log("Click on dropdown, we set focus to search field");
10202 setTimeout(() => { $(\'.inputsearch_dropdownselectedfields\').focus(); }, 200);
10203 });';
10204 }
10205 $out .= '
10206 });
10207 </script>
10208
10209 ';
10210 return $out;
10211 }
10212
10222 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
10223 {
10224 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
10225
10226 $cat = new Categorie($this->db);
10227 $categories = $cat->containing($id, $type);
10228
10229 if ($rendermode == 1) {
10230 $toprint = array();
10231 foreach ($categories as $c) {
10232 $ways = $c->print_all_ways('auto', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
10233 foreach ($ways as $way) {
10234 $color = $c->color;
10235 $sfortag = '<li class="select2-search-choice-dolibarr noborderoncategories'.(empty($toprint) ? ' nomarginleft' : '').'"' . ($color ? ' style="background: #' . $color . ';"' : ' style="background: #bbb"') . '>';
10236 $sfortag .= $way;
10237 $sfortag .= '</li>';
10238 $toprint[] = $sfortag;
10239 }
10240 }
10241 if (empty($toprint)) {
10242 return '';
10243 } else {
10244 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
10245 }
10246 }
10247
10248 if ($rendermode == 0) {
10249 $arrayselected = array();
10250 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
10251 foreach ($categories as $c) {
10252 $arrayselected[(string) $c->id] = (string) $c->id;
10253 }
10254
10255 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
10256 }
10257
10258 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
10259 }
10260
10270 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
10271 {
10272 global $conf, $langs, $hookmanager;
10273 global $action;
10274 global $db, $user; // Will be used into tpl
10275
10276 $object->fetchObjectLinked();
10277
10278 // Bypass the default method
10279 $hookmanager->initHooks(array('commonobject'));
10280 $parameters = array(
10281 'morehtmlright' => $morehtmlright,
10282 'compatibleImportElementsList' => &$compatibleImportElementsList,
10283 );
10284 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
10285
10286 $nbofdifferenttypes = count($object->linkedObjects);
10287
10288 if (empty($reshook)) {
10289 print '<!-- showLinkedObjectBlock -->';
10290 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, '', 'showlinkedobjectblock');
10291
10292
10293 print '<div class="div-table-responsive-no-min">';
10294 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
10295
10296 print '<tr class="liste_titre">';
10297 print '<td>' . $langs->trans("Type") . '</td>';
10298 print '<td>' . $langs->trans("Ref") . '</td>';
10299 print '<td class="center"></td>';
10300 print '<td class="center">' . $langs->trans("Date") . '</td>';
10301 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
10302 print '<td class="right">' . $langs->trans("Status") . '</td>';
10303 print '<td></td>';
10304 print '</tr>';
10305
10306 $nboftypesoutput = 0;
10307
10308 foreach ($object->linkedObjects as $objecttype => $objects) {
10309 $tplpath = $element = $subelement = $objecttype;
10310
10311 // to display import button on tpl
10312 global $showImportButton; // Will be used into tpl
10313 $showImportButton = false;
10314 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
10315 $showImportButton = true;
10316 }
10317
10318 $regs = array();
10319
10320 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
10321 $element = $regs[1];
10322 $subelement = $regs[2];
10323 $tplpath = $element . '/' . $subelement;
10324 }
10325 $tplname = 'linkedobjectblock';
10326
10327 // If we ask a resource form external module (instead of default path)
10328 if (preg_match('/^([^@]+)@([^@]+)$/i', $objecttype, $regs)) { // 'myobject@mymodule'
10329 $element = $regs[1];
10330 $module = $regs[2];
10331 $tplpath = $module. '/' . $element;
10332 $tplname = $tplname.'_'.$element;
10333 }
10334
10335 // To work with non standard path
10336 if ($objecttype == 'facture') {
10337 $tplpath = 'compta/' . $element;
10338 if (!isModEnabled('invoice')) {
10339 continue; // Do not show if module disabled
10340 }
10341 } elseif ($objecttype == 'facturerec') {
10342 $tplpath = 'compta/facture';
10343 $tplname = 'linkedobjectblockForRec';
10344 if (!isModEnabled('invoice')) {
10345 continue; // Do not show if module disabled
10346 }
10347 } elseif ($objecttype == 'propal') {
10348 $tplpath = 'comm/' . $element;
10349 if (!isModEnabled('propal')) {
10350 continue; // Do not show if module disabled
10351 }
10352 } elseif ($objecttype == 'supplier_proposal') {
10353 if (!isModEnabled('supplier_proposal')) {
10354 continue; // Do not show if module disabled
10355 }
10356 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
10357 $tplpath = 'expedition';
10358 if (!isModEnabled('shipping')) {
10359 continue; // Do not show if module disabled
10360 }
10361 } elseif ($objecttype == 'reception') {
10362 $tplpath = 'reception';
10363 if (!isModEnabled('reception')) {
10364 continue; // Do not show if module disabled
10365 }
10366 } elseif ($objecttype == 'delivery') {
10367 $tplpath = 'delivery';
10368 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
10369 continue; // Do not show if sub module disabled
10370 }
10371 } elseif ($objecttype == 'ficheinter') {
10372 $tplpath = 'fichinter';
10373 if (!isModEnabled('intervention')) {
10374 continue; // Do not show if module disabled
10375 }
10376 } elseif ($objecttype == 'invoice_supplier') {
10377 $tplpath = 'fourn/facture';
10378 } elseif ($objecttype == 'order_supplier') {
10379 $tplpath = 'fourn/commande';
10380 } elseif ($objecttype == 'expensereport') {
10381 $tplpath = 'expensereport';
10382 } elseif ($objecttype == 'subscription') {
10383 $tplpath = 'adherents';
10384 } elseif ($objecttype == 'conferenceorbooth') {
10385 $tplpath = 'eventorganization';
10386 } elseif ($objecttype == 'conferenceorboothattendee') {
10387 $tplpath = 'eventorganization';
10388 } elseif ($objecttype == 'mo') {
10389 $tplpath = 'mrp';
10390 if (!isModEnabled('mrp')) {
10391 continue; // Do not show if module disabled
10392 }
10393 } elseif ($objecttype == 'project_task') {
10394 $tplpath = 'projet/tasks';
10395 }
10396
10397 global $linkedObjectBlock; // Will be used into tpl
10398 $linkedObjectBlock = $objects;
10399
10400 // Output template part (modules that overwrite templates must declare this into descriptor)
10401 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
10402
10403 foreach ($dirtpls as $reldir) {
10404 $reldir = rtrim($reldir, '/');
10405 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
10406 global $noMoreLinkedObjectBlockAfter; // Will be used into tpl
10407 $noMoreLinkedObjectBlockAfter = 1;
10408 }
10409 $file = dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
10410 if (file_exists($file)) {
10411 $res = @include $file;
10412 if ($res) {
10413 $nboftypesoutput++;
10414 break;
10415 }
10416 }
10417 }
10418 }
10419
10420 if (!$nboftypesoutput) {
10421 print '<tr><td colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
10422 }
10423
10424 print '</table>';
10425
10426 if (!empty($compatibleImportElementsList)) {
10427 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
10428 }
10429
10430 print '</div>';
10431 }
10432
10433 return $nbofdifferenttypes;
10434 }
10435
10445 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array(), $nooutput = 0)
10446 {
10447 global $conf, $langs, $hookmanager, $form;
10448 global $action;
10449
10450 if (empty($form)) {
10451 $form = new Form($this->db);
10452 }
10453
10454 $linktoelem = '';
10455 $linktoelemlist = '';
10456 $listofidcompanytoscan = '';
10457
10458 if (!is_object($object->thirdparty)) {
10459 $object->fetch_thirdparty();
10460 }
10461
10462 $possiblelinks = array();
10463
10464 $dontIncludeCompletedItems = getDolGlobalString('DONT_INCLUDE_COMPLETED_ELEMENTS_LINKS');
10465
10466 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
10467 $listofidcompanytoscan = (int) $object->thirdparty->id;
10468 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
10469 $listofidcompanytoscan .= ',' . (int) $object->thirdparty->parent;
10470 }
10471 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
10472 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10473 $tmpproject = new Project($this->db);
10474 $tmpproject->fetch($object->fk_project);
10475 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
10476 $listofidcompanytoscan .= ',' . (int) $tmpproject->socid;
10477 }
10478 unset($tmpproject);
10479 }
10480
10481 $possiblelinks = array(
10482 'propal' => array(
10483 'enabled' => isModEnabled('propal'),
10484 'perms' => 1,
10485 'label' => 'LinkToProposal',
10486 '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' : ''),
10487 ),
10488 'shipping' => array(
10489 'enabled' => isModEnabled('shipping'),
10490 'perms' => 1,
10491 'label' => 'LinkToExpedition',
10492 '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' : ''),
10493 ),
10494 'order' => array(
10495 'enabled' => isModEnabled('order'),
10496 'perms' => 1,
10497 'label' => 'LinkToOrder',
10498 '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' : ''),
10499 'linkname' => 'commande',
10500 'subscription' => array(
10501 'enabled' => isModEnabled('member'),
10502 'perms' => 1,
10503 'label' => 'LinkToMemberSubscription',
10504 'sql' => "SELECT a.fk_soc as socid, CONCAT(a.firstname, ' ', a.lastname) as name, a.entity as client, sub.rowid, sub.note as ref, '' as ref_client, sub.subscription as total_ht FROM " . $this->db->prefix() . "adherent as a, " . $this->db->prefix() . "subscription as sub WHERE sub.fk_adherent = a.rowid AND a.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND a.entity IN (' . getEntity('subscription') . ')',
10505 'linkname' => 'subscription'),
10506 ),
10507 'invoice' => array(
10508 'enabled' => isModEnabled('invoice'),
10509 'perms' => 1,
10510 'label' => 'LinkToInvoice',
10511 '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' : ''),
10512 'linkname' => 'facture',
10513 ),
10514 'invoice_template' => array(
10515 'enabled' => isModEnabled('invoice'),
10516 'perms' => 1,
10517 'label' => 'LinkToTemplateInvoice',
10518 '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') . ')',
10519 ),
10520 'contrat' => array(
10521 'enabled' => isModEnabled('contract'),
10522 'perms' => 1,
10523 'label' => 'LinkToContract',
10524 '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
10525 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',
10526 ),
10527 'fichinter' => array(
10528 'enabled' => isModEnabled('intervention'),
10529 'perms' => 1,
10530 'label' => 'LinkToIntervention',
10531 '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') . ')',
10532 ),
10533 'supplier_proposal' => array(
10534 'enabled' => isModEnabled('supplier_proposal'),
10535 'perms' => 1,
10536 'label' => 'LinkToSupplierProposal',
10537 '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' : ''),
10538 ),
10539 'order_supplier' => array(
10540 'enabled' => isModEnabled("supplier_order"),
10541 'perms' => 1,
10542 'label' => 'LinkToSupplierOrder',
10543 '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' : ''),
10544 ),
10545 'invoice_supplier' => array(
10546 'enabled' => isModEnabled("supplier_invoice"),
10547 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
10548 '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' : ''),
10549 ),
10550 'ticket' => array(
10551 'enabled' => isModEnabled('ticket'),
10552 'perms' => 1,
10553 'label' => 'LinkToTicket',
10554 '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' : ''),
10555 ),
10556 'mo' => array(
10557 'enabled' => isModEnabled('mrp'),
10558 'perms' => 1,
10559 'label' => 'LinkToMo',
10560 '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' : ''),
10561 ),
10562 );
10563 }
10564
10565 if ($object->table_element == 'commande_fournisseur') {
10566 $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' : '');
10567 } elseif ($object->table_element == 'mrp_mo') {
10568 $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' : '');
10569 }
10570
10571 $reshook = 0; // Ensure $reshook is defined for static analysis
10572 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
10573 // Can complete the possiblelink array
10574 $hookmanager->initHooks(array('commonobject'));
10575 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
10576 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
10577 }
10578
10579 if (empty($reshook)) {
10580 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
10581 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
10582 }
10583 } elseif ($reshook > 0) {
10584 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
10585 $possiblelinks = $hookmanager->resArray;
10586 }
10587 }
10588
10589 if (!empty($possiblelinks)) {
10590 $object->fetchObjectLinked();
10591 }
10592
10593 // Build the html part with possible suggested links
10594 $htmltoenteralink = '';
10595 foreach ($possiblelinks as $key => $possiblelink) {
10596 $num = 0;
10597 if (empty($possiblelink['enabled'])) {
10598 continue;
10599 }
10600
10601
10602 // If we ask a resource form external module (instead of default path)
10603 $module = '';
10604 if (preg_match('/^([^@]+)@([^@]+)$/i', $key, $regs)) { // 'myobject@mymodule'
10605 $key = $regs[1];
10606 $module = $regs[2];
10607 }
10608
10609 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
10610 $htmltoenteralink .= '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
10611
10612 // Section for free ref input
10613 if (!getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10614 $htmltoenteralink .= '<br>'."\n";
10615 $htmltoenteralink .= '<!-- form to add a link from anywhere -->'."\n";
10616 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
10617 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
10618 $htmltoenteralink .= '<input type="hidden" name="action" value="addlinkbyref">';
10619 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
10620 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key .(!empty($module) ? '@'.$module : ''). '">';
10621 $htmltoenteralink .= '<table class="noborder">';
10622 $htmltoenteralink .= '<tr class="liste_titre">';
10623 //print '<td>' . $langs->trans("Ref") . '</td>';
10624 $htmltoenteralink .= '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
10625 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
10626 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
10627 $htmltoenteralink .= '</tr>';
10628 $htmltoenteralink .= '</table>';
10629 $htmltoenteralink .= '</form>';
10630 }
10631
10632 $sql = $possiblelink['sql'];
10633
10634 $resqllist = $this->db->query($sql);
10635 if ($resqllist) {
10636 $num = $this->db->num_rows($resqllist);
10637 $i = 0;
10638
10639 if ($num > 0) {
10640 // Section for free predefined list
10641 if (getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10642 $htmltoenteralink .= '<br>';
10643 }
10644 $htmltoenteralink .= '<!-- form to add a link from object to same thirdparty -->'."\n";
10645 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
10646 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
10647 $htmltoenteralink .= '<input type="hidden" name="action" value="addlink">';
10648 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
10649 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . (!empty($module) ? '@'.$module : ''). '">';
10650 $htmltoenteralink .= '<table class="noborder">';
10651 $htmltoenteralink .= '<tr class="liste_titre">';
10652 $htmltoenteralink .= '<td class="nowrap"></td>';
10653 $htmltoenteralink .= '<td>' . $langs->trans("Ref") . '</td>';
10654 $htmltoenteralink .= '<td>' . $langs->trans("RefCustomer") . '</td>';
10655 $htmltoenteralink .= '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
10656 $htmltoenteralink .= '<td>' . $langs->trans("Company") . '</td>';
10657 $htmltoenteralink .= '</tr>';
10658 while ($i < $num) {
10659 $objp = $this->db->fetch_object($resqllist);
10660 $alreadylinked = false;
10661 if (!empty($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key])) {
10662 if (in_array($objp->rowid, array_values($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key]))) {
10663 $alreadylinked = true;
10664 }
10665 }
10666 $htmltoenteralink .= '<tr class="oddeven">';
10667 $htmltoenteralink .= '<td>';
10668 if ($alreadylinked) {
10669 $htmltoenteralink .= img_picto('', 'link');
10670 } else {
10671 $htmltoenteralink .= '<input type="checkbox" name="idtolinkto[' . $key . '_' . $objp->rowid . ']" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
10672 }
10673 $htmltoenteralink .= '</td>';
10674 $htmltoenteralink .= '<td><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
10675 $htmltoenteralink .= '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
10676 $htmltoenteralink .= '<td class="right">';
10677 if ($possiblelink['label'] == 'LinkToContract') {
10678 $htmltoenteralink .= $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
10679 }
10680 $htmltoenteralink .= '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
10681 $htmltoenteralink .= '</td>';
10682 $htmltoenteralink .= '<td>' . $objp->name . '</td>';
10683 $htmltoenteralink .= '</tr>';
10684 $i++;
10685 }
10686 $htmltoenteralink .= '</table>';
10687 $htmltoenteralink .= '<div class="center">';
10688 if ($num) {
10689 $htmltoenteralink .= '<input type="submit" class="button valignmiddle marginleftonly marginrightonly smallpaddingimp" value="' . $langs->trans('ToLink') . '">';
10690 }
10691 if (empty($conf->use_javascript_ajax)) {
10692 $htmltoenteralink .= '<input type="submit" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
10693 } else {
10694 $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>';
10695 }
10696 $htmltoenteralink .= '</form>';
10697 }
10698
10699 $this->db->free($resqllist);
10700 } else {
10701 dol_print_error($this->db);
10702 }
10703 $htmltoenteralink .= '</div>';
10704
10705
10706 // Complete the list for the combo box
10707 if ($num > 0 || !getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10708 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
10709 // } else $linktoelem.=$langs->trans($possiblelink['label']);
10710 } else {
10711 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
10712 }
10713 }
10714 }
10715
10716 if ($linktoelemlist) {
10717 $linktoelem = '
10718 <dl class="dropdown" id="linktoobjectname">
10719 ';
10720 if (!empty($conf->use_javascript_ajax)) {
10721 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
10722 }
10723 $linktoelem .= '<dd>
10724 <div class="multiselectlinkto">
10725 <ul class="ulselectedfields">' . $linktoelemlist . '
10726 </ul>
10727 </div>
10728 </dd>
10729 </dl>';
10730 } else {
10731 $linktoelem = '';
10732 }
10733
10734 if (!empty($conf->use_javascript_ajax)) {
10735 print '<!-- Add js to show linkto box -->
10736 <script nonce="' . getNonce() . '">
10737 jQuery(document).ready(function() {
10738 jQuery(".linkto").click(function() {
10739 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
10740 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
10741 });
10742 });
10743 </script>
10744 ';
10745 }
10746
10747 if ($nooutput) {
10748 return array('linktoelem' => $linktoelem, 'htmltoenteralink' => $htmltoenteralink);
10749 } else {
10750 print $htmltoenteralink;
10751 }
10752
10753 return $linktoelem;
10754 }
10755
10770 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'yesno width75', $labelyes = 'Yes', $labelno = 'No')
10771 {
10772 global $langs;
10773
10774 $yes = "yes";
10775 $no = "no";
10776 if ($option) {
10777 $yes = "1";
10778 $no = "0";
10779 }
10780
10781 $disabled = ($disabled ? ' disabled' : '');
10782
10783 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
10784 if ($useempty) {
10785 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10786 }
10787 if (("$value" == 'yes') || ($value == 1)) {
10788 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
10789 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
10790 } else {
10791 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
10792 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
10793 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
10794 }
10795 $resultyesno .= '</select>' . "\n";
10796
10797 if ($addjscombo) {
10798 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
10799 }
10800
10801 return $resultyesno;
10802 }
10803
10804 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10805
10815 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
10816 {
10817 // phpcs:enable
10818 $sql = "SELECT rowid, label";
10819 $sql .= " FROM " . $this->db->prefix() . "export_model";
10820 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
10821 $sql .= " ORDER BY rowid";
10822 $result = $this->db->query($sql);
10823 if ($result) {
10824 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
10825 if ($useempty) {
10826 print '<option value="-1">&nbsp;</option>';
10827 }
10828
10829 $num = $this->db->num_rows($result);
10830 $i = 0;
10831 while ($i < $num) {
10832 $obj = $this->db->fetch_object($result);
10833 if ($selected == $obj->rowid) {
10834 print '<option value="' . $obj->rowid . '" selected>';
10835 } else {
10836 print '<option value="' . $obj->rowid . '">';
10837 }
10838 print $obj->label;
10839 print '</option>';
10840 $i++;
10841 }
10842 print "</select>";
10843 } else {
10844 dol_print_error($this->db);
10845 }
10846 }
10847
10866 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
10867 {
10868 global $conf, $langs, $hookmanager, $extralanguages;
10869
10870 $ret = '';
10871 if (empty($fieldid)) {
10872 $fieldid = 'rowid';
10873 }
10874 if (empty($fieldref)) {
10875 $fieldref = 'ref';
10876 }
10877
10878 // Preparing gender's display if there is one
10879 $addgendertxt = '';
10880 if (property_exists($object, 'gender') && !empty($object->gender)) {
10881 $addgendertxt = ' ';
10882 switch ($object->gender) {
10883 case 'man':
10884 $addgendertxt .= '<i class="fas fa-mars valignmiddle"></i>';
10885 break;
10886 case 'woman':
10887 $addgendertxt .= '<i class="fas fa-venus valignmiddle"></i>';
10888 break;
10889 case 'other':
10890 $addgendertxt .= '<i class="fas fa-transgender valignmiddle"></i>';
10891 break;
10892 }
10893 }
10894
10895 // Add where from hooks
10896 if (is_object($hookmanager)) {
10897 $parameters = array('showrefnav' => true);
10898 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
10899 if (!empty($hookmanager->resPrint)) {
10900 if (empty($object->next_prev_filter) && preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10901 $object->next_prev_filter = preg_replace('/^\s*AND\s*/i', '', $hookmanager->resPrint);
10902 } elseif (!empty($object->next_prev_filter) && !preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10903 $object->next_prev_filter .= ' AND '.$hookmanager->resPrint;
10904 } else {
10905 $object->next_prev_filter .= $hookmanager->resPrint;
10906 }
10907 }
10908 }
10909
10910 $previous_ref = $next_ref = '';
10911 if ($shownav) {
10912 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,fieldid=$fieldid,filedref=$fieldref,morehtmlref=$morehtmlref,moreparam=$moreparam";
10913 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
10914
10915 $navurl = $_SERVER["PHP_SELF"];
10916
10917 // Special case for token card
10918 if ($paramid == 'api_token_card') {
10919 if (preg_match('/\/user\/api_token/', $navurl)) {
10920 $navurl = preg_replace('/card/', 'list', $navurl);
10921 $paramid = 'id';
10922 }
10923 }
10924
10925 // Special case for project/task page
10926 if ($paramid == 'project_ref') {
10927 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
10928 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
10929 $paramid = 'ref';
10930 }
10931 }
10932
10933 $previous_ref = $object->ref_previous ? '<a accesskey="p" alt="'.dol_escape_htmltag($langs->trans("Previous")).'" title="' . $conf->browser->stringforfirstkey . ' p" class="classfortooltip reposition" 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>';
10934 $next_ref = $object->ref_next ? '<a accesskey="n" alt="'.dol_escape_htmltag($langs->trans("Next")).'" title="' . $conf->browser->stringforfirstkey . ' n" class="classfortooltip reposition" 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>';
10935 }
10936
10937 //print "xx".$previous_ref."x".$next_ref;
10938 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
10939
10940 // Right part of banner
10941 if ($morehtmlright) {
10942 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
10943 }
10944
10945 if ($previous_ref || $next_ref || $morehtml) {
10946 $ret .= '<div class="pagination paginationref"><ul class="right">';
10947 }
10948 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
10949 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
10950 }
10951 if ($shownav && ($previous_ref || $next_ref)) {
10952 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
10953 $ret .= '<li class="pagination">' . $next_ref . '</li>';
10954 }
10955 if ($previous_ref || $next_ref || $morehtml) {
10956 $ret .= '</ul></div>';
10957 }
10958
10959 // Status
10960 $parameters = array('morehtmlstatus' => $morehtmlstatus);
10961 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
10962 if (empty($reshook)) {
10963 $morehtmlstatus .= $hookmanager->resPrint;
10964 } else {
10965 $morehtmlstatus = $hookmanager->resPrint;
10966 }
10967 if ($morehtmlstatus) {
10968 $ret .= '<!-- status --><div class="statusref">' . $morehtmlstatus . '</div>';
10969 }
10970
10971 $parameters = array();
10972 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
10973 if (empty($reshook)) {
10974 $morehtmlref .= $hookmanager->resPrint;
10975 } elseif ($reshook > 0) {
10976 $morehtmlref = $hookmanager->resPrint;
10977 }
10978
10979 // Left part of banner
10980 if ($morehtmlleft) {
10981 if ($conf->browser->layout == 'phone') {
10982 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
10983 } else {
10984 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
10985 }
10986 }
10987
10988 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
10989 $ret .= '<!-- Ref or ID --><div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
10990
10991 // For thirdparty, contact, user, member, the ref is the id, so we show something else
10992 if ($object->element == 'societe') {
10993 $ret .= '<span class="valignmiddle">'.dol_htmlentities((string) $object->name).'</span>';
10994
10995 // List of extra languages
10996 $arrayoflangcode = array();
10997 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
10998 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
10999 }
11000
11001 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
11002 if (!is_object($extralanguages)) {
11003 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
11004 $extralanguages = new ExtraLanguages($this->db);
11005 }
11006 $extralanguages->fetch_name_extralanguages('societe');
11007
11008 // Guard against PHP 8 'Undefined array key' when MAIN_USE_ALTERNATE_TRANSLATION_FOR
11009 // is not configured and fetch_name_extralanguages() leaves attributes empty (issue #34596).
11010 if (!empty($extralanguages->attributes['societe']) && !empty($extralanguages->attributes['societe']['name'])) {
11011 $object->fetchValuesForExtraLanguages();
11012
11013 $htmltext = '';
11014 // If there is extra languages
11015 foreach ($arrayoflangcode as $extralangcode) {
11016 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
11017 if ($object->array_languages['name'][$extralangcode]) {
11018 $htmltext .= $object->array_languages['name'][$extralangcode];
11019 } else {
11020 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
11021 }
11022 }
11023 $ret .= '<!-- Show translations of name -->' . "\n";
11024 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
11025 }
11026 }
11027 } elseif ($object->element == 'member') {
11028 '@phan-var-force Adherent $object';
11029 $ret .= $object->ref . '<br>';
11030 $fullname = $object->getFullName($langs);
11031 if ($object->morphy == 'mor' && $object->societe) {
11032 $ret .= '<span class="valignmiddle">'.dol_htmlentities((string) $object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '').'</span>';
11033 } else {
11034 $ret .= '<span class="valignmiddle">'.dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities((string) $object->societe) . ')' : '').'</span>';
11035 }
11036 } elseif (in_array($object->element, array('contact', 'user'))) {
11037 $ret .= '<span class="valignmiddle">'.dol_htmlentities($object->getFullName($langs)).'</span>'.$addgendertxt;
11038 } elseif ($object->element == 'usergroup') {
11039 $ret .= dol_htmlentities((string) $object->name);
11040 } elseif (in_array($object->element, array('action', 'agenda'))) {
11041 '@phan-var-force ActionComm $object';
11042 $ret .= $object->ref . '<br>' . $object->label;
11043 } elseif (in_array($object->element, array('adherent_type'))) {
11044 $ret .= $object->label;
11045 } elseif ($object->element == 'ecm_directories') {
11046 $ret .= '';
11047 } elseif ($object->element == 'accountingbookkeeping' && !empty($object->context['mode']) && $object->context['mode'] == '_tmp') {
11048 $ret .= '<span class="valignmiddle">'.$langs->trans("Draft").'</span>';
11049 } elseif ($fieldref != 'none') {
11050 $ret .= '<span class="valignmiddle">'.dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "").'</span>';
11051 }
11052 if ($morehtmlref) {
11053 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
11054 if (substr($morehtmlref, 0, 4) != '<div') {
11055 $ret .= ' ';
11056 }
11057
11058 $ret .= '<!-- morehtmlref -->'.$morehtmlref;
11059 }
11060
11061 $ret .= '</div>';
11062
11063 $ret .= '</div><!-- End banner content -->';
11064
11065 return $ret;
11066 }
11067
11068
11077 public function showbarcode(&$object, $width = 100, $morecss = '')
11078 {
11079 global $conf;
11080
11081 //Check if barcode is filled in the card
11082 if (empty($object->barcode)) {
11083 return '';
11084 }
11085
11086 // Complete object if not complete
11087 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
11088 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
11089 $result = $object->fetchBarCode();
11090 //Check if fetchBarCode() failed
11091 if ($result < 1) {
11092 return '<!-- ErrorFetchBarcode -->';
11093 }
11094 }
11095
11096 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
11097 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
11098 $out = '<!-- url barcode = ' . $url . ' -->';
11099 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
11100
11101 return $out;
11102 }
11103
11122 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0, $usesharelinkifavailable = 0)
11123 {
11124 global $conf, $db, $langs;
11125
11126 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
11127 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
11128
11129 $dir = '';
11130 $file = '';
11131 $originalfile = '';
11132 $altfile = '';
11133 $email = '';
11134 $capture = '';
11135 if ($modulepart == 'societe') {
11136 $dir = $conf->societe->multidir_output[$entity];
11137 if (!empty($object->logo)) {
11138 if (dolIsAllowedForPreview($object->logo)) {
11139 if ((string) $imagesize == 'mini') {
11140 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
11141 } elseif ((string) $imagesize == 'small') {
11142 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
11143 } else {
11144 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
11145 }
11146 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
11147 }
11148 }
11149 $email = $object->email;
11150 } elseif ($modulepart == 'contact') {
11151 $dir = $conf->societe->multidir_output[$entity] . '/contact';
11152 $photo = $object->photo; // Copy to help static analysis
11153 if (!empty($photo)) {
11154 if (dolIsAllowedForPreview($photo)) {
11155 if ((string) $imagesize == 'mini') {
11156 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($photo, '_mini');
11157 } elseif ((string) $imagesize == 'small') {
11158 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($photo, '_small');
11159 } else {
11160 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $photo;
11161 }
11162 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $photo;
11163 }
11164 }
11165 $email = $object->email;
11166 $capture = 'user';
11167 } elseif ($modulepart == 'userphoto') {
11168 $dir = $conf->user->dir_output;
11169 $photo = $object->photo; // Copy to help static analysis
11170 if (!empty($photo)) {
11171 if (dolIsAllowedForPreview($photo)) {
11172 if ((string) $imagesize == 'mini') {
11173 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($photo, '_mini');
11174 } elseif ((string) $imagesize == 'small') {
11175 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($photo, '_small');
11176 } else {
11177 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $photo;
11178 }
11179 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $photo;
11180 }
11181 }
11182 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
11183 $altfile = $object->id . ".jpg"; // For backward compatibility
11184 }
11185 $email = $object->email;
11186 $capture = 'user';
11187 } elseif ($modulepart == 'memberphoto') {
11188 $dir = $conf->adherent->dir_output;
11189 $photo = $object->photo; // Copy to help static analysis
11190 if (!empty($photo)) {
11191 if (dolIsAllowedForPreview($photo)) {
11192 if ((string) $imagesize == 'mini') {
11193 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($photo, '_mini');
11194 } elseif ((string) $imagesize == 'small') {
11195 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($photo, '_small');
11196 } else {
11197 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $photo;
11198 }
11199 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $photo;
11200 }
11201 }
11202 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
11203 $altfile = $object->id . ".jpg"; // For backward compatibility
11204 }
11205 $email = $object->email;
11206 $capture = 'user';
11207 } else {
11208 // Generic case to show photos
11209 // TODO Implement this method in previous objects so we can always use this generic method.
11210 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
11211 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
11212
11213 $dir = $tmpdata['dir'];
11214 $file = $tmpdata['file'];
11215 $originalfile = $tmpdata['originalfile'];
11216 $altfile = $tmpdata['altfile'];
11217 $email = $tmpdata['email'];
11218 $capture = $tmpdata['capture'];
11219 }
11220 }
11221
11222 if ($forcecapture) {
11223 $capture = $forcecapture;
11224 }
11225
11226 $ret = '';
11227
11228 if ($dir) {
11229 if ($file && file_exists($dir . "/" . $file)) {
11230 if ($addlinktofullsize) {
11231 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
11232 if ($urladvanced) {
11233 $ret .= '<a href="' . $urladvanced . '">';
11234 } else {
11235 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
11236 }
11237 }
11238
11239 $sharekey = '';
11240 if ($usesharelinkifavailable) {
11241 // $dir is a full path '/home/.../dolibarr_documents/module'
11242 $relativefileforecm = preg_replace('/^'.preg_quote(DOL_DATA_ROOT.'/', '/').'/', '', $dir.'/'.$originalfile);
11243 // $relativefileforecme = 'module/...'
11244 require_once DOL_DOCUMENT_ROOT . '/ecm/class/ecmfiles.class.php';
11245 $ecmfiles = new EcmFiles($db);
11246 $ecmfiles->fetch(0, '', $relativefileforecm);
11247
11248 $sharekey = (string) $ecmfiles->share;
11249 }
11250
11251 if (!empty($sharekey)) {
11252 $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?hashp=' . urlencode($sharekey) . '&cache=' . urlencode((string) $cache) . '">';
11253 } else {
11254 $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 . '">';
11255 }
11256 if ($addlinktofullsize) {
11257 $ret .= '</a>';
11258 }
11259 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
11260 if ($addlinktofullsize) {
11261 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
11262 if ($urladvanced) {
11263 $ret .= '<a href="' . $urladvanced . '">';
11264 } else {
11265 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
11266 }
11267 }
11268 $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 . '">';
11269 if ($addlinktofullsize) {
11270 $ret .= '</a>';
11271 }
11272 } else {
11273 $nophoto = '/public/theme/common/nophoto.png';
11274 $defaultimg = 'identicon'; // For gravatar
11275 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
11276 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
11277 $nophoto = 'company';
11278 } else {
11279 $nophoto = '/public/theme/common/user_anonymous.png';
11280 if (!empty($object->gender) && $object->gender == 'man') {
11281 $nophoto = '/public/theme/common/user_man.png';
11282 }
11283 if (!empty($object->gender) && $object->gender == 'woman') {
11284 $nophoto = '/public/theme/common/user_woman.png';
11285 }
11286 }
11287 }
11288
11289 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
11290 // see https://gravatar.com/site/implement/images/php/
11291 $ret .= '<!-- Put link to gravatar -->';
11292 $ret .= '<img class="gravatar photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" title="'.dolPrintHTMLForAttribute('Gravatar avatar - '.$email).'" ' . ($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
11293 } else {
11294 if ($nophoto == 'company') {
11295 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
11296 //$ret .= '<div class="difforspanimgright"></div>';
11297 } else {
11298 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
11299 }
11300 }
11301 }
11302
11303 if ($caneditfield) {
11304 if ($object->photo) {
11305 $ret .= "<br>\n";
11306 }
11307 $ret .= '<table class="nobordernopadding centpercent">';
11308 if ($object->photo) {
11309 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
11310 }
11311 $ret .= '<tr><td class="tdoverflow">';
11312 $maxfilesizearray = getMaxFileSizeArray();
11313 $maxmin = $maxfilesizearray['maxmin'];
11314 if ($maxmin > 0) {
11315 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
11316 }
11317 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . dolPrintHTMLForAttribute($capture) . '"' : '') . '>';
11318 $ret .= '</td></tr>';
11319 $ret .= '</table>';
11320 }
11321 }
11322
11323 return $ret;
11324 }
11325
11326 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11327
11344 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
11345 {
11346 // phpcs:enable
11347 global $conf, $user, $langs;
11348
11349 // Allow excluding groups
11350 $excludeGroups = null;
11351 if (is_array($exclude)) {
11352 $excludeGroups = implode(",", $exclude);
11353 }
11354 // Allow including groups
11355 $includeGroups = null;
11356 if (is_array($include)) {
11357 $includeGroups = implode(",", $include);
11358 }
11359
11360 if (!is_array($selected)) {
11361 $selected = array($selected);
11362 }
11363
11364 $out = '';
11365
11366 // Build sql to search groups
11367 $sql = "SELECT ug.rowid, ug.nom as name";
11368 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
11369 $sql .= ", e.label";
11370 }
11371 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
11372 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
11373 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
11374 if ($force_entity) {
11375 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
11376 } else {
11377 $sql .= " WHERE ug.entity IS NOT NULL";
11378 }
11379 } else {
11380 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
11381 }
11382 if (is_array($exclude) && $excludeGroups) {
11383 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
11384 }
11385 if (is_array($include) && $includeGroups) {
11386 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
11387 }
11388 $sql .= " ORDER BY ug.nom ASC";
11389
11390 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
11391 $resql = $this->db->query($sql);
11392 if ($resql) {
11393 // Enhance with select2
11394 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11395
11396 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
11397
11398 $num = $this->db->num_rows($resql);
11399 $i = 0;
11400 if ($num) {
11401 if ($show_empty && !$multiple) {
11402 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
11403 }
11404
11405 while ($i < $num) {
11406 $obj = $this->db->fetch_object($resql);
11407 $disableline = 0;
11408 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
11409 $disableline = 1;
11410 }
11411
11412 $label = $obj->name;
11413 $labelhtml = $obj->name;
11414 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
11415 $label .= " (" . $obj->label . ")";
11416 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
11417 }
11418
11419 $out .= '<option value="' . $obj->rowid . '"';
11420 if ($disableline) {
11421 $out .= ' disabled';
11422 }
11423 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
11424 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
11425 $out .= ' selected';
11426 }
11427 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
11428 $out .= '>';
11429 $out .= $label;
11430 $out .= '</option>';
11431 $i++;
11432 }
11433 } else {
11434 if ($show_empty) {
11435 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
11436 }
11437 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
11438 }
11439 $out .= '</select>';
11440
11441 $out .= ajax_combobox($htmlname);
11442 } else {
11443 dol_print_error($this->db);
11444 }
11445
11446 return $out;
11447 }
11448
11449
11456 public function showFilterButtons($pos = '')
11457 {
11458 $out = '<div class="nowraponall">';
11459 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
11460 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
11461 $out .= '</div>';
11462
11463 return $out;
11464 }
11465
11474 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
11475 {
11476 global $conf;
11477
11478 $out = '';
11479
11480 if (!empty($conf->use_javascript_ajax)) {
11481 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
11482 }
11483 $out .= '<script nonce="' . getNonce() . '">
11484 $(document).ready(function() {
11485 $("#' . $cssclass . 's").click(function() {
11486 if($(this).is(\':checked\')){
11487 console.log("We check all ' . $cssclass . ' and trigger the change method");
11488 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
11489 }
11490 else
11491 {
11492 console.log("We uncheck all");
11493 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
11494 }' . "\n";
11495 if ($calljsfunction) {
11496 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
11497 }
11498 $out .= ' });
11499/*
11500 $(".' . $cssclass . '").change(function() {
11501 console.log("We check and change the tr class highlight after a change on .'.$cssclass.'");
11502 var $row = $(this).closest("tr");
11503 if ($row.length) {
11504 var anyChecked = $row.find(\'input[type="checkbox"].checkforselect:checked\').length > 0;
11505 console.log("anychecked="+anyChecked);
11506 if (!anyChecked) {
11507 $row.removeClass("highlight");
11508 } else {
11509 $row.addClass("highlight");
11510 }
11511 }
11512 });
11513*/
11514 });
11515 </script>';
11516
11517 return $out;
11518 }
11519
11529 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
11530 {
11531 $out = $this->showFilterButtons();
11532 if ($addcheckuncheckall) {
11533 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
11534 }
11535 return $out;
11536 }
11537
11551 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
11552 {
11553 global $langs, $user;
11554
11555 $out = '';
11556 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
11557 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
11558 if (!empty($excludeid)) {
11559 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
11560 }
11561 $sql .= " ORDER BY label";
11562
11563 $resql = $this->db->query($sql);
11564 if ($resql) {
11565 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
11566 if ($useempty) {
11567 $out .= '<option value="0">&nbsp;</option>';
11568 }
11569
11570 while ($obj = $this->db->fetch_object($resql)) {
11571 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
11572 }
11573 $out .= '</select>';
11574 $out .= ajax_combobox('select_' . $htmlname);
11575
11576 if (!empty($htmlname) && $user->admin && $info_admin) {
11577 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11578 }
11579
11580 if (!empty($target)) {
11581 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
11582 $resql = $this->db->query($sql);
11583 if ($resql) {
11584 if ($this->db->num_rows($resql) > 0) {
11585 $obj = $this->db->fetch_object($resql);
11586 $out .= '<script nonce="' . getNonce() . '">
11587 $(function() {
11588 $("select[name=' . $target . ']").on("change", function() {
11589 var current_val = $(this).val();
11590 if (current_val == ' . $obj->id . ') {';
11591 if (!empty($default_selected) || !empty($selected)) {
11592 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
11593 }
11594
11595 $out .= '
11596 $("select[name=' . $htmlname . ']").change();
11597 }
11598 });
11599
11600 $("select[name=' . $htmlname . ']").change(function() {
11601
11602 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
11603 // get price of kilometer to fill the unit price
11604 $.ajax({
11605 method: "POST",
11606 dataType: "json",
11607 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
11608 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
11609 }).done(function( data, textStatus, jqXHR ) {
11610 console.log(data);
11611 if (typeof data.up != "undefined") {
11612 $("input[name=value_unit]").val(data.up);
11613 $("select[name=' . $htmlname . ']").attr("title", data.title);
11614 } else {
11615 $("input[name=value_unit]").val("");
11616 $("select[name=' . $htmlname . ']").attr("title", "");
11617 }
11618 });
11619 }
11620 });
11621 });
11622 </script>';
11623 }
11624 }
11625 }
11626 } else {
11627 dol_print_error($this->db);
11628 }
11629
11630 return $out;
11631 }
11632
11641 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
11642 {
11643 global $conf, $langs;
11644
11645 $out = '';
11646 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
11647 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
11648
11649 $resql = $this->db->query($sql);
11650 if ($resql) {
11651 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
11652 if ($useempty) {
11653 $out .= '<option value="0"></option>';
11654 }
11655
11656 while ($obj = $this->db->fetch_object($resql)) {
11657 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
11658 }
11659 $out .= '</select>';
11660 } else {
11661 dol_print_error($this->db);
11662 }
11663
11664 return $out;
11665 }
11666
11677 public function selectExpenseFees($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
11678 {
11679 global $langs;
11680
11681 $out = '';
11682 $sql = "SELECT id, code, label";
11683 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
11684 $sql .= " WHERE active = 1";
11685
11686 $resql = $this->db->query($sql);
11687 if ($resql) {
11688 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
11689 if ($useempty) {
11690 $out .= '<option value="0"></option>';
11691 }
11692 if ($allchoice) {
11693 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
11694 }
11695
11696 $field = 'code';
11697 if ($useid) {
11698 $field = 'id';
11699 }
11700
11701 while ($obj = $this->db->fetch_object($resql)) {
11702 $key = $langs->trans($obj->code);
11703 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
11704 }
11705 $out .= '</select>';
11706
11707 $out .= ajax_combobox('select_'.$htmlname);
11708 } else {
11709 dol_print_error($this->db);
11710 }
11711
11712 return $out;
11713 }
11714
11733 public function selectInvoiceForTimeProject($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)
11734 {
11735 global $user, $conf, $langs;
11736
11737 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
11738
11739 if (is_null($usertofilter)) {
11740 $usertofilter = $user;
11741 }
11742
11743 $out = '';
11744
11745 $hideunselectables = false;
11746 if (getDolGlobalString('INVOICE_HIDE_UNSELECTABLES')) {
11747 $hideunselectables = true;
11748 }
11749
11750 if (empty($projectsListId)) {
11751 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
11752 $projectstatic = new Project($this->db);
11753 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
11754 }
11755 }
11756
11757 // Search all projects
11758 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref, p.title, p.fk_soc, p.fk_statut, p.public, s.nom as name";
11759 $sql .= " FROM " . $this->db->prefix() . "facture as f";
11760 $sql .= " INNER JOIN " . $this->db->prefix() . "projet as p ON p.entity IN (" . getEntity('project') . ") AND f.fk_projet = p.rowid";
11761 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON s.rowid = p.fk_soc";
11762 $sql .= " WHERE f.fk_statut = 0"; // Draft invoices only
11763 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
11764 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
11765 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
11766 $sql .= " ORDER BY p.ref, f.ref ASC";
11767
11768 $resql = $this->db->query($sql);
11769 if ($resql) {
11770 // Use select2 selector
11771 if (!empty($conf->use_javascript_ajax)) {
11772 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11773 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11774 $out .= $comboenhancement;
11775 $morecss = 'minwidth200imp maxwidth500';
11776 }
11777
11778 if (empty($option_only)) {
11779 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11780 }
11781 if (!empty($show_empty)) {
11782 $out .= '<option value="0" class="optiongrey">';
11783 if (!is_numeric($show_empty)) {
11784 $out .= $show_empty;
11785 } else {
11786 $out .= '&nbsp;';
11787 }
11788 $out .= '</option>';
11789 }
11790 $num = $this->db->num_rows($resql);
11791 $i = 0;
11792 if ($num) {
11793 while ($i < $num) {
11794 $obj = $this->db->fetch_object($resql);
11795 // 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.
11796 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
11797 // Do nothing
11798 } else {
11799 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11800 $i++;
11801 continue;
11802 }
11803
11804 $labeltoshow = '';
11805
11806 if ($showproject == 'all') {
11807 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
11808 if ($obj->name) {
11809 $labeltoshow .= ' - ' . $obj->name; // Soc name
11810 }
11811
11812 $disabled = 0;
11813 if ($obj->fk_statut == Project::STATUS_DRAFT) {
11814 $disabled = 1;
11815 $labeltoshow .= ' - ' . $langs->trans("Draft");
11816 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
11817 if ($discard_closed == 2) {
11818 $disabled = 1;
11819 }
11820 $labeltoshow .= ' - ' . $langs->trans("Closed");
11821 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
11822 $disabled = 1;
11823 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
11824 }
11825 }
11826
11827 if (!empty($selected) && $selected == $obj->rowid) {
11828 $out .= '<option value="' . $obj->rowid . '" selected';
11829 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11830 $out .= '>' . $labeltoshow . '</option>';
11831 } else {
11832 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11833 $resultat = '';
11834 } else {
11835 $resultat = '<option value="' . $obj->rowid . '"';
11836 if ($disabled) {
11837 $resultat .= ' disabled';
11838 }
11839 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11840 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11841 $resultat .= '>';
11842 $resultat .= $labeltoshow;
11843 $resultat .= '</option>';
11844 }
11845 $out .= $resultat;
11846 }
11847 }
11848 $i++;
11849 }
11850 }
11851 if (empty($option_only)) {
11852 $out .= '</select>';
11853 }
11854
11855 $this->db->free($resql);
11856
11857 return $out;
11858 } else {
11859 dol_print_error($this->db);
11860 return '';
11861 }
11862 }
11863
11878 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11879 {
11880 global $conf, $langs;
11881
11882 $out = '';
11883
11884 dol_syslog('FactureRec::fetch', LOG_DEBUG);
11885
11886 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
11887 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
11888 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
11889 $sql .= " ORDER BY f.titre ASC";
11890
11891 $resql = $this->db->query($sql);
11892 if ($resql) {
11893 // Use select2 selector
11894 if (!empty($conf->use_javascript_ajax)) {
11895 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11896 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11897 $out .= $comboenhancement;
11898 $morecss = 'minwidth200imp maxwidth500';
11899 }
11900
11901 if (empty($option_only)) {
11902 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11903 }
11904 if (!empty($show_empty)) {
11905 $out .= '<option value="0" class="optiongrey">';
11906 if (!is_numeric($show_empty)) {
11907 $out .= $show_empty;
11908 } else {
11909 $out .= '&nbsp;';
11910 }
11911 $out .= '</option>';
11912 }
11913 $num = $this->db->num_rows($resql);
11914 if ($num) {
11915 while ($obj = $this->db->fetch_object($resql)) {
11916 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
11917
11918 $disabled = 0;
11919 if (!empty($obj->suspended)) {
11920 $disabled = 1;
11921 $labeltoshow .= ' - ' . $langs->trans("Closed");
11922 }
11923
11924
11925 if (!empty($selected) && $selected == $obj->rowid) {
11926 $out .= '<option value="' . $obj->rowid . '" selected';
11927 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11928 $out .= '>' . $labeltoshow . '</option>';
11929 } else {
11930 if ($disabled && ($selected != $obj->rowid)) {
11931 $resultat = '';
11932 } else {
11933 $resultat = '<option value="' . $obj->rowid . '"';
11934 if ($disabled) {
11935 $resultat .= ' disabled';
11936 }
11937 $resultat .= '>';
11938 $resultat .= $labeltoshow;
11939 $resultat .= '</option>';
11940 }
11941 $out .= $resultat;
11942 }
11943 }
11944 }
11945 if (empty($option_only)) {
11946 $out .= '</select>';
11947 }
11948
11949 print $out;
11950
11951 $this->db->free($resql);
11952 return $num;
11953 } else {
11954 $this->errors[] = $this->db->lasterror;
11955 return -1;
11956 }
11957 }
11958
11959
11970 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '', $arrayoffiltercriterias = array())
11971 {
11972 // TODO: Use $arrayoffiltercriterias param instead of $arrayofcriterias to include linked object fields in search
11973 global $langs, $form;
11974
11975 //require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
11976 //$formother = new FormOther($this->db);
11977
11978 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
11979 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
11980 }
11981
11982 $ret = '<!-- searchComponent -->';
11983
11984 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
11985 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
11986 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
11987 $ret .= '</a>';
11988
11989 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
11990
11991 // Show select fields as tags.
11992 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
11993
11994 if ($search_component_params_hidden) {
11995 // Split the criteria on each AND
11996 //var_dump($search_component_params_hidden);
11997
11998 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
11999
12000 // $arrayofandtags is now array( '...' , '...', ...)
12001 // Show each AND part
12002 foreach ($arrayofandtags as $tmpkey => $tmpval) {
12003 $errormessage = '';
12004 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
12005 if ($errormessage) {
12006 $this->error = 'ERROR in parsing search string: '.$errormessage;
12007 }
12008 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
12009 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
12010 $searchtags = removeGlobalParenthesis($searchtags);
12011
12012 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
12013 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
12014 $ret .= dol_escape_htmltag($searchtags);
12015 $ret .= '</span>';
12016 }
12017 }
12018
12019 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
12020
12021 //$ret .= search_component_params
12022 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
12023 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
12024
12025 $show_search_component_params_hidden = 1;
12026 if ($show_search_component_params_hidden) {
12027 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
12028 }
12029 $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%')) -->";
12030 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
12031 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
12032
12033 // TODO : Use $arrayoffiltercriterias instead of $arrayofcriterias
12034 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
12035 foreach ($arrayofcriterias as $criteria) {
12036 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
12037 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
12038 continue;
12039 }
12040 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
12041 continue;
12042 }
12043 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
12044 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
12045 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
12046 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
12047 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
12048 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
12049 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
12050 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
12051 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
12052 } else {
12053 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
12054 }
12055 }
12056 }
12057
12058 $ret .= '</div>';
12059
12060 $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";
12061 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderall search_component_input" value="">';
12062
12063 $ret .= '</div>';
12064 $ret .= '</div>';
12065
12066 $ret .= '<script>
12067 jQuery(".tagsearchdelete").click(function(e) {
12068 var filterid = $(this).parents().attr("data-ufilterid");
12069 console.log("We click to delete the criteria nb "+filterid);
12070
12071 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
12072 var newparamstring = \'\';
12073 $(\'.tagsearch\').each(function(index, element) {
12074 tmpfilterid = $(this).attr("data-ufilterid");
12075 if (tmpfilterid != filterid) {
12076 // We keep this criteria
12077 if (newparamstring == \'\') {
12078 newparamstring = $(this).attr("data-ufilter");
12079 } else {
12080 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
12081 }
12082 }
12083 });
12084 console.log("newparamstring = "+newparamstring);
12085
12086 jQuery("#search_component_params_hidden").val(newparamstring);
12087
12088 // We repost the form
12089 $(this).closest(\'form\').submit();
12090 });
12091
12092 jQuery("#search_component_params_input").keydown(function(e) {
12093 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
12094 console.log(e.which);
12095 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
12096 /* We click on back when the input field is already empty */
12097 event.preventDefault();
12098 jQuery("#divsearch_component_params .tagsearch").last().remove();
12099 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
12100 var s = "";
12101 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
12102 if (s != "") {
12103 s = s + " AND ";
12104 }
12105 s = s + $(this).attr("data-ufilter");
12106 });
12107 console.log("New value for search_component_params_hidden = "+s);
12108 jQuery("#search_component_params_hidden").val(s);
12109 }
12110 });
12111
12112 </script>
12113 ';
12114
12115 // Convert $arrayoffiltercriterias into a json object that can be used in jquery to build the search component dynamically
12116 $arrayoffiltercriterias_json = json_encode($arrayoffiltercriterias);
12117 $ret .= '<script>
12118 var arrayoffiltercriterias = ' . $arrayoffiltercriterias_json . ';
12119 </script>';
12120
12121
12122 $arrayoffilterfieldslabel = array();
12123 foreach ($arrayoffiltercriterias as $key => $val) {
12124 $arrayoffilterfieldslabel[$key]['label'] = $val['label'];
12125 $arrayoffilterfieldslabel[$key]['data-type'] = $val['type'];
12126 }
12127
12128 // Adding the div for search assistance
12129 $ret .= '<div class="search-component-assistance">';
12130 $ret .= '<div>';
12131
12132 $ret .= '<p class="assistance-title">' . img_picto('', 'filter') . ' ' . $langs->trans('FilterAssistance') . ' </p>';
12133
12134 $ret .= '<p class="assistance-errors error" style="display:none">' . $langs->trans('AllFieldsRequired') . ' </p>';
12135
12136 $ret .= '<div class="operand">';
12137 $ret .= $form->selectarray('search_filter_field', $arrayoffilterfieldslabel, '', $langs->trans("Fields"), 0, 0, '', 0, 0, 0, '', 'width200 combolargeelem', 1);
12138 $ret .= '</div>';
12139
12140 $ret .= '<span class="separator"></span>';
12141
12142 // Operator selector (will be populated dynamically)
12143 $ret .= '<div class="operator">';
12144 $ret .= '<select class="operator-selector width150" id="operator-selector"">';
12145 $ret .= '</select>';
12146 $ret .= '<script>$(document).ready(function() {';
12147 $ret .= ' $(".operator-selector").select2({';
12148 $ret .= ' placeholder: \'' . dol_escape_js($langs->transnoentitiesnoconv('Operator')) . '\'';
12149 $ret .= ' });';
12150 $ret .= '});</script>';
12151 $ret .= '</div>';
12152
12153 $ret .= '<span class="separator"></span>';
12154
12155 $ret .= '<div class="value">';
12156 // Input field for entering values
12157 $ret .= '<input type="text" class="flat width100 value-input" placeholder="' . dolPrintHTML($langs->trans('Value')) . '">';
12158
12159 // Date selector
12160 $dateOne = '';
12161 $ret .= '<span class="date-one" style="display:none">';
12162 $ret .= $form->selectDate(($dateOne ? $dateOne : -1), 'dateone', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '');
12163 $ret .= '</span>';
12164
12165 // Value selector (will be populated dynamically) based on search_filter_field value if a selected value has an array of values
12166 $ret .= '<select class="value-selector width150" id="value-selector" style="display:none">';
12167 $ret .= '</select>';
12168 $ret .= '<script>
12169 $(document).ready(function() {
12170 $("#value-selector").select2({
12171 placeholder: "' . dol_escape_js($langs->trans('Value')) . '"
12172 });
12173 $("#value-selector").hide();
12174 $("#value-selector").next(".select2-container").hide();
12175 });
12176 </script>';
12177
12178 $ret .= '</div>';
12179
12180 $ret .= '<div class="btn-div">';
12181 $ret .= '<button class="button buttongen button-save add-filter-btn" type="button">' . $langs->trans("addToFilter") . '</button>';
12182 $ret .= '</div>';
12183
12184 $ret .= '</div>';
12185 //$ret .= '</tbody></table>';
12186
12187 // End of the assistance div
12188 $ret .= '</div>';
12189
12190 // Script jQuery to show/hide the floating assistance
12191 $ret .= '<script>
12192 $(document).ready(function() {
12193 $("#search_component_params_input").on("click", function() {
12194 const inputPosition = $(this).offset();
12195 const inputHeight = $(this).outerHeight();
12196 $(".search-component-assistance").css({
12197 top: inputPosition.top + inputHeight + 5 + "px",
12198 left: $("#divsearch_component_params").position().left
12199 }).slideToggle(200);
12200 });
12201 $(document).on("click", function(e) {
12202 if (!$(e.target).closest("#search_component_params_input, .search-component-assistance, #ui-datepicker-div").length) {
12203 $(".search-component-assistance").hide();
12204 }
12205 });
12206 });
12207 </script>';
12208
12209 $ret .= '<script>
12210 $(document).ready(function() {
12211 $(".search_filter_field").on("change", function() {
12212 console.log("We change search_filter_field");
12213
12214 let maybenull = 0;
12215 const selectedField = $(this).find(":selected");
12216 let fieldType = selectedField.data("type");
12217 const selectedFieldValue = selectedField.val();
12218
12219 // If the selected field has an array of values then ask toshow the value selector instead of the value input
12220 if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
12221 fieldType = "select";
12222 }
12223
12224 // If the selected field may be null then ask to append the "IsDefined" and "IsNotDefined" operators
12225 if (arrayoffiltercriterias[selectedFieldValue]["maybenull"] !== undefined) {
12226 maybenull = 1;
12227 }
12228 const operators = getOperatorsForFieldType(fieldType, maybenull);
12229 const operatorSelector = $(".operator-selector");
12230
12231 // Clear existing options
12232 operatorSelector.empty();
12233
12234 // Populate operators
12235 Object.entries(operators).forEach(function([operator, label]) {
12236 operatorSelector.append("<option value=\'" + operator + "\'>" + label + "</option>");
12237 });
12238
12239 operatorSelector.trigger("change.select2");
12240
12241 // Clear and hide all input elements initially
12242 $(".value-input, .dateone, .datemonth, .dateyear").val("").hide();
12243 $("#datemonth, #dateyear").val(null).trigger("change.select2");
12244 $("#dateone").datepicker("setDate", null);
12245 $(".date-one, .date-month, .date-year").hide();
12246 $("#value-selector").val("").hide();
12247 $("#value-selector").next(".select2-container").hide();
12248 $("#value-selector").val(null).trigger("change.select2");
12249
12250 if (fieldType === "date" || fieldType === "datetime" || fieldType === "timestamp") {
12251 $(".date-one").show();
12252 } else if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
12253 var arrayofkeyval = arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"];
12254 var valueSelector = $("#value-selector");
12255 valueSelector.empty();
12256 Object.entries(arrayofkeyval).forEach(function([key, val]) {
12257 valueSelector.append("<option value=\'" + key + "\'>" + val + "</option>");
12258 });
12259 valueSelector.trigger("change.select2");
12260
12261 $("#value-selector").show();
12262 $("#value-selector").next(".select2-container").show();
12263 } else {
12264 $(".value-input").show();
12265 }
12266 });
12267
12268 $("#operator-selector").on("change", function() {
12269 console.log("We change operator-selector");
12270
12271 const selectedOperator = $(this).find(":selected").val();
12272 if (selectedOperator === "IsDefined" || selectedOperator === "IsNotDefined") {
12273 // Disable all value input elements
12274 $(".value-input, .dateone, .datemonth, .dateyear").val("").prop("disabled", true);
12275 $("#datemonth, #dateyear").val(null).trigger("change.select2");
12276 $("#dateone").datepicker("setDate", null).datepicker("option", "disabled", true);
12277 $(".date-one, .date-month, .date-year").prop("disabled", true);
12278 $("#value-selector").val("").prop("disabled", true);
12279 $("#value-selector").val(null).trigger("change.select2");
12280 } else {
12281 // Enable all value input elements
12282 $(".value-input, .dateone, .datemonth, .dateyear").prop("disabled", false);
12283 $(".date-one, .date-month, .date-year").prop("disabled", false);
12284 $("#dateone").datepicker("option", "disabled", false);
12285 $("#value-selector").prop("disabled", false);
12286 }
12287 });
12288
12289 $(".add-filter-btn").on("click", function(event) {
12290 console.log("We click on add-filter-btn");
12291
12292 event.preventDefault();
12293
12294 const field = $(".search_filter_field").val();
12295 const operator = $(".operator-selector").val();
12296 let value = $(".value-input").val();
12297 const fieldType = $(".search_filter_field").find(":selected").data("type");
12298
12299 if (["date", "datetime", "timestamp"].includes(fieldType)) {
12300 const year = $("#dateoneyear").val().toString().padStart(4, "0");;
12301 const month = $("#dateonemonth").val().toString().padStart(2, "0");
12302 const day = $("#dateoneday").val().toString().padStart(2, "0");
12303 value = `${year}-${month}-${day}`;
12304 console.log("value="+value);
12305 }
12306
12307 // If the selected field has an array of values then take the selected value
12308 if (arrayoffiltercriterias[field]["arrayofkeyval"] !== undefined) {
12309 value = $("#value-selector").val();
12310 }
12311
12312 // If the operator is "IsDefined" or "IsNotDefined" then set the value to 1 (it will not be used)
12313 if (operator === "IsDefined" || operator === "IsNotDefined") {
12314 value = "1";
12315 }
12316
12317 const filterString = generateFilterString(field, operator, value, fieldType);
12318
12319 // Submit the form
12320 if (filterString !== "" && field !== "" && operator !== "" && value !== "") {
12321 $("#search_component_params_input").val($("#search_component_params_input").val() + " " + filterString);
12322 $("#search_component_params_input").closest("form").submit();
12323 } else {
12324 $(".assistance-errors").show();
12325 }
12326 });
12327 });
12328 </script>';
12329
12330 return $ret;
12331 }
12332
12344 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0, $selected = 0, $morecss = '')
12345 {
12346 global $langs, $user;
12347
12348 $retstring = '';
12349
12350 $TModels = array();
12351
12352 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
12353 $formmail = new FormMail($this->db);
12354 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
12355
12356 if ($default) {
12357 $TModels[0] = $langs->trans('DefaultMailModel');
12358 }
12359 if ($result > 0) {
12360 foreach ($formmail->lines_model as $model) {
12361 $TModels[(int) $model->id] = $model->label;
12362 }
12363 }
12364
12365 $retstring .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
12366
12367 foreach ($TModels as $id_model => $label_model) {
12368 $retstring .= '<option value="' . $id_model . '"';
12369 if (!empty($selected) && ((int) $selected) == $id_model) {
12370 $retstring .= "selected";
12371 }
12372 $retstring .= ">" . $label_model . "</option>";
12373 }
12374
12375 $retstring .= "</select>";
12376
12377 if ($addjscombo) {
12378 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
12379 }
12380
12381 return $retstring;
12382 }
12383
12395 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
12396 {
12397 global $langs;
12398
12399 $buttons = array();
12400
12401 $save = array(
12402 'name' => 'save',
12403 'label_key' => $save_label,
12404 );
12405
12406 if ($save_label == 'Create' || $save_label == 'Add') {
12407 $save['name'] = 'add';
12408 } elseif ($save_label == 'Modify') {
12409 $save['name'] = 'edit';
12410 }
12411
12412 $cancel = array(
12413 'name' => 'cancel',
12414 'label_key' => 'Cancel',
12415 );
12416
12417 // If MAIN_BUTTON_POSITION_FIRST_OR_LEFT not set, default is to have main action first, then complementary, then cancel at end
12418 if (!getDolGlobalInt('MAIN_BUTTON_POSITION_FIRST_OR_LEFT')) {
12419 !empty($save_label) ? $buttons[] = $save : '';
12420 if (!empty($morebuttons)) {
12421 $buttons[] = $morebuttons;
12422 }
12423 !empty($cancel_label) ? $buttons[] = $cancel : '';
12424 } else {
12425 if (!empty($morebuttons)) {
12426 $buttons[] = $morebuttons;
12427 }
12428 !empty($cancel_label) ? $buttons[] = $cancel : '';
12429 !empty($save_label) ? $buttons[] = $save : '';
12430 }
12431
12432 $retstring = $withoutdiv ? '' : '<div class="center">';
12433
12434 foreach ($buttons as $button) {
12435 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
12436 $retstring .= '<input type="submit" class="button marginleftonly marginrightonly button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->transnoentities($button['label_key'])) . '">';
12437 }
12438 $retstring .= $withoutdiv ? '' : '</div>';
12439
12440 if ($dol_openinpopup) {
12441 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
12442 $retstring .= '<script nonce="' . getNonce() . '">';
12443 $retstring .= 'jQuery(".button-cancel").click(function(e) {
12444 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
12445 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
12446 });';
12447 $retstring .= '</script>';
12448 }
12449
12450 return $retstring;
12451 }
12452
12453
12454 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
12455
12462 {
12463 // phpcs:enable
12464 global $langs;
12465
12466 $num = count($this->cache_invoice_subtype);
12467 if ($num > 0) {
12468 return 0; // Cache already loaded
12469 }
12470
12471 dol_syslog(__METHOD__, LOG_DEBUG);
12472
12473 $sql = "SELECT rowid, code, label as label";
12474 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
12475 $sql .= " WHERE active = 1";
12476
12477 $resql = $this->db->query($sql);
12478 if ($resql) {
12479 $num = $this->db->num_rows($resql);
12480 $i = 0;
12481 while ($i < $num) {
12482 $obj = $this->db->fetch_object($resql);
12483
12484 // If translation exists, we use it, otherwise we take the default wording
12485 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
12486 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
12487 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
12488 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
12489 $i++;
12490 }
12491
12492 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
12493
12494 return $num;
12495 } else {
12496 dol_print_error($this->db);
12497 return -1;
12498 }
12499 }
12500
12501
12512 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
12513 {
12514 global $langs, $user;
12515
12516 $out = '';
12517 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
12518
12519 $this->load_cache_invoice_subtype();
12520
12521 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
12522 if ($addempty) {
12523 $out .= '<option value="0">&nbsp;</option>';
12524 }
12525
12526 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
12527 $label = $subtype['label'];
12528 $out .= '<option value="' . $subtype['rowid'] . '"';
12529 if ($selected == $subtype['rowid']) {
12530 $out .= ' selected="selected"';
12531 }
12532 $out .= '>';
12533 $out .= $label;
12534 $out .= '</option>';
12535 }
12536
12537 $out .= '</select>';
12538 if ($user->admin && empty($noinfoadmin)) {
12539 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
12540 }
12541 $out .= ajax_combobox($htmlname);
12542
12543 return $out;
12544 }
12545
12555 public function getSearchFilterToolInput($dataTarget, $htmlName = 'search-tools-input', $value = '', $params = [])
12556 {
12557 global $langs;
12558
12559 $attr = array(
12560 'type' => 'search',
12561 'name' => $htmlName,
12562 'value' => $value,
12563 'class' => "search-tool-input",
12564 'placeholder' => $langs->trans('Search'),
12565 'autocomplete' => 'off'
12566 );
12567
12568 // Optional data attr
12569 // 'autofocus' : will set auto focus on field ,
12570 // data-counter-target : will get count results
12571 // data-no-item-target : will be display if count results is 0
12572
12573 if ($dataTarget !== false) {
12574 $attr['data-search-tool-target'] = $dataTarget;
12575 }
12576
12577 // Override attr
12578 if (!empty($params['attr']) && is_array($params['attr'])) {
12579 foreach ($params['attr'] as $key => $value) {
12580 if ($key == 'class') {
12581 $attr['class'] .= ' '.$value;
12582 } elseif ($key == 'classOverride') {
12583 $attr['class'] = $value;
12584 } else {
12585 $attr[$key] = $value;
12586 }
12587 }
12588 }
12589
12590 // automatic add tooltip when title is detected
12591 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
12592 $attr['class'] .= ' classfortooltip';
12593 }
12594
12595 $TCompiledAttr = [];
12596 foreach ($attr as $key => $value) {
12597 if (in_array($key, ['data-target'])
12598 || (!empty($params['use_unsecured_unescapedattr']) && is_array($params['use_unsecured_unescapedattr']) && in_array($key, $params['use_unsecured_unescapedattr']))) { // Not recommended
12599 $value = dol_htmlentities($value, ENT_QUOTES | ENT_SUBSTITUTE);
12600 } else {
12601 $value = dolPrintHTMLForAttribute($value);
12602 }
12603
12604 $TCompiledAttr[] = $key . '="' . $value . '"'; // $value has been escaped by the dolPrintHTMLForAttribute... just before
12605 }
12606
12607 $compiledAttributes = implode(' ', $TCompiledAttr);
12608
12609
12610 return '<div class="search-tool-container"><input '.$compiledAttributes.'></div>';
12611 }
12612
12626 public function inputType($type, $name, $value = '', $id = '', $morecss = '', $moreparam = '', $label = '', $addInputLabel = '')
12627 {
12628 $out = '';
12629 if ($label != '') {
12630 $out .= '<label for="' . dolPrintHTMLForAttribute($id) . '">';
12631 }
12632 $out .= '<input type="' . dolPrintHTMLForAttribute($type) . '"';
12633 $out .= ' class="flat valignmiddle maxwidthonsmartphone ' . dolPrintHTMLForAttribute($morecss) . '"';
12634 if ($id != '') {
12635 $out .= ' id="' . dolPrintHTMLForAttribute($id) . '"';
12636 }
12637 $out .= ' name="' . dolPrintHTMLForAttribute($name) . '"';
12638 $out .= ' value="' . dolPrintHTMLForAttribute($value) . '" ';
12639 $out .= ($moreparam ? ' ' . $moreparam : '');
12640 $out .= ' />' . $addInputLabel;
12641 if ($label != '') {
12642 $out .= $label . '</label>';
12643 }
12644
12645 return $out;
12646 }
12647
12660 public function inputSelectAjax($htmlName, $array, $id, $ajaxUrl, $ajaxData = [], $morecss = 'minwidth75', $moreparam = '')
12661 {
12662 $out = "
12663 <script>
12664 $(document).ready(function () {
12665 $('#" . $htmlName . "').select2({
12666 ajax: {
12667 url: '" . $ajaxUrl . "',
12668 dataType: 'json',
12669 delay: 250, // wait 250 milliseconds before triggering the request
12670 data: function (params) {
12671 var query = {
12672 search: params.term,
12673 page: params.page || 1";
12674 if (!empty($ajaxData) && is_array($ajaxData)) {
12675 foreach ($ajaxData as $key => $value) {
12676 $out .= ", " . $key . ": '" . $value . "'";
12677 }
12678 }
12679 $out .= "
12680 }
12681 return query;
12682 }
12683 }
12684 })
12685 });
12686 </script>";
12687
12688 $out .= $this->selectarray($htmlName, $array, $id, 0, 0, 0, $moreparam, 0, 0, 0, '', $morecss);
12689
12690 return $out;
12691 }
12692
12702 public function inputHtml($htmlName, $value, $morecss = '', $moreparam = '')
12703 {
12704 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
12705 $doleditor = new DolEditor($htmlName, $value, '', 200, 'dolibarr_notes', 'In', false, false, isModEnabled('fckeditor') && getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), ROWS_5, '90%');
12706
12707 return (string) $doleditor->Create(1, '', true, '', '', $moreparam, $morecss);
12708 }
12709
12720 public function inputText($htmlName, $value, $morecss = '', $moreparam = '', $options = array())
12721 {
12722 global $langs;
12723
12724 $out = '';
12725 if (!empty($options)) {
12726 // If the textarea field has a list of arrayofkeyval into its definition, we suggest a combo with possible values to fill the textarea.
12727 $out .= $this->selectarray($htmlName . "_multiinput", $options, '', 1, 0, 0, $moreparam, 0, 0, 0, '', "flat maxwidthonphone" . $morecss);
12728 $out .= '<input id="' . $htmlName . '_multiinputadd" type="button" class="button" value="' . $langs->trans("Add") . '">';
12729 $out .= "<script>";
12730 $out .= '
12731 function handlemultiinputdisabling(htmlname){
12732 console.log("We handle the disabling of used options for "+htmlname+"_multiinput");
12733 multiinput = $("#"+htmlname+"_multiinput");
12734 multiinput.find("option").each(function(){
12735 tmpval = $("#"+htmlname).val();
12736 tmpvalarray = tmpval.split("\n");
12737 valtotest = $(this).val();
12738 if(tmpvalarray.includes(valtotest)){
12739 $(this).prop("disabled",true);
12740 } else {
12741 if($(this).prop("disabled") == true){
12742 console.log(valtotest)
12743 $(this).prop("disabled", false);
12744 }
12745 }
12746 });
12747 }
12748
12749 $(document).ready(function () {
12750 $("#' . $htmlName . '_multiinputadd").on("click",function() {
12751 tmpval = $("#' . $htmlName . '").val();
12752 tmpvalarray = tmpval.split(",");
12753 valtotest = $("#' . $htmlName . '_multiinput").val();
12754 if(valtotest != -1 && !tmpvalarray.includes(valtotest)){
12755 console.log("We add the selected value to the text area ' . $htmlName . '");
12756 if(tmpval == ""){
12757 tmpval = valtotest;
12758 } else {
12759 tmpval = tmpval + "\n" + valtotest;
12760 }
12761 $("#' . $htmlName . '").val(tmpval);
12762 handlemultiinputdisabling("' . $htmlName . '");
12763 $("#' . $htmlName . '_multiinput").val(-1);
12764 } else {
12765 console.log("We add nothing the text area ' . $htmlName . '");
12766 }
12767 });
12768 $("#' . $htmlName . '").on("change",function(){
12769 handlemultiinputdisabling("' . $htmlName . '");
12770 });
12771 handlemultiinputdisabling("' . $htmlName . '");
12772 })';
12773 $out .= "</script>";
12774 $value = str_replace(',', "\n", $value);
12775 }
12776
12777 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
12778 $doleditor = new DolEditor($htmlName, (string) $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%');
12779 $out .= (string) $doleditor->Create(1, '', true, '', '', $moreparam, $morecss);
12780
12781 return $out;
12782 }
12783
12794 public function inputRadio($htmlName, $options, $selectedValue, $morecss = '', $moreparam = '')
12795 {
12796 $out = '';
12797 foreach ($options as $optionKey => $optionLabel) {
12798 $selected = ((string) $selectedValue) === ((string) $optionKey) ? ' checked="checked"' : '';
12799 $optionId = $htmlName . '_' . $optionKey;
12800 $out .= '<input class="flat' . $morecss . '" type="radio" name="' . $htmlName . '" id="' . $optionId . '" value="' . dolPrintHTMLForAttribute((string) $optionKey) . '"' . $selected . $moreparam . '/><label for="' . $optionId . '">' . $optionLabel . '</label><br>';
12801 }
12802
12803 return $out;
12804 }
12805
12816 public function inputStars($htmlName, $size, $value, $morecss = '', $moreparam = '')
12817 {
12818 $out = '<input type="hidden" class="flat ' . $morecss . '" name="' . $htmlName . '" id="' . $htmlName . '" value="' . dolPrintHTMLForAttribute((string) $value) . '"' . $moreparam . '>';
12819 $out .= '<div class="star-selection" id="' . $htmlName . '_selection">';
12820 for ($i = 1; $i <= $size; $i++) {
12821 $out .= '<span class="star" data-value="' . $i . '">' . img_picto('', 'fontawesome_star_fas') . '</span>';
12822 }
12823 $out .= '</div>';
12824 $out .= '<script>
12825 jQuery(function($) { /* commonobject.class.php 1 */
12826 let container = $("#' . $htmlName . '_selection");
12827 let selectedStars = parseInt($("#' . $htmlName . '").val()) || 0;
12828 container.find(".star").each(function() {
12829 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
12830 });
12831 container.find(".star").on("mouseover", function() {
12832 let selectedStar = $(this).data("value");
12833 container.find(".star").each(function() {
12834 $(this).toggleClass("active", $(this).data("value") <= selectedStar);
12835 });
12836 });
12837 container.on("mouseout", function() {
12838 container.find(".star").each(function() {
12839 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
12840 });
12841 });
12842 container.find(".star").off("click").on("click", function() {
12843 selectedStars = $(this).data("value");
12844 if (selectedStars === 1 && $("#' . $htmlName . '").val() == 1) {
12845 selectedStars = 0;
12846 }
12847 $("#' . $htmlName . '").val(selectedStars);
12848 container.find(".star").each(function() {
12849 $(this).toggleClass("active", $(this).data("value") <= selectedStars);
12850 });
12851 });
12852 });
12853 </script>';
12854
12855 return $out;
12856 }
12857
12867 public function inputIcon($htmlName, $value, $morecss = '', $moreparam = '')
12868 {
12869 global $langs;
12870
12871 /* External lib inclusion are not allowed in backoffice. Also lib is included several time if there is several icon file.
12872 Some code must be added into main when MAIN_ADD_ICONPICKER_JS is set to add of lib in html header
12873 $out ='<link rel="stylesheet" href="'.dol_buildpath('/myfield/css/fontawesome-iconpicker.min.css', 1).'">';
12874 $out.='<script src="'.dol_buildpath('/myfield/js/fontawesome-iconpicker.min.js', 1).'"></script>';
12875 */
12876 $out = '<input type="text" class="form-control icp icp-auto iconpicker-element iconpicker-input flat ' . $morecss . ' maxwidthonsmartphone"';
12877 $out .= ' name="' . $htmlName . '" id="' . $htmlName . '" value="' . dolPrintHTMLForAttribute((string) $value) . '" ' . ((string) $moreparam) . '>';
12878 if (getDolGlobalInt('MAIN_ADD_ICONPICKER_JS')) {
12879 $out .= '<script>';
12880 $options = "{ title: '<b>" . $langs->trans("IconFieldSelector") . "</b>', placement: 'right', showFooter: false, templates: {";
12881 $options .= "iconpicker: '<div class=\"iconpicker\"><div style=\"background-color:#EFEFEF;\" class=\"iconpicker-items\"></div></div>',";
12882 $options .= "iconpickerItem: '<a role=\"button\" href=\"#\" class=\"iconpicker-item\" style=\"background-color:#DDDDDD;\"><i></i></a>',";
12883 // $options.="buttons: '<button style=\"background-color:#FFFFFF;\" class=\"iconpicker-btn iconpicker-btn-cancel btn btn-default btn-sm\">".$langs->trans("Cancel")."</button>";
12884 // $options.="<button style=\"background-color:#FFFFFF;\" class=\"iconpicker-btn iconpicker-btn-accept btn btn-primary btn-sm\">".$langs->trans("Save")."</button>',";
12885 $options .= "footer: '<div class=\"popover-footer\" style=\"background-color:#EFEFEF;\"></div>',";
12886 $options .= "search: '<input type=\"search\" class\"form-control iconpicker-search\" placeholder=\"" . $langs->trans("TypeToFilter") . "\" />',";
12887 $options .= "popover: '<div class=\"iconpicker-popover popover\">";
12888 $options .= " <div class=\"arrow\" ></div>";
12889 $options .= " <div class=\"popover-title\" style=\"text-align:center;background-color:#EFEFEF;\"></div>";
12890 $options .= " <div class=\"popover-content \" ></div>";
12891 $options .= "</div>'}}";
12892 $out .= "$('#" . $htmlName . "').iconpicker(" . $options . ");";
12893 $out .= '</script>';
12894 }
12895
12896 return $out;
12897 }
12898
12907 public function inputGeoPoint($htmlName, $value, $type = '')
12908 {
12909 require_once DOL_DOCUMENT_ROOT . '/core/class/dolgeophp.class.php';
12910 require_once DOL_DOCUMENT_ROOT . '/core/class/geomapeditor.class.php';
12911 $dolgeophp = new DolGeoPHP($this->db);
12912 $geomapeditor = new GeoMapEditor();
12913
12914 $geojson = '{}';
12915 $centroidjson = getDolGlobalString('MAIN_INFO_SOCIETE_GEO_COORDINATES', '{}');
12916 if (!empty($value)) {
12917 $tmparray = $dolgeophp->parseGeoString($value);
12918 $geojson = $tmparray['geojson'];
12919 $centroidjson = $tmparray['centroidjson'];
12920 }
12921
12922 return $geomapeditor->getHtml($htmlName, $geojson, $centroidjson, $type);
12923 }
12924
12931 public function outputMultiValues($values)
12932 {
12933 $out = '';
12934 $toPrint = array();
12935 $values = is_array($values) ? $values : array();
12936
12937 foreach ($values as $value) {
12938 $toPrint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb">' . $value . '</li>';
12939 }
12940 if (!empty($toPrint)) {
12941 $out = '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">' . implode(' ', $toPrint) . '</ul></div>';
12942 }
12943
12944 return $out;
12945 }
12946
12954 public function outputStars($size, $value)
12955 {
12956 $out = '<div class="star-selection" data-value="' . dolPrintHTMLForAttribute((string) $value) . '">';
12957 for ($i = 1; $i <= $size; $i++) {
12958 $out .= '<span class="star' . ($i <= $value ? ' active' : '') . '" data-value="' . $i . '">' . img_picto('', 'fontawesome_star_fas') . '</span>';
12959 }
12960 $out .= '</div>';
12961
12962 return $out;
12963 }
12964
12971 public function outputIcon($value)
12972 {
12973 $out = '<span class="' . dolPrintHTMLForAttribute((string) $value) . '"></span>';
12974
12975 return $out;
12976 }
12977
12985 public function outputGeoPoint($value, $type)
12986 {
12987 $out = '';
12988
12989 if (!empty($value)) {
12990 require_once DOL_DOCUMENT_ROOT . '/core/class/dolgeophp.class.php';
12991 $dolgeophp = new DolGeoPHP($this->db);
12992 if ($type == 'point') {
12993 $out = $dolgeophp->getXYString($value);
12994 } else { // multipts, linestrg, polygon
12995 $out = $dolgeophp->getPointString($value);
12996 }
12997 }
12998
12999 return $out;
13000 }
13001
13016 public function getNomUrl(&$object, $withpicto = 0, $option = '', $maxlength = 0, $save_lastsearch_value = -1, $notooltip = 0, $morecss = '', $add_label = 0, $sep = ' - ')
13017 {
13018 if (is_object($object) && method_exists($object, 'getNomUrl')) {
13019 $out = $object->getNomUrl($withpicto, $option, $maxlength, $save_lastsearch_value, $notooltip, $morecss, $add_label, $sep);
13020 return $out;
13021 } else {
13022 return '';
13023 }
13024 }
13025}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
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:475
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:324
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:588
$c
Definition line.php:331
Class to manage bank accounts.
Class to manage categories.
Class to manage bank accounts description of third parties.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
Class to manage Geo processing Usage: $dolgeophp=new DolGeoPHP($db);.
DAO Resource object.
Class to manage ECM files.
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 invoice templates.
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.
inputSelectAjax($htmlName, $array, $id, $ajaxUrl, $ajaxData=[], $morecss='minwidth75', $moreparam='')
Html for select with get options by AJAX.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='maxwidth200 widthcentpercentminusx')
Return array of currencies in user language.
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.
inputRadio($htmlName, $options, $selectedValue, $morecss='', $moreparam='')
Html for input radio.
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0, $addentrynone=0)
Return a HTML select list of bank accounts.
static selectArrayAjax($htmlname, $url, $id='', $moreparam='', $moreparamtourl='', $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0)
Return a HTML select string, built from an array of key+value, but content returned into select come ...
inputGeoPoint($htmlName, $value, $type='')
Html for input geo point.
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.
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
getSelectRuleForLinesDates($selected='', $htmlname='rule_for_lines_dates', $addempty=0)
Returns select with rule for lines dates.
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')
Show a confirmation HTML form or AJAX popup.
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
static radio($htmlName, $radioItems, $selected='', $moreGlobalParams=[])
Generates a set of HTML radio inputs from an array of key-value items.
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.
inputType($type, $name, $value='', $id='', $morecss='', $moreparam='', $label='', $addInputLabel='')
Html for input with label.
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...
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0, $selected=0, $morecss='')
selectModelMail
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.
inputStars($htmlName, $size, $value, $morecss='', $moreparam='')
Html for input stars.
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.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $nu='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
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.
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()
Load int a cache property the list of possible delivery delays.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='', $maxlength=0, $showstatus=0, $morefilter='', $showalso=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
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.
form_rule_for_lines_dates($page, $selected='', $htmlname='rule_for_lines_dates', $addempty=0, $nooutput=0)
Form select for rule for lines dates.
selectcontacts($socid, $selected=array(), $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=0, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0, $filter='')
Return HTML code of the SELECT of list of all contacts (for a third party or all).
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party TODO Bad method.
inputIcon($htmlName, $value, $morecss='', $moreparam='')
Html for input icon.
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.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0, $usesharelinkifavailable=0)
Return HTML code to output a photo.
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.
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.
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
getSearchFilterToolInput($dataTarget, $htmlName='search-tools-input', $value='', $params=[])
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.
load_cache_rule_for_lines_dates()
Loads into a cache property the list of possible rules for line dates.
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.
getNomUrl(&$object, $withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1, $notooltip=0, $morecss='', $add_label=0, $sep=' - ')
Return link of object.
outputGeoPoint($value, $type)
Html for show geo point.
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...
inputText($htmlName, $value, $morecss='', $moreparam='', $options=array())
Html for HTML area.
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
textwithpicto($text, $htmltooltip, $direction=1, $type='help', $extracss='valignmiddle', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday=0, $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
load_cache_invoice_subtype()
Load into cache list of invoice subtypes.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
outputMultiValues($values)
Html for show selected multiple values.
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.
selectCategories($categtype, $htmlname, $object=null)
Return HTML component to select a category.
outputIcon($value)
Html for show icon.
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.
outputStars($size, $value)
Html for show stars.
getDurationTypes(Translate $langs, $plurial=true, $reverse=false)
Return an array of Duration Types.
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.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0, $morecss='')
Output HTML form to select list of input reason (events that triggered an object creation,...
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
load_cache_types_paiements()
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Return the list of type of delay available.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='', $nooutput=0)
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='yesno width75', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
inputHtml($htmlName, $value, $morecss='', $moreparam='')
Html for HTML area.
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 criteria.
selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty='', $searchkey='', $placeholder='', $morecss='', $moreparams='', $forcecombo=0, $outputmode=0, $disabled=0, $sortfield='', $filter='', $sortorder='ASC')
Output html form to select an object.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage a Leaflet map width geometrics objects.
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 translations.
Class to manage Dolibarr users.
Class toolbox to validate values.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
currency_name($code_iso, $withcode=0, $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
global $mysoc
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
dol_now($mode='gmt')
Return date for now.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
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.
dol_print_phone($phone, $countrycode='', $contactid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
commonHtmlAttributeBuilder($attr, array $unescapedAttr=[])
Builds an array of safe and properly escaped HTML attributes from a key-value pair list.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dolBuildUrl($url, $params=[], $addtoken=false)
Return path of url.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $jsonclose='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolUserString($key, $default='', $tmpuser=null)
Return Dolibarr user constant string value.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
natural_search($fields, $value, $mode=0, $nofirstand=0, $sqltoadd='')
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getElementProperties($elementType)
Get an array with properties of an element.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
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...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
dol_print_email($email, $contactid=0, $socid=0, $addlink=0, $max=0, $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_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
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 links.
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.
isModEnabled($module)
Is Dolibarr module enabled.
array_merge_recursive_distinct(array $array1, array $array2)
Recursively merges two arrays while preserving keys and replacing existing values.
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...
multi select button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
treeview li table
No Email.
a disabled
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:125
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:128
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.
getMaxFileSizeArray()
Return the max allowed for file upload.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition waf.inc.php:103