dolibarr 22.0.5
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-2024 Frédéric France <frederic.france@free.fr>
21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024-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
81 public $cache_types_paiements = array();
82 public $cache_conditions_paiements = array();
83 public $cache_transport_mode = array();
85 public $cache_availability = array();
86 public $cache_demand_reason = array();
87 public $cache_types_fees = array();
88 public $cache_vatrates = array();
89 public $cache_invoice_subtype = array();
91 public $cache_rule_for_lines_dates = array();
92
93
99 public function __construct($db)
100 {
101 $this->db = $db;
102 }
103
120 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
121 {
122 global $langs;
123
124 $ret = '';
125
126 // TODO change for compatibility
127 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
128 if ($perm) {
129 $tmp = explode(':', $typeofdata);
130 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
131 if ($fieldrequired) {
132 $ret .= '<span class="fieldrequired">';
133 }
134 if ($help) {
135 $ret .= $this->textwithpicto($langs->trans($text), $help);
136 } else {
137 $ret .= $langs->trans($text);
138 }
139 if ($fieldrequired) {
140 $ret .= '</span>';
141 }
142 $ret .= '</div>' . "\n";
143 } else {
144 if ($fieldrequired) {
145 $ret .= '<span class="fieldrequired">';
146 }
147 if ($help) {
148 $ret .= $this->textwithpicto($langs->trans($text), $help);
149 } else {
150 $ret .= $langs->trans($text);
151 }
152 if ($fieldrequired) {
153 $ret .= '</span>';
154 }
155 }
156 } else {
157 if (empty($notabletag) && $perm) {
158 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
159 }
160 if ($fieldrequired) {
161 $ret .= '<span class="fieldrequired">';
162 }
163 if ($help) {
164 $ret .= $this->textwithpicto($langs->trans($text), $help);
165 } else {
166 $ret .= $langs->trans($text);
167 }
168 if ($fieldrequired) {
169 $ret .= '</span>';
170 }
171 if (!empty($notabletag)) {
172 $ret .= ' ';
173 }
174 if (empty($notabletag) && $perm) {
175 $ret .= '</td>';
176 }
177 if (empty($notabletag) && $perm) {
178 $ret .= '<td class="right">';
179 }
180 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
181 $ret .= '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=edit' . $htmlname . '&token=' . newToken() . '&' . $paramid . '=' . $object->id . $moreparam . '">' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . '</a>';
182 }
183 if (!empty($notabletag) && $notabletag == 1) {
184 if ($text) {
185 $ret .= ' : ';
186 } else {
187 $ret .= ' ';
188 }
189 }
190 if (!empty($notabletag) && $notabletag == 3) {
191 $ret .= ' ';
192 }
193 if (empty($notabletag) && $perm) {
194 $ret .= '</td>';
195 }
196 if (empty($notabletag) && $perm) {
197 $ret .= '</tr></table>';
198 }
199 }
200
201 return $ret;
202 }
203
227 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 = '')
228 {
229 global $conf, $langs;
230
231 $ret = '';
232
233 // Check parameters
234 if (empty($typeofdata)) {
235 return 'ErrorBadParameter typeofdata is empty';
236 }
237 // Clean parameter $typeofdata
238 if ($typeofdata == 'datetime') {
239 $typeofdata = 'dayhour';
240 }
241 $reg = array();
242 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
243 if ($reg[1] == 'varchar') {
244 $typeofdata = 'string';
245 } elseif ($reg[1] == 'int') {
246 $typeofdata = 'numeric';
247 } else {
248 return 'ErrorBadParameter ' . $typeofdata;
249 }
250 }
251
252 // When option to edit inline is activated
253 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
254 $ret .= $this->editInPlace($object, $value, $htmlname, ($perm ? 1 : 0), $typeofdata, $editvalue, $extObject, $custommsg);
255 } else {
256 if ($editaction == '') {
257 $editaction = GETPOST('action', 'aZ09');
258 }
259 $editmode = ($editaction == 'edit' . $htmlname);
260 if ($editmode) { // edit mode
261 $ret .= "<!-- formeditfieldval -->\n";
262 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
263 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
264 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
265 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
266 if (empty($notabletag)) {
267 $ret .= '<table class="nobordernopadding centpercent">';
268 }
269 if (empty($notabletag)) {
270 $ret .= '<tr><td>';
271 }
272 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
273 $tmp = explode(':', $typeofdata);
274 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
275 } elseif (preg_match('/^(integer)/', $typeofdata)) {
276 $tmp = explode(':', $typeofdata);
277 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
278 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
279 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
280 $tmp = explode(':', $typeofdata);
281 $valuetoshow = price2num($editvalue ? $editvalue : $value);
282 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
283 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
284 $tmp = explode(':', $typeofdata);
285 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
286 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
287 $tmp = explode(':', $typeofdata);
288 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
289 $morealt = '';
290 if (preg_match('/%/', $cols)) {
291 $morealt = ' style="width: ' . $cols . '"';
292 $cols = '';
293 }
294 $valuetoshow = ($editvalue ? $editvalue : $value);
295 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
296 // textarea convert automatically entities chars into simple chars.
297 // 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.
298 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
299 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
300 $ret .= '</textarea><div class="clearboth"></div>';
301 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
302 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
303 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
304 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
305 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
306 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
307 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
308 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
309 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
310 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
311 } elseif (preg_match('/^select;/', $typeofdata)) {
312 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
313 $arraylist = array();
314 foreach ($arraydata as $val) {
315 $tmp = explode(':', $val);
316 $tmpkey = str_replace('|', ':', $tmp[0]);
317 $arraylist[$tmpkey] = $tmp[1];
318 }
319 $ret .= $this->selectarray($htmlname, $arraylist, $value);
320 } elseif (preg_match('/^link/', $typeofdata)) {
321 // TODO Not yet implemented. See code for extrafields
322 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
323 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
324 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
325 $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]));
326 $ret .= $doleditor->Create(1);
327 } elseif ($typeofdata == 'asis') {
328 $ret .= ($editvalue ? $editvalue : $value);
329 }
330 if (empty($notabletag)) {
331 $ret .= '</td>';
332 }
333
334 // Button save-cancel
335 if (empty($notabletag)) {
336 $ret .= '<td>';
337 }
338 //else $ret.='<div class="clearboth"></div>';
339 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Save") . '">';
340 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
341 $ret .= '<br>' . "\n";
342 }
343 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
344 if (empty($notabletag)) {
345 $ret .= '</td>';
346 }
347
348 if (empty($notabletag)) {
349 $ret .= '</tr></table>' . "\n";
350 }
351 $ret .= '</form>' . "\n";
352 } else { // view mode
353 if (preg_match('/^email/', $typeofdata)) {
354 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
355 } elseif (preg_match('/^phone/', $typeofdata)) {
356 $ret .= dol_print_phone($value, '_blank', 32, 1);
357 } elseif (preg_match('/^url/', $typeofdata)) {
358 $ret .= dol_print_url($value, '_blank', 32, 1);
359 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
360 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
361 } elseif (preg_match('/^checkbox/', $typeofdata)) {
362 $tmp = explode(':', $typeofdata);
363 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
364 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
366 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
368 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
369 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
370 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
371 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
372 } elseif (preg_match('/^select;/', $typeofdata)) {
373 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
374 $arraylist = array();
375 foreach ($arraydata as $val) {
376 $tmp = explode(':', $val);
377 $arraylist[$tmp[0]] = $tmp[1];
378 }
379 $ret .= $arraylist[$value];
380 if ($htmlname == 'fk_product_type') {
381 if ($value == 0) {
382 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
383 } else {
384 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
385 }
386 }
387 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
388 $tmpcontent = dol_htmlentitiesbr($value);
389 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
390 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
391 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
392 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
393 }
394 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
395 // clean data from some dangerous html
397 } else {
398 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
399 $ret .= dol_escape_htmltag($value);
400 } else {
401 $ret .= $value; // $value must be already html escaped.
402 }
403 }
404
405 // Custom format if parameter $formatfunc has been provided
406 if ($formatfunc && method_exists($object, $formatfunc)) {
407 $ret = $object->$formatfunc($ret);
408 }
409 }
410 }
411 return $ret;
412 }
413
425 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
426 {
427 global $conf, $langs, $extralanguages;
428
429 $result = '';
430
431 // List of extra languages
432 $arrayoflangcode = array();
433 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
434 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
435 }
436
437 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
438 if (!is_object($extralanguages)) {
439 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
440 $extralanguages = new ExtraLanguages($this->db);
441 }
442 $extralanguages->fetch_name_extralanguages('societe');
443
444 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
445 return ''; // No extralang field to show
446 }
447
448 $result .= '<!-- Widget for translation -->' . "\n";
449 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
450 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', 0, 0, 0, '', 'fa-15 editfieldlang');
451 $result .= $s;
452 $result .= '</div>';
453
454 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
455
456 $resultforextrlang = '';
457 foreach ($arrayoflangcode as $langcode) {
458 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
459 if (empty($valuetoshow)) {
460 $object->fetchValuesForExtraLanguages();
461 //var_dump($object->array_languages);
462 $valuetoshow = $object->array_languages[$fieldname][$langcode];
463 }
464
465 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
466 $resultforextrlang .= $s;
467
468 // TODO Use the showInputField() method of ExtraLanguages object
469 if ($typeofdata == 'textarea') {
470 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
471 $resultforextrlang .= $valuetoshow;
472 $resultforextrlang .= '</textarea>';
473 } else {
474 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
475 }
476 }
477 $result .= $resultforextrlang;
478
479 $result .= '</div>';
480 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
481 }
482
483 return $result;
484 }
485
499 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
500 {
501 $out = '';
502
503 // Check parameters
504 if (preg_match('/^text/', $inputType)) {
505 $value = dol_nl2br($value);
506 } elseif (preg_match('/^numeric/', $inputType)) {
507 $value = price($value);
508 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
509 $value = dol_print_date($value, 'day');
510 }
511
512 if ($condition) {
513 $element = false;
514 $table_element = false;
515 $fk_element = false;
516 $loadmethod = false;
517 $savemethod = false;
518 $ext_element = false;
519 $button_only = false;
520 $inputOption = '';
521 $rows = '';
522 $cols = '';
523
524 if (is_object($object)) {
525 $element = $object->element;
526 $table_element = $object->table_element;
527 $fk_element = $object->id;
528 }
529
530 if (is_object($extObject)) {
531 $ext_element = $extObject->element;
532 }
533
534 if (preg_match('/^(string|email|numeric)/', $inputType)) {
535 $tmp = explode(':', $inputType);
536 $inputType = $tmp[0];
537 if (!empty($tmp[1])) {
538 $inputOption = $tmp[1];
539 }
540 if (!empty($tmp[2])) {
541 $savemethod = $tmp[2];
542 }
543 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
544 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
545 $tmp = explode(':', $inputType);
546 $inputType = $tmp[0];
547 if (!empty($tmp[1])) {
548 $inputOption = $tmp[1];
549 }
550 if (!empty($tmp[2])) {
551 $savemethod = $tmp[2];
552 }
553
554 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
555 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
556 $tmp = explode(':', $inputType);
557 $inputType = $tmp[0];
558 $loadmethod = $tmp[1];
559 if (!empty($tmp[2])) {
560 $savemethod = $tmp[2];
561 }
562 if (!empty($tmp[3])) {
563 $button_only = true;
564 }
565 } elseif (preg_match('/^textarea/', $inputType)) {
566 $tmp = explode(':', $inputType);
567 $inputType = $tmp[0];
568 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
569 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
570 } elseif (preg_match('/^ckeditor/', $inputType)) {
571 $tmp = explode(':', $inputType);
572 $inputType = $tmp[0];
573 $toolbar = $tmp[1];
574 if (!empty($tmp[2])) {
575 $width = $tmp[2];
576 }
577 if (!empty($tmp[3])) {
578 $height = $tmp[3];
579 }
580 if (!empty($tmp[4])) {
581 $savemethod = $tmp[4];
582 }
583
584 if (isModEnabled('fckeditor')) {
585 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
586 } else {
587 $inputType = 'textarea';
588 }
589 }
590
591 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
592 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
593 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
594 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
595 if (!empty($savemethod)) {
596 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
597 }
598 if (!empty($ext_element)) {
599 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
600 }
601 if (!empty($custommsg)) {
602 if (is_array($custommsg)) {
603 if (!empty($custommsg['success'])) {
604 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
605 }
606 if (!empty($custommsg['error'])) {
607 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
608 }
609 } else {
610 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
611 }
612 }
613 if ($inputType == 'textarea') {
614 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
615 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
616 }
617 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
618 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
619 } else {
620 $out = $value;
621 }
622
623 return $out;
624 }
625
644 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
645 {
646 if ($incbefore) {
647 $text = $incbefore . $text;
648 }
649 if (!$htmltext) {
650 return $text;
651 }
652 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
653
654 $tag = 'td';
655 if ($notabs == 2) {
656 $tag = 'div';
657 }
658 if ($notabs == 3) {
659 $tag = 'span';
660 }
661 // Sanitize tooltip
662 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
663
664 $extrastyle = '';
665 if ($direction < 0) {
666 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
667 $extrastyle = 'padding: 0px; padding-left: 2px;';
668 }
669 if ($direction > 0) {
670 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
671 $extrastyle = 'padding: 0px; padding-right: 2px;';
672 }
673
674 $classfortooltip = 'classfortooltip';
675
676 $s = '';
677 $textfordialog = '';
678
679 if ($tooltiptrigger == '') {
680 $htmltext = str_replace('"', '&quot;', $htmltext);
681 } else {
682 $classfortooltip = 'classfortooltiponclick';
683 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext"';
684 // Set default title of dialog
685 global $langs;
686 if ($langs instanceof Translate) {
687 $textfordialog .= ' title="'.$langs->trans("Note").'"';
688 }
689 $textfordialog .= '>' . $htmltext . '</div>';
690 }
691 if ($tooltipon == 2 || $tooltipon == 3) {
692 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
693 if ($tooltiptrigger == '') {
694 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
695 } else {
696 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
697 }
698 } else {
699 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
700 }
701 if ($tooltipon == 1 || $tooltipon == 3) {
702 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ($tag != 'td' ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
703 if ($tooltiptrigger == '') {
704 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
705 } else {
706 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
707 }
708 } else {
709 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
710 }
711 if (empty($notabs)) {
712 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
713 } elseif ($notabs == 2) {
714 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
715 }
716 // Define value if value is before
717 if ($direction < 0) {
718 $s .= '<' . $tag . $paramfortooltipimg;
719 if ($tag == 'td') {
720 $s .= ' class="valigntop" width="14"';
721 }
722 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
723 }
724 // Use another method to help avoid having a space in value in order to use this value with jquery
725 // Define label
726 if ((string) $text != '') {
727 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
728 }
729 // Define value if value is after
730 if ($direction > 0) {
731 $s .= '<' . $tag . $paramfortooltipimg;
732 if ($tag == 'td') {
733 $s .= ' class="valignmiddle" width="14"';
734 }
735 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
736 }
737 if (empty($notabs)) {
738 $s .= '</tr></table>';
739 } elseif ($notabs == 2) {
740 $s .= '</div>';
741 }
742
743 return $s;
744 }
745
760 public function textwithpicto($text, $htmltooltip, $direction = 1, $type = 'help', $extracss = 'valignmiddle', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
761 {
762 global $conf, $langs;
763
764 //For backwards compatibility
765 if ($type == '0') {
766 $type = 'info';
767 } elseif ($type == '1') {
768 $type = 'help';
769 }
770 // Clean parameters
771 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
772
773 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
774 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
775 }
776 $alt = '';
777 if ($tooltiptrigger) {
778 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
779 }
780
781 // If info or help with no javascript, show only text
782 if (empty($conf->use_javascript_ajax)) {
783 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
784 return $text;
785 } else {
786 $alt = $htmltooltip;
787 $htmltooltip = '';
788 }
789 }
790
791 // If info or help with smartphone, show only text (tooltip hover can't works)
792 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
793 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
794 return $text;
795 }
796 }
797 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
798 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
799 //{
800 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
801 //}
802
803 $img = '';
804 if ($type == 'info') {
805 $img = img_help(($tooltiptrigger != '' ? 2 : 0), $alt);
806 } elseif ($type == 'help') {
807 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
808 } elseif ($type == 'helpclickable') {
809 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
810 } elseif ($type == 'superadmin') {
811 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
812 $img = img_picto($alt, 'redstar');
813 } elseif ($type == 'admin') {
814 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
815 $img = img_picto($alt, 'star');
816 } elseif ($type == 'warning') {
817 $img = img_warning($alt);
818 } elseif ($type != 'none') {
819 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
820 $img = img_picto($alt, $type); // $type can be an image path
821 }
822
823 $tooltipon = ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2);
824
825 return $this->textwithtooltip($text, $htmltooltip, $tooltipon, $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
826 }
827
838 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
839 {
840 global $conf, $langs, $hookmanager;
841
842 $disabled = 0;
843 $ret = '<div class="centpercent center">';
844 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
845
846 // 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.
847 $parameters = array();
848 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
849 // check if there is a mass action
850
851 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
852 return;
853 }
854 if (empty($reshook)) {
855 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
856 if (is_array($arrayofaction)) {
857 foreach ($arrayofaction as $code => $label) {
858 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
859 }
860 }
861 }
862 $ret .= $hookmanager->resPrint;
863
864 $ret .= '</select>';
865
866 if (empty($conf->dol_optimize_smallscreen)) {
867 $ret .= ajax_combobox('.' . $name . 'select');
868 }
869
870 // 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
871 $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.
872 $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")) . '">';
873 $ret .= '</div>';
874
875 if (!empty($conf->use_javascript_ajax)) {
876 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
877 <script nonce="' . getNonce() . '">
878 function initCheckForSelect(mode, name, cssclass) { /* mode is 0 during init of page or click all, 1 when we click on 1 checkboxi, "name" refers to the class of the massaction button, "cssclass" to the class of the checkfor select boxes */
879 atleastoneselected=0;
880 jQuery("."+cssclass).each(function( index ) {
881 /* console.log( index + ": " + $( this ).text() ); */
882 if ($(this).is(\':checked\')) atleastoneselected++;
883 });
884
885 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
886
887 if (atleastoneselected || ' . ((int) $alwaysvisible) . ') {
888 jQuery("."+name).show();
889 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
890 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
891 } else {
892 jQuery("."+name).hide();
893 jQuery("."+name+"other").hide();
894 }
895 }
896
897 jQuery(document).ready(function () {
898 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
899 jQuery(".' . $cssclass . '").click(function() {
900 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
901 });
902 jQuery(".' . $name . 'select").change(function() {
903 var massaction = $( this ).val();
904 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
905 if (massaction == "builddoc") {
906 urlform = urlform + "#show_files";
907 }
908 $( this ).closest("form").attr("action", urlform);
909 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
910 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
911 if ($(this).val() != \'0\') {
912 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
913 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
914 jQuery(".' . $name . '"+massaction).show();
915 } else {
916 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
917 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
918 }
919 });
920 });
921 </script>
922 ';
923 }
924
925 return $ret;
926 }
927
928 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
929
947 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)
948 {
949 // phpcs:enable
950 global $langs, $mysoc;
951
952 $langs->load("dict");
953
954 $out = '';
955 $countryArray = array();
956 $favorite = array();
957 $label = array();
958 $atleastonefavorite = 0;
959
960 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
961 $sql .= " FROM " . $this->db->prefix() . "c_country";
962 $sql .= " WHERE active > 0";
963 //$sql.= " ORDER BY code ASC";
964
965 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
966 $resql = $this->db->query($sql);
967 if ($resql) {
968 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
969 $num = $this->db->num_rows($resql);
970 $i = 0;
971 if ($num) {
972 while ($i < $num) {
973 $obj = $this->db->fetch_object($resql);
974
975 $countryArray[$i]['rowid'] = $obj->rowid;
976 $countryArray[$i]['code_iso'] = $obj->code_iso;
977 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
978 $countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
979 $countryArray[$i]['favorite'] = $obj->favorite;
980 $countryArray[$i]['eec'] = $obj->eec;
981 $favorite[$i] = $obj->favorite;
982 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
983 $i++;
984 }
985
986 if (empty($disablefavorites)) {
987 $array1_sort_order = SORT_DESC;
988 $array2_sort_order = SORT_ASC;
989 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
990 } else {
991 $countryArray = dol_sort_array($countryArray, 'label');
992 }
993
994 if ($showempty) {
995 if (is_numeric($showempty)) {
996 $out .= '<option value="">&nbsp;</option>' . "\n";
997 } else {
998 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
999 }
1000 }
1001
1002 if ($addspecialentries) { // Add dedicated entries for groups of countries
1003 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
1004 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1005 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
1006 if ($mysoc->isInEEC()) {
1007 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1008 }
1009 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1010 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1011 }
1012
1013 foreach ($countryArray as $row) {
1014 //if (empty($showempty) && empty($row['rowid'])) continue;
1015 if (empty($row['rowid'])) {
1016 continue;
1017 }
1018 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1019 continue; // exclude some countries
1020 }
1021
1022 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1023 $atleastonefavorite++;
1024 }
1025 if (empty($row['favorite']) && $atleastonefavorite) {
1026 $atleastonefavorite = 0;
1027 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1028 }
1029
1030 $labeltoshow = '';
1031 if ($row['label']) {
1032 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1033 } else {
1034 $labeltoshow .= '&nbsp;';
1035 }
1036 if ($row['code_iso']) {
1037 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1038 if (empty($hideflags)) {
1039 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1040 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1041 }
1042 }
1043
1044 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1045 $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']) . '">';
1046 } else {
1047 $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']) . '">';
1048 }
1049 $out .= dol_string_nohtmltag($labeltoshow);
1050 $out .= '</option>' . "\n";
1051 }
1052 }
1053 $out .= '</select>';
1054 } else {
1055 dol_print_error($this->db);
1056 }
1057
1058 // Make select dynamic
1059 if (empty($forcecombo)) {
1060 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1061 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1062 }
1063
1064 return $out;
1065 }
1066
1067 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1068
1082 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1083 {
1084 // phpcs:enable
1085 global $conf, $langs;
1086
1087 $langs->load("dict");
1088
1089 $out = '';
1090 //$moreattrib = '';
1091 $incotermArray = array();
1092
1093 $sql = "SELECT rowid, code";
1094 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1095 $sql .= " WHERE active > 0";
1096 $sql .= " ORDER BY code ASC";
1097
1098 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1099 $resql = $this->db->query($sql);
1100 if ($resql) {
1101 if ($conf->use_javascript_ajax && !$forcecombo) {
1102 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1103 $out .= ajax_combobox($htmlname, $events);
1104 }
1105
1106 if (!empty($page)) {
1107 $out .= '<form method="post" action="' . $page . '">';
1108 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1109 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1110 }
1111
1112 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1113 $out .= '<option value="0">&nbsp;</option>';
1114 $num = $this->db->num_rows($resql);
1115 $i = 0;
1116 if ($num) {
1117 while ($i < $num) {
1118 $obj = $this->db->fetch_object($resql);
1119 $incotermArray[$i]['rowid'] = $obj->rowid;
1120 $incotermArray[$i]['code'] = $obj->code;
1121 $i++;
1122 }
1123
1124 foreach ($incotermArray as $row) {
1125 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1126 $out .= '<option value="' . $row['rowid'] . '" selected>';
1127 } else {
1128 $out .= '<option value="' . $row['rowid'] . '">';
1129 }
1130
1131 if ($row['code']) {
1132 $out .= $row['code'];
1133 }
1134
1135 $out .= '</option>';
1136 }
1137 }
1138 $out .= '</select>';
1139 $out .= ajax_combobox($htmlname);
1140
1141 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1142 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1143 //$moreattrib .= ' autocomplete="off"';
1144 }
1145 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone heightofcombo" type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1146
1147 if (!empty($page)) {
1148 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1149 }
1150 } else {
1151 dol_print_error($this->db);
1152 }
1153
1154 return $out;
1155 }
1156
1157 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1158
1172 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "", $useajaxcombo = 1)
1173 {
1174 // phpcs:enable
1175 global $langs;
1176
1177 // If product & services are enabled or both disabled.
1178 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1179 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1180 if (empty($hidetext)) {
1181 print $langs->trans("Type").'...';
1182 }
1183 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1184 if ($showempty) {
1185 print '<option value="-1" class="opacitymedium"'.($useajaxcombo ? '' : ' disabled="disabled"');
1186 if ($selected == -1) {
1187 print ' selected';
1188 }
1189 print '>';
1190 if (is_numeric($showempty)) {
1191 print '&nbsp;';
1192 } else {
1193 print $showempty;
1194 }
1195 print '</option>';
1196 }
1197
1198 print '<option value="0"';
1199 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1200 print ' selected';
1201 }
1202 print '>' . $langs->trans("Product");
1203
1204 print '<option value="1"';
1205 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1206 print ' selected';
1207 }
1208 print '>' . $langs->trans("Service");
1209
1210 print '</select>';
1211
1212 if ($useajaxcombo) {
1213 print ajax_combobox('select_' . $htmlname);
1214 }
1215 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1216 }
1217 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1218 print $langs->trans("Service");
1219 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1220 }
1221 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1222 print $langs->trans("Product");
1223 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1224 }
1225 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1226 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
1227 }
1228 }
1229
1230 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1231
1237 public function load_cache_types_fees()
1238 {
1239 // phpcs:enable
1240 global $langs;
1241
1242 $num = count($this->cache_types_fees);
1243 if ($num > 0) {
1244 return 0; // Cache already loaded
1245 }
1246
1247 dol_syslog(__METHOD__, LOG_DEBUG);
1248
1249 $langs->load("trips");
1250
1251 $sql = "SELECT c.code, c.label";
1252 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1253 $sql .= " WHERE active > 0";
1254
1255 $resql = $this->db->query($sql);
1256 if ($resql) {
1257 $num = $this->db->num_rows($resql);
1258 $i = 0;
1259
1260 while ($i < $num) {
1261 $obj = $this->db->fetch_object($resql);
1262
1263 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1264 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1265 $this->cache_types_fees[$obj->code] = $label;
1266 $i++;
1267 }
1268
1269 asort($this->cache_types_fees);
1270
1271 return $num;
1272 } else {
1273 dol_print_error($this->db);
1274 return -1;
1275 }
1276 }
1277
1278 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1279
1288 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1289 {
1290 // phpcs:enable
1291 global $user, $langs;
1292
1293 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1294
1295 $this->load_cache_types_fees();
1296
1297 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1298 if ($showempty) {
1299 print '<option value="-1"';
1300 if ($selected == -1) {
1301 print ' selected';
1302 }
1303 print '>&nbsp;</option>';
1304 }
1305
1306 foreach ($this->cache_types_fees as $key => $value) {
1307 print '<option value="' . $key . '"';
1308 if ($key == $selected) {
1309 print ' selected';
1310 }
1311 print '>';
1312 print $value;
1313 print '</option>';
1314 }
1315
1316 print '</select>';
1317 if ($user->admin) {
1318 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1319 }
1320 }
1321
1322
1323 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1324
1347 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)
1348 {
1349 // phpcs:enable
1350 global $conf, $langs;
1351
1352 $out = '';
1353
1354 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1355 if (is_null($ajaxoptions)) {
1356 $ajaxoptions = array();
1357 }
1358
1359 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1360
1361 // No immediate load of all database
1362 $placeholder = '';
1363 if ($selected && empty($selected_input_value)) {
1364 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1365 $societetmp = new Societe($this->db);
1366 $societetmp->fetch($selected);
1367 $selected_input_value = $societetmp->name;
1368 unset($societetmp);
1369 }
1370
1371 // mode 1
1372 $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)) : '');
1373
1374 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1375 if (empty($hidelabel)) {
1376 $out .= $langs->trans("RefOrLabel") . ' : ';
1377 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1378 $placeholder = $langs->trans($showempty);
1379 } elseif ($hidelabel > 1) {
1380 $placeholder = $langs->trans("RefOrLabel");
1381 if ($hidelabel == 2) {
1382 $out .= img_picto($langs->trans("Search"), 'search');
1383 }
1384 }
1385 $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' : '') . ' />';
1386 if ($hidelabel == 3) {
1387 $out .= img_picto($langs->trans("Search"), 'search');
1388 }
1389
1390 $out .= ajax_event($htmlname, $events);
1391
1392 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1393 } else {
1394 // Immediate load of all database
1395 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1396 }
1397
1398 return $out;
1399 }
1400
1401
1402 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1403
1429 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 = '')
1430 {
1431 // phpcs:enable
1432
1433 global $conf, $langs;
1434
1435 $out = '';
1436
1437 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1438 if ($nokeyifsocid && $socid > 0) {
1439 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1440 }
1441
1442 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1443 if (is_null($events)) {
1444 $events = array();
1445 }
1446
1447 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1448
1449 // No immediate load of all database
1450 $placeholder = '';
1451 if ($selected && empty($selected_input_value)) {
1452 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1453 $contacttmp = new Contact($this->db);
1454 $contacttmp->fetch($selected);
1455 $selected_input_value = $contacttmp->getFullName($langs);
1456 unset($contacttmp);
1457 }
1458 if (!is_numeric($showempty)) {
1459 $placeholder = $showempty;
1460 }
1461
1462 // mode 1
1463 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1464
1465 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1466
1467 $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' : '') . ' />';
1468
1469 $out .= ajax_event($htmlname, $events);
1470
1471 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1472 } else {
1473 // Immediate load of all database
1474 $multiple = false;
1475 $disableifempty = 0;
1476 $options_only = 0;
1477 $limitto = '';
1478
1479 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1480 }
1481
1482 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1483
1484 return $out;
1485 }
1486
1487
1488 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1489
1514 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)
1515 {
1516 // phpcs:enable
1517 global $user, $langs;
1518 global $hookmanager;
1519
1520 $langs->loadLangs(array("companies", "suppliers"));
1521
1522 $out = '';
1523 $num = 0;
1524 $outarray = array();
1525
1526 if ($selected === '') {
1527 $selected = array();
1528 } elseif (!is_array($selected)) {
1529 $selected = array($selected);
1530 }
1531
1532 // Clean $filter that may contains sql conditions so sql code
1533 if (function_exists('testSqlAndScriptInject')) {
1534 if (testSqlAndScriptInject($filter, 3) > 0) {
1535 $filter = '';
1536 return 'SQLInjectionTryDetected';
1537 }
1538 }
1539
1540 if ($filter != '') { // If a filter was provided
1541 if (preg_match('/[\‍(\‍)]/', $filter)) {
1542 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1543 $errormsg = '';
1544 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1545
1546 // Redo clean $filter that may contains sql conditions so sql code
1547 if (function_exists('testSqlAndScriptInject')) {
1548 if (testSqlAndScriptInject($filter, 3) > 0) {
1549 $filter = '';
1550 return 'SQLInjectionTryDetected';
1551 }
1552 }
1553 } else {
1554 // If not, we do nothing. We already know that there is no parenthesis
1555 // TODO Disallow this case in a future.
1556 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1557 }
1558 }
1559
1560 // We search companies
1561 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1562 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1563 $sql .= ", s.address, s.zip, s.town";
1564 $sql .= ", dictp.code as country_code";
1565 }
1566 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1567 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1568 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1569 }
1570 if (!$user->hasRight('societe', 'client', 'voir')) {
1571 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1572 }
1573 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1574 if (!empty($user->socid)) {
1575 $sql .= " AND s.rowid = " . ((int) $user->socid);
1576 }
1577 if ($filter) {
1578 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1579 // if not, by testSqlAndScriptInject() only.
1580 $sql .= " AND (" . $filter . ")";
1581 }
1582 if (!$user->hasRight('societe', 'client', 'voir')) {
1583 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1584 }
1585 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1586 $sql .= " AND s.status <> 0";
1587 }
1588 if (!empty($excludeids)) {
1589 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1590 }
1591 // Add where from hooks
1592 $parameters = array();
1593 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1594 $sql .= $hookmanager->resPrint;
1595 // Add criteria
1596 if ($filterkey && $filterkey != '') {
1597 $sql .= " AND (";
1598 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1599 // For natural search
1600 $search_crit = explode(' ', $filterkey);
1601 $i = 0;
1602 if (count($search_crit) > 1) {
1603 $sql .= "(";
1604 }
1605 foreach ($search_crit as $crit) {
1606 if ($i > 0) {
1607 $sql .= " AND ";
1608 }
1609 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1610 $i++;
1611 }
1612 if (count($search_crit) > 1) {
1613 $sql .= ")";
1614 }
1615 if (isModEnabled('barcode')) {
1616 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1617 }
1618 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1619 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1620 $sql .= ")";
1621 }
1622 $sql .= $this->db->order("nom", "ASC");
1623 $sql .= $this->db->plimit($limit, 0);
1624
1625 // Build output string
1626 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1627 $resql = $this->db->query($sql);
1628 if ($resql) {
1629 // Construct $out and $outarray
1630 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1631
1632 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1633 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1634 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1635 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1636 if ($showempty && !is_numeric($showempty)) {
1637 $textifempty = $langs->trans($showempty);
1638 } else {
1639 $textifempty .= $langs->trans("All");
1640 }
1641 }
1642 if ($showempty) {
1643 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1644 }
1645
1646 $companytemp = new Societe($this->db);
1647
1648 $num = $this->db->num_rows($resql);
1649 $i = 0;
1650 if ($num) {
1651 while ($i < $num) {
1652 $obj = $this->db->fetch_object($resql);
1653 $label = '';
1654 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1655 if (($obj->client) && (!empty($obj->code_client))) {
1656 $label = $obj->code_client . ' - ';
1657 }
1658 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1659 $label .= $obj->code_fournisseur . ' - ';
1660 }
1661 $label .= ' ' . $obj->name;
1662 } else {
1663 $label = $obj->name;
1664 }
1665
1666 if (!empty($obj->name_alias)) {
1667 $label .= ' (' . $obj->name_alias . ')';
1668 }
1669
1670 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1671 $label .= ' - '.$obj->tva_intra;
1672 }
1673
1674 $labelhtml = $label;
1675
1676 if ($showtype) {
1677 $companytemp->id = $obj->rowid;
1678 $companytemp->client = $obj->client;
1679 $companytemp->fournisseur = $obj->fournisseur;
1680 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1681 if ($tmptype) {
1682 $labelhtml .= ' ' . $tmptype;
1683 }
1684
1685 if ($obj->client || $obj->fournisseur) {
1686 $label .= ' (';
1687 }
1688 if ($obj->client == 1 || $obj->client == 3) {
1689 $label .= $langs->trans("Customer");
1690 }
1691 if ($obj->client == 2 || $obj->client == 3) {
1692 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1693 }
1694 if ($obj->fournisseur) {
1695 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1696 }
1697 if ($obj->client || $obj->fournisseur) {
1698 $label .= ')';
1699 }
1700 }
1701
1702 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1703 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1704 if (!empty($obj->country_code)) {
1705 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1706 }
1707 $label .= $s;
1708 $labelhtml .= $s;
1709 }
1710
1711 if (empty($outputmode)) {
1712 if (in_array($obj->rowid, $selected)) {
1713 $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>';
1714 } else {
1715 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1716 }
1717 } else {
1718 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1719 }
1720
1721 $i++;
1722 if (($i % 10) == 0) {
1723 $out .= "\n";
1724 }
1725 }
1726 }
1727 $out .= '</select>' . "\n";
1728 if (!$forcecombo) {
1729 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1730 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1731 }
1732 } else {
1733 dol_print_error($this->db);
1734 }
1735
1736 $this->result = array('nbofthirdparties' => $num);
1737
1738 if ($outputmode) {
1739 return $outarray;
1740 }
1741 return $out;
1742 }
1743
1744
1770 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 = '')
1771 {
1772 global $conf, $user, $langs, $hookmanager, $action;
1773
1774 $langs->load('companies');
1775
1776 if (empty($htmlid)) {
1777 $htmlid = $htmlname;
1778 }
1779 $num = 0;
1780 $out = '';
1781 $outarray = array();
1782
1783 if ($selected === '') {
1784 $selected = array();
1785 } elseif (!is_array($selected)) {
1786 $selected = array((int) $selected);
1787 }
1788
1789 // Clean $filter that may contains sql conditions so sql code
1790 if (function_exists('testSqlAndScriptInject')) {
1791 if (testSqlAndScriptInject($filter, 3) > 0) {
1792 $filter = '';
1793 return 'SQLInjectionTryDetected';
1794 }
1795 }
1796
1797 if ($filter != '') { // If a filter was provided
1798 if (preg_match('/[\‍(\‍)]/', $filter)) {
1799 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1800 $errormsg = '';
1801 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1802
1803 // Redo clean $filter that may contains sql conditions so sql code
1804 if (function_exists('testSqlAndScriptInject')) {
1805 if (testSqlAndScriptInject($filter, 3) > 0) {
1806 $filter = '';
1807 return 'SQLInjectionTryDetected';
1808 }
1809 }
1810 } else {
1811 // If not, we do nothing. We already know that there is no parenthesis
1812 // TODO Disallow this case in a future by returning an error here.
1813 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1814 }
1815 }
1816
1817 if (!is_object($hookmanager)) {
1818 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1819 $hookmanager = new HookManager($this->db);
1820 }
1821
1822 // We search third parties
1823 $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";
1824 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1825 $sql .= ", s.nom as company, s.town AS company_town";
1826 }
1827 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1828 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1829 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON s.rowid = sp.fk_soc";
1830 }
1831 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1832 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1833 if ($socid > 0 || $socid == -1) {
1834 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1835 }
1836 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1837 $sql .= " AND sp.statut <> 0";
1838 }
1839 // filter user access
1840 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
1841 $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 .")";
1842 }
1843 if ($user->socid > 0) {
1844 $sql .= " AND sp.fk_soc = ".((int) $user->socid);
1845 }
1846 if ($filter) {
1847 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1848 // if not, by testSqlAndScriptInject() only.
1849 $sql .= " AND (" . $filter . ")";
1850 }
1851 // Add where from hooks
1852 $parameters = array();
1853 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1854 $sql .= $hookmanager->resPrint;
1855 $sql .= " ORDER BY sp.lastname ASC";
1856
1857 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1858 $resql = $this->db->query($sql);
1859 if ($resql) {
1860 $num = $this->db->num_rows($resql);
1861
1862 if ($htmlname != 'none' && !$options_only) {
1863 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1864 }
1865
1866 if ($showempty && !is_numeric($showempty)) {
1867 $textforempty = $showempty;
1868 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1869 } else {
1870 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1871 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1872 }
1873 if ($showempty == 2) {
1874 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1875 }
1876 }
1877
1878 $i = 0;
1879 if ($num) {
1880 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1881 $contactstatic = new Contact($this->db);
1882
1883 while ($i < $num) {
1884 $obj = $this->db->fetch_object($resql);
1885
1886 // Set email (or phones) and town extended infos
1887 $extendedInfos = '';
1888 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1889 $extendedInfos = array();
1890 $email = trim($obj->email);
1891 if (!empty($email)) {
1892 $extendedInfos[] = $email;
1893 } else {
1894 $phone = trim($obj->phone);
1895 $phone_perso = trim($obj->phone_perso);
1896 $phone_mobile = trim($obj->phone_mobile);
1897 if (!empty($phone)) {
1898 $extendedInfos[] = $phone;
1899 }
1900 if (!empty($phone_perso)) {
1901 $extendedInfos[] = $phone_perso;
1902 }
1903 if (!empty($phone_mobile)) {
1904 $extendedInfos[] = $phone_mobile;
1905 }
1906 }
1907 $contact_town = trim($obj->contact_town);
1908 $company_town = trim($obj->company_town);
1909 if (!empty($contact_town)) {
1910 $extendedInfos[] = $contact_town;
1911 } elseif (!empty($company_town)) {
1912 $extendedInfos[] = $company_town;
1913 }
1914 $extendedInfos = implode(' - ', $extendedInfos);
1915 if (!empty($extendedInfos)) {
1916 $extendedInfos = ' - ' . $extendedInfos;
1917 }
1918 }
1919
1920 $contactstatic->id = $obj->rowid;
1921 $contactstatic->lastname = $obj->lastname;
1922 $contactstatic->firstname = $obj->firstname;
1923 if ($obj->statut == 1) {
1924 $tmplabel = '';
1925 if ($htmlname != 'none') {
1926 $disabled = 0;
1927 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1928 $disabled = 1;
1929 }
1930 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1931 $disabled = 1;
1932 }
1933 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1934 $out .= '<option value="' . $obj->rowid . '"';
1935 if ($disabled) {
1936 $out .= ' disabled';
1937 }
1938 $out .= ' selected>';
1939
1940 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1941 if ($showfunction && $obj->poste) {
1942 $tmplabel .= ' (' . $obj->poste . ')';
1943 }
1944 if (($showsoc > 0) && $obj->company) {
1945 $tmplabel .= ' - (' . $obj->company . ')';
1946 }
1947
1948 $out .= $tmplabel;
1949 $out .= '</option>';
1950 } else {
1951 $out .= '<option value="' . $obj->rowid . '"';
1952 if ($disabled) {
1953 $out .= ' disabled';
1954 }
1955 $out .= '>';
1956
1957 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1958 if ($showfunction && $obj->poste) {
1959 $tmplabel .= ' (' . $obj->poste . ')';
1960 }
1961 if (($showsoc > 0) && $obj->company) {
1962 $tmplabel .= ' - (' . $obj->company . ')';
1963 }
1964
1965 $out .= $tmplabel;
1966 $out .= '</option>';
1967 }
1968 } else {
1969 if (in_array($obj->rowid, $selected)) {
1970 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1971 if ($showfunction && $obj->poste) {
1972 $tmplabel .= ' (' . $obj->poste . ')';
1973 }
1974 if (($showsoc > 0) && $obj->company) {
1975 $tmplabel .= ' - (' . $obj->company . ')';
1976 }
1977
1978 $out .= $tmplabel;
1979 }
1980 }
1981
1982 if ($tmplabel != '') {
1983 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1984 }
1985 }
1986 $i++;
1987 }
1988 } else {
1989 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1990 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1991 $out .= $labeltoshow;
1992 $out .= '</option>';
1993 }
1994
1995 $parameters = array(
1996 'socid' => $socid,
1997 'htmlname' => $htmlname,
1998 'resql' => $resql,
1999 'out' => &$out,
2000 'showfunction' => $showfunction,
2001 'showsoc' => $showsoc,
2002 );
2003
2004 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2005
2006 if ($htmlname != 'none' && !$options_only) {
2007 $out .= '</select>';
2008 }
2009
2010 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
2011 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2012 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
2013 }
2014
2015 $this->num = $num;
2016
2017 if ($options_only === 2) {
2018 // Return array of options
2019 return $outarray;
2020 } else {
2021 return $out;
2022 }
2023 } else {
2024 dol_print_error($this->db);
2025 return -1;
2026 }
2027 }
2028
2029
2030 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2031
2042 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2043 {
2044 // phpcs:enable
2045 global $langs, $conf;
2046
2047 // On recherche les remises
2048 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2049 $sql .= " re.description, re.fk_facture_source";
2050 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2051 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2052 $sql .= " AND re.entity = " . $conf->entity;
2053 if ($filter) {
2054 $sql .= " AND " . $filter;
2055 }
2056 $sql .= " ORDER BY re.description ASC";
2057
2058 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2059 $resql = $this->db->query($sql);
2060 if ($resql) {
2061 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2062 $num = $this->db->num_rows($resql);
2063
2064 $qualifiedlines = $num;
2065
2066 $i = 0;
2067 if ($num) {
2068 print '<option value="0">&nbsp;</option>';
2069 while ($i < $num) {
2070 $obj = $this->db->fetch_object($resql);
2071 $desc = dol_trunc($obj->description, 40);
2072 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2073 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2074 }
2075 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2076 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2077 }
2078 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2079 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2080 }
2081 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2082 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2083 }
2084
2085 $selectstring = '';
2086 if ($selected > 0 && $selected == $obj->rowid) {
2087 $selectstring = ' selected';
2088 }
2089
2090 $disabled = '';
2091 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2092 $qualifiedlines--;
2093 $disabled = ' disabled';
2094 }
2095
2096 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2097 $tmpfac = new Facture($this->db);
2098 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2099 $desc = $desc . ' - ' . $tmpfac->ref;
2100 }
2101 }
2102
2103 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2104 $i++;
2105 }
2106 }
2107 print '</select>';
2108 print ajax_combobox('select_' . $htmlname);
2109
2110 return $qualifiedlines;
2111 } else {
2112 dol_print_error($this->db);
2113 return -1;
2114 }
2115 }
2116
2117
2118 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2119
2135 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2136 {
2137 // phpcs:enable
2138 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2139 }
2140
2141 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2142
2167 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)
2168 {
2169 // phpcs:enable
2170 global $conf, $user, $langs, $hookmanager;
2171 global $action;
2172
2173 // If no preselected user defined, we take current user
2174 if ((is_numeric($selected) && ($selected < -3 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2175 $selected = $user->id;
2176 }
2177
2178 if ($selected === '') {
2179 $selected = array();
2180 } elseif (!is_array($selected)) {
2181 $selected = array($selected);
2182 }
2183
2184 // Exclude some users in $excludeUsers string
2185 $excludeUsers = null;
2186 if (is_array($exclude)) {
2187 $excludeUsers = implode(",", $exclude);
2188 }
2189
2190 // Include some users in $includeUsers string
2191 $includeUsers = null;
2192 $includeUsersArray = array();
2193 if (is_array($include)) {
2194 $includeUsersArray = $include;
2195 } elseif ($include == 'hierarchy') {
2196 // Build list includeUsersArray to have only hierarchy
2197 $includeUsersArray = $user->getAllChildIds(0);
2198 } elseif ($include == 'hierarchyme') {
2199 // Build list includeUsersArray to have only hierarchy and current user
2200 $includeUsersArray = $user->getAllChildIds(1);
2201 }
2202 // Get list of allowed users
2203 /* 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
2204 * see all other users and element in other. For example in agenda, we can have permission to read all event of otherusers.
2205 * So we disable this.
2206 if (!$user->hasRight('user', 'user', 'lire')) {
2207 if (empty($includeUsersArray)) {
2208 $includeUsers = implode(",", $user->getAllChildIds(1));
2209 } else {
2210 $includeUsers = implode(",", array_intersect($includeUsersArray, $user->getAllChildIds(1)));
2211 }
2212 } else {
2213 $includeUsers = implode(",", $includeUsersArray);
2214 } */
2215 $includeUsers = implode(",", $includeUsersArray);
2216
2217 $num = 0;
2218
2219 $out = '';
2220 $outarray = array();
2221 $outarray2 = array();
2222
2223 // Do we want to show the label of entity into the combo list ?
2224 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity) && !preg_match('/^search_/', $htmlname);
2225 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2226
2227 // Forge request to select users
2228 $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";
2229 if ($showlabelofentity) {
2230 $sql .= ", e.label";
2231 }
2232 $sql .= " FROM " . $this->db->prefix() . "user as u";
2233 if ($showlabelofentity) {
2234 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2235 }
2236 // Condition here should be the same than into societe->getSalesRepresentatives().
2237 if ($userissuperadminentityone && $force_entity !== 'default') {
2238 if (!empty($force_entity)) {
2239 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2240 } else {
2241 $sql .= " WHERE u.entity IS NOT NULL";
2242 }
2243 } else {
2244 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2245 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2246 } else {
2247 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2248 }
2249 }
2250
2251 if (!empty($user->socid)) {
2252 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2253 }
2254 if (is_array($exclude) && $excludeUsers) {
2255 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2256 }
2257 if ($includeUsers) {
2258 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2259 }
2260 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2261 $sql .= " AND u.statut <> 0";
2262 }
2263 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2264 $sql .= " AND u.employee <> 0";
2265 }
2266 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2267 $sql .= " AND u.fk_soc IS NULL";
2268 }
2269 if (!empty($morefilter)) {
2270 $errormessage = '';
2271 $sql .= forgeSQLFromUniversalSearchCriteria($morefilter, $errormessage);
2272 if ($errormessage) {
2273 $this->errors[] = $errormessage;
2274 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2275 if ($outputmode == 0) {
2276 return 'Error bad param $morefilter';
2277 } else {
2278 return array();
2279 }
2280 }
2281 }
2282
2283 //Add hook to filter on user (for example on usergroup define in custom modules)
2284 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2285 if (!empty($reshook)) {
2286 $sql .= $hookmanager->resPrint;
2287 }
2288
2289 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2290 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2291 } else {
2292 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2293 }
2294
2295 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2296
2297 $resql = $this->db->query($sql);
2298 if ($resql) {
2299 $num = $this->db->num_rows($resql);
2300 $i = 0;
2301 if ($num) {
2302 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2303 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2304 if ($show_empty && !$multiple) {
2305 $textforempty = ' ';
2306 if (!empty($conf->use_javascript_ajax)) {
2307 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2308 }
2309 if (!is_numeric($show_empty)) {
2310 $textforempty = $show_empty;
2311 }
2312 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2313
2314 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2315 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2316 'id' => ($show_empty < 0 ? $show_empty : -1),
2317 'label' => $textforempty,
2318 'labelhtml' => $textforempty,
2319 'color' => '',
2320 'picto' => ''
2321 );
2322 }
2323 if ($showalso == 2 || $showalso == 3) {
2324 $out .= '<option value="-3"' . ((in_array(-3, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("MyTeam") . ' --</option>' . "\n";
2325
2326 $hasAtLeastOneSubordinate = (count($user->getAllChildIds(1)) > 1);
2327 if ($hasAtLeastOneSubordinate) {
2328 //$sql = "SELECT rowid FROM".MAIN_DB_PREFIX."user "
2329 $outarray[-3] = '-- ' . $langs->trans("MyTeam") . ' --';
2330 $outarray2[-3] = array(
2331 'id' => -3,
2332 'label' => '-- ' . $langs->trans("MyTeam") . ' --',
2333 'labelhtml' => '-- ' . $langs->trans("MyTeam") . ' --',
2334 'color' => '',
2335 'picto' => ''
2336 );
2337 }
2338 }
2339 if ($showalso == 1 || $showalso == 3) {
2340 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2341
2342 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2343 $outarray2[-2] = array(
2344 'id' => -2,
2345 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2346 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2347 'color' => '',
2348 'picto' => ''
2349 );
2350 }
2351
2352 $userstatic = new User($this->db);
2353
2354 while ($i < $num) {
2355 $obj = $this->db->fetch_object($resql);
2356
2357 $userstatic->id = $obj->rowid;
2358 $userstatic->lastname = $obj->lastname;
2359 $userstatic->firstname = $obj->firstname;
2360 $userstatic->photo = $obj->photo;
2361 $userstatic->status = $obj->status;
2362 $userstatic->entity = $obj->entity;
2363 $userstatic->admin = $obj->admin;
2364 $userstatic->gender = $obj->gender;
2365
2366 $disableline = '';
2367 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2368 $disableline = ($enableonlytext ? $enableonlytext : '1');
2369 }
2370
2371 $labeltoshow = '';
2372 $labeltoshowhtml = '';
2373
2374 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2375 $fullNameMode = 0;
2376 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2377 $fullNameMode = 1; //Firstname+lastname
2378 }
2379 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2380 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2381 if (empty($obj->firstname) && empty($obj->lastname)) {
2382 $labeltoshow .= $obj->login;
2383 $labeltoshowhtml .= $obj->login;
2384 }
2385
2386 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2387 $moreinfo = '';
2388 $moreinfohtml = '';
2389 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2390 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2391 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2392 $moreinfo .= $obj->login;
2393 $moreinfohtml .= $obj->login;
2394 }
2395 if ($showstatus >= 0) {
2396 if ($obj->status == 1 && $showstatus == 1) {
2397 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2398 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2399 }
2400 if ($obj->status == 0 && $showstatus == 1) {
2401 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2402 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2403 }
2404 }
2405 if ($showlabelofentity) {
2406 if (empty($obj->entity)) {
2407 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2408 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2409 } else {
2410 if ($obj->entity != $conf->entity) {
2411 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2412 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2413 }
2414 }
2415 }
2416 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2417 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2418 if (!empty($disableline) && $disableline != '1') {
2419 // Add text from $enableonlytext parameter
2420 $moreinfo .= ' - ' . $disableline;
2421 $moreinfohtml .= ' - ' . $disableline;
2422 }
2423 $labeltoshow .= $moreinfo;
2424 $labeltoshowhtml .= $moreinfohtml;
2425
2426 $out .= '<option value="' . $obj->rowid . '"';
2427 if (!empty($disableline)) {
2428 $out .= ' disabled';
2429 }
2430 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2431 $out .= ' selected';
2432 }
2433 $out .= ' data-html="';
2434
2435 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2436 if ($showstatus >= 0 && $obj->status == 0) {
2437 $outhtml .= '<strike class="opacitymediumxxx">';
2438 }
2439 $outhtml .= $labeltoshowhtml;
2440 if ($showstatus >= 0 && $obj->status == 0) {
2441 $outhtml .= '</strike>';
2442 }
2443 $labeltoshowhtml = $outhtml;
2444
2445 $out .= dol_escape_htmltag($outhtml);
2446 $out .= '">';
2447 $out .= $labeltoshow;
2448 $out .= '</option>';
2449
2450 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2451 $outarray2[$userstatic->id] = array(
2452 'id' => $userstatic->id,
2453 'label' => $labeltoshow,
2454 'labelhtml' => $labeltoshowhtml,
2455 'color' => '',
2456 'picto' => ''
2457 );
2458
2459 $i++;
2460 }
2461 } else {
2462 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2463 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2464 }
2465 $out .= '</select>';
2466
2467 if ($num && !$forcecombo) {
2468 // Enhance with select2
2469 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2470 $out .= ajax_combobox($htmlname);
2471 }
2472 } else {
2473 dol_print_error($this->db);
2474 }
2475
2476 $this->num = $num;
2477
2478 if ($outputmode == 2) {
2479 return $outarray2;
2480 } elseif ($outputmode) {
2481 return $outarray;
2482 }
2483
2484 return $out;
2485 }
2486
2487
2488 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2512 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)
2513 {
2514 // phpcs:enable
2515 global $langs, $user;
2516
2517 $userstatic = new User($this->db);
2518 $out = '';
2519
2520 if (!empty($_SESSION['assignedtouser'])) {
2521 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2522 if (!is_array($assignedtouser)) {
2523 $assignedtouser = array();
2524 }
2525 } else {
2526 $assignedtouser = array();
2527 }
2528 $nbassignetouser = count($assignedtouser);
2529
2530 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2531 if ($nbassignetouser) {
2532 $out .= '<ul class="attendees">';
2533 }
2534 $i = 0;
2535 $ownerid = 0;
2536 foreach ($assignedtouser as $key => $value) {
2537 if ($value['id'] == $ownerid) {
2538 continue;
2539 }
2540
2541 $out .= '<li>';
2542 $userstatic->fetch($value['id']);
2543 $out .= $userstatic->getNomUrl(-1);
2544 if ($i == 0) {
2545 $ownerid = $value['id'];
2546 $out .= ' (' . $langs->trans("Owner") . ')';
2547 }
2548 // Add picto to delete owner/assignee
2549 if ($nbassignetouser > 1 && $action != 'view') {
2550 $canremoveassignee = 1;
2551 if ($i == 0) {
2552 // We are on the owner of the event
2553 if (!$canremoveowner) {
2554 $canremoveassignee = 0;
2555 }
2556 if (!$user->hasRight('agenda', 'allactions', 'create')) {
2557 $canremoveassignee = 0; // Can't remove the owner
2558 }
2559 } else {
2560 // We are not on the owner of the event but on a secondary assignee
2561 }
2562 if ($canremoveassignee) {
2563 // If user has all permission, he should be ableto remove a assignee.
2564 // If user has not all permission, he can onlyremove assignee of other (he can't remove itself)
2565 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $userstatic->id . '" class="removedassigned reposition" id="removedassigned_' . $userstatic->id . '" name="removedassigned_' . $userstatic->id . '">';
2566 }
2567 }
2568 // Show my availability
2569 if ($showproperties) {
2570 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2571 $out .= '<div class="myavailability inline-block">';
2572 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;';
2573 //$out .= '<span class="opacitymedium">' . $langs->trans("Availability") . ':</span>';
2574 $out .= '</span>';
2575 $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>';
2576 $out .= '</div>';
2577 }
2578 }
2579 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2580 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2581
2582 $out .= '</li>';
2583 $i++;
2584 }
2585 if ($nbassignetouser) {
2586 $out .= '</ul>';
2587 }
2588
2589 // Method with no ajax
2590 if ($action != 'view') {
2591 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2592 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2593 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2594 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2595 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2596 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2597 $out .= '});';
2598 $out .= '})</script>';
2599 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2600 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2601 $out .= '<br>';
2602 }
2603
2604 return $out;
2605 }
2606
2607 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2627 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())
2628 {
2629 // phpcs:enable
2630 global $langs;
2631
2632 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2633 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2634 $formresources = new FormResource($this->db);
2635 $resourcestatic = new Dolresource($this->db);
2636
2637 $out = '';
2638 if (!empty($_SESSION['assignedtoresource'])) {
2639 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2640 if (!is_array($assignedtoresource)) {
2641 $assignedtoresource = array();
2642 }
2643 } else {
2644 $assignedtoresource = array();
2645 }
2646 $nbassignetoresource = count($assignedtoresource);
2647
2648 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2649 if ($nbassignetoresource) {
2650 $out .= '<ul class="attendees">';
2651 }
2652 $i = 0;
2653
2654 foreach ($assignedtoresource as $key => $value) {
2655 $out .= '<li>';
2656 $resourcestatic->fetch($value['id']);
2657 $out .= $resourcestatic->getNomUrl(-1);
2658 if ($nbassignetoresource >= 1 && $action != 'view') {
2659 $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 . '">';
2660 }
2661 // Show my availability
2662 if ($showproperties) {
2663 if (is_array($listofresourceid) && count($listofresourceid)) {
2664 $out .= '<div class="myavailability inline-block">';
2665 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;';
2666 //$out .= '<span class="opacitymedium">' . $langs->trans("Availability") . ': </span>';
2667 $out .= '</span>';
2668 $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>';
2669 $out .= '</div>';
2670 }
2671 }
2672 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2673 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2674
2675 $out .= '</li>';
2676 $i++;
2677 }
2678 if ($nbassignetoresource) {
2679 $out .= '</ul>';
2680 }
2681
2682 // Method with no ajax
2683 if ($action != 'view') {
2684 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2685 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2686 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2687 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2688 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2689 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2690 $out .= '});';
2691 $out .= '})</script>';
2692
2693 $events = array();
2694 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2695 $out .= $formresources->select_resource_list(0, $htmlname, '', 1, 1, 0, $events, '', 2, 0);
2696 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2697 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2698 $out .= '<br>';
2699 }
2700
2701 return $out;
2702 }
2703
2704 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2705
2735 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)
2736 {
2737 // phpcs:enable
2738 global $langs, $conf;
2739
2740 $out = '';
2741
2742 // check parameters
2743 $price_level = (!empty($price_level) ? $price_level : 0);
2744 if (is_null($ajaxoptions)) {
2745 $ajaxoptions = array();
2746 }
2747
2748 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2749 if (isModEnabled("product") && !isModEnabled('service')) {
2750 $filtertype = '0';
2751 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2752 $filtertype = '1';
2753 }
2754 }
2755
2756 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2757 $placeholder = (is_numeric($showempty) ? '' : 'placeholder="'.dolPrintHTML($showempty).'"');
2758
2759 if ($selected && empty($selected_input_value)) {
2760 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2761 $producttmpselect = new Product($this->db);
2762 $producttmpselect->fetch($selected);
2763 $selected_input_value = $producttmpselect->ref;
2764 unset($producttmpselect);
2765 }
2766 // handle case where product or service module is disabled + no filter specified
2767 if ($filtertype == '') {
2768 if (!isModEnabled('product')) { // when product module is disabled, show services only
2769 $filtertype = 1;
2770 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2771 $filtertype = 0;
2772 }
2773 }
2774 // mode=1 means customers products
2775 $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;
2776 if ((int) $warehouseId > 0) {
2777 $urloption .= '&warehouseid=' . (int) $warehouseId;
2778 }
2779
2780 if (isModEnabled('variants') && is_array($selected_combinations)) {
2781 // Code to automatically insert with javascript the select of attributes under the select of product
2782 // when a parent of variant has been selected.
2783 // Note: Samecode than for product input using select
2784 $htmltag = 'input';
2785 $out .= '
2786 <!-- script to auto show attributes select tags if a variant was selected -->
2787 <script nonce="' . getNonce() . '">
2788 // auto show attributes fields
2789 selected = ' . json_encode($selected_combinations) . ';
2790 combvalues = {};
2791
2792 jQuery(document).ready(function () {
2793
2794 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2795 if (jQuery(this).val() == \'free\') {
2796 jQuery(\'div#attributes_box\').empty();
2797 }
2798 });
2799
2800 jQuery("'.$htmltag.'#' . $htmlname . '").change(function () {
2801
2802 if (!jQuery(this).val()) {
2803 jQuery(\'div#attributes_box\').empty();
2804 return;
2805 }
2806
2807 console.log("A change has started. We get variants fields to inject html select");
2808
2809 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2810 id: jQuery(this).val()
2811 }, function (data) {
2812 jQuery(\'div#attributes_box\').empty();
2813
2814 jQuery.each(data, function (key, val) {
2815
2816 combvalues[val.id] = val.values;
2817
2818 var span = jQuery(document.createElement(\'div\')).css({
2819 \'display\': \'table-row\'
2820 });
2821
2822 span.append(
2823 jQuery(document.createElement(\'div\')).text(val.label).css({
2824 \'font-weight\': \'bold\',
2825 \'display\': \'table-cell\'
2826 })
2827 );
2828
2829 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2830 \'margin-left\': \'15px\',
2831 \'white-space\': \'pre\'
2832 }).append(
2833 jQuery(document.createElement(\'option\')).val(\'\')
2834 );
2835
2836 jQuery.each(combvalues[val.id], function (key, val) {
2837 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2838
2839 if (selected[val.fk_product_attribute] == val.id) {
2840 tag.attr(\'selected\', \'selected\');
2841 }
2842
2843 html.append(tag);
2844 });
2845
2846 span.append(html);
2847 jQuery(\'div#attributes_box\').append(span);
2848 });
2849 })
2850 });
2851
2852 ' . ($selected ? 'jQuery("'.$htmltag.'#' . $htmlname . '").change();' : '') . '
2853 });
2854 </script>
2855 ';
2856 }
2857
2858 if (empty($hidelabel)) {
2859 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2860 } elseif ($hidelabel > 1) {
2861 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2862 if ($hidelabel == 2) {
2863 $out .= img_picto($langs->trans("Search"), 'search');
2864 }
2865 }
2866
2867 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2868 if ($hidelabel == 3) {
2869 $out .= img_picto($langs->trans("Search"), 'search');
2870 }
2871
2872 $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);
2873 } else {
2874 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2875
2876 if (isModEnabled('variants') && is_array($selected_combinations)) {
2877 // Code to automatically insert with javascript the select of attributes under the select of product
2878 // when a parent of variant has been selected.
2879 // Note: Samecode than for product input using Ajax
2880 $htmltag = 'select';
2881 $out .= '
2882 <!-- script to auto show attributes select tags if a variant was selected -->
2883 <script nonce="' . getNonce() . '">
2884 // auto show attributes fields
2885 selected = ' . json_encode($selected_combinations) . ';
2886 combvalues = {};
2887
2888 jQuery(document).ready(function () {
2889
2890 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2891 if (jQuery(this).val() == \'free\') {
2892 jQuery(\'div#attributes_box\').empty();
2893 }
2894 });
2895
2896 jQuery("'.$htmltag.'#' . $htmlname . '").change(function () {
2897
2898 if (!jQuery(this).val()) {
2899 jQuery(\'div#attributes_box\').empty();
2900 return;
2901 }
2902
2903 console.log("A change has started. We get variants fields to inject html select");
2904
2905 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2906 id: jQuery(this).val()
2907 }, function (data) {
2908 jQuery(\'div#attributes_box\').empty();
2909
2910 jQuery.each(data, function (key, val) {
2911
2912 combvalues[val.id] = val.values;
2913
2914 var span = jQuery(document.createElement(\'div\')).css({
2915 \'display\': \'table-row\'
2916 });
2917
2918 span.append(
2919 jQuery(document.createElement(\'div\')).text(val.label).css({
2920 \'font-weight\': \'bold\',
2921 \'display\': \'table-cell\'
2922 })
2923 );
2924
2925 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2926 \'margin-left\': \'15px\',
2927 \'white-space\': \'pre\'
2928 }).append(
2929 jQuery(document.createElement(\'option\')).val(\'\')
2930 );
2931
2932 jQuery.each(combvalues[val.id], function (key, val) {
2933 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2934
2935 if (selected[val.fk_product_attribute] == val.id) {
2936 tag.attr(\'selected\', \'selected\');
2937 }
2938
2939 html.append(tag);
2940 });
2941
2942 span.append(html);
2943 jQuery(\'div#attributes_box\').append(span);
2944 });
2945 })
2946 });
2947
2948 ' . ($selected ? 'jQuery("'.$htmltag.'#' . $htmlname . '").change();' : '') . '
2949 });
2950 </script>
2951 ';
2952 }
2953 }
2954
2955 if (empty($nooutput)) {
2956 print $out;
2957 } else {
2958 return $out;
2959 }
2960 }
2961
2962 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2963
2979 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2980 {
2981 // phpcs:enable
2982 global $db;
2983
2984 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2985
2986 $error = 0;
2987 $out = '';
2988
2989 if (!$forcecombo) {
2990 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2991 $events = array();
2992 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("BOM_USE_SEARCH_TO_SELECT"));
2993 }
2994
2995 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2996
2997 $sql = 'SELECT b.rowid, b.ref, b.label as bomLabel, p.label as productLabel';
2998 $sql .= ' FROM ' . $this->db->prefix() . 'bom_bom as b';
2999 $sql .= ' INNER JOIN ' . $this->db->prefix() . 'product as p ON b.fk_product = p.rowid';
3000 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
3001 if (!empty($status)) {
3002 $sql .= ' AND status = ' . (int) $status;
3003 }
3004 if (!empty($type)) {
3005 $sql .= ' AND bomtype = ' . (int) $type;
3006 }
3007 if (!empty($TProducts)) {
3008 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
3009 }
3010 if (!empty($limit)) {
3011 $sql .= ' LIMIT ' . (int) $limit;
3012 }
3013 $resql = $db->query($sql);
3014 if ($resql) {
3015 if ($showempty) {
3016 $out .= '<option value="-1"';
3017 if (empty($selected)) {
3018 $out .= ' selected';
3019 }
3020 $out .= '>&nbsp;</option>';
3021 }
3022 while ($obj = $db->fetch_object($resql)) {
3023 $out .= '<option value="' . $obj->rowid . '"';
3024 if ($obj->rowid == $selected) {
3025 $out .= 'selected';
3026 }
3027 $out .= '>' . $obj->ref . ' - ' . $obj->productLabel . ' - ' . $obj->bomLabel . '</option>';
3028 }
3029 } else {
3030 $error++;
3031 dol_print_error($db);
3032 }
3033 $out .= '</select>';
3034 if (empty($nooutput)) {
3035 print $out;
3036 } else {
3037 return $out;
3038 }
3039 }
3040
3041 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3042
3069 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)
3070 {
3071 // phpcs:enable
3072 global $langs;
3073 global $hookmanager;
3074
3075 $out = '';
3076 $outarray = array();
3077
3078 // Units
3079 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3080 $langs->load('other');
3081 }
3082
3083 $warehouseStatusArray = array();
3084 if (!empty($warehouseStatus)) {
3085 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
3086 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
3087 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
3088 }
3089 if (preg_match('/warehouseopen/', $warehouseStatus)) {
3090 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
3091 }
3092 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
3093 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
3094 }
3095 }
3096
3097 $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";
3098 if (count($warehouseStatusArray)) {
3099 $selectFieldsGrouped = ", sum(" . $this->db->ifsql("e.statut IS NULL", "0", "ps.reel") . ") as stock"; // e.statut is null if there is no record in stock
3100 } else {
3101 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", '0', "p.stock") . " AS stock";
3102 }
3103
3104 $sql = "SELECT ";
3105
3106 // Add select from hooks
3107 $parameters = array();
3108 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
3109 if (empty($reshook)) {
3110 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
3111 } else {
3112 $sql .= $hookmanager->resPrint;
3113 }
3114
3115 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3116 //Product category
3117 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
3118 FROM " . $this->db->prefix() . "categorie_product
3119 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
3120 LIMIT 1
3121 ) AS categorie_product_id ";
3122 }
3123
3124 //Price by customer
3125 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3126 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
3127 $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';
3128 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref, custdiscount_percent";
3129 }
3130 // Units
3131 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3132 $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";
3133 $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';
3134 }
3135
3136 // Multilang : we add translation
3137 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3138 $sql .= ", pl.label as label_translated";
3139 $sql .= ", pl.description as description_translated";
3140 $selectFields .= ", label_translated";
3141 $selectFields .= ", description_translated";
3142 }
3143 // Price by quantity
3144 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3145 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
3146 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3147 $sql .= " AND price_level = " . ((int) $price_level);
3148 }
3149 $sql .= " ORDER BY date_price";
3150 $sql .= " DESC LIMIT 1) as price_rowid";
3151 $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
3152 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3153 $sql .= " AND price_level = " . ((int) $price_level);
3154 }
3155 $sql .= " ORDER BY date_price";
3156 $sql .= " DESC LIMIT 1) as price_by_qty";
3157 $selectFields .= ", price_rowid, price_by_qty";
3158 }
3159
3160 $sql .= " FROM ".$this->db->prefix()."product as p";
3161
3162 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
3163 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
3164 }
3165
3166 // Add from (left join) from hooks
3167 $parameters = array(
3168 'socid' => $socid,
3169 );
3170 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3171 $sql .= $hookmanager->resPrint;
3172
3173 if (count($warehouseStatusArray)) {
3174 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
3175 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3176 $sql .= ' AND e.statut IN (' . $this->db->sanitize($this->db->escape(implode(',', $warehouseStatusArray))) . ')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0.
3177 }
3178
3179 //Price by customer
3180 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3181 $now = dol_now();
3182 $sql .= " LEFT JOIN (";
3183 $sql .= " SELECT pcp1.*";
3184 $sql .= " FROM " . $this->db->prefix() . "product_customer_price AS pcp1";
3185 $sql .= " LEFT JOIN (";
3186 $sql .= " SELECT fk_soc, fk_product, MIN(date_begin) AS date_begin";
3187 $sql .= " FROM " . $this->db->prefix() . "product_customer_price";
3188 $sql .= " WHERE fk_soc = " . ((int) $socid);
3189 $sql .= " AND date_begin <= '" . $this->db->idate($now) . "'";
3190 $sql .= " AND (date_end IS NULL OR '" . $this->db->idate($now) . "' <= date_end)";
3191 $sql .= " GROUP BY fk_soc, fk_product";
3192 $sql .= " ) AS pcp2 ON pcp1.fk_soc = pcp2.fk_soc AND pcp1.fk_product = pcp2.fk_product AND pcp1.date_begin = pcp2.date_begin";
3193 $sql .= " WHERE pcp2.fk_soc IS NOT NULL";
3194 $sql .= " ) AS pcp ON pcp.fk_soc = " . ((int) $socid) . " AND pcp.fk_product = p.rowid";
3195 }
3196 // Units
3197 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3198 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3199 }
3200 // Multilang : we add translation
3201 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3202 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3203 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3204 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3205 $soc = new Societe($this->db);
3206 $result = $soc->fetch($socid);
3207 if ($result > 0 && !empty($soc->default_lang)) {
3208 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3209 } else {
3210 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3211 }
3212 } else {
3213 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3214 }
3215 }
3216
3217 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3218 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3219 }
3220
3221 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3222
3223 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3224 $sql .= " AND pac.rowid IS NULL";
3225 }
3226
3227 if ($finished == 0) {
3228 $sql .= " AND p.finished = " . ((int) $finished);
3229 } elseif ($finished == 1) {
3230 $sql .= " AND p.finished = ".((int) $finished);
3231 }
3232 if ($status >= 0) {
3233 $sql .= " AND p.tosell = ".((int) $status);
3234 }
3235 if ($status_purchase >= 0) {
3236 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3237 }
3238 // Filter by product type
3239 if (strval($filtertype) != '') {
3240 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3241 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3242 $sql .= " AND p.fk_product_type = 1";
3243 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3244 $sql .= " AND p.fk_product_type = 0";
3245 }
3246
3247 if ((int) $warehouseId > 0) {
3248 $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)";
3249 }
3250
3251 // Add where from hooks
3252 $parameters = array(
3253 'filterkey' => &$filterkey,
3254 'socid' => $socid,
3255 );
3256 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3257 $sql .= $hookmanager->resPrint;
3258 // Add criteria on ref/label
3259 if ($filterkey != '') {
3260 $sqlSupplierSearch = '';
3261
3262 $sql .= ' AND (';
3263 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3264 // For natural search
3265 $search_crit = explode(' ', $filterkey);
3266 $i = 0;
3267 if (count($search_crit) > 1) {
3268 $sql .= "(";
3269 }
3270 foreach ($search_crit as $crit) {
3271 if ($i > 0) {
3272 $sql .= " AND ";
3273 }
3274 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3275 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3276 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3277 }
3278 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3279 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3280 }
3281 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3282 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3283 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3284 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3285 }
3286 }
3287
3288 // include search in supplier ref
3289 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3290 $sqlSupplierSearch .= !empty($sqlSupplierSearch) ? ' AND ':'';
3291 $sqlSupplierSearch .= " pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3292 }
3293 $sql .= ")";
3294 $i++;
3295 }
3296 if (count($search_crit) > 1) {
3297 $sql .= ")";
3298 }
3299 if (isModEnabled('barcode')) {
3300 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3301 }
3302
3303 // include search in supplier ref
3304 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3305 $sql .= " OR EXISTS (SELECT pfp.fk_product FROM " . $this->db->prefix() . "product_fournisseur_price as pfp WHERE p.rowid = pfp.fk_product";
3306 $sql .= " AND (";
3307 $sql .= $sqlSupplierSearch;
3308 $sql .= "))";
3309 }
3310
3311 $sql .= ')';
3312 }
3313 if (count($warehouseStatusArray)) {
3314 $sql .= " GROUP BY " . $selectFields;
3315 }
3316
3317 //Sort by category
3318 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3319 $sql .= " ORDER BY categorie_product_id ";
3320 //ASC OR DESC order
3321 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3322 } else {
3323 $sql .= $this->db->order("p.ref");
3324 }
3325
3326 $limit = getDolGlobalInt('SEARCH_LIMIT_AJAX') ?: $limit;
3327 $sql .= $this->db->plimit($limit, 0);
3328
3329 // Build output string
3330 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3331 $result = $this->db->query($sql);
3332 if ($result) {
3333 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3334 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3335 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3336
3337 $num = $this->db->num_rows($result);
3338
3339 $events = array();
3340
3341 if (!$forcecombo) {
3342 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3343 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3344 }
3345
3346 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3347
3348 $textifempty = '';
3349 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3350 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3351 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3352 if ($showempty && !is_numeric($showempty)) {
3353 $textifempty = $langs->trans($showempty);
3354 } else {
3355 $textifempty .= $langs->trans("All");
3356 }
3357 } else {
3358 if ($showempty && !is_numeric($showempty)) {
3359 $textifempty = $langs->trans($showempty);
3360 }
3361 }
3362 if ($showempty) {
3363 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3364 }
3365
3366 $i = 0;
3367 while ($num && $i < $num) {
3368 $opt = '';
3369 $optJson = array();
3370 $objp = $this->db->fetch_object($result);
3371
3372 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
3373 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3374 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3375 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3376 $sql .= " ORDER BY quantity ASC";
3377
3378 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3379 $result2 = $this->db->query($sql);
3380 if ($result2) {
3381 $nb_prices = $this->db->num_rows($result2);
3382 $j = 0;
3383 while ($nb_prices && $j < $nb_prices) {
3384 $objp2 = $this->db->fetch_object($result2);
3385
3386 $objp->price_by_qty_rowid = $objp2->rowid;
3387 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3388 $objp->price_by_qty_quantity = $objp2->quantity;
3389 $objp->price_by_qty_unitprice = $objp2->unitprice;
3390 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3391 // For backward compatibility
3392 $objp->quantity = $objp2->quantity;
3393 $objp->price = $objp2->price;
3394 $objp->unitprice = $objp2->unitprice;
3395 $objp->remise_percent = $objp2->remise_percent;
3396
3397 //$objp->tva_tx is not overwritten by $objp2 value
3398 //$objp->default_vat_code is not overwritten by $objp2 value
3399
3400 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3401 '@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';
3402 $j++;
3403
3404 // Add new entry
3405 // "key" value of json key array is used by jQuery automatically as selected value
3406 // "label" value of json key array is used by jQuery automatically as text for combo box
3407 $out .= $opt;
3408 array_push($outarray, $optJson);
3409 }
3410 }
3411 } else {
3412 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3413 $price_product = new Product($this->db);
3414 $price_product->fetch($objp->rowid, '', '', '1');
3415
3416 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3417 $priceparser = new PriceParser($this->db);
3418 $price_result = $priceparser->parseProduct($price_product);
3419 if ($price_result >= 0) {
3420 $objp->price = $price_result;
3421 $objp->unitprice = $price_result;
3422 //Calculate the VAT
3423 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3424 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3425 }
3426 }
3427 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3428 $price_level = '';
3429 }
3430 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3431 // Add new entry
3432 // "key" value of json key array is used by jQuery automatically as selected value
3433 // "label" value of json key array is used by jQuery automatically as text for combo box
3434 $out .= $opt;
3435 array_push($outarray, $optJson);
3436 }
3437
3438 $i++;
3439 }
3440
3441 $out .= '</select>';
3442
3443 $this->db->free($result);
3444
3445 if (empty($outputmode)) {
3446 return $out;
3447 }
3448
3449 return $outarray;
3450 } else {
3451 dol_print_error($this->db);
3452 }
3453
3454 return '';
3455 }
3456
3472 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3473 {
3474 global $langs, $conf, $user;
3475 global $hookmanager;
3476
3477 $outkey = '';
3478 $outval = '';
3479 $outref = '';
3480 $outlabel = '';
3481 $outlabel_translated = '';
3482 $outdesc = '';
3483 $outdesc_translated = '';
3484 $outbarcode = '';
3485 $outorigin = '';
3486 $outtype = '';
3487 $outprice_ht = '';
3488 $outprice_ttc = '';
3489 $outpricebasetype = '';
3490 $outtva_tx = '';
3491 $outdefault_vat_code = '';
3492 $outqty = 1;
3493 $outdiscount = '0';
3494
3495 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3496
3497 $label = $objp->label;
3498 if (!empty($objp->label_translated)) {
3499 $label = $objp->label_translated;
3500 }
3501 if (!empty($filterkey) && $filterkey != '') {
3502 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3503 }
3504
3505 $outkey = $objp->rowid;
3506 $outref = $objp->ref;
3507 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3508 $outlabel = $objp->label;
3509 $outdesc = $objp->description;
3510 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3511 $outlabel_translated = $objp->label_translated;
3512 $outdesc_translated = $objp->description_translated;
3513 }
3514 $outbarcode = $objp->barcode;
3515 $outorigin = $objp->fk_country;
3516 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3517
3518 $outtype = $objp->fk_product_type;
3519 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3520 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3521
3522 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3523 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3524 }
3525
3526 // Units
3527 $outvalUnits = '';
3528 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3529 if (!empty($objp->unit_short)) {
3530 $outvalUnits .= ' - ' . $objp->unit_short;
3531 }
3532 }
3533 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3534 if (!empty($objp->weight) && $objp->weight_units !== null) {
3535 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3536 $outvalUnits .= ' - ' . $unitToShow;
3537 }
3538 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3539 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3540 $outvalUnits .= ' - ' . $unitToShow;
3541 }
3542 if (!empty($objp->surface) && $objp->surface_units !== null) {
3543 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3544 $outvalUnits .= ' - ' . $unitToShow;
3545 }
3546 if (!empty($objp->volume) && $objp->volume_units !== null) {
3547 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3548 $outvalUnits .= ' - ' . $unitToShow;
3549 }
3550 }
3551 if ($outdurationvalue && $outdurationunit) {
3552 $da = array(
3553 'h' => $langs->trans('Hour'),
3554 'd' => $langs->trans('Day'),
3555 'w' => $langs->trans('Week'),
3556 'm' => $langs->trans('Month'),
3557 'y' => $langs->trans('Year')
3558 );
3559 if (isset($da[$outdurationunit])) {
3560 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3561 }
3562 }
3563
3564 // Set stocktag (stock too low or not or unknown)
3565 $stocktag = 0;
3566 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3567 if ($user->hasRight('stock', 'lire')) {
3568 if ($objp->stock > 0) {
3569 $stocktag = 1;
3570 } elseif ($objp->stock <= 0) {
3571 $stocktag = -1;
3572 }
3573 }
3574 }
3575
3576 // Set $labeltoshow
3577 $labeltoshow = '';
3578 $labeltoshow .= $objp->ref;
3579 if (!empty($objp->custref)) {
3580 $labeltoshow .= ' (' . $objp->custref . ')';
3581 }
3582 if ($outbarcode) {
3583 $labeltoshow .= ' (' . $outbarcode . ')';
3584 }
3585 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3586 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3587 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3588 }
3589
3590 // Set $labltoshowhtml
3591 $labeltoshowhtml = '';
3592 $labeltoshowhtml .= $objp->ref;
3593 if (!empty($objp->custref)) {
3594 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3595 }
3596 if (!empty($filterkey) && $filterkey != '') {
3597 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3598 }
3599 if ($outbarcode) {
3600 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3601 }
3602 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3603 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3604 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3605 }
3606
3607 // Stock
3608 $labeltoshowstock = '';
3609 $labeltoshowhtmlstock = '';
3610 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3611 if ($user->hasRight('stock', 'lire')) {
3612 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3613
3614 if ($objp->stock > 0) {
3615 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3616 } elseif ($objp->stock <= 0) {
3617 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3618 }
3619 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3620 $labeltoshowhtmlstock .= '</span>';
3621
3622 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3623 $langs->load("stocks");
3624
3625 $tmpproduct = new Product($this->db);
3626 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3627 $tmpproduct->load_virtual_stock();
3628 $virtualstock = $tmpproduct->stock_theorique;
3629
3630 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3631
3632 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3633 if ($virtualstock > 0) {
3634 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3635 } elseif ($virtualstock <= 0) {
3636 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3637 }
3638 $labeltoshowhtmlstock .= $virtualstock;
3639 $labeltoshowhtmlstock .= '</span>';
3640
3641 unset($tmpproduct);
3642 }
3643 }
3644 }
3645
3646 // Price
3647 $found = 0;
3648 $labeltoshowprice = '';
3649 $labeltoshowhtmlprice = '';
3650 // If we need a particular price level (from 1 to n)
3651 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3652 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3653 $sql .= " FROM " . $this->db->prefix() . "product_price";
3654 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3655 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3656 $sql .= " AND price_level = " . ((int) $price_level);
3657 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3658 $sql .= " LIMIT 1";
3659
3660 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3661 $result2 = $this->db->query($sql);
3662 if ($result2) {
3663 $objp2 = $this->db->fetch_object($result2);
3664 if ($objp2) {
3665 $found = 1;
3666 if ($objp2->price_base_type == 'HT') {
3667 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3668 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3669 } else {
3670 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3671 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3672 }
3673 $outprice_ht = price($objp2->price);
3674 $outprice_ttc = price($objp2->price_ttc);
3675 $outpricebasetype = $objp2->price_base_type;
3676 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3677 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3678 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3679 } else {
3680 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3681 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3682 }
3683 }
3684 } else {
3685 dol_print_error($this->db);
3686 }
3687 }
3688
3689 // Price by quantity
3690 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3691 $found = 1;
3692 $outqty = $objp->quantity;
3693 $outdiscount = $objp->remise_percent;
3694 if ($objp->quantity == 1) {
3695 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3696 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3697 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3698 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3699 } else {
3700 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3701 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3702 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3703 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3704 }
3705
3706 $outprice_ht = price($objp->unitprice);
3707 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3708 $outpricebasetype = $objp->price_base_type;
3709 $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
3710 $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
3711 }
3712 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3713 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3714 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3715 }
3716 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3717 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3718 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3719 }
3720
3721 // Price by customer
3722 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3723 if (!empty($objp->idprodcustprice)) {
3724 $found = 1;
3725
3726 if ($objp->custprice_base_type == 'HT') {
3727 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3728 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3729 } else {
3730 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3731 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3732 }
3733
3734 $outprice_ht = price($objp->custprice);
3735 $outprice_ttc = price($objp->custprice_ttc);
3736 $outpricebasetype = $objp->custprice_base_type;
3737 $outtva_tx = $objp->custtva_tx;
3738 $outdefault_vat_code = $objp->custdefault_vat_code;
3739 $outdiscount = $objp->custdiscount_percent;
3740 }
3741 }
3742
3743 // If level no defined or multiprice not found, we used the default price
3744 if (empty($hidepriceinlabel) && !$found) {
3745 if ($objp->price_base_type == 'HT') {
3746 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3747 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3748 } else {
3749 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3750 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3751 }
3752 $outprice_ht = price($objp->price);
3753 $outprice_ttc = price($objp->price_ttc);
3754 $outpricebasetype = $objp->price_base_type;
3755 $outtva_tx = $objp->tva_tx;
3756 $outdefault_vat_code = $objp->default_vat_code;
3757 }
3758
3759 // Build options
3760 $opt = '<option value="' . $objp->rowid . '"';
3761 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3762 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3763 $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 . '"';
3764 }
3765 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3766 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3767 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3768 }
3769
3770 if ($stocktag == 1) {
3771 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3772 //$opt .= ' class="product_line_stock_ok"';
3773 }
3774 if ($stocktag == -1) {
3775 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3776 //$opt .= ' class="product_line_stock_too_low"';
3777 }
3778
3779 $opt .= '>';
3780
3781 // Ref, barcode, country
3782 $opt .= $labeltoshow;
3783 $outval .= $labeltoshowhtml;
3784
3785 // Units
3786 $opt .= $outvalUnits;
3787 $outval .= $outvalUnits;
3788
3789 // Price
3790 $opt .= $labeltoshowprice;
3791 $outval .= $labeltoshowhtmlprice;
3792
3793 // Stock
3794 $opt .= $labeltoshowstock;
3795 $outval .= $labeltoshowhtmlstock;
3796
3797
3798 $parameters = array('objp' => $objp);
3799 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3800 if (empty($reshook)) {
3801 $opt .= $hookmanager->resPrint;
3802 } else {
3803 $opt = $hookmanager->resPrint;
3804 }
3805
3806 $opt .= "</option>\n";
3807 $optJson = array(
3808 'key' => $outkey,
3809 'value' => $outref,
3810 'label' => $outval,
3811 'label2' => $outlabel,
3812 'desc' => $outdesc,
3813 'type' => $outtype,
3814 'price_ht' => price2num($outprice_ht),
3815 'price_ttc' => price2num($outprice_ttc),
3816 'price_ht_locale' => price(price2num($outprice_ht)),
3817 'price_ttc_locale' => price(price2num($outprice_ttc)),
3818 'pricebasetype' => $outpricebasetype,
3819 'tva_tx' => $outtva_tx,
3820 'default_vat_code' => $outdefault_vat_code,
3821 'qty' => $outqty,
3822 'discount' => $outdiscount,
3823 'duration_value' => $outdurationvalue,
3824 'duration_unit' => $outdurationunit,
3825 'pbq' => $outpbq,
3826 'labeltrans' => $outlabel_translated,
3827 'desctrans' => $outdesc_translated,
3828 'ref_customer' => $outrefcust
3829 );
3830 }
3831
3832 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3833
3850 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '', $nooutput = 0)
3851 {
3852 // phpcs:enable
3853 global $langs, $conf;
3854 global $price_level, $status, $finished;
3855
3856 if (!isset($status)) {
3857 $status = 1;
3858 }
3859
3860 $selected_input_value = '';
3861 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3862 if ((int) $selected > 0) {
3863 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3864 $producttmpselect = new Product($this->db);
3865 $producttmpselect->fetch((int) $selected);
3866 $selected_input_value = $producttmpselect->ref;
3867 unset($producttmpselect);
3868 }
3869
3870 // mode=2 means suppliers products
3871 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3872
3873 $s = ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3874
3875 $s .= ($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3876 } else {
3877 $s = $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, getDolGlobalInt('SUPPLIER_SHOW_STOCK_IN_PRODUCTS_COMBO'), $placeholder);
3878 }
3879
3880 if ($nooutput) {
3881 return $s;
3882 } else {
3883 print $s;
3884 }
3885 }
3886
3887 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3888
3907 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 = '')
3908 {
3909 // phpcs:enable
3910 global $langs, $conf, $user;
3911 global $hookmanager;
3912
3913 $out = '';
3914 $outarray = array();
3915
3916 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3917
3918 $langs->load('stocks');
3919 // Units
3920 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3921 $langs->load('other');
3922 }
3923
3924 $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,";
3925 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3926 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3927 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3928 $sql .= ", pfp.supplier_reputation";
3929 // if we use supplier description of the products
3930 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3931 $sql .= ", pfp.desc_fourn as description";
3932 } else {
3933 $sql .= ", p.description";
3934 }
3935 // Units
3936 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3937 $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";
3938 }
3939
3940 // Add select from hooks
3941 $parameters = [];
3942 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
3943 $sql .= $hookmanager->resPrint;
3944
3945 $sql .= " FROM " . $this->db->prefix() . "product as p";
3946
3947 // Add join from hooks
3948 $parameters = [];
3949 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3950 $sql .= $hookmanager->resPrint;
3951
3952 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3953 if ($socid > 0) {
3954 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3955 }
3956 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3957 // Units
3958 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3959 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3960 }
3961 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3962 if ($statut != -1) {
3963 $sql .= " AND p.tobuy = " . ((int) $statut);
3964 }
3965 if (strval($filtertype) != '') {
3966 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3967 }
3968 if (!empty($filtre)) {
3969 $sql .= " " . $filtre;
3970 }
3971 // Add where from hooks
3972 $parameters = array();
3973 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3974 $sql .= $hookmanager->resPrint;
3975 // Add criteria on ref/label
3976 if ($filterkey != '') {
3977 $sql .= ' AND (';
3978 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3979 // For natural search
3980 $search_crit = explode(' ', $filterkey);
3981 $i = 0;
3982 if (count($search_crit) > 1) {
3983 $sql .= "(";
3984 }
3985 foreach ($search_crit as $crit) {
3986 if ($i > 0) {
3987 $sql .= " AND ";
3988 }
3989 $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) . "%'";
3990 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3991 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3992 }
3993 $sql .= ")";
3994 $i++;
3995 }
3996 if (count($search_crit) > 1) {
3997 $sql .= ")";
3998 }
3999 if (isModEnabled('barcode')) {
4000 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
4001 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
4002 }
4003 $sql .= ')';
4004 }
4005 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
4006 $sql .= $this->db->plimit($limit, 0);
4007
4008 // Build output string
4009
4010 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
4011 $result = $this->db->query($sql);
4012 if ($result) {
4013 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4014 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
4015
4016 $num = $this->db->num_rows($result);
4017
4018 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
4019 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
4020 if (!$selected) {
4021 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
4022 } else {
4023 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
4024 }
4025
4026 $i = 0;
4027 while ($i < $num) {
4028 $objp = $this->db->fetch_object($result);
4029
4030 if (is_null($objp->idprodfournprice)) {
4031 // There is no supplier price found, we will use the vat rate for sale
4032 $objp->tva_tx = $objp->tva_tx_sale;
4033 $objp->default_vat_code = $objp->default_vat_code_sale;
4034 }
4035
4036 $outkey = $objp->idprodfournprice; // id in table of price
4037 if (!$outkey && $alsoproductwithnosupplierprice) {
4038 $outkey = 'idprod_' . $objp->rowid; // id of product
4039 }
4040
4041 $outref = $objp->ref;
4042 $outbarcode = $objp->barcode;
4043 $outqty = 1;
4044 $outdiscount = 0;
4045 $outtype = $objp->fk_product_type;
4046 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
4047 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
4048
4049 // Units
4050 $outvalUnits = '';
4051 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
4052 if (!empty($objp->unit_short)) {
4053 $outvalUnits .= ' - ' . $objp->unit_short;
4054 }
4055 if (!empty($objp->weight) && $objp->weight_units !== null) {
4056 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
4057 $outvalUnits .= ' - ' . $unitToShow;
4058 }
4059 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
4060 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
4061 $outvalUnits .= ' - ' . $unitToShow;
4062 }
4063 if (!empty($objp->surface) && $objp->surface_units !== null) {
4064 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
4065 $outvalUnits .= ' - ' . $unitToShow;
4066 }
4067 if (!empty($objp->volume) && $objp->volume_units !== null) {
4068 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
4069 $outvalUnits .= ' - ' . $unitToShow;
4070 }
4071 if ($outdurationvalue && $outdurationunit) {
4072 $da = array(
4073 'h' => $langs->trans('Hour'),
4074 'd' => $langs->trans('Day'),
4075 'w' => $langs->trans('Week'),
4076 'm' => $langs->trans('Month'),
4077 'y' => $langs->trans('Year')
4078 );
4079 if (isset($da[$outdurationunit])) {
4080 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
4081 }
4082 }
4083 }
4084
4085 $objRef = $objp->ref;
4086 if ($filterkey && $filterkey != '') {
4087 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
4088 }
4089 $objRefFourn = $objp->ref_fourn;
4090 if ($filterkey && $filterkey != '') {
4091 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
4092 }
4093 $label = $objp->label;
4094 if ($filterkey && $filterkey != '') {
4095 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
4096 }
4097
4098 switch ($objp->fk_product_type) {
4100 $picto = 'product';
4101 break;
4103 $picto = 'service';
4104 break;
4105 default:
4106 $picto = '';
4107 break;
4108 }
4109
4110 if (empty($picto)) {
4111 $optlabel = '';
4112 } else {
4113 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
4114 }
4115
4116 $optlabel .= $objp->ref;
4117 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
4118 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
4119 }
4120 if (isModEnabled('barcode') && !empty($objp->barcode)) {
4121 $optlabel .= ' (' . $outbarcode . ')';
4122 }
4123 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
4124
4125 $outvallabel = $objRef;
4126 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
4127 $outvallabel .= ' (' . $objRefFourn . ')';
4128 }
4129 if (isModEnabled('barcode') && !empty($objp->barcode)) {
4130 $outvallabel .= ' (' . $outbarcode . ')';
4131 }
4132 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
4133
4134 // Units
4135 $optlabel .= $outvalUnits;
4136 $outvallabel .= $outvalUnits;
4137
4138 if (!empty($objp->idprodfournprice)) {
4139 $outqty = $objp->quantity;
4140 $outdiscount = $objp->remise_percent;
4141 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4142 $prod_supplier = new ProductFournisseur($this->db);
4143 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4144 $prod_supplier->id = $objp->fk_product;
4145 $prod_supplier->fourn_qty = $objp->quantity;
4146 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4147 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4148
4149 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4150 $priceparser = new PriceParser($this->db);
4151 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4152 if ($price_result >= 0) {
4153 $objp->fprice = $price_result;
4154 if ($objp->quantity >= 1) {
4155 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
4156 }
4157 }
4158 }
4159 if ($objp->quantity == 1) {
4160 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4161 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
4162 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
4163 $outvallabel .= $langs->transnoentities("Unit");
4164 } else {
4165 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
4166 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
4167 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
4168 $outvallabel .= ' ' . $langs->transnoentities("Units");
4169 }
4170
4171 if ($objp->quantity != 1) {
4172 $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
4173 $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
4174 }
4175 if ($objp->remise_percent >= 1) {
4176 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4177 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4178 }
4179 if ($objp->duration) {
4180 $optlabel .= " - " . $objp->duration;
4181 $outvallabel .= " - " . $objp->duration;
4182 }
4183 if (!$socid) {
4184 $optlabel .= " - " . dol_trunc($objp->name, 8);
4185 $outvallabel .= " - " . dol_trunc($objp->name, 8);
4186 }
4187 if ($objp->supplier_reputation) {
4188 //TODO dictionary
4189 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
4190
4191 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
4192 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
4193 }
4194 } else {
4195 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
4196 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
4197 }
4198
4199 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
4200 $novirtualstock = ($showstockinlist == 2);
4201
4202 if ($user->hasRight('stock', 'lire')) {
4203 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
4204
4205 if ($objp->stock > 0) {
4206 $optlabel .= ' - <span class="product_line_stock_ok">';
4207 } elseif ($objp->stock <= 0) {
4208 $optlabel .= ' - <span class="product_line_stock_too_low">';
4209 }
4210 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
4211 $optlabel .= '</span>';
4212 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
4213 $langs->load("stocks");
4214
4215 $tmpproduct = new Product($this->db);
4216 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
4217 $tmpproduct->load_virtual_stock();
4218 $virtualstock = $tmpproduct->stock_theorique;
4219
4220 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4221
4222 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4223 if ($virtualstock > 0) {
4224 $optlabel .= '<span class="product_line_stock_ok">';
4225 } elseif ($virtualstock <= 0) {
4226 $optlabel .= '<span class="product_line_stock_too_low">';
4227 }
4228 $optlabel .= $virtualstock;
4229 $optlabel .= '</span>';
4230
4231 unset($tmpproduct);
4232 }
4233 }
4234 }
4235
4236 $optstart = '<option value="' . $outkey . '"';
4237 if ($selected && preg_match('/^idprod_/', (string) $selected) && (string) $selected == 'idprod_'.$objp->rowid) {
4238 $optstart .= ' selected';
4239 } elseif ($selected && (string) $selected == (string) $objp->idprodfournprice) {
4240 $optstart .= ' selected';
4241 }
4242
4243 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4244 $optstart .= ' disabled';
4245 }
4246
4247 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4248 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4249 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4250 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4251 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"'; // the price with numeric international format
4252 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"'; // the price formatted in user language
4253 $optstart .= ' data-discount="' . dol_escape_htmltag((string) $outdiscount) . '"';
4254 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"'; // the rate with numeric international format
4255 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"'; // the rate formatted in user language
4256 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4257 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4258 if (isModEnabled('multicurrency')) {
4259 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4260 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag(price2num($objp->multicurrency_unitprice)) . '"'; // the price with numeric international format
4261 }
4262 }
4263 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4264
4265 // set $parameters to call hook
4266 $outarrayentry = array(
4267 'key' => $outkey,
4268 'value' => $outref,
4269 'label' => $outvallabel,
4270 'labelhtml' => $optlabel,
4271 'qty' => $outqty,
4272 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4273 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4274 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4275 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4276 'tva_tx' => price2num($objp->tva_tx),
4277 'default_vat_code' => $objp->default_vat_code,
4278 'supplier_ref' => $objp->ref_fourn,
4279 'discount' => $outdiscount,
4280 'type' => $outtype,
4281 'duration_value' => $outdurationvalue,
4282 'duration_unit' => $outdurationunit,
4283 'disabled' => empty($objp->idprodfournprice),
4284 'description' => $objp->description
4285 );
4286 if (isModEnabled('multicurrency')) {
4287 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4288 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4289 }
4290 $parameters = array(
4291 'objp' => &$objp,
4292 'optstart' => &$optstart,
4293 'optlabel' => &$optlabel,
4294 'outvallabel' => &$outvallabel,
4295 'outarrayentry' => &$outarrayentry,
4296 'fk_soc' => $socid
4297 );
4298 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4299
4300
4301 // Add new entry
4302 // "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
4303 // "label" value of json key array is used by jQuery automatically as text for combo box
4304 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4305 $outarraypush = array(
4306 'key' => $outkey,
4307 'value' => $outref,
4308 'label' => $outvallabel,
4309 'labelhtml' => $optlabel,
4310 'qty' => $outqty,
4311 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4312 'price_qty_ht_locale' => price($objp->fprice),
4313 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4314 'price_unit_ht_locale' => price($objp->unitprice),
4315 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4316 'tva_tx_formated' => price($objp->tva_tx),
4317 'tva_tx' => price2num($objp->tva_tx),
4318 'default_vat_code' => $objp->default_vat_code,
4319 'supplier_ref' => $objp->ref_fourn,
4320 'discount' => $outdiscount,
4321 'type' => $outtype,
4322 'duration_value' => $outdurationvalue,
4323 'duration_unit' => $outdurationunit,
4324 'disabled' => empty($objp->idprodfournprice),
4325 'description' => $objp->description
4326 );
4327 if (isModEnabled('multicurrency')) {
4328 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4329 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4330 }
4331 array_push($outarray, $outarraypush);
4332
4333 // Example of var_dump $outarray
4334 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4335 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4336 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4337 //}
4338 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4339 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4340 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4341
4342 $i++;
4343 }
4344 $out .= '</select>';
4345
4346 $this->db->free($result);
4347
4348 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4349 $out .= ajax_combobox($htmlname);
4350 } else {
4351 dol_print_error($this->db);
4352 }
4353
4354 if (empty($outputmode)) {
4355 return $out;
4356 }
4357 return $outarray;
4358 }
4359
4360 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4361
4370 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4371 {
4372 // phpcs:enable
4373 global $langs, $conf;
4374
4375 $langs->load('stocks');
4376
4377 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4378 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4379 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4380 $sql .= " FROM " . $this->db->prefix() . "product as p";
4381 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4382 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4383 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4384 $sql .= " AND p.tobuy = 1";
4385 $sql .= " AND s.fournisseur = 1";
4386 $sql .= " AND p.rowid = " . ((int) $productid);
4387 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4388 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4389 } else {
4390 $sql .= " ORDER BY pfp.unitprice ASC";
4391 }
4392
4393 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4394 $result = $this->db->query($sql);
4395
4396 if ($result) {
4397 $num = $this->db->num_rows($result);
4398
4399 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4400
4401 if (!$num) {
4402 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4403 } else {
4404 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4405 $form .= '<option value="0">&nbsp;</option>';
4406
4407 $i = 0;
4408 while ($i < $num) {
4409 $objp = $this->db->fetch_object($result);
4410
4411 $opt = '<option value="' . $objp->idprodfournprice . '"';
4412 //if there is only one supplier, preselect it
4413 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4414 $opt .= ' selected';
4415 }
4416 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4417
4418 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4419 $prod_supplier = new ProductFournisseur($this->db);
4420 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4421 $prod_supplier->id = $productid;
4422 $prod_supplier->fourn_qty = $objp->quantity;
4423 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4424 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4425
4426 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4427 $priceparser = new PriceParser($this->db);
4428 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4429 if ($price_result >= 0) {
4430 $objp->fprice = $price_result;
4431 if ($objp->quantity >= 1) {
4432 $objp->unitprice = $objp->fprice / $objp->quantity;
4433 }
4434 }
4435 }
4436 if ($objp->quantity == 1) {
4437 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4438 }
4439
4440 $opt .= $objp->quantity . ' ';
4441
4442 if ($objp->quantity == 1) {
4443 $opt .= $langs->trans("Unit");
4444 } else {
4445 $opt .= $langs->trans("Units");
4446 }
4447 if ($objp->quantity > 1) {
4448 $opt .= " - ";
4449 $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");
4450 }
4451 if ($objp->duration) {
4452 $opt .= " - " . $objp->duration;
4453 }
4454 $opt .= "</option>\n";
4455
4456 $form .= $opt;
4457 $i++;
4458 }
4459 }
4460
4461 $form .= '</select>';
4462 $this->db->free($result);
4463 return $form;
4464 } else {
4465 dol_print_error($this->db);
4466 return '';
4467 }
4468 }
4469
4470
4471 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4478 {
4479 // phpcs:enable
4480 global $langs, $hookmanager;
4481
4482 $num = count($this->cache_conditions_paiements);
4483 if ($num > 0) {
4484 return 0; // Cache already loaded
4485 }
4486
4487 dol_syslog(__METHOD__, LOG_DEBUG);
4488
4489 $this->cache_conditions_paiements = array();
4490
4491 $sql = "SELECT rowid, code, libelle as label, deposit_percent, entity";
4492 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4493 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4494 $sql .= " AND active > 0";
4495 $sql .= " ORDER BY sortorder";
4496
4497 $resql = $this->db->query($sql);
4498 if ($resql) {
4499 $num = $this->db->num_rows($resql);
4500 $i = 0;
4501 while ($i < $num) {
4502 $obj = $this->db->fetch_object($resql);
4503
4504 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4505 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4506 $this->cache_conditions_paiements[$obj->rowid]['code'] = (string) $obj->code;
4507 $this->cache_conditions_paiements[$obj->rowid]['label'] = (string) $label;
4508 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = (string) $obj->deposit_percent;
4509 $this->cache_conditions_paiements[$obj->rowid]['entity'] = (int) $obj->entity;
4510 $i++;
4511 }
4512
4513 $parameters = array('context' => 'paymentterm');
4514 $reshook = $hookmanager->executeHooks('loadDictionaryCache', $parameters, $this); // Note that $action and $object may have been modified by hook
4515 if (empty($reshook)) {
4516 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
4517 $this->cache_conditions_paiements = array_merge($this->cache_conditions_paiements, $hookmanager->resArray);
4518 }
4519 } else {
4520 $this->cache_conditions_paiements = $hookmanager->resArray;
4521 }
4522
4523 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4524
4525 return $num;
4526 } else {
4527 dol_print_error($this->db);
4528 return -1;
4529 }
4530 }
4531
4532 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4533
4540 {
4541 // phpcs:enable
4542 $factureRec = new FactureRec($this->db);
4543
4544 $this->cache_rule_for_lines_dates = $factureRec->fields['rule_for_lines_dates']['arrayofkeyval'];
4545
4546 if (empty($this->cache_rule_for_lines_dates)) {
4547 return -1;
4548 }
4549
4550 return 1;
4551 }
4552
4553 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4554
4560 public function load_cache_availability()
4561 {
4562 // phpcs:enable
4563 global $langs;
4564
4565 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4566 if ($num > 0) {
4567 return 0; // Cache already loaded
4568 }
4569
4570 dol_syslog(__METHOD__, LOG_DEBUG);
4571
4572 $this->cache_availability = array();
4573
4574 $langs->load('propal');
4575
4576 $sql = "SELECT rowid, code, label, position";
4577 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4578 $sql .= " WHERE active > 0";
4579
4580 $resql = $this->db->query($sql);
4581 if ($resql) {
4582 $num = $this->db->num_rows($resql);
4583 $i = 0;
4584 while ($i < $num) {
4585 $obj = $this->db->fetch_object($resql);
4586
4587 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4588 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4589 $this->cache_availability[$obj->rowid]['code'] = (string) $obj->code;
4590 $this->cache_availability[$obj->rowid]['label'] = (string) $label;
4591 $this->cache_availability[$obj->rowid]['position'] = (int) $obj->position;
4592 $i++;
4593 }
4594
4595 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4596
4597 return $num;
4598 } else {
4599 dol_print_error($this->db);
4600 return -1;
4601 }
4602 }
4603
4614 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4615 {
4616 global $langs, $user;
4617
4618 $this->load_cache_availability();
4619
4620 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4621
4622 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4623 if ($addempty) {
4624 print '<option value="0">&nbsp;</option>';
4625 }
4626 foreach ($this->cache_availability as $id => $arrayavailability) {
4627 if ($selected == $id) {
4628 print '<option value="' . $id . '" selected>';
4629 } else {
4630 print '<option value="' . $id . '">';
4631 }
4632 print dol_escape_htmltag($arrayavailability['label']);
4633 print '</option>';
4634 }
4635 print '</select>';
4636 if ($user->admin) {
4637 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4638 }
4639 print ajax_combobox($htmlname);
4640 }
4641
4647 public function loadCacheInputReason()
4648 {
4649 global $langs;
4650
4651 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4652 if ($num > 0) {
4653 return 0; // Cache already loaded
4654 }
4655
4656 $sql = "SELECT rowid, code, label";
4657 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4658 $sql .= " WHERE active > 0";
4659
4660 $resql = $this->db->query($sql);
4661 if ($resql) {
4662 $num = $this->db->num_rows($resql);
4663 $i = 0;
4664 $tmparray = array();
4665 while ($i < $num) {
4666 $obj = $this->db->fetch_object($resql);
4667
4668 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4669 $label = ($obj->label != '-' ? $obj->label : '');
4670 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4671 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4672 }
4673 if ($langs->trans($obj->code) != $obj->code) {
4674 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4675 }
4676
4677 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4678 $tmparray[$obj->rowid]['code'] = $obj->code;
4679 $tmparray[$obj->rowid]['label'] = $label;
4680 $i++;
4681 }
4682
4683 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4684
4685 unset($tmparray);
4686 return $num;
4687 } else {
4688 dol_print_error($this->db);
4689 return -1;
4690 }
4691 }
4692
4705 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4706 {
4707 global $langs, $user;
4708
4709 $this->loadCacheInputReason();
4710
4711 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4712 if ($addempty) {
4713 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4714 }
4715 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4716 if ($arraydemandreason['code'] == $exclude) {
4717 continue;
4718 }
4719
4720 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4721 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4722 } else {
4723 print '<option value="' . $arraydemandreason['id'] . '">';
4724 }
4725 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4726 print $langs->trans($label);
4727 print '</option>';
4728 }
4729 print '</select>';
4730 if ($user->admin && empty($notooltip)) {
4731 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4732 }
4733 print ajax_combobox('select_' . $htmlname);
4734 }
4735
4736 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4737
4744 {
4745 // phpcs:enable
4746 global $langs, $hookmanager;
4747
4748 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4749 if ($num > 0) {
4750 return $num; // Cache already loaded
4751 }
4752
4753 dol_syslog(__METHOD__, LOG_DEBUG);
4754
4755 $this->cache_types_paiements = array();
4756
4757 $sql = "SELECT id, code, libelle as label, type, entity, active";
4758 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4759 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4760
4761 $resql = $this->db->query($sql);
4762 if ($resql) {
4763 $num = $this->db->num_rows($resql);
4764 $i = 0;
4765 while ($i < $num) {
4766 $obj = $this->db->fetch_object($resql);
4767
4768 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4769 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4770 $this->cache_types_paiements[$obj->id]['id'] = (int) $obj->id;
4771 $this->cache_types_paiements[$obj->id]['code'] = (string) $obj->code;
4772 $this->cache_types_paiements[$obj->id]['label'] = (string) $label;
4773 $this->cache_types_paiements[$obj->id]['type'] = (int) $obj->type;
4774 $this->cache_types_paiements[$obj->id]['entity'] = (int) $obj->entity;
4775 $this->cache_types_paiements[$obj->id]['active'] = (int) $obj->active;
4776 $i++;
4777 }
4778
4779 $parameters = array('context' => 'paymenttype');
4780 $reshook = $hookmanager->executeHooks('loadDictionaryCache', $parameters, $this); // Note that $action and $object may have been modified by hook
4781 if (empty($reshook)) {
4782 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
4783 $this->cache_types_paiements = array_merge($this->cache_types_paiements, $hookmanager->resArray);
4784 }
4785 } else {
4786 $this->cache_types_paiements = $hookmanager->resArray;
4787 }
4788
4789 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4790
4791 return $num;
4792 } else {
4793 dol_print_error($this->db);
4794 return -1;
4795 }
4796 }
4797
4798
4799 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4800
4819 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4820 {
4821 // phpcs:enable
4822 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4823 if (empty($noprint)) {
4824 print $out;
4825 } else {
4826 return $out;
4827 }
4828 }
4829
4830
4847 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4848 {
4849 global $langs, $user, $conf;
4850
4851 $out = '';
4852 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4853
4855
4856 // Set default value if not already set by caller
4857 if (empty($selected) && strpos($htmlname, 'search_') !== 0 && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4858 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4859 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4860 }
4861
4862 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4863 if ($addempty) {
4864 $out .= '<option value="0">&nbsp;</option>';
4865 }
4866
4867 $selectedDepositPercent = null;
4868
4869 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4870 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4871 continue;
4872 }
4873
4874 if ($selected == $id) {
4875 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4876 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4877 } else {
4878 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4879 }
4880 $label = $arrayconditions['label'];
4881
4882 if (!empty($arrayconditions['deposit_percent'])) {
4883 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4884 }
4885
4886 $out .= $label;
4887 $out .= '</option>';
4888 }
4889 $out .= '</select>';
4890 if ($user->admin && empty($noinfoadmin)) {
4891 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4892 }
4893 $out .= ajax_combobox($htmlname);
4894
4895 if ($deposit_percent >= 0) {
4896 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4897 $out .= $langs->trans('DepositPercent') . ' : ';
4898 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4899 $out .= '</span>';
4900 $out .= '
4901 <script nonce="' . getNonce() . '">
4902 $(document).ready(function () {
4903 $("#' . $htmlname . '").change(function () {
4904 let $selected = $(this).find("option:selected");
4905 let depositPercent = $selected.attr("data-deposit_percent");
4906
4907 if (depositPercent.length > 0) {
4908 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4909 } else {
4910 $("#' . $htmlname . '_deposit_percent_container").hide();
4911 }
4912
4913 return true;
4914 });
4915 });
4916 </script>';
4917 }
4918
4919 return $out;
4920 }
4921
4922
4931 public function getSelectRuleForLinesDates($selected = '', $htmlname = 'rule_for_lines_dates', $addempty = 0)
4932 {
4933 global $langs;
4934
4935 $out = '';
4936
4938
4939 $out .= '<select id="' . $htmlname . '" class="flat selectbillingterm" name="' . $htmlname . '">';
4940 if ($addempty) {
4941 $out .= '<option value="-1">&nbsp;</option>';
4942 }
4943
4944
4945 foreach ($this->cache_rule_for_lines_dates as $rule_for_lines_dates_key => $rule_for_lines_dates_name) {
4946 if ($selected == $rule_for_lines_dates_key) {
4947 $out .= '<option value="' . $rule_for_lines_dates_key . '" selected>';
4948 } else {
4949 $out .= '<option value="' . $rule_for_lines_dates_key . '">';
4950 }
4951
4952 $out .= $langs->trans($rule_for_lines_dates_name);
4953 $out .= '</option>';
4954 }
4955 $out .= '</select>';
4956
4957 $out .= ajax_combobox($htmlname);
4958
4959 return $out;
4960 }
4961
4962
4963 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4964
4981 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4982 {
4983 // phpcs:enable
4984 global $langs, $user, $conf;
4985
4986 $out = '';
4987
4988 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4989
4990 $filterarray = array();
4991 if ($filtertype == 'CRDT') {
4992 $filterarray = array(0, 2, 3);
4993 } elseif ($filtertype == 'DBIT') {
4994 $filterarray = array(1, 2, 3);
4995 } elseif ($filtertype != '' && $filtertype != '-1') {
4996 $filterarray = explode(',', $filtertype);
4997 }
4998
5000
5001 // Set default value if not already set by caller
5002 if (empty($selected) && strpos($htmlname, 'search_') !== 0 && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
5003 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
5004 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
5005 }
5006
5007 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
5008 if ($empty) {
5009 $out .= '<option value="">&nbsp;</option>';
5010 }
5011 foreach ($this->cache_types_paiements as $id => $arraytypes) {
5012 // If not good status
5013 if ($active >= 0 && $arraytypes['active'] != $active) {
5014 continue;
5015 }
5016
5017 // We skip of the user requested to filter on specific payment methods
5018 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
5019 continue;
5020 }
5021
5022 // We discard empty lines if showempty is on because an empty line has already been output.
5023 if ($empty && empty($arraytypes['code'])) {
5024 continue;
5025 }
5026
5027 if ($format == 0) {
5028 $out .= '<option value="' . $id . '" data-code="'.$arraytypes['code'].'"';
5029 } elseif ($format == 1) {
5030 $out .= '<option value="' . $arraytypes['code'] . '"';
5031 } elseif ($format == 2) {
5032 $out .= '<option value="' . $arraytypes['code'] . '"';
5033 } elseif ($format == 3) {
5034 $out .= '<option value="' . $id . '"';
5035 }
5036 // Print attribute selected or not
5037 if ($format == 1 || $format == 2) {
5038 if ($selected == $arraytypes['code']) {
5039 $out .= ' selected';
5040 }
5041 } else {
5042 if ($selected == $id) {
5043 $out .= ' selected';
5044 }
5045 }
5046 $out .= '>';
5047 $value = '';
5048 if ($format == 0) {
5049 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5050 } elseif ($format == 1) {
5051 $value = $arraytypes['code'];
5052 } elseif ($format == 2) {
5053 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5054 } elseif ($format == 3) {
5055 $value = $arraytypes['code'];
5056 }
5057 $out .= $value ? $value : '&nbsp;';
5058 $out .= '</option>';
5059 }
5060 $out .= '</select>';
5061 if ($user->admin && !$noadmininfo) {
5062 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5063 }
5064 $out .= ajax_combobox('select' . $htmlname);
5065
5066 if (empty($nooutput)) {
5067 print $out;
5068 } else {
5069 return $out;
5070 }
5071 }
5072
5073
5082 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
5083 {
5084 global $langs;
5085
5086 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
5087 $options = array(
5088 'HT' => $langs->trans("HT"),
5089 'TTC' => $langs->trans("TTC")
5090 );
5091 foreach ($options as $id => $value) {
5092 if ($selected == $id) {
5093 $return .= '<option value="' . $id . '" selected>' . $value;
5094 } else {
5095 $return .= '<option value="' . $id . '">' . $value;
5096 }
5097 $return .= '</option>';
5098 }
5099 $return .= '</select>';
5100 if ($addjscombo) {
5101 $return .= ajax_combobox('select_' . $htmlname);
5102 }
5103
5104 return $return;
5105 }
5106
5107 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5108
5115 {
5116 // phpcs:enable
5117 global $langs;
5118
5119 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
5120 if ($num > 0) {
5121 return $num; // Cache already loaded
5122 }
5123
5124 dol_syslog(__METHOD__, LOG_DEBUG);
5125
5126 $this->cache_transport_mode = array();
5127
5128 $sql = "SELECT rowid, code, label, active";
5129 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
5130 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
5131
5132 $resql = $this->db->query($sql);
5133 if ($resql) {
5134 $num = $this->db->num_rows($resql);
5135 $i = 0;
5136 while ($i < $num) {
5137 $obj = $this->db->fetch_object($resql);
5138
5139 // If traduction exist, we use it else we take the default label
5140 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
5141 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
5142 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
5143 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
5144 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
5145 $i++;
5146 }
5147
5148 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
5149
5150 return $num;
5151 } else {
5152 dol_print_error($this->db);
5153 return -1;
5154 }
5155 }
5156
5170 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
5171 {
5172 global $langs, $user;
5173
5174 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
5175
5177
5178 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
5179 if ($empty) {
5180 print '<option value="">&nbsp;</option>';
5181 }
5182 foreach ($this->cache_transport_mode as $id => $arraytypes) {
5183 // If not good status
5184 if ($active >= 0 && $arraytypes['active'] != $active) {
5185 continue;
5186 }
5187
5188 // We discard empty line if showempty is on because an empty line has already been output.
5189 if ($empty && empty($arraytypes['code'])) {
5190 continue;
5191 }
5192
5193 if ($format == 0) {
5194 print '<option value="' . $id . '"';
5195 } elseif ($format == 1) {
5196 print '<option value="' . $arraytypes['code'] . '"';
5197 } elseif ($format == 2) {
5198 print '<option value="' . $arraytypes['code'] . '"';
5199 } elseif ($format == 3) {
5200 print '<option value="' . $id . '"';
5201 }
5202 // If text is selected, we compare with code, else with id
5203 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
5204 print ' selected';
5205 } elseif ($selected == $id) {
5206 print ' selected';
5207 }
5208 print '>';
5209 $value = '';
5210 if ($format == 0) {
5211 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5212 } elseif ($format == 1) {
5213 $value = $arraytypes['code'];
5214 } elseif ($format == 2) {
5215 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5216 } elseif ($format == 3) {
5217 $value = $arraytypes['code'];
5218 }
5219 print $value ? $value : '&nbsp;';
5220 print '</option>';
5221 }
5222 print '</select>';
5223
5224 print ajax_combobox("select".$htmlname);
5225
5226 if ($user->admin && !$noadmininfo) {
5227 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5228 }
5229 }
5230
5243 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
5244 {
5245 global $langs, $user;
5246
5247 $langs->load("admin");
5248 $langs->load("deliveries");
5249
5250 $sql = "SELECT rowid, code, libelle as label";
5251 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
5252 $sql .= " WHERE active > 0";
5253 if ($filtre) {
5254 $sql .= " AND " . $filtre;
5255 }
5256 $sql .= " ORDER BY libelle ASC";
5257
5258 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
5259 $result = $this->db->query($sql);
5260 if ($result) {
5261 $num = $this->db->num_rows($result);
5262 $i = 0;
5263 if ($num) {
5264 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5265 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5266 print '<option value="-1">&nbsp;</option>';
5267 }
5268 while ($i < $num) {
5269 $obj = $this->db->fetch_object($result);
5270 if ($selected == $obj->rowid) {
5271 print '<option value="' . $obj->rowid . '" selected>';
5272 } else {
5273 print '<option value="' . $obj->rowid . '">';
5274 }
5275 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
5276 print '</option>';
5277 $i++;
5278 }
5279 print "</select>";
5280 if ($user->admin && empty($noinfoadmin)) {
5281 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5282 }
5283
5284 print ajax_combobox('select' . $htmlname);
5285 } else {
5286 print $langs->trans("NoShippingMethodDefined");
5287 }
5288 } else {
5289 dol_print_error($this->db);
5290 }
5291 }
5292
5302 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
5303 {
5304 global $langs;
5305
5306 $langs->load("deliveries");
5307
5308 if ($htmlname != "none") {
5309 print '<form method="POST" action="' . $page . '">';
5310 print '<input type="hidden" name="action" value="setshippingmethod">';
5311 print '<input type="hidden" name="token" value="' . newToken() . '">';
5312 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5313 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5314 print '</form>';
5315 } else {
5316 if ($selected) {
5317 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5318 print $langs->trans("SendingMethod" . strtoupper($code));
5319 } else {
5320 print "&nbsp;";
5321 }
5322 }
5323 }
5324
5333 public function selectSituationInvoices($selected = '', $socid = 0)
5334 {
5335 global $langs;
5336
5337 $langs->load('bills');
5338
5339 $opt = '';
5340
5341 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5342 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5343 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5344 $sql .= ' AND situation_counter >= 1';
5345 $sql .= ' AND fk_soc = ' . (int) $socid;
5346 $sql .= ' AND type <> 2';
5347 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5348 $resql = $this->db->query($sql);
5349
5350 $nbSituationInvoiceForThirdparty = 0;
5351
5352 if ($resql && $this->db->num_rows($resql) > 0) {
5353 // Last seen cycle
5354 $ref = 0;
5355 while ($obj = $this->db->fetch_object($resql)) {
5356 //Same cycle ?
5357 if ($obj->situation_cycle_ref != $ref) {
5358 // Just seen this cycle
5359 $ref = $obj->situation_cycle_ref;
5360 //not final ?
5361 if ($obj->situation_final != 1) {
5362 //Not prov?
5363 if (substr($obj->ref, 1, 4) != 'PROV') {
5364 $nbSituationInvoiceForThirdparty++;
5365
5366 if ($selected == $obj->rowid) {
5367 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5368 } else {
5369 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5370 }
5371 }
5372 }
5373 }
5374 }
5375 } else {
5376 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5377 }
5378
5379 if ($nbSituationInvoiceForThirdparty > 0) {
5380 $opt = '<option class="minwidth100" value="" selected>&nbsp;</option>'.$opt;
5381 } else {
5382 $opt = '<option class="minwidth100" value="-1" selected>'.$langs->trans('NoSituations').'</option>';
5383 }
5384
5385 return $opt;
5386 }
5387
5397 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5398 {
5399 global $langs;
5400
5401 $langs->load('products');
5402
5403 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5404
5405 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5406 $sql .= ' WHERE active > 0';
5407 if (!empty($unit_type)) {
5408 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5409 }
5410 $sql .= " ORDER BY sortorder";
5411
5412 $resql = $this->db->query($sql);
5413 if ($resql && $this->db->num_rows($resql) > 0) {
5414 if ($showempty) {
5415 $return .= '<option value="-1"></option>';
5416 }
5417
5418 while ($res = $this->db->fetch_object($resql)) {
5419 $unitLabel = $res->label;
5420 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5421 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5422 }
5423
5424 if ($selected == $res->rowid) {
5425 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5426 } else {
5427 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5428 }
5429 }
5430 $return .= '</select>';
5431
5432 $return .= ajax_combobox($htmlname);
5433 }
5434 return $return;
5435 }
5436
5437 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5438
5453 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5454 {
5455 // phpcs:enable
5456 global $langs;
5457
5458 $out = '';
5459
5460 $langs->loadLangs(array("admin", "banks"));
5461 $num = 0;
5462
5463 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5464 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5465 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5466 if ($status != 2) {
5467 $sql .= " AND clos = " . (int) $status;
5468 }
5469 if ($filtre) { // TODO Support USF
5470 $sql .= " AND " . $filtre;
5471 }
5472 $sql .= " ORDER BY label";
5473
5474 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5475 $result = $this->db->query($sql);
5476 if ($result) {
5477 $num = $this->db->num_rows($result);
5478 $i = 0;
5479
5480 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5481
5482 if ($num == 0) {
5483 if ($status == 0) {
5484 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5485 } else {
5486 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5487 }
5488 } else {
5489 if (!empty($useempty) && !is_numeric($useempty)) {
5490 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5491 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5492 $out .= '<option value="-1">&nbsp;</option>';
5493 }
5494 }
5495
5496 while ($i < $num) {
5497 $obj = $this->db->fetch_object($result);
5498
5499 $labeltoshow = trim($obj->label);
5500 $labeltoshowhtml = trim($obj->label);
5501 if ($showcurrency) {
5502 $labeltoshow .= ' (' . $obj->currency_code . ')';
5503 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5504 }
5505 if ($status == 2 && $obj->status == 1) {
5506 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5507 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5508 }
5509
5510 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5511 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5512 } else {
5513 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5514 }
5515 $out .= $labeltoshow;
5516 $out .= '</option>';
5517 $i++;
5518 }
5519 $out .= "</select>";
5520 $out .= ajax_combobox('select' . $htmlname);
5521 } else {
5522 dol_print_error($this->db);
5523 }
5524
5525 // Output or return
5526 if (empty($nooutput)) {
5527 print $out;
5528 } else {
5529 return $out;
5530 }
5531
5532 return $num;
5533 }
5534
5548 public function selectRib($selected = '', $htmlname = 'ribcompanyid', $filtre = '', $useempty = 0, $moreattrib = '', $showibanbic = 0, $morecss = '', $nooutput = 0)
5549 {
5550 // phpcs:enable
5551 global $langs;
5552
5553 $out = '';
5554
5555 $langs->loadLangs(array("admin", "banks"));
5556 $num = 0;
5557
5558 $sql = "SELECT rowid, label, bank, status, iban_prefix, bic";
5559 $sql .= " FROM " . $this->db->prefix() . "societe_rib";
5560 $sql .= " WHERE type = 'ban'";
5561 if ($filtre) { // TODO Support USF
5562 $sql .= " AND " . $filtre;
5563 }
5564 $sql .= " ORDER BY label";
5565 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5566 $result = $this->db->query($sql);
5567 if ($result) {
5568 $num = $this->db->num_rows($result);
5569 $i = 0;
5570
5571 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5572
5573 if ($num == 0) {
5574 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5575 } else {
5576 if (!empty($useempty) && !is_numeric($useempty)) {
5577 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5578 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5579 $out .= '<option value="-1">&nbsp;</option>';
5580 }
5581 }
5582
5583 while ($i < $num) {
5584 $obj = $this->db->fetch_object($result);
5585 $iban = dolDecrypt($obj->iban_prefix);
5586 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5587 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '" selected>';
5588 } else {
5589 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '">';
5590 }
5591 $out .= trim($obj->label);
5592 if ($showibanbic) {
5593 $out .= ' (' . $iban . '/' .$obj->bic. ')';
5594 }
5595 $out .= '</option>';
5596 $i++;
5597 }
5598 $out .= "</select>";
5599 $out .= ajax_combobox('select' . $htmlname);
5600 } else {
5601 dol_print_error($this->db);
5602 }
5603
5604 // Output or return
5605 if (empty($nooutput)) {
5606 print $out;
5607 } else {
5608 return $out;
5609 }
5610
5611 return $num;
5612 }
5613
5625 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5626 {
5627 global $langs;
5628
5629 $langs->load("admin");
5630 $num = 0;
5631
5632 $sql = "SELECT rowid, name, fk_country, status, entity";
5633 $sql .= " FROM " . $this->db->prefix() . "establishment";
5634 $sql .= " WHERE 1=1";
5635 if ($status != 2) {
5636 $sql .= " AND status = " . (int) $status;
5637 }
5638 if ($filtre) { // TODO Support USF
5639 $sql .= " AND " . $filtre;
5640 }
5641 $sql .= " ORDER BY name";
5642
5643 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5644 $result = $this->db->query($sql);
5645 if ($result) {
5646 $num = $this->db->num_rows($result);
5647 $i = 0;
5648 if ($num) {
5649 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5650 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5651 print '<option value="-1">&nbsp;</option>';
5652 }
5653
5654 while ($i < $num) {
5655 $obj = $this->db->fetch_object($result);
5656 if ($selected == $obj->rowid) {
5657 print '<option value="' . $obj->rowid . '" selected>';
5658 } else {
5659 print '<option value="' . $obj->rowid . '">';
5660 }
5661 print trim($obj->name);
5662 if ($status == 2 && $obj->status == 1) {
5663 print ' (' . $langs->trans("Closed") . ')';
5664 }
5665 print '</option>';
5666 $i++;
5667 }
5668 print "</select>";
5669 } else {
5670 if ($status == 0) {
5671 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5672 } else {
5673 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5674 }
5675 }
5676
5677 return $num;
5678 } else {
5679 dol_print_error($this->db);
5680 return -1;
5681 }
5682 }
5683
5693 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5694 {
5695 global $langs;
5696 if ($htmlname != "none") {
5697 print '<form method="POST" action="' . $page . '">';
5698 print '<input type="hidden" name="action" value="setbankaccount">';
5699 print '<input type="hidden" name="token" value="' . newToken() . '">';
5700 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5701 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5702 if ($nbaccountfound > 0) {
5703 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5704 }
5705 print '</form>';
5706 } else {
5707 $langs->load('banks');
5708
5709 if ($selected) {
5710 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5711 $bankstatic = new Account($this->db);
5712 $result = $bankstatic->fetch((int) $selected);
5713 if ($result) {
5714 print $bankstatic->getNomUrl(1);
5715 }
5716 } else {
5717 print "&nbsp;";
5718 }
5719 }
5720 }
5721
5733 public function formRib($page, $selected = '', $htmlname = 'ribcompanyid', $filtre = '', $addempty = 0, $showibanbic = 0)
5734 {
5735 global $langs;
5736 if ($htmlname != "none") {
5737 print '<form method="POST" action="' . $page . '">';
5738 print '<input type="hidden" name="action" value="setbankaccountcustomer">';
5739 print '<input type="hidden" name="token" value="' . newToken() . '">';
5740 $nbaccountfound = $this->selectRib($selected, $htmlname, $filtre, $addempty, '', $showibanbic);
5741 if ($nbaccountfound > 0) {
5742 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5743 }
5744 print '</form>';
5745 } else {
5746 $langs->load('banks');
5747
5748 if ($selected) {
5749 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
5750 $bankstatic = new CompanyBankAccount($this->db);
5751 $result = $bankstatic->fetch((int) $selected);
5752 if ($result) {
5753 print $bankstatic->label;
5754 if ($showibanbic) {
5755 print ' (' . $bankstatic->iban . '/' .$bankstatic->bic. ')';
5756 }
5757 }
5758 } else {
5759 print "&nbsp;";
5760 }
5761 }
5762 }
5763
5764 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5765
5775 public function selectCategories($categtype, $htmlname, $object = null)
5776 {
5777 global $langs;
5778
5779 $out = '';
5780
5781 $cate_arbo = $this->select_all_categories($categtype, '', '', 64, 0, 3);
5782
5783 $arrayselected = array();
5784 if (GETPOSTISARRAY($htmlname)) {
5785 $arrayselected = GETPOST($htmlname, 'array:int');
5786 } elseif (is_object($object) && $object->id > 0) {
5787 $c = new Categorie($this->db);
5788 $cats = $c->containing($object->id, $categtype);
5789 $arrayselected = array();
5790 foreach ($cats as $cat) {
5791 $arrayselected[] = $cat->id;
5792 }
5793 }
5794
5795 $out .= img_picto('', 'category', 'class="pictofixedwidth"');
5796 $out .= $this->multiselectarray($htmlname, $cate_arbo, $arrayselected, 0, 0, 'minwidth100 widthcentpercentminusxx', 0, 0);
5797
5798 if (!getDolGlobalString('CATEGORY_EDIT_IN_MENU_NOT_IN_POPUP')) {
5799 // Add html code to add the edit button and go back
5800 $jsonclose = 'doJsCodeAfterPopupClose'.$htmlname.'()';
5801 $urltoopen = '/categories/categorie_list.php?type='.urlencode($categtype).'&nosearch=1';
5802
5803 $s = dolButtonToOpenUrlInDialogPopup($htmlname, $langs->transnoentitiesnoconv("Categories"), img_picto('', 'add', 'class="editfielda"'), $urltoopen, '', '', '', $jsonclose);
5804 $out .= $s;
5805 // Add js code to add the edit button and go back
5806 $out .= '<!-- Add js code to open the popup for category/edit/add -->'."\n";
5807 $out .= '<script>function doJsCodeAfterPopupClose'.$htmlname.'() {
5808 console.log("doJsCodeAfterPopupClose'.$htmlname.' has been called, we refresh the combo content + refresh select2...");
5809
5810 // Call an ajax to reload values and update the select
5811 // $("#'.dol_escape_js($htmlname).'").append(new Option("Option 4", "4"));
5812
5813 // Refresh select2 to take account of new values (enough for small change)
5814
5815 $.ajax({
5816 url: \''.DOL_URL_ROOT.'/core/ajax/fetchCategories.php\',
5817 data: {
5818 action: \'getCategories\',
5819 type: \''.dol_escape_htmltag($categtype).'\'
5820 },
5821 type: \'GET\',
5822 dataType: \'json\',
5823 success: function (data) {
5824 var $select = $(\'#'.dol_escape_js($htmlname).'\');
5825 var selectedValues = $select.val(); // This is an array of selected values
5826 console.log(selectedValues);
5827 $select.empty();
5828 $.each(data, function (index, item) {
5829 $select.append(\'<option value="\' + item.id + \'" data-html="\' + item.htmlforattribute + \'">\' + item.htmlforoption + \'</option>\');
5830 });
5831 $select.val(selectedValues);
5832 },
5833 error: function (xhr, status, error) {
5834 console.log("Error when loading ajax page : " + error);
5835 }
5836 });
5837
5838 $("#'.dol_escape_js($htmlname).'").trigger("change");
5839 // Alternative if change in select is complex
5840 /*
5841 $("#'.dol_escape_js($htmlname).'").select2("destroy");
5842 $("#'.dol_escape_js($htmlname).'").select2();
5843 */
5844 }</script>';
5845 }
5846
5847 return $out;
5848 }
5849
5850
5870 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5871 {
5872 // phpcs:enable
5873 global $langs;
5874
5875 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5876
5877 $cat = new Categorie($this->db);
5878
5879 if (is_numeric($type)) {
5880 $type = array_search($type, $cat->MAP_ID); // For backward compatibility
5881 }
5882
5883 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5884
5885 $outarray = array();
5886 $outarrayrichhtml = array();
5887
5888
5889 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5890 if (is_array($cate_arbo)) {
5891 $num = count($cate_arbo);
5892
5893 if (!$num) {
5894 $langs->load("categories");
5895 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5896 } else {
5897 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5898 $output .= '<option value="-1">&nbsp;</option>';
5899 }
5900 foreach ($cate_arbo as $key => $value) {
5901 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5902 $add = 'selected ';
5903 } else {
5904 $add = '';
5905 }
5906
5907 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth"'.(empty($cate_arbo[$key]['color']) ? '' : ' style="color: #' . $cate_arbo[$key]['color'] . '"'));
5908 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5909
5910 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5911
5912 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5913
5914 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5915 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5916 $output .= '>';
5917 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5918 $output .= '</option>';
5919
5920 $cate_arbo[$key]['data-html'] = $labeltoshow;
5921 }
5922 }
5923 }
5924 $output .= '</select>';
5925 $output .= "\n";
5926
5927 $this->num = count($cate_arbo);
5928
5929 if ($outputmode == 2) {
5930 // TODO: handle error when $cate_arbo is not an array
5931 return $cate_arbo;
5932 } elseif ($outputmode == 1) {
5933 return $outarray;
5934 } elseif ($outputmode == 3) {
5935 return $outarrayrichhtml;
5936 }
5937 return $output;
5938 }
5939
5940 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5941
5960 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5961 {
5962 // phpcs:enable
5963 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5964 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5965 }
5966
5993 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5994 {
5995 global $langs, $conf;
5996
5997 $more = '';
5998 $formconfirm = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5999
6000 $inputok = array();
6001 $inputko = array();
6002
6003 // Clean parameters
6004 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
6005 if ($conf->browser->layout == 'phone') {
6006 $width = '95%';
6007 }
6008
6009 // Set height automatically if not defined
6010 if (empty($height)) {
6011 $height = 250;
6012 if (is_array($formquestion) && count($formquestion) > 2) {
6013 $height += ((count($formquestion) - 2) * 24);
6014 }
6015 }
6016
6017 if (is_array($formquestion) && !empty($formquestion)) {
6018 // First add hidden fields and value
6019 foreach ($formquestion as $key => $input) {
6020 if (is_array($input) && !empty($input)) {
6021 if ($input['type'] == 'hidden') {
6022 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
6023 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
6024
6025 $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";
6026 }
6027 }
6028 }
6029
6030 // Now add questions
6031 $moreonecolumn = '';
6032 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
6033 foreach ($formquestion as $key => $input) {
6034 if (is_array($input) && !empty($input)) {
6035 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
6036 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
6037 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
6038
6039 if ($input['type'] == 'text' || $input['type'] == 'input') { // traditional input
6040 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . ($input['label'] ?? '') . '</div><div class="tagtd"><input type="text" class="flat' . $morecss . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $size . ' value="' . (empty($input['value']) ? '' : $input['value']) . '"' . $moreattr . ' /></div></div>' . "\n";
6041 } elseif ($input['type'] == 'password') {
6042 $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";
6043 } elseif ($input['type'] == 'textarea') {
6044 $moreonecolumn .= '<div class="margintoponly">';
6045 $moreonecolumn .= $input['label'] . '<br>';
6046 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
6047 $moreonecolumn .= $input['value'];
6048 $moreonecolumn .= '</textarea>';
6049 $moreonecolumn .= '</div>';
6050 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
6051 if (empty($morecss)) {
6052 $morecss = 'minwidth100';
6053 }
6054
6055 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
6056 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
6057 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
6058 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
6059 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
6060 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
6061 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
6062
6063 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
6064 if (!empty($input['label'])) {
6065 $more .= $input['label'] . '</div><div class="tagtd left">';
6066 }
6067 if ($input['type'] == 'select') {
6068 $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);
6069 } else {
6070 $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);
6071 }
6072 $more .= '</div></div>' . "\n";
6073 } elseif ($input['type'] == 'checkbox') {
6074 $more .= '<div class="tagtr">';
6075 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
6076 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
6077 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
6078 $more .= ' checked';
6079 }
6080 if (is_bool($input['value']) && $input['value']) {
6081 $more .= ' checked';
6082 }
6083 if (isset($input['disabled'])) {
6084 $more .= ' disabled';
6085 }
6086 $more .= ' /></div>';
6087 $more .= '</div>' . "\n";
6088 } elseif ($input['type'] == 'radio') {
6089 $i = 0;
6090 foreach ($input['values'] as $selkey => $selval) {
6091 $more .= '<div class="tagtr">';
6092 if (isset($input['label'])) {
6093 if ($i == 0) {
6094 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
6095 } else {
6096 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
6097 }
6098 }
6099 $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;
6100 if (!empty($input['disabled'])) {
6101 $more .= ' disabled';
6102 }
6103 if (isset($input['default']) && $input['default'] === $selkey) {
6104 $more .= ' checked="checked"';
6105 }
6106 $more .= ' /> ';
6107 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
6108 $more .= '</div></div>' . "\n";
6109 $i++;
6110 }
6111 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
6112 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
6113 $more .= '<div class="tagtd">';
6114 $addnowlink = (empty($input['datenow']) ? 0 : 1);
6115 $h = $m = 0;
6116 if ($input['type'] == 'datetime') {
6117 $h = isset($input['hours']) ? $input['hours'] : 1;
6118 $m = isset($input['minutes']) ? $input['minutes'] : 1;
6119 }
6120 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
6121 $more .= '</div></div>'."\n";
6122 $formquestion[] = array('name' => $input['name'].'day');
6123 $formquestion[] = array('name' => $input['name'].'month');
6124 $formquestion[] = array('name' => $input['name'].'year');
6125 $formquestion[] = array('name' => $input['name'].'hour');
6126 $formquestion[] = array('name' => $input['name'].'min');
6127 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
6128 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
6129 if (!empty($input['label'])) {
6130 $more .= $input['label'] . '</div><div class="tagtd">';
6131 }
6132 if (!empty($input['value'])) {
6133 $more .= $input['value'];
6134 }
6135 $more .= '</div></div>' . "\n";
6136 } elseif ($input['type'] == 'onecolumn') {
6137 $moreonecolumn .= '<div class="margintoponly">';
6138 $moreonecolumn .= $input['value'];
6139 $moreonecolumn .= '</div>' . "\n";
6140 } elseif ($input['type'] == 'hidden') {
6141 // Do nothing more, already added by a previous loop
6142 } elseif ($input['type'] == 'separator') {
6143 $more .= '<br>';
6144 } else {
6145 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
6146 }
6147 }
6148 }
6149 $more .= '</div>' . "\n";
6150 $more .= $moreonecolumn;
6151 }
6152
6153 // JQUERY method dialog is broken with smartphone, we use standard HTML.
6154 // 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
6155 // See page product/card.php for example
6156 if (!empty($conf->dol_use_jmobile)) {
6157 $useajax = 0;
6158 }
6159 if (empty($conf->use_javascript_ajax)) {
6160 $useajax = 0;
6161 }
6162
6163 if ($useajax) {
6164 $autoOpen = true;
6165 $dialogconfirm = 'dialog-confirm';
6166 $button = '';
6167 if (!is_numeric($useajax)) {
6168 $button = $useajax;
6169 $useajax = 1;
6170 $autoOpen = false;
6171 $dialogconfirm .= '-' . $button;
6172 }
6173 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
6174 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
6175
6176 // Add input fields into list of fields to read during submit (inputok and inputko)
6177 if (is_array($formquestion)) {
6178 foreach ($formquestion as $key => $input) {
6179 //print "xx ".$key." rr ".is_array($input)."<br>\n";
6180 // Add name of fields to propagate with the GET when submitting the form with button OK.
6181 if (is_array($input) && isset($input['name'])) {
6182 if (strpos($input['name'], ',') > 0) {
6183 $inputok = array_merge($inputok, explode(',', $input['name']));
6184 } else {
6185 array_push($inputok, $input['name']);
6186 }
6187 }
6188 // Add name of fields to propagate with the GET when submitting the form with button KO.
6189 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
6190 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
6191 array_push($inputko, $input['name']);
6192 }
6193 }
6194 }
6195
6196 // Show JQuery confirm box.
6197 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
6198 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
6199 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
6200 }
6201 if (!empty($more)) {
6202 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
6203 }
6204 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
6205 $formconfirm .= '</div>' . "\n";
6206
6207 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
6208 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6209 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
6210 $formconfirm .= 'jQuery(document).ready(function() {
6211 $(function() {
6212 $( "#' . $dialogconfirm . '" ).dialog(
6213 {
6214 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
6215 if ($newselectedchoice == 'no') {
6216 $formconfirm .= '
6217 open: function() {
6218 $(this).parent().find("button.ui-button:eq(2)").focus();
6219 },';
6220 }
6221
6222 $jsforcursor = '';
6223 if ($useajax == 1) {
6224 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
6225 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
6226 }
6227
6228 $postconfirmas = 'GET';
6229
6230 $formconfirm .= '
6231 resizable: false,
6232 height: \'' . dol_escape_js($height) . '\',
6233 width: \'' . dol_escape_js($width) . '\',
6234 modal: true,
6235 closeOnEscape: false,
6236 buttons: {
6237 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
6238 var options = "token=' . urlencode(newToken()) . '";
6239 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
6240 var page = \'' . dol_escape_js(!empty($page) ? $page : '') . '\';
6241 var pageyes = \'' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '\';
6242
6243 if (inputok.length > 0) {
6244 $.each(inputok, function(i, inputname) {
6245 var more = "";
6246 var inputvalue;
6247 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
6248 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
6249 } else {
6250 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
6251 inputvalue = $("#" + inputname + more).val();
6252 }
6253 if (typeof inputvalue == "undefined") { inputvalue=""; }
6254 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
6255 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
6256 });
6257 }
6258 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
6259 if (pageyes.length > 0) {';
6260 if ($postconfirmas == 'GET') {
6261 $formconfirm .= 'location.href = urljump;';
6262 } else {
6263 $formconfirm .= $jsforcursor;
6264 $formconfirm .= 'var post = $.post(
6265 pageyes,
6266 options,
6267 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
6268 );';
6269 }
6270 $formconfirm .= '
6271 console.log("after post ok");
6272 }
6273 $(this).dialog("close");
6274 },
6275 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
6276 var options = "token=' . urlencode(newToken()) . '";
6277 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
6278 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
6279 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
6280 if (inputko.length > 0) {
6281 $.each(inputko, function(i, inputname) {
6282 var more = "";
6283 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
6284 var inputvalue = $("#" + inputname + more).val();
6285 if (typeof inputvalue == "undefined") { inputvalue=""; }
6286 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
6287 });
6288 }
6289 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
6290 //alert(urljump);
6291 if (pageno.length > 0) {';
6292 if ($postconfirmas == 'GET') {
6293 $formconfirm .= 'location.href = urljump;';
6294 } else {
6295 $formconfirm .= $jsforcursor;
6296 $formconfirm .= 'var post = $.post(
6297 pageno,
6298 options,
6299 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
6300 );';
6301 }
6302 $formconfirm .= '
6303 console.log("after post ko");
6304 }
6305 $(this).dialog("close");
6306 }
6307 }
6308 }
6309 );
6310
6311 var button = "' . $button . '";
6312 if (button.length > 0) {
6313 $( "#" + button ).click(function() {
6314 $("#' . $dialogconfirm . '").dialog("open");
6315 });
6316 }
6317 });
6318 });
6319 </script>';
6320 $formconfirm .= "<!-- end ajax formconfirm -->\n";
6321 } else {
6322 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
6323
6324 if (empty($disableformtag)) {
6325 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
6326 }
6327
6328 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
6329 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
6330
6331 $formconfirm .= '<table class="valid centpercent">' . "\n";
6332
6333 // Line title
6334 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
6335 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
6336 $formconfirm .= '</td></tr>' . "\n";
6337
6338 // Line text
6339 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
6340 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
6341 }
6342
6343 // Line form fields
6344 if ($more) {
6345 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
6346 $formconfirm .= $more;
6347 $formconfirm .= '</td></tr>' . "\n";
6348 }
6349
6350 // Line with question
6351 $formconfirm .= '<tr class="valid">';
6352 $formconfirm .= '<td class="valid">' . $question . '</td>';
6353 $formconfirm .= '<td class="valid center">';
6354 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
6355 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
6356 $formconfirm .= '</td>';
6357 $formconfirm .= '</tr>' . "\n";
6358
6359 $formconfirm .= '</table>' . "\n";
6360
6361 if (empty($disableformtag)) {
6362 $formconfirm .= "</form>\n";
6363 }
6364 $formconfirm .= '<br>';
6365
6366 if (!empty($conf->use_javascript_ajax)) {
6367 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
6368 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6369 $formconfirm .= '
6370 $(document).ready(function () {
6371 $(".confirmvalidatebutton").on("click", function() {
6372 console.log("We click on button confirmvalidatebutton");
6373 $(this).attr("disabled", "disabled");
6374 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
6375 //console.log($(this).closest("form"));
6376 $(this).closest("form").submit();
6377 });
6378 });
6379 ';
6380 $formconfirm .= '</script>' . "\n";
6381 }
6382
6383 $formconfirm .= "<!-- end formconfirm -->\n";
6384 }
6385
6386 return $formconfirm;
6387 }
6388
6389
6390 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6391
6407 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
6408 {
6409 // phpcs:enable
6410 global $langs;
6411
6412 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
6413 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
6414
6415 $out = '';
6416
6417 $formproject = new FormProjets($this->db);
6418
6419 $langs->load("project");
6420 if ($htmlname != "none") {
6421 $out .= '<form method="post" action="' . $page . '">';
6422 $out .= '<input type="hidden" name="action" value="classin">';
6423 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6424 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
6425 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6426 $out .= '</form>';
6427 } else {
6428 $out .= '<span class="project_head_block">';
6429 if ($selected) {
6430 $projet = new Project($this->db);
6431 $projet->fetch((int) $selected);
6432 $out .= $projet->getNomUrl(0, '', 1);
6433 } else {
6434 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
6435 }
6436 $out .= '</span>';
6437 }
6438
6439 if (empty($nooutput)) {
6440 print $out;
6441 return '';
6442 }
6443 return $out;
6444 }
6445
6446 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6447
6463 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
6464 {
6465 // phpcs:enable
6466 global $langs;
6467
6468 $out = '';
6469
6470 if ($htmlname != "none") {
6471 $out .= '<form method="POST" action="' . $page . '">';
6472 $out .= '<input type="hidden" name="action" value="setconditions">';
6473 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6474 if ($type) {
6475 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6476 }
6477 $out .= $this->getSelectConditionsPaiements((int) $selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6478 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6479 $out .= '</form>';
6480 } else {
6481 if ($selected) {
6482 $this->load_cache_conditions_paiements();
6483 if (isset($this->cache_conditions_paiements[$selected])) {
6484 $label = $this->cache_conditions_paiements[$selected]['label'];
6485
6486 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6487 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6488 }
6489
6490 $out .= $label;
6491 } else {
6492 $langs->load('errors');
6493 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6494 }
6495 } else {
6496 $out .= '&nbsp;';
6497 }
6498 }
6499
6500 if (empty($nooutput)) {
6501 print $out;
6502 return '';
6503 }
6504 return $out;
6505 }
6506
6507 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6508
6519 public function form_rule_for_lines_dates($page, $selected = '', $htmlname = 'rule_for_lines_dates', $addempty = 0, $nooutput = 0): string
6520 {
6521 global $langs;
6522
6523 $out = '';
6524
6525 if ($htmlname != 'none') {
6526 $out .= '<form method="POST" action="' . $page . '">';
6527 $out .= '<input type="hidden" name="action" value="setruleforlinesdates">';
6528 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6529 $out .= $this->getSelectRuleForLinesDates($selected, $htmlname, $addempty);
6530 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6531 $out .= '</form>';
6532 } else {
6533 if (isset($selected)) {
6534 $this->load_cache_rule_for_lines_dates();
6535 if (isset($this->cache_rule_for_lines_dates[$selected])) {
6536 $label = $this->cache_rule_for_lines_dates[$selected];
6537 $out .= $langs->trans($label);
6538 }
6539 } else {
6540 $out .= '&nbsp;';
6541 }
6542 }
6543
6544 if (empty($nooutput)) {
6545 print $out;
6546 return '';
6547 }
6548
6549 return $out;
6550 }
6551
6552 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6553
6563 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
6564 {
6565 // phpcs:enable
6566 global $langs;
6567 if ($htmlname != "none") {
6568 print '<form method="post" action="' . $page . '">';
6569 print '<input type="hidden" name="action" value="setavailability">';
6570 print '<input type="hidden" name="token" value="' . newToken() . '">';
6571 $this->selectAvailabilityDelay($selected, $htmlname, '', $addempty);
6572 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6573 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
6574 print '</form>';
6575 } else {
6576 if ($selected) {
6577 $this->load_cache_availability();
6578 print $this->cache_availability[$selected]['label'];
6579 } else {
6580 print "&nbsp;";
6581 }
6582 }
6583 }
6584
6595 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
6596 {
6597 global $langs;
6598 if ($htmlname != "none") {
6599 print '<form method="post" action="' . $page . '">';
6600 print '<input type="hidden" name="action" value="setdemandreason">';
6601 print '<input type="hidden" name="token" value="' . newToken() . '">';
6602 $this->selectInputReason($selected, $htmlname, '-1', $addempty);
6603 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6604 print '</form>';
6605 } else {
6606 if ($selected) {
6607 $this->loadCacheInputReason();
6608 foreach ($this->cache_demand_reason as $key => $val) {
6609 if ($val['id'] == $selected) {
6610 print $val['label'];
6611 break;
6612 }
6613 }
6614 } else {
6615 print "&nbsp;";
6616 }
6617 }
6618 }
6619
6620 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6621
6635 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6636 {
6637 // phpcs:enable
6638 global $langs;
6639
6640 $ret = '';
6641
6642 if ($htmlname != "none") {
6643 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6644 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6645 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6646 if ($type) {
6647 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6648 }
6649 $ret .= '<table class="nobordernopadding">';
6650 $ret .= '<tr><td>';
6651 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6652 $ret .= '</td>';
6653 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6654 $ret .= '</tr></table></form>';
6655 } else {
6656 if ($displayhour) {
6657 $ret .= dol_print_date($selected, 'dayhour');
6658 } else {
6659 $ret .= dol_print_date($selected, 'day');
6660 }
6661 }
6662
6663 if (empty($nooutput)) {
6664 print $ret;
6665 }
6666 return $ret;
6667 }
6668
6669
6670 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6671
6682 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6683 {
6684 // phpcs:enable
6685 global $langs;
6686
6687 if ($htmlname != "none") {
6688 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6689 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6690 print '<input type="hidden" name="token" value="' . newToken() . '">';
6691 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6692 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6693 print '</form>';
6694 } else {
6695 if ($selected) {
6696 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6697 $theuser = new User($this->db);
6698 $theuser->fetch((int) $selected);
6699 print $theuser->getNomUrl(1);
6700 } else {
6701 print "&nbsp;";
6702 }
6703 }
6704 }
6705
6706
6707 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6708
6722 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6723 {
6724 // phpcs:enable
6725 global $langs;
6726
6727 $out = '';
6728 if ($htmlname != "none") {
6729 $out .= '<form method="POST" action="' . $page . '">';
6730 $out .= '<input type="hidden" name="action" value="setmode">';
6731 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6732 if ($type) {
6733 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6734 }
6735 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6736 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6737 $out .= '</form>';
6738 } else {
6739 if ($selected) {
6740 $this->load_cache_types_paiements();
6741 $out .= $this->cache_types_paiements[$selected]['label'];
6742 } else {
6743 $out .= "&nbsp;";
6744 }
6745 }
6746
6747 if ($nooutput) {
6748 return $out;
6749 } else {
6750 print $out;
6751 }
6752 return '';
6753 }
6754
6765 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6766 {
6767 global $langs;
6768 if ($htmlname != "none") {
6769 print '<form method="POST" action="' . $page . '">';
6770 print '<input type="hidden" name="action" value="settransportmode">';
6771 print '<input type="hidden" name="token" value="' . newToken() . '">';
6772 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6773 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6774 print '</form>';
6775 } else {
6776 if ($selected) {
6777 $this->load_cache_transport_mode();
6778 print $this->cache_transport_mode[$selected]['label'];
6779 } else {
6780 print "&nbsp;";
6781 }
6782 }
6783 }
6784
6785 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6786
6795 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6796 {
6797 // phpcs:enable
6798 global $langs;
6799 if ($htmlname != "none") {
6800 print '<form method="POST" action="' . $page . '">';
6801 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6802 print '<input type="hidden" name="token" value="' . newToken() . '">';
6803 print $this->selectMultiCurrency($selected, $htmlname, 0);
6804 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6805 print '</form>';
6806 } else {
6807 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6808 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6809 }
6810 }
6811
6812 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6813
6823 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6824 {
6825 // phpcs:enable
6826 global $langs, $conf;
6827
6828 if ($htmlname != "none") {
6829 print '<form method="POST" action="' . $page . '">';
6830 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6831 print '<input type="hidden" name="token" value="' . newToken() . '">';
6832 print '<input type="text" class="maxwidth75" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6833 print '<select name="calculation_mode" id="calculation_mode">';
6834 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6835 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6836 print '</select> ';
6837 print ajax_combobox("calculation_mode");
6838 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6839 print '</form>';
6840 } else {
6841 if (!empty($rate)) {
6842 print price($rate, 1, $langs, 0, 0);
6843 if ($currency && $rate != 1) {
6844 print ' &nbsp; <span class="opacitymedium">(' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')</span>';
6845 }
6846 } else {
6847 print 1;
6848 }
6849 }
6850 }
6851
6852 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6853
6869 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6870 {
6871 // phpcs:enable
6872 global $conf, $langs;
6873
6874 if ($htmlname != "none") {
6875 print '<form method="post" action="' . $page . '">';
6876 print '<input type="hidden" name="action" value="setabsolutediscount">';
6877 print '<input type="hidden" name="token" value="' . newToken() . '">';
6878 print '<div class="inline-block">';
6879 if (!empty($discount_type)) {
6880 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6881 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6882 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6883 } else {
6884 $translationKey = 'HasCreditNoteFromSupplier';
6885 }
6886 } else {
6887 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6888 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6889 } else {
6890 $translationKey = 'HasCreditNoteFromSupplier';
6891 }
6892 }
6893 } else {
6894 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6895 if (!$filter || $filter == "fk_facture_source IS NULL") {
6896 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6897 } else {
6898 $translationKey = 'CompanyHasCreditNote';
6899 }
6900 } else {
6901 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6902 $translationKey = 'CompanyHasAbsoluteDiscount';
6903 } else {
6904 $translationKey = 'CompanyHasCreditNote';
6905 }
6906 }
6907 }
6908 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6909 if (empty($hidelist)) {
6910 print ' ';
6911 }
6912 print '</div>';
6913 if (empty($hidelist)) {
6914 print '<div class="inline-block" style="padding-right: 10px">';
6915 $newfilter = 'discount_type=' . intval($discount_type);
6916 if (!empty($discount_type)) {
6917 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6918 } else {
6919 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6920 }
6921 if ($filter) {
6922 $newfilter .= ' AND (' . $filter . ')';
6923 }
6924 // output the combo of discounts
6925 $nbqualifiedlines = $this->select_remises((string) $selected, $htmlname, $newfilter, $socid, $maxvalue);
6926 if ($nbqualifiedlines > 0) {
6927 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6928 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6929 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6930 }
6931 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6932 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6933 }
6934
6935 print '>';
6936 }
6937 print '</div>';
6938 }
6939 if ($more) {
6940 print '<div class="inline-block">';
6941 print $more;
6942 print '</div>';
6943 }
6944 print '</form>';
6945 } else {
6946 if ($selected) {
6947 print $selected;
6948 } else {
6949 print "0";
6950 }
6951 }
6952 }
6953
6954
6955 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6956
6966 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6967 {
6968 // phpcs:enable
6969 global $langs;
6970
6971 if ($htmlname != "none") {
6972 print '<form method="post" action="' . $page . '">';
6973 print '<input type="hidden" name="action" value="set_contact">';
6974 print '<input type="hidden" name="token" value="' . newToken() . '">';
6975 print '<table class="nobordernopadding">';
6976 print '<tr><td>';
6977 print $this->selectcontacts($societe->id, $selected, $htmlname);
6978 $num = $this->num;
6979 if ($num == 0) {
6980 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6981 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&action=create&backtoreferer=1">' . $addcontact . '</a>';
6982 }
6983 print '</td>';
6984 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6985 print '</tr></table></form>';
6986 } else {
6987 if ($selected) {
6988 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6989 $contact = new Contact($this->db);
6990 $contact->fetch((int) $selected);
6991 print $contact->getFullName($langs);
6992 } else {
6993 print "&nbsp;";
6994 }
6995 }
6996 }
6997
6998 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6999
7016 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
7017 {
7018 // phpcs:enable
7019 global $langs;
7020
7021 $out = '';
7022 if ($htmlname != "none") {
7023 $out .= '<form method="post" action="' . $page . '">';
7024 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
7025 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
7026 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
7027 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
7028 $out .= '</form>';
7029 } else {
7030 if ($selected) {
7031 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
7032 $soc = new Societe($this->db);
7033 $soc->fetch((int) $selected);
7034 $out .= $soc->getNomUrl(0, '');
7035 } else {
7036 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
7037 }
7038 }
7039
7040 if ($nooutput) {
7041 return $out;
7042 } else {
7043 print $out;
7044 }
7045
7046 return '';
7047 }
7048
7049 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7050
7059 public function select_currency($selected = '', $htmlname = 'currency_id')
7060 {
7061 // phpcs:enable
7062 print $this->selectCurrency($selected, $htmlname);
7063 }
7064
7074 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
7075 {
7076 global $langs, $user;
7077
7078 $langs->loadCacheCurrencies('');
7079
7080 $out = '';
7081
7082 if ($selected == 'euro' || $selected == 'euros') {
7083 $selected = 'EUR'; // Pour compatibilite
7084 }
7085
7086 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
7087 if ($useempty) {
7088 $out .= '<option value="-1" selected></option>';
7089 }
7090 foreach ($langs->cache_currencies as $code_iso => $currency) {
7091 $labeltoshow = $currency['label'];
7092 if ($mode == 1) {
7093 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
7094 } else {
7095 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
7096 }
7097
7098 if ($selected && $selected == $code_iso) {
7099 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
7100 } else {
7101 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
7102 }
7103 $out .= dol_string_nohtmltag($labeltoshow);
7104 $out .= '</option>';
7105 }
7106 $out .= '</select>';
7107 if ($user->admin) {
7108 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
7109 }
7110
7111 // Make select dynamic
7112 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7113 $out .= ajax_combobox($htmlname);
7114
7115 return $out;
7116 }
7117
7130 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = 'maxwidth200 widthcentpercentminusx')
7131 {
7132 global $conf, $langs;
7133
7134 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
7135
7136 $TCurrency = array();
7137
7138 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
7139 $sql .= " WHERE entity IN ('" . getEntity('multicurrency') . "')";
7140 if ($filter) {
7141 $sql .= " AND " . $filter;
7142 }
7143 $resql = $this->db->query($sql);
7144 if ($resql) {
7145 while ($obj = $this->db->fetch_object($resql)) {
7146 $TCurrency[$obj->code] = $obj->code;
7147 }
7148 }
7149
7150 $out = '';
7151 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7152 if ($useempty) {
7153 $out .= '<option value="">&nbsp;</option>';
7154 }
7155 // If company current currency not in table, we add it into list. Should always be available.
7156 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
7157 $TCurrency[$conf->currency] = $conf->currency;
7158 }
7159 if (count($TCurrency) > 0) {
7160 foreach ($langs->cache_currencies as $code_iso => $currency) {
7161 if (isset($TCurrency[$code_iso])) {
7162 if (!empty($selected) && $selected == $code_iso) {
7163 $out .= '<option value="' . $code_iso . '" selected="selected">';
7164 } else {
7165 $out .= '<option value="' . $code_iso . '">';
7166 }
7167
7168 $out .= $currency['label'];
7169 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
7170 $out .= '</option>';
7171 }
7172 }
7173 }
7174
7175 $out .= '</select>';
7176
7177 // Make select dynamic
7178 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7179 $out .= ajax_combobox($htmlname);
7180
7181 return $out;
7182 }
7183
7184 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7185
7192 public function load_cache_vatrates($country_code)
7193 {
7194 // phpcs:enable
7195 global $langs, $user;
7196
7197 $num = count($this->cache_vatrates);
7198 if ($num > 0) {
7199 return $num; // Cache already loaded
7200 }
7201
7202 dol_syslog(__METHOD__, LOG_DEBUG);
7203
7204 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
7205 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
7206 $sql .= " WHERE t.fk_pays = c.rowid";
7207 $sql .= " AND t.active > 0";
7208 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
7209 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
7210 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
7211
7212 $resql = $this->db->query($sql);
7213 if ($resql) {
7214 $num = $this->db->num_rows($resql);
7215 if ($num) {
7216 for ($i = 0; $i < $num; $i++) {
7217 $obj = $this->db->fetch_object($resql);
7218
7219 $tmparray = array();
7220 $tmparray['rowid'] = $obj->rowid;
7221 $tmparray['type_vat'] = ($obj->type_vat <= 0 ? 0 : $obj->type_vat); // Some version have type_vat corrupted with value -1
7222 $tmparray['code'] = $obj->code;
7223 $tmparray['txtva'] = $obj->taux;
7224 $tmparray['nprtva'] = $obj->recuperableonly;
7225 $tmparray['localtax1'] = $obj->localtax1;
7226 $tmparray['localtax1_type'] = $obj->localtax1_type;
7227 $tmparray['localtax2'] = $obj->localtax2;
7228 $tmparray['localtax2_type'] = $obj->localtax1_type;
7229 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
7230 $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
7231 $positiverates = '';
7232 if ($obj->taux) {
7233 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
7234 }
7235 if ($obj->localtax1) {
7236 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
7237 }
7238 if ($obj->localtax2) {
7239 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
7240 }
7241 if (empty($positiverates)) {
7242 $positiverates = '0';
7243 }
7244 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
7245
7246 $this->cache_vatrates[$obj->rowid] = $tmparray;
7247 }
7248
7249 return $num;
7250 } else {
7251 $this->error = '<span class="error">';
7252 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
7253 $reg = array();
7254 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
7255 $langs->load("errors");
7256 $new_country_code = $reg[1];
7257 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid');
7258 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
7259 }
7260 $this->error .= '</span>';
7261 return -1;
7262 }
7263 } else {
7264 $this->error = '<span class="error">' . $this->db->error() . '</span>';
7265 return -2;
7266 }
7267 }
7268
7269 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7270
7293 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)
7294 {
7295 // phpcs:enable
7296 global $langs, $mysoc, $hookmanager;
7297
7298 $langs->load('errors');
7299
7300 $return = '';
7301 // Bypass the default method
7302 $hookmanager->initHooks(array('commonobject'));
7303 $info_bits == 1 ? $is_npr = 1 : $is_npr = 0;
7304 $parameters = array(
7305 'seller' => $societe_vendeuse,
7306 'buyer' => $societe_acheteuse,
7307 'idprod' => $idprod,
7308 'is_npr' => $is_npr,
7309 'type' => $type,
7310 'options_only' => $options_only,
7311 'mode' => $mode,
7312 'type_vat' => $type_vat
7313 );
7314 $reshook = $hookmanager->executeHooks('load_tva', $parameters);
7315 if ($reshook > 0) {
7316 return $hookmanager->resPrint;
7317 } elseif ($reshook === 0) {
7318 $return .= $hookmanager->resPrint;
7319 }
7320
7321 // Define defaultnpr, defaultttx and defaultcode
7322 $defaultnpr = ($info_bits & 0x01);
7323 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
7324 $defaulttx = str_replace('*', '', $selectedrate);
7325 $defaultcode = '';
7326 $reg = array();
7327 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7328 $defaultcode = $reg[1];
7329 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7330 }
7331 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
7332
7333 // Check parameters
7334 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
7335 if ($societe_vendeuse->id == $mysoc->id) {
7336 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
7337 } else {
7338 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
7339 }
7340 return $return;
7341 }
7342
7343 //var_dump($societe_acheteuse);
7344 //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";
7345 //exit;
7346
7347 // Define list of countries to use to search VAT rates to show
7348 // First we defined code_country to use to find list
7349 if (is_object($societe_vendeuse)) {
7350 $code_country = "'" . $societe_vendeuse->country_code . "'";
7351 } else {
7352 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
7353 }
7354
7355 if ($societe_vendeuse == $mysoc && getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
7356 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
7357 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
7358 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
7359 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
7360 if (is_object($societe_vendeuse) && is_object($societe_acheteuse) && isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
7361 // We also add the buyer country code
7362 if (is_numeric($type)) {
7363 if ($type == 1) { // We know product is a service
7364 switch ($selectVatComboMode) {
7365 case '1':
7366 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7367 break;
7368 case '2':
7369 $code_country = "'" . $societe_acheteuse->country_code . "'";
7370 break;
7371 }
7372 }
7373 } elseif (!$idprod) { // We don't know type of product
7374 switch ($selectVatComboMode) {
7375 case '1':
7376 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7377 break;
7378 case '2':
7379 $code_country = "'" . $societe_acheteuse->country_code . "'";
7380 break;
7381 }
7382 } else {
7383 $prodstatic = new Product($this->db);
7384 $prodstatic->fetch($idprod);
7385 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
7386 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7387 }
7388 }
7389 }
7390 }
7391
7392 // Now we load the list of VAT
7393 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
7394
7395 // Keep only the VAT qualified for $type_vat
7396 $arrayofvatrates = array();
7397 foreach ($this->cache_vatrates as $cachevalue) {
7398 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] == $type_vat) {
7399 $arrayofvatrates[] = $cachevalue;
7400 }
7401 }
7402
7403 $num = count($arrayofvatrates);
7404 if ($num > 0) {
7405 // Define the vat rate to pre-select (if defaulttx not forced so is -1 or '')
7406 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7407 // Define a default thirdparty to use if the seller or buyer is not defined
7408 $tmpthirdparty = new Societe($this->db);
7409 $tmpthirdparty->country_code = $mysoc->country_code;
7410
7411 $defaulttx = get_default_tva(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7412 $defaultnpr = get_default_npr(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7413
7414 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7415 $defaultcode = $reg[1];
7416 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7417 }
7418 if (empty($defaulttx)) {
7419 $defaultnpr = 0;
7420 }
7421 }
7422
7423 // If we fails to find a default vat rate, we take the last one in list
7424 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
7425 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7426 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
7427 // We take the last one found in list
7428 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
7429 } else {
7430 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
7431 $defaulttx = '';
7432 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
7433 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
7434 }
7435 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7436 $defaultcode = $reg[1];
7437 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7438 }
7439 }
7440 }
7441
7442 // Disabled is true if the seller is not subject to VAT
7443 $disabled = false;
7444 $title = '';
7445 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && empty($societe_vendeuse->tva_assuj)) {
7446 // 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
7447 // EXPENSEREPORT_OVERRIDE_VAT is a strange option that allow to override/enable VAT regardless of sellet vat option - needed for expense report if
7448 // expense report used for business expenses instead of using supplier invoices (but this is a very bad idea !)
7449 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
7450 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
7451 $disabled = true;
7452 }
7453 }
7454
7455 if (!$options_only) {
7456 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
7457 }
7458
7459 $selectedfound = false;
7460 foreach ($arrayofvatrates as $rate) {
7461 // Keep only 0 if seller is not subject to VAT
7462 if ($disabled && $rate['txtva'] != 0) {
7463 continue;
7464 }
7465
7466 // Define key to use into select list
7467 $key = $rate['txtva'];
7468 $key .= $rate['nprtva'] ? '*' : '';
7469 if ($mode > 0 && $rate['code']) {
7470 $key .= ' (' . $rate['code'] . ')';
7471 }
7472 if ($mode < 0) {
7473 $key = $rate['rowid'];
7474 }
7475
7476 $return .= '<option value="' . $key . '"';
7477 if (!$selectedfound) {
7478 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
7479 if ($defaultcode == $rate['code']) {
7480 $return .= ' selected';
7481 $selectedfound = true;
7482 }
7483 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
7484 $return .= ' selected';
7485 $selectedfound = true;
7486 }
7487 }
7488 $return .= '>';
7489
7490 // Show label of VAT
7491 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
7492 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
7493 $return .= $rate['labelpositiverates'];
7494 } else {
7495 // Simple label
7496 $return .= vatrate($rate['label']);
7497 }
7498
7499 //$return.=($rate['code']?' '.$rate['code']:'');
7500 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
7501
7502 $return .= '</option>';
7503 }
7504
7505 if (!$options_only) {
7506 $return .= '</select>';
7507 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
7508 }
7509 } else {
7510 $return .= $this->error;
7511 }
7512
7513 $this->num = $num;
7514 return $return;
7515 }
7516
7517
7518 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7519
7544 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 = '')
7545 {
7546 // phpcs:enable
7547 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
7548 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
7549 if (!empty($nooutput)) {
7550 return $retstring;
7551 }
7552 print $retstring;
7553
7554 return '';
7555 }
7556
7572 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
7573 {
7574 global $langs;
7575
7576 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
7577 if ($forcenewline) {
7578 $ret .= '<br>';
7579 }
7580 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
7581 return $ret;
7582 }
7583
7612 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 = '')
7613 {
7614 global $conf, $langs;
7615
7616 if ($gm === 'auto') {
7617 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7618 }
7619
7620 $retstring = '';
7621
7622 if ($prefix == '') {
7623 $prefix = 're';
7624 }
7625 if ($h == '') {
7626 $h = 0;
7627 }
7628 if ($m == '') {
7629 $m = 0;
7630 }
7631 $emptydate = 0;
7632 $emptyhours = 0;
7633 if ($stepminutes <= 0 || $stepminutes > 30) {
7634 $stepminutes = 1;
7635 }
7636 if ($empty == 1) {
7637 $emptydate = 1;
7638 $emptyhours = 1;
7639 }
7640 if ($empty == 2) {
7641 $emptydate = 0;
7642 $emptyhours = 1;
7643 }
7644 $orig_set_time = $set_time;
7645
7646 if ($set_time === '' && $emptydate == 0) {
7647 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7648 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7649 $set_time = dol_now($gm);
7650 } else {
7651 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7652 }
7653 }
7654
7655 // Analysis of the pre-selection date
7656 $reg = array();
7657 $shour = '';
7658 $smin = '';
7659 $ssec = '';
7660 if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', (string) $set_time, $reg)) { // deprecated usage
7661 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7662 $syear = (!empty($reg[1]) ? $reg[1] : '');
7663 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7664 $sday = (!empty($reg[3]) ? $reg[3] : '');
7665 $shour = (!empty($reg[4]) ? $reg[4] : '');
7666 $smin = (!empty($reg[5]) ? $reg[5] : '');
7667 } elseif (strval($set_time) != '' && $set_time != -1) {
7668 // set_time est un timestamps (0 possible)
7669 $syear = dol_print_date($set_time, "%Y", $gm);
7670 $smonth = dol_print_date($set_time, "%m", $gm);
7671 $sday = dol_print_date($set_time, "%d", $gm);
7672 if ($orig_set_time != '') {
7673 $shour = dol_print_date($set_time, "%H", $gm);
7674 $smin = dol_print_date($set_time, "%M", $gm);
7675 $ssec = dol_print_date($set_time, "%S", $gm);
7676 }
7677 } else {
7678 // Date est '' ou vaut -1
7679 $syear = '';
7680 $smonth = '';
7681 $sday = '';
7682 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7683 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7684 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7685 }
7686 if ($h == 3 || $h == 4) {
7687 $shour = '';
7688 }
7689 if ($m == 3) {
7690 $smin = '';
7691 }
7692
7693 $nowgmt = dol_now('gmt');
7694 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7695
7696 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7697 $usecalendar = 'combo';
7698 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7699 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : getDolGlobalString("MAIN_POPUP_CALENDAR"));
7700 }
7701 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7702 // If we use a text browser or screen reader, we use the 'combo' date selector
7703 $usecalendar = 'html';
7704 }
7705
7706 if ($d) {
7707 // Show date with popup
7708 if ($usecalendar != 'combo') {
7709 $formatted_date = '';
7710 //print "e".$set_time." t ".$conf->format_date_short;
7711 if (strval($set_time) != '' && $set_time != -1) {
7712 //$formatted_date=dol_print_date($set_time,$conf->format_date_short);
7713 $formatted_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7714 }
7715
7716 // Calendrier popup version eldy
7717 if ($usecalendar == "eldy") {
7718 // To have this manager working back, you must retrieve all functions showDP child found into the lib_head.js of v4 for example
7719 // and use load the js so the call of showDP will works.
7720
7721 /*
7722 // Input area to enter date manually
7723 $retstring .= '<!-- datepicker usecalendar=eldy --><input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formatted_date . '"';
7724 $retstring .= ($disabled ? ' disabled' : '');
7725 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7726 $retstring .= ' autocomplete="off">';
7727
7728 // Icon calendar
7729 $retstringbuttom = '';
7730 if (!$disabled) {
7731 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7732 $base = DOL_URL_ROOT . '/core/';
7733 $retstringbuttom .= ' onClick="showDP(\'' . dol_escape_js($base) . '\',\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\',\'' . dol_escape_js($langs->defaultlang) . '\');"';
7734 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink paddingright"') . '</button>';
7735 } else {
7736 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink paddingright"') . '</button>';
7737 }
7738 $retstring = $retstringbuttom . $retstring;
7739
7740 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7741 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7742 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7743 */
7744 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7745 if (!$disabled && $usecalendar != 'html') {
7746 // Output javascript for datepicker
7747 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7748 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7749
7750 $retstring .= '<!-- datepicker usecalendar='.$usecalendar.' --><script nonce="' . getNonce() . '" type="text/javascript">';
7751 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7752 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7753 autoclose: true,
7754 todayHighlight: true,
7755 yearRange: '" . $minYear . ":" . $maxYear . "',";
7756 if (!empty($conf->dol_use_jmobile)) {
7757 $retstring .= "
7758 beforeShow: function (input, datePicker) {
7759 input.disabled = true;
7760 },
7761 onClose: function (dateText, datePicker) {
7762 this.disabled = false;
7763 },
7764 ";
7765 }
7766 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7767 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7768 $buttonImage = $calendarpicto ?: DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png";
7769 $retstring .= "
7770 showOn: 'button', /* both has problem with autocompletion */
7771 buttonImage: '" . $buttonImage . "',
7772 buttonImageOnly: true";
7773 }
7774 $retstring .= "
7775 }) });";
7776 $retstring .= "</script>";
7777 }
7778
7779 // Input area to enter date manually
7780 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7781 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="'.($usecalendar == 'html' ? "date" : "text").'" class="maxwidthdate center" maxlength="11" value="'.$formatted_date.'"';
7782 $retstring .= ($disabled ? ' disabled' : '');
7783 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7784 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($usecalendar == 'html' ? 'yyyy-MM-dd' : $langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7785 $retstring .= ' autocomplete="off">';
7786
7787 // Icon calendar
7788 if ($disabled) {
7789 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7790 $retstring = $retstringbutton . $retstring;
7791 }
7792
7793 $retstring .= '</div>';
7794 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7795 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7796 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7797 } else {
7798 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7799 }
7800 } else {
7801 // Show date with combo selects
7802 // Day
7803 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7804
7805 if ($emptydate || $set_time == -1) {
7806 $retstring .= '<option value="0" selected>&nbsp;</option>';
7807 }
7808
7809 for ($day = 1; $day <= 31; $day++) {
7810 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7811 }
7812
7813 $retstring .= "</select>";
7814
7815 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7816 if ($emptydate || $set_time == -1) {
7817 $retstring .= '<option value="0" selected>&nbsp;</option>';
7818 }
7819
7820 // Month
7821 for ($month = 1; $month <= 12; $month++) {
7822 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7823 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7824 $retstring .= "</option>";
7825 }
7826 $retstring .= "</select>";
7827
7828 // Year
7829 if ($emptydate || $set_time == -1) {
7830 $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 . '">';
7831 } else {
7832 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7833
7834 $syear = (int) $syear;
7835 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7836 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7837 }
7838 $retstring .= "</select>\n";
7839 }
7840 }
7841 }
7842
7843 if ($d && $h) {
7844 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7845 $retstring .= '<span class="nowraponall">';
7846 }
7847
7848 if ($h) {
7849 $hourstart = 0;
7850 $hourend = 24;
7851 if ($openinghours != '') {
7852 $openinghours = explode(',', $openinghours);
7853 $hourstart = $openinghours[0];
7854 $hourend = $openinghours[1];
7855 if ($hourend < $hourstart) {
7856 $hourend = $hourstart;
7857 }
7858 }
7859
7860 // Show hour
7861 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7862 if ($emptyhours) {
7863 $retstring .= '<option value="-1">&nbsp;</option>';
7864 }
7865 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7866 if (strlen($hour) < 2) {
7867 $hour = "0" . $hour;
7868 }
7869 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7870 $retstring .= '</option>';
7871 }
7872 $retstring .= '</select>';
7873
7874 if ($disabled) {
7875 $retstring .= '<input type="hidden" id="' . $prefix . 'hour" name="' . $prefix . 'hour" value="' . $shour . '">' . "\n";
7876 }
7877 if ($m) {
7878 $retstring .= ":";
7879 }
7880 }
7881
7882 if ($m) {
7883 // Show minutes
7884 $retstring .= '<select ' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7885 if ($emptyhours) {
7886 $retstring .= '<option value="-1">&nbsp;</option>';
7887 }
7888 for ($min = 0; $min < 60; $min += $stepminutes) {
7889 $min_str = sprintf("%02d", $min);
7890 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7891 }
7892 $retstring .= '</select>';
7893 if ($disabled) {
7894 $retstring .= '<input type="hidden" id="' . $prefix . 'min" name="' . $prefix . 'min" value="' . $smin . '">' . "\n";
7895 }
7896 // Add also seconds
7897 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7898 }
7899
7900 if ($d && $h) {
7901 $retstring .= '</span>';
7902 }
7903
7904 // Add a "Now" link
7905 if (!empty($conf->use_javascript_ajax) && $addnowlink && !$disabled) {
7906 // Script which will be inserted in the onClick of the "Now" link
7907 $reset_scripts = "";
7908 if ($addnowlink == 2) { // local computer time
7909 // pad add leading 0 on numbers
7910 $reset_scripts .= "Number.prototype.pad = function(size) {
7911 var s = String(this);
7912 while (s.length < (size || 2)) {s = '0' + s;}
7913 return s;
7914 };
7915 var d = new Date();";
7916 }
7917
7918 // Generate the date part, depending on the use or not of the javascript calendar
7919 if ($addnowlink == 1) { // server time expressed in user time setup
7920 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7921 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7922 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7923 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7924 } elseif ($addnowlink == 2) {
7925 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7926 * This break application for foreign languages.
7927 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7928 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7929 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7930 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7931 */
7932 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7933 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7934 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7935 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7936 }
7937 /*if ($usecalendar == "eldy")
7938 {
7939 $base=DOL_URL_ROOT.'/core/';
7940 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7941 }
7942 else
7943 {
7944 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7945 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7946 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7947 }*/
7948 // Update the hour part
7949 if ($h) {
7950 if ($fullday) {
7951 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7952 }
7953 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7954 if ($addnowlink == 1) {
7955 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7956 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7957 } elseif ($addnowlink == 2) {
7958 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7959 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7960 }
7961
7962 if ($fullday) {
7963 $reset_scripts .= ' } ';
7964 }
7965 }
7966 // Update the minute part
7967 if ($m) {
7968 if ($fullday) {
7969 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7970 }
7971 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7972 if ($addnowlink == 1) {
7973 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7974 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7975 } elseif ($addnowlink == 2) {
7976 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7977 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7978 }
7979 if ($fullday) {
7980 $reset_scripts .= ' } ';
7981 }
7982 }
7983 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7984 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7985 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7986 $retstring .= $langs->trans("Now");
7987 $retstring .= '</button> ';
7988 }
7989 }
7990
7991 // Add a "Plus one hour" link
7992 if ($conf->use_javascript_ajax && $addplusone && !$disabled) {
7993 // Script which will be inserted in the onClick of the "Add plusone" link
7994 $reset_scripts = "";
7995
7996 // Generate the date part, depending on the use or not of the javascript calendar
7997 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7998 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7999 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
8000 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
8001 // Update the hour part
8002 if ($h) {
8003 if ($fullday) {
8004 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
8005 }
8006 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
8007 if ($fullday) {
8008 $reset_scripts .= ' } ';
8009 }
8010 }
8011 // Update the minute part
8012 if ($m) {
8013 if ($fullday) {
8014 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
8015 }
8016 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
8017 if ($fullday) {
8018 $reset_scripts .= ' } ';
8019 }
8020 }
8021 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
8022 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
8023 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
8024 $retstring .= $langs->trans("DateStartPlusOne");
8025 $retstring .= '</button> ';
8026 }
8027 }
8028
8029 // Add a link to set data
8030 if ($conf->use_javascript_ajax && !empty($adddateof) && !$disabled) {
8031 if (!is_array($adddateof)) {
8032 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
8033 } else {
8034 $arrayofdateof = $adddateof;
8035 }
8036 foreach ($arrayofdateof as $valuedateof) {
8037 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
8038 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
8039 $tmparray = dol_getdate($tmpadddateof);
8040 if (empty($tmplabeladddateof)) {
8041 $tmplabeladddateof = $langs->trans("DateInvoice");
8042 }
8043 $reset_scripts = 'console.log(\'Click on now link\'); ';
8044 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
8045 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
8046 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
8047 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
8048 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
8049 }
8050 }
8051
8052 return $retstring;
8053 }
8054
8063 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
8064 {
8065 global $langs;
8066
8067 $TDurationTypes = array(
8068 'y' => $langs->trans('Years'),
8069 'm' => $langs->trans('Month'),
8070 'w' => $langs->trans('Weeks'),
8071 'd' => $langs->trans('Days'),
8072 'h' => $langs->trans('Hours'),
8073 'i' => $langs->trans('Minutes')
8074 );
8075
8076 // Removed undesired duration types
8077 foreach ($excludetypes as $value) {
8078 unset($TDurationTypes[$value]);
8079 }
8080
8081 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
8082 foreach ($TDurationTypes as $key => $typeduration) {
8083 $retstring .= '<option value="' . $key . '"';
8084 if ($key == $selected) {
8085 $retstring .= " selected";
8086 }
8087 $retstring .= ">" . $typeduration . "</option>";
8088 }
8089 $retstring .= "</select>";
8090
8091 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
8092
8093 return $retstring;
8094 }
8095
8096 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8097
8111 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
8112 {
8113 // phpcs:enable
8114 global $langs;
8115
8116 $retstring = '<span class="nowraponall">';
8117
8118 $hourSelected = '';
8119 $minSelected = '';
8120
8121 // Hours
8122 if ($iSecond != '') {
8123 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
8124
8125 $hourSelected = convertSecondToTime($iSecond, 'allhour');
8126 $minSelected = convertSecondToTime($iSecond, 'min');
8127 }
8128
8129 if ($typehour == 'select') {
8130 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
8131 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
8132 $retstring .= '<option value="' . $hour . '"';
8133 if (is_numeric($hourSelected) && $hourSelected == $hour) {
8134 $retstring .= " selected";
8135 }
8136 $retstring .= ">" . $hour . "</option>";
8137 }
8138 $retstring .= "</select>";
8139 } elseif ($typehour == 'text' || $typehour == 'textselect') {
8140 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
8141 } else {
8142 return 'BadValueForParameterTypeHour';
8143 }
8144
8145 if ($typehour != 'text') {
8146 $retstring .= ' ' . $langs->trans('HourShort');
8147 } else {
8148 $retstring .= '<span class="">:</span>';
8149 }
8150
8151 // Minutes
8152 if ($minunderhours) {
8153 $retstring .= '<br>';
8154 } else {
8155 if ($typehour != 'text') {
8156 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
8157 }
8158 }
8159
8160 if ($typehour == 'select' || $typehour == 'textselect') {
8161 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
8162 for ($min = 0; $min <= 55; $min += 5) {
8163 $retstring .= '<option value="' . $min . '"';
8164 if (is_numeric($minSelected) && $minSelected == $min) {
8165 $retstring .= ' selected';
8166 }
8167 $retstring .= '>' . $min . '</option>';
8168 }
8169 $retstring .= "</select>";
8170 } elseif ($typehour == 'text') {
8171 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
8172 }
8173
8174 if ($typehour != 'text') {
8175 $retstring .= ' ' . $langs->trans('MinuteShort');
8176 }
8177
8178 $retstring .= "</span>";
8179
8180 if (!empty($nooutput)) {
8181 return $retstring;
8182 }
8183
8184 print $retstring;
8185
8186 return '';
8187 }
8188
8208 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)
8209 {
8210 global $langs, $conf;
8211
8212 $out = '';
8213
8214 // check parameters
8215 if (is_null($ajaxoptions)) {
8216 $ajaxoptions = array();
8217 }
8218
8219 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8220 $placeholder = '';
8221
8222 if ($selected && empty($selected_input_value)) {
8223 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
8224 $tickettmpselect = new Ticket($this->db);
8225 $tickettmpselect->fetch((int) $selected);
8226 $selected_input_value = $tickettmpselect->ref;
8227 unset($tickettmpselect);
8228 }
8229
8230 $urloption = '';
8231 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8232
8233 if (empty($hidelabel)) {
8234 $out .= $langs->trans("RefOrLabel") . ' : ';
8235 } elseif ($hidelabel > 1) {
8236 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8237 if ($hidelabel == 2) {
8238 $out .= img_picto($langs->trans("Search"), 'search');
8239 }
8240 }
8241 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8242 if ($hidelabel == 3) {
8243 $out .= img_picto($langs->trans("Search"), 'search');
8244 }
8245 } else {
8246 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8247 }
8248
8249 if (empty($nooutput)) {
8250 print $out;
8251 } else {
8252 return $out;
8253 }
8254 return '';
8255 }
8256
8257
8274 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8275 {
8276 global $langs, $conf;
8277
8278 $out = '';
8279 $outarray = array();
8280
8281 $selectFields = " p.rowid, p.ref, p.message";
8282
8283 $sql = "SELECT ";
8284 $sql .= $selectFields;
8285 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
8286 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
8287
8288 // Add criteria on ref/label
8289 if ($filterkey != '') {
8290 $sql .= ' AND (';
8291 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8292 // For natural search
8293 $search_crit = explode(' ', $filterkey);
8294 $i = 0;
8295 if (count($search_crit) > 1) {
8296 $sql .= "(";
8297 }
8298 foreach ($search_crit as $crit) {
8299 if ($i > 0) {
8300 $sql .= " AND ";
8301 }
8302 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8303 $sql .= ")";
8304 $i++;
8305 }
8306 if (count($search_crit) > 1) {
8307 $sql .= ")";
8308 }
8309 $sql .= ')';
8310 }
8311
8312 $sql .= $this->db->plimit($limit, 0);
8313
8314 // Build output string
8315 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
8316 $result = $this->db->query($sql);
8317 if ($result) {
8318 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
8319 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
8320
8321 $num = $this->db->num_rows($result);
8322
8323 $events = array();
8324
8325 if (!$forcecombo) {
8326 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8327 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('TICKET_USE_SEARCH_TO_SELECT'));
8328 }
8329
8330 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8331
8332 $textifempty = '';
8333 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8334 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8335 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8336 if ($showempty && !is_numeric($showempty)) {
8337 $textifempty = $langs->trans($showempty);
8338 } else {
8339 $textifempty .= $langs->trans("All");
8340 }
8341 } else {
8342 if ($showempty && !is_numeric($showempty)) {
8343 $textifempty = $langs->trans($showempty);
8344 }
8345 }
8346 if ($showempty) {
8347 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8348 }
8349
8350 $i = 0;
8351 while ($num && $i < $num) {
8352 $opt = '';
8353 $optJson = array();
8354 $objp = $this->db->fetch_object($result);
8355
8356 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
8357 '@phan-var-force array{key:string,value:mixed,type:int} $optJson';
8358 // Add new entry
8359 // "key" value of json key array is used by jQuery automatically as selected value
8360 // "label" value of json key array is used by jQuery automatically as text for combo box
8361 $out .= $opt;
8362 array_push($outarray, $optJson);
8363
8364 $i++;
8365 }
8366
8367 $out .= '</select>';
8368
8369 $this->db->free($result);
8370
8371 if (empty($outputmode)) {
8372 return $out;
8373 }
8374 return $outarray;
8375 } else {
8376 dol_print_error($this->db);
8377 }
8378
8379 return array();
8380 }
8381
8393 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8394 {
8395 $outkey = '';
8396 $outref = '';
8397 $outtype = '';
8398
8399 $outkey = $objp->rowid;
8400 $outref = $objp->ref;
8401
8402 $opt = '<option value="' . $objp->rowid . '"';
8403 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8404 $opt .= '>';
8405 $opt .= $objp->ref;
8406 $objRef = $objp->ref;
8407 if (!empty($filterkey) && $filterkey != '') {
8408 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8409 }
8410
8411 $opt .= "</option>\n";
8412 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8413 }
8414
8434 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)
8435 {
8436 global $langs, $conf;
8437
8438 $out = '';
8439
8440 // check parameters
8441 if (is_null($ajaxoptions)) {
8442 $ajaxoptions = array();
8443 }
8444
8445 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8446 $placeholder = '';
8447
8448 if ($selected && empty($selected_input_value)) {
8449 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8450 $projecttmpselect = new Project($this->db);
8451 $projecttmpselect->fetch((int) $selected);
8452 $selected_input_value = $projecttmpselect->ref;
8453 unset($projecttmpselect);
8454 }
8455
8456 $urloption = '';
8457 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8458
8459 if (empty($hidelabel)) {
8460 $out .= $langs->trans("RefOrLabel") . ' : ';
8461 } elseif ($hidelabel > 1) {
8462 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8463 if ($hidelabel == 2) {
8464 $out .= img_picto($langs->trans("Search"), 'search');
8465 }
8466 }
8467 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8468 if ($hidelabel == 3) {
8469 $out .= img_picto($langs->trans("Search"), 'search');
8470 }
8471 } else {
8472 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8473 }
8474
8475 if (empty($nooutput)) {
8476 print $out;
8477 } else {
8478 return $out;
8479 }
8480 return '';
8481 }
8482
8499 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8500 {
8501 global $langs, $conf;
8502
8503 $out = '';
8504 $outarray = array();
8505
8506 $selectFields = " p.rowid, p.ref";
8507
8508 $sql = "SELECT ";
8509 $sql .= $selectFields;
8510 $sql .= " FROM " . $this->db->prefix() . "projet as p";
8511 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
8512
8513 // Add criteria on ref/label
8514 if ($filterkey != '') {
8515 $sql .= ' AND (';
8516 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8517 // For natural search
8518 $search_crit = explode(' ', $filterkey);
8519 $i = 0;
8520 if (count($search_crit) > 1) {
8521 $sql .= "(";
8522 }
8523 foreach ($search_crit as $crit) {
8524 if ($i > 0) {
8525 $sql .= " AND ";
8526 }
8527 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8528 $sql .= "";
8529 $i++;
8530 }
8531 if (count($search_crit) > 1) {
8532 $sql .= ")";
8533 }
8534 $sql .= ')';
8535 }
8536
8537 $sql .= $this->db->plimit($limit, 0);
8538
8539 // Build output string
8540 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
8541 $result = $this->db->query($sql);
8542 if ($result) {
8543 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8544 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
8545
8546 $num = $this->db->num_rows($result);
8547
8548 $events = array();
8549
8550 if (!$forcecombo) {
8551 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8552 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8553 }
8554
8555 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8556
8557 $textifempty = '';
8558 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8559 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8560 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8561 if ($showempty && !is_numeric($showempty)) {
8562 $textifempty = $langs->trans($showempty);
8563 } else {
8564 $textifempty .= $langs->trans("All");
8565 }
8566 } else {
8567 if ($showempty && !is_numeric($showempty)) {
8568 $textifempty = $langs->trans($showempty);
8569 }
8570 }
8571 if ($showempty) {
8572 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8573 }
8574
8575 $i = 0;
8576 while ($num && $i < $num) {
8577 $opt = '';
8578 $optJson = array();
8579 $objp = $this->db->fetch_object($result);
8580
8581 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
8582 // Add new entry
8583 // "key" value of json key array is used by jQuery automatically as selected value
8584 // "label" value of json key array is used by jQuery automatically as text for combo box
8585 $out .= $opt;
8586 array_push($outarray, $optJson);
8587
8588 $i++;
8589 }
8590
8591 $out .= '</select>';
8592
8593 $this->db->free($result);
8594
8595 if (empty($outputmode)) {
8596 return $out;
8597 }
8598 return $outarray;
8599 } else {
8600 dol_print_error($this->db);
8601 }
8602
8603 return array();
8604 }
8605
8619 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8620 {
8621 $outkey = '';
8622 $outref = '';
8623 $outtype = '';
8624
8625 $label = $objp->label;
8626
8627 $outkey = $objp->rowid;
8628 $outref = $objp->ref;
8629 $outlabel = $objp->label;
8630 $outtype = $objp->fk_product_type;
8631
8632 $opt = '<option value="' . $objp->rowid . '"';
8633 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8634 $opt .= '>';
8635 $opt .= $objp->ref;
8636 $objRef = $objp->ref;
8637 if (!empty($filterkey) && $filterkey != '') {
8638 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8639 }
8640
8641 $opt .= "</option>\n";
8642 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8643 }
8644
8645
8665 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)
8666 {
8667 global $langs, $conf;
8668
8669 $out = '';
8670
8671 // check parameters
8672 if (is_null($ajaxoptions)) {
8673 $ajaxoptions = array();
8674 }
8675
8676 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8677 $placeholder = '';
8678
8679 if ($selected && empty($selected_input_value)) {
8680 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8681 $adherenttmpselect = new Adherent($this->db);
8682 $adherenttmpselect->fetch((int) $selected);
8683 $selected_input_value = $adherenttmpselect->ref;
8684 unset($adherenttmpselect);
8685 }
8686
8687 $urloption = '';
8688
8689 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8690
8691 if (empty($hidelabel)) {
8692 $out .= $langs->trans("RefOrLabel") . ' : ';
8693 } elseif ($hidelabel > 1) {
8694 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8695 if ($hidelabel == 2) {
8696 $out .= img_picto($langs->trans("Search"), 'search');
8697 }
8698 }
8699 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8700 if ($hidelabel == 3) {
8701 $out .= img_picto($langs->trans("Search"), 'search');
8702 }
8703 } else {
8704 $filterkey = '';
8705
8706 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8707 }
8708
8709 if (empty($nooutput)) {
8710 print $out;
8711 } else {
8712 return $out;
8713 }
8714 return '';
8715 }
8716
8733 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8734 {
8735 global $langs, $conf;
8736
8737 $out = '';
8738 $outarray = array();
8739
8740 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8741
8742 $sql = "SELECT ";
8743 $sql .= $selectFields;
8744 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8745 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8746
8747 // Add criteria on ref/label
8748 if ($filterkey != '') {
8749 $sql .= ' AND (';
8750 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8751 // For natural search
8752 $search_crit = explode(' ', $filterkey);
8753 $i = 0;
8754 if (count($search_crit) > 1) {
8755 $sql .= "(";
8756 }
8757 foreach ($search_crit as $crit) {
8758 if ($i > 0) {
8759 $sql .= " AND ";
8760 }
8761 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8762 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8763 $i++;
8764 }
8765 if (count($search_crit) > 1) {
8766 $sql .= ")";
8767 }
8768 $sql .= ')';
8769 }
8770 if ($status != -1) {
8771 $sql .= ' AND statut = ' . ((int) $status);
8772 }
8773 $sql .= $this->db->plimit($limit, 0);
8774
8775 // Build output string
8776 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8777 $result = $this->db->query($sql);
8778 if ($result) {
8779 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8780 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8781
8782 $num = $this->db->num_rows($result);
8783
8784 $events = array();
8785
8786 if (!$forcecombo) {
8787 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8788 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8789 }
8790
8791 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8792
8793 $textifempty = '';
8794 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8795 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8796 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8797 if ($showempty && !is_numeric($showempty)) {
8798 $textifempty = $langs->trans($showempty);
8799 } else {
8800 $textifempty .= $langs->trans("All");
8801 }
8802 } else {
8803 if ($showempty && !is_numeric($showempty)) {
8804 $textifempty = $langs->trans($showempty);
8805 }
8806 }
8807 if ($showempty) {
8808 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8809 }
8810
8811 $i = 0;
8812 while ($num && $i < $num) {
8813 $opt = '';
8814 $optJson = array();
8815 $objp = $this->db->fetch_object($result);
8816
8817 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8818
8819 // Add new entry
8820 // "key" value of json key array is used by jQuery automatically as selected value
8821 // "label" value of json key array is used by jQuery automatically as text for combo box
8822 $out .= $opt;
8823 array_push($outarray, $optJson);
8824
8825 $i++;
8826 }
8827
8828 $out .= '</select>';
8829
8830 $this->db->free($result);
8831
8832 if (empty($outputmode)) {
8833 return $out;
8834 }
8835 return $outarray;
8836 } else {
8837 dol_print_error($this->db);
8838 }
8839
8840 return array();
8841 }
8842
8854 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8855 {
8856 $outkey = '';
8857 $outlabel = '';
8858 $outtype = '';
8859
8860 $outkey = $objp->rowid;
8861 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8862 $outtype = $objp->fk_adherent_type;
8863
8864 $opt = '<option value="' . $objp->rowid . '"';
8865 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8866 $opt .= '>';
8867 if (!empty($filterkey) && $filterkey != '') {
8868 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8869 }
8870 $opt .= $outlabel;
8871 $opt .= "</option>\n";
8872
8873 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8874 }
8875
8896 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8897 {
8898 global $conf, $extrafields, $user;
8899
8900 // Example of common usage for a link to a thirdparty
8901
8902 // We got this in a modulebuilder form of "MyObject" of module "mymodule".
8903 // 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
8904 // $objectdesc = 'Societe'
8905 // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc']) or it can be an array that is directly
8906 // array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8907
8908 // We got this when showing an extrafields on resource that is a link to societe
8909 // When extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)', we have
8910 // $objectdesc = 'Societe'
8911 // $objectfield = 'resource:options_link_to_societe' or it can be an array that is directly
8912 // array("type"=>'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8913
8914 // With old usage:
8915 // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))'
8916 // $objectfield = ''
8917
8918 //var_dump($objectdesc.' '.$objectfield);
8919 //debug_print_backtrace();
8920
8921 $objectdescorig = $objectdesc;
8922 $objecttmp = null;
8923 $InfoFieldList = array();
8924 $classname = '';
8925 $filter = ''; // Ensure filter has value (for static analysis)
8926 $sortfield = ''; // Ensure filter has value (for static analysis)
8927
8928 if (is_array($objectfield)) { // objectfield is an array
8929 $objectdesc = $objectfield['type'];
8930 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8931 } 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.
8932 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8933 $tmparray = explode(':', $objectfield);
8934
8935 // Get instance of object from $element
8936 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8937
8938 if (is_object($objectforfieldstmp)) {
8939 $objectdesc = '';
8940
8941 $reg = array();
8942 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8943 // For a property in extrafields
8944 $key = $reg[1];
8945 // fetch optionals attributes and labels
8946 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8947
8948 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8949 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8950 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8951 $objectdesc = $tmpextrafields[0];
8952 }
8953 }
8954 } else {
8955 // For a property in ->fields
8956 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8957 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8958 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8959 }
8960 }
8961 }
8962 }
8963
8964 if ($objectdesc) {
8965 // Example of value for $objectdesc:
8966 // Bom:bom/class/bom.class.php:0:t.status=1
8967 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8968 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8969 $InfoFieldList = explode(":", $objectdesc, 4);
8970 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8971 $reg = array();
8972 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8973 $InfoFieldList[4] = $reg[1]; // take the sort field
8974 }
8975 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8976
8977 $classname = $InfoFieldList[0];
8978 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8979 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8980 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8981 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8982
8983 // Load object according to $id and $element
8984 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8985
8986 // Fallback to another solution to get $objecttmp
8987 if (empty($objecttmp) && !empty($classpath)) {
8988 dol_include_once($classpath);
8989
8990 if ($classname && class_exists($classname)) {
8991 $objecttmp = new $classname($this->db);
8992 }
8993 }
8994 }
8995
8996 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
8997 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
8998 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
8999 $filter = str_replace(
9000 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
9001 array($conf->entity, $sharedentities, $user->id),
9002 $filter
9003 );
9004
9005 if (!is_object($objecttmp)) {
9006 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.(is_array($objectfield) ? 'array' : $objectfield).', objectdesc='.$objectdesc, LOG_WARNING);
9007 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.(is_array($objectfield) ? 'array' : $objectfield).', objectdesc='.$objectdesc;
9008 }
9009 '@phan-var-force CommonObject $objecttmp';
9011 //var_dump($filter);
9012 $prefixforautocompletemode = $objecttmp->element;
9013 if ($prefixforautocompletemode == 'societe') {
9014 $prefixforautocompletemode = 'company';
9015 }
9016 if ($prefixforautocompletemode == 'product') {
9017 $prefixforautocompletemode = 'produit';
9018 }
9019
9020 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
9021
9022 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
9023
9024 // Generate the combo HTML component
9025 $out = '';
9026 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
9027 // No immediate load of all database
9028 $placeholder = '';
9029
9030 if ($preSelectedValue && empty($selected_input_value)) {
9031 $objecttmp->fetch($preSelectedValue);
9032 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
9033
9034 $oldValueForShowOnCombobox = 0;
9035 foreach ($objecttmp->fields as $fieldK => $fielV) {
9036 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
9037 continue;
9038 }
9039
9040 if (!$oldValueForShowOnCombobox) {
9041 $selected_input_value = '';
9042 }
9043
9044 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
9045 $selected_input_value .= $objecttmp->$fieldK;
9046 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
9047 }
9048 }
9049
9050 // Set url and param to call to get json of the search results
9051 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
9052 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . (is_scalar($objectfield) ? '&objectfield='.urlencode($objectfield) : '') . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
9053
9054 // Activate the auto complete using ajax call.
9055 $out .= ajax_autocompleter((string) $preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalInt($confkeyforautocompletemode), 0);
9056 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
9057 $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) . '"' : '') . ' />';
9058 } else {
9059 // Immediate load of table record.
9060 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
9061 }
9062
9063 return $out;
9064 }
9065
9066
9087 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
9088 {
9089 global $langs, $user, $hookmanager;
9090
9091 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
9092
9093 $prefixforautocompletemode = $objecttmp->element;
9094 if ($prefixforautocompletemode == 'societe') {
9095 $prefixforautocompletemode = 'company';
9096 }
9097 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
9098
9099 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
9100 $tmpfieldstoshow = '';
9101 foreach ($objecttmp->fields as $key => $val) {
9102 if (! (int) dol_eval((string) $val['enabled'], 1, 1, '1')) {
9103 continue;
9104 }
9105 if (!empty($val['showoncombobox'])) {
9106 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
9107 }
9108 }
9109 if ($tmpfieldstoshow) {
9110 $fieldstoshow = $tmpfieldstoshow;
9111 }
9112 } elseif ($objecttmp->element === 'category') {
9113 $fieldstoshow = 't.label';
9114 } else {
9115 // For backward compatibility
9116 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
9117 }
9118
9119 if (empty($fieldstoshow)) {
9120 if (!empty($objecttmp->parent_element)) {
9121 $fieldstoshow = 'o.ref';
9122 if (empty($sortfield)) {
9123 $sortfield = 'o.ref';
9124 }
9125 if (in_array($objecttmp->element, ['commandedet', 'propaldet', 'facturedet', 'expeditiondet'])) {
9126 $fieldstoshow .= ',p.ref AS p_ref,p.label,t.description';
9127 $sortfield .= ', p.ref';
9128 }
9129 } elseif (isset($objecttmp->fields['ref'])) {
9130 $fieldstoshow = 't.ref';
9131 } else {
9132 $langs->load("errors");
9133 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
9134 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
9135 }
9136 }
9137
9138 $out = '';
9139 $outarray = array();
9140 $tmparray = array();
9141
9142 $num = 0;
9143
9144 // Search data
9145 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . " as t";
9146 if (!empty($objecttmp->isextrafieldmanaged)) {
9147 $extrafieldTable = $objecttmp->table_element;
9148 if ($extrafieldTable == 'categorie') {
9149 $extrafieldTable = 'categories'; // For compatibility
9150 }
9151 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($extrafieldTable) . "_extrafields as e ON t.rowid = e.fk_object";
9152 }
9153 if (!empty($objecttmp->parent_element)) { // If parent_element is defined
9154 $parent_properties = getElementProperties($objecttmp->parent_element);
9155 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($parent_properties['table_element']) . " as o ON o.rowid = t.".$objecttmp->fk_parent_attribute;
9156 }
9157 if (isset($objecttmp->parent_element) && in_array($objecttmp->parent_element, ['commande', 'propal', 'facture', 'expedition'])) {
9158 $sql .= " LEFT JOIN " . $this->db->prefix() . "product as p ON p.rowid = t.fk_product";
9159 }
9160 if (!empty($objecttmp->ismultientitymanaged)) {
9161 if ($objecttmp->ismultientitymanaged == 1) { // @phan-suppress-current-line PhanPluginEmptyStatementIf
9162 // No need to join/link another table
9163 }
9164 if (!is_numeric($objecttmp->ismultientitymanaged)) {
9165 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
9166 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($tmparray[1]) . " as parenttable ON parenttable.rowid = t." . $this->db->sanitize($tmparray[0]);
9167 }
9168 }
9169
9170 // Add where from hooks
9171 $parameters = array(
9172 'object' => $objecttmp,
9173 'htmlname' => $htmlname,
9174 'filter' => $filter,
9175 'searchkey' => $searchkey
9176 );
9177
9178 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
9179 if (!empty($hookmanager->resPrint)) {
9180 $sql .= $hookmanager->resPrint;
9181 } else {
9182 $sql .= " WHERE 1=1";
9183
9184 // If table need a multientity restriction
9185 if (!empty($objecttmp->ismultientitymanaged)) {
9186 if ($objecttmp->ismultientitymanaged == 1) {
9187 $sql .= " AND t.entity IN (" . getEntity($objecttmp->element) . ")";
9188 }
9189 if (!is_numeric($objecttmp->ismultientitymanaged)) {
9190 $sql .= " AND parenttable.entity = t." . $this->db->sanitize($tmparray[0]);
9191 }
9192 // If the parent table is llx_societe and user is not an external user (a more robust test done later for external users),
9193 // then we must also check that user has permissions
9194 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
9195 if (!$user->hasRight('societe', 'client', 'voir') && empty($user->socid)) {
9196 $sql .= " AND EXISTS (SELECT sc.rowid FROM ".$this->db->prefix() . "societe_commerciaux as sc";
9197 $sql .= " WHERE sc.fk_soc = t.fk_soc AND sc.fk_user = ".((int) $user->id).")";
9198 }
9199 }
9200 }
9201
9202 // If user is external user, we must also make a test on llx_societe_commerciaux
9203 if (!empty($user->socid)) {
9204 if ($objecttmp->element == 'societe') {
9205 $sql .= " AND t.rowid = " . ((int) $user->socid);
9206 } elseif (!empty($objecttmp->fields['fk_soc']) || !empty($objecttmp->fields['t.fk_soc']) || property_exists($objecttmp, 'fk_soc') || property_exists($objecttmp, 'socid')) {
9207 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
9208 }
9209 }
9210
9211 $splittedfieldstoshow = explode(',', $fieldstoshow);
9212 foreach ($splittedfieldstoshow as &$field2) {
9213 if (is_numeric($pos = strpos($field2, ' '))) {
9214 $field2 = substr($field2, 0, $pos);
9215 }
9216 }
9217 if ($searchkey != '') {
9218 $sql .= natural_search($splittedfieldstoshow, $searchkey);
9219 }
9220
9221 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
9222 $errormessage = '';
9223 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
9224 if ($errormessage) {
9225 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
9226 }
9227 }
9228 }
9229 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
9230 //$sql.=$this->db->plimit($limit, 0);
9231 //print $sql;
9232
9233 // Build output string
9234 $resql = $this->db->query($sql);
9235 if ($resql) {
9236 // Construct $out and $outarray
9237 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
9238
9239 // 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
9240 $textifempty = '&nbsp;';
9241
9242 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
9243 if (getDolGlobalInt($confkeyforautocompletemode)) {
9244 if ($showempty && !is_numeric($showempty)) {
9245 $textifempty = $langs->trans($showempty);
9246 } else {
9247 $textifempty .= $langs->trans("All");
9248 }
9249 }
9250 if ($showempty) {
9251 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
9252 }
9253
9254 $num = $this->db->num_rows($resql);
9255 $i = 0;
9256 if ($num) {
9257 while ($i < $num) {
9258 $obj = $this->db->fetch_object($resql);
9259 $label = '';
9260 $labelhtml = '';
9261 $tmparray = explode(',', $fieldstoshow);
9262 $oldvalueforshowoncombobox = 0;
9263 foreach ($tmparray as $key => $val) {
9264 $val = preg_replace('/(t|p|o)\./', '', $val);
9265 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
9266 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
9267 $label .= $obj->$val;
9268 $labelhtml .= $obj->$val;
9269
9270 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
9271 }
9272 if (empty($outputmode)) {
9273 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
9274 $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>';
9275 } else {
9276 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
9277 }
9278 } else {
9279 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
9280 }
9281
9282 $i++;
9283 if (($i % 10) == 0) {
9284 $out .= "\n";
9285 }
9286 }
9287 }
9288
9289 $out .= '</select>' . "\n";
9290
9291 if (!$forcecombo) {
9292 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9293 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
9294 }
9295 } else {
9296 dol_print_error($this->db);
9297 }
9298
9299 $this->result = array('nbofelement' => $num);
9300
9301 if ($outputmode) {
9302 return $outarray;
9303 }
9304 return $out;
9305 }
9306
9307
9331 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)
9332 {
9333 global $conf, $langs;
9334
9335 // Do we want a multiselect ?
9336 //$jsbeautify = 0;
9337 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
9338 $jsbeautify = 1;
9339
9340 if ($value_as_key) {
9341 $array = array_combine($array, $array);
9342 }
9343
9344 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
9345
9346 $out = '';
9347
9348 if ($addjscombo < 0) {
9349 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9350 $addjscombo = 1;
9351 } else {
9352 $addjscombo = 0;
9353 }
9354 }
9355 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
9356 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
9357 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
9358 $out .= '>'."\n";
9359
9360 if ($show_empty) {
9361 $textforempty = ' ';
9362 if (!empty($conf->use_javascript_ajax)) {
9363 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
9364 }
9365 if (!is_numeric($show_empty)) {
9366 $textforempty = $show_empty;
9367 }
9368 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
9369 }
9370 if (is_array($array)) {
9371 // Translate
9372 if ($translate) {
9373 foreach ($array as $key => $value) {
9374 if (!is_array($value)) {
9375 $array[$key] = $langs->trans($value);
9376 } else {
9377 $array[$key]['label'] = $langs->trans($value['label']);
9378 }
9379 }
9380 }
9381 // Sort
9382 if ($sort == 'ASC') {
9383 asort($array);
9384 } elseif ($sort == 'DESC') {
9385 arsort($array);
9386 }
9387
9388 foreach ($array as $key => $tmpvalue) {
9389 if (is_array($tmpvalue)) {
9390 $value = $tmpvalue['label'];
9391 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
9392 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
9393 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
9394 } else {
9395 $value = $tmpvalue;
9396 //$valuehtml = $tmpvalue;
9397 $disabled = '';
9398 $style = '';
9399 }
9400 if (!empty($disablebademail)) {
9401 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
9402 || ($disablebademail == 2 && preg_match('/---/', $value))) {
9403 $disabled = ' disabled';
9404 $style = ' class="warning"';
9405 }
9406 }
9407 if ($key_in_label) {
9408 if (empty($nohtmlescape)) {
9409 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
9410 } else {
9411 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
9412 }
9413 } else {
9414 if (empty($nohtmlescape)) {
9415 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
9416 } else {
9417 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
9418 }
9419 if ($value == '' || $value == '-') {
9420 $selectOptionValue = '&nbsp;';
9421 }
9422 }
9423 $out .= '<option value="' . $key . '"';
9424 $out .= $style . $disabled;
9425 if (is_array($id)) {
9426 if (in_array($key, $id) && !$disabled) {
9427 $out .= ' selected'; // To preselect a value
9428 }
9429 } else {
9430 $id = (string) $id; // if $id = 0, then $id = '0'
9431 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
9432 $out .= ' selected'; // To preselect a value
9433 }
9434 }
9435 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
9436 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
9437 }
9438
9439 if (is_array($tmpvalue)) {
9440 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
9441 if ($keyforvalue == 'labelhtml') {
9442 $keyforvalue = 'data-html';
9443 }
9444 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
9445 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
9446 }
9447 }
9448 }
9449 $out .= '>';
9450 $out .= $selectOptionValue;
9451 $out .= "</option>\n";
9452 }
9453 }
9454 $out .= "</select>";
9455
9456 // Add code for jquery to use multiselect
9457 if ($addjscombo && $jsbeautify) {
9458 // Enhance with select2
9459 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9460 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
9461 }
9462
9463 return $out;
9464 }
9465
9484 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
9485 {
9486 global $conf;
9487 global $delayedhtmlcontent; // Will be used later outside of this function
9488
9489 // TODO Use an internal dolibarr component instead of select2
9490 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9491 return '';
9492 }
9493
9494 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
9495
9496 $outdelayed = '';
9497 if (!empty($conf->use_javascript_ajax)) {
9498 $tmpplugin = 'select2';
9499 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9500 <script nonce="' . getNonce() . '">
9501 $(document).ready(function () {
9502
9503 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
9504
9505 $(".' . $htmlname . '").select2({
9506 ajax: {
9507 dir: "ltr",
9508 url: "' . $url . '",
9509 dataType: \'json\',
9510 delay: 250,
9511 data: function (params) {
9512 return {
9513 q: params.term, // search term
9514 page: params.page
9515 }
9516 },
9517 processResults: function (data) {
9518 // parse the results into the format expected by Select2.
9519 // since we are using custom formatting functions we do not need to alter the remote JSON data
9520 //console.log(data);
9521 saveRemoteData = data;
9522 /* format json result for select2 */
9523 result = []
9524 $.each( data, function( key, value ) {
9525 result.push({id: key, text: value.text});
9526 });
9527 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
9528 //console.log(result);
9529 return {results: result, more: false}
9530 },
9531 cache: true
9532 },
9533 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9534 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9535 placeholder: \'' . dol_escape_js($placeholder) . '\',
9536 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9537 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9538 formatResult: function (result, container, query, escapeMarkup) {
9539 return escapeMarkup(result.text);
9540 },
9541 });
9542
9543 ' . ($callurlonselect ? '
9544 /* Code to execute a GET when we select a value */
9545 $(".' . $htmlname . '").change(function() {
9546 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9547 console.log("We select in selectArrayAjax the entry "+selected)
9548 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9549 $.each( saveRemoteData, function( key, value ) {
9550 if (key == selected)
9551 {
9552 console.log("selectArrayAjax - Do a redirect to "+value.url)
9553 location.assign(value.url);
9554 }
9555 });
9556 });' : '') . '
9557
9558 });
9559 </script>';
9560 }
9561
9562 if ($acceptdelayedhtml) {
9563 $delayedhtmlcontent .= $outdelayed;
9564 } else {
9565 $out .= $outdelayed;
9566 }
9567 return $out;
9568 }
9569
9589 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
9590 {
9591 global $conf;
9592 global $delayedhtmlcontent; // Will be used later outside of this function
9593
9594 // TODO Use an internal dolibarr component instead of select2
9595 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9596 return '';
9597 }
9598
9599 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
9600
9601 $formattedarrayresult = array();
9602
9603 foreach ($array as $key => $value) {
9604 $o = new stdClass();
9605 $o->id = $key;
9606 $o->text = $value['text'];
9607 $o->url = $value['url'];
9608 $formattedarrayresult[] = $o;
9609 }
9610
9611 $outdelayed = '';
9612 if (!empty($conf->use_javascript_ajax)) {
9613 $tmpplugin = 'select2';
9614 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9615 <script nonce="' . getNonce() . '">
9616 $(document).ready(function () {
9617 var data = ' . json_encode($formattedarrayresult) . ';
9618
9619 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
9620
9621 $(\'.' . dol_escape_js($htmlname) . '\').select2({
9622 data: data,
9623 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9624 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9625 placeholder: \'' . dol_escape_js($placeholder) . '\',
9626 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9627 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9628 formatResult: function (result, container, query, escapeMarkup) {
9629 return escapeMarkup(result.text);
9630 },
9631 matcher: function (params, data) {
9632
9633 if(! data.id) return null;';
9634
9635 if ($callurlonselect) {
9636 // We forge the url with 'sall='
9637 $outdelayed .= '
9638
9639 var urlBase = data.url;
9640 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
9641 /* console.log("params.term="+params.term); */
9642 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
9643 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
9644 }
9645
9646 if (!$disableFiltering) {
9647 $outdelayed .= '
9648
9649 if(data.text.match(new RegExp(params.term))) {
9650 return data;
9651 }
9652
9653 return null;';
9654 } else {
9655 $outdelayed .= '
9656
9657 return data;';
9658 }
9659
9660 $outdelayed .= '
9661 }
9662 });
9663
9664 ' . ($callurlonselect ? '
9665 /* Code to execute a GET when we select a value */
9666 $(\'.' . dol_escape_js($htmlname) . '\').change(function() {
9667 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9668 console.log("We select "+selected)
9669
9670 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9671 $.each( saveRemoteData, function( key, value ) {
9672 if (key == selected)
9673 {
9674 console.log("selectArrayFilter - Do a redirect to "+value.url)
9675 location.assign(value.url);
9676 }
9677 });
9678 });' : '') . '
9679
9680 });
9681 </script>';
9682 }
9683
9684 if ($acceptdelayedhtml) {
9685 $delayedhtmlcontent .= $outdelayed;
9686 } else {
9687 $out .= $outdelayed;
9688 }
9689 return $out;
9690 }
9691
9710 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)
9711 {
9712 global $conf, $langs;
9713 $out = '';
9714
9715 if ($addjscombo < 0) {
9716 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9717 $addjscombo = 1;
9718 } else {
9719 $addjscombo = 0;
9720 }
9721 }
9722
9723 $useenhancedmultiselect = 0;
9724 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9725 if ($addjscombo) {
9726 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9727 }
9728 }
9729
9730 $out .= '<span class="multiselectarray'.$htmlname.'">';
9731
9732 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9733 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9734 // submitted to nothing.
9735 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9736 // Output select component
9737 $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";
9738 if (is_array($array) && !empty($array)) {
9739 if ($value_as_key) {
9740 $array = array_combine($array, $array);
9741 }
9742
9743 if (!empty($array)) {
9744 foreach ($array as $key => $value) {
9745 $tmpkey = $key;
9746 $tmpvalue = $value;
9747 $tmpcolor = '';
9748 $tmppicto = '';
9749 $tmplabelhtml = '';
9750 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9751 $tmpkey = $value['id'];
9752 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9753 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9754 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9755 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']) : $value['labelhtml'];
9756 }
9757 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9758 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9759
9760 $out .= '<option value="' . $tmpkey . '"';
9761 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9762 $out .= ' selected';
9763 }
9764 if (!empty($tmplabelhtml)) {
9765 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9766 } else {
9767 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9768 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9769 }
9770 $out .= '>';
9771 $out .= dol_htmlentitiesbr($newval);
9772 $out .= '</option>' . "\n";
9773 }
9774 }
9775 }
9776 $out .= '</select>' . "\n";
9777
9778 $out .= '</span>';
9779
9780 // Add code for jquery to use multiselect
9781 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9782 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9783 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9784 if ($addjscombo == 1) {
9785 $tmpplugin = getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT', (defined('REQUIRE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : 'select2'));
9786
9787 // If property data-html set, we decode html entities and use this.
9788 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9789 // TODO Move this into common js ?
9790 $out .= 'function formatResult(record, container) {' . "\n";
9791 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9792 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9793 $out .= ' }'."\n";
9794 $out .= ' return record.text;';
9795 $out .= '}' . "\n";
9796
9797 $out .= 'function formatSelection(record) {' . "\n";
9798 $out .= ' return record.text;';
9799 $out .= '}' . "\n";
9800
9801 // Load the select2 enhancer
9802 //$out .= 'console.log(\'addjscombo=1 for htmlname=' . dol_escape_js($htmlname) . '\');';
9803 $out .= '$(document).ready(function () {
9804 $(\'#' . dol_escape_js($htmlname) . '\').' . $tmpplugin . '({';
9805 if ($placeholder) {
9806 $out .= '
9807 placeholder: {
9808 id: \'-1\',
9809 text: \''.dol_escape_js($placeholder).'\'
9810 },';
9811 }
9812 $out .= ' dir: \'ltr\',
9813 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9814 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. */
9815 // Specify format function for dropdown item
9816 formatResult: formatResult,
9817 templateResult: formatResult, /* For 4.0 */
9818 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9819 // Specify format function for selected item
9820 formatSelection: formatSelection,
9821 templateSelection: formatSelection, /* For 4.0 */
9822 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage
9823 });
9824
9825 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are shown dynamically after load, because select2 set
9826 the size only if component is not hidden by default on load */
9827 $(\'#' . dol_escape_js($htmlname) . ' + .select2\').addClass(\'' . dol_escape_js($morecss) . '\');
9828 });' . "\n";
9829 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9830 // Add other js lib
9831 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9832 // ...
9833 $out .= 'console.log(\'addjscombo=2 for htmlname=' . dol_escape_js($htmlname) . '\');';
9834 $out .= '$(document).ready(function () {
9835 $(\'#' . dol_escape_js($htmlname) . '\').multiSelect({
9836 containerHTML: \'<div class="multi-select-container">\',
9837 menuHTML: \'<div class="multi-select-menu">\',
9838 buttonHTML: \'<span class="multi-select-button ' . dol_escape_js($morecss) . '">\',
9839 menuItemHTML: \'<label class="multi-select-menuitem">\',
9840 activeClass: \'multi-select-container--open\',
9841 noneText: \'' . dol_escape_js($placeholder) . '\'
9842 });
9843 })';
9844 }
9845 $out .= '</script>';
9846 }
9847
9848 return $out;
9849 }
9850
9851
9863 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9864 {
9865 global $conf, $langs, $user;
9866
9867 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9868 return '';
9869 }
9870 if (empty($array)) {
9871 return '';
9872 }
9873
9874 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9875
9876 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9877 $tmparray = explode(',', $user->conf->$tmpvar);
9878 foreach ($array as $key => $val) {
9879 //var_dump($key);
9880 //var_dump($tmparray);
9881 if (in_array($key, $tmparray)) {
9882 $array[$key]['checked'] = 1;
9883 } else {
9884 $array[$key]['checked'] = 0;
9885 }
9886 }
9887 } else { // There is no list of fields already customized for user
9888 foreach ($array as $key => $val) {
9889 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9890 $array[$key]['checked'] = 0;
9891 }
9892 }
9893 }
9894
9895 $listoffieldsforselection = '';
9896 $listcheckedstring = '';
9897
9898 foreach ($array as $key => $val) {
9899 // var_dump($val);
9900 // var_dump(array_key_exists('enabled', $val));
9901 // var_dump(!$val['enabled']);
9902 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9903 unset($array[$key]); // We don't want this field
9904 continue;
9905 }
9906 if (!empty($val['type']) && $val['type'] == 'separate') {
9907 // Field remains in array but we don't add it into $listoffieldsforselection
9908 //$listoffieldsforselection .= '<li>-----</li>';
9909 continue;
9910 }
9911 if (!empty($val['label']) && $val['label']) {
9912 if (!empty($val['langfile']) && is_object($langs)) {
9913 $langs->load($val['langfile']);
9914 }
9915
9916 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9917 $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']).'" />';
9918 $listoffieldsforselection .= '<label for="checkbox' . $key . '" class="paddingleft">';
9919 $listoffieldsforselection .= dolPrintHTML(dol_string_nohtmltag($langs->trans($val['label'])));
9920 $listoffieldsforselection .= '</label></li>';
9921 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9922 }
9923 }
9924
9925 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9926
9927 <dl class="dropdown">
9928 <dt>
9929 <a href="#' . $htmlname . '">
9930 ' . img_picto('', 'list') . '
9931 </a>
9932 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9933 </dt>
9934 <dd class="dropdowndd">
9935 <div class="multiselectcheckbox'.$htmlname.'">
9936 <ul class="'.$htmlname.(((string) $pos == '1' || (string) $pos == 'left') ? 'left' : '').'">
9937 <li class="liinputsearch">
9938 <input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'">
9939 </li>
9940 '.$listoffieldsforselection.'
9941 </ul>
9942 </div>
9943 </dd>
9944 </dl>
9945
9946 <script nonce="' . getNonce() . '" type="text/javascript">
9947 jQuery(document).ready(function () {
9948 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on("click", function () {
9949 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9950
9951 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9952
9953 var title = $(this).val() + ",";
9954 if ($(this).is(\':checked\')) {
9955 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9956 }
9957 else {
9958 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9959 }
9960 // Now, we submit page
9961 //$(this).parents(\'form:first\').submit();
9962 });
9963
9964 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9965 console.log("keyup on inputsearch_dropdownselectedfields");
9966 var value = $(this).val().toLowerCase();
9967 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9968 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9969 });
9970 });
9971 ';
9972 if (empty($conf->browser->layout) || $conf->browser->layout != 'phone') {
9973 $out .= '
9974 $(".dropdown dt a").on("click", function () {
9975 console.log("Click on dropdown, we set focus to search field");
9976 setTimeout(() => { $(\'.inputsearch_dropdownselectedfields\').focus(); }, 200);
9977 });';
9978 }
9979 $out .= '
9980 });
9981 </script>
9982
9983 ';
9984 return $out;
9985 }
9986
9996 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
9997 {
9998 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
9999
10000 $cat = new Categorie($this->db);
10001 $categories = $cat->containing($id, $type);
10002
10003 if ($rendermode == 1) {
10004 $toprint = array();
10005 foreach ($categories as $c) {
10006 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
10007 foreach ($ways as $way) {
10008 $color = $c->color;
10009 $sfortag = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($color ? ' style="background: #' . $color . ';"' : ' style="background: #bbb"') . '>';
10010 $sfortag .= $way;
10011 $sfortag .= '</li>';
10012 $toprint[] = $sfortag;
10013 }
10014 }
10015 if (empty($toprint)) {
10016 return '';
10017 } else {
10018 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
10019 }
10020 }
10021
10022 if ($rendermode == 0) {
10023 $arrayselected = array();
10024 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
10025 foreach ($categories as $c) {
10026 $arrayselected[(string) $c->id] = (string) $c->id;
10027 }
10028
10029 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
10030 }
10031
10032 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
10033 }
10034
10044 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
10045 {
10046 global $conf, $langs, $hookmanager;
10047 global $action;
10048
10049 $object->fetchObjectLinked();
10050
10051 // Bypass the default method
10052 $hookmanager->initHooks(array('commonobject'));
10053 $parameters = array(
10054 'morehtmlright' => $morehtmlright,
10055 'compatibleImportElementsList' => &$compatibleImportElementsList,
10056 );
10057 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
10058
10059 $nbofdifferenttypes = count($object->linkedObjects);
10060
10061 if (empty($reshook)) {
10062 print '<!-- showLinkedObjectBlock -->';
10063 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, '', 'showlinkedobjectblock');
10064
10065
10066 print '<div class="div-table-responsive-no-min">';
10067 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
10068
10069 print '<tr class="liste_titre">';
10070 print '<td>' . $langs->trans("Type") . '</td>';
10071 print '<td>' . $langs->trans("Ref") . '</td>';
10072 print '<td class="center"></td>';
10073 print '<td class="center">' . $langs->trans("Date") . '</td>';
10074 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
10075 print '<td class="right">' . $langs->trans("Status") . '</td>';
10076 print '<td></td>';
10077 print '</tr>';
10078
10079 $nboftypesoutput = 0;
10080
10081 foreach ($object->linkedObjects as $objecttype => $objects) {
10082 $tplpath = $element = $subelement = $objecttype;
10083
10084 // to display import button on tpl
10085 $showImportButton = false;
10086 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
10087 $showImportButton = true;
10088 }
10089
10090 $regs = array();
10091
10092 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
10093 $element = $regs[1];
10094 $subelement = $regs[2];
10095 $tplpath = $element . '/' . $subelement;
10096 }
10097 $tplname = 'linkedobjectblock';
10098
10099 // If we ask a resource form external module (instead of default path)
10100 if (preg_match('/^([^@]+)@([^@]+)$/i', $objecttype, $regs)) { // 'myobject@mymodule'
10101 $element = $regs[1];
10102 $module = $regs[2];
10103 $tplpath = $module. '/' . $element;
10104 $tplname = $tplname.'_'.$element;
10105 }
10106
10107 // To work with non standard path
10108 if ($objecttype == 'facture') {
10109 $tplpath = 'compta/' . $element;
10110 if (!isModEnabled('invoice')) {
10111 continue; // Do not show if module disabled
10112 }
10113 } elseif ($objecttype == 'facturerec') {
10114 $tplpath = 'compta/facture';
10115 $tplname = 'linkedobjectblockForRec';
10116 if (!isModEnabled('invoice')) {
10117 continue; // Do not show if module disabled
10118 }
10119 } elseif ($objecttype == 'propal') {
10120 $tplpath = 'comm/' . $element;
10121 if (!isModEnabled('propal')) {
10122 continue; // Do not show if module disabled
10123 }
10124 } elseif ($objecttype == 'supplier_proposal') {
10125 if (!isModEnabled('supplier_proposal')) {
10126 continue; // Do not show if module disabled
10127 }
10128 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
10129 $tplpath = 'expedition';
10130 if (!isModEnabled('shipping')) {
10131 continue; // Do not show if module disabled
10132 }
10133 } elseif ($objecttype == 'reception') {
10134 $tplpath = 'reception';
10135 if (!isModEnabled('reception')) {
10136 continue; // Do not show if module disabled
10137 }
10138 } elseif ($objecttype == 'delivery') {
10139 $tplpath = 'delivery';
10140 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
10141 continue; // Do not show if sub module disabled
10142 }
10143 } elseif ($objecttype == 'ficheinter') {
10144 $tplpath = 'fichinter';
10145 if (!isModEnabled('intervention')) {
10146 continue; // Do not show if module disabled
10147 }
10148 } elseif ($objecttype == 'invoice_supplier') {
10149 $tplpath = 'fourn/facture';
10150 } elseif ($objecttype == 'order_supplier') {
10151 $tplpath = 'fourn/commande';
10152 } elseif ($objecttype == 'expensereport') {
10153 $tplpath = 'expensereport';
10154 } elseif ($objecttype == 'subscription') {
10155 $tplpath = 'adherents';
10156 } elseif ($objecttype == 'conferenceorbooth') {
10157 $tplpath = 'eventorganization';
10158 } elseif ($objecttype == 'conferenceorboothattendee') {
10159 $tplpath = 'eventorganization';
10160 } elseif ($objecttype == 'mo') {
10161 $tplpath = 'mrp';
10162 if (!isModEnabled('mrp')) {
10163 continue; // Do not show if module disabled
10164 }
10165 } elseif ($objecttype == 'project_task') {
10166 $tplpath = 'projet/tasks';
10167 }
10168
10169 global $linkedObjectBlock;
10170 $linkedObjectBlock = $objects;
10171
10172 // Output template part (modules that overwrite templates must declare this into descriptor)
10173 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
10174
10175 foreach ($dirtpls as $reldir) {
10176 $reldir = rtrim($reldir, '/');
10177 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
10178 global $noMoreLinkedObjectBlockAfter;
10179 $noMoreLinkedObjectBlockAfter = 1;
10180 }
10181
10182 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
10183 if ($res) {
10184 $nboftypesoutput++;
10185 break;
10186 }
10187 }
10188 }
10189
10190 if (!$nboftypesoutput) {
10191 print '<tr><td colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
10192 }
10193
10194 print '</table>';
10195
10196 if (!empty($compatibleImportElementsList)) {
10197 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
10198 }
10199
10200 print '</div>';
10201 }
10202
10203 return $nbofdifferenttypes;
10204 }
10205
10215 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array(), $nooutput = 0)
10216 {
10217 global $conf, $langs, $hookmanager, $form;
10218 global $action;
10219
10220 if (empty($form)) {
10221 $form = new Form($this->db);
10222 }
10223
10224 $linktoelem = '';
10225 $linktoelemlist = '';
10226 $listofidcompanytoscan = '';
10227
10228 if (!is_object($object->thirdparty)) {
10229 $object->fetch_thirdparty();
10230 }
10231
10232 $possiblelinks = array();
10233
10234 $dontIncludeCompletedItems = getDolGlobalString('DONT_INCLUDE_COMPLETED_ELEMENTS_LINKS');
10235
10236 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
10237 $listofidcompanytoscan = (int) $object->thirdparty->id;
10238 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
10239 $listofidcompanytoscan .= ',' . (int) $object->thirdparty->parent;
10240 }
10241 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
10242 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10243 $tmpproject = new Project($this->db);
10244 $tmpproject->fetch($object->fk_project);
10245 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
10246 $listofidcompanytoscan .= ',' . (int) $tmpproject->socid;
10247 }
10248 unset($tmpproject);
10249 }
10250
10251 $possiblelinks = array(
10252 'propal' => array(
10253 'enabled' => isModEnabled('propal'),
10254 'perms' => 1,
10255 'label' => 'LinkToProposal',
10256 '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' : ''),
10257 ),
10258 'shipping' => array(
10259 'enabled' => isModEnabled('shipping'),
10260 'perms' => 1,
10261 'label' => 'LinkToExpedition',
10262 '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' : ''),
10263 ),
10264 'order' => array(
10265 'enabled' => isModEnabled('order'),
10266 'perms' => 1,
10267 'label' => 'LinkToOrder',
10268 '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' : ''),
10269 'linkname' => 'commande',
10270 'subscription' => array(
10271 'enabled' => isModEnabled('member'),
10272 'perms' => 1,
10273 'label' => 'LinkToMemberSubscription',
10274 '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') . ')',
10275 'linkname' => 'subscription'),
10276 ),
10277 'invoice' => array(
10278 'enabled' => isModEnabled('invoice'),
10279 'perms' => 1,
10280 'label' => 'LinkToInvoice',
10281 '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' : ''),
10282 'linkname' => 'facture',
10283 ),
10284 'invoice_template' => array(
10285 'enabled' => isModEnabled('invoice'),
10286 'perms' => 1,
10287 'label' => 'LinkToTemplateInvoice',
10288 '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') . ')',
10289 ),
10290 'contrat' => array(
10291 'enabled' => isModEnabled('contract'),
10292 'perms' => 1,
10293 'label' => 'LinkToContract',
10294 '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
10295 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',
10296 ),
10297 'fichinter' => array(
10298 'enabled' => isModEnabled('intervention'),
10299 'perms' => 1,
10300 'label' => 'LinkToIntervention',
10301 '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') . ')',
10302 ),
10303 'supplier_proposal' => array(
10304 'enabled' => isModEnabled('supplier_proposal'),
10305 'perms' => 1,
10306 'label' => 'LinkToSupplierProposal',
10307 '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' : ''),
10308 ),
10309 'order_supplier' => array(
10310 'enabled' => isModEnabled("supplier_order"),
10311 'perms' => 1,
10312 'label' => 'LinkToSupplierOrder',
10313 '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' : ''),
10314 ),
10315 'invoice_supplier' => array(
10316 'enabled' => isModEnabled("supplier_invoice"),
10317 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
10318 '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' : ''),
10319 ),
10320 'ticket' => array(
10321 'enabled' => isModEnabled('ticket'),
10322 'perms' => 1,
10323 'label' => 'LinkToTicket',
10324 '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' : ''),
10325 ),
10326 'mo' => array(
10327 'enabled' => isModEnabled('mrp'),
10328 'perms' => 1,
10329 'label' => 'LinkToMo',
10330 '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' : ''),
10331 ),
10332 );
10333 }
10334
10335 if ($object->table_element == 'commande_fournisseur') {
10336 $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' : '');
10337 } elseif ($object->table_element == 'mrp_mo') {
10338 $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' : '');
10339 }
10340
10341 $reshook = 0; // Ensure $reshook is defined for static analysis
10342 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
10343 // Can complete the possiblelink array
10344 $hookmanager->initHooks(array('commonobject'));
10345 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
10346 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
10347 }
10348
10349 if (empty($reshook)) {
10350 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
10351 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
10352 }
10353 } elseif ($reshook > 0) {
10354 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
10355 $possiblelinks = $hookmanager->resArray;
10356 }
10357 }
10358
10359 if (!empty($possiblelinks)) {
10360 $object->fetchObjectLinked();
10361 }
10362
10363 // Build the html part with possible suggested links
10364 $htmltoenteralink = '';
10365 foreach ($possiblelinks as $key => $possiblelink) {
10366 $num = 0;
10367 if (empty($possiblelink['enabled'])) {
10368 continue;
10369 }
10370
10371
10372 // If we ask a resource form external module (instead of default path)
10373 $module='';
10374 if (preg_match('/^([^@]+)@([^@]+)$/i', $key, $regs)) { // 'myobject@mymodule'
10375 $key = $regs[1];
10376 $module=$regs[2];
10377 }
10378
10379 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
10380 $htmltoenteralink .= '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
10381
10382 // Section for free ref input
10383 if (!getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10384 $htmltoenteralink .= '<br>'."\n";
10385 $htmltoenteralink .= '<!-- form to add a link from anywhere -->'."\n";
10386 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
10387 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
10388 $htmltoenteralink .= '<input type="hidden" name="action" value="addlinkbyref">';
10389 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
10390 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key .(!empty($module)?'@'.$module:''). '">';
10391 $htmltoenteralink .= '<table class="noborder">';
10392 $htmltoenteralink .= '<tr class="liste_titre">';
10393 //print '<td>' . $langs->trans("Ref") . '</td>';
10394 $htmltoenteralink .= '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
10395 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
10396 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
10397 $htmltoenteralink .= '</tr>';
10398 $htmltoenteralink .= '</table>';
10399 $htmltoenteralink .= '</form>';
10400 }
10401
10402 $sql = $possiblelink['sql'];
10403
10404 $resqllist = $this->db->query($sql);
10405 if ($resqllist) {
10406 $num = $this->db->num_rows($resqllist);
10407 $i = 0;
10408
10409 if ($num > 0) {
10410 // Section for free predefined list
10411 if (getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10412 $htmltoenteralink .= '<br>';
10413 }
10414 $htmltoenteralink .= '<!-- form to add a link from object to same thirdparty -->'."\n";
10415 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
10416 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
10417 $htmltoenteralink .= '<input type="hidden" name="action" value="addlink">';
10418 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
10419 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . (!empty($module)?'@'.$module:''). '">';
10420 $htmltoenteralink .= '<table class="noborder">';
10421 $htmltoenteralink .= '<tr class="liste_titre">';
10422 $htmltoenteralink .= '<td class="nowrap"></td>';
10423 $htmltoenteralink .= '<td>' . $langs->trans("Ref") . '</td>';
10424 $htmltoenteralink .= '<td>' . $langs->trans("RefCustomer") . '</td>';
10425 $htmltoenteralink .= '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
10426 $htmltoenteralink .= '<td>' . $langs->trans("Company") . '</td>';
10427 $htmltoenteralink .= '</tr>';
10428 while ($i < $num) {
10429 $objp = $this->db->fetch_object($resqllist);
10430 $alreadylinked = false;
10431 if (!empty($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key])) {
10432 if (in_array($objp->rowid, array_values($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key]))) {
10433 $alreadylinked = true;
10434 }
10435 }
10436 $htmltoenteralink .= '<tr class="oddeven">';
10437 $htmltoenteralink .= '<td>';
10438 if ($alreadylinked) {
10439 $htmltoenteralink .= img_picto('', 'link');
10440 } else {
10441 $htmltoenteralink .= '<input type="checkbox" name="idtolinkto[' . $key . '_' . $objp->rowid . ']" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
10442 }
10443 $htmltoenteralink .= '</td>';
10444 $htmltoenteralink .= '<td><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
10445 $htmltoenteralink .= '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
10446 $htmltoenteralink .= '<td class="right">';
10447 if ($possiblelink['label'] == 'LinkToContract') {
10448 $htmltoenteralink .= $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
10449 }
10450 $htmltoenteralink .= '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
10451 $htmltoenteralink .= '</td>';
10452 $htmltoenteralink .= '<td>' . $objp->name . '</td>';
10453 $htmltoenteralink .= '</tr>';
10454 $i++;
10455 }
10456 $htmltoenteralink .= '</table>';
10457 $htmltoenteralink .= '<div class="center">';
10458 if ($num) {
10459 $htmltoenteralink .= '<input type="submit" class="button valignmiddle marginleftonly marginrightonly smallpaddingimp" value="' . $langs->trans('ToLink') . '">';
10460 }
10461 if (empty($conf->use_javascript_ajax)) {
10462 $htmltoenteralink .= '<input type="submit" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
10463 } else {
10464 $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>';
10465 }
10466 $htmltoenteralink .= '</form>';
10467 }
10468
10469 $this->db->free($resqllist);
10470 } else {
10471 dol_print_error($this->db);
10472 }
10473 $htmltoenteralink .= '</div>';
10474
10475
10476 // Complete the list for the combo box
10477 if ($num > 0 || !getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10478 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
10479 // } else $linktoelem.=$langs->trans($possiblelink['label']);
10480 } else {
10481 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
10482 }
10483 }
10484 }
10485
10486 if ($linktoelemlist) {
10487 $linktoelem = '
10488 <dl class="dropdown" id="linktoobjectname">
10489 ';
10490 if (!empty($conf->use_javascript_ajax)) {
10491 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
10492 }
10493 $linktoelem .= '<dd>
10494 <div class="multiselectlinkto">
10495 <ul class="ulselectedfields">' . $linktoelemlist . '
10496 </ul>
10497 </div>
10498 </dd>
10499 </dl>';
10500 } else {
10501 $linktoelem = '';
10502 }
10503
10504 if (!empty($conf->use_javascript_ajax)) {
10505 print '<!-- Add js to show linkto box -->
10506 <script nonce="' . getNonce() . '">
10507 jQuery(document).ready(function() {
10508 jQuery(".linkto").click(function() {
10509 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
10510 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
10511 });
10512 });
10513 </script>
10514 ';
10515 }
10516
10517 if ($nooutput) {
10518 return array('linktoelem' => $linktoelem, 'htmltoenteralink' => $htmltoenteralink);
10519 } else {
10520 print $htmltoenteralink;
10521 }
10522
10523 return $linktoelem;
10524 }
10525
10540 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'width75', $labelyes = 'Yes', $labelno = 'No')
10541 {
10542 global $langs;
10543
10544 $yes = "yes";
10545 $no = "no";
10546 if ($option) {
10547 $yes = "1";
10548 $no = "0";
10549 }
10550
10551 $disabled = ($disabled ? ' disabled' : '');
10552
10553 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
10554 if ($useempty) {
10555 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10556 }
10557 if (("$value" == 'yes') || ($value == 1)) {
10558 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
10559 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
10560 } else {
10561 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
10562 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
10563 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
10564 }
10565 $resultyesno .= '</select>' . "\n";
10566
10567 if ($addjscombo) {
10568 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
10569 }
10570
10571 return $resultyesno;
10572 }
10573
10574 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10575
10585 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
10586 {
10587 // phpcs:enable
10588 $sql = "SELECT rowid, label";
10589 $sql .= " FROM " . $this->db->prefix() . "export_model";
10590 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
10591 $sql .= " ORDER BY rowid";
10592 $result = $this->db->query($sql);
10593 if ($result) {
10594 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
10595 if ($useempty) {
10596 print '<option value="-1">&nbsp;</option>';
10597 }
10598
10599 $num = $this->db->num_rows($result);
10600 $i = 0;
10601 while ($i < $num) {
10602 $obj = $this->db->fetch_object($result);
10603 if ($selected == $obj->rowid) {
10604 print '<option value="' . $obj->rowid . '" selected>';
10605 } else {
10606 print '<option value="' . $obj->rowid . '">';
10607 }
10608 print $obj->label;
10609 print '</option>';
10610 $i++;
10611 }
10612 print "</select>";
10613 } else {
10614 dol_print_error($this->db);
10615 }
10616 }
10617
10636 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
10637 {
10638 global $conf, $langs, $hookmanager, $extralanguages;
10639
10640 $ret = '';
10641 if (empty($fieldid)) {
10642 $fieldid = 'rowid';
10643 }
10644 if (empty($fieldref)) {
10645 $fieldref = 'ref';
10646 }
10647
10648 // Preparing gender's display if there is one
10649 $addgendertxt = '';
10650 if (property_exists($object, 'gender') && !empty($object->gender)) {
10651 $addgendertxt = ' ';
10652 switch ($object->gender) {
10653 case 'man':
10654 $addgendertxt .= '<i class="fas fa-mars valignmiddle"></i>';
10655 break;
10656 case 'woman':
10657 $addgendertxt .= '<i class="fas fa-venus valignmiddle"></i>';
10658 break;
10659 case 'other':
10660 $addgendertxt .= '<i class="fas fa-transgender valignmiddle"></i>';
10661 break;
10662 }
10663 }
10664
10665 // Add where from hooks
10666 if (is_object($hookmanager)) {
10667 $parameters = array('showrefnav' => true);
10668 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
10669 if (!empty($hookmanager->resPrint)) {
10670 if (empty($object->next_prev_filter) && preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10671 $object->next_prev_filter = preg_replace('/^\s*AND\s*/i', '', $hookmanager->resPrint);
10672 } elseif (!empty($object->next_prev_filter) && !preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10673 $object->next_prev_filter .= ' AND '.$hookmanager->resPrint;
10674 } else {
10675 $object->next_prev_filter .= $hookmanager->resPrint;
10676 }
10677 }
10678 }
10679
10680 $previous_ref = $next_ref = '';
10681 if ($shownav) {
10682 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
10683 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
10684
10685 $navurl = $_SERVER["PHP_SELF"];
10686 // Special case for project/task page
10687 if ($paramid == 'project_ref') {
10688 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
10689 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
10690 $paramid = 'ref';
10691 }
10692 }
10693
10694 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
10695 // accesskey is for Mac: CTRL + key for all browsers
10696 $stringforfirstkey = $langs->trans("KeyboardShortcut");
10697 if ($conf->browser->name == 'chrome') {
10698 $stringforfirstkey .= ' ALT +';
10699 } elseif ($conf->browser->name == 'firefox') {
10700 $stringforfirstkey .= ' ALT + SHIFT +';
10701 } else {
10702 $stringforfirstkey .= ' CTL +';
10703 }
10704
10705 $previous_ref = $object->ref_previous ? '<a accesskey="p" alt="'.dol_escape_htmltag($langs->trans("Previous")).'" title="' . $stringforfirstkey . ' p" class="classfortooltip" href="' . $navurl . '?' . $paramid . '=' . urlencode($object->ref_previous) . $moreparam . '"><i class="fa fa-chevron-left"></i></a>' : '<span class="inactive"><i class="fa fa-chevron-left opacitymedium"></i></span>';
10706 $next_ref = $object->ref_next ? '<a accesskey="n" alt="'.dol_escape_htmltag($langs->trans("Next")).'" title="' . $stringforfirstkey . ' n" class="classfortooltip" href="' . $navurl . '?' . $paramid . '=' . urlencode($object->ref_next) . $moreparam . '"><i class="fa fa-chevron-right"></i></a>' : '<span class="inactive"><i class="fa fa-chevron-right opacitymedium"></i></span>';
10707 }
10708
10709 //print "xx".$previous_ref."x".$next_ref;
10710 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
10711
10712 // Right part of banner
10713 if ($morehtmlright) {
10714 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
10715 }
10716
10717 if ($previous_ref || $next_ref || $morehtml) {
10718 $ret .= '<div class="pagination paginationref"><ul class="right">';
10719 }
10720 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
10721 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
10722 }
10723 if ($shownav && ($previous_ref || $next_ref)) {
10724 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
10725 $ret .= '<li class="pagination">' . $next_ref . '</li>';
10726 }
10727 if ($previous_ref || $next_ref || $morehtml) {
10728 $ret .= '</ul></div>';
10729 }
10730
10731 // Status
10732 $parameters = array('morehtmlstatus' => $morehtmlstatus);
10733 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
10734 if (empty($reshook)) {
10735 $morehtmlstatus .= $hookmanager->resPrint;
10736 } else {
10737 $morehtmlstatus = $hookmanager->resPrint;
10738 }
10739 if ($morehtmlstatus) {
10740 $ret .= '<!-- status --><div class="statusref">' . $morehtmlstatus . '</div>';
10741 }
10742
10743 $parameters = array();
10744 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
10745 if (empty($reshook)) {
10746 $morehtmlref .= $hookmanager->resPrint;
10747 } elseif ($reshook > 0) {
10748 $morehtmlref = $hookmanager->resPrint;
10749 }
10750
10751 // Left part of banner
10752 if ($morehtmlleft) {
10753 if ($conf->browser->layout == 'phone') {
10754 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
10755 } else {
10756 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
10757 }
10758 }
10759
10760 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
10761 $ret .= '<!-- Ref or ID --><div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
10762
10763 // For thirdparty, contact, user, member, the ref is the id, so we show something else
10764 if ($object->element == 'societe') {
10765 $ret .= dol_htmlentities((string) $object->name);
10766
10767 // List of extra languages
10768 $arrayoflangcode = array();
10769 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
10770 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
10771 }
10772
10773 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
10774 if (!is_object($extralanguages)) {
10775 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
10776 $extralanguages = new ExtraLanguages($this->db);
10777 }
10778 $extralanguages->fetch_name_extralanguages('societe');
10779
10780 if (!empty($extralanguages->attributes['societe']['name'])) {
10781 $object->fetchValuesForExtraLanguages();
10782
10783 $htmltext = '';
10784 // If there is extra languages
10785 foreach ($arrayoflangcode as $extralangcode) {
10786 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
10787 if ($object->array_languages['name'][$extralangcode]) {
10788 $htmltext .= $object->array_languages['name'][$extralangcode];
10789 } else {
10790 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
10791 }
10792 }
10793 $ret .= '<!-- Show translations of name -->' . "\n";
10794 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
10795 }
10796 }
10797 } elseif ($object->element == 'member') {
10798 '@phan-var-force Adherent $object';
10799 $ret .= $object->ref . '<br>';
10800 $fullname = $object->getFullName($langs);
10801 if ($object->morphy == 'mor' && $object->societe) {
10802 $ret .= dol_htmlentities((string) $object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
10803 } else {
10804 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities((string) $object->societe) . ')' : '');
10805 }
10806 } elseif (in_array($object->element, array('contact', 'user'))) {
10807 $ret .= '<span class="valignmiddle">'.dol_htmlentities($object->getFullName($langs)).'</span>'.$addgendertxt;
10808 } elseif ($object->element == 'usergroup') {
10809 $ret .= dol_htmlentities((string) $object->name);
10810 } elseif (in_array($object->element, array('action', 'agenda'))) {
10811 '@phan-var-force ActionComm $object';
10812 $ret .= $object->ref . '<br>' . $object->label;
10813 } elseif (in_array($object->element, array('adherent_type'))) {
10814 $ret .= $object->label;
10815 } elseif ($object->element == 'ecm_directories') {
10816 $ret .= '';
10817 } elseif ($object->element == 'accountingbookkeeping' && !empty($object->context['mode']) && $object->context['mode'] == '_tmp') {
10818 $ret .= $langs->trans("Draft");
10819 } elseif ($fieldref != 'none') {
10820 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
10821 }
10822 if ($morehtmlref) {
10823 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
10824 if (substr($morehtmlref, 0, 4) != '<div') {
10825 $ret .= ' ';
10826 }
10827
10828 $ret .= '<!-- morehtmlref -->'.$morehtmlref;
10829 }
10830
10831 $ret .= '</div>';
10832
10833 $ret .= '</div><!-- End banner content -->';
10834
10835 return $ret;
10836 }
10837
10838
10847 public function showbarcode(&$object, $width = 100, $morecss = '')
10848 {
10849 global $conf;
10850
10851 //Check if barcode is filled in the card
10852 if (empty($object->barcode)) {
10853 return '';
10854 }
10855
10856 // Complete object if not complete
10857 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10858 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10859 $result = $object->fetchBarCode();
10860 //Check if fetchBarCode() failed
10861 if ($result < 1) {
10862 return '<!-- ErrorFetchBarcode -->';
10863 }
10864 }
10865
10866 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10867 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10868 $out = '<!-- url barcode = ' . $url . ' -->';
10869 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10870
10871 return $out;
10872 }
10873
10891 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10892 {
10893 global $conf, $langs;
10894
10895 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10896 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10897
10898 $dir = '';
10899 $file = '';
10900 $originalfile = '';
10901 $altfile = '';
10902 $email = '';
10903 $capture = '';
10904 if ($modulepart == 'societe') {
10905 $dir = $conf->societe->multidir_output[$entity];
10906 if (!empty($object->logo)) {
10907 if (dolIsAllowedForPreview($object->logo)) {
10908 if ((string) $imagesize == 'mini') {
10909 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10910 } elseif ((string) $imagesize == 'small') {
10911 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10912 } else {
10913 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10914 }
10915 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10916 }
10917 }
10918 $email = $object->email;
10919 } elseif ($modulepart == 'contact') {
10920 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10921 if (!empty($object->photo)) {
10922 if (dolIsAllowedForPreview($object->photo)) {
10923 if ((string) $imagesize == 'mini') {
10924 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10925 } elseif ((string) $imagesize == 'small') {
10926 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10927 } else {
10928 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10929 }
10930 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10931 }
10932 }
10933 $email = $object->email;
10934 $capture = 'user';
10935 } elseif ($modulepart == 'userphoto') {
10936 $dir = $conf->user->dir_output;
10937 if (!empty($object->photo)) {
10938 if (dolIsAllowedForPreview($object->photo)) {
10939 if ((string) $imagesize == 'mini') {
10940 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10941 } elseif ((string) $imagesize == 'small') {
10942 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10943 } else {
10944 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10945 }
10946 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10947 }
10948 }
10949 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10950 $altfile = $object->id . ".jpg"; // For backward compatibility
10951 }
10952 $email = $object->email;
10953 $capture = 'user';
10954 } elseif ($modulepart == 'memberphoto') {
10955 $dir = $conf->adherent->dir_output;
10956 if (!empty($object->photo)) {
10957 if (dolIsAllowedForPreview($object->photo)) {
10958 if ((string) $imagesize == 'mini') {
10959 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10960 } elseif ((string) $imagesize == 'small') {
10961 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10962 } else {
10963 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10964 }
10965 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10966 }
10967 }
10968 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10969 $altfile = $object->id . ".jpg"; // For backward compatibility
10970 }
10971 $email = $object->email;
10972 $capture = 'user';
10973 } else {
10974 // Generic case to show photos
10975 // TODO Implement this method in previous objects so we can always use this generic method.
10976 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10977 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10978
10979 $dir = $tmpdata['dir'];
10980 $file = $tmpdata['file'];
10981 $originalfile = $tmpdata['originalfile'];
10982 $altfile = $tmpdata['altfile'];
10983 $email = $tmpdata['email'];
10984 $capture = $tmpdata['capture'];
10985 }
10986 }
10987
10988 if ($forcecapture) {
10989 $capture = $forcecapture;
10990 }
10991
10992 $ret = '';
10993
10994 if ($dir) {
10995 if ($file && file_exists($dir . "/" . $file)) {
10996 if ($addlinktofullsize) {
10997 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10998 if ($urladvanced) {
10999 $ret .= '<a href="' . $urladvanced . '">';
11000 } else {
11001 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
11002 }
11003 }
11004 $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 . '">';
11005 if ($addlinktofullsize) {
11006 $ret .= '</a>';
11007 }
11008 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
11009 if ($addlinktofullsize) {
11010 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
11011 if ($urladvanced) {
11012 $ret .= '<a href="' . $urladvanced . '">';
11013 } else {
11014 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
11015 }
11016 }
11017 $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 . '">';
11018 if ($addlinktofullsize) {
11019 $ret .= '</a>';
11020 }
11021 } else {
11022 $nophoto = '/public/theme/common/nophoto.png';
11023 $defaultimg = 'identicon'; // For gravatar
11024 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
11025 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
11026 $nophoto = 'company';
11027 } else {
11028 $nophoto = '/public/theme/common/user_anonymous.png';
11029 if (!empty($object->gender) && $object->gender == 'man') {
11030 $nophoto = '/public/theme/common/user_man.png';
11031 }
11032 if (!empty($object->gender) && $object->gender == 'woman') {
11033 $nophoto = '/public/theme/common/user_woman.png';
11034 }
11035 }
11036 }
11037
11038 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
11039 // see https://gravatar.com/site/implement/images/php/
11040 $ret .= '<!-- Put link to gravatar -->';
11041 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" title="' . $email . ' Gravatar avatar" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="https://www.gravatar.com/avatar/' . dol_hash(strtolower(trim($email)), 'sha256', 1) . '?s=' . $width . '&d=' . $defaultimg . '">'; // gravatar need md5 hash
11042 } else {
11043 if ($nophoto == 'company') {
11044 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
11045 //$ret .= '<div class="difforspanimgright"></div>';
11046 } else {
11047 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
11048 }
11049 }
11050 }
11051
11052 if ($caneditfield) {
11053 if ($object->photo) {
11054 $ret .= "<br>\n";
11055 }
11056 $ret .= '<table class="nobordernopadding centpercent">';
11057 if ($object->photo) {
11058 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
11059 }
11060 $ret .= '<tr><td class="tdoverflow">';
11061 $maxfilesizearray = getMaxFileSizeArray();
11062 $maxmin = $maxfilesizearray['maxmin'];
11063 if ($maxmin > 0) {
11064 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
11065 }
11066 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . dolPrintHTMLForAttribute($capture) . '"' : '') . '>';
11067 $ret .= '</td></tr>';
11068 $ret .= '</table>';
11069 }
11070 }
11071
11072 return $ret;
11073 }
11074
11075 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11076
11093 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
11094 {
11095 // phpcs:enable
11096 global $conf, $user, $langs;
11097
11098 // Allow excluding groups
11099 $excludeGroups = null;
11100 if (is_array($exclude)) {
11101 $excludeGroups = implode(",", $exclude);
11102 }
11103 // Allow including groups
11104 $includeGroups = null;
11105 if (is_array($include)) {
11106 $includeGroups = implode(",", $include);
11107 }
11108
11109 if (!is_array($selected)) {
11110 $selected = array($selected);
11111 }
11112
11113 $out = '';
11114
11115 // Build sql to search groups
11116 $sql = "SELECT ug.rowid, ug.nom as name";
11117 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
11118 $sql .= ", e.label";
11119 }
11120 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
11121 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
11122 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
11123 if ($force_entity) {
11124 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
11125 } else {
11126 $sql .= " WHERE ug.entity IS NOT NULL";
11127 }
11128 } else {
11129 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
11130 }
11131 if (is_array($exclude) && $excludeGroups) {
11132 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
11133 }
11134 if (is_array($include) && $includeGroups) {
11135 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
11136 }
11137 $sql .= " ORDER BY ug.nom ASC";
11138
11139 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
11140 $resql = $this->db->query($sql);
11141 if ($resql) {
11142 // Enhance with select2
11143 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11144
11145 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
11146
11147 $num = $this->db->num_rows($resql);
11148 $i = 0;
11149 if ($num) {
11150 if ($show_empty && !$multiple) {
11151 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
11152 }
11153
11154 while ($i < $num) {
11155 $obj = $this->db->fetch_object($resql);
11156 $disableline = 0;
11157 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
11158 $disableline = 1;
11159 }
11160
11161 $label = $obj->name;
11162 $labelhtml = $obj->name;
11163 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
11164 $label .= " (" . $obj->label . ")";
11165 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
11166 }
11167
11168 $out .= '<option value="' . $obj->rowid . '"';
11169 if ($disableline) {
11170 $out .= ' disabled';
11171 }
11172 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
11173 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
11174 $out .= ' selected';
11175 }
11176 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
11177 $out .= '>';
11178 $out .= $label;
11179 $out .= '</option>';
11180 $i++;
11181 }
11182 } else {
11183 if ($show_empty) {
11184 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
11185 }
11186 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
11187 }
11188 $out .= '</select>';
11189
11190 $out .= ajax_combobox($htmlname);
11191 } else {
11192 dol_print_error($this->db);
11193 }
11194
11195 return $out;
11196 }
11197
11198
11205 public function showFilterButtons($pos = '')
11206 {
11207 $out = '<div class="nowraponall">';
11208 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
11209 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
11210 $out .= '</div>';
11211
11212 return $out;
11213 }
11214
11223 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
11224 {
11225 global $conf;
11226
11227 $out = '';
11228
11229 if (!empty($conf->use_javascript_ajax)) {
11230 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
11231 }
11232 $out .= '<script nonce="' . getNonce() . '">
11233 $(document).ready(function() {
11234 $("#' . $cssclass . 's").click(function() {
11235 if($(this).is(\':checked\')){
11236 console.log("We check all ' . $cssclass . ' and trigger the change method");
11237 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
11238 }
11239 else
11240 {
11241 console.log("We uncheck all");
11242 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
11243 }' . "\n";
11244 if ($calljsfunction) {
11245 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
11246 }
11247 $out .= ' });
11248 $(".' . $cssclass . '").change(function() {
11249 console.log("We check and change the tr class highlight after a change on .'.$cssclass.'");
11250 var $row = $(this).closest("tr");
11251 if ($row.length) {
11252 var anyChecked = $row.find(\'input[type="checkbox"].checkforselect:checked\').length > 0;
11253 console.log(anyChecked);
11254 if (!anyChecked) {
11255 $row.removeClass("highlight");
11256 } else {
11257 $row.addClass("highlight");
11258 }
11259 }
11260 });
11261 });
11262 </script>';
11263
11264 return $out;
11265 }
11266
11276 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
11277 {
11278 $out = $this->showFilterButtons();
11279 if ($addcheckuncheckall) {
11280 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
11281 }
11282 return $out;
11283 }
11284
11298 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
11299 {
11300 global $langs, $user;
11301
11302 $out = '';
11303 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
11304 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
11305 if (!empty($excludeid)) {
11306 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
11307 }
11308 $sql .= " ORDER BY label";
11309
11310 $resql = $this->db->query($sql);
11311 if ($resql) {
11312 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
11313 if ($useempty) {
11314 $out .= '<option value="0">&nbsp;</option>';
11315 }
11316
11317 while ($obj = $this->db->fetch_object($resql)) {
11318 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
11319 }
11320 $out .= '</select>';
11321 $out .= ajax_combobox('select_' . $htmlname);
11322
11323 if (!empty($htmlname) && $user->admin && $info_admin) {
11324 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11325 }
11326
11327 if (!empty($target)) {
11328 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
11329 $resql = $this->db->query($sql);
11330 if ($resql) {
11331 if ($this->db->num_rows($resql) > 0) {
11332 $obj = $this->db->fetch_object($resql);
11333 $out .= '<script nonce="' . getNonce() . '">
11334 $(function() {
11335 $("select[name=' . $target . ']").on("change", function() {
11336 var current_val = $(this).val();
11337 if (current_val == ' . $obj->id . ') {';
11338 if (!empty($default_selected) || !empty($selected)) {
11339 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
11340 }
11341
11342 $out .= '
11343 $("select[name=' . $htmlname . ']").change();
11344 }
11345 });
11346
11347 $("select[name=' . $htmlname . ']").change(function() {
11348
11349 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
11350 // get price of kilometer to fill the unit price
11351 $.ajax({
11352 method: "POST",
11353 dataType: "json",
11354 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
11355 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
11356 }).done(function( data, textStatus, jqXHR ) {
11357 console.log(data);
11358 if (typeof data.up != "undefined") {
11359 $("input[name=value_unit]").val(data.up);
11360 $("select[name=' . $htmlname . ']").attr("title", data.title);
11361 } else {
11362 $("input[name=value_unit]").val("");
11363 $("select[name=' . $htmlname . ']").attr("title", "");
11364 }
11365 });
11366 }
11367 });
11368 });
11369 </script>';
11370 }
11371 }
11372 }
11373 } else {
11374 dol_print_error($this->db);
11375 }
11376
11377 return $out;
11378 }
11379
11388 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
11389 {
11390 global $conf, $langs;
11391
11392 $out = '';
11393 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
11394 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
11395
11396 $resql = $this->db->query($sql);
11397 if ($resql) {
11398 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
11399 if ($useempty) {
11400 $out .= '<option value="0"></option>';
11401 }
11402
11403 while ($obj = $this->db->fetch_object($resql)) {
11404 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
11405 }
11406 $out .= '</select>';
11407 } else {
11408 dol_print_error($this->db);
11409 }
11410
11411 return $out;
11412 }
11413
11424 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
11425 {
11426 global $langs;
11427
11428 $out = '';
11429 $sql = "SELECT id, code, label";
11430 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
11431 $sql .= " WHERE active = 1";
11432
11433 $resql = $this->db->query($sql);
11434 if ($resql) {
11435 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
11436 if ($useempty) {
11437 $out .= '<option value="0"></option>';
11438 }
11439 if ($allchoice) {
11440 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
11441 }
11442
11443 $field = 'code';
11444 if ($useid) {
11445 $field = 'id';
11446 }
11447
11448 while ($obj = $this->db->fetch_object($resql)) {
11449 $key = $langs->trans($obj->code);
11450 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
11451 }
11452 $out .= '</select>';
11453
11454 $out .= ajax_combobox('select_'.$htmlname);
11455 } else {
11456 dol_print_error($this->db);
11457 }
11458
11459 return $out;
11460 }
11461
11480 public function selectInvoice($socid = -1, $selected = '', $htmlname = 'invoiceid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500', $projectsListId = '', $showproject = 'all', $usertofilter = null)
11481 {
11482 global $user, $conf, $langs;
11483
11484 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
11485
11486 if (is_null($usertofilter)) {
11487 $usertofilter = $user;
11488 }
11489
11490 $out = '';
11491
11492 $hideunselectables = false;
11493 if (getDolGlobalString('INVOICE_HIDE_UNSELECTABLES')) {
11494 $hideunselectables = true;
11495 }
11496
11497 if (empty($projectsListId)) {
11498 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
11499 $projectstatic = new Project($this->db);
11500 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
11501 }
11502 }
11503
11504 // Search all projects
11505 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
11506 p.title, p.fk_soc, p.fk_statut, p.public,";
11507 $sql .= ' s.nom as name';
11508 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
11509 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
11510 $sql .= ' ' . $this->db->prefix() . 'facture as f';
11511 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
11512 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
11513 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
11514 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
11515 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
11516 $sql .= " ORDER BY p.ref, f.ref ASC";
11517
11518 $resql = $this->db->query($sql);
11519 if ($resql) {
11520 // Use select2 selector
11521 if (!empty($conf->use_javascript_ajax)) {
11522 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11523 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11524 $out .= $comboenhancement;
11525 $morecss = 'minwidth200imp maxwidth500';
11526 }
11527
11528 if (empty($option_only)) {
11529 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11530 }
11531 if (!empty($show_empty)) {
11532 $out .= '<option value="0" class="optiongrey">';
11533 if (!is_numeric($show_empty)) {
11534 $out .= $show_empty;
11535 } else {
11536 $out .= '&nbsp;';
11537 }
11538 $out .= '</option>';
11539 }
11540 $num = $this->db->num_rows($resql);
11541 $i = 0;
11542 if ($num) {
11543 while ($i < $num) {
11544 $obj = $this->db->fetch_object($resql);
11545 // 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.
11546 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
11547 // Do nothing
11548 } else {
11549 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11550 $i++;
11551 continue;
11552 }
11553
11554 $labeltoshow = '';
11555
11556 if ($showproject == 'all') {
11557 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
11558 if ($obj->name) {
11559 $labeltoshow .= ' - ' . $obj->name; // Soc name
11560 }
11561
11562 $disabled = 0;
11563 if ($obj->fk_statut == Project::STATUS_DRAFT) {
11564 $disabled = 1;
11565 $labeltoshow .= ' - ' . $langs->trans("Draft");
11566 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
11567 if ($discard_closed == 2) {
11568 $disabled = 1;
11569 }
11570 $labeltoshow .= ' - ' . $langs->trans("Closed");
11571 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
11572 $disabled = 1;
11573 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
11574 }
11575 }
11576
11577 if (!empty($selected) && $selected == $obj->rowid) {
11578 $out .= '<option value="' . $obj->rowid . '" selected';
11579 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11580 $out .= '>' . $labeltoshow . '</option>';
11581 } else {
11582 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11583 $resultat = '';
11584 } else {
11585 $resultat = '<option value="' . $obj->rowid . '"';
11586 if ($disabled) {
11587 $resultat .= ' disabled';
11588 }
11589 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11590 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11591 $resultat .= '>';
11592 $resultat .= $labeltoshow;
11593 $resultat .= '</option>';
11594 }
11595 $out .= $resultat;
11596 }
11597 }
11598 $i++;
11599 }
11600 }
11601 if (empty($option_only)) {
11602 $out .= '</select>';
11603 }
11604
11605 $this->db->free($resql);
11606
11607 return $out;
11608 } else {
11609 dol_print_error($this->db);
11610 return '';
11611 }
11612 }
11613
11627 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11628 {
11629 global $conf, $langs;
11630
11631 $out = '';
11632
11633 dol_syslog('FactureRec::fetch', LOG_DEBUG);
11634
11635 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
11636 //$sql.= ', el.fk_source';
11637 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
11638 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
11639 $sql .= " ORDER BY f.titre ASC";
11640
11641 $resql = $this->db->query($sql);
11642 if ($resql) {
11643 // Use select2 selector
11644 if (!empty($conf->use_javascript_ajax)) {
11645 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11646 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11647 $out .= $comboenhancement;
11648 $morecss = 'minwidth200imp maxwidth500';
11649 }
11650
11651 if (empty($option_only)) {
11652 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11653 }
11654 if (!empty($show_empty)) {
11655 $out .= '<option value="0" class="optiongrey">';
11656 if (!is_numeric($show_empty)) {
11657 $out .= $show_empty;
11658 } else {
11659 $out .= '&nbsp;';
11660 }
11661 $out .= '</option>';
11662 }
11663 $num = $this->db->num_rows($resql);
11664 if ($num) {
11665 while ($obj = $this->db->fetch_object($resql)) {
11666 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
11667
11668 $disabled = 0;
11669 if (!empty($obj->suspended)) {
11670 $disabled = 1;
11671 $labeltoshow .= ' - ' . $langs->trans("Closed");
11672 }
11673
11674
11675 if (!empty($selected) && $selected == $obj->rowid) {
11676 $out .= '<option value="' . $obj->rowid . '" selected';
11677 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11678 $out .= '>' . $labeltoshow . '</option>';
11679 } else {
11680 if ($disabled && ($selected != $obj->rowid)) {
11681 $resultat = '';
11682 } else {
11683 $resultat = '<option value="' . $obj->rowid . '"';
11684 if ($disabled) {
11685 $resultat .= ' disabled';
11686 }
11687 $resultat .= '>';
11688 $resultat .= $labeltoshow;
11689 $resultat .= '</option>';
11690 }
11691 $out .= $resultat;
11692 }
11693 }
11694 }
11695 if (empty($option_only)) {
11696 $out .= '</select>';
11697 }
11698
11699 print $out;
11700
11701 $this->db->free($resql);
11702 return $num;
11703 } else {
11704 $this->errors[] = $this->db->lasterror;
11705 return -1;
11706 }
11707 }
11708
11709
11725 public function selectOrder($selected = '', $htmlname = 'orderid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11726 {
11727 global $user, $conf, $langs;
11728
11729 $out = '';
11730
11731 $hideunselectables = false;
11732 if (getDolGlobalString('ORDER_HIDE_UNSELECTABLES')) {
11733 $hideunselectables = true;
11734 }
11735
11736 // Search all orders
11737 $sql = "SELECT c.rowid, c.ref";
11738 $sql .= ' FROM '.$this->db->prefix().'commande as c';
11739 $sql .= " ORDER BY c.ref ASC";
11740
11741 $resql = $this->db->query($sql);
11742 if ($resql) {
11743 // Use select2 selector
11744 if (!empty($conf->use_javascript_ajax)) {
11745 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
11746 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11747 $out .= $comboenhancement;
11748 $morecss = 'minwidth200imp maxwidth500';
11749 }
11750
11751 if (empty($option_only)) {
11752 $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
11753 }
11754 if (!empty($show_empty)) {
11755 $out .= '<option value="0" class="optiongrey">';
11756 if (!is_numeric($show_empty)) {
11757 $out .= $show_empty;
11758 } else {
11759 $out .= '&nbsp;';
11760 }
11761 $out .= '</option>';
11762 }
11763 $num = $this->db->num_rows($resql);
11764 $i = 0;
11765 if ($num) {
11766 while ($i < $num) {
11767 $obj = $this->db->fetch_object($resql);
11768
11769 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11770 $i++;
11771 continue;
11772 }
11773
11774 $labeltoshow = dol_trunc($obj->ref, 18); // Order ref
11775
11776 if (!empty($selected) && $selected == $obj->rowid) {
11777 $out .= '<option value="'.$obj->rowid.'" selected';
11778 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11779 $out .= '>'.$labeltoshow.'</option>';
11780 } else {
11781 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11782 $resultat = '';
11783 } else {
11784 $resultat = '<option value="'.$obj->rowid.'"';
11785 if ($disabled) {
11786 $resultat .= ' disabled';
11787 }
11788 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11789 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11790 $resultat .= '>';
11791 $resultat .= $labeltoshow;
11792 $resultat .= '</option>';
11793 }
11794 $out .= $resultat;
11795 }
11796 $i++;
11797 }
11798 }
11799 if (empty($option_only)) {
11800 $out .= '</select>';
11801 }
11802
11803 print $out;
11804
11805 $this->db->free($resql);
11806 return $num;
11807 } else {
11808 dol_print_error($this->db);
11809 return -1;
11810 }
11811 }
11812
11828 public function selectSupplierOrder($selected = '', $htmlname = 'supplierorderid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11829 {
11830 global $user, $conf, $langs;
11831
11832 $out = '';
11833
11834 $hideunselectables = false;
11835 if (getDolGlobalString('SUPPLIER_ORDER_HIDE_UNSELECTABLES')) {
11836 $hideunselectables = true;
11837 }
11838
11839 // Search all supplier orders
11840 $sql = "SELECT cf.rowid, cf.ref";
11841 $sql .= ' FROM '.$this->db->prefix().'commande_fournisseur as cf';
11842 $sql .= " ORDER BY cf.ref ASC";
11843
11844 $resql = $this->db->query($sql);
11845 if ($resql) {
11846 // Use select2 selector
11847 if (!empty($conf->use_javascript_ajax)) {
11848 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
11849 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11850 $out .= $comboenhancement;
11851 $morecss = 'minwidth200imp maxwidth500';
11852 }
11853
11854 if (empty($option_only)) {
11855 $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
11856 }
11857 if (!empty($show_empty)) {
11858 $out .= '<option value="0" class="optiongrey">';
11859 if (!is_numeric($show_empty)) {
11860 $out .= $show_empty;
11861 } else {
11862 $out .= '&nbsp;';
11863 }
11864 $out .= '</option>';
11865 }
11866 $num = $this->db->num_rows($resql);
11867 $i = 0;
11868 if ($num) {
11869 while ($i < $num) {
11870 $obj = $this->db->fetch_object($resql);
11871
11872 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11873 $i++;
11874 continue;
11875 }
11876
11877 $labeltoshow = dol_trunc($obj->ref, 18); // Supplier order ref
11878
11879 if (!empty($selected) && $selected == $obj->rowid) {
11880 $out .= '<option value="'.$obj->rowid.'" selected';
11881 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11882 $out .= '>'.$labeltoshow.'</option>';
11883 } else {
11884 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11885 $resultat = '';
11886 } else {
11887 $resultat = '<option value="'.$obj->rowid.'"';
11888 if ($disabled) {
11889 $resultat .= ' disabled';
11890 }
11891 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11892 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11893 $resultat .= '>';
11894 $resultat .= $labeltoshow;
11895 $resultat .= '</option>';
11896 }
11897 $out .= $resultat;
11898 }
11899 $i++;
11900 }
11901 }
11902 if (empty($option_only)) {
11903 $out .= '</select>';
11904 }
11905
11906 print $out;
11907
11908 $this->db->free($resql);
11909 return $num;
11910 } else {
11911 dol_print_error($this->db);
11912 return -1;
11913 }
11914 }
11915
11931 public function selectSupplierInvoice($selected = '', $htmlname = 'supplierinvoiceid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11932 {
11933 global $user, $conf, $langs;
11934
11935 $out = '';
11936
11937 $hideunselectables = false;
11938 if (getDolGlobalString('SUPPLIER_INVOICE_HIDE_UNSELECTABLES')) {
11939 $hideunselectables = true;
11940 }
11941
11942 // Search all supplier orders
11943 $sql = "SELECT ff.rowid, ff.ref";
11944 $sql .= ' FROM '.$this->db->prefix().'facture_fourn as ff';
11945 $sql .= " ORDER BY ff.ref ASC";
11946
11947 $resql = $this->db->query($sql);
11948 if ($resql) {
11949 // Use select2 selector
11950 if (!empty($conf->use_javascript_ajax)) {
11951 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
11952 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11953 $out .= $comboenhancement;
11954 $morecss = 'minwidth200imp maxwidth500';
11955 }
11956
11957 if (empty($option_only)) {
11958 $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
11959 }
11960 if (!empty($show_empty)) {
11961 $out .= '<option value="0" class="optiongrey">';
11962 if (!is_numeric($show_empty)) {
11963 $out .= $show_empty;
11964 } else {
11965 $out .= '&nbsp;';
11966 }
11967 $out .= '</option>';
11968 }
11969 $num = $this->db->num_rows($resql);
11970 $i = 0;
11971 if ($num) {
11972 while ($i < $num) {
11973 $obj = $this->db->fetch_object($resql);
11974
11975 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11976 $i++;
11977 continue;
11978 }
11979
11980 $labeltoshow = dol_trunc($obj->ref, 18); // Supplier order ref
11981
11982 if (!empty($selected) && $selected == $obj->rowid) {
11983 $out .= '<option value="'.$obj->rowid.'" selected';
11984 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11985 $out .= '>'.$labeltoshow.'</option>';
11986 } else {
11987 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11988 $resultat = '';
11989 } else {
11990 $resultat = '<option value="'.$obj->rowid.'"';
11991 if ($disabled) {
11992 $resultat .= ' disabled';
11993 }
11994 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11995 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11996 $resultat .= '>';
11997 $resultat .= $labeltoshow;
11998 $resultat .= '</option>';
11999 }
12000 $out .= $resultat;
12001 }
12002 $i++;
12003 }
12004 }
12005 if (empty($option_only)) {
12006 $out .= '</select>';
12007 }
12008
12009 print $out;
12010
12011 $this->db->free($resql);
12012 return $num;
12013 } else {
12014 dol_print_error($this->db);
12015 return -1;
12016 }
12017 }
12018
12029 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '', $arrayoffiltercriterias = array())
12030 {
12031 // TODO: Use $arrayoffiltercriterias param instead of $arrayofcriterias to include linked object fields in search
12032 global $langs, $form;
12033
12034 //require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
12035 //$formother = new FormOther($this->db);
12036
12037 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
12038 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
12039 }
12040
12041 $ret = '<!-- searchComponent -->';
12042
12043 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
12044 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
12045 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
12046 $ret .= '</a>';
12047
12048 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
12049
12050 // Show select fields as tags.
12051 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
12052
12053 if ($search_component_params_hidden) {
12054 // Split the criteria on each AND
12055 //var_dump($search_component_params_hidden);
12056
12057 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
12058
12059 // $arrayofandtags is now array( '...' , '...', ...)
12060 // Show each AND part
12061 foreach ($arrayofandtags as $tmpkey => $tmpval) {
12062 $errormessage = '';
12063 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
12064 if ($errormessage) {
12065 $this->error = 'ERROR in parsing search string: '.$errormessage;
12066 }
12067 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
12068 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
12069 $searchtags = removeGlobalParenthesis($searchtags);
12070
12071 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
12072 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
12073 $ret .= dol_escape_htmltag($searchtags);
12074 $ret .= '</span>';
12075 }
12076 }
12077
12078 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
12079
12080 //$ret .= search_component_params
12081 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
12082 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
12083
12084 $show_search_component_params_hidden = 1;
12085 if ($show_search_component_params_hidden) {
12086 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
12087 }
12088 $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%')) -->";
12089 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
12090 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
12091
12092 // TODO : Use $arrayoffiltercriterias instead of $arrayofcriterias
12093 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
12094 foreach ($arrayofcriterias as $criteria) {
12095 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
12096 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
12097 continue;
12098 }
12099 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
12100 continue;
12101 }
12102 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
12103 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
12104 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
12105 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
12106 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
12107 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
12108 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
12109 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
12110 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
12111 } else {
12112 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
12113 }
12114 }
12115 }
12116
12117 $ret .= '</div>';
12118
12119 $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";
12120 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
12121
12122 $ret .= '</div>';
12123 $ret .= '</div>';
12124
12125 $ret .= '<script>
12126 jQuery(".tagsearchdelete").click(function(e) {
12127 var filterid = $(this).parents().attr("data-ufilterid");
12128 console.log("We click to delete the criteria nb "+filterid);
12129
12130 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
12131 var newparamstring = \'\';
12132 $(\'.tagsearch\').each(function(index, element) {
12133 tmpfilterid = $(this).attr("data-ufilterid");
12134 if (tmpfilterid != filterid) {
12135 // We keep this criteria
12136 if (newparamstring == \'\') {
12137 newparamstring = $(this).attr("data-ufilter");
12138 } else {
12139 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
12140 }
12141 }
12142 });
12143 console.log("newparamstring = "+newparamstring);
12144
12145 jQuery("#search_component_params_hidden").val(newparamstring);
12146
12147 // We repost the form
12148 $(this).closest(\'form\').submit();
12149 });
12150
12151 jQuery("#search_component_params_input").keydown(function(e) {
12152 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
12153 console.log(e.which);
12154 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
12155 /* We click on back when the input field is already empty */
12156 event.preventDefault();
12157 jQuery("#divsearch_component_params .tagsearch").last().remove();
12158 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
12159 var s = "";
12160 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
12161 if (s != "") {
12162 s = s + " AND ";
12163 }
12164 s = s + $(this).attr("data-ufilter");
12165 });
12166 console.log("New value for search_component_params_hidden = "+s);
12167 jQuery("#search_component_params_hidden").val(s);
12168 }
12169 });
12170
12171 </script>
12172 ';
12173
12174 // Convert $arrayoffiltercriterias into a json object that can be used in jquery to build the search component dynamically
12175 $arrayoffiltercriterias_json = json_encode($arrayoffiltercriterias);
12176 $ret .= '<script>
12177 var arrayoffiltercriterias = ' . $arrayoffiltercriterias_json . ';
12178 </script>';
12179
12180
12181 $arrayoffilterfieldslabel = array();
12182 foreach ($arrayoffiltercriterias as $key => $val) {
12183 $arrayoffilterfieldslabel[$key]['label'] = $val['label'];
12184 $arrayoffilterfieldslabel[$key]['data-type'] = $val['type'];
12185 }
12186
12187 // Adding the div for search assistance
12188 $ret .= '<div class="search-component-assistance">';
12189 $ret .= '<div>';
12190
12191 $ret .= '<p class="assistance-title">' . img_picto('', 'filter') . ' ' . $langs->trans('FilterAssistance') . ' </p>';
12192
12193 $ret .= '<p class="assistance-errors error" style="display:none">' . $langs->trans('AllFieldsRequired') . ' </p>';
12194
12195 $ret .= '<div class="operand">';
12196 $ret .= $form->selectarray('search_filter_field', $arrayoffilterfieldslabel, '', $langs->trans("Fields"), 0, 0, '', 0, 0, 0, '', 'width200 combolargeelem', 1);
12197 $ret .= '</div>';
12198
12199 $ret .= '<span class="separator"></span>';
12200
12201 // Operator selector (will be populated dynamically)
12202 $ret .= '<div class="operator">';
12203 $ret .= '<select class="operator-selector width150" id="operator-selector"">';
12204 $ret .= '</select>';
12205 $ret .= '<script>$(document).ready(function() {';
12206 $ret .= ' $(".operator-selector").select2({';
12207 $ret .= ' placeholder: \'' . dol_escape_js($langs->transnoentitiesnoconv('Operator')) . '\'';
12208 $ret .= ' });';
12209 $ret .= '});</script>';
12210 $ret .= '</div>';
12211
12212 $ret .= '<span class="separator"></span>';
12213
12214 $ret .= '<div class="value">';
12215 // Input field for entering values
12216 $ret .= '<input type="text" class="flat width100 value-input" placeholder="' . dolPrintHTML($langs->trans('Value')) . '">';
12217
12218 // Date selector
12219 $dateOne = '';
12220 $ret .= '<span class="date-one" style="display:none">';
12221 $ret .= $form->selectDate(($dateOne ? $dateOne : -1), 'dateone', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '');
12222 $ret .= '</span>';
12223
12224 // Value selector (will be populated dynamically) based on search_filter_field value if a selected value has an array of values
12225 $ret .= '<select class="value-selector width150" id="value-selector" style="display:none">';
12226 $ret .= '</select>';
12227 $ret .= '<script>
12228 $(document).ready(function() {
12229 $("#value-selector").select2({
12230 placeholder: "' . dol_escape_js($langs->trans('Value')) . '"
12231 });
12232 $("#value-selector").hide();
12233 $("#value-selector").next(".select2-container").hide();
12234 });
12235 </script>';
12236
12237 $ret .= '</div>';
12238
12239 $ret .= '<div class="btn-div">';
12240 $ret .= '<button class="button buttongen button-save add-filter-btn" type="button">' . $langs->trans("addToFilter") . '</button>';
12241 $ret .= '</div>';
12242
12243 $ret .= '</div>';
12244 //$ret .= '</tbody></table>';
12245
12246 // End of the assistance div
12247 $ret .= '</div>';
12248
12249 // Script jQuery to show/hide the floating assistance
12250 $ret .= '<script>
12251 $(document).ready(function() {
12252 $("#search_component_params_input").on("click", function() {
12253 const inputPosition = $(this).offset();
12254 const inputHeight = $(this).outerHeight();
12255 $(".search-component-assistance").css({
12256 top: inputPosition.top + inputHeight + 5 + "px",
12257 left: $("#divsearch_component_params").position().left
12258 }).slideToggle(200);
12259 });
12260 $(document).on("click", function(e) {
12261 if (!$(e.target).closest("#search_component_params_input, .search-component-assistance, #ui-datepicker-div").length) {
12262 $(".search-component-assistance").hide();
12263 }
12264 });
12265 });
12266 </script>';
12267
12268 $ret .= '<script>
12269 $(document).ready(function() {
12270 $(".search_filter_field").on("change", function() {
12271 console.log("We change search_filter_field");
12272
12273 let maybenull = 0;
12274 const selectedField = $(this).find(":selected");
12275 let fieldType = selectedField.data("type");
12276 const selectedFieldValue = selectedField.val();
12277
12278 // If the selected field has an array of values then ask toshow the value selector instead of the value input
12279 if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
12280 fieldType = "select";
12281 }
12282
12283 // If the selected field may be null then ask to append the "IsDefined" and "IsNotDefined" operators
12284 if (arrayoffiltercriterias[selectedFieldValue]["maybenull"] !== undefined) {
12285 maybenull = 1;
12286 }
12287 const operators = getOperatorsForFieldType(fieldType, maybenull);
12288 const operatorSelector = $(".operator-selector");
12289
12290 // Clear existing options
12291 operatorSelector.empty();
12292
12293 // Populate operators
12294 Object.entries(operators).forEach(function([operator, label]) {
12295 operatorSelector.append("<option value=\'" + operator + "\'>" + label + "</option>");
12296 });
12297
12298 operatorSelector.trigger("change.select2");
12299
12300 // Clear and hide all input elements initially
12301 $(".value-input, .dateone, .datemonth, .dateyear").val("").hide();
12302 $("#datemonth, #dateyear").val(null).trigger("change.select2");
12303 $("#dateone").datepicker("setDate", null);
12304 $(".date-one, .date-month, .date-year").hide();
12305 $("#value-selector").val("").hide();
12306 $("#value-selector").next(".select2-container").hide();
12307 $("#value-selector").val(null).trigger("change.select2");
12308
12309 if (fieldType === "date" || fieldType === "datetime" || fieldType === "timestamp") {
12310 $(".date-one").show();
12311 } else if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
12312 var arrayofkeyval = arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"];
12313 var valueSelector = $("#value-selector");
12314 valueSelector.empty();
12315 Object.entries(arrayofkeyval).forEach(function([key, val]) {
12316 valueSelector.append("<option value=\'" + key + "\'>" + val + "</option>");
12317 });
12318 valueSelector.trigger("change.select2");
12319
12320 $("#value-selector").show();
12321 $("#value-selector").next(".select2-container").show();
12322 } else {
12323 $(".value-input").show();
12324 }
12325 });
12326
12327 $("#operator-selector").on("change", function() {
12328 console.log("We change operator-selector");
12329
12330 const selectedOperator = $(this).find(":selected").val();
12331 if (selectedOperator === "IsDefined" || selectedOperator === "IsNotDefined") {
12332 // Disable all value input elements
12333 $(".value-input, .dateone, .datemonth, .dateyear").val("").prop("disabled", true);
12334 $("#datemonth, #dateyear").val(null).trigger("change.select2");
12335 $("#dateone").datepicker("setDate", null).datepicker("option", "disabled", true);
12336 $(".date-one, .date-month, .date-year").prop("disabled", true);
12337 $("#value-selector").val("").prop("disabled", true);
12338 $("#value-selector").val(null).trigger("change.select2");
12339 } else {
12340 // Enable all value input elements
12341 $(".value-input, .dateone, .datemonth, .dateyear").prop("disabled", false);
12342 $(".date-one, .date-month, .date-year").prop("disabled", false);
12343 $("#dateone").datepicker("option", "disabled", false);
12344 $("#value-selector").prop("disabled", false);
12345 }
12346 });
12347
12348 $(".add-filter-btn").on("click", function(event) {
12349 console.log("We click on add-filter-btn");
12350
12351 event.preventDefault();
12352
12353 const field = $(".search_filter_field").val();
12354 const operator = $(".operator-selector").val();
12355 let value = $(".value-input").val();
12356 const fieldType = $(".search_filter_field").find(":selected").data("type");
12357
12358 if (["date", "datetime", "timestamp"].includes(fieldType)) {
12359 const year = $("#dateoneyear").val().toString().padStart(4, "0");;
12360 const month = $("#dateonemonth").val().toString().padStart(2, "0");
12361 const day = $("#dateoneday").val().toString().padStart(2, "0");
12362 value = `${year}-${month}-${day}`;
12363 console.log("value="+value);
12364 }
12365
12366 // If the selected field has an array of values then take the selected value
12367 if (arrayoffiltercriterias[field]["arrayofkeyval"] !== undefined) {
12368 value = $("#value-selector").val();
12369 }
12370
12371 // If the operator is "IsDefined" or "IsNotDefined" then set the value to 1 (it will not be used)
12372 if (operator === "IsDefined" || operator === "IsNotDefined") {
12373 value = "1";
12374 }
12375
12376 const filterString = generateFilterString(field, operator, value, fieldType);
12377
12378 // Submit the form
12379 if (filterString !== "" && field !== "" && operator !== "" && value !== "") {
12380 $("#search_component_params_input").val($("#search_component_params_input").val() + " " + filterString);
12381 $("#search_component_params_input").closest("form").submit();
12382 } else {
12383 $(".assistance-errors").show();
12384 }
12385 });
12386 });
12387 </script>';
12388
12389 return $ret;
12390 }
12391
12402 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0, $selected = 0)
12403 {
12404 global $langs, $user;
12405
12406 $retstring = '';
12407
12408 $TModels = array();
12409
12410 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
12411 $formmail = new FormMail($this->db);
12412 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
12413
12414 if ($default) {
12415 $TModels[0] = $langs->trans('DefaultMailModel');
12416 }
12417 if ($result > 0) {
12418 foreach ($formmail->lines_model as $model) {
12419 $TModels[(int) $model->id] = $model->label;
12420 }
12421 }
12422
12423 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
12424
12425 foreach ($TModels as $id_model => $label_model) {
12426 $retstring .= '<option value="' . $id_model . '"';
12427 if (!empty($selected) && ((int) $selected) == $id_model) {
12428 $retstring .= "selected";
12429 }
12430 $retstring .= ">" . $label_model . "</option>";
12431 }
12432
12433 $retstring .= "</select>";
12434
12435 if ($addjscombo) {
12436 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
12437 }
12438
12439 return $retstring;
12440 }
12441
12453 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
12454 {
12455 global $langs;
12456
12457 $buttons = array();
12458
12459 $save = array(
12460 'name' => 'save',
12461 'label_key' => $save_label,
12462 );
12463
12464 if ($save_label == 'Create' || $save_label == 'Add') {
12465 $save['name'] = 'add';
12466 } elseif ($save_label == 'Modify') {
12467 $save['name'] = 'edit';
12468 }
12469
12470 $cancel = array(
12471 'name' => 'cancel',
12472 'label_key' => 'Cancel',
12473 );
12474
12475 // If MAIN_BUTTON_POSITION_FIRST_OR_LEFT not set, default is to have main action first, then complementary, then cancel at end
12476 if (!getDolGlobalInt('MAIN_BUTTON_POSITION_FIRST_OR_LEFT')) {
12477 !empty($save_label) ? $buttons[] = $save : '';
12478 if (!empty($morebuttons)) {
12479 $buttons[] = $morebuttons;
12480 }
12481 !empty($cancel_label) ? $buttons[] = $cancel : '';
12482 } else {
12483 if (!empty($morebuttons)) {
12484 $buttons[] = $morebuttons;
12485 }
12486 !empty($cancel_label) ? $buttons[] = $cancel : '';
12487 !empty($save_label) ? $buttons[] = $save : '';
12488 }
12489
12490 $retstring = $withoutdiv ? '' : '<div class="center">';
12491
12492 foreach ($buttons as $button) {
12493 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
12494 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->transnoentities($button['label_key'])) . '">';
12495 }
12496 $retstring .= $withoutdiv ? '' : '</div>';
12497
12498 if ($dol_openinpopup) {
12499 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
12500 $retstring .= '<script nonce="' . getNonce() . '">';
12501 $retstring .= 'jQuery(".button-cancel").click(function(e) {
12502 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
12503 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
12504 });';
12505 $retstring .= '</script>';
12506 }
12507
12508 return $retstring;
12509 }
12510
12511
12512 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
12513
12520 {
12521 // phpcs:enable
12522 global $langs;
12523
12524 $num = count($this->cache_invoice_subtype);
12525 if ($num > 0) {
12526 return 0; // Cache already loaded
12527 }
12528
12529 dol_syslog(__METHOD__, LOG_DEBUG);
12530
12531 $sql = "SELECT rowid, code, label as label";
12532 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
12533 $sql .= " WHERE active = 1";
12534
12535 $resql = $this->db->query($sql);
12536 if ($resql) {
12537 $num = $this->db->num_rows($resql);
12538 $i = 0;
12539 while ($i < $num) {
12540 $obj = $this->db->fetch_object($resql);
12541
12542 // If translation exists, we use it, otherwise we take the default wording
12543 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
12544 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
12545 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
12546 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
12547 $i++;
12548 }
12549
12550 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
12551
12552 return $num;
12553 } else {
12554 dol_print_error($this->db);
12555 return -1;
12556 }
12557 }
12558
12559
12570 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
12571 {
12572 global $langs, $user;
12573
12574 $out = '';
12575 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
12576
12577 $this->load_cache_invoice_subtype();
12578
12579 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
12580 if ($addempty) {
12581 $out .= '<option value="0">&nbsp;</option>';
12582 }
12583
12584 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
12585 $label = $subtype['label'];
12586 $out .= '<option value="' . $subtype['rowid'] . '"';
12587 if ($selected == $subtype['rowid']) {
12588 $out .= ' selected="selected"';
12589 }
12590 $out .= '>';
12591 $out .= $label;
12592 $out .= '</option>';
12593 }
12594
12595 $out .= '</select>';
12596 if ($user->admin && empty($noinfoadmin)) {
12597 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
12598 }
12599 $out .= ajax_combobox($htmlname);
12600
12601 return $out;
12602 }
12603
12613 public function getSearchFilterToolInput($dataTarget, $htmlName = 'search-tools-input', $value = '', $params = [])
12614 {
12615 global $langs;
12616
12617 $attr = array(
12618 'type' => 'search',
12619 'name' => $htmlName,
12620 'value' => $value,
12621 'class' => "search-tool-input",
12622 'placeholder' => $langs->trans('Search'),
12623 'autocomplete' => 'off'
12624 );
12625
12626 // Optional data attr
12627 // 'autofocus' : will set auto focus on field ,
12628 // data-counter-target : will get count results
12629 // data-no-item-target : will be display if count results is 0
12630
12631 if ($dataTarget !== false) {
12632 $attr['data-search-tool-target'] = $dataTarget;
12633 }
12634
12635 // Override attr
12636 if (!empty($params['attr']) && is_array($params['attr'])) {
12637 foreach ($params['attr'] as $key => $value) {
12638 if ($key == 'class') {
12639 $attr['class'] .= ' '.$value;
12640 } elseif ($key == 'classOverride') {
12641 $attr['class'] = $value;
12642 } else {
12643 $attr[$key] = $value;
12644 }
12645 }
12646 }
12647
12648 // automatic add tooltip when title is detected
12649 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
12650 $attr['class'] .= ' classfortooltip';
12651 }
12652
12653 $TCompiledAttr = [];
12654 foreach ($attr as $key => $value) {
12655 if (in_array($key, ['data-target'])
12656 || (!empty($params['use_unsecured_unescapedattr']) && is_array($params['use_unsecured_unescapedattr']) && in_array($key, $params['use_unsecured_unescapedattr']))) { // Not recommended
12657 $value = dol_htmlentities($value, ENT_QUOTES | ENT_SUBSTITUTE);
12658 } else {
12659 $value = dolPrintHTMLForAttribute($value);
12660 }
12661
12662 $TCompiledAttr[] = $key . '="' . $value . '"'; // $value has been escaped by the dolPrintHTMLForAttribute... just before
12663 }
12664
12665 $compiledAttributes = implode(' ', $TCompiledAttr);
12666
12667
12668 return '<div class="search-tool-container"><input '.$compiledAttributes.'></div>';
12669 }
12670}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
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:578
$c
Definition line.php:331
$object ref
Definition info.php:90
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.
DAO Resource object.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage 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.
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.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0, $selected=0)
selectModelMail
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.
formRib($page, $selected='', $htmlname='ribcompanyid', $filtre='', $addempty=0, $showibanbic=0)
Display form to select bank customer account.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party This call select_thirdparty_list() or ajax depending on setu...
select_produits($selected=0, $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1, $warehouseId=0)
Return list of products for customer.
select_dolgroups($selected=0, $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly=array(), $force_entity='0', $multiple=false, $morecss='minwidth200')
Return select list of user groups.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
selectSupplierOrder($selected='', $htmlname='supplierorderid', $maxlength=24, $option_only=0, $show_empty='1', $discard_closed=0, $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with supplier orders qualified for a third party.
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.
selectSupplierInvoice($selected='', $htmlname='supplierinvoiceid', $maxlength=24, $option_only=0, $show_empty='1', $discard_closed=0, $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with supplier invoices qualified for a third party.
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="", $useajaxcombo=1)
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
selectRib($selected='', $htmlname='ribcompanyid', $filtre='', $useempty=0, $moreattrib='', $showibanbic=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts customer.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
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.
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.
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.
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)
Return combo list of activated countries, into language of user.
selectOrder($selected='', $htmlname='orderid', $maxlength=24, $option_only=0, $show_empty='1', $discard_closed=0, $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with orders qualified for a third party.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
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.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='width75', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly=array(), $force_entity='0')
Return the HTML select list of users.
selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='', $openinghours='', $stepminutes=1, $labeladddateof='', $placeholder='', $gm='auto', $calendarpicto='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
static selectArrayFilter($htmlname, $array, $id='', $moreparam='', $disableFiltering=0, $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0, $textfortitle='')
Return a HTML select string, built from an array of key+value, but content returned into select is de...
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...
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 compopent to select a category.
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.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
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...
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='', $arrayoffiltercriterias=array())
Output the component to make advanced search criteries.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage hooks.
Class for MyObject.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
const STATUS_CLOSED
Closed status.
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)
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_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_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.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
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'.
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.
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.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
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, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0, $morecss='paddingrightonly')
Show EMail link formatted for HTML output.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external 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.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
a disabled
treeview li table
No Email.
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
measuringUnitString($unitid, $measuring_style='', $unitscale=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
Definition repair.php:158
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:161
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