dolibarr 21.0.0-beta
html.form.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13 * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18 * Copyright (C) 2014-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
27 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
28 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 3 of the License, or
32 * (at your option) any later version.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program. If not, see <https://www.gnu.org/licenses/>.
41 */
42
56class Form
57{
61 public $db;
62
66 public $error = '';
67
71 public $errors = array();
72
73 // Some properties used to return data by some methods
75 public $result;
77 public $num;
78
79 // Cache arrays
80 public $cache_types_paiements = array();
81 public $cache_conditions_paiements = array();
82 public $cache_transport_mode = array();
83 public $cache_availability = array();
84 public $cache_demand_reason = array();
85 public $cache_types_fees = array();
86 public $cache_vatrates = array();
87 public $cache_invoice_subtype = array();
88
89
95 public function __construct($db)
96 {
97 $this->db = $db;
98 }
99
116 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
117 {
118 global $langs;
119
120 $ret = '';
121
122 // TODO change for compatibility
123 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
124 if (!empty($perm)) {
125 $tmp = explode(':', $typeofdata);
126 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
127 if ($fieldrequired) {
128 $ret .= '<span class="fieldrequired">';
129 }
130 if ($help) {
131 $ret .= $this->textwithpicto($langs->trans($text), $help);
132 } else {
133 $ret .= $langs->trans($text);
134 }
135 if ($fieldrequired) {
136 $ret .= '</span>';
137 }
138 $ret .= '</div>' . "\n";
139 } else {
140 if ($fieldrequired) {
141 $ret .= '<span class="fieldrequired">';
142 }
143 if ($help) {
144 $ret .= $this->textwithpicto($langs->trans($text), $help);
145 } else {
146 $ret .= $langs->trans($text);
147 }
148 if ($fieldrequired) {
149 $ret .= '</span>';
150 }
151 }
152 } else {
153 if (empty($notabletag) && $perm) {
154 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
155 }
156 if ($fieldrequired) {
157 $ret .= '<span class="fieldrequired">';
158 }
159 if ($help) {
160 $ret .= $this->textwithpicto($langs->trans($text), $help);
161 } else {
162 $ret .= $langs->trans($text);
163 }
164 if ($fieldrequired) {
165 $ret .= '</span>';
166 }
167 if (!empty($notabletag)) {
168 $ret .= ' ';
169 }
170 if (empty($notabletag) && $perm) {
171 $ret .= '</td>';
172 }
173 if (empty($notabletag) && $perm) {
174 $ret .= '<td class="right">';
175 }
176 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
177 $ret .= '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=edit' . $htmlname . '&token=' . newToken() . '&' . $paramid . '=' . $object->id . $moreparam . '">' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . '</a>';
178 }
179 if (!empty($notabletag) && $notabletag == 1) {
180 if ($text) {
181 $ret .= ' : ';
182 } else {
183 $ret .= ' ';
184 }
185 }
186 if (!empty($notabletag) && $notabletag == 3) {
187 $ret .= ' ';
188 }
189 if (empty($notabletag) && $perm) {
190 $ret .= '</td>';
191 }
192 if (empty($notabletag) && $perm) {
193 $ret .= '</tr></table>';
194 }
195 }
196
197 return $ret;
198 }
199
223 public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '')
224 {
225 global $conf, $langs;
226
227 $ret = '';
228
229 // Check parameters
230 if (empty($typeofdata)) {
231 return 'ErrorBadParameter typeofdata is empty';
232 }
233 // Clean parameter $typeofdata
234 if ($typeofdata == 'datetime') {
235 $typeofdata = 'dayhour';
236 }
237 $reg = array();
238 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
239 if ($reg[1] == 'varchar') {
240 $typeofdata = 'string';
241 } elseif ($reg[1] == 'int') {
242 $typeofdata = 'numeric';
243 } else {
244 return 'ErrorBadParameter ' . $typeofdata;
245 }
246 }
247
248 // When option to edit inline is activated
249 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
250 $ret .= $this->editInPlace($object, $value, $htmlname, ($perm ? 1 : 0), $typeofdata, $editvalue, $extObject, $custommsg);
251 } else {
252 if ($editaction == '') {
253 $editaction = GETPOST('action', 'aZ09');
254 }
255 $editmode = ($editaction == 'edit' . $htmlname);
256 if ($editmode) { // edit mode
257 $ret .= "<!-- formeditfieldval -->\n";
258 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
259 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
260 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
261 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
262 if (empty($notabletag)) {
263 $ret .= '<table class="nobordernopadding centpercent">';
264 }
265 if (empty($notabletag)) {
266 $ret .= '<tr><td>';
267 }
268 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
269 $tmp = explode(':', $typeofdata);
270 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
271 } elseif (preg_match('/^(integer)/', $typeofdata)) {
272 $tmp = explode(':', $typeofdata);
273 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
274 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
275 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
276 $tmp = explode(':', $typeofdata);
277 $valuetoshow = price2num($editvalue ? $editvalue : $value);
278 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
279 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
280 $tmp = explode(':', $typeofdata);
281 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
282 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
283 $tmp = explode(':', $typeofdata);
284 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
285 $morealt = '';
286 if (preg_match('/%/', $cols)) {
287 $morealt = ' style="width: ' . $cols . '"';
288 $cols = '';
289 }
290 $valuetoshow = ($editvalue ? $editvalue : $value);
291 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
292 // textarea convert automatically entities chars into simple chars.
293 // So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwyg is off.
294 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
295 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
296 $ret .= '</textarea><div class="clearboth"></div>';
297 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
298 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
299 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
300 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
301 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
302 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
303 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
304 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
305 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
306 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
307 } elseif (preg_match('/^select;/', $typeofdata)) {
308 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
309 $arraylist = array();
310 foreach ($arraydata as $val) {
311 $tmp = explode(':', $val);
312 $tmpkey = str_replace('|', ':', $tmp[0]);
313 $arraylist[$tmpkey] = $tmp[1];
314 }
315 $ret .= $this->selectarray($htmlname, $arraylist, $value);
316 } elseif (preg_match('/^link/', $typeofdata)) {
317 // TODO Not yet implemented. See code for extrafields
318 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
319 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
320 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
321 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? 100 : (int) $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? false : (bool) $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? 20 : (int) $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
322 $ret .= $doleditor->Create(1);
323 } elseif ($typeofdata == 'asis') {
324 $ret .= ($editvalue ? $editvalue : $value);
325 }
326 if (empty($notabletag)) {
327 $ret .= '</td>';
328 }
329
330 // Button save-cancel
331 if (empty($notabletag)) {
332 $ret .= '<td>';
333 }
334 //else $ret.='<div class="clearboth"></div>';
335 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
336 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
337 $ret .= '<br>' . "\n";
338 }
339 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
340 if (empty($notabletag)) {
341 $ret .= '</td>';
342 }
343
344 if (empty($notabletag)) {
345 $ret .= '</tr></table>' . "\n";
346 }
347 $ret .= '</form>' . "\n";
348 } else { // view mode
349 if (preg_match('/^email/', $typeofdata)) {
350 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
351 } elseif (preg_match('/^phone/', $typeofdata)) {
352 $ret .= dol_print_phone($value, '_blank', 32, 1);
353 } elseif (preg_match('/^url/', $typeofdata)) {
354 $ret .= dol_print_url($value, '_blank', 32, 1);
355 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
356 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
357 } elseif (preg_match('/^checkbox/', $typeofdata)) {
358 $tmp = explode(':', $typeofdata);
359 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
360 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
362 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
364 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
365 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
366 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
367 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
368 } elseif (preg_match('/^select;/', $typeofdata)) {
369 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
370 $arraylist = array();
371 foreach ($arraydata as $val) {
372 $tmp = explode(':', $val);
373 $arraylist[$tmp[0]] = $tmp[1];
374 }
375 $ret .= $arraylist[$value];
376 if ($htmlname == 'fk_product_type') {
377 if ($value == 0) {
378 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
379 } else {
380 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
381 }
382 }
383 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
384 $tmpcontent = dol_htmlentitiesbr($value);
385 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
386 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
387 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
388 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
389 }
390 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
391 // clean data from some dangerous html
393 } else {
394 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
395 $ret .= dol_escape_htmltag($value);
396 } else {
397 $ret .= $value; // $value must be already html escaped.
398 }
399 }
400
401 // Custom format if parameter $formatfunc has been provided
402 if ($formatfunc && method_exists($object, $formatfunc)) {
403 $ret = $object->$formatfunc($ret);
404 }
405 }
406 }
407 return $ret;
408 }
409
421 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
422 {
423 global $conf, $langs, $extralanguages;
424
425 $result = '';
426
427 // List of extra languages
428 $arrayoflangcode = array();
429 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
430 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
431 }
432
433 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
434 if (!is_object($extralanguages)) {
435 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
436 $extralanguages = new ExtraLanguages($this->db);
437 }
438 $extralanguages->fetch_name_extralanguages('societe');
439
440 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
441 return ''; // No extralang field to show
442 }
443
444 $result .= '<!-- Widget for translation -->' . "\n";
445 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
446 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', 0, 0, 0, '', 'fa-15 editfieldlang');
447 $result .= $s;
448 $result .= '</div>';
449
450 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
451
452 $resultforextrlang = '';
453 foreach ($arrayoflangcode as $langcode) {
454 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
455 if (empty($valuetoshow)) {
456 $object->fetchValuesForExtraLanguages();
457 //var_dump($object->array_languages);
458 $valuetoshow = $object->array_languages[$fieldname][$langcode];
459 }
460
461 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
462 $resultforextrlang .= $s;
463
464 // TODO Use the showInputField() method of ExtraLanguages object
465 if ($typeofdata == 'textarea') {
466 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
467 $resultforextrlang .= $valuetoshow;
468 $resultforextrlang .= '</textarea>';
469 } else {
470 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
471 }
472 }
473 $result .= $resultforextrlang;
474
475 $result .= '</div>';
476 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
477 }
478
479 return $result;
480 }
481
495 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
496 {
497 $out = '';
498
499 // Check parameters
500 if (preg_match('/^text/', $inputType)) {
501 $value = dol_nl2br($value);
502 } elseif (preg_match('/^numeric/', $inputType)) {
503 $value = price($value);
504 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
505 $value = dol_print_date($value, 'day');
506 }
507
508 if ($condition) {
509 $element = false;
510 $table_element = false;
511 $fk_element = false;
512 $loadmethod = false;
513 $savemethod = false;
514 $ext_element = false;
515 $button_only = false;
516 $inputOption = '';
517 $rows = '';
518 $cols = '';
519
520 if (is_object($object)) {
521 $element = $object->element;
522 $table_element = $object->table_element;
523 $fk_element = $object->id;
524 }
525
526 if (is_object($extObject)) {
527 $ext_element = $extObject->element;
528 }
529
530 if (preg_match('/^(string|email|numeric)/', $inputType)) {
531 $tmp = explode(':', $inputType);
532 $inputType = $tmp[0];
533 if (!empty($tmp[1])) {
534 $inputOption = $tmp[1];
535 }
536 if (!empty($tmp[2])) {
537 $savemethod = $tmp[2];
538 }
539 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
540 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
541 $tmp = explode(':', $inputType);
542 $inputType = $tmp[0];
543 if (!empty($tmp[1])) {
544 $inputOption = $tmp[1];
545 }
546 if (!empty($tmp[2])) {
547 $savemethod = $tmp[2];
548 }
549
550 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
551 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
552 $tmp = explode(':', $inputType);
553 $inputType = $tmp[0];
554 $loadmethod = $tmp[1];
555 if (!empty($tmp[2])) {
556 $savemethod = $tmp[2];
557 }
558 if (!empty($tmp[3])) {
559 $button_only = true;
560 }
561 } elseif (preg_match('/^textarea/', $inputType)) {
562 $tmp = explode(':', $inputType);
563 $inputType = $tmp[0];
564 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
565 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
566 } elseif (preg_match('/^ckeditor/', $inputType)) {
567 $tmp = explode(':', $inputType);
568 $inputType = $tmp[0];
569 $toolbar = $tmp[1];
570 if (!empty($tmp[2])) {
571 $width = $tmp[2];
572 }
573 if (!empty($tmp[3])) {
574 $height = $tmp[3];
575 }
576 if (!empty($tmp[4])) {
577 $savemethod = $tmp[4];
578 }
579
580 if (isModEnabled('fckeditor')) {
581 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
582 } else {
583 $inputType = 'textarea';
584 }
585 }
586
587 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
588 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
589 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
590 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
591 if (!empty($savemethod)) {
592 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
593 }
594 if (!empty($ext_element)) {
595 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
596 }
597 if (!empty($custommsg)) {
598 if (is_array($custommsg)) {
599 if (!empty($custommsg['success'])) {
600 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
601 }
602 if (!empty($custommsg['error'])) {
603 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
604 }
605 } else {
606 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
607 }
608 }
609 if ($inputType == 'textarea') {
610 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
611 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
612 }
613 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
614 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
615 } else {
616 $out = $value;
617 }
618
619 return $out;
620 }
621
640 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
641 {
642 if ($incbefore) {
643 $text = $incbefore . $text;
644 }
645 if (!$htmltext) {
646 return $text;
647 }
648 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
649
650 $tag = 'td';
651 if ($notabs == 2) {
652 $tag = 'div';
653 }
654 if ($notabs == 3) {
655 $tag = 'span';
656 }
657 // Sanitize tooltip
658 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
659
660 $extrastyle = '';
661 if ($direction < 0) {
662 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
663 $extrastyle = 'padding: 0px; padding-left: 2px;';
664 }
665 if ($direction > 0) {
666 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
667 $extrastyle = 'padding: 0px; padding-right: 2px;';
668 }
669
670 $classfortooltip = 'classfortooltip';
671
672 $s = '';
673 $textfordialog = '';
674
675 if ($tooltiptrigger == '') {
676 $htmltext = str_replace('"', '&quot;', $htmltext);
677 } else {
678 $classfortooltip = 'classfortooltiponclick';
679 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
680 }
681 if ($tooltipon == 2 || $tooltipon == 3) {
682 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
683 if ($tooltiptrigger == '') {
684 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
685 } else {
686 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
687 }
688 } else {
689 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
690 }
691 if ($tooltipon == 1 || $tooltipon == 3) {
692 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
693 if ($tooltiptrigger == '') {
694 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
695 } else {
696 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
697 }
698 } else {
699 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
700 }
701 if (empty($notabs)) {
702 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
703 } elseif ($notabs == 2) {
704 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
705 }
706 // Define value if value is before
707 if ($direction < 0) {
708 $s .= '<' . $tag . $paramfortooltipimg;
709 if ($tag == 'td') {
710 $s .= ' class="valigntop" width="14"';
711 }
712 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
713 }
714 // Use another method to help avoid having a space in value in order to use this value with jquery
715 // Define label
716 if ((string) $text != '') {
717 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
718 }
719 // Define value if value is after
720 if ($direction > 0) {
721 $s .= '<' . $tag . $paramfortooltipimg;
722 if ($tag == 'td') {
723 $s .= ' class="valignmiddle" width="14"';
724 }
725 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
726 }
727 if (empty($notabs)) {
728 $s .= '</tr></table>';
729 } elseif ($notabs == 2) {
730 $s .= '</div>';
731 }
732
733 return $s;
734 }
735
750 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = 'valignmiddle', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
751 {
752 global $conf, $langs;
753
754 //For backwards compatibility
755 if ($type == '0') {
756 $type = 'info';
757 } elseif ($type == '1') {
758 $type = 'help';
759 }
760 // Clean parameters
761 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
762
763 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
764 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
765 }
766 $alt = '';
767 if ($tooltiptrigger) {
768 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
769 }
770
771 // If info or help with no javascript, show only text
772 if (empty($conf->use_javascript_ajax)) {
773 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
774 return $text;
775 } else {
776 $alt = $htmltext;
777 $htmltext = '';
778 }
779 }
780
781 // If info or help with smartphone, show only text (tooltip hover can't works)
782 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
783 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
784 return $text;
785 }
786 }
787 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
788 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
789 //{
790 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
791 //}
792
793 $img = '';
794 if ($type == 'info') {
795 $img = img_help(0, $alt);
796 } elseif ($type == 'help') {
797 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
798 } elseif ($type == 'helpclickable') {
799 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
800 } elseif ($type == 'superadmin') {
801 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
802 $img = img_picto($alt, 'redstar');
803 } elseif ($type == 'admin') {
804 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
805 $img = img_picto($alt, 'star');
806 } elseif ($type == 'warning') {
807 $img = img_warning($alt);
808 } elseif ($type != 'none') {
809 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
810 $img = img_picto($alt, $type); // $type can be an image path
811 }
812
813 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
814 }
815
826 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
827 {
828 global $conf, $langs, $hookmanager;
829
830 $disabled = 0;
831 $ret = '<div class="centpercent center">';
832 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
833
834 // Complete list with data from external modules. THe module can use $_SERVER['PHP_SELF'] to know on which page we are, or use the $parameters['currentcontext'] completed by executeHooks.
835 $parameters = array();
836 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
837 // check if there is a mass action
838
839 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
840 return;
841 }
842 if (empty($reshook)) {
843 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
844 if (is_array($arrayofaction)) {
845 foreach ($arrayofaction as $code => $label) {
846 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
847 }
848 }
849 }
850 $ret .= $hookmanager->resPrint;
851
852 $ret .= '</select>';
853
854 if (empty($conf->dol_optimize_smallscreen)) {
855 $ret .= ajax_combobox('.' . $name . 'select');
856 }
857
858 // Warning: if you set submit button to disabled, post using 'Enter' will no more work if there is no another input submit. So we add a hidden button
859 $ret .= '<input type="submit" name="confirmmassactioninvisible" style="display: none" tabindex="-1">'; // Hidden button BEFORE so it is the one used when we submit with ENTER.
860 $ret .= '<input type="submit" disabled name="confirmmassaction"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display: none"') . ' class="reposition button smallpaddingimp' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'confirmed" value="' . dol_escape_htmltag($langs->trans("Confirm")) . '">';
861 $ret .= '</div>';
862
863 if (!empty($conf->use_javascript_ajax)) {
864 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
865 <script nonce="' . getNonce() . '">
866 function initCheckForSelect(mode, name, cssclass) /* mode is 0 during init of page or click all, 1 when we click on 1 checkboxi, "name" refers to the class of the massaction button, "cssclass" to the class of the checkfor select boxes */
867 {
868 atleastoneselected=0;
869 jQuery("."+cssclass).each(function( index ) {
870 /* console.log( index + ": " + $( this ).text() ); */
871 if ($(this).is(\':checked\')) atleastoneselected++;
872 });
873
874 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
875
876 if (atleastoneselected || ' . $alwaysvisible . ')
877 {
878 jQuery("."+name).show();
879 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
880 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
881 }
882 else
883 {
884 jQuery("."+name).hide();
885 jQuery("."+name+"other").hide();
886 }
887 }
888
889 jQuery(document).ready(function () {
890 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
891 jQuery(".' . $cssclass . '").click(function() {
892 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
893 });
894 jQuery(".' . $name . 'select").change(function() {
895 var massaction = $( this ).val();
896 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
897 if (massaction == "builddoc") {
898 urlform = urlform + "#show_files";
899 }
900 $( this ).closest("form").attr("action", urlform);
901 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
902 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
903 if ($(this).val() != \'0\') {
904 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
905 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
906 jQuery(".' . $name . '"+massaction).show();
907 } else {
908 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
909 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
910 }
911 });
912 });
913 </script>
914 ';
915 }
916
917 return $ret;
918 }
919
920 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
921
938 public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0)
939 {
940 // phpcs:enable
941 global $conf, $langs, $mysoc;
942
943 $langs->load("dict");
944
945 $out = '';
946 $countryArray = array();
947 $favorite = array();
948 $label = array();
949 $atleastonefavorite = 0;
950
951 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
952 $sql .= " FROM " . $this->db->prefix() . "c_country";
953 $sql .= " WHERE active > 0";
954 //$sql.= " ORDER BY code ASC";
955
956 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
957 $resql = $this->db->query($sql);
958 if ($resql) {
959 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
960 $num = $this->db->num_rows($resql);
961 $i = 0;
962 if ($num) {
963 while ($i < $num) {
964 $obj = $this->db->fetch_object($resql);
965
966 $countryArray[$i]['rowid'] = $obj->rowid;
967 $countryArray[$i]['code_iso'] = $obj->code_iso;
968 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
969 $countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
970 $countryArray[$i]['favorite'] = $obj->favorite;
971 $countryArray[$i]['eec'] = $obj->eec;
972 $favorite[$i] = $obj->favorite;
973 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
974 $i++;
975 }
976
977 if (empty($disablefavorites)) {
978 $array1_sort_order = SORT_DESC;
979 $array2_sort_order = SORT_ASC;
980 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
981 } else {
982 $countryArray = dol_sort_array($countryArray, 'label');
983 }
984
985 if ($showempty) {
986 if (is_numeric($showempty)) {
987 $out .= '<option value="">&nbsp;</option>' . "\n";
988 } else {
989 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
990 }
991 }
992
993 if ($addspecialentries) { // Add dedicated entries for groups of countries
994 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
995 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
996 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
997 if ($mysoc->isInEEC()) {
998 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
999 }
1000 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1001 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1002 }
1003
1004 foreach ($countryArray as $row) {
1005 //if (empty($showempty) && empty($row['rowid'])) continue;
1006 if (empty($row['rowid'])) {
1007 continue;
1008 }
1009 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1010 continue; // exclude some countries
1011 }
1012
1013 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1014 $atleastonefavorite++;
1015 }
1016 if (empty($row['favorite']) && $atleastonefavorite) {
1017 $atleastonefavorite = 0;
1018 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1019 }
1020
1021 $labeltoshow = '';
1022 if ($row['label']) {
1023 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1024 } else {
1025 $labeltoshow .= '&nbsp;';
1026 }
1027 if ($row['code_iso']) {
1028 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1029 if (empty($hideflags)) {
1030 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1031 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1032 }
1033 }
1034
1035 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1036 $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1037 } else {
1038 $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1039 }
1040 $out .= $labeltoshow;
1041 $out .= '</option>' . "\n";
1042 }
1043 }
1044 $out .= '</select>';
1045 } else {
1046 dol_print_error($this->db);
1047 }
1048
1049 // Make select dynamic
1050 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1051 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1052
1053 return $out;
1054 }
1055
1056 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1057
1071 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1072 {
1073 // phpcs:enable
1074 global $conf, $langs;
1075
1076 $langs->load("dict");
1077
1078 $out = '';
1079 $moreattrib = '';
1080 $incotermArray = array();
1081
1082 $sql = "SELECT rowid, code";
1083 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1084 $sql .= " WHERE active > 0";
1085 $sql .= " ORDER BY code ASC";
1086
1087 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1088 $resql = $this->db->query($sql);
1089 if ($resql) {
1090 if ($conf->use_javascript_ajax && !$forcecombo) {
1091 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1092 $out .= ajax_combobox($htmlname, $events);
1093 }
1094
1095 if (!empty($page)) {
1096 $out .= '<form method="post" action="' . $page . '">';
1097 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1098 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1099 }
1100
1101 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1102 $out .= '<option value="0">&nbsp;</option>';
1103 $num = $this->db->num_rows($resql);
1104 $i = 0;
1105 if ($num) {
1106 while ($i < $num) {
1107 $obj = $this->db->fetch_object($resql);
1108 $incotermArray[$i]['rowid'] = $obj->rowid;
1109 $incotermArray[$i]['code'] = $obj->code;
1110 $i++;
1111 }
1112
1113 foreach ($incotermArray as $row) {
1114 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1115 $out .= '<option value="' . $row['rowid'] . '" selected>';
1116 } else {
1117 $out .= '<option value="' . $row['rowid'] . '">';
1118 }
1119
1120 if ($row['code']) {
1121 $out .= $row['code'];
1122 }
1123
1124 $out .= '</option>';
1125 }
1126 }
1127 $out .= '</select>';
1128 $out .= ajax_combobox($htmlname);
1129
1130 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1131 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1132 $moreattrib .= ' autocomplete="off"';
1133 }
1134 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1135
1136 if (!empty($page)) {
1137 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1138 }
1139 } else {
1140 dol_print_error($this->db);
1141 }
1142
1143 return $out;
1144 }
1145
1146 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1147
1160 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "")
1161 {
1162 // phpcs:enable
1163 global $langs;
1164
1165 // If product & services are enabled or both disabled.
1166 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1167 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1168 if (empty($hidetext)) {
1169 print $langs->trans("Type") . ': ';
1170 }
1171 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1172 if ($showempty) {
1173 print '<option value="-1"';
1174 if ($selected == -1) {
1175 print ' selected';
1176 }
1177 print '>';
1178 if (is_numeric($showempty)) {
1179 print '&nbsp;';
1180 } else {
1181 print $showempty;
1182 }
1183 print '</option>';
1184 }
1185
1186 print '<option value="0"';
1187 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1188 print ' selected';
1189 }
1190 print '>' . $langs->trans("Product");
1191
1192 print '<option value="1"';
1193 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1194 print ' selected';
1195 }
1196 print '>' . $langs->trans("Service");
1197
1198 print '</select>';
1199 print ajax_combobox('select_' . $htmlname);
1200 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1201 }
1202 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1203 print $langs->trans("Service");
1204 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1205 }
1206 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1207 print $langs->trans("Product");
1208 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1209 }
1210 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1211 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
1212 }
1213 }
1214
1215 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1216
1222 public function load_cache_types_fees()
1223 {
1224 // phpcs:enable
1225 global $langs;
1226
1227 $num = count($this->cache_types_fees);
1228 if ($num > 0) {
1229 return 0; // Cache already loaded
1230 }
1231
1232 dol_syslog(__METHOD__, LOG_DEBUG);
1233
1234 $langs->load("trips");
1235
1236 $sql = "SELECT c.code, c.label";
1237 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1238 $sql .= " WHERE active > 0";
1239
1240 $resql = $this->db->query($sql);
1241 if ($resql) {
1242 $num = $this->db->num_rows($resql);
1243 $i = 0;
1244
1245 while ($i < $num) {
1246 $obj = $this->db->fetch_object($resql);
1247
1248 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1249 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1250 $this->cache_types_fees[$obj->code] = $label;
1251 $i++;
1252 }
1253
1254 asort($this->cache_types_fees);
1255
1256 return $num;
1257 } else {
1258 dol_print_error($this->db);
1259 return -1;
1260 }
1261 }
1262
1263 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1264
1273 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1274 {
1275 // phpcs:enable
1276 global $user, $langs;
1277
1278 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1279
1280 $this->load_cache_types_fees();
1281
1282 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1283 if ($showempty) {
1284 print '<option value="-1"';
1285 if ($selected == -1) {
1286 print ' selected';
1287 }
1288 print '>&nbsp;</option>';
1289 }
1290
1291 foreach ($this->cache_types_fees as $key => $value) {
1292 print '<option value="' . $key . '"';
1293 if ($key == $selected) {
1294 print ' selected';
1295 }
1296 print '>';
1297 print $value;
1298 print '</option>';
1299 }
1300
1301 print '</select>';
1302 if ($user->admin) {
1303 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1304 }
1305 }
1306
1307
1308 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1309
1332 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)
1333 {
1334 // phpcs:enable
1335 global $conf, $langs;
1336
1337 $out = '';
1338
1339 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1340 if (is_null($ajaxoptions)) {
1341 $ajaxoptions = array();
1342 }
1343
1344 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1345
1346 // No immediate load of all database
1347 $placeholder = '';
1348 if ($selected && empty($selected_input_value)) {
1349 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1350 $societetmp = new Societe($this->db);
1351 $societetmp->fetch($selected);
1352 $selected_input_value = $societetmp->name;
1353 unset($societetmp);
1354 }
1355
1356 // mode 1
1357 $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)) : '');
1358
1359 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1360 if (empty($hidelabel)) {
1361 $out .= $langs->trans("RefOrLabel") . ' : ';
1362 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1363 $placeholder = $langs->trans($showempty);
1364 } elseif ($hidelabel > 1) {
1365 $placeholder = $langs->trans("RefOrLabel");
1366 if ($hidelabel == 2) {
1367 $out .= img_picto($langs->trans("Search"), 'search');
1368 }
1369 }
1370 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('THIRDPARTY_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1371 if ($hidelabel == 3) {
1372 $out .= img_picto($langs->trans("Search"), 'search');
1373 }
1374
1375 $out .= ajax_event($htmlname, $events);
1376
1377 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1378 } else {
1379 // Immediate load of all database
1380 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1381 }
1382
1383 return $out;
1384 }
1385
1386
1387 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1388
1414 public function select_contact($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $nokeyifsocid = true, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $selected_input_value = '', $filter = '')
1415 {
1416 // phpcs:enable
1417
1418 global $conf, $langs;
1419
1420 $out = '';
1421
1422 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1423 if ($nokeyifsocid && $socid > 0) {
1424 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1425 }
1426
1427 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1428 if (is_null($events)) {
1429 $events = array();
1430 }
1431
1432 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1433
1434 // No immediate load of all database
1435 $placeholder = '';
1436 if ($selected && empty($selected_input_value)) {
1437 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1438 $contacttmp = new Contact($this->db);
1439 $contacttmp->fetch($selected);
1440 $selected_input_value = $contacttmp->getFullName($langs);
1441 unset($contacttmp);
1442 }
1443 if (!is_numeric($showempty)) {
1444 $placeholder = $showempty;
1445 }
1446
1447 // mode 1
1448 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1449
1450 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1451
1452 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('CONTACT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1453
1454 $out .= ajax_event($htmlname, $events);
1455
1456 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1457 } else {
1458 // Immediate load of all database
1459 $multiple = false;
1460 $disableifempty = 0;
1461 $options_only = 0;
1462 $limitto = '';
1463
1464 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1465 }
1466
1467 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1468
1469 return $out;
1470 }
1471
1472
1473 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1474
1499 public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false, $excludeids = array(), $showcode = 0)
1500 {
1501 // phpcs:enable
1502 global $user, $langs;
1503 global $hookmanager;
1504
1505 $out = '';
1506 $num = 0;
1507 $outarray = array();
1508
1509 if ($selected === '') {
1510 $selected = array();
1511 } elseif (!is_array($selected)) {
1512 $selected = array($selected);
1513 }
1514
1515 // Clean $filter that may contains sql conditions so sql code
1516 if (function_exists('testSqlAndScriptInject')) {
1517 if (testSqlAndScriptInject($filter, 3) > 0) {
1518 $filter = '';
1519 return 'SQLInjectionTryDetected';
1520 }
1521 }
1522
1523 if ($filter != '') { // If a filter was provided
1524 if (preg_match('/[\‍(\‍)]/', $filter)) {
1525 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1526 $errormsg = '';
1527 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1528
1529 // Redo clean $filter that may contains sql conditions so sql code
1530 if (function_exists('testSqlAndScriptInject')) {
1531 if (testSqlAndScriptInject($filter, 3) > 0) {
1532 $filter = '';
1533 return 'SQLInjectionTryDetected';
1534 }
1535 }
1536 } else {
1537 // If not, we do nothing. We already know that there is no parenthesis
1538 // TODO Disallow this case in a future.
1539 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1540 }
1541 }
1542
1543 // We search companies
1544 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1545 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1546 $sql .= ", s.address, s.zip, s.town";
1547 $sql .= ", dictp.code as country_code";
1548 }
1549 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1550 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1551 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1552 }
1553 if (!$user->hasRight('societe', 'client', 'voir')) {
1554 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1555 }
1556 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1557 if (!empty($user->socid)) {
1558 $sql .= " AND s.rowid = " . ((int) $user->socid);
1559 }
1560 if ($filter) {
1561 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1562 // if not, by testSqlAndScriptInject() only.
1563 $sql .= " AND (" . $filter . ")";
1564 }
1565 if (!$user->hasRight('societe', 'client', 'voir')) {
1566 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1567 }
1568 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1569 $sql .= " AND s.status <> 0";
1570 }
1571 if (!empty($excludeids)) {
1572 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1573 }
1574 // Add where from hooks
1575 $parameters = array();
1576 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1577 $sql .= $hookmanager->resPrint;
1578 // Add criteria
1579 if ($filterkey && $filterkey != '') {
1580 $sql .= " AND (";
1581 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1582 // For natural search
1583 $search_crit = explode(' ', $filterkey);
1584 $i = 0;
1585 if (count($search_crit) > 1) {
1586 $sql .= "(";
1587 }
1588 foreach ($search_crit as $crit) {
1589 if ($i > 0) {
1590 $sql .= " AND ";
1591 }
1592 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1593 $i++;
1594 }
1595 if (count($search_crit) > 1) {
1596 $sql .= ")";
1597 }
1598 if (isModEnabled('barcode')) {
1599 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1600 }
1601 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1602 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1603 $sql .= ")";
1604 }
1605 $sql .= $this->db->order("nom", "ASC");
1606 $sql .= $this->db->plimit($limit, 0);
1607
1608 // Build output string
1609 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1610 $resql = $this->db->query($sql);
1611 if ($resql) {
1612 // Construct $out and $outarray
1613 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1614
1615 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1616 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1617 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1618 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1619 if ($showempty && !is_numeric($showempty)) {
1620 $textifempty = $langs->trans($showempty);
1621 } else {
1622 $textifempty .= $langs->trans("All");
1623 }
1624 }
1625 if ($showempty) {
1626 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1627 }
1628
1629 $companytemp = new Societe($this->db);
1630
1631 $num = $this->db->num_rows($resql);
1632 $i = 0;
1633 if ($num) {
1634 while ($i < $num) {
1635 $obj = $this->db->fetch_object($resql);
1636 $label = '';
1637 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1638 if (($obj->client) && (!empty($obj->code_client))) {
1639 $label = $obj->code_client . ' - ';
1640 }
1641 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1642 $label .= $obj->code_fournisseur . ' - ';
1643 }
1644 $label .= ' ' . $obj->name;
1645 } else {
1646 $label = $obj->name;
1647 }
1648
1649 if (!empty($obj->name_alias)) {
1650 $label .= ' (' . $obj->name_alias . ')';
1651 }
1652
1653 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1654 $label .= ' - '.$obj->tva_intra;
1655 }
1656
1657 $labelhtml = $label;
1658
1659 if ($showtype) {
1660 $companytemp->id = $obj->rowid;
1661 $companytemp->client = $obj->client;
1662 $companytemp->fournisseur = $obj->fournisseur;
1663 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1664 if ($tmptype) {
1665 $labelhtml .= ' ' . $tmptype;
1666 }
1667
1668 if ($obj->client || $obj->fournisseur) {
1669 $label .= ' (';
1670 }
1671 if ($obj->client == 1 || $obj->client == 3) {
1672 $label .= $langs->trans("Customer");
1673 }
1674 if ($obj->client == 2 || $obj->client == 3) {
1675 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1676 }
1677 if ($obj->fournisseur) {
1678 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1679 }
1680 if ($obj->client || $obj->fournisseur) {
1681 $label .= ')';
1682 }
1683 }
1684
1685 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1686 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1687 if (!empty($obj->country_code)) {
1688 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1689 }
1690 $label .= $s;
1691 $labelhtml .= $s;
1692 }
1693
1694 if (empty($outputmode)) {
1695 if (in_array($obj->rowid, $selected)) {
1696 $out .= '<option value="' . $obj->rowid . '" selected data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1697 } else {
1698 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1699 }
1700 } else {
1701 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1702 }
1703
1704 $i++;
1705 if (($i % 10) == 0) {
1706 $out .= "\n";
1707 }
1708 }
1709 }
1710 $out .= '</select>' . "\n";
1711 if (!$forcecombo) {
1712 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1713 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1714 }
1715 } else {
1716 dol_print_error($this->db);
1717 }
1718
1719 $this->result = array('nbofthirdparties' => $num);
1720
1721 if ($outputmode) {
1722 return $outarray;
1723 }
1724 return $out;
1725 }
1726
1727
1753 public function selectcontacts($socid, $selected = array(), $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = 0, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0, $filter = '')
1754 {
1755 global $conf, $user, $langs, $hookmanager, $action;
1756
1757 $langs->load('companies');
1758
1759 if (empty($htmlid)) {
1760 $htmlid = $htmlname;
1761 }
1762 $num = 0;
1763 $out = '';
1764 $outarray = array();
1765
1766 if ($selected === '') {
1767 $selected = array();
1768 } elseif (!is_array($selected)) {
1769 $selected = array((int) $selected);
1770 }
1771
1772 // Clean $filter that may contains sql conditions so sql code
1773 if (function_exists('testSqlAndScriptInject')) {
1774 if (testSqlAndScriptInject($filter, 3) > 0) {
1775 $filter = '';
1776 return 'SQLInjectionTryDetected';
1777 }
1778 }
1779
1780 if ($filter != '') { // If a filter was provided
1781 if (preg_match('/[\‍(\‍)]/', $filter)) {
1782 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1783 $errormsg = '';
1784 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1785
1786 // Redo clean $filter that may contains sql conditions so sql code
1787 if (function_exists('testSqlAndScriptInject')) {
1788 if (testSqlAndScriptInject($filter, 3) > 0) {
1789 $filter = '';
1790 return 'SQLInjectionTryDetected';
1791 }
1792 }
1793 } else {
1794 // If not, we do nothing. We already know that there is no parenthesis
1795 // TODO Disallow this case in a future by returning an error here.
1796 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1797 }
1798 }
1799
1800 if (!is_object($hookmanager)) {
1801 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1802 $hookmanager = new HookManager($this->db);
1803 }
1804
1805 // We search third parties
1806 $sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste, sp.email, sp.phone, sp.phone_perso, sp.phone_mobile, sp.town AS contact_town";
1807 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1808 $sql .= ", s.nom as company, s.town AS company_town";
1809 }
1810 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1811 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1812 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1813 }
1814 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1815 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1816 if ($socid > 0 || $socid == -1) {
1817 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1818 }
1819 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1820 $sql .= " AND sp.statut <> 0";
1821 }
1822 if ($filter) {
1823 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1824 // if not, by testSqlAndScriptInject() only.
1825 $sql .= " AND (" . $filter . ")";
1826 }
1827 // Add where from hooks
1828 $parameters = array();
1829 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1830 $sql .= $hookmanager->resPrint;
1831 $sql .= " ORDER BY sp.lastname ASC";
1832
1833 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1834 $resql = $this->db->query($sql);
1835 if ($resql) {
1836 $num = $this->db->num_rows($resql);
1837
1838 if ($htmlname != 'none' && !$options_only) {
1839 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1840 }
1841
1842 if ($showempty && !is_numeric($showempty)) {
1843 $textforempty = $showempty;
1844 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1845 } else {
1846 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1847 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1848 }
1849 if ($showempty == 2) {
1850 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1851 }
1852 }
1853
1854 $i = 0;
1855 if ($num) {
1856 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1857 $contactstatic = new Contact($this->db);
1858
1859 while ($i < $num) {
1860 $obj = $this->db->fetch_object($resql);
1861
1862 // Set email (or phones) and town extended infos
1863 $extendedInfos = '';
1864 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1865 $extendedInfos = array();
1866 $email = trim($obj->email);
1867 if (!empty($email)) {
1868 $extendedInfos[] = $email;
1869 } else {
1870 $phone = trim($obj->phone);
1871 $phone_perso = trim($obj->phone_perso);
1872 $phone_mobile = trim($obj->phone_mobile);
1873 if (!empty($phone)) {
1874 $extendedInfos[] = $phone;
1875 }
1876 if (!empty($phone_perso)) {
1877 $extendedInfos[] = $phone_perso;
1878 }
1879 if (!empty($phone_mobile)) {
1880 $extendedInfos[] = $phone_mobile;
1881 }
1882 }
1883 $contact_town = trim($obj->contact_town);
1884 $company_town = trim($obj->company_town);
1885 if (!empty($contact_town)) {
1886 $extendedInfos[] = $contact_town;
1887 } elseif (!empty($company_town)) {
1888 $extendedInfos[] = $company_town;
1889 }
1890 $extendedInfos = implode(' - ', $extendedInfos);
1891 if (!empty($extendedInfos)) {
1892 $extendedInfos = ' - ' . $extendedInfos;
1893 }
1894 }
1895
1896 $contactstatic->id = $obj->rowid;
1897 $contactstatic->lastname = $obj->lastname;
1898 $contactstatic->firstname = $obj->firstname;
1899 if ($obj->statut == 1) {
1900 $tmplabel = '';
1901 if ($htmlname != 'none') {
1902 $disabled = 0;
1903 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1904 $disabled = 1;
1905 }
1906 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1907 $disabled = 1;
1908 }
1909 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1910 $out .= '<option value="' . $obj->rowid . '"';
1911 if ($disabled) {
1912 $out .= ' disabled';
1913 }
1914 $out .= ' selected>';
1915
1916 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1917 if ($showfunction && $obj->poste) {
1918 $tmplabel .= ' (' . $obj->poste . ')';
1919 }
1920 if (($showsoc > 0) && $obj->company) {
1921 $tmplabel .= ' - (' . $obj->company . ')';
1922 }
1923
1924 $out .= $tmplabel;
1925 $out .= '</option>';
1926 } else {
1927 $out .= '<option value="' . $obj->rowid . '"';
1928 if ($disabled) {
1929 $out .= ' disabled';
1930 }
1931 $out .= '>';
1932
1933 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1934 if ($showfunction && $obj->poste) {
1935 $tmplabel .= ' (' . $obj->poste . ')';
1936 }
1937 if (($showsoc > 0) && $obj->company) {
1938 $tmplabel .= ' - (' . $obj->company . ')';
1939 }
1940
1941 $out .= $tmplabel;
1942 $out .= '</option>';
1943 }
1944 } else {
1945 if (in_array($obj->rowid, $selected)) {
1946 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1947 if ($showfunction && $obj->poste) {
1948 $tmplabel .= ' (' . $obj->poste . ')';
1949 }
1950 if (($showsoc > 0) && $obj->company) {
1951 $tmplabel .= ' - (' . $obj->company . ')';
1952 }
1953
1954 $out .= $tmplabel;
1955 }
1956 }
1957
1958 if ($tmplabel != '') {
1959 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1960 }
1961 }
1962 $i++;
1963 }
1964 } else {
1965 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1966 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1967 $out .= $labeltoshow;
1968 $out .= '</option>';
1969 }
1970
1971 $parameters = array(
1972 'socid' => $socid,
1973 'htmlname' => $htmlname,
1974 'resql' => $resql,
1975 'out' => &$out,
1976 'showfunction' => $showfunction,
1977 'showsoc' => $showsoc,
1978 );
1979
1980 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1981
1982 if ($htmlname != 'none' && !$options_only) {
1983 $out .= '</select>';
1984 }
1985
1986 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1987 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1988 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
1989 }
1990
1991 $this->num = $num;
1992
1993 if ($options_only === 2) {
1994 // Return array of options
1995 return $outarray;
1996 } else {
1997 return $out;
1998 }
1999 } else {
2000 dol_print_error($this->db);
2001 return -1;
2002 }
2003 }
2004
2005
2006 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2007
2018 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2019 {
2020 // phpcs:enable
2021 global $langs, $conf;
2022
2023 // On recherche les remises
2024 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2025 $sql .= " re.description, re.fk_facture_source";
2026 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2027 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2028 $sql .= " AND re.entity = " . $conf->entity;
2029 if ($filter) {
2030 $sql .= " AND " . $filter;
2031 }
2032 $sql .= " ORDER BY re.description ASC";
2033
2034 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2035 $resql = $this->db->query($sql);
2036 if ($resql) {
2037 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2038 $num = $this->db->num_rows($resql);
2039
2040 $qualifiedlines = $num;
2041
2042 $i = 0;
2043 if ($num) {
2044 print '<option value="0">&nbsp;</option>';
2045 while ($i < $num) {
2046 $obj = $this->db->fetch_object($resql);
2047 $desc = dol_trunc($obj->description, 40);
2048 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2049 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2050 }
2051 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2052 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2053 }
2054 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2055 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2056 }
2057 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2058 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2059 }
2060
2061 $selectstring = '';
2062 if ($selected > 0 && $selected == $obj->rowid) {
2063 $selectstring = ' selected';
2064 }
2065
2066 $disabled = '';
2067 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2068 $qualifiedlines--;
2069 $disabled = ' disabled';
2070 }
2071
2072 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2073 $tmpfac = new Facture($this->db);
2074 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2075 $desc = $desc . ' - ' . $tmpfac->ref;
2076 }
2077 }
2078
2079 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2080 $i++;
2081 }
2082 }
2083 print '</select>';
2084 print ajax_combobox('select_' . $htmlname);
2085
2086 return $qualifiedlines;
2087 } else {
2088 dol_print_error($this->db);
2089 return -1;
2090 }
2091 }
2092
2093
2094 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2095
2111 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2112 {
2113 // phpcs:enable
2114 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2115 }
2116
2117 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2118
2143 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2144 {
2145 // phpcs:enable
2146 global $conf, $user, $langs, $hookmanager;
2147 global $action;
2148
2149 // If no preselected user defined, we take current user
2150 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2151 $selected = $user->id;
2152 }
2153
2154 if ($selected === '') {
2155 $selected = array();
2156 } elseif (!is_array($selected)) {
2157 $selected = array($selected);
2158 }
2159
2160 $excludeUsers = null;
2161 $includeUsers = null;
2162
2163 // Exclude some users
2164 if (is_array($exclude)) {
2165 $excludeUsers = implode(",", $exclude);
2166 }
2167 // Include some uses
2168 if (is_array($include)) {
2169 $includeUsers = implode(",", $include);
2170 } elseif ($include == 'hierarchy') {
2171 // Build list includeUsers to have only hierarchy
2172 $includeUsers = implode(",", $user->getAllChildIds(0));
2173 } elseif ($include == 'hierarchyme') {
2174 // Build list includeUsers to have only hierarchy and current user
2175 $includeUsers = implode(",", $user->getAllChildIds(1));
2176 }
2177
2178 $num = 0;
2179
2180 $out = '';
2181 $outarray = array();
2182 $outarray2 = array();
2183
2184 // Do we want to show the label of entity into the combo list ?
2185 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2186 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2187
2188 // Forge request to select users
2189 $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.gender, u.photo";
2190 if ($showlabelofentity) {
2191 $sql .= ", e.label";
2192 }
2193 $sql .= " FROM " . $this->db->prefix() . "user as u";
2194 if ($showlabelofentity) {
2195 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2196 }
2197 // Condition here should be the same than into societe->getSalesRepresentatives().
2198 if ($userissuperadminentityone && $force_entity != 'default') {
2199 if (!empty($force_entity)) {
2200 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2201 } else {
2202 $sql .= " WHERE u.entity IS NOT NULL";
2203 }
2204 } else {
2205 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2206 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2207 } else {
2208 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2209 }
2210 }
2211
2212 if (!empty($user->socid)) {
2213 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2214 }
2215 if (is_array($exclude) && $excludeUsers) {
2216 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2217 }
2218 if ($includeUsers) {
2219 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2220 }
2221 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2222 $sql .= " AND u.statut <> 0";
2223 }
2224 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2225 $sql .= " AND u.employee <> 0";
2226 }
2227 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2228 $sql .= " AND u.fk_soc IS NULL";
2229 }
2230 if (!empty($morefilter)) {
2231 $sql .= " " . $morefilter;
2232 }
2233
2234 //Add hook to filter on user (for example on usergroup define in custom modules)
2235 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2236 if (!empty($reshook)) {
2237 $sql .= $hookmanager->resPrint;
2238 }
2239
2240 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2241 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2242 } else {
2243 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2244 }
2245
2246 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2247
2248 $resql = $this->db->query($sql);
2249 if ($resql) {
2250 $num = $this->db->num_rows($resql);
2251 $i = 0;
2252 if ($num) {
2253 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2254 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2255 if ($show_empty && !$multiple) {
2256 $textforempty = ' ';
2257 if (!empty($conf->use_javascript_ajax)) {
2258 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2259 }
2260 if (!is_numeric($show_empty)) {
2261 $textforempty = $show_empty;
2262 }
2263 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2264
2265 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2266 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2267 'id' => ($show_empty < 0 ? $show_empty : -1),
2268 'label' => $textforempty,
2269 'labelhtml' => $textforempty,
2270 'color' => '',
2271 'picto' => ''
2272 );
2273 }
2274 if ($show_every) {
2275 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2276
2277 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2278 $outarray2[-2] = array(
2279 'id' => -2,
2280 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2281 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2282 'color' => '',
2283 'picto' => ''
2284 );
2285 }
2286
2287 $userstatic = new User($this->db);
2288
2289 while ($i < $num) {
2290 $obj = $this->db->fetch_object($resql);
2291
2292 $userstatic->id = $obj->rowid;
2293 $userstatic->lastname = $obj->lastname;
2294 $userstatic->firstname = $obj->firstname;
2295 $userstatic->photo = $obj->photo;
2296 $userstatic->status = $obj->status;
2297 $userstatic->entity = $obj->entity;
2298 $userstatic->admin = $obj->admin;
2299 $userstatic->gender = $obj->gender;
2300
2301 $disableline = '';
2302 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2303 $disableline = ($enableonlytext ? $enableonlytext : '1');
2304 }
2305
2306 $labeltoshow = '';
2307 $labeltoshowhtml = '';
2308
2309 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2310 $fullNameMode = 0;
2311 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2312 $fullNameMode = 1; //Firstname+lastname
2313 }
2314 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2315 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2316 if (empty($obj->firstname) && empty($obj->lastname)) {
2317 $labeltoshow .= $obj->login;
2318 $labeltoshowhtml .= $obj->login;
2319 }
2320
2321 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2322 $moreinfo = '';
2323 $moreinfohtml = '';
2324 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2325 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2326 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2327 $moreinfo .= $obj->login;
2328 $moreinfohtml .= $obj->login;
2329 }
2330 if ($showstatus >= 0) {
2331 if ($obj->status == 1 && $showstatus == 1) {
2332 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2333 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2334 }
2335 if ($obj->status == 0 && $showstatus == 1) {
2336 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2337 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2338 }
2339 }
2340 if ($showlabelofentity) {
2341 if (empty($obj->entity)) {
2342 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2343 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2344 } else {
2345 if ($obj->entity != $conf->entity) {
2346 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2347 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2348 }
2349 }
2350 }
2351 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2352 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2353 if (!empty($disableline) && $disableline != '1') {
2354 // Add text from $enableonlytext parameter
2355 $moreinfo .= ' - ' . $disableline;
2356 $moreinfohtml .= ' - ' . $disableline;
2357 }
2358 $labeltoshow .= $moreinfo;
2359 $labeltoshowhtml .= $moreinfohtml;
2360
2361 $out .= '<option value="' . $obj->rowid . '"';
2362 if (!empty($disableline)) {
2363 $out .= ' disabled';
2364 }
2365 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2366 $out .= ' selected';
2367 }
2368 $out .= ' data-html="';
2369
2370 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2371 if ($showstatus >= 0 && $obj->status == 0) {
2372 $outhtml .= '<strike class="opacitymediumxxx">';
2373 }
2374 $outhtml .= $labeltoshowhtml;
2375 if ($showstatus >= 0 && $obj->status == 0) {
2376 $outhtml .= '</strike>';
2377 }
2378 $labeltoshowhtml = $outhtml;
2379
2380 $out .= dol_escape_htmltag($outhtml);
2381 $out .= '">';
2382 $out .= $labeltoshow;
2383 $out .= '</option>';
2384
2385 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2386 $outarray2[$userstatic->id] = array(
2387 'id' => $userstatic->id,
2388 'label' => $labeltoshow,
2389 'labelhtml' => $labeltoshowhtml,
2390 'color' => '',
2391 'picto' => ''
2392 );
2393
2394 $i++;
2395 }
2396 } else {
2397 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2398 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2399 }
2400 $out .= '</select>';
2401
2402 if ($num && !$forcecombo) {
2403 // Enhance with select2
2404 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2405 $out .= ajax_combobox($htmlname);
2406 }
2407 } else {
2408 dol_print_error($this->db);
2409 }
2410
2411 $this->num = $num;
2412
2413 if ($outputmode == 2) {
2414 return $outarray2;
2415 } elseif ($outputmode) {
2416 return $outarray;
2417 }
2418
2419 return $out;
2420 }
2421
2422
2423 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2446 public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array())
2447 {
2448 // phpcs:enable
2449 global $langs;
2450
2451 $userstatic = new User($this->db);
2452 $out = '';
2453
2454 if (!empty($_SESSION['assignedtouser'])) {
2455 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2456 if (!is_array($assignedtouser)) {
2457 $assignedtouser = array();
2458 }
2459 } else {
2460 $assignedtouser = array();
2461 }
2462 $nbassignetouser = count($assignedtouser);
2463
2464 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2465 if ($nbassignetouser) {
2466 $out .= '<ul class="attendees">';
2467 }
2468 $i = 0;
2469 $ownerid = 0;
2470 foreach ($assignedtouser as $key => $value) {
2471 if ($value['id'] == $ownerid) {
2472 continue;
2473 }
2474
2475 $out .= '<li>';
2476 $userstatic->fetch($value['id']);
2477 $out .= $userstatic->getNomUrl(-1);
2478 if ($i == 0) {
2479 $ownerid = $value['id'];
2480 $out .= ' (' . $langs->trans("Owner") . ')';
2481 }
2482 if ($nbassignetouser > 1 && $action != 'view') {
2483 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $userstatic->id . '" class="removedassigned reposition" id="removedassigned_' . $userstatic->id . '" name="removedassigned_' . $userstatic->id . '">';
2484 }
2485 // Show my availability
2486 if ($showproperties) {
2487 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2488 $out .= '<div class="myavailability inline-block">';
2489 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparency" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofuserid[$ownerid]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2490 $out .= '</div>';
2491 }
2492 }
2493 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2494 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2495
2496 $out .= '</li>';
2497 $i++;
2498 }
2499 if ($nbassignetouser) {
2500 $out .= '</ul>';
2501 }
2502
2503 // Method with no ajax
2504 if ($action != 'view') {
2505 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2506 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2507 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2508 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2509 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2510 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2511 $out .= '});';
2512 $out .= '})</script>';
2513 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2514 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2515 $out .= '<br>';
2516 }
2517
2518 return $out;
2519 }
2520
2521 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2541 public function select_dolresources_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofresourceid = array())
2542 {
2543 // phpcs:enable
2544 global $langs;
2545
2546 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2547 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2548 $formresources = new FormResource($this->db);
2549 $resourcestatic = new Dolresource($this->db);
2550
2551 $out = '';
2552 if (!empty($_SESSION['assignedtoresource'])) {
2553 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2554 if (!is_array($assignedtoresource)) {
2555 $assignedtoresource = array();
2556 }
2557 } else {
2558 $assignedtoresource = array();
2559 }
2560 $nbassignetoresource = count($assignedtoresource);
2561
2562 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2563 if ($nbassignetoresource) {
2564 $out .= '<ul class="attendees">';
2565 }
2566 $i = 0;
2567
2568 foreach ($assignedtoresource as $key => $value) {
2569 $out .= '<li>';
2570 $resourcestatic->fetch($value['id']);
2571 $out .= $resourcestatic->getNomUrl(-1);
2572 if ($nbassignetoresource >= 1 && $action != 'view') {
2573 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassignedresource reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2574 }
2575 // Show my availability
2576 if ($showproperties) {
2577 if (is_array($listofresourceid) && count($listofresourceid)) {
2578 $out .= '<div class="myavailability inline-block">';
2579 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparencyresource" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2580 $out .= '</div>';
2581 }
2582 }
2583 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2584 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2585
2586 $out .= '</li>';
2587 $i++;
2588 }
2589 if ($nbassignetoresource) {
2590 $out .= '</ul>';
2591 }
2592
2593 // Method with no ajax
2594 if ($action != 'view') {
2595 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2596 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2597 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2598 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2599 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2600 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2601 $out .= '});';
2602 $out .= '})</script>';
2603
2604 $events = array();
2605 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2606 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2607 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2608 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2609 $out .= '<br>';
2610 }
2611
2612 return $out;
2613 }
2614
2615 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2616
2646 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)
2647 {
2648 // phpcs:enable
2649 global $langs, $conf;
2650
2651 $out = '';
2652
2653 // check parameters
2654 $price_level = (!empty($price_level) ? $price_level : 0);
2655 if (is_null($ajaxoptions)) {
2656 $ajaxoptions = array();
2657 }
2658
2659 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2660 if (isModEnabled("product") && !isModEnabled('service')) {
2661 $filtertype = '0';
2662 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2663 $filtertype = '1';
2664 }
2665 }
2666
2667 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2668 $placeholder = (is_numeric($showempty) ? '' : 'placeholder="'.dolPrintHTML($showempty).'"');
2669
2670 if ($selected && empty($selected_input_value)) {
2671 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2672 $producttmpselect = new Product($this->db);
2673 $producttmpselect->fetch($selected);
2674 $selected_input_value = $producttmpselect->ref;
2675 unset($producttmpselect);
2676 }
2677 // handle case where product or service module is disabled + no filter specified
2678 if ($filtertype == '') {
2679 if (!isModEnabled('product')) { // when product module is disabled, show services only
2680 $filtertype = 1;
2681 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2682 $filtertype = 0;
2683 }
2684 }
2685 // mode=1 means customers products
2686 $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;
2687 if ((int) $warehouseId > 0) {
2688 $urloption .= '&warehouseid=' . (int) $warehouseId;
2689 }
2690
2691 $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);
2692
2693 if (isModEnabled('variants') && is_array($selected_combinations)) {
2694 // Code to automatically insert with javascript the select of attributes under the select of product
2695 // when a parent of variant has been selected.
2696 $out .= '
2697 <!-- script to auto show attributes select tags if a variant was selected -->
2698 <script nonce="' . getNonce() . '">
2699 // auto show attributes fields
2700 selected = ' . json_encode($selected_combinations) . ';
2701 combvalues = {};
2702
2703 jQuery(document).ready(function () {
2704
2705 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2706 if (jQuery(this).val() == \'free\') {
2707 jQuery(\'div#attributes_box\').empty();
2708 }
2709 });
2710
2711 jQuery("input#' . $htmlname . '").change(function () {
2712
2713 if (!jQuery(this).val()) {
2714 jQuery(\'div#attributes_box\').empty();
2715 return;
2716 }
2717
2718 console.log("A change has started. We get variants fields to inject html select");
2719
2720 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2721 id: jQuery(this).val()
2722 }, function (data) {
2723 jQuery(\'div#attributes_box\').empty();
2724
2725 jQuery.each(data, function (key, val) {
2726
2727 combvalues[val.id] = val.values;
2728
2729 var span = jQuery(document.createElement(\'div\')).css({
2730 \'display\': \'table-row\'
2731 });
2732
2733 span.append(
2734 jQuery(document.createElement(\'div\')).text(val.label).css({
2735 \'font-weight\': \'bold\',
2736 \'display\': \'table-cell\'
2737 })
2738 );
2739
2740 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2741 \'margin-left\': \'15px\',
2742 \'white-space\': \'pre\'
2743 }).append(
2744 jQuery(document.createElement(\'option\')).val(\'\')
2745 );
2746
2747 jQuery.each(combvalues[val.id], function (key, val) {
2748 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2749
2750 if (selected[val.fk_product_attribute] == val.id) {
2751 tag.attr(\'selected\', \'selected\');
2752 }
2753
2754 html.append(tag);
2755 });
2756
2757 span.append(html);
2758 jQuery(\'div#attributes_box\').append(span);
2759 });
2760 })
2761 });
2762
2763 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2764 });
2765 </script>
2766 ';
2767 }
2768
2769 if (empty($hidelabel)) {
2770 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2771 } elseif ($hidelabel > 1) {
2772 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2773 if ($hidelabel == 2) {
2774 $out .= img_picto($langs->trans("Search"), 'search');
2775 }
2776 }
2777
2778 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2779 if ($hidelabel == 3) {
2780 $out .= img_picto($langs->trans("Search"), 'search');
2781 }
2782 } else {
2783 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2784 }
2785
2786 if (empty($nooutput)) {
2787 print $out;
2788 } else {
2789 return $out;
2790 }
2791 }
2792
2793 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2794
2810 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2811 {
2812 // phpcs:enable
2813 global $db;
2814
2815 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2816
2817 $error = 0;
2818 $out = '';
2819
2820 if (!$forcecombo) {
2821 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2822 $events = array();
2823 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2824 }
2825
2826 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2827
2828 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2829 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2830 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2831 if (!empty($status)) {
2832 $sql .= ' AND status = ' . (int) $status;
2833 }
2834 if (!empty($type)) {
2835 $sql .= ' AND bomtype = ' . (int) $type;
2836 }
2837 if (!empty($TProducts)) {
2838 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2839 }
2840 if (!empty($limit)) {
2841 $sql .= ' LIMIT ' . (int) $limit;
2842 }
2843 $resql = $db->query($sql);
2844 if ($resql) {
2845 if ($showempty) {
2846 $out .= '<option value="-1"';
2847 if (empty($selected)) {
2848 $out .= ' selected';
2849 }
2850 $out .= '>&nbsp;</option>';
2851 }
2852 while ($obj = $db->fetch_object($resql)) {
2853 $product = new Product($db);
2854 $res = $product->fetch($obj->fk_product);
2855 $out .= '<option value="' . $obj->rowid . '"';
2856 if ($obj->rowid == $selected) {
2857 $out .= 'selected';
2858 }
2859 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2860 }
2861 } else {
2862 $error++;
2863 dol_print_error($db);
2864 }
2865 $out .= '</select>';
2866 if (empty($nooutput)) {
2867 print $out;
2868 } else {
2869 return $out;
2870 }
2871 }
2872
2873 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2874
2901 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)
2902 {
2903 // phpcs:enable
2904 global $langs;
2905 global $hookmanager;
2906
2907 $out = '';
2908 $outarray = array();
2909
2910 // Units
2911 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2912 $langs->load('other');
2913 }
2914
2915 $warehouseStatusArray = array();
2916 if (!empty($warehouseStatus)) {
2917 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2918 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2919 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2920 }
2921 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2922 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2923 }
2924 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2925 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2926 }
2927 }
2928
2929 $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";
2930 if (count($warehouseStatusArray)) {
2931 $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
2932 } else {
2933 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2934 }
2935
2936 $sql = "SELECT ";
2937
2938 // Add select from hooks
2939 $parameters = array();
2940 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2941 if (empty($reshook)) {
2942 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2943 } else {
2944 $sql .= $hookmanager->resPrint;
2945 }
2946
2947 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2948 //Product category
2949 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2950 FROM " . $this->db->prefix() . "categorie_product
2951 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2952 LIMIT 1
2953 ) AS categorie_product_id ";
2954 }
2955
2956 //Price by customer
2957 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
2958 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2959 $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';
2960 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2961 }
2962 // Units
2963 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2964 $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";
2965 $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';
2966 }
2967
2968 // Multilang : we add translation
2969 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2970 $sql .= ", pl.label as label_translated";
2971 $sql .= ", pl.description as description_translated";
2972 $selectFields .= ", label_translated";
2973 $selectFields .= ", description_translated";
2974 }
2975 // Price by quantity
2976 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2977 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2978 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2979 $sql .= " AND price_level = " . ((int) $price_level);
2980 }
2981 $sql .= " ORDER BY date_price";
2982 $sql .= " DESC LIMIT 1) as price_rowid";
2983 $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
2984 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2985 $sql .= " AND price_level = " . ((int) $price_level);
2986 }
2987 $sql .= " ORDER BY date_price";
2988 $sql .= " DESC LIMIT 1) as price_by_qty";
2989 $selectFields .= ", price_rowid, price_by_qty";
2990 }
2991
2992 $sql .= " FROM ".$this->db->prefix()."product as p";
2993
2994 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
2995 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
2996 }
2997
2998 // Add from (left join) from hooks
2999 $parameters = array();
3000 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3001 $sql .= $hookmanager->resPrint;
3002
3003 if (count($warehouseStatusArray)) {
3004 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
3005 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3006 $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.
3007 }
3008
3009 // include search in supplier ref
3010 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3011 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3012 }
3013
3014 //Price by customer
3015 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3016 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
3017 }
3018 // Units
3019 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3020 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3021 }
3022 // Multilang : we add translation
3023 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3024 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3025 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3026 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3027 $soc = new Societe($this->db);
3028 $result = $soc->fetch($socid);
3029 if ($result > 0 && !empty($soc->default_lang)) {
3030 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3031 } else {
3032 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3033 }
3034 } else {
3035 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3036 }
3037 }
3038
3039 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3040 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3041 }
3042
3043 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3044
3045 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3046 $sql .= " AND pac.rowid IS NULL";
3047 }
3048
3049 if ($finished == 0) {
3050 $sql .= " AND p.finished = " . ((int) $finished);
3051 } elseif ($finished == 1) {
3052 $sql .= " AND p.finished = ".((int) $finished);
3053 }
3054 if ($status >= 0) {
3055 $sql .= " AND p.tosell = ".((int) $status);
3056 }
3057 if ($status_purchase >= 0) {
3058 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3059 }
3060 // Filter by product type
3061 if (strval($filtertype) != '') {
3062 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3063 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3064 $sql .= " AND p.fk_product_type = 1";
3065 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3066 $sql .= " AND p.fk_product_type = 0";
3067 }
3068
3069 if ((int) $warehouseId > 0) {
3070 $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)";
3071 }
3072
3073 // Add where from hooks
3074 $parameters = array();
3075 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3076 $sql .= $hookmanager->resPrint;
3077 // Add criteria on ref/label
3078 if ($filterkey != '') {
3079 $sql .= ' AND (';
3080 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3081 // For natural search
3082 $search_crit = explode(' ', $filterkey);
3083 $i = 0;
3084 if (count($search_crit) > 1) {
3085 $sql .= "(";
3086 }
3087 foreach ($search_crit as $crit) {
3088 if ($i > 0) {
3089 $sql .= " AND ";
3090 }
3091 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3092 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3093 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3094 }
3095 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3096 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3097 }
3098 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3099 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3100 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3101 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3102 }
3103 }
3104 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3105 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3106 }
3107 $sql .= ")";
3108 $i++;
3109 }
3110 if (count($search_crit) > 1) {
3111 $sql .= ")";
3112 }
3113 if (isModEnabled('barcode')) {
3114 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3115 }
3116 $sql .= ')';
3117 }
3118 if (count($warehouseStatusArray)) {
3119 $sql .= " GROUP BY " . $selectFields;
3120 }
3121
3122 //Sort by category
3123 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3124 $sql .= " ORDER BY categorie_product_id ";
3125 //ASC OR DESC order
3126 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3127 } else {
3128 $sql .= $this->db->order("p.ref");
3129 }
3130
3131 $sql .= $this->db->plimit($limit, 0);
3132
3133 // Build output string
3134 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3135 $result = $this->db->query($sql);
3136 if ($result) {
3137 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3138 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3139 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3140
3141 $num = $this->db->num_rows($result);
3142
3143 $events = array();
3144
3145 if (!$forcecombo) {
3146 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3147 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3148 }
3149
3150 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3151
3152 $textifempty = '';
3153 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3154 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3155 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3156 if ($showempty && !is_numeric($showempty)) {
3157 $textifempty = $langs->trans($showempty);
3158 } else {
3159 $textifempty .= $langs->trans("All");
3160 }
3161 } else {
3162 if ($showempty && !is_numeric($showempty)) {
3163 $textifempty = $langs->trans($showempty);
3164 }
3165 }
3166 if ($showempty) {
3167 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3168 }
3169
3170 $i = 0;
3171 while ($num && $i < $num) {
3172 $opt = '';
3173 $optJson = array();
3174 $objp = $this->db->fetch_object($result);
3175
3176 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
3177 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3178 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3179 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3180 $sql .= " ORDER BY quantity ASC";
3181
3182 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3183 $result2 = $this->db->query($sql);
3184 if ($result2) {
3185 $nb_prices = $this->db->num_rows($result2);
3186 $j = 0;
3187 while ($nb_prices && $j < $nb_prices) {
3188 $objp2 = $this->db->fetch_object($result2);
3189
3190 $objp->price_by_qty_rowid = $objp2->rowid;
3191 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3192 $objp->price_by_qty_quantity = $objp2->quantity;
3193 $objp->price_by_qty_unitprice = $objp2->unitprice;
3194 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3195 // For backward compatibility
3196 $objp->quantity = $objp2->quantity;
3197 $objp->price = $objp2->price;
3198 $objp->unitprice = $objp2->unitprice;
3199 $objp->remise_percent = $objp2->remise_percent;
3200
3201 //$objp->tva_tx is not overwritten by $objp2 value
3202 //$objp->default_vat_code is not overwritten by $objp2 value
3203
3204 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3205 '@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';
3206 $j++;
3207
3208 // Add new entry
3209 // "key" value of json key array is used by jQuery automatically as selected value
3210 // "label" value of json key array is used by jQuery automatically as text for combo box
3211 $out .= $opt;
3212 array_push($outarray, $optJson);
3213 }
3214 }
3215 } else {
3216 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3217 $price_product = new Product($this->db);
3218 $price_product->fetch($objp->rowid, '', '', 1);
3219
3220 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3221 $priceparser = new PriceParser($this->db);
3222 $price_result = $priceparser->parseProduct($price_product);
3223 if ($price_result >= 0) {
3224 $objp->price = $price_result;
3225 $objp->unitprice = $price_result;
3226 //Calculate the VAT
3227 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3228 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3229 }
3230 }
3231 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3232 $price_level = '';
3233 }
3234 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3235 // Add new entry
3236 // "key" value of json key array is used by jQuery automatically as selected value
3237 // "label" value of json key array is used by jQuery automatically as text for combo box
3238 $out .= $opt;
3239 array_push($outarray, $optJson);
3240 }
3241
3242 $i++;
3243 }
3244
3245 $out .= '</select>';
3246
3247 $this->db->free($result);
3248
3249 if (empty($outputmode)) {
3250 return $out;
3251 }
3252
3253 return $outarray;
3254 } else {
3255 dol_print_error($this->db);
3256 }
3257
3258 return '';
3259 }
3260
3276 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3277 {
3278 global $langs, $conf, $user;
3279 global $hookmanager;
3280
3281 $outkey = '';
3282 $outval = '';
3283 $outref = '';
3284 $outlabel = '';
3285 $outlabel_translated = '';
3286 $outdesc = '';
3287 $outdesc_translated = '';
3288 $outbarcode = '';
3289 $outorigin = '';
3290 $outtype = '';
3291 $outprice_ht = '';
3292 $outprice_ttc = '';
3293 $outpricebasetype = '';
3294 $outtva_tx = '';
3295 $outdefault_vat_code = '';
3296 $outqty = 1;
3297 $outdiscount = 0;
3298
3299 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3300
3301 $label = $objp->label;
3302 if (!empty($objp->label_translated)) {
3303 $label = $objp->label_translated;
3304 }
3305 if (!empty($filterkey) && $filterkey != '') {
3306 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3307 }
3308
3309 $outkey = $objp->rowid;
3310 $outref = $objp->ref;
3311 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3312 $outlabel = $objp->label;
3313 $outdesc = $objp->description;
3314 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3315 $outlabel_translated = $objp->label_translated;
3316 $outdesc_translated = $objp->description_translated;
3317 }
3318 $outbarcode = $objp->barcode;
3319 $outorigin = $objp->fk_country;
3320 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3321
3322 $outtype = $objp->fk_product_type;
3323 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3324 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3325
3326 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3327 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3328 }
3329
3330 // Units
3331 $outvalUnits = '';
3332 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3333 if (!empty($objp->unit_short)) {
3334 $outvalUnits .= ' - ' . $objp->unit_short;
3335 }
3336 }
3337 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3338 if (!empty($objp->weight) && $objp->weight_units !== null) {
3339 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3340 $outvalUnits .= ' - ' . $unitToShow;
3341 }
3342 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3343 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3344 $outvalUnits .= ' - ' . $unitToShow;
3345 }
3346 if (!empty($objp->surface) && $objp->surface_units !== null) {
3347 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3348 $outvalUnits .= ' - ' . $unitToShow;
3349 }
3350 if (!empty($objp->volume) && $objp->volume_units !== null) {
3351 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3352 $outvalUnits .= ' - ' . $unitToShow;
3353 }
3354 }
3355 if ($outdurationvalue && $outdurationunit) {
3356 $da = array(
3357 'h' => $langs->trans('Hour'),
3358 'd' => $langs->trans('Day'),
3359 'w' => $langs->trans('Week'),
3360 'm' => $langs->trans('Month'),
3361 'y' => $langs->trans('Year')
3362 );
3363 if (isset($da[$outdurationunit])) {
3364 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3365 }
3366 }
3367
3368 // Set stocktag (stock too low or not or unknown)
3369 $stocktag = 0;
3370 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3371 if ($user->hasRight('stock', 'lire')) {
3372 if ($objp->stock > 0) {
3373 $stocktag = 1;
3374 } elseif ($objp->stock <= 0) {
3375 $stocktag = -1;
3376 }
3377 }
3378 }
3379
3380 // Set $labeltoshow
3381 $labeltoshow = '';
3382 $labeltoshow .= $objp->ref;
3383 if (!empty($objp->custref)) {
3384 $labeltoshow .= ' (' . $objp->custref . ')';
3385 }
3386 if ($outbarcode) {
3387 $labeltoshow .= ' (' . $outbarcode . ')';
3388 }
3389 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3390 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3391 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3392 }
3393
3394 // Set $labltoshowhtml
3395 $labeltoshowhtml = '';
3396 $labeltoshowhtml .= $objp->ref;
3397 if (!empty($objp->custref)) {
3398 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3399 }
3400 if (!empty($filterkey) && $filterkey != '') {
3401 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3402 }
3403 if ($outbarcode) {
3404 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3405 }
3406 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3407 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3408 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3409 }
3410
3411 // Stock
3412 $labeltoshowstock = '';
3413 $labeltoshowhtmlstock = '';
3414 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3415 if ($user->hasRight('stock', 'lire')) {
3416 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3417
3418 if ($objp->stock > 0) {
3419 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3420 } elseif ($objp->stock <= 0) {
3421 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3422 }
3423 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3424 $labeltoshowhtmlstock .= '</span>';
3425
3426 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3427 $langs->load("stocks");
3428
3429 $tmpproduct = new Product($this->db);
3430 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3431 $tmpproduct->load_virtual_stock();
3432 $virtualstock = $tmpproduct->stock_theorique;
3433
3434 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3435
3436 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3437 if ($virtualstock > 0) {
3438 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3439 } elseif ($virtualstock <= 0) {
3440 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3441 }
3442 $labeltoshowhtmlstock .= $virtualstock;
3443 $labeltoshowhtmlstock .= '</span>';
3444
3445 unset($tmpproduct);
3446 }
3447 }
3448 }
3449
3450 // Price
3451 $found = 0;
3452 $labeltoshowprice = '';
3453 $labeltoshowhtmlprice = '';
3454 // If we need a particular price level (from 1 to n)
3455 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3456 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3457 $sql .= " FROM " . $this->db->prefix() . "product_price";
3458 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3459 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3460 $sql .= " AND price_level = " . ((int) $price_level);
3461 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3462 $sql .= " LIMIT 1";
3463
3464 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3465 $result2 = $this->db->query($sql);
3466 if ($result2) {
3467 $objp2 = $this->db->fetch_object($result2);
3468 if ($objp2) {
3469 $found = 1;
3470 if ($objp2->price_base_type == 'HT') {
3471 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3472 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3473 } else {
3474 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3475 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3476 }
3477 $outprice_ht = price($objp2->price);
3478 $outprice_ttc = price($objp2->price_ttc);
3479 $outpricebasetype = $objp2->price_base_type;
3480 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3481 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3482 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3483 } else {
3484 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3485 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3486 }
3487 }
3488 } else {
3489 dol_print_error($this->db);
3490 }
3491 }
3492
3493 // Price by quantity
3494 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3495 $found = 1;
3496 $outqty = $objp->quantity;
3497 $outdiscount = $objp->remise_percent;
3498 if ($objp->quantity == 1) {
3499 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3500 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3501 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3502 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3503 } else {
3504 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3505 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3506 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3507 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3508 }
3509
3510 $outprice_ht = price($objp->unitprice);
3511 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3512 $outpricebasetype = $objp->price_base_type;
3513 $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
3514 $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
3515 }
3516 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3517 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3518 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3519 }
3520 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3521 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3522 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3523 }
3524
3525 // Price by customer
3526 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3527 if (!empty($objp->idprodcustprice)) {
3528 $found = 1;
3529
3530 if ($objp->custprice_base_type == 'HT') {
3531 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3532 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3533 } else {
3534 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3535 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3536 }
3537
3538 $outprice_ht = price($objp->custprice);
3539 $outprice_ttc = price($objp->custprice_ttc);
3540 $outpricebasetype = $objp->custprice_base_type;
3541 $outtva_tx = $objp->custtva_tx;
3542 $outdefault_vat_code = $objp->custdefault_vat_code;
3543 }
3544 }
3545
3546 // If level no defined or multiprice not found, we used the default price
3547 if (empty($hidepriceinlabel) && !$found) {
3548 if ($objp->price_base_type == 'HT') {
3549 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3550 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3551 } else {
3552 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3553 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3554 }
3555 $outprice_ht = price($objp->price);
3556 $outprice_ttc = price($objp->price_ttc);
3557 $outpricebasetype = $objp->price_base_type;
3558 $outtva_tx = $objp->tva_tx;
3559 $outdefault_vat_code = $objp->default_vat_code;
3560 }
3561
3562 // Build options
3563 $opt = '<option value="' . $objp->rowid . '"';
3564 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3565 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3566 $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 . '"';
3567 }
3568 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3569 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3570 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3571 }
3572
3573 if ($stocktag == 1) {
3574 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3575 //$opt .= ' class="product_line_stock_ok"';
3576 }
3577 if ($stocktag == -1) {
3578 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3579 //$opt .= ' class="product_line_stock_too_low"';
3580 }
3581
3582 $opt .= '>';
3583
3584 // Ref, barcode, country
3585 $opt .= $labeltoshow;
3586 $outval .= $labeltoshowhtml;
3587
3588 // Units
3589 $opt .= $outvalUnits;
3590 $outval .= $outvalUnits;
3591
3592 // Price
3593 $opt .= $labeltoshowprice;
3594 $outval .= $labeltoshowhtmlprice;
3595
3596 // Stock
3597 $opt .= $labeltoshowstock;
3598 $outval .= $labeltoshowhtmlstock;
3599
3600
3601 $parameters = array('objp' => $objp);
3602 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3603 if (empty($reshook)) {
3604 $opt .= $hookmanager->resPrint;
3605 } else {
3606 $opt = $hookmanager->resPrint;
3607 }
3608
3609 $opt .= "</option>\n";
3610 $optJson = array(
3611 'key' => $outkey,
3612 'value' => $outref,
3613 'label' => $outval,
3614 'label2' => $outlabel,
3615 'desc' => $outdesc,
3616 'type' => $outtype,
3617 'price_ht' => price2num($outprice_ht),
3618 'price_ttc' => price2num($outprice_ttc),
3619 'price_ht_locale' => price(price2num($outprice_ht)),
3620 'price_ttc_locale' => price(price2num($outprice_ttc)),
3621 'pricebasetype' => $outpricebasetype,
3622 'tva_tx' => $outtva_tx,
3623 'default_vat_code' => $outdefault_vat_code,
3624 'qty' => $outqty,
3625 'discount' => $outdiscount,
3626 'duration_value' => $outdurationvalue,
3627 'duration_unit' => $outdurationunit,
3628 'pbq' => $outpbq,
3629 'labeltrans' => $outlabel_translated,
3630 'desctrans' => $outdesc_translated,
3631 'ref_customer' => $outrefcust
3632 );
3633 }
3634
3635 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3636
3652 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3653 {
3654 // phpcs:enable
3655 global $langs, $conf;
3656 global $price_level, $status, $finished;
3657
3658 if (!isset($status)) {
3659 $status = 1;
3660 }
3661
3662 $selected_input_value = '';
3663 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3664 if ($selected > 0) {
3665 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3666 $producttmpselect = new Product($this->db);
3667 $producttmpselect->fetch($selected);
3668 $selected_input_value = $producttmpselect->ref;
3669 unset($producttmpselect);
3670 }
3671
3672 // mode=2 means suppliers products
3673 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3674 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3675
3676 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3677 } else {
3678 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3679 }
3680 }
3681
3682 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3683
3702 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 = '')
3703 {
3704 // phpcs:enable
3705 global $langs, $conf, $user;
3706 global $hookmanager;
3707
3708 $out = '';
3709 $outarray = array();
3710
3711 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3712
3713 $langs->load('stocks');
3714 // Units
3715 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3716 $langs->load('other');
3717 }
3718
3719 $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,";
3720 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3721 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3722 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3723 $sql .= ", pfp.supplier_reputation";
3724 // if we use supplier description of the products
3725 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3726 $sql .= ", pfp.desc_fourn as description";
3727 } else {
3728 $sql .= ", p.description";
3729 }
3730 // Units
3731 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3732 $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";
3733 }
3734 $sql .= " FROM " . $this->db->prefix() . "product as p";
3735 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3736 if ($socid > 0) {
3737 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3738 }
3739 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3740 // Units
3741 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3742 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3743 }
3744 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3745 if ($statut != -1) {
3746 $sql .= " AND p.tobuy = " . ((int) $statut);
3747 }
3748 if (strval($filtertype) != '') {
3749 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3750 }
3751 if (!empty($filtre)) {
3752 $sql .= " " . $filtre;
3753 }
3754 // Add where from hooks
3755 $parameters = array();
3756 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3757 $sql .= $hookmanager->resPrint;
3758 // Add criteria on ref/label
3759 if ($filterkey != '') {
3760 $sql .= ' AND (';
3761 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3762 // For natural search
3763 $search_crit = explode(' ', $filterkey);
3764 $i = 0;
3765 if (count($search_crit) > 1) {
3766 $sql .= "(";
3767 }
3768 foreach ($search_crit as $crit) {
3769 if ($i > 0) {
3770 $sql .= " AND ";
3771 }
3772 $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) . "%'";
3773 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3774 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3775 }
3776 $sql .= ")";
3777 $i++;
3778 }
3779 if (count($search_crit) > 1) {
3780 $sql .= ")";
3781 }
3782 if (isModEnabled('barcode')) {
3783 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3784 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3785 }
3786 $sql .= ')';
3787 }
3788 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3789 $sql .= $this->db->plimit($limit, 0);
3790
3791 // Build output string
3792
3793 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3794 $result = $this->db->query($sql);
3795 if ($result) {
3796 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3797 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3798
3799 $num = $this->db->num_rows($result);
3800
3801 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3802 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3803 if (!$selected) {
3804 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3805 } else {
3806 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3807 }
3808
3809 $i = 0;
3810 while ($i < $num) {
3811 $objp = $this->db->fetch_object($result);
3812
3813 if (is_null($objp->idprodfournprice)) {
3814 // There is no supplier price found, we will use the vat rate for sale
3815 $objp->tva_tx = $objp->tva_tx_sale;
3816 $objp->default_vat_code = $objp->default_vat_code_sale;
3817 }
3818
3819 $outkey = $objp->idprodfournprice; // id in table of price
3820 if (!$outkey && $alsoproductwithnosupplierprice) {
3821 $outkey = 'idprod_' . $objp->rowid; // id of product
3822 }
3823
3824 $outref = $objp->ref;
3825 $outbarcode = $objp->barcode;
3826 $outqty = 1;
3827 $outdiscount = 0;
3828 $outtype = $objp->fk_product_type;
3829 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3830 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3831
3832 // Units
3833 $outvalUnits = '';
3834 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3835 if (!empty($objp->unit_short)) {
3836 $outvalUnits .= ' - ' . $objp->unit_short;
3837 }
3838 if (!empty($objp->weight) && $objp->weight_units !== null) {
3839 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3840 $outvalUnits .= ' - ' . $unitToShow;
3841 }
3842 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3843 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3844 $outvalUnits .= ' - ' . $unitToShow;
3845 }
3846 if (!empty($objp->surface) && $objp->surface_units !== null) {
3847 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3848 $outvalUnits .= ' - ' . $unitToShow;
3849 }
3850 if (!empty($objp->volume) && $objp->volume_units !== null) {
3851 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3852 $outvalUnits .= ' - ' . $unitToShow;
3853 }
3854 if ($outdurationvalue && $outdurationunit) {
3855 $da = array(
3856 'h' => $langs->trans('Hour'),
3857 'd' => $langs->trans('Day'),
3858 'w' => $langs->trans('Week'),
3859 'm' => $langs->trans('Month'),
3860 'y' => $langs->trans('Year')
3861 );
3862 if (isset($da[$outdurationunit])) {
3863 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3864 }
3865 }
3866 }
3867
3868 $objRef = $objp->ref;
3869 if ($filterkey && $filterkey != '') {
3870 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3871 }
3872 $objRefFourn = $objp->ref_fourn;
3873 if ($filterkey && $filterkey != '') {
3874 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3875 }
3876 $label = $objp->label;
3877 if ($filterkey && $filterkey != '') {
3878 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3879 }
3880
3881 switch ($objp->fk_product_type) {
3883 $picto = 'product';
3884 break;
3886 $picto = 'service';
3887 break;
3888 default:
3889 $picto = '';
3890 break;
3891 }
3892
3893 if (empty($picto)) {
3894 $optlabel = '';
3895 } else {
3896 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3897 }
3898
3899 $optlabel .= $objp->ref;
3900 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3901 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3902 }
3903 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3904 $optlabel .= ' (' . $outbarcode . ')';
3905 }
3906 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3907
3908 $outvallabel = $objRef;
3909 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3910 $outvallabel .= ' (' . $objRefFourn . ')';
3911 }
3912 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3913 $outvallabel .= ' (' . $outbarcode . ')';
3914 }
3915 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3916
3917 // Units
3918 $optlabel .= $outvalUnits;
3919 $outvallabel .= $outvalUnits;
3920
3921 if (!empty($objp->idprodfournprice)) {
3922 $outqty = $objp->quantity;
3923 $outdiscount = $objp->remise_percent;
3924 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3925 $prod_supplier = new ProductFournisseur($this->db);
3926 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3927 $prod_supplier->id = $objp->fk_product;
3928 $prod_supplier->fourn_qty = $objp->quantity;
3929 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3930 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3931
3932 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3933 $priceparser = new PriceParser($this->db);
3934 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3935 if ($price_result >= 0) {
3936 $objp->fprice = $price_result;
3937 if ($objp->quantity >= 1) {
3938 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3939 }
3940 }
3941 }
3942 if ($objp->quantity == 1) {
3943 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3944 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3945 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3946 $outvallabel .= $langs->transnoentities("Unit");
3947 } else {
3948 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3949 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3950 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3951 $outvallabel .= ' ' . $langs->transnoentities("Units");
3952 }
3953
3954 if ($objp->quantity > 1) {
3955 $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
3956 $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
3957 }
3958 if ($objp->remise_percent >= 1) {
3959 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3960 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3961 }
3962 if ($objp->duration) {
3963 $optlabel .= " - " . $objp->duration;
3964 $outvallabel .= " - " . $objp->duration;
3965 }
3966 if (!$socid) {
3967 $optlabel .= " - " . dol_trunc($objp->name, 8);
3968 $outvallabel .= " - " . dol_trunc($objp->name, 8);
3969 }
3970 if ($objp->supplier_reputation) {
3971 //TODO dictionary
3972 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3973
3974 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3975 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3976 }
3977 } else {
3978 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3979 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3980 }
3981
3982 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3983 $novirtualstock = ($showstockinlist == 2);
3984
3985 if ($user->hasRight('stock', 'lire')) {
3986 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3987
3988 if ($objp->stock > 0) {
3989 $optlabel .= ' - <span class="product_line_stock_ok">';
3990 } elseif ($objp->stock <= 0) {
3991 $optlabel .= ' - <span class="product_line_stock_too_low">';
3992 }
3993 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3994 $optlabel .= '</span>';
3995 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3996 $langs->load("stocks");
3997
3998 $tmpproduct = new Product($this->db);
3999 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
4000 $tmpproduct->load_virtual_stock();
4001 $virtualstock = $tmpproduct->stock_theorique;
4002
4003 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4004
4005 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4006 if ($virtualstock > 0) {
4007 $optlabel .= '<span class="product_line_stock_ok">';
4008 } elseif ($virtualstock <= 0) {
4009 $optlabel .= '<span class="product_line_stock_too_low">';
4010 }
4011 $optlabel .= $virtualstock;
4012 $optlabel .= '</span>';
4013
4014 unset($tmpproduct);
4015 }
4016 }
4017 }
4018
4019 $optstart = '<option value="' . $outkey . '"';
4020 if ($selected && $selected == $objp->idprodfournprice) {
4021 $optstart .= ' selected';
4022 }
4023 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4024 $optstart .= ' disabled';
4025 }
4026
4027 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4028 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4029 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4030 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4031 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
4032 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
4033 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
4034 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
4035 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
4036 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4037 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4038 if (isModEnabled('multicurrency')) {
4039 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4040 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
4041 }
4042 }
4043 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4044
4045 // set $parameters to call hook
4046 $outarrayentry = array(
4047 'key' => $outkey,
4048 'value' => $outref,
4049 'label' => $outvallabel,
4050 'labelhtml' => $optlabel,
4051 'qty' => $outqty,
4052 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4053 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4054 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4055 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4056 'tva_tx' => price2num($objp->tva_tx),
4057 'default_vat_code' => $objp->default_vat_code,
4058 'supplier_ref' => $objp->ref_fourn,
4059 'discount' => $outdiscount,
4060 'type' => $outtype,
4061 'duration_value' => $outdurationvalue,
4062 'duration_unit' => $outdurationunit,
4063 'disabled' => empty($objp->idprodfournprice),
4064 'description' => $objp->description
4065 );
4066 if (isModEnabled('multicurrency')) {
4067 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4068 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4069 }
4070 $parameters = array(
4071 'objp' => &$objp,
4072 'optstart' => &$optstart,
4073 'optlabel' => &$optlabel,
4074 'outvallabel' => &$outvallabel,
4075 'outarrayentry' => &$outarrayentry,
4076 'fk_soc' => $socid
4077 );
4078 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4079
4080
4081 // Add new entry
4082 // "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
4083 // "label" value of json key array is used by jQuery automatically as text for combo box
4084 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4085 $outarraypush = array(
4086 'key' => $outkey,
4087 'value' => $outref,
4088 'label' => $outvallabel,
4089 'labelhtml' => $optlabel,
4090 'qty' => $outqty,
4091 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4092 'price_qty_ht_locale' => price($objp->fprice),
4093 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4094 'price_unit_ht_locale' => price($objp->unitprice),
4095 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4096 'tva_tx_formated' => price($objp->tva_tx),
4097 'tva_tx' => price2num($objp->tva_tx),
4098 'default_vat_code' => $objp->default_vat_code,
4099 'supplier_ref' => $objp->ref_fourn,
4100 'discount' => $outdiscount,
4101 'type' => $outtype,
4102 'duration_value' => $outdurationvalue,
4103 'duration_unit' => $outdurationunit,
4104 'disabled' => empty($objp->idprodfournprice),
4105 'description' => $objp->description
4106 );
4107 if (isModEnabled('multicurrency')) {
4108 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4109 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4110 }
4111 array_push($outarray, $outarraypush);
4112
4113 // Example of var_dump $outarray
4114 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4115 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4116 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4117 //}
4118 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4119 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4120 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4121
4122 $i++;
4123 }
4124 $out .= '</select>';
4125
4126 $this->db->free($result);
4127
4128 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4129 $out .= ajax_combobox($htmlname);
4130 } else {
4131 dol_print_error($this->db);
4132 }
4133
4134 if (empty($outputmode)) {
4135 return $out;
4136 }
4137 return $outarray;
4138 }
4139
4140 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4141
4150 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4151 {
4152 // phpcs:enable
4153 global $langs, $conf;
4154
4155 $langs->load('stocks');
4156
4157 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4158 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4159 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4160 $sql .= " FROM " . $this->db->prefix() . "product as p";
4161 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4162 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4163 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4164 $sql .= " AND p.tobuy = 1";
4165 $sql .= " AND s.fournisseur = 1";
4166 $sql .= " AND p.rowid = " . ((int) $productid);
4167 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4168 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4169 } else {
4170 $sql .= " ORDER BY pfp.unitprice ASC";
4171 }
4172
4173 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4174 $result = $this->db->query($sql);
4175
4176 if ($result) {
4177 $num = $this->db->num_rows($result);
4178
4179 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4180
4181 if (!$num) {
4182 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4183 } else {
4184 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4185 $form .= '<option value="0">&nbsp;</option>';
4186
4187 $i = 0;
4188 while ($i < $num) {
4189 $objp = $this->db->fetch_object($result);
4190
4191 $opt = '<option value="' . $objp->idprodfournprice . '"';
4192 //if there is only one supplier, preselect it
4193 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4194 $opt .= ' selected';
4195 }
4196 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4197
4198 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4199 $prod_supplier = new ProductFournisseur($this->db);
4200 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4201 $prod_supplier->id = $productid;
4202 $prod_supplier->fourn_qty = $objp->quantity;
4203 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4204 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4205
4206 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4207 $priceparser = new PriceParser($this->db);
4208 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4209 if ($price_result >= 0) {
4210 $objp->fprice = $price_result;
4211 if ($objp->quantity >= 1) {
4212 $objp->unitprice = $objp->fprice / $objp->quantity;
4213 }
4214 }
4215 }
4216 if ($objp->quantity == 1) {
4217 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4218 }
4219
4220 $opt .= $objp->quantity . ' ';
4221
4222 if ($objp->quantity == 1) {
4223 $opt .= $langs->trans("Unit");
4224 } else {
4225 $opt .= $langs->trans("Units");
4226 }
4227 if ($objp->quantity > 1) {
4228 $opt .= " - ";
4229 $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");
4230 }
4231 if ($objp->duration) {
4232 $opt .= " - " . $objp->duration;
4233 }
4234 $opt .= "</option>\n";
4235
4236 $form .= $opt;
4237 $i++;
4238 }
4239 }
4240
4241 $form .= '</select>';
4242 $this->db->free($result);
4243 return $form;
4244 } else {
4245 dol_print_error($this->db);
4246 return '';
4247 }
4248 }
4249
4250
4251 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4258 {
4259 // phpcs:enable
4260 global $langs;
4261
4262 $num = count($this->cache_conditions_paiements);
4263 if ($num > 0) {
4264 return 0; // Cache already loaded
4265 }
4266
4267 dol_syslog(__METHOD__, LOG_DEBUG);
4268
4269 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4270 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4271 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4272 $sql .= " AND active > 0";
4273 $sql .= " ORDER BY sortorder";
4274
4275 $resql = $this->db->query($sql);
4276 if ($resql) {
4277 $num = $this->db->num_rows($resql);
4278 $i = 0;
4279 while ($i < $num) {
4280 $obj = $this->db->fetch_object($resql);
4281
4282 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4283 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4284 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4285 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4286 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4287 $i++;
4288 }
4289
4290 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4291
4292 return $num;
4293 } else {
4294 dol_print_error($this->db);
4295 return -1;
4296 }
4297 }
4298
4299 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4300
4306 public function load_cache_availability()
4307 {
4308 // phpcs:enable
4309 global $langs;
4310
4311 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4312 if ($num > 0) {
4313 return 0; // Cache already loaded
4314 }
4315
4316 dol_syslog(__METHOD__, LOG_DEBUG);
4317
4318 $langs->load('propal');
4319
4320 $sql = "SELECT rowid, code, label, position";
4321 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4322 $sql .= " WHERE active > 0";
4323
4324 $resql = $this->db->query($sql);
4325 if ($resql) {
4326 $num = $this->db->num_rows($resql);
4327 $i = 0;
4328 while ($i < $num) {
4329 $obj = $this->db->fetch_object($resql);
4330
4331 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4332 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4333 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4334 $this->cache_availability[$obj->rowid]['label'] = $label;
4335 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4336 $i++;
4337 }
4338
4339 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4340
4341 return $num;
4342 } else {
4343 dol_print_error($this->db);
4344 return -1;
4345 }
4346 }
4347
4358 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4359 {
4360 global $langs, $user;
4361
4362 $this->load_cache_availability();
4363
4364 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4365
4366 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4367 if ($addempty) {
4368 print '<option value="0">&nbsp;</option>';
4369 }
4370 foreach ($this->cache_availability as $id => $arrayavailability) {
4371 if ($selected == $id) {
4372 print '<option value="' . $id . '" selected>';
4373 } else {
4374 print '<option value="' . $id . '">';
4375 }
4376 print dol_escape_htmltag($arrayavailability['label']);
4377 print '</option>';
4378 }
4379 print '</select>';
4380 if ($user->admin) {
4381 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4382 }
4383 print ajax_combobox($htmlname);
4384 }
4385
4391 public function loadCacheInputReason()
4392 {
4393 global $langs;
4394
4395 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4396 if ($num > 0) {
4397 return 0; // Cache already loaded
4398 }
4399
4400 $sql = "SELECT rowid, code, label";
4401 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4402 $sql .= " WHERE active > 0";
4403
4404 $resql = $this->db->query($sql);
4405 if ($resql) {
4406 $num = $this->db->num_rows($resql);
4407 $i = 0;
4408 $tmparray = array();
4409 while ($i < $num) {
4410 $obj = $this->db->fetch_object($resql);
4411
4412 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4413 $label = ($obj->label != '-' ? $obj->label : '');
4414 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4415 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4416 }
4417 if ($langs->trans($obj->code) != $obj->code) {
4418 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4419 }
4420
4421 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4422 $tmparray[$obj->rowid]['code'] = $obj->code;
4423 $tmparray[$obj->rowid]['label'] = $label;
4424 $i++;
4425 }
4426
4427 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4428
4429 unset($tmparray);
4430 return $num;
4431 } else {
4432 dol_print_error($this->db);
4433 return -1;
4434 }
4435 }
4436
4449 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4450 {
4451 global $langs, $user;
4452
4453 $this->loadCacheInputReason();
4454
4455 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4456 if ($addempty) {
4457 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4458 }
4459 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4460 if ($arraydemandreason['code'] == $exclude) {
4461 continue;
4462 }
4463
4464 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4465 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4466 } else {
4467 print '<option value="' . $arraydemandreason['id'] . '">';
4468 }
4469 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4470 print $langs->trans($label);
4471 print '</option>';
4472 }
4473 print '</select>';
4474 if ($user->admin && empty($notooltip)) {
4475 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4476 }
4477 print ajax_combobox('select_' . $htmlname);
4478 }
4479
4480 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4481
4488 {
4489 // phpcs:enable
4490 global $langs;
4491
4492 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4493 if ($num > 0) {
4494 return $num; // Cache already loaded
4495 }
4496
4497 dol_syslog(__METHOD__, LOG_DEBUG);
4498
4499 $this->cache_types_paiements = array();
4500
4501 $sql = "SELECT id, code, libelle as label, type, active";
4502 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4503 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4504
4505 $resql = $this->db->query($sql);
4506 if ($resql) {
4507 $num = $this->db->num_rows($resql);
4508 $i = 0;
4509 while ($i < $num) {
4510 $obj = $this->db->fetch_object($resql);
4511
4512 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4513 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4514 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4515 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4516 $this->cache_types_paiements[$obj->id]['label'] = $label;
4517 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4518 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4519 $i++;
4520 }
4521
4522 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4523
4524 return $num;
4525 } else {
4526 dol_print_error($this->db);
4527 return -1;
4528 }
4529 }
4530
4531
4532 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4533
4552 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4553 {
4554 // phpcs:enable
4555 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4556 if (empty($noprint)) {
4557 print $out;
4558 } else {
4559 return $out;
4560 }
4561 }
4562
4563
4580 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4581 {
4582 global $langs, $user, $conf;
4583
4584 $out = '';
4585 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4586
4588
4589 // Set default value if not already set by caller
4590 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4591 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4592 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4593 }
4594
4595 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4596 if ($addempty) {
4597 $out .= '<option value="0">&nbsp;</option>';
4598 }
4599
4600 $selectedDepositPercent = null;
4601
4602 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4603 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4604 continue;
4605 }
4606
4607 if ($selected == $id) {
4608 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4609 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4610 } else {
4611 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4612 }
4613 $label = $arrayconditions['label'];
4614
4615 if (!empty($arrayconditions['deposit_percent'])) {
4616 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4617 }
4618
4619 $out .= $label;
4620 $out .= '</option>';
4621 }
4622 $out .= '</select>';
4623 if ($user->admin && empty($noinfoadmin)) {
4624 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4625 }
4626 $out .= ajax_combobox($htmlname);
4627
4628 if ($deposit_percent >= 0) {
4629 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4630 $out .= $langs->trans('DepositPercent') . ' : ';
4631 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4632 $out .= '</span>';
4633 $out .= '
4634 <script nonce="' . getNonce() . '">
4635 $(document).ready(function () {
4636 $("#' . $htmlname . '").change(function () {
4637 let $selected = $(this).find("option:selected");
4638 let depositPercent = $selected.attr("data-deposit_percent");
4639
4640 if (depositPercent.length > 0) {
4641 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4642 } else {
4643 $("#' . $htmlname . '_deposit_percent_container").hide();
4644 }
4645
4646 return true;
4647 });
4648 });
4649 </script>';
4650 }
4651
4652 return $out;
4653 }
4654
4655
4656 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4657
4674 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4675 {
4676 // phpcs:enable
4677 global $langs, $user, $conf;
4678
4679 $out = '';
4680
4681 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4682
4683 $filterarray = array();
4684 if ($filtertype == 'CRDT') {
4685 $filterarray = array(0, 2, 3);
4686 } elseif ($filtertype == 'DBIT') {
4687 $filterarray = array(1, 2, 3);
4688 } elseif ($filtertype != '' && $filtertype != '-1') {
4689 $filterarray = explode(',', $filtertype);
4690 }
4691
4693
4694 // Set default value if not already set by caller
4695 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4696 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4697 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4698 }
4699
4700 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4701 if ($empty) {
4702 $out .= '<option value="">&nbsp;</option>';
4703 }
4704 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4705 // If not good status
4706 if ($active >= 0 && $arraytypes['active'] != $active) {
4707 continue;
4708 }
4709
4710 // We skip of the user requested to filter on specific payment methods
4711 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4712 continue;
4713 }
4714
4715 // We discard empty lines if showempty is on because an empty line has already been output.
4716 if ($empty && empty($arraytypes['code'])) {
4717 continue;
4718 }
4719
4720 if ($format == 0) {
4721 $out .= '<option value="' . $id . '" data-code="'.$arraytypes['code'].'"';
4722 } elseif ($format == 1) {
4723 $out .= '<option value="' . $arraytypes['code'] . '"';
4724 } elseif ($format == 2) {
4725 $out .= '<option value="' . $arraytypes['code'] . '"';
4726 } elseif ($format == 3) {
4727 $out .= '<option value="' . $id . '"';
4728 }
4729 // Print attribute selected or not
4730 if ($format == 1 || $format == 2) {
4731 if ($selected == $arraytypes['code']) {
4732 $out .= ' selected';
4733 }
4734 } else {
4735 if ($selected == $id) {
4736 $out .= ' selected';
4737 }
4738 }
4739 $out .= '>';
4740 $value = '';
4741 if ($format == 0) {
4742 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4743 } elseif ($format == 1) {
4744 $value = $arraytypes['code'];
4745 } elseif ($format == 2) {
4746 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4747 } elseif ($format == 3) {
4748 $value = $arraytypes['code'];
4749 }
4750 $out .= $value ? $value : '&nbsp;';
4751 $out .= '</option>';
4752 }
4753 $out .= '</select>';
4754 if ($user->admin && !$noadmininfo) {
4755 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4756 }
4757 $out .= ajax_combobox('select' . $htmlname);
4758
4759 if (empty($nooutput)) {
4760 print $out;
4761 } else {
4762 return $out;
4763 }
4764 }
4765
4766
4775 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4776 {
4777 global $langs;
4778
4779 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4780 $options = array(
4781 'HT' => $langs->trans("HT"),
4782 'TTC' => $langs->trans("TTC")
4783 );
4784 foreach ($options as $id => $value) {
4785 if ($selected == $id) {
4786 $return .= '<option value="' . $id . '" selected>' . $value;
4787 } else {
4788 $return .= '<option value="' . $id . '">' . $value;
4789 }
4790 $return .= '</option>';
4791 }
4792 $return .= '</select>';
4793 if ($addjscombo) {
4794 $return .= ajax_combobox('select_' . $htmlname);
4795 }
4796
4797 return $return;
4798 }
4799
4800 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4801
4808 {
4809 // phpcs:enable
4810 global $langs;
4811
4812 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4813 if ($num > 0) {
4814 return $num; // Cache already loaded
4815 }
4816
4817 dol_syslog(__METHOD__, LOG_DEBUG);
4818
4819 $this->cache_transport_mode = array();
4820
4821 $sql = "SELECT rowid, code, label, active";
4822 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4823 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4824
4825 $resql = $this->db->query($sql);
4826 if ($resql) {
4827 $num = $this->db->num_rows($resql);
4828 $i = 0;
4829 while ($i < $num) {
4830 $obj = $this->db->fetch_object($resql);
4831
4832 // If traduction exist, we use it else we take the default label
4833 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4834 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4835 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4836 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4837 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4838 $i++;
4839 }
4840
4841 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4842
4843 return $num;
4844 } else {
4845 dol_print_error($this->db);
4846 return -1;
4847 }
4848 }
4849
4863 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4864 {
4865 global $langs, $user;
4866
4867 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4868
4870
4871 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4872 if ($empty) {
4873 print '<option value="">&nbsp;</option>';
4874 }
4875 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4876 // If not good status
4877 if ($active >= 0 && $arraytypes['active'] != $active) {
4878 continue;
4879 }
4880
4881 // We discard empty line if showempty is on because an empty line has already been output.
4882 if ($empty && empty($arraytypes['code'])) {
4883 continue;
4884 }
4885
4886 if ($format == 0) {
4887 print '<option value="' . $id . '"';
4888 } elseif ($format == 1) {
4889 print '<option value="' . $arraytypes['code'] . '"';
4890 } elseif ($format == 2) {
4891 print '<option value="' . $arraytypes['code'] . '"';
4892 } elseif ($format == 3) {
4893 print '<option value="' . $id . '"';
4894 }
4895 // If text is selected, we compare with code, else with id
4896 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4897 print ' selected';
4898 } elseif ($selected == $id) {
4899 print ' selected';
4900 }
4901 print '>';
4902 $value = '';
4903 if ($format == 0) {
4904 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4905 } elseif ($format == 1) {
4906 $value = $arraytypes['code'];
4907 } elseif ($format == 2) {
4908 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4909 } elseif ($format == 3) {
4910 $value = $arraytypes['code'];
4911 }
4912 print $value ? $value : '&nbsp;';
4913 print '</option>';
4914 }
4915 print '</select>';
4916
4917 print ajax_combobox("select".$htmlname);
4918
4919 if ($user->admin && !$noadmininfo) {
4920 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4921 }
4922 }
4923
4936 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4937 {
4938 global $langs, $user;
4939
4940 $langs->load("admin");
4941 $langs->load("deliveries");
4942
4943 $sql = "SELECT rowid, code, libelle as label";
4944 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4945 $sql .= " WHERE active > 0";
4946 if ($filtre) {
4947 $sql .= " AND " . $filtre;
4948 }
4949 $sql .= " ORDER BY libelle ASC";
4950
4951 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4952 $result = $this->db->query($sql);
4953 if ($result) {
4954 $num = $this->db->num_rows($result);
4955 $i = 0;
4956 if ($num) {
4957 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4958 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4959 print '<option value="-1">&nbsp;</option>';
4960 }
4961 while ($i < $num) {
4962 $obj = $this->db->fetch_object($result);
4963 if ($selected == $obj->rowid) {
4964 print '<option value="' . $obj->rowid . '" selected>';
4965 } else {
4966 print '<option value="' . $obj->rowid . '">';
4967 }
4968 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
4969 print '</option>';
4970 $i++;
4971 }
4972 print "</select>";
4973 if ($user->admin && empty($noinfoadmin)) {
4974 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4975 }
4976
4977 print ajax_combobox('select' . $htmlname);
4978 } else {
4979 print $langs->trans("NoShippingMethodDefined");
4980 }
4981 } else {
4982 dol_print_error($this->db);
4983 }
4984 }
4985
4995 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4996 {
4997 global $langs;
4998
4999 $langs->load("deliveries");
5000
5001 if ($htmlname != "none") {
5002 print '<form method="POST" action="' . $page . '">';
5003 print '<input type="hidden" name="action" value="setshippingmethod">';
5004 print '<input type="hidden" name="token" value="' . newToken() . '">';
5005 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5006 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5007 print '</form>';
5008 } else {
5009 if ($selected) {
5010 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5011 print $langs->trans("SendingMethod" . strtoupper($code));
5012 } else {
5013 print "&nbsp;";
5014 }
5015 }
5016 }
5017
5026 public function selectSituationInvoices($selected = '', $socid = 0)
5027 {
5028 global $langs;
5029
5030 $langs->load('bills');
5031
5032 $opt = '<option value="" selected></option>';
5033 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5034 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5035 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5036 $sql .= ' AND situation_counter >= 1';
5037 $sql .= ' AND fk_soc = ' . (int) $socid;
5038 $sql .= ' AND type <> 2';
5039 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5040 $resql = $this->db->query($sql);
5041
5042 if ($resql && $this->db->num_rows($resql) > 0) {
5043 // Last seen cycle
5044 $ref = 0;
5045 while ($obj = $this->db->fetch_object($resql)) {
5046 //Same cycle ?
5047 if ($obj->situation_cycle_ref != $ref) {
5048 // Just seen this cycle
5049 $ref = $obj->situation_cycle_ref;
5050 //not final ?
5051 if ($obj->situation_final != 1) {
5052 //Not prov?
5053 if (substr($obj->ref, 1, 4) != 'PROV') {
5054 if ($selected == $obj->rowid) {
5055 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5056 } else {
5057 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5058 }
5059 }
5060 }
5061 }
5062 }
5063 } else {
5064 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5065 }
5066 if ($opt == '<option value ="" selected></option>') {
5067 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5068 }
5069 return $opt;
5070 }
5071
5081 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5082 {
5083 global $langs;
5084
5085 $langs->load('products');
5086
5087 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5088
5089 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5090 $sql .= ' WHERE active > 0';
5091 if (!empty($unit_type)) {
5092 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5093 }
5094 $sql .= " ORDER BY sortorder";
5095
5096 $resql = $this->db->query($sql);
5097 if ($resql && $this->db->num_rows($resql) > 0) {
5098 if ($showempty) {
5099 $return .= '<option value="none"></option>';
5100 }
5101
5102 while ($res = $this->db->fetch_object($resql)) {
5103 $unitLabel = $res->label;
5104 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5105 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5106 }
5107
5108 if ($selected == $res->rowid) {
5109 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5110 } else {
5111 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5112 }
5113 }
5114 $return .= '</select>';
5115 }
5116 return $return;
5117 }
5118
5119 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5120
5135 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5136 {
5137 // phpcs:enable
5138 global $langs;
5139
5140 $out = '';
5141
5142 $langs->loadLangs(array("admin", "banks"));
5143 $num = 0;
5144
5145 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5146 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5147 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5148 if ($status != 2) {
5149 $sql .= " AND clos = " . (int) $status;
5150 }
5151 if ($filtre) { // TODO Support USF
5152 $sql .= " AND " . $filtre;
5153 }
5154 $sql .= " ORDER BY label";
5155
5156 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5157 $result = $this->db->query($sql);
5158 if ($result) {
5159 $num = $this->db->num_rows($result);
5160 $i = 0;
5161
5162 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5163
5164 if ($num == 0) {
5165 if ($status == 0) {
5166 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5167 } else {
5168 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5169 }
5170 } else {
5171 if (!empty($useempty) && !is_numeric($useempty)) {
5172 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5173 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5174 $out .= '<option value="-1">&nbsp;</option>';
5175 }
5176 }
5177
5178 while ($i < $num) {
5179 $obj = $this->db->fetch_object($result);
5180
5181 $labeltoshow = trim($obj->label);
5182 $labeltoshowhtml = trim($obj->label);
5183 if ($showcurrency) {
5184 $labeltoshow .= ' (' . $obj->currency_code . ')';
5185 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5186 }
5187 if ($status == 2 && $obj->status == 1) {
5188 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5189 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5190 }
5191
5192 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5193 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5194 } else {
5195 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5196 }
5197 $out .= $labeltoshow;
5198 $out .= '</option>';
5199 $i++;
5200 }
5201 $out .= "</select>";
5202 $out .= ajax_combobox('select' . $htmlname);
5203 } else {
5204 dol_print_error($this->db);
5205 }
5206
5207 // Output or return
5208 if (empty($nooutput)) {
5209 print $out;
5210 } else {
5211 return $out;
5212 }
5213
5214 return $num;
5215 }
5216
5230 public function selectRib($selected = '', $htmlname = 'ribcompanyid', $filtre = '', $useempty = 0, $moreattrib = '', $showibanbic = 0, $morecss = '', $nooutput = 0)
5231 {
5232 // phpcs:enable
5233 global $langs;
5234
5235 $out = '';
5236
5237 $langs->loadLangs(array("admin", "banks"));
5238 $num = 0;
5239
5240 $sql = "SELECT rowid, label, bank, status, iban_prefix, bic";
5241 $sql .= " FROM " . $this->db->prefix() . "societe_rib";
5242 $sql.= " WHERE type = 'ban'";
5243 if ($filtre) { // TODO Support USF
5244 $sql .= " AND " . $filtre;
5245 }
5246 $sql .= " ORDER BY label";
5247 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5248 $result = $this->db->query($sql);
5249 if ($result) {
5250 $num = $this->db->num_rows($result);
5251 $i = 0;
5252
5253 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5254
5255 if ($num == 0) {
5256 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5257 } else {
5258 if (!empty($useempty) && !is_numeric($useempty)) {
5259 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5260 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5261 $out .= '<option value="-1">&nbsp;</option>';
5262 }
5263 }
5264
5265 while ($i < $num) {
5266 $obj = $this->db->fetch_object($result);
5267 $iban = dolDecrypt($obj->iban_prefix);
5268 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5269 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '" selected>';
5270 } else {
5271 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '">';
5272 }
5273 $out .= trim($obj->label);
5274 if ($showibanbic) {
5275 $out .= ' (' . $iban . '/' .$obj->bic. ')';
5276 }
5277 $out .= '</option>';
5278 $i++;
5279 }
5280 $out .= "</select>";
5281 $out .= ajax_combobox('select' . $htmlname);
5282 } else {
5283 dol_print_error($this->db);
5284 }
5285
5286 // Output or return
5287 if (empty($nooutput)) {
5288 print $out;
5289 } else {
5290 return $out;
5291 }
5292
5293 return $num;
5294 }
5295
5307 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5308 {
5309 global $langs;
5310
5311 $langs->load("admin");
5312 $num = 0;
5313
5314 $sql = "SELECT rowid, name, fk_country, status, entity";
5315 $sql .= " FROM " . $this->db->prefix() . "establishment";
5316 $sql .= " WHERE 1=1";
5317 if ($status != 2) {
5318 $sql .= " AND status = " . (int) $status;
5319 }
5320 if ($filtre) { // TODO Support USF
5321 $sql .= " AND " . $filtre;
5322 }
5323 $sql .= " ORDER BY name";
5324
5325 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5326 $result = $this->db->query($sql);
5327 if ($result) {
5328 $num = $this->db->num_rows($result);
5329 $i = 0;
5330 if ($num) {
5331 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5332 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5333 print '<option value="-1">&nbsp;</option>';
5334 }
5335
5336 while ($i < $num) {
5337 $obj = $this->db->fetch_object($result);
5338 if ($selected == $obj->rowid) {
5339 print '<option value="' . $obj->rowid . '" selected>';
5340 } else {
5341 print '<option value="' . $obj->rowid . '">';
5342 }
5343 print trim($obj->name);
5344 if ($status == 2 && $obj->status == 1) {
5345 print ' (' . $langs->trans("Closed") . ')';
5346 }
5347 print '</option>';
5348 $i++;
5349 }
5350 print "</select>";
5351 } else {
5352 if ($status == 0) {
5353 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5354 } else {
5355 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5356 }
5357 }
5358
5359 return $num;
5360 } else {
5361 dol_print_error($this->db);
5362 return -1;
5363 }
5364 }
5365
5375 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5376 {
5377 global $langs;
5378 if ($htmlname != "none") {
5379 print '<form method="POST" action="' . $page . '">';
5380 print '<input type="hidden" name="action" value="setbankaccount">';
5381 print '<input type="hidden" name="token" value="' . newToken() . '">';
5382 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5383 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5384 if ($nbaccountfound > 0) {
5385 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5386 }
5387 print '</form>';
5388 } else {
5389 $langs->load('banks');
5390
5391 if ($selected) {
5392 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5393 $bankstatic = new Account($this->db);
5394 $result = $bankstatic->fetch($selected);
5395 if ($result) {
5396 print $bankstatic->getNomUrl(1);
5397 }
5398 } else {
5399 print "&nbsp;";
5400 }
5401 }
5402 }
5403
5415 public function formRib($page, $selected = '', $htmlname = 'ribcompanyid', $filtre = '', $addempty = 0, $showibanbic = 0)
5416 {
5417 global $langs;
5418 if ($htmlname != "none") {
5419 print '<form method="POST" action="' . $page . '">';
5420 print '<input type="hidden" name="action" value="setbankaccountcustomer">';
5421 print '<input type="hidden" name="token" value="' . newToken() . '">';
5422 $nbaccountfound = $this->selectRib($selected, $htmlname, $filtre, $addempty, '', $showibanbic);
5423 if ($nbaccountfound > 0) {
5424 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5425 }
5426 print '</form>';
5427 } else {
5428 $langs->load('banks');
5429
5430 if ($selected) {
5431 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
5432 $bankstatic = new CompanyBankAccount($this->db);
5433 $result = $bankstatic->fetch($selected);
5434 if ($result) {
5435 print $bankstatic->label;
5436 if ($showibanbic) print ' (' . $bankstatic->iban . '/' .$bankstatic->bic. ')';
5437 }
5438 } else {
5439 print "&nbsp;";
5440 }
5441 }
5442 }
5443
5444 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5445
5465 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5466 {
5467 // phpcs:enable
5468 global $conf, $langs;
5469 $langs->load("categories");
5470
5471 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5472
5473 // For backward compatibility
5474 if (is_numeric($type)) {
5475 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5476 }
5477
5478 if ($type === Categorie::TYPE_BANK_LINE) {
5479 // TODO Move this into common category feature after migration of llx_category_bankline into llx_categorie_bankline
5480 $cat = new Categorie($this->db);
5481 $cate_arbo = array();
5482 $sql = "SELECT c.label, c.rowid";
5483 $sql .= " FROM " . $this->db->prefix() . "categorie as c";
5484 $sql .= " WHERE entity = " . $conf->entity . " AND type = " . ((int) $cat->getMapId()[$type]);
5485 $sql .= " ORDER BY c.label";
5486 $result = $this->db->query($sql);
5487 if ($result) {
5488 $num = $this->db->num_rows($result);
5489 $i = 0;
5490 while ($i < $num) {
5491 $objp = $this->db->fetch_object($result);
5492 if ($objp) {
5493 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5494 }
5495 $i++;
5496 }
5497 $this->db->free($result);
5498 } else {
5499 dol_print_error($this->db);
5500 }
5501 } else {
5502 $cat = new Categorie($this->db);
5503 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5504 }
5505
5506 $outarray = array();
5507 $outarrayrichhtml = array();
5508
5509
5510 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5511 if (is_array($cate_arbo)) {
5512 $num = count($cate_arbo);
5513
5514 if (!$num) {
5515 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5516 } else {
5517 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5518 $output .= '<option value="-1">&nbsp;</option>';
5519 }
5520 foreach ($cate_arbo as $key => $value) {
5521 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5522 $add = 'selected ';
5523 } else {
5524 $add = '';
5525 }
5526
5527 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5528 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5529
5530 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5531
5532 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5533
5534 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5535 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5536 $output .= '>';
5537 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5538 $output .= '</option>';
5539
5540 $cate_arbo[$key]['data-html'] = $labeltoshow;
5541 }
5542 }
5543 }
5544 $output .= '</select>';
5545 $output .= "\n";
5546
5547 if ($outputmode == 2) {
5548 // TODO: handle error when $cate_arbo is not an array
5549 return $cate_arbo;
5550 } elseif ($outputmode == 1) {
5551 return $outarray;
5552 } elseif ($outputmode == 3) {
5553 return $outarrayrichhtml;
5554 }
5555 return $output;
5556 }
5557
5558 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5559
5578 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5579 {
5580 // phpcs:enable
5581 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5582 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5583 }
5584
5612 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5613 {
5614 global $langs, $conf;
5615
5616 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5617 $formconfirm = '';
5618 $inputok = array();
5619 $inputko = array();
5620
5621 // Clean parameters
5622 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5623 if ($conf->browser->layout == 'phone') {
5624 $width = '95%';
5625 }
5626
5627 // Set height automatically if not defined
5628 if (empty($height)) {
5629 $height = 220;
5630 if (is_array($formquestion) && count($formquestion) > 2) {
5631 $height += ((count($formquestion) - 2) * 24);
5632 }
5633 }
5634
5635 if (is_array($formquestion) && !empty($formquestion)) {
5636 // First add hidden fields and value
5637 foreach ($formquestion as $key => $input) {
5638 if (is_array($input) && !empty($input)) {
5639 if ($input['type'] == 'hidden') {
5640 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5641 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5642
5643 $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";
5644 }
5645 }
5646 }
5647
5648 // Now add questions
5649 $moreonecolumn = '';
5650 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5651 foreach ($formquestion as $key => $input) {
5652 if (is_array($input) && !empty($input)) {
5653 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5654 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5655 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5656
5657 if ($input['type'] == 'text') {
5658 $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";
5659 } elseif ($input['type'] == 'password') {
5660 $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";
5661 } elseif ($input['type'] == 'textarea') {
5662 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5663 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5664 $more .= $input['value'];
5665 $more .= '</textarea>';
5666 $more .= '</div></div>'."\n";*/
5667 $moreonecolumn .= '<div class="margintoponly">';
5668 $moreonecolumn .= $input['label'] . '<br>';
5669 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5670 $moreonecolumn .= $input['value'];
5671 $moreonecolumn .= '</textarea>';
5672 $moreonecolumn .= '</div>';
5673 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5674 if (empty($morecss)) {
5675 $morecss = 'minwidth100';
5676 }
5677
5678 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5679 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5680 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5681 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5682 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5683 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5684 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5685
5686 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5687 if (!empty($input['label'])) {
5688 $more .= $input['label'] . '</div><div class="tagtd left">';
5689 }
5690 if ($input['type'] == 'select') {
5691 $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);
5692 } else {
5693 $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);
5694 }
5695 $more .= '</div></div>' . "\n";
5696 } elseif ($input['type'] == 'checkbox') {
5697 $more .= '<div class="tagtr">';
5698 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5699 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5700 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5701 $more .= ' checked';
5702 }
5703 if (is_bool($input['value']) && $input['value']) {
5704 $more .= ' checked';
5705 }
5706 if (isset($input['disabled'])) {
5707 $more .= ' disabled';
5708 }
5709 $more .= ' /></div>';
5710 $more .= '</div>' . "\n";
5711 } elseif ($input['type'] == 'radio') {
5712 $i = 0;
5713 foreach ($input['values'] as $selkey => $selval) {
5714 $more .= '<div class="tagtr">';
5715 if (isset($input['label'])) {
5716 if ($i == 0) {
5717 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5718 } else {
5719 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5720 }
5721 }
5722 $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;
5723 if (!empty($input['disabled'])) {
5724 $more .= ' disabled';
5725 }
5726 if (isset($input['default']) && $input['default'] === $selkey) {
5727 $more .= ' checked="checked"';
5728 }
5729 $more .= ' /> ';
5730 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5731 $more .= '</div></div>' . "\n";
5732 $i++;
5733 }
5734 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5735 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5736 $more .= '<div class="tagtd">';
5737 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5738 $h = $m = 0;
5739 if ($input['type'] == 'datetime') {
5740 $h = isset($input['hours']) ? $input['hours'] : 1;
5741 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5742 }
5743 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5744 $more .= '</div></div>'."\n";
5745 $formquestion[] = array('name' => $input['name'].'day');
5746 $formquestion[] = array('name' => $input['name'].'month');
5747 $formquestion[] = array('name' => $input['name'].'year');
5748 $formquestion[] = array('name' => $input['name'].'hour');
5749 $formquestion[] = array('name' => $input['name'].'min');
5750 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5751 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5752 if (!empty($input['label'])) {
5753 $more .= $input['label'] . '</div><div class="tagtd">';
5754 }
5755 $more .= $input['value'];
5756 $more .= '</div></div>' . "\n";
5757 } elseif ($input['type'] == 'onecolumn') {
5758 $moreonecolumn .= '<div class="margintoponly">';
5759 $moreonecolumn .= $input['value'];
5760 $moreonecolumn .= '</div>' . "\n";
5761 } elseif ($input['type'] == 'hidden') {
5762 // Do nothing more, already added by a previous loop
5763 } elseif ($input['type'] == 'separator') {
5764 $more .= '<br>';
5765 } else {
5766 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5767 }
5768 }
5769 }
5770 $more .= '</div>' . "\n";
5771 $more .= $moreonecolumn;
5772 }
5773
5774 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5775 // 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
5776 // See page product/card.php for example
5777 if (!empty($conf->dol_use_jmobile)) {
5778 $useajax = 0;
5779 }
5780 if (empty($conf->use_javascript_ajax)) {
5781 $useajax = 0;
5782 }
5783
5784 if ($useajax) {
5785 $autoOpen = true;
5786 $dialogconfirm = 'dialog-confirm';
5787 $button = '';
5788 if (!is_numeric($useajax)) {
5789 $button = $useajax;
5790 $useajax = 1;
5791 $autoOpen = false;
5792 $dialogconfirm .= '-' . $button;
5793 }
5794 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5795 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5796
5797 // Add input fields into list of fields to read during submit (inputok and inputko)
5798 if (is_array($formquestion)) {
5799 foreach ($formquestion as $key => $input) {
5800 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5801 // Add name of fields to propagate with the GET when submitting the form with button OK.
5802 if (is_array($input) && isset($input['name'])) {
5803 if (strpos($input['name'], ',') > 0) {
5804 $inputok = array_merge($inputok, explode(',', $input['name']));
5805 } else {
5806 array_push($inputok, $input['name']);
5807 }
5808 }
5809 // Add name of fields to propagate with the GET when submitting the form with button KO.
5810 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5811 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5812 array_push($inputko, $input['name']);
5813 }
5814 }
5815 }
5816
5817 // Show JQuery confirm box.
5818 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5819 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5820 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5821 }
5822 if (!empty($more)) {
5823 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5824 }
5825 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5826 $formconfirm .= '</div>' . "\n";
5827
5828 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5829 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5830 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5831 $formconfirm .= 'jQuery(document).ready(function() {
5832 $(function() {
5833 $( "#' . $dialogconfirm . '" ).dialog(
5834 {
5835 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5836 if ($newselectedchoice == 'no') {
5837 $formconfirm .= '
5838 open: function() {
5839 $(this).parent().find("button.ui-button:eq(2)").focus();
5840 },';
5841 }
5842
5843 $jsforcursor = '';
5844 if ($useajax == 1) {
5845 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5846 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5847 }
5848
5849 $postconfirmas = 'GET';
5850
5851 $formconfirm .= '
5852 resizable: false,
5853 height: "' . $height . '",
5854 width: "' . $width . '",
5855 modal: true,
5856 closeOnEscape: false,
5857 buttons: {
5858 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5859 var options = "token=' . urlencode(newToken()) . '";
5860 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5861 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5862 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5863
5864 if (inputok.length > 0) {
5865 $.each(inputok, function(i, inputname) {
5866 var more = "";
5867 var inputvalue;
5868 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5869 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5870 } else {
5871 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5872 inputvalue = $("#" + inputname + more).val();
5873 }
5874 if (typeof inputvalue == "undefined") { inputvalue=""; }
5875 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5876 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5877 });
5878 }
5879 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5880 if (pageyes.length > 0) {';
5881 if ($postconfirmas == 'GET') {
5882 $formconfirm .= 'location.href = urljump;';
5883 } else {
5884 $formconfirm .= $jsforcursor;
5885 $formconfirm .= 'var post = $.post(
5886 pageyes,
5887 options,
5888 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5889 );';
5890 }
5891 $formconfirm .= '
5892 console.log("after post ok");
5893 }
5894 $(this).dialog("close");
5895 },
5896 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5897 var options = "token=' . urlencode(newToken()) . '";
5898 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5899 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5900 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5901 if (inputko.length > 0) {
5902 $.each(inputko, function(i, inputname) {
5903 var more = "";
5904 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5905 var inputvalue = $("#" + inputname + more).val();
5906 if (typeof inputvalue == "undefined") { inputvalue=""; }
5907 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5908 });
5909 }
5910 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5911 //alert(urljump);
5912 if (pageno.length > 0) {';
5913 if ($postconfirmas == 'GET') {
5914 $formconfirm .= 'location.href = urljump;';
5915 } else {
5916 $formconfirm .= $jsforcursor;
5917 $formconfirm .= 'var post = $.post(
5918 pageno,
5919 options,
5920 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5921 );';
5922 }
5923 $formconfirm .= '
5924 console.log("after post ko");
5925 }
5926 $(this).dialog("close");
5927 }
5928 }
5929 }
5930 );
5931
5932 var button = "' . $button . '";
5933 if (button.length > 0) {
5934 $( "#" + button ).click(function() {
5935 $("#' . $dialogconfirm . '").dialog("open");
5936 });
5937 }
5938 });
5939 });
5940 </script>';
5941 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5942 } else {
5943 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5944
5945 if (empty($disableformtag)) {
5946 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
5947 }
5948
5949 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5950 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5951
5952 $formconfirm .= '<table class="valid centpercent">' . "\n";
5953
5954 // Line title
5955 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5956 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5957 $formconfirm .= '</td></tr>' . "\n";
5958
5959 // Line text
5960 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5961 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5962 }
5963
5964 // Line form fields
5965 if ($more) {
5966 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5967 $formconfirm .= $more;
5968 $formconfirm .= '</td></tr>' . "\n";
5969 }
5970
5971 // Line with question
5972 $formconfirm .= '<tr class="valid">';
5973 $formconfirm .= '<td class="valid">' . $question . '</td>';
5974 $formconfirm .= '<td class="valid center">';
5975 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5976 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5977 $formconfirm .= '</td>';
5978 $formconfirm .= '</tr>' . "\n";
5979
5980 $formconfirm .= '</table>' . "\n";
5981
5982 if (empty($disableformtag)) {
5983 $formconfirm .= "</form>\n";
5984 }
5985 $formconfirm .= '<br>';
5986
5987 if (!empty($conf->use_javascript_ajax)) {
5988 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5989 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5990 $formconfirm .= '
5991 $(document).ready(function () {
5992 $(".confirmvalidatebutton").on("click", function() {
5993 console.log("We click on button confirmvalidatebutton");
5994 $(this).attr("disabled", "disabled");
5995 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5996 //console.log($(this).closest("form"));
5997 $(this).closest("form").submit();
5998 });
5999 });
6000 ';
6001 $formconfirm .= '</script>' . "\n";
6002 }
6003
6004 $formconfirm .= "<!-- end formconfirm -->\n";
6005 }
6006
6007 return $formconfirm;
6008 }
6009
6010
6011 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6012
6028 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
6029 {
6030 // phpcs:enable
6031 global $langs;
6032
6033 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
6034 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
6035
6036 $out = '';
6037
6038 $formproject = new FormProjets($this->db);
6039
6040 $langs->load("project");
6041 if ($htmlname != "none") {
6042 $out .= '<form method="post" action="' . $page . '">';
6043 $out .= '<input type="hidden" name="action" value="classin">';
6044 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6045 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
6046 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6047 $out .= '</form>';
6048 } else {
6049 $out .= '<span class="project_head_block">';
6050 if ($selected) {
6051 $projet = new Project($this->db);
6052 $projet->fetch($selected);
6053 $out .= $projet->getNomUrl(0, '', 1);
6054 } else {
6055 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
6056 }
6057 $out .= '</span>';
6058 }
6059
6060 if (empty($nooutput)) {
6061 print $out;
6062 return '';
6063 }
6064 return $out;
6065 }
6066
6067 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6068
6084 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
6085 {
6086 // phpcs:enable
6087 global $langs;
6088
6089 $out = '';
6090
6091 if ($htmlname != "none") {
6092 $out .= '<form method="POST" action="' . $page . '">';
6093 $out .= '<input type="hidden" name="action" value="setconditions">';
6094 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6095 if ($type) {
6096 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6097 }
6098 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6099 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6100 $out .= '</form>';
6101 } else {
6102 if ($selected) {
6104 if (isset($this->cache_conditions_paiements[$selected])) {
6105 $label = $this->cache_conditions_paiements[$selected]['label'];
6106
6107 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6108 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6109 }
6110
6111 $out .= $label;
6112 } else {
6113 $langs->load('errors');
6114 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6115 }
6116 } else {
6117 $out .= '&nbsp;';
6118 }
6119 }
6120
6121 if (empty($nooutput)) {
6122 print $out;
6123 return '';
6124 }
6125 return $out;
6126 }
6127
6128 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6129
6139 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
6140 {
6141 // phpcs:enable
6142 global $langs;
6143 if ($htmlname != "none") {
6144 print '<form method="post" action="' . $page . '">';
6145 print '<input type="hidden" name="action" value="setavailability">';
6146 print '<input type="hidden" name="token" value="' . newToken() . '">';
6147 $this->selectAvailabilityDelay($selected, $htmlname, '', $addempty);
6148 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6149 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
6150 print '</form>';
6151 } else {
6152 if ($selected) {
6153 $this->load_cache_availability();
6154 print $this->cache_availability[$selected]['label'];
6155 } else {
6156 print "&nbsp;";
6157 }
6158 }
6159 }
6160
6171 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
6172 {
6173 global $langs;
6174 if ($htmlname != "none") {
6175 print '<form method="post" action="' . $page . '">';
6176 print '<input type="hidden" name="action" value="setdemandreason">';
6177 print '<input type="hidden" name="token" value="' . newToken() . '">';
6178 $this->selectInputReason($selected, $htmlname, '-1', $addempty);
6179 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6180 print '</form>';
6181 } else {
6182 if ($selected) {
6183 $this->loadCacheInputReason();
6184 foreach ($this->cache_demand_reason as $key => $val) {
6185 if ($val['id'] == $selected) {
6186 print $val['label'];
6187 break;
6188 }
6189 }
6190 } else {
6191 print "&nbsp;";
6192 }
6193 }
6194 }
6195
6196 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6197
6211 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6212 {
6213 // phpcs:enable
6214 global $langs;
6215
6216 $ret = '';
6217
6218 if ($htmlname != "none") {
6219 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6220 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6221 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6222 if ($type) {
6223 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6224 }
6225 $ret .= '<table class="nobordernopadding">';
6226 $ret .= '<tr><td>';
6227 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6228 $ret .= '</td>';
6229 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6230 $ret .= '</tr></table></form>';
6231 } else {
6232 if ($displayhour) {
6233 $ret .= dol_print_date($selected, 'dayhour');
6234 } else {
6235 $ret .= dol_print_date($selected, 'day');
6236 }
6237 }
6238
6239 if (empty($nooutput)) {
6240 print $ret;
6241 }
6242 return $ret;
6243 }
6244
6245
6246 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6247
6258 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6259 {
6260 // phpcs:enable
6261 global $langs;
6262
6263 if ($htmlname != "none") {
6264 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6265 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6266 print '<input type="hidden" name="token" value="' . newToken() . '">';
6267 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6268 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6269 print '</form>';
6270 } else {
6271 if ($selected) {
6272 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6273 $theuser = new User($this->db);
6274 $theuser->fetch($selected);
6275 print $theuser->getNomUrl(1);
6276 } else {
6277 print "&nbsp;";
6278 }
6279 }
6280 }
6281
6282
6283 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6284
6298 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6299 {
6300 // phpcs:enable
6301 global $langs;
6302
6303 $out = '';
6304 if ($htmlname != "none") {
6305 $out .= '<form method="POST" action="' . $page . '">';
6306 $out .= '<input type="hidden" name="action" value="setmode">';
6307 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6308 if ($type) {
6309 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6310 }
6311 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6312 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6313 $out .= '</form>';
6314 } else {
6315 if ($selected) {
6317 $out .= $this->cache_types_paiements[$selected]['label'];
6318 } else {
6319 $out .= "&nbsp;";
6320 }
6321 }
6322
6323 if ($nooutput) {
6324 return $out;
6325 } else {
6326 print $out;
6327 }
6328 return '';
6329 }
6330
6341 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6342 {
6343 global $langs;
6344 if ($htmlname != "none") {
6345 print '<form method="POST" action="' . $page . '">';
6346 print '<input type="hidden" name="action" value="settransportmode">';
6347 print '<input type="hidden" name="token" value="' . newToken() . '">';
6348 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6349 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6350 print '</form>';
6351 } else {
6352 if ($selected) {
6354 print $this->cache_transport_mode[$selected]['label'];
6355 } else {
6356 print "&nbsp;";
6357 }
6358 }
6359 }
6360
6361 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6362
6371 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6372 {
6373 // phpcs:enable
6374 global $langs;
6375 if ($htmlname != "none") {
6376 print '<form method="POST" action="' . $page . '">';
6377 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6378 print '<input type="hidden" name="token" value="' . newToken() . '">';
6379 print $this->selectMultiCurrency($selected, $htmlname, 0);
6380 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6381 print '</form>';
6382 } else {
6383 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6384 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6385 }
6386 }
6387
6388 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6389
6399 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6400 {
6401 // phpcs:enable
6402 global $langs, $mysoc, $conf;
6403
6404 if ($htmlname != "none") {
6405 print '<form method="POST" action="' . $page . '">';
6406 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6407 print '<input type="hidden" name="token" value="' . newToken() . '">';
6408 print '<input type="text" class="maxwidth75" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6409 print '<select name="calculation_mode" id="calculation_mode">';
6410 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6411 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6412 print '</select> ';
6413 print ajax_combobox("calculation_mode");
6414 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6415 print '</form>';
6416 } else {
6417 if (!empty($rate)) {
6418 print price($rate, 1, $langs, 0, 0);
6419 if ($currency && $rate != 1) {
6420 print ' &nbsp; <span class="opacitymedium">(' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')</span>';
6421 }
6422 } else {
6423 print 1;
6424 }
6425 }
6426 }
6427
6428 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6429
6445 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6446 {
6447 // phpcs:enable
6448 global $conf, $langs;
6449 if ($htmlname != "none") {
6450 print '<form method="post" action="' . $page . '">';
6451 print '<input type="hidden" name="action" value="setabsolutediscount">';
6452 print '<input type="hidden" name="token" value="' . newToken() . '">';
6453 print '<div class="inline-block">';
6454 if (!empty($discount_type)) {
6455 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6456 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6457 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6458 } else {
6459 $translationKey = 'HasCreditNoteFromSupplier';
6460 }
6461 } else {
6462 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6463 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6464 } else {
6465 $translationKey = 'HasCreditNoteFromSupplier';
6466 }
6467 }
6468 } else {
6469 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6470 if (!$filter || $filter == "fk_facture_source IS NULL") {
6471 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6472 } else {
6473 $translationKey = 'CompanyHasCreditNote';
6474 }
6475 } else {
6476 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6477 $translationKey = 'CompanyHasAbsoluteDiscount';
6478 } else {
6479 $translationKey = 'CompanyHasCreditNote';
6480 }
6481 }
6482 }
6483 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6484 if (empty($hidelist)) {
6485 print ' ';
6486 }
6487 print '</div>';
6488 if (empty($hidelist)) {
6489 print '<div class="inline-block" style="padding-right: 10px">';
6490 $newfilter = 'discount_type=' . intval($discount_type);
6491 if (!empty($discount_type)) {
6492 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6493 } else {
6494 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6495 }
6496 if ($filter) {
6497 $newfilter .= ' AND (' . $filter . ')';
6498 }
6499 // output the combo of discounts
6500 $nbqualifiedlines = $this->select_remises((string) $selected, $htmlname, $newfilter, $socid, $maxvalue);
6501 if ($nbqualifiedlines > 0) {
6502 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6503 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6504 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6505 }
6506 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6507 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6508 }
6509
6510 print '>';
6511 }
6512 print '</div>';
6513 }
6514 if ($more) {
6515 print '<div class="inline-block">';
6516 print $more;
6517 print '</div>';
6518 }
6519 print '</form>';
6520 } else {
6521 if ($selected) {
6522 print $selected;
6523 } else {
6524 print "0";
6525 }
6526 }
6527 }
6528
6529
6530 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6531
6541 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6542 {
6543 // phpcs:enable
6544 global $langs;
6545
6546 if ($htmlname != "none") {
6547 print '<form method="post" action="' . $page . '">';
6548 print '<input type="hidden" name="action" value="set_contact">';
6549 print '<input type="hidden" name="token" value="' . newToken() . '">';
6550 print '<table class="nobordernopadding">';
6551 print '<tr><td>';
6552 print $this->selectcontacts($societe->id, $selected, $htmlname);
6553 $num = $this->num;
6554 if ($num == 0) {
6555 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6556 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&amp;action=create&amp;backtoreferer=1">' . $addcontact . '</a>';
6557 }
6558 print '</td>';
6559 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6560 print '</tr></table></form>';
6561 } else {
6562 if ($selected) {
6563 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6564 $contact = new Contact($this->db);
6565 $contact->fetch($selected);
6566 print $contact->getFullName($langs);
6567 } else {
6568 print "&nbsp;";
6569 }
6570 }
6571 }
6572
6573 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6574
6591 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6592 {
6593 // phpcs:enable
6594 global $langs;
6595
6596 $out = '';
6597 if ($htmlname != "none") {
6598 $out .= '<form method="post" action="' . $page . '">';
6599 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6600 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6601 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6602 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6603 $out .= '</form>';
6604 } else {
6605 if ($selected) {
6606 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6607 $soc = new Societe($this->db);
6608 $soc->fetch($selected);
6609 $out .= $soc->getNomUrl(0, '');
6610 } else {
6611 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6612 }
6613 }
6614
6615 if ($nooutput) {
6616 return $out;
6617 } else {
6618 print $out;
6619 }
6620
6621 return '';
6622 }
6623
6624 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6625
6634 public function select_currency($selected = '', $htmlname = 'currency_id')
6635 {
6636 // phpcs:enable
6637 print $this->selectCurrency($selected, $htmlname);
6638 }
6639
6649 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6650 {
6651 global $langs, $user;
6652
6653 $langs->loadCacheCurrencies('');
6654
6655 $out = '';
6656
6657 if ($selected == 'euro' || $selected == 'euros') {
6658 $selected = 'EUR'; // Pour compatibilite
6659 }
6660
6661 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6662 if ($useempty) {
6663 $out .= '<option value="-1" selected></option>';
6664 }
6665 foreach ($langs->cache_currencies as $code_iso => $currency) {
6666 $labeltoshow = $currency['label'];
6667 if ($mode == 1) {
6668 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6669 } else {
6670 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6671 }
6672
6673 if ($selected && $selected == $code_iso) {
6674 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6675 } else {
6676 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6677 }
6678 $out .= $labeltoshow;
6679 $out .= '</option>';
6680 }
6681 $out .= '</select>';
6682 if ($user->admin) {
6683 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6684 }
6685
6686 // Make select dynamic
6687 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6688 $out .= ajax_combobox($htmlname);
6689
6690 return $out;
6691 }
6692
6705 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6706 {
6707 global $conf, $langs;
6708
6709 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6710
6711 $TCurrency = array();
6712
6713 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6714 $sql .= " WHERE entity IN ('" . getEntity('mutlicurrency') . "')";
6715 if ($filter) {
6716 $sql .= " AND " . $filter;
6717 }
6718 $resql = $this->db->query($sql);
6719 if ($resql) {
6720 while ($obj = $this->db->fetch_object($resql)) {
6721 $TCurrency[$obj->code] = $obj->code;
6722 }
6723 }
6724
6725 $out = '';
6726 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6727 if ($useempty) {
6728 $out .= '<option value="">&nbsp;</option>';
6729 }
6730 // If company current currency not in table, we add it into list. Should always be available.
6731 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6732 $TCurrency[$conf->currency] = $conf->currency;
6733 }
6734 if (count($TCurrency) > 0) {
6735 foreach ($langs->cache_currencies as $code_iso => $currency) {
6736 if (isset($TCurrency[$code_iso])) {
6737 if (!empty($selected) && $selected == $code_iso) {
6738 $out .= '<option value="' . $code_iso . '" selected="selected">';
6739 } else {
6740 $out .= '<option value="' . $code_iso . '">';
6741 }
6742
6743 $out .= $currency['label'];
6744 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6745 $out .= '</option>';
6746 }
6747 }
6748 }
6749
6750 $out .= '</select>';
6751
6752 // Make select dynamic
6753 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6754 $out .= ajax_combobox($htmlname);
6755
6756 return $out;
6757 }
6758
6759 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6760
6767 public function load_cache_vatrates($country_code)
6768 {
6769 // phpcs:enable
6770 global $langs, $user;
6771
6772 $num = count($this->cache_vatrates);
6773 if ($num > 0) {
6774 return $num; // Cache already loaded
6775 }
6776
6777 dol_syslog(__METHOD__, LOG_DEBUG);
6778
6779 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6780 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6781 $sql .= " WHERE t.fk_pays = c.rowid";
6782 $sql .= " AND t.active > 0";
6783 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6784 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6785 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6786
6787 $resql = $this->db->query($sql);
6788 if ($resql) {
6789 $num = $this->db->num_rows($resql);
6790 if ($num) {
6791 for ($i = 0; $i < $num; $i++) {
6792 $obj = $this->db->fetch_object($resql);
6793
6794 $tmparray = array();
6795 $tmparray['rowid'] = $obj->rowid;
6796 $tmparray['type_vat'] = $obj->type_vat;
6797 $tmparray['code'] = $obj->code;
6798 $tmparray['txtva'] = $obj->taux;
6799 $tmparray['nprtva'] = $obj->recuperableonly;
6800 $tmparray['localtax1'] = $obj->localtax1;
6801 $tmparray['localtax1_type'] = $obj->localtax1_type;
6802 $tmparray['localtax2'] = $obj->localtax2;
6803 $tmparray['localtax2_type'] = $obj->localtax1_type;
6804 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6805 $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
6806 $positiverates = '';
6807 if ($obj->taux) {
6808 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6809 }
6810 if ($obj->localtax1) {
6811 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6812 }
6813 if ($obj->localtax2) {
6814 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6815 }
6816 if (empty($positiverates)) {
6817 $positiverates = '0';
6818 }
6819 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6820
6821 $this->cache_vatrates[$obj->rowid] = $tmparray;
6822 }
6823
6824 return $num;
6825 } else {
6826 $this->error = '<span class="error">';
6827 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6828 $reg = array();
6829 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6830 $langs->load("errors");
6831 $new_country_code = $reg[1];
6832 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid');
6833 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6834 }
6835 $this->error .= '</span>';
6836 return -1;
6837 }
6838 } else {
6839 $this->error = '<span class="error">' . $this->db->error() . '</span>';
6840 return -2;
6841 }
6842 }
6843
6844 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6845
6868 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)
6869 {
6870 // phpcs:enable
6871 global $langs, $mysoc;
6872
6873 $langs->load('errors');
6874
6875 $return = '';
6876
6877 // Define defaultnpr, defaultttx and defaultcode
6878 $defaultnpr = ($info_bits & 0x01);
6879 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6880 $defaulttx = str_replace('*', '', $selectedrate);
6881 $defaultcode = '';
6882 $reg = array();
6883 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6884 $defaultcode = $reg[1];
6885 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6886 }
6887 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6888
6889 // Check parameters
6890 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6891 if ($societe_vendeuse->id == $mysoc->id) {
6892 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6893 } else {
6894 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6895 }
6896 return $return;
6897 }
6898
6899 //var_dump($societe_acheteuse);
6900 //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";
6901 //exit;
6902
6903 // Define list of countries to use to search VAT rates to show
6904 // First we defined code_country to use to find list
6905 if (is_object($societe_vendeuse)) {
6906 $code_country = "'" . $societe_vendeuse->country_code . "'";
6907 } else {
6908 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6909 }
6910 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
6911 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6912 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
6913 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
6914 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
6915 if (isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
6916 // We also add the buyer country code
6917 if (is_numeric($type)) {
6918 if ($type == 1) { // We know product is a service
6919 switch ($selectVatComboMode) {
6920 case '1':
6921 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6922 break;
6923 case '2':
6924 $code_country = "'" . $societe_acheteuse->country_code . "'";
6925 break;
6926 }
6927 }
6928 } elseif (!$idprod) { // We don't know type of product
6929 switch ($selectVatComboMode) {
6930 case '1':
6931 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6932 break;
6933 case '2':
6934 $code_country = "'" . $societe_acheteuse->country_code . "'";
6935 break;
6936 }
6937 } else {
6938 $prodstatic = new Product($this->db);
6939 $prodstatic->fetch($idprod);
6940 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6941 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6942 }
6943 }
6944 }
6945 }
6946
6947 // Now we load the list of VAT
6948 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6949
6950 // Keep only the VAT qualified for $type_vat
6951 $arrayofvatrates = array();
6952 foreach ($this->cache_vatrates as $cachevalue) {
6953 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] != $type_vat) {
6954 $arrayofvatrates[] = $cachevalue;
6955 }
6956 }
6957
6958 $num = count($arrayofvatrates);
6959
6960 if ($num > 0) {
6961 // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6962 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6963 $tmpthirdparty = new Societe($this->db);
6964
6965 $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6966 $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6967
6968 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6969 $defaultcode = $reg[1];
6970 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6971 }
6972 if (empty($defaulttx)) {
6973 $defaultnpr = 0;
6974 }
6975 }
6976
6977 // If we fails to find a default vat rate, we take the last one in list
6978 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
6979 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6980 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6981 // We take the last one found in list
6982 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
6983 } else {
6984 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
6985 $defaulttx = '';
6986 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6987 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
6988 }
6989 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6990 $defaultcode = $reg[1];
6991 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6992 }
6993 }
6994 }
6995
6996 // Disabled if seller is not subject to VAT
6997 $disabled = false;
6998 $title = '';
6999 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
7000 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
7001 // of using supplier invoices (this is a very bad idea !)
7002 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
7003 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
7004 $disabled = true;
7005 }
7006 }
7007
7008 if (!$options_only) {
7009 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
7010 }
7011
7012 $selectedfound = false;
7013 foreach ($arrayofvatrates as $rate) {
7014 // Keep only 0 if seller is not subject to VAT
7015 if ($disabled && $rate['txtva'] != 0) {
7016 continue;
7017 }
7018
7019 // Define key to use into select list
7020 $key = $rate['txtva'];
7021 $key .= $rate['nprtva'] ? '*' : '';
7022 if ($mode > 0 && $rate['code']) {
7023 $key .= ' (' . $rate['code'] . ')';
7024 }
7025 if ($mode < 0) {
7026 $key = $rate['rowid'];
7027 }
7028
7029 $return .= '<option value="' . $key . '"';
7030 if (!$selectedfound) {
7031 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
7032 if ($defaultcode == $rate['code']) {
7033 $return .= ' selected';
7034 $selectedfound = true;
7035 }
7036 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
7037 $return .= ' selected';
7038 $selectedfound = true;
7039 }
7040 }
7041 $return .= '>';
7042
7043 // Show label of VAT
7044 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
7045 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
7046 $return .= $rate['labelpositiverates'];
7047 } else {
7048 // Simple label
7049 $return .= vatrate($rate['label']);
7050 }
7051
7052 //$return.=($rate['code']?' '.$rate['code']:'');
7053 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
7054
7055 $return .= '</option>';
7056 }
7057
7058 if (!$options_only) {
7059 $return .= '</select>';
7060 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
7061 }
7062 } else {
7063 $return .= $this->error;
7064 }
7065
7066 $this->num = $num;
7067 return $return;
7068 }
7069
7070
7071 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7072
7097 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 = '')
7098 {
7099 // phpcs:enable
7100 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
7101 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
7102 if (!empty($nooutput)) {
7103 return $retstring;
7104 }
7105 print $retstring;
7106
7107 return '';
7108 }
7109
7125 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
7126 {
7127 global $langs;
7128
7129 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
7130 if ($forcenewline) {
7131 $ret .= '<br>';
7132 }
7133 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
7134 return $ret;
7135 }
7136
7164 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')
7165 {
7166 global $conf, $langs;
7167
7168 if ($gm === 'auto') {
7169 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7170 }
7171
7172 $retstring = '';
7173
7174 if ($prefix == '') {
7175 $prefix = 're';
7176 }
7177 if ($h == '') {
7178 $h = 0;
7179 }
7180 if ($m == '') {
7181 $m = 0;
7182 }
7183 $emptydate = 0;
7184 $emptyhours = 0;
7185 if ($stepminutes <= 0 || $stepminutes > 30) {
7186 $stepminutes = 1;
7187 }
7188 if ($empty == 1) {
7189 $emptydate = 1;
7190 $emptyhours = 1;
7191 }
7192 if ($empty == 2) {
7193 $emptydate = 0;
7194 $emptyhours = 1;
7195 }
7196 $orig_set_time = $set_time;
7197
7198 if ($set_time === '' && $emptydate == 0) {
7199 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7200 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7201 $set_time = dol_now($gm);
7202 } else {
7203 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7204 }
7205 }
7206
7207 // Analysis of the pre-selection date
7208 $reg = array();
7209 $shour = '';
7210 $smin = '';
7211 $ssec = '';
7212 if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
7213 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7214 $syear = (!empty($reg[1]) ? $reg[1] : '');
7215 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7216 $sday = (!empty($reg[3]) ? $reg[3] : '');
7217 $shour = (!empty($reg[4]) ? $reg[4] : '');
7218 $smin = (!empty($reg[5]) ? $reg[5] : '');
7219 } elseif (strval($set_time) != '' && $set_time != -1) {
7220 // set_time est un timestamps (0 possible)
7221 $syear = dol_print_date($set_time, "%Y", $gm);
7222 $smonth = dol_print_date($set_time, "%m", $gm);
7223 $sday = dol_print_date($set_time, "%d", $gm);
7224 if ($orig_set_time != '') {
7225 $shour = dol_print_date($set_time, "%H", $gm);
7226 $smin = dol_print_date($set_time, "%M", $gm);
7227 $ssec = dol_print_date($set_time, "%S", $gm);
7228 }
7229 } else {
7230 // Date est '' ou vaut -1
7231 $syear = '';
7232 $smonth = '';
7233 $sday = '';
7234 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7235 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7236 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7237 }
7238 if ($h == 3 || $h == 4) {
7239 $shour = '';
7240 }
7241 if ($m == 3) {
7242 $smin = '';
7243 }
7244
7245 $nowgmt = dol_now('gmt');
7246 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7247
7248 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7249 $usecalendar = 'combo';
7250 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7251 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
7252 }
7253 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7254 // If we use a text browser or screen reader, we use the 'combo' date selector
7255 $usecalendar = 'html';
7256 }
7257
7258 if ($d) {
7259 // Show date with popup
7260 if ($usecalendar != 'combo') {
7261 $formated_date = '';
7262 //print "e".$set_time." t ".$conf->format_date_short;
7263 if (strval($set_time) != '' && $set_time != -1) {
7264 //$formated_date=dol_print_date($set_time,$conf->format_date_short);
7265 $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7266 }
7267
7268 // Calendrier popup version eldy
7269 if ($usecalendar == "eldy") {
7270 // Input area to enter date manually
7271 $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formated_date . '"';
7272 $retstring .= ($disabled ? ' disabled' : '');
7273 $retstring .= ' onChange="dpChangeDay(\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7274 $retstring .= ' autocomplete="off">';
7275
7276 // Icon calendar
7277 $retstringbuttom = '';
7278 if (!$disabled) {
7279 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7280 $base = DOL_URL_ROOT . '/core/';
7281 $retstringbuttom .= ' onClick="showDP(\'' . $base . '\',\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\',\'' . $langs->defaultlang . '\');"';
7282 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
7283 } else {
7284 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7285 }
7286 $retstring = $retstringbuttom . $retstring;
7287
7288 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7289 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7290 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7291 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7292 if (!$disabled && $usecalendar != 'html') {
7293 // Output javascript for datepicker
7294 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7295 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7296
7297 $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
7298 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7299 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7300 autoclose: true,
7301 todayHighlight: true,
7302 yearRange: '" . $minYear . ":" . $maxYear . "',";
7303 if (!empty($conf->dol_use_jmobile)) {
7304 $retstring .= "
7305 beforeShow: function (input, datePicker) {
7306 input.disabled = true;
7307 },
7308 onClose: function (dateText, datePicker) {
7309 this.disabled = false;
7310 },
7311 ";
7312 }
7313 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7314 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7315 $retstring .= "
7316 showOn: 'button', /* both has problem with autocompletion */
7317 buttonImage: '" . DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png',
7318 buttonImageOnly: true";
7319 }
7320 $retstring .= "
7321 }) });";
7322 $retstring .= "</script>";
7323 }
7324
7325 // Input area to enter date manually
7326 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7327 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate center" maxlength="11" value="'.$formated_date.'"';
7328 $retstring .= ($disabled ? ' disabled' : '');
7329 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7330 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7331 $retstring .= ' autocomplete="off">';
7332
7333 // Icone calendrier
7334 if ($disabled) {
7335 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7336 $retstring = $retstringbutton . $retstring;
7337 }
7338
7339 $retstring .= '</div>';
7340 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7341 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7342 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7343 } else {
7344 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7345 }
7346 } else {
7347 // Show date with combo selects
7348 // Day
7349 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7350
7351 if ($emptydate || $set_time == -1) {
7352 $retstring .= '<option value="0" selected>&nbsp;</option>';
7353 }
7354
7355 for ($day = 1; $day <= 31; $day++) {
7356 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7357 }
7358
7359 $retstring .= "</select>";
7360
7361 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7362 if ($emptydate || $set_time == -1) {
7363 $retstring .= '<option value="0" selected>&nbsp;</option>';
7364 }
7365
7366 // Month
7367 for ($month = 1; $month <= 12; $month++) {
7368 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7369 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7370 $retstring .= "</option>";
7371 }
7372 $retstring .= "</select>";
7373
7374 // Year
7375 if ($emptydate || $set_time == -1) {
7376 $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 . '">';
7377 } else {
7378 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7379
7380 $syear = (int) $syear;
7381 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7382 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7383 }
7384 $retstring .= "</select>\n";
7385 }
7386 }
7387 }
7388
7389 if ($d && $h) {
7390 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7391 $retstring .= '<span class="nowraponall">';
7392 }
7393
7394 if ($h) {
7395 $hourstart = 0;
7396 $hourend = 24;
7397 if ($openinghours != '') {
7398 $openinghours = explode(',', $openinghours);
7399 $hourstart = $openinghours[0];
7400 $hourend = $openinghours[1];
7401 if ($hourend < $hourstart) {
7402 $hourend = $hourstart;
7403 }
7404 }
7405 // Show hour
7406 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7407 if ($emptyhours) {
7408 $retstring .= '<option value="-1">&nbsp;</option>';
7409 }
7410 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7411 if (strlen($hour) < 2) {
7412 $hour = "0" . $hour;
7413 }
7414 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7415 //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
7416 $retstring .= '</option>';
7417 }
7418 $retstring .= '</select>';
7419 //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
7420 if ($m) {
7421 $retstring .= ":";
7422 }
7423 }
7424
7425 if ($m) {
7426 // Show minutes
7427 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7428 if ($emptyhours) {
7429 $retstring .= '<option value="-1">&nbsp;</option>';
7430 }
7431 for ($min = 0; $min < 60; $min += $stepminutes) {
7432 $min_str = sprintf("%02d", $min);
7433 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7434 }
7435 $retstring .= '</select>';
7436
7437 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7438 }
7439
7440 if ($d && $h) {
7441 $retstring .= '</span>';
7442 }
7443
7444 // Add a "Now" link
7445 if (!empty($conf->use_javascript_ajax) && $addnowlink) {
7446 // Script which will be inserted in the onClick of the "Now" link
7447 $reset_scripts = "";
7448 if ($addnowlink == 2) { // local computer time
7449 // pad add leading 0 on numbers
7450 $reset_scripts .= "Number.prototype.pad = function(size) {
7451 var s = String(this);
7452 while (s.length < (size || 2)) {s = '0' + s;}
7453 return s;
7454 };
7455 var d = new Date();";
7456 }
7457
7458 // Generate the date part, depending on the use or not of the javascript calendar
7459 if ($addnowlink == 1) { // server time expressed in user time setup
7460 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7461 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7462 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7463 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7464 } elseif ($addnowlink == 2) {
7465 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7466 * This break application for foreign languages.
7467 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7468 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7469 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7470 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7471 */
7472 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7473 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7474 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7475 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7476 }
7477 /*if ($usecalendar == "eldy")
7478 {
7479 $base=DOL_URL_ROOT.'/core/';
7480 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7481 }
7482 else
7483 {
7484 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7485 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7486 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7487 }*/
7488 // Update the hour part
7489 if ($h) {
7490 if ($fullday) {
7491 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7492 }
7493 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7494 if ($addnowlink == 1) {
7495 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7496 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7497 } elseif ($addnowlink == 2) {
7498 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7499 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7500 }
7501
7502 if ($fullday) {
7503 $reset_scripts .= ' } ';
7504 }
7505 }
7506 // Update the minute part
7507 if ($m) {
7508 if ($fullday) {
7509 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7510 }
7511 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7512 if ($addnowlink == 1) {
7513 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7514 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7515 } elseif ($addnowlink == 2) {
7516 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7517 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7518 }
7519 if ($fullday) {
7520 $reset_scripts .= ' } ';
7521 }
7522 }
7523 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7524 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7525 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7526 $retstring .= $langs->trans("Now");
7527 $retstring .= '</button> ';
7528 }
7529 }
7530
7531 // Add a "Plus one hour" link
7532 if ($conf->use_javascript_ajax && $addplusone) {
7533 // Script which will be inserted in the onClick of the "Add plusone" link
7534 $reset_scripts = "";
7535
7536 // Generate the date part, depending on the use or not of the javascript calendar
7537 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7538 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7539 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7540 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7541 // Update the hour part
7542 if ($h) {
7543 if ($fullday) {
7544 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7545 }
7546 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7547 if ($fullday) {
7548 $reset_scripts .= ' } ';
7549 }
7550 }
7551 // Update the minute part
7552 if ($m) {
7553 if ($fullday) {
7554 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7555 }
7556 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7557 if ($fullday) {
7558 $reset_scripts .= ' } ';
7559 }
7560 }
7561 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7562 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7563 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7564 $retstring .= $langs->trans("DateStartPlusOne");
7565 $retstring .= '</button> ';
7566 }
7567 }
7568
7569 // Add a link to set data
7570 if ($conf->use_javascript_ajax && !empty($adddateof)) {
7571 if (!is_array($adddateof)) {
7572 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
7573 } else {
7574 $arrayofdateof = $adddateof;
7575 }
7576 foreach ($arrayofdateof as $valuedateof) {
7577 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
7578 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
7579 $tmparray = dol_getdate($tmpadddateof);
7580 if (empty($tmplabeladddateof)) {
7581 $tmplabeladddateof = $langs->trans("DateInvoice");
7582 }
7583 $reset_scripts = 'console.log(\'Click on now link\'); ';
7584 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7585 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7586 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7587 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7588 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7589 }
7590 }
7591
7592 return $retstring;
7593 }
7594
7603 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7604 {
7605 global $langs;
7606
7607 $TDurationTypes = array(
7608 'y' => $langs->trans('Years'),
7609 'm' => $langs->trans('Month'),
7610 'w' => $langs->trans('Weeks'),
7611 'd' => $langs->trans('Days'),
7612 'h' => $langs->trans('Hours'),
7613 'i' => $langs->trans('Minutes')
7614 );
7615
7616 // Removed undesired duration types
7617 foreach ($excludetypes as $value) {
7618 unset($TDurationTypes[$value]);
7619 }
7620
7621 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7622 foreach ($TDurationTypes as $key => $typeduration) {
7623 $retstring .= '<option value="' . $key . '"';
7624 if ($key == $selected) {
7625 $retstring .= " selected";
7626 }
7627 $retstring .= ">" . $typeduration . "</option>";
7628 }
7629 $retstring .= "</select>";
7630
7631 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7632
7633 return $retstring;
7634 }
7635
7636 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7637
7651 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7652 {
7653 // phpcs:enable
7654 global $langs;
7655
7656 $retstring = '<span class="nowraponall">';
7657
7658 $hourSelected = '';
7659 $minSelected = '';
7660
7661 // Hours
7662 if ($iSecond != '') {
7663 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7664
7665 $hourSelected = convertSecondToTime($iSecond, 'allhour');
7666 $minSelected = convertSecondToTime($iSecond, 'min');
7667 }
7668
7669 if ($typehour == 'select') {
7670 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7671 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7672 $retstring .= '<option value="' . $hour . '"';
7673 if (is_numeric($hourSelected) && $hourSelected == $hour) {
7674 $retstring .= " selected";
7675 }
7676 $retstring .= ">" . $hour . "</option>";
7677 }
7678 $retstring .= "</select>";
7679 } elseif ($typehour == 'text' || $typehour == 'textselect') {
7680 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7681 } else {
7682 return 'BadValueForParameterTypeHour';
7683 }
7684
7685 if ($typehour != 'text') {
7686 $retstring .= ' ' . $langs->trans('HourShort');
7687 } else {
7688 $retstring .= '<span class="">:</span>';
7689 }
7690
7691 // Minutes
7692 if ($minunderhours) {
7693 $retstring .= '<br>';
7694 } else {
7695 if ($typehour != 'text') {
7696 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7697 }
7698 }
7699
7700 if ($typehour == 'select' || $typehour == 'textselect') {
7701 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7702 for ($min = 0; $min <= 55; $min += 5) {
7703 $retstring .= '<option value="' . $min . '"';
7704 if (is_numeric($minSelected) && $minSelected == $min) {
7705 $retstring .= ' selected';
7706 }
7707 $retstring .= '>' . $min . '</option>';
7708 }
7709 $retstring .= "</select>";
7710 } elseif ($typehour == 'text') {
7711 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7712 }
7713
7714 if ($typehour != 'text') {
7715 $retstring .= ' ' . $langs->trans('MinuteShort');
7716 }
7717
7718 $retstring .= "</span>";
7719
7720 if (!empty($nooutput)) {
7721 return $retstring;
7722 }
7723
7724 print $retstring;
7725
7726 return '';
7727 }
7728
7748 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)
7749 {
7750 global $langs, $conf;
7751
7752 $out = '';
7753
7754 // check parameters
7755 if (is_null($ajaxoptions)) {
7756 $ajaxoptions = array();
7757 }
7758
7759 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7760 $placeholder = '';
7761
7762 if ($selected && empty($selected_input_value)) {
7763 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7764 $tickettmpselect = new Ticket($this->db);
7765 $tickettmpselect->fetch($selected);
7766 $selected_input_value = $tickettmpselect->ref;
7767 unset($tickettmpselect);
7768 }
7769
7770 $urloption = '';
7771 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7772
7773 if (empty($hidelabel)) {
7774 $out .= $langs->trans("RefOrLabel") . ' : ';
7775 } elseif ($hidelabel > 1) {
7776 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7777 if ($hidelabel == 2) {
7778 $out .= img_picto($langs->trans("Search"), 'search');
7779 }
7780 }
7781 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7782 if ($hidelabel == 3) {
7783 $out .= img_picto($langs->trans("Search"), 'search');
7784 }
7785 } else {
7786 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7787 }
7788
7789 if (empty($nooutput)) {
7790 print $out;
7791 } else {
7792 return $out;
7793 }
7794 return '';
7795 }
7796
7797
7814 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7815 {
7816 global $langs, $conf;
7817
7818 $out = '';
7819 $outarray = array();
7820
7821 $selectFields = " p.rowid, p.ref, p.message";
7822
7823 $sql = "SELECT ";
7824 $sql .= $selectFields;
7825 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7826 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7827
7828 // Add criteria on ref/label
7829 if ($filterkey != '') {
7830 $sql .= ' AND (';
7831 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7832 // For natural search
7833 $search_crit = explode(' ', $filterkey);
7834 $i = 0;
7835 if (count($search_crit) > 1) {
7836 $sql .= "(";
7837 }
7838 foreach ($search_crit as $crit) {
7839 if ($i > 0) {
7840 $sql .= " AND ";
7841 }
7842 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7843 $sql .= ")";
7844 $i++;
7845 }
7846 if (count($search_crit) > 1) {
7847 $sql .= ")";
7848 }
7849 $sql .= ')';
7850 }
7851
7852 $sql .= $this->db->plimit($limit, 0);
7853
7854 // Build output string
7855 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7856 $result = $this->db->query($sql);
7857 if ($result) {
7858 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7859 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7860
7861 $num = $this->db->num_rows($result);
7862
7863 $events = array();
7864
7865 if (!$forcecombo) {
7866 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7867 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('TICKET_USE_SEARCH_TO_SELECT'));
7868 }
7869
7870 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7871
7872 $textifempty = '';
7873 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7874 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7875 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7876 if ($showempty && !is_numeric($showempty)) {
7877 $textifempty = $langs->trans($showempty);
7878 } else {
7879 $textifempty .= $langs->trans("All");
7880 }
7881 } else {
7882 if ($showempty && !is_numeric($showempty)) {
7883 $textifempty = $langs->trans($showempty);
7884 }
7885 }
7886 if ($showempty) {
7887 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7888 }
7889
7890 $i = 0;
7891 while ($num && $i < $num) {
7892 $opt = '';
7893 $optJson = array();
7894 $objp = $this->db->fetch_object($result);
7895
7896 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7897 '@phan-var-force array{key:string,value:mixed,type:int} $optJson';
7898 // Add new entry
7899 // "key" value of json key array is used by jQuery automatically as selected value
7900 // "label" value of json key array is used by jQuery automatically as text for combo box
7901 $out .= $opt;
7902 array_push($outarray, $optJson);
7903
7904 $i++;
7905 }
7906
7907 $out .= '</select>';
7908
7909 $this->db->free($result);
7910
7911 if (empty($outputmode)) {
7912 return $out;
7913 }
7914 return $outarray;
7915 } else {
7916 dol_print_error($this->db);
7917 }
7918
7919 return array();
7920 }
7921
7933 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7934 {
7935 $outkey = '';
7936 $outref = '';
7937 $outtype = '';
7938
7939 $outkey = $objp->rowid;
7940 $outref = $objp->ref;
7941
7942 $opt = '<option value="' . $objp->rowid . '"';
7943 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7944 $opt .= '>';
7945 $opt .= $objp->ref;
7946 $objRef = $objp->ref;
7947 if (!empty($filterkey) && $filterkey != '') {
7948 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7949 }
7950
7951 $opt .= "</option>\n";
7952 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7953 }
7954
7974 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)
7975 {
7976 global $langs, $conf;
7977
7978 $out = '';
7979
7980 // check parameters
7981 if (is_null($ajaxoptions)) {
7982 $ajaxoptions = array();
7983 }
7984
7985 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7986 $placeholder = '';
7987
7988 if ($selected && empty($selected_input_value)) {
7989 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7990 $projecttmpselect = new Project($this->db);
7991 $projecttmpselect->fetch($selected);
7992 $selected_input_value = $projecttmpselect->ref;
7993 unset($projecttmpselect);
7994 }
7995
7996 $urloption = '';
7997 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7998
7999 if (empty($hidelabel)) {
8000 $out .= $langs->trans("RefOrLabel") . ' : ';
8001 } elseif ($hidelabel > 1) {
8002 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8003 if ($hidelabel == 2) {
8004 $out .= img_picto($langs->trans("Search"), 'search');
8005 }
8006 }
8007 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8008 if ($hidelabel == 3) {
8009 $out .= img_picto($langs->trans("Search"), 'search');
8010 }
8011 } else {
8012 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8013 }
8014
8015 if (empty($nooutput)) {
8016 print $out;
8017 } else {
8018 return $out;
8019 }
8020 return '';
8021 }
8022
8039 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8040 {
8041 global $langs, $conf;
8042
8043 $out = '';
8044 $outarray = array();
8045
8046 $selectFields = " p.rowid, p.ref";
8047
8048 $sql = "SELECT ";
8049 $sql .= $selectFields;
8050 $sql .= " FROM " . $this->db->prefix() . "projet as p";
8051 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
8052
8053 // Add criteria on ref/label
8054 if ($filterkey != '') {
8055 $sql .= ' AND (';
8056 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8057 // For natural search
8058 $search_crit = explode(' ', $filterkey);
8059 $i = 0;
8060 if (count($search_crit) > 1) {
8061 $sql .= "(";
8062 }
8063 foreach ($search_crit as $crit) {
8064 if ($i > 0) {
8065 $sql .= " AND ";
8066 }
8067 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8068 $sql .= "";
8069 $i++;
8070 }
8071 if (count($search_crit) > 1) {
8072 $sql .= ")";
8073 }
8074 $sql .= ')';
8075 }
8076
8077 $sql .= $this->db->plimit($limit, 0);
8078
8079 // Build output string
8080 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
8081 $result = $this->db->query($sql);
8082 if ($result) {
8083 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8084 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
8085
8086 $num = $this->db->num_rows($result);
8087
8088 $events = array();
8089
8090 if (!$forcecombo) {
8091 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8092 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8093 }
8094
8095 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8096
8097 $textifempty = '';
8098 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8099 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8100 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8101 if ($showempty && !is_numeric($showempty)) {
8102 $textifempty = $langs->trans($showempty);
8103 } else {
8104 $textifempty .= $langs->trans("All");
8105 }
8106 } else {
8107 if ($showempty && !is_numeric($showempty)) {
8108 $textifempty = $langs->trans($showempty);
8109 }
8110 }
8111 if ($showempty) {
8112 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8113 }
8114
8115 $i = 0;
8116 while ($num && $i < $num) {
8117 $opt = '';
8118 $optJson = array();
8119 $objp = $this->db->fetch_object($result);
8120
8121 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
8122 // Add new entry
8123 // "key" value of json key array is used by jQuery automatically as selected value
8124 // "label" value of json key array is used by jQuery automatically as text for combo box
8125 $out .= $opt;
8126 array_push($outarray, $optJson);
8127
8128 $i++;
8129 }
8130
8131 $out .= '</select>';
8132
8133 $this->db->free($result);
8134
8135 if (empty($outputmode)) {
8136 return $out;
8137 }
8138 return $outarray;
8139 } else {
8140 dol_print_error($this->db);
8141 }
8142
8143 return array();
8144 }
8145
8157 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8158 {
8159 $outkey = '';
8160 $outref = '';
8161 $outtype = '';
8162
8163 $label = $objp->label;
8164
8165 $outkey = $objp->rowid;
8166 $outref = $objp->ref;
8167 $outlabel = $objp->label;
8168 $outtype = $objp->fk_product_type;
8169
8170 $opt = '<option value="' . $objp->rowid . '"';
8171 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8172 $opt .= '>';
8173 $opt .= $objp->ref;
8174 $objRef = $objp->ref;
8175 if (!empty($filterkey) && $filterkey != '') {
8176 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8177 }
8178
8179 $opt .= "</option>\n";
8180 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8181 }
8182
8183
8203 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)
8204 {
8205 global $langs, $conf;
8206
8207 $out = '';
8208
8209 // check parameters
8210 if (is_null($ajaxoptions)) {
8211 $ajaxoptions = array();
8212 }
8213
8214 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8215 $placeholder = '';
8216
8217 if ($selected && empty($selected_input_value)) {
8218 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8219 $adherenttmpselect = new Adherent($this->db);
8220 $adherenttmpselect->fetch($selected);
8221 $selected_input_value = $adherenttmpselect->ref;
8222 unset($adherenttmpselect);
8223 }
8224
8225 $urloption = '';
8226
8227 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8228
8229 if (empty($hidelabel)) {
8230 $out .= $langs->trans("RefOrLabel") . ' : ';
8231 } elseif ($hidelabel > 1) {
8232 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8233 if ($hidelabel == 2) {
8234 $out .= img_picto($langs->trans("Search"), 'search');
8235 }
8236 }
8237 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8238 if ($hidelabel == 3) {
8239 $out .= img_picto($langs->trans("Search"), 'search');
8240 }
8241 } else {
8242 $filterkey = '';
8243
8244 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8245 }
8246
8247 if (empty($nooutput)) {
8248 print $out;
8249 } else {
8250 return $out;
8251 }
8252 return '';
8253 }
8254
8271 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8272 {
8273 global $langs, $conf;
8274
8275 $out = '';
8276 $outarray = array();
8277
8278 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8279
8280 $sql = "SELECT ";
8281 $sql .= $selectFields;
8282 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8283 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8284
8285 // Add criteria on ref/label
8286 if ($filterkey != '') {
8287 $sql .= ' AND (';
8288 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8289 // For natural search
8290 $search_crit = explode(' ', $filterkey);
8291 $i = 0;
8292 if (count($search_crit) > 1) {
8293 $sql .= "(";
8294 }
8295 foreach ($search_crit as $crit) {
8296 if ($i > 0) {
8297 $sql .= " AND ";
8298 }
8299 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8300 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8301 $i++;
8302 }
8303 if (count($search_crit) > 1) {
8304 $sql .= ")";
8305 }
8306 $sql .= ')';
8307 }
8308 if ($status != -1) {
8309 $sql .= ' AND statut = ' . ((int) $status);
8310 }
8311 $sql .= $this->db->plimit($limit, 0);
8312
8313 // Build output string
8314 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8315 $result = $this->db->query($sql);
8316 if ($result) {
8317 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8318 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8319
8320 $num = $this->db->num_rows($result);
8321
8322 $events = array();
8323
8324 if (!$forcecombo) {
8325 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8326 $out .= ajax_combobox($htmlname, $events, getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT') ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
8327 }
8328
8329 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8330
8331 $textifempty = '';
8332 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8333 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8334 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8335 if ($showempty && !is_numeric($showempty)) {
8336 $textifempty = $langs->trans($showempty);
8337 } else {
8338 $textifempty .= $langs->trans("All");
8339 }
8340 } else {
8341 if ($showempty && !is_numeric($showempty)) {
8342 $textifempty = $langs->trans($showempty);
8343 }
8344 }
8345 if ($showempty) {
8346 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8347 }
8348
8349 $i = 0;
8350 while ($num && $i < $num) {
8351 $opt = '';
8352 $optJson = array();
8353 $objp = $this->db->fetch_object($result);
8354
8355 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8356
8357 // Add new entry
8358 // "key" value of json key array is used by jQuery automatically as selected value
8359 // "label" value of json key array is used by jQuery automatically as text for combo box
8360 $out .= $opt;
8361 array_push($outarray, $optJson);
8362
8363 $i++;
8364 }
8365
8366 $out .= '</select>';
8367
8368 $this->db->free($result);
8369
8370 if (empty($outputmode)) {
8371 return $out;
8372 }
8373 return $outarray;
8374 } else {
8375 dol_print_error($this->db);
8376 }
8377
8378 return array();
8379 }
8380
8392 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8393 {
8394 $outkey = '';
8395 $outlabel = '';
8396 $outtype = '';
8397
8398 $outkey = $objp->rowid;
8399 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8400 $outtype = $objp->fk_adherent_type;
8401
8402 $opt = '<option value="' . $objp->rowid . '"';
8403 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8404 $opt .= '>';
8405 if (!empty($filterkey) && $filterkey != '') {
8406 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8407 }
8408 $opt .= $outlabel;
8409 $opt .= "</option>\n";
8410
8411 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8412 }
8413
8434 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8435 {
8436 global $conf, $extrafields, $user;
8437
8438 // Example of common usage for a link to a thirdparty
8439
8440 // We got this in a modulebuilder form of "MyObject" of module "mymodule".
8441 // ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8442 // $objectdesc = 'Societe'
8443 // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc'])
8444
8445 // We got this when showing an extrafields on resource that is a link to societe
8446 // extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)'
8447 // $objectdesc = 'Societe'
8448 // $objectfield = 'resource:options_link_to_societe'
8449
8450 // With old usage:
8451 // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))'
8452 // $objectfield = ''
8453
8454 //var_dump($objectdesc.' '.$objectfield);
8455 //debug_print_backtrace();
8456
8457 $objectdescorig = $objectdesc;
8458 $objecttmp = null;
8459 $InfoFieldList = array();
8460 $classname = '';
8461 $filter = ''; // Ensure filter has value (for static analysis)
8462 $sortfield = ''; // Ensure filter has value (for static analysis)
8463
8464 if ($objectfield) { // We must retrieve the objectdesc from the field or extrafield
8465 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8466 $tmparray = explode(':', $objectfield);
8467
8468 // Get instance of object from $element
8469 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8470
8471 if (is_object($objectforfieldstmp)) {
8472 $objectdesc = '';
8473
8474 $reg = array();
8475 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8476 // For a property in extrafields
8477 $key = $reg[1];
8478 // fetch optionals attributes and labels
8479 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8480
8481 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8482 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8483 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8484 $objectdesc = $tmpextrafields[0];
8485 }
8486 }
8487 } else {
8488 // For a property in ->fields
8489 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8490 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8491 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8492 }
8493 }
8494 }
8495 }
8496
8497 if ($objectdesc) {
8498 // Example of value for $objectdesc:
8499 // Bom:bom/class/bom.class.php:0:t.status=1
8500 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8501 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8502 $InfoFieldList = explode(":", $objectdesc, 4);
8503 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8504 $reg = array();
8505 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8506 $InfoFieldList[4] = $reg[1]; // take the sort field
8507 }
8508 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8509
8510 $classname = $InfoFieldList[0];
8511 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8512 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8513 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8514 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8515
8516 // Load object according to $id and $element
8517 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8518
8519 // Fallback to another solution to get $objecttmp
8520 if (empty($objecttmp) && !empty($classpath)) {
8521 dol_include_once($classpath);
8522
8523 if ($classname && class_exists($classname)) {
8524 $objecttmp = new $classname($this->db);
8525 }
8526 }
8527 }
8528
8529 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
8530 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
8531 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
8532 $filter = str_replace(
8533 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
8534 array($conf->entity, $sharedentities, $user->id),
8535 $filter
8536 );
8537
8538 if (!is_object($objecttmp)) {
8539 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc, LOG_WARNING);
8540 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc;
8541 }
8542 '@phan-var-force CommonObject $objecttmp';
8544 //var_dump($filter);
8545 $prefixforautocompletemode = $objecttmp->element;
8546 if ($prefixforautocompletemode == 'societe') {
8547 $prefixforautocompletemode = 'company';
8548 }
8549 if ($prefixforautocompletemode == 'product') {
8550 $prefixforautocompletemode = 'produit';
8551 }
8552 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8553
8554 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
8555
8556 // Generate the combo HTML component
8557 $out = '';
8558 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
8559 // No immediate load of all database
8560 $placeholder = '';
8561
8562 if ($preSelectedValue && empty($selected_input_value)) {
8563 $objecttmp->fetch($preSelectedValue);
8564 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
8565
8566 $oldValueForShowOnCombobox = 0;
8567 foreach ($objecttmp->fields as $fieldK => $fielV) {
8568 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
8569 continue;
8570 }
8571
8572 if (!$oldValueForShowOnCombobox) {
8573 $selected_input_value = '';
8574 }
8575
8576 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
8577 $selected_input_value .= $objecttmp->$fieldK;
8578 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
8579 }
8580 }
8581
8582 // Set url and param to call to get json of the search results
8583 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
8584 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . '&objectfield='.urlencode($objectfield) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
8585
8586 // Activate the auto complete using ajax call.
8587 $out .= ajax_autocompleter((string) $preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalInt($confkeyforautocompletemode), 0);
8588 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
8589 $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) . '"' : '') . ' />';
8590 } else {
8591 // Immediate load of table record.
8592 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
8593 }
8594
8595 return $out;
8596 }
8597
8598
8619 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
8620 {
8621 global $langs, $user, $hookmanager;
8622
8623 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
8624
8625 $prefixforautocompletemode = $objecttmp->element;
8626 if ($prefixforautocompletemode == 'societe') {
8627 $prefixforautocompletemode = 'company';
8628 }
8629 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8630
8631 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
8632 $tmpfieldstoshow = '';
8633 foreach ($objecttmp->fields as $key => $val) {
8634 if (! (int) dol_eval($val['enabled'], 1, 1, '1')) {
8635 continue;
8636 }
8637 if (!empty($val['showoncombobox'])) {
8638 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8639 }
8640 }
8641 if ($tmpfieldstoshow) {
8642 $fieldstoshow = $tmpfieldstoshow;
8643 }
8644 } else {
8645 // For backward compatibility
8646 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8647 }
8648
8649 if (empty($fieldstoshow)) {
8650 if (!empty($objecttmp->parent_element)) {
8651 $fieldstoshow = 'o.ref';
8652 if (empty($sortfield)) {
8653 $sortfield = 'o.ref';
8654 }
8655 if (in_array($objecttmp->element, ['commandedet', 'propaldet', 'facturedet', 'expeditiondet'])) {
8656 $fieldstoshow .= ',p.ref AS p_ref,p.label,t.description';
8657 $sortfield .= ', p.ref';
8658 }
8659 } elseif (isset($objecttmp->fields['ref'])) {
8660 $fieldstoshow = 't.ref';
8661 } else {
8662 $langs->load("errors");
8663 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8664 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8665 }
8666 }
8667
8668 $out = '';
8669 $outarray = array();
8670 $tmparray = array();
8671
8672 $num = 0;
8673
8674 // Search data
8675 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . " as t";
8676 if (!empty($objecttmp->isextrafieldmanaged)) {
8677 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . "_extrafields as e ON t.rowid = e.fk_object";
8678 }
8679 if (!empty($objecttmp->parent_element)) {
8680 $parent_properties = getElementProperties($objecttmp->parent_element);
8681 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($parent_properties['table_element']) . " as o ON o.rowid = t.".$objecttmp->fk_parent_attribute;
8682 }
8683 if (in_array($objecttmp->parent_element, ['commande', 'propal', 'facture', 'expedition'])) {
8684 $sql .= " LEFT JOIN " . $this->db->prefix() . "product as p ON p.rowid = t.fk_product";
8685 }
8686 if (isset($objecttmp->ismultientitymanaged)) {
8687 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8688 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8689 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($tmparray[1]) . " as parenttable ON parenttable.rowid = t." . $this->db->sanitize($tmparray[0]);
8690 }
8691 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8692 if (!$user->hasRight('societe', 'client', 'voir')) {
8693 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8694 }
8695 }
8696 }
8697
8698 // Add where from hooks
8699 $parameters = array(
8700 'object' => $objecttmp,
8701 'htmlname' => $htmlname,
8702 'filter' => $filter,
8703 'searchkey' => $searchkey
8704 );
8705
8706 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8707 if (!empty($hookmanager->resPrint)) {
8708 $sql .= $hookmanager->resPrint;
8709 } else {
8710 $sql .= " WHERE 1=1";
8711 if (isset($objecttmp->ismultientitymanaged)) {
8712 if ($objecttmp->ismultientitymanaged == 1) {
8713 $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8714 }
8715 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8716 $sql .= " AND parenttable.entity = t." . $this->db->sanitize($tmparray[0]);
8717 }
8718 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8719 if ($objecttmp->element == 'societe') {
8720 $sql .= " AND t.rowid = " . ((int) $user->socid);
8721 } else {
8722 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8723 }
8724 }
8725 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8726 if (!$user->hasRight('societe', 'client', 'voir')) {
8727 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8728 }
8729 }
8730 }
8731 $splittedfieldstoshow = explode(',', $fieldstoshow);
8732 foreach ($splittedfieldstoshow as &$field2) {
8733 if (is_numeric($pos=strpos($field2, ' '))) {
8734 $field2 = substr($field2, 0, $pos);
8735 }
8736 }
8737 if ($searchkey != '') {
8738 $sql .= natural_search($splittedfieldstoshow, $searchkey);
8739 }
8740
8741 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8742 $errormessage = '';
8743 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8744 if ($errormessage) {
8745 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8746 }
8747 }
8748 }
8749 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8750 //$sql.=$this->db->plimit($limit, 0);
8751 //print $sql;
8752
8753 // Build output string
8754 $resql = $this->db->query($sql);
8755 if ($resql) {
8756 // Construct $out and $outarray
8757 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8758
8759 // 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
8760 $textifempty = '&nbsp;';
8761
8762 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8763 if (getDolGlobalInt($confkeyforautocompletemode)) {
8764 if ($showempty && !is_numeric($showempty)) {
8765 $textifempty = $langs->trans($showempty);
8766 } else {
8767 $textifempty .= $langs->trans("All");
8768 }
8769 }
8770 if ($showempty) {
8771 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8772 }
8773
8774 $num = $this->db->num_rows($resql);
8775 $i = 0;
8776 if ($num) {
8777 while ($i < $num) {
8778 $obj = $this->db->fetch_object($resql);
8779 $label = '';
8780 $labelhtml = '';
8781 $tmparray = explode(',', $fieldstoshow);
8782 $oldvalueforshowoncombobox = 0;
8783 foreach ($tmparray as $key => $val) {
8784 $val = preg_replace('/(t|p|o)\./', '', $val);
8785 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8786 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8787 $label .= $obj->$val;
8788 $labelhtml .= $obj->$val;
8789
8790 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8791 }
8792 if (empty($outputmode)) {
8793 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8794 $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>';
8795 } else {
8796 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8797 }
8798 } else {
8799 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8800 }
8801
8802 $i++;
8803 if (($i % 10) == 0) {
8804 $out .= "\n";
8805 }
8806 }
8807 }
8808
8809 $out .= '</select>' . "\n";
8810
8811 if (!$forcecombo) {
8812 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8813 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
8814 }
8815 } else {
8816 dol_print_error($this->db);
8817 }
8818
8819 $this->result = array('nbofelement' => $num);
8820
8821 if ($outputmode) {
8822 return $outarray;
8823 }
8824 return $out;
8825 }
8826
8827
8851 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)
8852 {
8853 global $conf, $langs;
8854
8855 // Do we want a multiselect ?
8856 //$jsbeautify = 0;
8857 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8858 $jsbeautify = 1;
8859
8860 if ($value_as_key) {
8861 $array = array_combine($array, $array);
8862 }
8863
8864 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
8865
8866 $out = '';
8867
8868 if ($addjscombo < 0) {
8869 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8870 $addjscombo = 1;
8871 } else {
8872 $addjscombo = 0;
8873 }
8874 }
8875 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8876 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8877 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8878 $out .= '>'."\n";
8879
8880 if ($show_empty) {
8881 $textforempty = ' ';
8882 if (!empty($conf->use_javascript_ajax)) {
8883 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8884 }
8885 if (!is_numeric($show_empty)) {
8886 $textforempty = $show_empty;
8887 }
8888 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8889 }
8890 if (is_array($array)) {
8891 // Translate
8892 if ($translate) {
8893 foreach ($array as $key => $value) {
8894 if (!is_array($value)) {
8895 $array[$key] = $langs->trans($value);
8896 } else {
8897 $array[$key]['label'] = $langs->trans($value['label']);
8898 }
8899 }
8900 }
8901 // Sort
8902 if ($sort == 'ASC') {
8903 asort($array);
8904 } elseif ($sort == 'DESC') {
8905 arsort($array);
8906 }
8907
8908 foreach ($array as $key => $tmpvalue) {
8909 if (is_array($tmpvalue)) {
8910 $value = $tmpvalue['label'];
8911 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
8912 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8913 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8914 } else {
8915 $value = $tmpvalue;
8916 //$valuehtml = $tmpvalue;
8917 $disabled = '';
8918 $style = '';
8919 }
8920 if (!empty($disablebademail)) {
8921 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8922 || ($disablebademail == 2 && preg_match('/---/', $value))) {
8923 $disabled = ' disabled';
8924 $style = ' class="warning"';
8925 }
8926 }
8927 if ($key_in_label) {
8928 if (empty($nohtmlescape)) {
8929 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8930 } else {
8931 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8932 }
8933 } else {
8934 if (empty($nohtmlescape)) {
8935 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
8936 } else {
8937 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8938 }
8939 if ($value == '' || $value == '-') {
8940 $selectOptionValue = '&nbsp;';
8941 }
8942 }
8943 $out .= '<option value="' . $key . '"';
8944 $out .= $style . $disabled;
8945 if (is_array($id)) {
8946 if (in_array($key, $id) && !$disabled) {
8947 $out .= ' selected'; // To preselect a value
8948 }
8949 } else {
8950 $id = (string) $id; // if $id = 0, then $id = '0'
8951 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8952 $out .= ' selected'; // To preselect a value
8953 }
8954 }
8955 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
8956 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
8957 }
8958
8959 if (is_array($tmpvalue)) {
8960 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
8961 if ($keyforvalue == 'labelhtml') {
8962 $keyforvalue = 'data-html';
8963 }
8964 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
8965 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
8966 }
8967 }
8968 }
8969 $out .= '>';
8970 $out .= $selectOptionValue;
8971 $out .= "</option>\n";
8972 }
8973 }
8974 $out .= "</select>";
8975
8976 // Add code for jquery to use multiselect
8977 if ($addjscombo && $jsbeautify) {
8978 // Enhance with select2
8979 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8980 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
8981 }
8982
8983 return $out;
8984 }
8985
9004 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
9005 {
9006 global $conf, $langs;
9007 global $delayedhtmlcontent; // Will be used later outside of this function
9008
9009 // TODO Use an internal dolibarr component instead of select2
9010 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9011 return '';
9012 }
9013
9014 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
9015
9016 $outdelayed = '';
9017 if (!empty($conf->use_javascript_ajax)) {
9018 $tmpplugin = 'select2';
9019 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9020 <script nonce="' . getNonce() . '">
9021 $(document).ready(function () {
9022
9023 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
9024
9025 $(".' . $htmlname . '").select2({
9026 ajax: {
9027 dir: "ltr",
9028 url: "' . $url . '",
9029 dataType: \'json\',
9030 delay: 250,
9031 data: function (params) {
9032 return {
9033 q: params.term, // search term
9034 page: params.page
9035 }
9036 },
9037 processResults: function (data) {
9038 // parse the results into the format expected by Select2.
9039 // since we are using custom formatting functions we do not need to alter the remote JSON data
9040 //console.log(data);
9041 saveRemoteData = data;
9042 /* format json result for select2 */
9043 result = []
9044 $.each( data, function( key, value ) {
9045 result.push({id: key, text: value.text});
9046 });
9047 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
9048 //console.log(result);
9049 return {results: result, more: false}
9050 },
9051 cache: true
9052 },
9053 language: select2arrayoflanguage,
9054 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9055 placeholder: "' . dol_escape_js($placeholder) . '",
9056 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9057 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9058 formatResult: function (result, container, query, escapeMarkup) {
9059 return escapeMarkup(result.text);
9060 },
9061 });
9062
9063 ' . ($callurlonselect ? '
9064 /* Code to execute a GET when we select a value */
9065 $(".' . $htmlname . '").change(function() {
9066 var selected = $(".' . $htmlname . '").val();
9067 console.log("We select in selectArrayAjax the entry "+selected)
9068 $(".' . $htmlname . '").val(""); /* reset visible combo value */
9069 $.each( saveRemoteData, function( key, value ) {
9070 if (key == selected)
9071 {
9072 console.log("selectArrayAjax - Do a redirect to "+value.url)
9073 location.assign(value.url);
9074 }
9075 });
9076 });' : '') . '
9077
9078 });
9079 </script>';
9080 }
9081
9082 if ($acceptdelayedhtml) {
9083 $delayedhtmlcontent .= $outdelayed;
9084 } else {
9085 $out .= $outdelayed;
9086 }
9087 return $out;
9088 }
9089
9109 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
9110 {
9111 global $conf, $langs;
9112 global $delayedhtmlcontent; // Will be used later outside of this function
9113
9114 // TODO Use an internal dolibarr component instead of select2
9115 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9116 return '';
9117 }
9118
9119 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
9120
9121 $formattedarrayresult = array();
9122
9123 foreach ($array as $key => $value) {
9124 $o = new stdClass();
9125 $o->id = $key;
9126 $o->text = $value['text'];
9127 $o->url = $value['url'];
9128 $formattedarrayresult[] = $o;
9129 }
9130
9131 $outdelayed = '';
9132 if (!empty($conf->use_javascript_ajax)) {
9133 $tmpplugin = 'select2';
9134 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9135 <script nonce="' . getNonce() . '">
9136 $(document).ready(function () {
9137 var data = ' . json_encode($formattedarrayresult) . ';
9138
9139 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
9140
9141 $(".' . $htmlname . '").select2({
9142 data: data,
9143 language: select2arrayoflanguage,
9144 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9145 placeholder: "' . dol_escape_js($placeholder) . '",
9146 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9147 minimumInputLength: ' . $minimumInputLength . ',
9148 formatResult: function (result, container, query, escapeMarkup) {
9149 return escapeMarkup(result.text);
9150 },
9151 matcher: function (params, data) {
9152
9153 if(! data.id) return null;';
9154
9155 if ($callurlonselect) {
9156 // We forge the url with 'sall='
9157 $outdelayed .= '
9158
9159 var urlBase = data.url;
9160 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
9161 /* console.log("params.term="+params.term); */
9162 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
9163 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
9164 }
9165
9166 if (!$disableFiltering) {
9167 $outdelayed .= '
9168
9169 if(data.text.match(new RegExp(params.term))) {
9170 return data;
9171 }
9172
9173 return null;';
9174 } else {
9175 $outdelayed .= '
9176
9177 return data;';
9178 }
9179
9180 $outdelayed .= '
9181 }
9182 });
9183
9184 ' . ($callurlonselect ? '
9185 /* Code to execute a GET when we select a value */
9186 $(".' . $htmlname . '").change(function() {
9187 var selected = $(".' . $htmlname . '").val();
9188 console.log("We select "+selected)
9189
9190 $(".' . $htmlname . '").val(""); /* reset visible combo value */
9191 $.each( saveRemoteData, function( key, value ) {
9192 if (key == selected)
9193 {
9194 console.log("selectArrayFilter - Do a redirect to "+value.url)
9195 location.assign(value.url);
9196 }
9197 });
9198 });' : '') . '
9199
9200 });
9201 </script>';
9202 }
9203
9204 if ($acceptdelayedhtml) {
9205 $delayedhtmlcontent .= $outdelayed;
9206 } else {
9207 $out .= $outdelayed;
9208 }
9209 return $out;
9210 }
9211
9230 public static function multiselectarray($htmlname, $array, $selected = array(), $key_in_label = 0, $value_as_key = 0, $morecss = '', $translate = 0, $width = 0, $moreattrib = '', $elemtype = '', $placeholder = '', $addjscombo = -1)
9231 {
9232 global $conf, $langs;
9233 $out = '';
9234
9235 if ($addjscombo < 0) {
9236 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9237 $addjscombo = 1;
9238 } else {
9239 $addjscombo = 0;
9240 }
9241 }
9242
9243 $useenhancedmultiselect = 0;
9244 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9245 if ($addjscombo) {
9246 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9247 }
9248 }
9249
9250 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9251 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9252 // submitted to nothing.
9253 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9254 // Output select component
9255 $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";
9256 if (is_array($array) && !empty($array)) {
9257 if ($value_as_key) {
9258 $array = array_combine($array, $array);
9259 }
9260
9261 if (!empty($array)) {
9262 foreach ($array as $key => $value) {
9263 $tmpkey = $key;
9264 $tmpvalue = $value;
9265 $tmpcolor = '';
9266 $tmppicto = '';
9267 $tmplabelhtml = '';
9268 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9269 $tmpkey = $value['id'];
9270 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9271 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9272 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9273 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']) : $value['labelhtml'];
9274 }
9275 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9276 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9277
9278 $out .= '<option value="' . $tmpkey . '"';
9279 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9280 $out .= ' selected';
9281 }
9282 if (!empty($tmplabelhtml)) {
9283 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9284 } else {
9285 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9286 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9287 }
9288 $out .= '>';
9289 $out .= dol_htmlentitiesbr($newval);
9290 $out .= '</option>' . "\n";
9291 }
9292 }
9293 }
9294 $out .= '</select>' . "\n";
9295
9296 // Add code for jquery to use multiselect
9297 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9298 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9299 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9300 if ($addjscombo == 1) {
9301 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
9302 $out .= 'function formatResult(record, container) {' . "\n";
9303 // If property data-html set, we decode html entities and use this.
9304 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9305 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9306 //$out .= ' console.log("aaa");';
9307 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9308 $out .= ' }'."\n";
9309 $out .= ' return record.text;';
9310 $out .= '}' . "\n";
9311 $out .= 'function formatSelection(record) {' . "\n";
9312 if ($elemtype == 'category') {
9313 $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
9314 } else {
9315 $out .= 'return record.text;';
9316 }
9317 $out .= '}' . "\n";
9318 $out .= '$(document).ready(function () {
9319 $(\'#' . $htmlname . '\').' . $tmpplugin . '({';
9320 if ($placeholder) {
9321 $out .= '
9322 placeholder: {
9323 id: \'-1\',
9324 text: \'' . dol_escape_js($placeholder) . '\'
9325 },';
9326 }
9327 $out .= ' dir: \'ltr\',
9328 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9329 dropdownCssClass: \'' . $morecss . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
9330 // Specify format function for dropdown item
9331 formatResult: formatResult,
9332 templateResult: formatResult, /* For 4.0 */
9333 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9334 // Specify format function for selected item
9335 formatSelection: formatSelection,
9336 templateSelection: formatSelection /* For 4.0 */
9337 });
9338
9339 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
9340 the size only if component is not hidden by default on load */
9341 $(\'#' . $htmlname . ' + .select2\').addClass(\'' . $morecss . '\');
9342 });' . "\n";
9343 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9344 // Add other js lib
9345 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9346 // ...
9347 $out .= 'console.log(\'addjscombo=2 for htmlname=' . $htmlname . '\');';
9348 $out .= '$(document).ready(function () {
9349 $(\'#' . $htmlname . '\').multiSelect({
9350 containerHTML: \'<div class="multi-select-container">\',
9351 menuHTML: \'<div class="multi-select-menu">\',
9352 buttonHTML: \'<span class="multi-select-button ' . $morecss . '">\',
9353 menuItemHTML: \'<label class="multi-select-menuitem">\',
9354 activeClass: \'multi-select-container--open\',
9355 noneText: \'' . $placeholder . '\'
9356 });
9357 })';
9358 }
9359 $out .= '</script>';
9360 }
9361
9362 return $out;
9363 }
9364
9365
9377 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9378 {
9379 global $langs, $user;
9380
9381 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9382 return '';
9383 }
9384 if (empty($array)) {
9385 return '';
9386 }
9387
9388 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9389
9390 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9391 $tmparray = explode(',', $user->conf->$tmpvar);
9392 foreach ($array as $key => $val) {
9393 //var_dump($key);
9394 //var_dump($tmparray);
9395 if (in_array($key, $tmparray)) {
9396 $array[$key]['checked'] = 1;
9397 } else {
9398 $array[$key]['checked'] = 0;
9399 }
9400 }
9401 } else { // There is no list of fields already customized for user
9402 foreach ($array as $key => $val) {
9403 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9404 $array[$key]['checked'] = 0;
9405 }
9406 }
9407 }
9408
9409 $listoffieldsforselection = '';
9410 $listcheckedstring = '';
9411
9412 foreach ($array as $key => $val) {
9413 // var_dump($val);
9414 // var_dump(array_key_exists('enabled', $val));
9415 // var_dump(!$val['enabled']);
9416 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9417 unset($array[$key]); // We don't want this field
9418 continue;
9419 }
9420 if (!empty($val['type']) && $val['type'] == 'separate') {
9421 // Field remains in array but we don't add it into $listoffieldsforselection
9422 //$listoffieldsforselection .= '<li>-----</li>';
9423 continue;
9424 }
9425 if (!empty($val['label']) && $val['label']) {
9426 if (!empty($val['langfile']) && is_object($langs)) {
9427 $langs->load($val['langfile']);
9428 }
9429
9430 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9431 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((!array_key_exists('checked', $val) || empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . '/><label for="checkbox' . $key . '">' . dol_escape_htmltag($langs->trans($val['label'])) . '</label></li>';
9432 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9433 }
9434 }
9435
9436 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9437
9438 <dl class="dropdown">
9439 <dt>
9440 <a href="#' . $htmlname . '">
9441 ' . img_picto('', 'list') . '
9442 </a>
9443 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9444 </dt>
9445 <dd class="dropdowndd">
9446 <div class="multiselectcheckbox'.$htmlname.'">
9447 <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
9448 <li class="liinputsearch"><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
9449 '.$listoffieldsforselection.'
9450 </ul>
9451 </div>
9452 </dd>
9453 </dl>
9454
9455 <script nonce="' . getNonce() . '" type="text/javascript">
9456 jQuery(document).ready(function () {
9457 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
9458 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9459
9460 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9461
9462 var title = $(this).val() + ",";
9463 if ($(this).is(\':checked\')) {
9464 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9465 }
9466 else {
9467 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9468 }
9469 // Now, we submit page
9470 //$(this).parents(\'form:first\').submit();
9471 });
9472 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9473 var value = $(this).val().toLowerCase();
9474 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9475 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9476 });
9477 });
9478
9479
9480 });
9481 </script>
9482
9483 ';
9484 return $out;
9485 }
9486
9496 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
9497 {
9498 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
9499
9500 $cat = new Categorie($this->db);
9501 $categories = $cat->containing($id, $type);
9502
9503 if ($rendermode == 1) {
9504 $toprint = array();
9505 foreach ($categories as $c) {
9506 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
9507 foreach ($ways as $way) {
9508 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
9509 }
9510 }
9511 if (empty($toprint)) {
9512 return '';
9513 } else {
9514 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
9515 }
9516 }
9517
9518 if ($rendermode == 0) {
9519 $arrayselected = array();
9520 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
9521 foreach ($categories as $c) {
9522 $arrayselected[] = $c->id;
9523 }
9524
9525 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
9526 }
9527
9528 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
9529 }
9530
9540 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
9541 {
9542 global $conf, $langs, $hookmanager;
9543 global $action;
9544
9545 $object->fetchObjectLinked();
9546
9547 // Bypass the default method
9548 $hookmanager->initHooks(array('commonobject'));
9549 $parameters = array(
9550 'morehtmlright' => $morehtmlright,
9551 'compatibleImportElementsList' => &$compatibleImportElementsList,
9552 );
9553 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9554
9555 $nbofdifferenttypes = count($object->linkedObjects);
9556
9557 if (empty($reshook)) {
9558 print '<!-- showLinkedObjectBlock -->';
9559 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, '', 'showlinkedobjectblock');
9560
9561
9562 print '<div class="div-table-responsive-no-min">';
9563 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
9564
9565 print '<tr class="liste_titre">';
9566 print '<td>' . $langs->trans("Type") . '</td>';
9567 print '<td>' . $langs->trans("Ref") . '</td>';
9568 print '<td class="center"></td>';
9569 print '<td class="center">' . $langs->trans("Date") . '</td>';
9570 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9571 print '<td class="right">' . $langs->trans("Status") . '</td>';
9572 print '<td></td>';
9573 print '</tr>';
9574
9575 $nboftypesoutput = 0;
9576
9577 foreach ($object->linkedObjects as $objecttype => $objects) {
9578 $tplpath = $element = $subelement = $objecttype;
9579
9580 // to display import button on tpl
9581 $showImportButton = false;
9582 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
9583 $showImportButton = true;
9584 }
9585
9586 $regs = array();
9587 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
9588 $element = $regs[1];
9589 $subelement = $regs[2];
9590 $tplpath = $element . '/' . $subelement;
9591 }
9592 $tplname = 'linkedobjectblock';
9593
9594 // To work with non standard path
9595 if ($objecttype == 'facture') {
9596 $tplpath = 'compta/' . $element;
9597 if (!isModEnabled('invoice')) {
9598 continue; // Do not show if module disabled
9599 }
9600 } elseif ($objecttype == 'facturerec') {
9601 $tplpath = 'compta/facture';
9602 $tplname = 'linkedobjectblockForRec';
9603 if (!isModEnabled('invoice')) {
9604 continue; // Do not show if module disabled
9605 }
9606 } elseif ($objecttype == 'propal') {
9607 $tplpath = 'comm/' . $element;
9608 if (!isModEnabled('propal')) {
9609 continue; // Do not show if module disabled
9610 }
9611 } elseif ($objecttype == 'supplier_proposal') {
9612 if (!isModEnabled('supplier_proposal')) {
9613 continue; // Do not show if module disabled
9614 }
9615 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
9616 $tplpath = 'expedition';
9617 if (!isModEnabled('shipping')) {
9618 continue; // Do not show if module disabled
9619 }
9620 } elseif ($objecttype == 'reception') {
9621 $tplpath = 'reception';
9622 if (!isModEnabled('reception')) {
9623 continue; // Do not show if module disabled
9624 }
9625 } elseif ($objecttype == 'delivery') {
9626 $tplpath = 'delivery';
9627 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
9628 continue; // Do not show if sub module disabled
9629 }
9630 } elseif ($objecttype == 'ficheinter') {
9631 $tplpath = 'fichinter';
9632 if (!isModEnabled('intervention')) {
9633 continue; // Do not show if module disabled
9634 }
9635 } elseif ($objecttype == 'invoice_supplier') {
9636 $tplpath = 'fourn/facture';
9637 } elseif ($objecttype == 'order_supplier') {
9638 $tplpath = 'fourn/commande';
9639 } elseif ($objecttype == 'expensereport') {
9640 $tplpath = 'expensereport';
9641 } elseif ($objecttype == 'subscription') {
9642 $tplpath = 'adherents';
9643 } elseif ($objecttype == 'conferenceorbooth') {
9644 $tplpath = 'eventorganization';
9645 } elseif ($objecttype == 'conferenceorboothattendee') {
9646 $tplpath = 'eventorganization';
9647 } elseif ($objecttype == 'mo') {
9648 $tplpath = 'mrp';
9649 if (!isModEnabled('mrp')) {
9650 continue; // Do not show if module disabled
9651 }
9652 } elseif ($objecttype == 'project_task') {
9653 $tplpath = 'projet/tasks';
9654 }
9655
9656 global $linkedObjectBlock;
9657 $linkedObjectBlock = $objects;
9658
9659 // Output template part (modules that overwrite templates must declare this into descriptor)
9660 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
9661 foreach ($dirtpls as $reldir) {
9662 $reldir = rtrim($reldir, '/');
9663 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
9664 global $noMoreLinkedObjectBlockAfter;
9665 $noMoreLinkedObjectBlockAfter = 1;
9666 }
9667
9668 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
9669 if ($res) {
9670 $nboftypesoutput++;
9671 break;
9672 }
9673 }
9674 }
9675
9676 if (!$nboftypesoutput) {
9677 print '<tr><td colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9678 }
9679
9680 print '</table>';
9681
9682 if (!empty($compatibleImportElementsList)) {
9683 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9684 }
9685
9686 print '</div>';
9687 }
9688
9689 return $nbofdifferenttypes;
9690 }
9691
9701 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array(), $nooutput = 0)
9702 {
9703 global $conf, $langs, $hookmanager, $form;
9704 global $action;
9705
9706 if (empty($form)) {
9707 $form = new Form($this->db);
9708 }
9709
9710 $linktoelem = '';
9711 $linktoelemlist = '';
9712 $listofidcompanytoscan = '';
9713
9714 if (!is_object($object->thirdparty)) {
9715 $object->fetch_thirdparty();
9716 }
9717
9718 $possiblelinks = array();
9719
9720 $dontIncludeCompletedItems = getDolGlobalString('DONT_INCLUDE_COMPLETED_ELEMENTS_LINKS');
9721
9722 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9723 $listofidcompanytoscan = (int) $object->thirdparty->id;
9724 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
9725 $listofidcompanytoscan .= ',' . (int) $object->thirdparty->parent;
9726 }
9727 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
9728 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9729 $tmpproject = new Project($this->db);
9730 $tmpproject->fetch($object->fk_project);
9731 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9732 $listofidcompanytoscan .= ',' . (int) $tmpproject->socid;
9733 }
9734 unset($tmpproject);
9735 }
9736
9737 $possiblelinks = array(
9738 'propal' => array(
9739 'enabled' => isModEnabled('propal'),
9740 'perms' => 1,
9741 'label' => 'LinkToProposal',
9742 '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' : ''),
9743 ),
9744 'shipping' => array(
9745 'enabled' => isModEnabled('shipping'),
9746 'perms' => 1,
9747 'label' => 'LinkToExpedition',
9748 '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' : ''),
9749 ),
9750 'order' => array(
9751 'enabled' => isModEnabled('order'),
9752 'perms' => 1,
9753 'label' => 'LinkToOrder',
9754 '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' : ''),
9755 'linkname' => 'commande',
9756 ),
9757 'invoice' => array(
9758 'enabled' => isModEnabled('invoice'),
9759 'perms' => 1,
9760 'label' => 'LinkToInvoice',
9761 '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' : ''),
9762 'linkname' => 'facture',
9763 ),
9764 'invoice_template' => array(
9765 'enabled' => isModEnabled('invoice'),
9766 'perms' => 1,
9767 'label' => 'LinkToTemplateInvoice',
9768 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('invoice') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : ''),
9769 ),
9770 'contrat' => array(
9771 'enabled' => isModEnabled('contract'),
9772 'perms' => 1,
9773 'label' => 'LinkToContract',
9774 '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
9775 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',
9776 ),
9777 'fichinter' => array(
9778 'enabled' => isModEnabled('intervention'),
9779 'perms' => 1,
9780 'label' => 'LinkToIntervention',
9781 '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') . ')',
9782 ),
9783 'supplier_proposal' => array(
9784 'enabled' => isModEnabled('supplier_proposal'),
9785 'perms' => 1,
9786 'label' => 'LinkToSupplierProposal',
9787 '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' : ''),
9788 ),
9789 'order_supplier' => array(
9790 'enabled' => isModEnabled("supplier_order"),
9791 'perms' => 1,
9792 'label' => 'LinkToSupplierOrder',
9793 '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' : ''),
9794 ),
9795 'invoice_supplier' => array(
9796 'enabled' => isModEnabled("supplier_invoice"),
9797 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9798 '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' : ''),
9799 ),
9800 'ticket' => array(
9801 'enabled' => isModEnabled('ticket'),
9802 'perms' => 1,
9803 'label' => 'LinkToTicket',
9804 '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' : ''),
9805 ),
9806 'mo' => array(
9807 'enabled' => isModEnabled('mrp'),
9808 'perms' => 1,
9809 'label' => 'LinkToMo',
9810 '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' : ''),
9811 ),
9812 );
9813 }
9814
9815 if ($object->table_element == 'commande_fournisseur') {
9816 $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' : '');
9817 } elseif ($object->table_element == 'mrp_mo') {
9818 $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' : '');
9819 }
9820
9821 $reshook = 0; // Ensure $reshook is defined for static analysis
9822 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9823 // Can complete the possiblelink array
9824 $hookmanager->initHooks(array('commonobject'));
9825 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9826 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9827 }
9828
9829 if (empty($reshook)) {
9830 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9831 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9832 }
9833 } elseif ($reshook > 0) {
9834 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9835 $possiblelinks = $hookmanager->resArray;
9836 }
9837 }
9838
9839 if (!empty($possiblelinks)) {
9840 $object->fetchObjectLinked();
9841 }
9842
9843 // Build the html part with possible suggested links
9844 $htmltoenteralink = '';
9845 foreach ($possiblelinks as $key => $possiblelink) {
9846 $num = 0;
9847 if (empty($possiblelink['enabled'])) {
9848 continue;
9849 }
9850
9851 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9852 $htmltoenteralink .= '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9853
9854 // Section for free ref input
9855 if (!getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9856 $htmltoenteralink .= '<br>'."\n";
9857 $htmltoenteralink .= '<!-- form to add a link from anywhere -->'."\n";
9858 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9859 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9860 $htmltoenteralink .= '<input type="hidden" name="action" value="addlinkbyref">';
9861 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9862 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9863 $htmltoenteralink .= '<table class="noborder">';
9864 $htmltoenteralink .= '<tr class="liste_titre">';
9865 //print '<td>' . $langs->trans("Ref") . '</td>';
9866 $htmltoenteralink .= '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9867 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9868 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9869 $htmltoenteralink .= '</tr>';
9870 $htmltoenteralink .= '</table>';
9871 $htmltoenteralink .= '</form>';
9872 }
9873
9874 $sql = $possiblelink['sql'];
9875
9876 $resqllist = $this->db->query($sql);
9877 if ($resqllist) {
9878 $num = $this->db->num_rows($resqllist);
9879 $i = 0;
9880
9881 if ($num > 0) {
9882 // Section for free predefined list
9883 if (getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9884 $htmltoenteralink .= '<br>';
9885 }
9886 $htmltoenteralink .= '<!-- form to add a link from object to same thirdparty -->'."\n";
9887 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9888 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9889 $htmltoenteralink .= '<input type="hidden" name="action" value="addlink">';
9890 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9891 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9892 $htmltoenteralink .= '<table class="noborder">';
9893 $htmltoenteralink .= '<tr class="liste_titre">';
9894 $htmltoenteralink .= '<td class="nowrap"></td>';
9895 $htmltoenteralink .= '<td>' . $langs->trans("Ref") . '</td>';
9896 $htmltoenteralink .= '<td>' . $langs->trans("RefCustomer") . '</td>';
9897 $htmltoenteralink .= '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9898 $htmltoenteralink .= '<td>' . $langs->trans("Company") . '</td>';
9899 $htmltoenteralink .= '</tr>';
9900 while ($i < $num) {
9901 $objp = $this->db->fetch_object($resqllist);
9902 $alreadylinked = false;
9903 if (!empty($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key])) {
9904 if (in_array($objp->rowid, array_values($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key]))) {
9905 $alreadylinked = true;
9906 }
9907 }
9908 $htmltoenteralink .= '<tr class="oddeven">';
9909 $htmltoenteralink .= '<td>';
9910 if ($alreadylinked) {
9911 $htmltoenteralink .= img_picto('', 'link');
9912 } else {
9913 $htmltoenteralink .= '<input type="checkbox" name="idtolinkto[' . $key . '_' . $objp->rowid . ']" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9914 }
9915 $htmltoenteralink .= '</td>';
9916 $htmltoenteralink .= '<td><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9917 $htmltoenteralink .= '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9918 $htmltoenteralink .= '<td class="right">';
9919 if ($possiblelink['label'] == 'LinkToContract') {
9920 $htmltoenteralink .= $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9921 }
9922 $htmltoenteralink .= '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9923 $htmltoenteralink .= '</td>';
9924 $htmltoenteralink .= '<td>' . $objp->name . '</td>';
9925 $htmltoenteralink .= '</tr>';
9926 $i++;
9927 }
9928 $htmltoenteralink .= '</table>';
9929 $htmltoenteralink .= '<div class="center">';
9930 if ($num) {
9931 $htmltoenteralink .= '<input type="submit" class="button valignmiddle marginleftonly marginrightonly smallpaddingimp" value="' . $langs->trans('ToLink') . '">';
9932 }
9933 if (empty($conf->use_javascript_ajax)) {
9934 $htmltoenteralink .= '<input type="submit" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9935 } else {
9936 $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>';
9937 }
9938 $htmltoenteralink .= '</form>';
9939 }
9940
9941 $this->db->free($resqllist);
9942 } else {
9943 dol_print_error($this->db);
9944 }
9945 $htmltoenteralink .= '</div>';
9946
9947
9948 // Complete the list for the combo box
9949 if ($num > 0 || !getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9950 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
9951 // } else $linktoelem.=$langs->trans($possiblelink['label']);
9952 } else {
9953 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
9954 }
9955 }
9956 }
9957
9958 if ($linktoelemlist) {
9959 $linktoelem = '
9960 <dl class="dropdown" id="linktoobjectname">
9961 ';
9962 if (!empty($conf->use_javascript_ajax)) {
9963 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
9964 }
9965 $linktoelem .= '<dd>
9966 <div class="multiselectlinkto">
9967 <ul class="ulselectedfields">' . $linktoelemlist . '
9968 </ul>
9969 </div>
9970 </dd>
9971 </dl>';
9972 } else {
9973 $linktoelem = '';
9974 }
9975
9976 if (!empty($conf->use_javascript_ajax)) {
9977 print '<!-- Add js to show linkto box -->
9978 <script nonce="' . getNonce() . '">
9979 jQuery(document).ready(function() {
9980 jQuery(".linkto").click(function() {
9981 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
9982 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
9983 });
9984 });
9985 </script>
9986 ';
9987 }
9988
9989 if ($nooutput) {
9990 return array('linktoelem' => $linktoelem, 'htmltoenteralink' => $htmltoenteralink);
9991 } else {
9992 print $htmltoenteralink;
9993 }
9994
9995 return $linktoelem;
9996 }
9997
10012 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'width75', $labelyes = 'Yes', $labelno = 'No')
10013 {
10014 global $langs;
10015
10016 $yes = "yes";
10017 $no = "no";
10018 if ($option) {
10019 $yes = "1";
10020 $no = "0";
10021 }
10022
10023 $disabled = ($disabled ? ' disabled' : '');
10024
10025 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
10026 if ($useempty) {
10027 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10028 }
10029 if (("$value" == 'yes') || ($value == 1)) {
10030 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
10031 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
10032 } else {
10033 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
10034 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
10035 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
10036 }
10037 $resultyesno .= '</select>' . "\n";
10038
10039 if ($addjscombo) {
10040 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
10041 }
10042
10043 return $resultyesno;
10044 }
10045
10046 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10047
10057 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
10058 {
10059 // phpcs:enable
10060 $sql = "SELECT rowid, label";
10061 $sql .= " FROM " . $this->db->prefix() . "export_model";
10062 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
10063 $sql .= " ORDER BY rowid";
10064 $result = $this->db->query($sql);
10065 if ($result) {
10066 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
10067 if ($useempty) {
10068 print '<option value="-1">&nbsp;</option>';
10069 }
10070
10071 $num = $this->db->num_rows($result);
10072 $i = 0;
10073 while ($i < $num) {
10074 $obj = $this->db->fetch_object($result);
10075 if ($selected == $obj->rowid) {
10076 print '<option value="' . $obj->rowid . '" selected>';
10077 } else {
10078 print '<option value="' . $obj->rowid . '">';
10079 }
10080 print $obj->label;
10081 print '</option>';
10082 $i++;
10083 }
10084 print "</select>";
10085 } else {
10086 dol_print_error($this->db);
10087 }
10088 }
10089
10108 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
10109 {
10110 global $conf, $langs, $hookmanager, $extralanguages;
10111
10112 $ret = '';
10113 if (empty($fieldid)) {
10114 $fieldid = 'rowid';
10115 }
10116 if (empty($fieldref)) {
10117 $fieldref = 'ref';
10118 }
10119
10120 // Preparing gender's display if there is one
10121 $addgendertxt = '';
10122 if (property_exists($object, 'gender') && !empty($object->gender)) {
10123 $addgendertxt = ' ';
10124 switch ($object->gender) {
10125 case 'man':
10126 $addgendertxt .= '<i class="fas fa-mars valignmiddle"></i>';
10127 break;
10128 case 'woman':
10129 $addgendertxt .= '<i class="fas fa-venus valignmiddle"></i>';
10130 break;
10131 case 'other':
10132 $addgendertxt .= '<i class="fas fa-transgender valignmiddle"></i>';
10133 break;
10134 }
10135 }
10136
10137 // Add where from hooks
10138 if (is_object($hookmanager)) {
10139 $parameters = array('showrefnav' => true);
10140 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
10141 $object->next_prev_filter .= $hookmanager->resPrint;
10142 }
10143
10144 $previous_ref = $next_ref = '';
10145 if ($shownav) {
10146 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
10147 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
10148
10149 $navurl = $_SERVER["PHP_SELF"];
10150 // Special case for project/task page
10151 if ($paramid == 'project_ref') {
10152 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
10153 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
10154 $paramid = 'ref';
10155 }
10156 }
10157
10158 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
10159 // accesskey is for Mac: CTRL + key for all browsers
10160 $stringforfirstkey = $langs->trans("KeyboardShortcut");
10161 if ($conf->browser->name == 'chrome') {
10162 $stringforfirstkey .= ' ALT +';
10163 } elseif ($conf->browser->name == 'firefox') {
10164 $stringforfirstkey .= ' ALT + SHIFT +';
10165 } else {
10166 $stringforfirstkey .= ' CTL +';
10167 }
10168
10169 $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>';
10170 $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>';
10171 }
10172
10173 //print "xx".$previous_ref."x".$next_ref;
10174 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
10175
10176 // Right part of banner
10177 if ($morehtmlright) {
10178 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
10179 }
10180
10181 if ($previous_ref || $next_ref || $morehtml) {
10182 $ret .= '<div class="pagination paginationref"><ul class="right">';
10183 }
10184 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
10185 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
10186 }
10187 if ($shownav && ($previous_ref || $next_ref)) {
10188 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
10189 $ret .= '<li class="pagination">' . $next_ref . '</li>';
10190 }
10191 if ($previous_ref || $next_ref || $morehtml) {
10192 $ret .= '</ul></div>';
10193 }
10194
10195 // Status
10196 $parameters = array('morehtmlstatus' => $morehtmlstatus);
10197 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
10198 if (empty($reshook)) {
10199 $morehtmlstatus .= $hookmanager->resPrint;
10200 } else {
10201 $morehtmlstatus = $hookmanager->resPrint;
10202 }
10203 if ($morehtmlstatus) {
10204 $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
10205 }
10206
10207 $parameters = array();
10208 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
10209 if (empty($reshook)) {
10210 $morehtmlref .= $hookmanager->resPrint;
10211 } elseif ($reshook > 0) {
10212 $morehtmlref = $hookmanager->resPrint;
10213 }
10214
10215 // Left part of banner
10216 if ($morehtmlleft) {
10217 if ($conf->browser->layout == 'phone') {
10218 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
10219 } else {
10220 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
10221 }
10222 }
10223
10224 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
10225 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
10226
10227 // For thirdparty, contact, user, member, the ref is the id, so we show something else
10228 if ($object->element == 'societe') {
10229 $ret .= dol_htmlentities($object->name);
10230
10231 // List of extra languages
10232 $arrayoflangcode = array();
10233 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
10234 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
10235 }
10236
10237 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
10238 if (!is_object($extralanguages)) {
10239 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
10240 $extralanguages = new ExtraLanguages($this->db);
10241 }
10242 $extralanguages->fetch_name_extralanguages('societe');
10243
10244 if (!empty($extralanguages->attributes['societe']['name'])) {
10245 $object->fetchValuesForExtraLanguages();
10246
10247 $htmltext = '';
10248 // If there is extra languages
10249 foreach ($arrayoflangcode as $extralangcode) {
10250 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
10251 if ($object->array_languages['name'][$extralangcode]) {
10252 $htmltext .= $object->array_languages['name'][$extralangcode];
10253 } else {
10254 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
10255 }
10256 }
10257 $ret .= '<!-- Show translations of name -->' . "\n";
10258 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
10259 }
10260 }
10261 } elseif ($object->element == 'member') {
10262 '@phan-var-force Adherent $object';
10263 $ret .= $object->ref . '<br>';
10264 $fullname = $object->getFullName($langs);
10265 if ($object->morphy == 'mor' && $object->societe) {
10266 $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
10267 } else {
10268 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
10269 }
10270 } elseif (in_array($object->element, array('contact', 'user'))) {
10271 $ret .= '<span class="valignmiddle">'.dol_htmlentities($object->getFullName($langs)).'</span>'.$addgendertxt;
10272 } elseif ($object->element == 'usergroup') {
10273 $ret .= dol_htmlentities($object->name);
10274 } elseif (in_array($object->element, array('action', 'agenda'))) {
10275 '@phan-var-force ActionComm $object';
10276 $ret .= $object->ref . '<br>' . $object->label;
10277 } elseif (in_array($object->element, array('adherent_type'))) {
10278 $ret .= $object->label;
10279 } elseif ($object->element == 'ecm_directories') {
10280 $ret .= '';
10281 } elseif ($fieldref != 'none') {
10282 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
10283 }
10284 if ($morehtmlref) {
10285 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
10286 if (substr($morehtmlref, 0, 4) != '<div') {
10287 $ret .= ' ';
10288 }
10289
10290 $ret .= '<!-- morehtmlref -->'.$morehtmlref;
10291 }
10292
10293 $ret .= '</div>';
10294
10295 $ret .= '</div><!-- End banner content -->';
10296
10297 return $ret;
10298 }
10299
10300
10309 public function showbarcode(&$object, $width = 100, $morecss = '')
10310 {
10311 global $conf;
10312
10313 //Check if barcode is filled in the card
10314 if (empty($object->barcode)) {
10315 return '';
10316 }
10317
10318 // Complete object if not complete
10319 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10320 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10321 $result = $object->fetchBarCode();
10322 //Check if fetchBarCode() failed
10323 if ($result < 1) {
10324 return '<!-- ErrorFetchBarcode -->';
10325 }
10326 }
10327
10328 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10329 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10330 $out = '<!-- url barcode = ' . $url . ' -->';
10331 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10332
10333 return $out;
10334 }
10335
10353 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10354 {
10355 global $conf, $langs;
10356
10357 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10358 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10359
10360 $dir = '';
10361 $file = '';
10362 $originalfile = '';
10363 $altfile = '';
10364 $email = '';
10365 $capture = '';
10366 if ($modulepart == 'societe') {
10367 $dir = $conf->societe->multidir_output[$entity];
10368 if (!empty($object->logo)) {
10369 if (dolIsAllowedForPreview($object->logo)) {
10370 if ((string) $imagesize == 'mini') {
10371 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10372 } elseif ((string) $imagesize == 'small') {
10373 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10374 } else {
10375 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10376 }
10377 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10378 }
10379 }
10380 $email = $object->email;
10381 } elseif ($modulepart == 'contact') {
10382 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10383 if (!empty($object->photo)) {
10384 if (dolIsAllowedForPreview($object->photo)) {
10385 if ((string) $imagesize == 'mini') {
10386 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10387 } elseif ((string) $imagesize == 'small') {
10388 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10389 } else {
10390 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10391 }
10392 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10393 }
10394 }
10395 $email = $object->email;
10396 $capture = 'user';
10397 } elseif ($modulepart == 'userphoto') {
10398 $dir = $conf->user->dir_output;
10399 if (!empty($object->photo)) {
10400 if (dolIsAllowedForPreview($object->photo)) {
10401 if ((string) $imagesize == 'mini') {
10402 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10403 } elseif ((string) $imagesize == 'small') {
10404 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10405 } else {
10406 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10407 }
10408 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10409 }
10410 }
10411 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10412 $altfile = $object->id . ".jpg"; // For backward compatibility
10413 }
10414 $email = $object->email;
10415 $capture = 'user';
10416 } elseif ($modulepart == 'memberphoto') {
10417 $dir = $conf->adherent->dir_output;
10418 if (!empty($object->photo)) {
10419 if (dolIsAllowedForPreview($object->photo)) {
10420 if ((string) $imagesize == 'mini') {
10421 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10422 } elseif ((string) $imagesize == 'small') {
10423 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10424 } else {
10425 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10426 }
10427 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10428 }
10429 }
10430 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10431 $altfile = $object->id . ".jpg"; // For backward compatibility
10432 }
10433 $email = $object->email;
10434 $capture = 'user';
10435 } else {
10436 // Generic case to show photos
10437 // TODO Implement this method in previous objects so we can always use this generic method.
10438 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10439 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10440
10441 $dir = $tmpdata['dir'];
10442 $file = $tmpdata['file'];
10443 $originalfile = $tmpdata['originalfile'];
10444 $altfile = $tmpdata['altfile'];
10445 $email = $tmpdata['email'];
10446 $capture = $tmpdata['capture'];
10447 }
10448 }
10449
10450 if ($forcecapture) {
10451 $capture = $forcecapture;
10452 }
10453
10454 $ret = '';
10455
10456 if ($dir) {
10457 if ($file && file_exists($dir . "/" . $file)) {
10458 if ($addlinktofullsize) {
10459 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10460 if ($urladvanced) {
10461 $ret .= '<a href="' . $urladvanced . '">';
10462 } else {
10463 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10464 }
10465 }
10466 $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 . '">';
10467 if ($addlinktofullsize) {
10468 $ret .= '</a>';
10469 }
10470 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
10471 if ($addlinktofullsize) {
10472 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10473 if ($urladvanced) {
10474 $ret .= '<a href="' . $urladvanced . '">';
10475 } else {
10476 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10477 }
10478 }
10479 $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 . '">';
10480 if ($addlinktofullsize) {
10481 $ret .= '</a>';
10482 }
10483 } else {
10484 $nophoto = '/public/theme/common/nophoto.png';
10485 $defaultimg = 'identicon'; // For gravatar
10486 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
10487 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
10488 $nophoto = 'company';
10489 } else {
10490 $nophoto = '/public/theme/common/user_anonymous.png';
10491 if (!empty($object->gender) && $object->gender == 'man') {
10492 $nophoto = '/public/theme/common/user_man.png';
10493 }
10494 if (!empty($object->gender) && $object->gender == 'woman') {
10495 $nophoto = '/public/theme/common/user_woman.png';
10496 }
10497 }
10498 }
10499
10500 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
10501 // see https://gravatar.com/site/implement/images/php/
10502 $ret .= '<!-- Put link to gravatar -->';
10503 $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
10504 } else {
10505 if ($nophoto == 'company') {
10506 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
10507 //$ret .= '<div class="difforspanimgright"></div>';
10508 } else {
10509 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
10510 }
10511 }
10512 }
10513
10514 if ($caneditfield) {
10515 if ($object->photo) {
10516 $ret .= "<br>\n";
10517 }
10518 $ret .= '<table class="nobordernopadding centpercent">';
10519 if ($object->photo) {
10520 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
10521 }
10522 $ret .= '<tr><td class="tdoverflow">';
10523 $maxfilesizearray = getMaxFileSizeArray();
10524 $maxmin = $maxfilesizearray['maxmin'];
10525 if ($maxmin > 0) {
10526 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
10527 }
10528 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
10529 $ret .= '</td></tr>';
10530 $ret .= '</table>';
10531 }
10532 }
10533
10534 return $ret;
10535 }
10536
10537 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10538
10555 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
10556 {
10557 // phpcs:enable
10558 global $conf, $user, $langs;
10559
10560 // Allow excluding groups
10561 $excludeGroups = null;
10562 if (is_array($exclude)) {
10563 $excludeGroups = implode(",", $exclude);
10564 }
10565 // Allow including groups
10566 $includeGroups = null;
10567 if (is_array($include)) {
10568 $includeGroups = implode(",", $include);
10569 }
10570
10571 if (!is_array($selected)) {
10572 $selected = array($selected);
10573 }
10574
10575 $out = '';
10576
10577 // Build sql to search groups
10578 $sql = "SELECT ug.rowid, ug.nom as name";
10579 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10580 $sql .= ", e.label";
10581 }
10582 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
10583 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10584 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
10585 if ($force_entity) {
10586 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
10587 } else {
10588 $sql .= " WHERE ug.entity IS NOT NULL";
10589 }
10590 } else {
10591 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
10592 }
10593 if (is_array($exclude) && $excludeGroups) {
10594 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
10595 }
10596 if (is_array($include) && $includeGroups) {
10597 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
10598 }
10599 $sql .= " ORDER BY ug.nom ASC";
10600
10601 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
10602 $resql = $this->db->query($sql);
10603 if ($resql) {
10604 // Enhance with select2
10605 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10606
10607 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
10608
10609 $num = $this->db->num_rows($resql);
10610 $i = 0;
10611 if ($num) {
10612 if ($show_empty && !$multiple) {
10613 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10614 }
10615
10616 while ($i < $num) {
10617 $obj = $this->db->fetch_object($resql);
10618 $disableline = 0;
10619 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
10620 $disableline = 1;
10621 }
10622
10623 $label = $obj->name;
10624 $labelhtml = $obj->name;
10625 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
10626 $label .= " (" . $obj->label . ")";
10627 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
10628 }
10629
10630 $out .= '<option value="' . $obj->rowid . '"';
10631 if ($disableline) {
10632 $out .= ' disabled';
10633 }
10634 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
10635 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
10636 $out .= ' selected';
10637 }
10638 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
10639 $out .= '>';
10640 $out .= $label;
10641 $out .= '</option>';
10642 $i++;
10643 }
10644 } else {
10645 if ($show_empty) {
10646 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
10647 }
10648 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
10649 }
10650 $out .= '</select>';
10651
10652 $out .= ajax_combobox($htmlname);
10653 } else {
10654 dol_print_error($this->db);
10655 }
10656
10657 return $out;
10658 }
10659
10660
10667 public function showFilterButtons($pos = '')
10668 {
10669 $out = '<div class="nowraponall">';
10670 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
10671 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
10672 $out .= '</div>';
10673
10674 return $out;
10675 }
10676
10685 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10686 {
10687 global $conf;
10688
10689 $out = '';
10690
10691 if (!empty($conf->use_javascript_ajax)) {
10692 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
10693 }
10694 $out .= '<script nonce="' . getNonce() . '">
10695 $(document).ready(function() {
10696 $("#' . $cssclass . 's").click(function() {
10697 if($(this).is(\':checked\')){
10698 console.log("We check all ' . $cssclass . ' and trigger the change method");
10699 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
10700 }
10701 else
10702 {
10703 console.log("We uncheck all");
10704 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
10705 }' . "\n";
10706 if ($calljsfunction) {
10707 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
10708 }
10709 $out .= ' });
10710 $(".' . $cssclass . '").change(function() {
10711 $(this).closest("tr").toggleClass("highlight", this.checked);
10712 });
10713 });
10714 </script>';
10715
10716 return $out;
10717 }
10718
10728 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10729 {
10730 $out = $this->showFilterButtons();
10731 if ($addcheckuncheckall) {
10732 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10733 }
10734 return $out;
10735 }
10736
10750 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10751 {
10752 global $langs, $user;
10753
10754 $out = '';
10755 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10756 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10757 if (!empty($excludeid)) {
10758 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10759 }
10760 $sql .= " ORDER BY label";
10761
10762 $resql = $this->db->query($sql);
10763 if ($resql) {
10764 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10765 if ($useempty) {
10766 $out .= '<option value="0">&nbsp;</option>';
10767 }
10768
10769 while ($obj = $this->db->fetch_object($resql)) {
10770 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10771 }
10772 $out .= '</select>';
10773 $out .= ajax_combobox('select_' . $htmlname);
10774
10775 if (!empty($htmlname) && $user->admin && $info_admin) {
10776 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10777 }
10778
10779 if (!empty($target)) {
10780 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10781 $resql = $this->db->query($sql);
10782 if ($resql) {
10783 if ($this->db->num_rows($resql) > 0) {
10784 $obj = $this->db->fetch_object($resql);
10785 $out .= '<script nonce="' . getNonce() . '">
10786 $(function() {
10787 $("select[name=' . $target . ']").on("change", function() {
10788 var current_val = $(this).val();
10789 if (current_val == ' . $obj->id . ') {';
10790 if (!empty($default_selected) || !empty($selected)) {
10791 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10792 }
10793
10794 $out .= '
10795 $("select[name=' . $htmlname . ']").change();
10796 }
10797 });
10798
10799 $("select[name=' . $htmlname . ']").change(function() {
10800
10801 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10802 // get price of kilometer to fill the unit price
10803 $.ajax({
10804 method: "POST",
10805 dataType: "json",
10806 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10807 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
10808 }).done(function( data, textStatus, jqXHR ) {
10809 console.log(data);
10810 if (typeof data.up != "undefined") {
10811 $("input[name=value_unit]").val(data.up);
10812 $("select[name=' . $htmlname . ']").attr("title", data.title);
10813 } else {
10814 $("input[name=value_unit]").val("");
10815 $("select[name=' . $htmlname . ']").attr("title", "");
10816 }
10817 });
10818 }
10819 });
10820 });
10821 </script>';
10822 }
10823 }
10824 }
10825 } else {
10826 dol_print_error($this->db);
10827 }
10828
10829 return $out;
10830 }
10831
10840 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10841 {
10842 global $conf, $langs;
10843
10844 $out = '';
10845 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10846 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10847
10848 $resql = $this->db->query($sql);
10849 if ($resql) {
10850 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10851 if ($useempty) {
10852 $out .= '<option value="0"></option>';
10853 }
10854
10855 while ($obj = $this->db->fetch_object($resql)) {
10856 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10857 }
10858 $out .= '</select>';
10859 } else {
10860 dol_print_error($this->db);
10861 }
10862
10863 return $out;
10864 }
10865
10876 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10877 {
10878 global $langs;
10879
10880 $out = '';
10881 $sql = "SELECT id, code, label";
10882 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
10883 $sql .= " WHERE active = 1";
10884
10885 $resql = $this->db->query($sql);
10886 if ($resql) {
10887 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10888 if ($useempty) {
10889 $out .= '<option value="0"></option>';
10890 }
10891 if ($allchoice) {
10892 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10893 }
10894
10895 $field = 'code';
10896 if ($useid) {
10897 $field = 'id';
10898 }
10899
10900 while ($obj = $this->db->fetch_object($resql)) {
10901 $key = $langs->trans($obj->code);
10902 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10903 }
10904 $out .= '</select>';
10905
10906 $out .= ajax_combobox('select_'.$htmlname);
10907 } else {
10908 dol_print_error($this->db);
10909 }
10910
10911 return $out;
10912 }
10913
10932 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)
10933 {
10934 global $user, $conf, $langs;
10935
10936 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10937
10938 if (is_null($usertofilter)) {
10939 $usertofilter = $user;
10940 }
10941
10942 $out = '';
10943
10944 $hideunselectables = false;
10945 if (getDolGlobalString('PROJECT_HIDE_UNSELECTABLES')) {
10946 $hideunselectables = true;
10947 }
10948
10949 if (empty($projectsListId)) {
10950 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
10951 $projectstatic = new Project($this->db);
10952 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10953 }
10954 }
10955
10956 // Search all projects
10957 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10958 p.title, p.fk_soc, p.fk_statut, p.public,";
10959 $sql .= ' s.nom as name';
10960 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
10961 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
10962 $sql .= ' ' . $this->db->prefix() . 'facture as f';
10963 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
10964 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
10965 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
10966 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
10967 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
10968 $sql .= " ORDER BY p.ref, f.ref ASC";
10969
10970 $resql = $this->db->query($sql);
10971 if ($resql) {
10972 // Use select2 selector
10973 if (!empty($conf->use_javascript_ajax)) {
10974 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10975 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
10976 $out .= $comboenhancement;
10977 $morecss = 'minwidth200imp maxwidth500';
10978 }
10979
10980 if (empty($option_only)) {
10981 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10982 }
10983 if (!empty($show_empty)) {
10984 $out .= '<option value="0" class="optiongrey">';
10985 if (!is_numeric($show_empty)) {
10986 $out .= $show_empty;
10987 } else {
10988 $out .= '&nbsp;';
10989 }
10990 $out .= '</option>';
10991 }
10992 $num = $this->db->num_rows($resql);
10993 $i = 0;
10994 if ($num) {
10995 while ($i < $num) {
10996 $obj = $this->db->fetch_object($resql);
10997 // 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.
10998 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
10999 // Do nothing
11000 } else {
11001 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11002 $i++;
11003 continue;
11004 }
11005
11006 $labeltoshow = '';
11007
11008 if ($showproject == 'all') {
11009 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
11010 if ($obj->name) {
11011 $labeltoshow .= ' - ' . $obj->name; // Soc name
11012 }
11013
11014 $disabled = 0;
11015 if ($obj->fk_statut == Project::STATUS_DRAFT) {
11016 $disabled = 1;
11017 $labeltoshow .= ' - ' . $langs->trans("Draft");
11018 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
11019 if ($discard_closed == 2) {
11020 $disabled = 1;
11021 }
11022 $labeltoshow .= ' - ' . $langs->trans("Closed");
11023 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
11024 $disabled = 1;
11025 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
11026 }
11027 }
11028
11029 if (!empty($selected) && $selected == $obj->rowid) {
11030 $out .= '<option value="' . $obj->rowid . '" selected';
11031 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11032 $out .= '>' . $labeltoshow . '</option>';
11033 } else {
11034 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11035 $resultat = '';
11036 } else {
11037 $resultat = '<option value="' . $obj->rowid . '"';
11038 if ($disabled) {
11039 $resultat .= ' disabled';
11040 }
11041 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11042 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11043 $resultat .= '>';
11044 $resultat .= $labeltoshow;
11045 $resultat .= '</option>';
11046 }
11047 $out .= $resultat;
11048 }
11049 }
11050 $i++;
11051 }
11052 }
11053 if (empty($option_only)) {
11054 $out .= '</select>';
11055 }
11056
11057 $this->db->free($resql);
11058
11059 return $out;
11060 } else {
11061 dol_print_error($this->db);
11062 return '';
11063 }
11064 }
11065
11079 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11080 {
11081 global $conf, $langs;
11082
11083 $out = '';
11084
11085 dol_syslog('FactureRec::fetch', LOG_DEBUG);
11086
11087 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
11088 //$sql.= ', el.fk_source';
11089 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
11090 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
11091 $sql .= " ORDER BY f.titre ASC";
11092
11093 $resql = $this->db->query($sql);
11094 if ($resql) {
11095 // Use select2 selector
11096 if (!empty($conf->use_javascript_ajax)) {
11097 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11098 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11099 $out .= $comboenhancement;
11100 $morecss = 'minwidth200imp maxwidth500';
11101 }
11102
11103 if (empty($option_only)) {
11104 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11105 }
11106 if (!empty($show_empty)) {
11107 $out .= '<option value="0" class="optiongrey">';
11108 if (!is_numeric($show_empty)) {
11109 $out .= $show_empty;
11110 } else {
11111 $out .= '&nbsp;';
11112 }
11113 $out .= '</option>';
11114 }
11115 $num = $this->db->num_rows($resql);
11116 if ($num) {
11117 while ($obj = $this->db->fetch_object($resql)) {
11118 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
11119
11120 $disabled = 0;
11121 if (!empty($obj->suspended)) {
11122 $disabled = 1;
11123 $labeltoshow .= ' - ' . $langs->trans("Closed");
11124 }
11125
11126
11127 if (!empty($selected) && $selected == $obj->rowid) {
11128 $out .= '<option value="' . $obj->rowid . '" selected';
11129 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11130 $out .= '>' . $labeltoshow . '</option>';
11131 } else {
11132 if ($disabled && ($selected != $obj->rowid)) {
11133 $resultat = '';
11134 } else {
11135 $resultat = '<option value="' . $obj->rowid . '"';
11136 if ($disabled) {
11137 $resultat .= ' disabled';
11138 }
11139 $resultat .= '>';
11140 $resultat .= $labeltoshow;
11141 $resultat .= '</option>';
11142 }
11143 $out .= $resultat;
11144 }
11145 }
11146 }
11147 if (empty($option_only)) {
11148 $out .= '</select>';
11149 }
11150
11151 print $out;
11152
11153 $this->db->free($resql);
11154 return $num;
11155 } else {
11156 $this->errors[] = $this->db->lasterror;
11157 return -1;
11158 }
11159 }
11160
11171 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '', $arrayoffiltercriterias = array())
11172 {
11173 // TODO: Use $arrayoffiltercriterias param instead of $arrayofcriterias to include linked object fields in search
11174 global $langs, $form;
11175
11176 require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
11177 $formother = new FormOther($this->db);
11178
11179 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
11180 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
11181 }
11182
11183 $ret = '';
11184
11185 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
11186 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
11187 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
11188 $ret .= '</a>';
11189
11190 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
11191
11192 // Show select fields as tags.
11193 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
11194
11195 if ($search_component_params_hidden) {
11196 // Split the criteria on each AND
11197 //var_dump($search_component_params_hidden);
11198
11199 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
11200
11201 // $arrayofandtags is now array( '...' , '...', ...)
11202 // Show each AND part
11203 foreach ($arrayofandtags as $tmpkey => $tmpval) {
11204 $errormessage = '';
11205 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
11206 if ($errormessage) {
11207 $this->error = 'ERROR in parsing search string: '.$errormessage;
11208 }
11209 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
11210 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
11211 $searchtags = removeGlobalParenthesis($searchtags);
11212
11213 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
11214 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
11215 $ret .= dol_escape_htmltag($searchtags);
11216 $ret .= '</span>';
11217 }
11218 }
11219
11220 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
11221
11222 //$ret .= search_component_params
11223 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
11224 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
11225
11226 $show_search_component_params_hidden = 1;
11227 if ($show_search_component_params_hidden) {
11228 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
11229 }
11230 $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%')) -->";
11231 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
11232 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
11233
11234 // TODO : Use $arrayoffiltercriterias instead of $arrayofcriterias
11235 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
11236 foreach ($arrayofcriterias as $criteria) {
11237 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
11238 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
11239 continue;
11240 }
11241 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
11242 continue;
11243 }
11244 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
11245 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
11246 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
11247 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
11248 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
11249 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
11250 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
11251 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
11252 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
11253 } else {
11254 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
11255 }
11256 }
11257 }
11258
11259 $ret .= '</div>';
11260
11261 $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";
11262 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
11263
11264 $ret .= '</div>';
11265 $ret .= '</div>';
11266
11267 $ret .= '<script>
11268 jQuery(".tagsearchdelete").click(function(e) {
11269 var filterid = $(this).parents().attr("data-ufilterid");
11270 console.log("We click to delete the criteria nb "+filterid);
11271
11272 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
11273 var newparamstring = \'\';
11274 $(\'.tagsearch\').each(function(index, element) {
11275 tmpfilterid = $(this).attr("data-ufilterid");
11276 if (tmpfilterid != filterid) {
11277 // We keep this criteria
11278 if (newparamstring == \'\') {
11279 newparamstring = $(this).attr("data-ufilter");
11280 } else {
11281 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
11282 }
11283 }
11284 });
11285 console.log("newparamstring = "+newparamstring);
11286
11287 jQuery("#search_component_params_hidden").val(newparamstring);
11288
11289 // We repost the form
11290 $(this).closest(\'form\').submit();
11291 });
11292
11293 jQuery("#search_component_params_input").keydown(function(e) {
11294 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
11295 console.log(e.which);
11296 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
11297 /* We click on back when the input field is already empty */
11298 event.preventDefault();
11299 jQuery("#divsearch_component_params .tagsearch").last().remove();
11300 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
11301 var s = "";
11302 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
11303 if (s != "") {
11304 s = s + " AND ";
11305 }
11306 s = s + $(this).attr("data-ufilter");
11307 });
11308 console.log("New value for search_component_params_hidden = "+s);
11309 jQuery("#search_component_params_hidden").val(s);
11310 }
11311 });
11312
11313 </script>
11314 ';
11315
11316 $arrayoffilterfieldslabel = array();
11317 foreach ($arrayoffiltercriterias as $key => $val) {
11318 $arrayoffilterfieldslabel[$key]['label'] = $val['label'];
11319 $arrayoffilterfieldslabel[$key]['data-type'] = $val['type'];
11320 }
11321
11322 // Adding the div for search assistance
11323 $ret .= '<div class="search-component-assistance">';
11324 $ret .= '<div>';
11325
11326 $ret .= '<p class="assistance-title">' . img_picto('', 'filter') . ' ' . $langs->trans('FilterAssistance') . ' </p>';
11327
11328 $ret .= '<p class="assistance-errors error" style="display:none">' . $langs->trans('AllFieldsRequired') . ' </p>';
11329
11330 $ret .= '<div class="operand">';
11331 $ret .= $form->selectarray('search_filter_field', $arrayoffilterfieldslabel, '', $langs->trans("Fields"), 0, 0, '', 0, 0, 0, '', 'width250', 1);
11332 $ret .= '</div>';
11333
11334 $ret .= '<span class="separator"></span>';
11335
11336 // Operator selector (will be populated dynamically)
11337 $ret .= '<div class="operator">';
11338 $ret .= '<select class="operator-selector width150" id="operator-selector"">';
11339 $ret .= '</select>';
11340 $ret .= '<script>$(document).ready(function() {';
11341 $ret .= ' $(".operator-selector").select2({';
11342 $ret .= ' placeholder: \'' . dol_escape_js($langs->trans('Operator')) . '\'';
11343 $ret .= ' });';
11344 $ret .= '});</script>';
11345 $ret .= '</div>';
11346
11347 $ret .= '<span class="separator"></span>';
11348
11349 $ret .= '<div class="value">';
11350 // Input field for entering values
11351 $ret .= '<input type="text" class="flat width100 value-input" placeholder="' . dolPrintHTML($langs->trans('Value')) . '">';
11352
11353 // Date selector
11354 $dateOne = '';
11355 $ret .= '<span class="date-one" style="display:none">';
11356 $ret .= $form->selectDate(($dateOne ? $dateOne : -1), 'dateone', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '');
11357 $ret .= '</span>';
11358
11359 $ret .= '</div>';
11360
11361 $ret .= '<div class="btn-div">';
11362 $ret .= '<button class="button buttongen button-save add-filter-btn" type="button">' . $langs->trans("addToFilter") . '</button>';
11363 $ret .= '</div>';
11364
11365 $ret .= '</div>';
11366 //$ret .= '</tbody></table>';
11367
11368 // End of the assistance div
11369 $ret .= '</div>';
11370
11371 // Script jQuery to show/hide the floating assistance
11372 $ret .= '<script>
11373 $(document).ready(function() {
11374 $("#search_component_params_input").on("click", function() {
11375 const inputPosition = $(this).offset();
11376 const inputHeight = $(this).outerHeight();
11377 $(".search-component-assistance").css({
11378 top: inputPosition.top + inputHeight + 5 + "px",
11379 left: $("#divsearch_component_params").position().left
11380 }).slideToggle(200);
11381 });
11382 $(document).on("click", function(e) {
11383 if (!$(e.target).closest("#search_component_params_input, .search-component-assistance, #ui-datepicker-div").length) {
11384 $(".search-component-assistance").hide();
11385 }
11386 });
11387 });
11388 </script>';
11389
11390 $ret .= '<script>
11391 $(document).ready(function() {
11392 $(".search_filter_field").on("change", function() {
11393 const selectedField = $(this).find(":selected");
11394 const fieldType = selectedField.data("type");
11395 const selectedFieldValue = selectedField.val();
11396 const operators = getOperatorsForFieldType(fieldType);
11397 const operatorSelector = $(".operator-selector");
11398
11399 // Clear existing options
11400 operatorSelector.empty();
11401
11402 // Populate operators
11403 Object.entries(operators).forEach(function([operator, label]) {
11404 operatorSelector.append("<option value=\'" + operator + "\'>" + label + "</option>");
11405 });
11406
11407 operatorSelector.trigger("change.select2");
11408
11409 // Clear and hide all input elements initially
11410 $(".value-input, .dateone, .datemonth, .dateyear").val("").hide();
11411 $("#datemonth, #dateyear").val(null).trigger("change.select2");
11412 $("#dateone").datepicker("setDate", null);
11413 $(".date-one, .date-month, .date-year").hide();
11414
11415 if (fieldType === "date" || fieldType === "datetime" || fieldType === "timestamp") {
11416 $(".date-one").show();
11417 } else {
11418 $(".value-input").show();
11419 }
11420 });
11421
11422 $(".add-filter-btn").on("click", function(event) {
11423 event.preventDefault();
11424
11425 const field = $(".search_filter_field").val();
11426 const operator = $(".operator-selector").val();
11427 let value = $(".value-input").val();
11428 const fieldType = $(".search_filter_field").find(":selected").data("type");
11429
11430 if (["date", "datetime", "timestamp"].includes(fieldType)) {
11431 const parsedDate = new Date($("#dateone").val());
11432 if (!isNaN(parsedDate)) {
11433 const year = parsedDate.getFullYear();
11434 const month = String(parsedDate.getMonth() + 1).padStart(2, "0");
11435 const day = String(parsedDate.getDate()).padStart(2, "0");
11436 value = `${year}-${month}-${day}`;
11437 }
11438 }
11439 const filterString = generateFilterString(field, operator, value, fieldType);
11440
11441 // Submit the form
11442 if (filterString !== "" && field !== "" && operator !== "" && value !== "") {
11443 $("#search_component_params_input").val($("#search_component_params_input").val() + " " + filterString);
11444 $("#search_component_params_input").closest("form").submit();
11445 } else {
11446 $(".assistance-errors").show();
11447 }
11448 });
11449 });
11450 </script>';
11451
11452 return $ret;
11453 }
11454
11465 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0, $selected = '')
11466 {
11467 global $langs, $user;
11468
11469 $retstring = '';
11470
11471 $TModels = array();
11472
11473 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
11474 $formmail = new FormMail($this->db);
11475 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
11476
11477 if ($default) {
11478 $TModels[0] = $langs->trans('DefaultMailModel');
11479 }
11480 if ($result > 0) {
11481 foreach ($formmail->lines_model as $model) {
11482 $TModels[$model->id] = $model->label;
11483 }
11484 }
11485
11486 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
11487
11488 foreach ($TModels as $id_model => $label_model) {
11489 $retstring .= '<option value="' . $id_model . '"';
11490 if (!empty($selected) && $selected == $id_model) {
11491 $retstring .= "selected";
11492 }
11493 $retstring .= ">" . $label_model . "</option>";
11494 }
11495
11496 $retstring .= "</select>";
11497
11498 if ($addjscombo) {
11499 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
11500 }
11501
11502 return $retstring;
11503 }
11504
11516 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
11517 {
11518 global $langs;
11519
11520 $buttons = array();
11521
11522 $save = array(
11523 'name' => 'save',
11524 'label_key' => $save_label,
11525 );
11526
11527 if ($save_label == 'Create' || $save_label == 'Add') {
11528 $save['name'] = 'add';
11529 } elseif ($save_label == 'Modify') {
11530 $save['name'] = 'edit';
11531 }
11532
11533 $cancel = array(
11534 'name' => 'cancel',
11535 'label_key' => 'Cancel',
11536 );
11537
11538 !empty($save_label) ? $buttons[] = $save : '';
11539
11540 if (!empty($morebuttons)) {
11541 $buttons[] = $morebuttons;
11542 }
11543
11544 !empty($cancel_label) ? $buttons[] = $cancel : '';
11545
11546 $retstring = $withoutdiv ? '' : '<div class="center">';
11547
11548 foreach ($buttons as $button) {
11549 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
11550 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
11551 }
11552 $retstring .= $withoutdiv ? '' : '</div>';
11553
11554 if ($dol_openinpopup) {
11555 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
11556 $retstring .= '<script nonce="' . getNonce() . '">';
11557 $retstring .= 'jQuery(".button-cancel").click(function(e) {
11558 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
11559 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
11560 });';
11561 $retstring .= '</script>';
11562 }
11563
11564 return $retstring;
11565 }
11566
11567
11568 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11569
11576 {
11577 // phpcs:enable
11578 global $langs;
11579
11580 $num = count($this->cache_invoice_subtype);
11581 if ($num > 0) {
11582 return 0; // Cache already loaded
11583 }
11584
11585 dol_syslog(__METHOD__, LOG_DEBUG);
11586
11587 $sql = "SELECT rowid, code, label as label";
11588 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
11589 $sql .= " WHERE active = 1";
11590
11591 $resql = $this->db->query($sql);
11592 if ($resql) {
11593 $num = $this->db->num_rows($resql);
11594 $i = 0;
11595 while ($i < $num) {
11596 $obj = $this->db->fetch_object($resql);
11597
11598 // If translation exists, we use it, otherwise we take the default wording
11599 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
11600 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
11601 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
11602 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
11603 $i++;
11604 }
11605
11606 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
11607
11608 return $num;
11609 } else {
11610 dol_print_error($this->db);
11611 return -1;
11612 }
11613 }
11614
11615
11626 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
11627 {
11628 global $langs, $user;
11629
11630 $out = '';
11631 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
11632
11634
11635 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
11636 if ($addempty) {
11637 $out .= '<option value="0">&nbsp;</option>';
11638 }
11639
11640 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
11641 $label = $subtype['label'];
11642 $out .= '<option value="' . $subtype['rowid'] . '"';
11643 if ($selected == $subtype['rowid']) {
11644 $out .= ' selected="selected"';
11645 }
11646 $out .= '>';
11647 $out .= $label;
11648 $out .= '</option>';
11649 }
11650
11651 $out .= '</select>';
11652 if ($user->admin && empty($noinfoadmin)) {
11653 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11654 }
11655 $out .= ajax_combobox($htmlname);
11656
11657 return $out;
11658 }
11659}
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to transform a common input text or select field into ...
Definition ajax.lib.php:49
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:459
ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
Generic function that return javascript to add to a page to transform a common input text field into ...
Definition ajax.lib.php:308
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:562
$object ref
Definition info.php:89
Class to manage bank accounts.
Class to manage categories.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage bank accounts description of third parties.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
DAO Resource object.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array(), $nooutput=0)
Show block with links "to link to" other objects.
showFilterButtons($pos='')
Return HTML to show the search and clear search button.
load_cache_vatrates($country_code)
Load into the cache ->cache_vatrates, all the vat rates of a country.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=array(), $title='RelatedObjects')
Show linked object block.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
select_dolresources_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofresourceid=array())
Return select list of resources.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
formRib($page, $selected='', $htmlname='ribcompanyid', $filtre='', $addempty=0, $showibanbic=0)
Display form to select bank customer account.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party This call select_thirdparty_list() or ajax depending on setu...
select_produits($selected=0, $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1, $warehouseId=0)
Return list of products for customer.
select_dolgroups($selected=0, $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly=array(), $force_entity='0', $multiple=false, $morecss='minwidth200')
Return select list of groups.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
select_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())
Return select list of users.
select_contact($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $nokeyifsocid=true, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $selected_input_value='', $filter='')
Output html form to select a contact This call select_contacts() or ajax depending on setup.
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
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')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
selectRib($selected='', $htmlname='ribcompanyid', $filtre='', $useempty=0, $moreattrib='', $showibanbic=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts customer.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
getSelectInvoiceSubtype($selected=0, $htmlname='subtypeid', $addempty=0, $noinfoadmin=0, $morecss='')
Return list of invoice subtypes.
select_produits_list($selected=0, $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='maxwidth500', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1, $warehouseId=0)
Return list of products for a customer.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse=null, $societe_acheteuse=null, $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0, $type_vat=0)
Output an HTML select vat rate.
form_multicurrency_rate($page, $rate=0.0, $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
load_cache_availability()
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
selectcontacts($socid, $selected=array(), $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=0, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0, $filter='')
Return HTML code of the SELECT of list of all contacts (for a third party or all).
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
selectMembersList($selected='', $htmlname='adherentid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of adherents.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
selectTicketsList($selected='', $htmlname='ticketid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of tickets.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=false, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
selectProjectsList($selected='', $htmlname='projectid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of projects.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0, $selected='')
selectModelMail
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1, $noprint=0)
print list of payment modes.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
form_confirm($page, $title, $question, $action, $formquestion=array(), $selectedchoice="", $useajax=0, $height=170, $width=500)
load_cache_conditions_paiements()
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier=0)
Return list of suppliers prices for a product.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='width75', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0)
Return combo list of activated countries, into language of user.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="")
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
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.
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
static selectArrayFilter($htmlname, $array, $id='', $moreparam='', $disableFiltering=0, $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0, $textfortitle='')
Return a HTML select string, built from an array of key+value, but content returned into select is de...
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday=0, $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
load_cache_invoice_subtype()
Load into cache list of invoice subtypes.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $elemtype='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
textwithpicto($text, $htmltext, $direction=1, $type='help', $extracss='valignmiddle', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
load_cache_types_paiements()
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Return the list of type of delay available.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='', $arrayoffiltercriterias=array())
Output the component to make advanced search criteries.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class permettant la generation de composants html autre Only common components are here.
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage hooks.
Class for MyObject.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
currency_name($code_iso, $withcode=0, $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0, $allowscript=0, $allowstyle=0)
Clean a string to keep only desirable HTML tags.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dolPrintHTMLForAttribute($s)
Return a string ready to be output on an HTML attribute (alt, title, data-html, .....
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0, $morecss='paddingrightonly')
Show EMail link formatted for HTML output.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
a disabled
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition main.inc.php:123
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
measuringUnitString($unitid, $measuring_style='', $unitscale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:149
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:152
getMaxFileSizeArray()
Return the max allowed for file upload.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.