dolibarr 21.0.4
html.form.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13 * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18 * Copyright (C) 2014-2026 Alexandre Spangaro <alexandre@inovea-conseil.com>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024 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 // ExtraLanguages::fetch_name_extralanguages() leaves $this->attributes empty
441 // when MAIN_USE_ALTERNATE_TRANSLATION_FOR is not configured, so PHP 8 raises
442 // 'Undefined array key' on the read below if we do not guard it (issue #34596).
443 if (empty($extralanguages->attributes[$object->element]) || !is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
444 return ''; // No extralang field to show
445 }
446
447 $result .= '<!-- Widget for translation -->' . "\n";
448 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
449 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', 0, 0, 0, '', 'fa-15 editfieldlang');
450 $result .= $s;
451 $result .= '</div>';
452
453 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
454
455 $resultforextrlang = '';
456 foreach ($arrayoflangcode as $langcode) {
457 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
458 if (empty($valuetoshow)) {
459 $object->fetchValuesForExtraLanguages();
460 //var_dump($object->array_languages);
461 $valuetoshow = $object->array_languages[$fieldname][$langcode];
462 }
463
464 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
465 $resultforextrlang .= $s;
466
467 // TODO Use the showInputField() method of ExtraLanguages object
468 if ($typeofdata == 'textarea') {
469 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
470 $resultforextrlang .= $valuetoshow;
471 $resultforextrlang .= '</textarea>';
472 } else {
473 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
474 }
475 }
476 $result .= $resultforextrlang;
477
478 $result .= '</div>';
479 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
480 }
481
482 return $result;
483 }
484
498 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
499 {
500 $out = '';
501
502 // Check parameters
503 if (preg_match('/^text/', $inputType)) {
504 $value = dol_nl2br($value);
505 } elseif (preg_match('/^numeric/', $inputType)) {
506 $value = price($value);
507 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
508 $value = dol_print_date($value, 'day');
509 }
510
511 if ($condition) {
512 $element = false;
513 $table_element = false;
514 $fk_element = false;
515 $loadmethod = false;
516 $savemethod = false;
517 $ext_element = false;
518 $button_only = false;
519 $inputOption = '';
520 $rows = '';
521 $cols = '';
522
523 if (is_object($object)) {
524 $element = $object->element;
525 $table_element = $object->table_element;
526 $fk_element = $object->id;
527 }
528
529 if (is_object($extObject)) {
530 $ext_element = $extObject->element;
531 }
532
533 if (preg_match('/^(string|email|numeric)/', $inputType)) {
534 $tmp = explode(':', $inputType);
535 $inputType = $tmp[0];
536 if (!empty($tmp[1])) {
537 $inputOption = $tmp[1];
538 }
539 if (!empty($tmp[2])) {
540 $savemethod = $tmp[2];
541 }
542 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
543 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
544 $tmp = explode(':', $inputType);
545 $inputType = $tmp[0];
546 if (!empty($tmp[1])) {
547 $inputOption = $tmp[1];
548 }
549 if (!empty($tmp[2])) {
550 $savemethod = $tmp[2];
551 }
552
553 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
554 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
555 $tmp = explode(':', $inputType);
556 $inputType = $tmp[0];
557 $loadmethod = $tmp[1];
558 if (!empty($tmp[2])) {
559 $savemethod = $tmp[2];
560 }
561 if (!empty($tmp[3])) {
562 $button_only = true;
563 }
564 } elseif (preg_match('/^textarea/', $inputType)) {
565 $tmp = explode(':', $inputType);
566 $inputType = $tmp[0];
567 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
568 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
569 } elseif (preg_match('/^ckeditor/', $inputType)) {
570 $tmp = explode(':', $inputType);
571 $inputType = $tmp[0];
572 $toolbar = $tmp[1];
573 if (!empty($tmp[2])) {
574 $width = $tmp[2];
575 }
576 if (!empty($tmp[3])) {
577 $height = $tmp[3];
578 }
579 if (!empty($tmp[4])) {
580 $savemethod = $tmp[4];
581 }
582
583 if (isModEnabled('fckeditor')) {
584 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
585 } else {
586 $inputType = 'textarea';
587 }
588 }
589
590 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
591 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
592 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
593 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
594 if (!empty($savemethod)) {
595 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
596 }
597 if (!empty($ext_element)) {
598 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
599 }
600 if (!empty($custommsg)) {
601 if (is_array($custommsg)) {
602 if (!empty($custommsg['success'])) {
603 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
604 }
605 if (!empty($custommsg['error'])) {
606 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
607 }
608 } else {
609 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
610 }
611 }
612 if ($inputType == 'textarea') {
613 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
614 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
615 }
616 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
617 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
618 } else {
619 $out = $value;
620 }
621
622 return $out;
623 }
624
643 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
644 {
645 if ($incbefore) {
646 $text = $incbefore . $text;
647 }
648 if (!$htmltext) {
649 return $text;
650 }
651 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
652
653 $tag = 'td';
654 if ($notabs == 2) {
655 $tag = 'div';
656 }
657 if ($notabs == 3) {
658 $tag = 'span';
659 }
660 // Sanitize tooltip
661 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
662
663 $extrastyle = '';
664 if ($direction < 0) {
665 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
666 $extrastyle = 'padding: 0px; padding-left: 2px;';
667 }
668 if ($direction > 0) {
669 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
670 $extrastyle = 'padding: 0px; padding-right: 2px;';
671 }
672
673 $classfortooltip = 'classfortooltip';
674
675 $s = '';
676 $textfordialog = '';
677
678 if ($tooltiptrigger == '') {
679 $htmltext = str_replace('"', '&quot;', $htmltext);
680 } else {
681 $classfortooltip = 'classfortooltiponclick';
682 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
683 }
684 if ($tooltipon == 2 || $tooltipon == 3) {
685 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
686 if ($tooltiptrigger == '') {
687 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
688 } else {
689 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
690 }
691 } else {
692 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
693 }
694 if ($tooltipon == 1 || $tooltipon == 3) {
695 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ($tag != 'td' ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
696 if ($tooltiptrigger == '') {
697 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
698 } else {
699 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
700 }
701 } else {
702 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
703 }
704 if (empty($notabs)) {
705 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
706 } elseif ($notabs == 2) {
707 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
708 }
709 // Define value if value is before
710 if ($direction < 0) {
711 $s .= '<' . $tag . $paramfortooltipimg;
712 if ($tag == 'td') {
713 $s .= ' class="valigntop" width="14"';
714 }
715 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
716 }
717 // Use another method to help avoid having a space in value in order to use this value with jquery
718 // Define label
719 if ((string) $text != '') {
720 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
721 }
722 // Define value if value is after
723 if ($direction > 0) {
724 $s .= '<' . $tag . $paramfortooltipimg;
725 if ($tag == 'td') {
726 $s .= ' class="valignmiddle" width="14"';
727 }
728 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
729 }
730 if (empty($notabs)) {
731 $s .= '</tr></table>';
732 } elseif ($notabs == 2) {
733 $s .= '</div>';
734 }
735
736 return $s;
737 }
738
753 public function textwithpicto($text, $htmltooltip, $direction = 1, $type = 'help', $extracss = 'valignmiddle', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
754 {
755 global $conf, $langs;
756
757 //For backwards compatibility
758 if ($type == '0') {
759 $type = 'info';
760 } elseif ($type == '1') {
761 $type = 'help';
762 }
763 // Clean parameters
764 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
765
766 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
767 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
768 }
769 $alt = '';
770 if ($tooltiptrigger) {
771 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
772 }
773
774 // If info or help with no javascript, show only text
775 if (empty($conf->use_javascript_ajax)) {
776 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
777 return $text;
778 } else {
779 $alt = $htmltooltip;
780 $htmltooltip = '';
781 }
782 }
783
784 // If info or help with smartphone, show only text (tooltip hover can't works)
785 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
786 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
787 return $text;
788 }
789 }
790 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
791 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
792 //{
793 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
794 //}
795
796 $img = '';
797 if ($type == 'info') {
798 $img = img_help(0, $alt);
799 } elseif ($type == 'help') {
800 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
801 } elseif ($type == 'helpclickable') {
802 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
803 } elseif ($type == 'superadmin') {
804 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
805 $img = img_picto($alt, 'redstar');
806 } elseif ($type == 'admin') {
807 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
808 $img = img_picto($alt, 'star');
809 } elseif ($type == 'warning') {
810 $img = img_warning($alt);
811 } elseif ($type != 'none') {
812 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
813 $img = img_picto($alt, $type); // $type can be an image path
814 }
815
816 return $this->textwithtooltip($text, $htmltooltip, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
817 }
818
829 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
830 {
831 global $conf, $langs, $hookmanager;
832
833 $disabled = 0;
834 $ret = '<div class="centpercent center">';
835 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
836
837 // 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.
838 $parameters = array();
839 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
840 // check if there is a mass action
841
842 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
843 return;
844 }
845 if (empty($reshook)) {
846 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
847 if (is_array($arrayofaction)) {
848 foreach ($arrayofaction as $code => $label) {
849 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
850 }
851 }
852 }
853 $ret .= $hookmanager->resPrint;
854
855 $ret .= '</select>';
856
857 if (empty($conf->dol_optimize_smallscreen)) {
858 $ret .= ajax_combobox('.' . $name . 'select');
859 }
860
861 // 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
862 $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.
863 $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")) . '">';
864 $ret .= '</div>';
865
866 if (!empty($conf->use_javascript_ajax)) {
867 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
868 <script nonce="' . getNonce() . '">
869 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 */
870 {
871 atleastoneselected=0;
872 jQuery("."+cssclass).each(function( index ) {
873 /* console.log( index + ": " + $( this ).text() ); */
874 if ($(this).is(\':checked\')) atleastoneselected++;
875 });
876
877 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
878
879 if (atleastoneselected || ' . ((int) $alwaysvisible) . ')
880 {
881 jQuery("."+name).show();
882 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
883 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
884 }
885 else
886 {
887 jQuery("."+name).hide();
888 jQuery("."+name+"other").hide();
889 }
890 }
891
892 jQuery(document).ready(function () {
893 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
894 jQuery(".' . $cssclass . '").click(function() {
895 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
896 });
897 jQuery(".' . $name . 'select").change(function() {
898 var massaction = $( this ).val();
899 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
900 if (massaction == "builddoc") {
901 urlform = urlform + "#show_files";
902 }
903 $( this ).closest("form").attr("action", urlform);
904 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
905 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
906 if ($(this).val() != \'0\') {
907 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
908 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
909 jQuery(".' . $name . '"+massaction).show();
910 } else {
911 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
912 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
913 }
914 });
915 });
916 </script>
917 ';
918 }
919
920 return $ret;
921 }
922
923 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
924
942 public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0, $forcecombo = 0)
943 {
944 // phpcs:enable
945 global $conf, $langs, $mysoc;
946
947 $langs->load("dict");
948
949 $out = '';
950 $countryArray = array();
951 $favorite = array();
952 $label = array();
953 $atleastonefavorite = 0;
954
955 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
956 $sql .= " FROM " . $this->db->prefix() . "c_country";
957 $sql .= " WHERE active > 0";
958 //$sql.= " ORDER BY code ASC";
959
960 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
961 $resql = $this->db->query($sql);
962 if ($resql) {
963 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
964 $num = $this->db->num_rows($resql);
965 $i = 0;
966 if ($num) {
967 while ($i < $num) {
968 $obj = $this->db->fetch_object($resql);
969
970 $countryArray[$i]['rowid'] = $obj->rowid;
971 $countryArray[$i]['code_iso'] = $obj->code_iso;
972 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
973 $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 : ''));
974 $countryArray[$i]['favorite'] = $obj->favorite;
975 $countryArray[$i]['eec'] = $obj->eec;
976 $favorite[$i] = $obj->favorite;
977 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
978 $i++;
979 }
980
981 if (empty($disablefavorites)) {
982 $array1_sort_order = SORT_DESC;
983 $array2_sort_order = SORT_ASC;
984 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
985 } else {
986 $countryArray = dol_sort_array($countryArray, 'label');
987 }
988
989 if ($showempty) {
990 if (is_numeric($showempty)) {
991 $out .= '<option value="">&nbsp;</option>' . "\n";
992 } else {
993 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
994 }
995 }
996
997 if ($addspecialentries) { // Add dedicated entries for groups of countries
998 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
999 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1000 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
1001 if ($mysoc->isInEEC()) {
1002 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1003 }
1004 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1005 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1006 }
1007
1008 foreach ($countryArray as $row) {
1009 //if (empty($showempty) && empty($row['rowid'])) continue;
1010 if (empty($row['rowid'])) {
1011 continue;
1012 }
1013 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1014 continue; // exclude some countries
1015 }
1016
1017 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1018 $atleastonefavorite++;
1019 }
1020 if (empty($row['favorite']) && $atleastonefavorite) {
1021 $atleastonefavorite = 0;
1022 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1023 }
1024
1025 $labeltoshow = '';
1026 if ($row['label']) {
1027 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1028 } else {
1029 $labeltoshow .= '&nbsp;';
1030 }
1031 if ($row['code_iso']) {
1032 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1033 if (empty($hideflags)) {
1034 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1035 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1036 }
1037 }
1038
1039 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1040 $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']) . '">';
1041 } else {
1042 $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']) . '">';
1043 }
1044 $out .= $labeltoshow;
1045 $out .= '</option>' . "\n";
1046 }
1047 }
1048 $out .= '</select>';
1049 } else {
1050 dol_print_error($this->db);
1051 }
1052
1053 // Make select dynamic
1054 if (empty($forcecombo)) {
1055 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1056 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1057 }
1058
1059 return $out;
1060 }
1061
1062 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1063
1077 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1078 {
1079 // phpcs:enable
1080 global $conf, $langs;
1081
1082 $langs->load("dict");
1083
1084 $out = '';
1085 //$moreattrib = '';
1086 $incotermArray = array();
1087
1088 $sql = "SELECT rowid, code";
1089 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1090 $sql .= " WHERE active > 0";
1091 $sql .= " ORDER BY code ASC";
1092
1093 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1094 $resql = $this->db->query($sql);
1095 if ($resql) {
1096 if ($conf->use_javascript_ajax && !$forcecombo) {
1097 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1098 $out .= ajax_combobox($htmlname, $events);
1099 }
1100
1101 if (!empty($page)) {
1102 $out .= '<form method="post" action="' . $page . '">';
1103 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1104 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1105 }
1106
1107 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1108 $out .= '<option value="0">&nbsp;</option>';
1109 $num = $this->db->num_rows($resql);
1110 $i = 0;
1111 if ($num) {
1112 while ($i < $num) {
1113 $obj = $this->db->fetch_object($resql);
1114 $incotermArray[$i]['rowid'] = $obj->rowid;
1115 $incotermArray[$i]['code'] = $obj->code;
1116 $i++;
1117 }
1118
1119 foreach ($incotermArray as $row) {
1120 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1121 $out .= '<option value="' . $row['rowid'] . '" selected>';
1122 } else {
1123 $out .= '<option value="' . $row['rowid'] . '">';
1124 }
1125
1126 if ($row['code']) {
1127 $out .= $row['code'];
1128 }
1129
1130 $out .= '</option>';
1131 }
1132 }
1133 $out .= '</select>';
1134 $out .= ajax_combobox($htmlname);
1135
1136 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1137 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1138 //$moreattrib .= ' autocomplete="off"';
1139 }
1140 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1141
1142 if (!empty($page)) {
1143 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1144 }
1145 } else {
1146 dol_print_error($this->db);
1147 }
1148
1149 return $out;
1150 }
1151
1152 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1153
1167 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "", $useajaxcombo = 1)
1168 {
1169 // phpcs:enable
1170 global $langs;
1171
1172 // If product & services are enabled or both disabled.
1173 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1174 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1175 if (empty($hidetext)) {
1176 print $langs->trans("Type").'...';
1177 }
1178 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1179 if ($showempty) {
1180 print '<option value="-1" class="opacitymedium"'.($useajaxcombo ? '' : ' disabled="disabled"');
1181 if ($selected == -1) {
1182 print ' selected';
1183 }
1184 print '>';
1185 if (is_numeric($showempty)) {
1186 print '&nbsp;';
1187 } else {
1188 print $showempty;
1189 }
1190 print '</option>';
1191 }
1192
1193 print '<option value="0"';
1194 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1195 print ' selected';
1196 }
1197 print '>' . $langs->trans("Product");
1198
1199 print '<option value="1"';
1200 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1201 print ' selected';
1202 }
1203 print '>' . $langs->trans("Service");
1204
1205 print '</select>';
1206
1207 if ($useajaxcombo) {
1208 print ajax_combobox('select_' . $htmlname);
1209 }
1210 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1211 }
1212 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1213 print $langs->trans("Service");
1214 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1215 }
1216 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1217 print $langs->trans("Product");
1218 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1219 }
1220 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1221 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
1222 }
1223 }
1224
1225 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1226
1232 public function load_cache_types_fees()
1233 {
1234 // phpcs:enable
1235 global $langs;
1236
1237 $num = count($this->cache_types_fees);
1238 if ($num > 0) {
1239 return 0; // Cache already loaded
1240 }
1241
1242 dol_syslog(__METHOD__, LOG_DEBUG);
1243
1244 $langs->load("trips");
1245
1246 $sql = "SELECT c.code, c.label";
1247 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1248 $sql .= " WHERE active > 0";
1249
1250 $resql = $this->db->query($sql);
1251 if ($resql) {
1252 $num = $this->db->num_rows($resql);
1253 $i = 0;
1254
1255 while ($i < $num) {
1256 $obj = $this->db->fetch_object($resql);
1257
1258 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1259 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1260 $this->cache_types_fees[$obj->code] = $label;
1261 $i++;
1262 }
1263
1264 asort($this->cache_types_fees);
1265
1266 return $num;
1267 } else {
1268 dol_print_error($this->db);
1269 return -1;
1270 }
1271 }
1272
1273 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1274
1283 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1284 {
1285 // phpcs:enable
1286 global $user, $langs;
1287
1288 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1289
1290 $this->load_cache_types_fees();
1291
1292 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1293 if ($showempty) {
1294 print '<option value="-1"';
1295 if ($selected == -1) {
1296 print ' selected';
1297 }
1298 print '>&nbsp;</option>';
1299 }
1300
1301 foreach ($this->cache_types_fees as $key => $value) {
1302 print '<option value="' . $key . '"';
1303 if ($key == $selected) {
1304 print ' selected';
1305 }
1306 print '>';
1307 print $value;
1308 print '</option>';
1309 }
1310
1311 print '</select>';
1312 if ($user->admin) {
1313 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1314 }
1315 }
1316
1317
1318 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1319
1342 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)
1343 {
1344 // phpcs:enable
1345 global $conf, $langs;
1346
1347 $out = '';
1348
1349 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1350 if (is_null($ajaxoptions)) {
1351 $ajaxoptions = array();
1352 }
1353
1354 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1355
1356 // No immediate load of all database
1357 $placeholder = '';
1358 if ($selected && empty($selected_input_value)) {
1359 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1360 $societetmp = new Societe($this->db);
1361 $societetmp->fetch($selected);
1362 $selected_input_value = $societetmp->name;
1363 unset($societetmp);
1364 }
1365
1366 // mode 1
1367 $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)) : '');
1368
1369 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1370 if (empty($hidelabel)) {
1371 $out .= $langs->trans("RefOrLabel") . ' : ';
1372 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1373 $placeholder = $langs->trans($showempty);
1374 } elseif ($hidelabel > 1) {
1375 $placeholder = $langs->trans("RefOrLabel");
1376 if ($hidelabel == 2) {
1377 $out .= img_picto($langs->trans("Search"), 'search');
1378 }
1379 }
1380 $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' : '') . ' />';
1381 if ($hidelabel == 3) {
1382 $out .= img_picto($langs->trans("Search"), 'search');
1383 }
1384
1385 $out .= ajax_event($htmlname, $events);
1386
1387 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1388 } else {
1389 // Immediate load of all database
1390 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1391 }
1392
1393 return $out;
1394 }
1395
1396
1397 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1398
1424 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 = '')
1425 {
1426 // phpcs:enable
1427
1428 global $conf, $langs;
1429
1430 $out = '';
1431
1432 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1433 if ($nokeyifsocid && $socid > 0) {
1434 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1435 }
1436
1437 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1438 if (is_null($events)) {
1439 $events = array();
1440 }
1441
1442 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1443
1444 // No immediate load of all database
1445 $placeholder = '';
1446 if ($selected && empty($selected_input_value)) {
1447 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1448 $contacttmp = new Contact($this->db);
1449 $contacttmp->fetch($selected);
1450 $selected_input_value = $contacttmp->getFullName($langs);
1451 unset($contacttmp);
1452 }
1453 if (!is_numeric($showempty)) {
1454 $placeholder = $showempty;
1455 }
1456
1457 // mode 1
1458 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1459
1460 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1461
1462 $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' : '') . ' />';
1463
1464 $out .= ajax_event($htmlname, $events);
1465
1466 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1467 } else {
1468 // Immediate load of all database
1469 $multiple = false;
1470 $disableifempty = 0;
1471 $options_only = 0;
1472 $limitto = '';
1473
1474 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1475 }
1476
1477 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1478
1479 return $out;
1480 }
1481
1482
1483 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1484
1509 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)
1510 {
1511 // phpcs:enable
1512 global $user, $langs;
1513 global $hookmanager;
1514
1515 $langs->loadLangs(array("companies", "suppliers"));
1516
1517 $out = '';
1518 $num = 0;
1519 $outarray = array();
1520
1521 if ($selected === '') {
1522 $selected = array();
1523 } elseif (!is_array($selected)) {
1524 $selected = array($selected);
1525 }
1526
1527 // Clean $filter that may contains sql conditions so sql code
1528 if (function_exists('testSqlAndScriptInject')) {
1529 if (testSqlAndScriptInject($filter, 3) > 0) {
1530 $filter = '';
1531 return 'SQLInjectionTryDetected';
1532 }
1533 }
1534
1535 if ($filter != '') { // If a filter was provided
1536 if (preg_match('/[\‍(\‍)]/', $filter)) {
1537 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1538 $errormsg = '';
1539 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1540
1541 // Redo clean $filter that may contains sql conditions so sql code
1542 if (function_exists('testSqlAndScriptInject')) {
1543 if (testSqlAndScriptInject($filter, 3) > 0) {
1544 $filter = '';
1545 return 'SQLInjectionTryDetected';
1546 }
1547 }
1548 } else {
1549 // If not, we do nothing. We already know that there is no parenthesis
1550 // TODO Disallow this case in a future.
1551 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1552 }
1553 }
1554
1555 // We search companies
1556 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1557 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1558 $sql .= ", s.address, s.zip, s.town";
1559 $sql .= ", dictp.code as country_code";
1560 }
1561 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1562 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1563 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1564 }
1565 if (!$user->hasRight('societe', 'client', 'voir')) {
1566 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1567 }
1568 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1569 if (!empty($user->socid)) {
1570 $sql .= " AND s.rowid = " . ((int) $user->socid);
1571 }
1572 if ($filter) {
1573 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1574 // if not, by testSqlAndScriptInject() only.
1575 $sql .= " AND (" . $filter . ")";
1576 }
1577 if (!$user->hasRight('societe', 'client', 'voir')) {
1578 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1579 }
1580 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1581 $sql .= " AND s.status <> 0";
1582 }
1583 if (!empty($excludeids)) {
1584 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1585 }
1586 // Add where from hooks
1587 $parameters = array();
1588 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1589 $sql .= $hookmanager->resPrint;
1590 // Add criteria
1591 if ($filterkey && $filterkey != '') {
1592 $sql .= " AND (";
1593 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1594 // For natural search
1595 $search_crit = explode(' ', $filterkey);
1596 $i = 0;
1597 if (count($search_crit) > 1) {
1598 $sql .= "(";
1599 }
1600 foreach ($search_crit as $crit) {
1601 if ($i > 0) {
1602 $sql .= " AND ";
1603 }
1604 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1605 $i++;
1606 }
1607 if (count($search_crit) > 1) {
1608 $sql .= ")";
1609 }
1610 if (isModEnabled('barcode')) {
1611 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1612 }
1613 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1614 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1615 $sql .= ")";
1616 }
1617 $sql .= $this->db->order("nom", "ASC");
1618 $sql .= $this->db->plimit($limit, 0);
1619
1620 // Build output string
1621 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1622 $resql = $this->db->query($sql);
1623 if ($resql) {
1624 // Construct $out and $outarray
1625 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1626
1627 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1628 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1629 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1630 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1631 if ($showempty && !is_numeric($showempty)) {
1632 $textifempty = $langs->trans($showempty);
1633 } else {
1634 $textifempty .= $langs->trans("All");
1635 }
1636 }
1637 if ($showempty) {
1638 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1639 }
1640
1641 $companytemp = new Societe($this->db);
1642
1643 $num = $this->db->num_rows($resql);
1644 $i = 0;
1645 if ($num) {
1646 while ($i < $num) {
1647 $obj = $this->db->fetch_object($resql);
1648 $label = '';
1649 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1650 if (($obj->client) && (!empty($obj->code_client))) {
1651 $label = $obj->code_client . ' - ';
1652 }
1653 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1654 $label .= $obj->code_fournisseur . ' - ';
1655 }
1656 $label .= ' ' . $obj->name;
1657 } else {
1658 $label = $obj->name;
1659 }
1660
1661 if (!empty($obj->name_alias)) {
1662 $label .= ' (' . $obj->name_alias . ')';
1663 }
1664
1665 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1666 $label .= ' - '.$obj->tva_intra;
1667 }
1668
1669 $labelhtml = $label;
1670
1671 if ($showtype) {
1672 $companytemp->id = $obj->rowid;
1673 $companytemp->client = $obj->client;
1674 $companytemp->fournisseur = $obj->fournisseur;
1675 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1676 if ($tmptype) {
1677 $labelhtml .= ' ' . $tmptype;
1678 }
1679
1680 if ($obj->client || $obj->fournisseur) {
1681 $label .= ' (';
1682 }
1683 if ($obj->client == 1 || $obj->client == 3) {
1684 $label .= $langs->trans("Customer");
1685 }
1686 if ($obj->client == 2 || $obj->client == 3) {
1687 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1688 }
1689 if ($obj->fournisseur) {
1690 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1691 }
1692 if ($obj->client || $obj->fournisseur) {
1693 $label .= ')';
1694 }
1695 }
1696
1697 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1698 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1699 if (!empty($obj->country_code)) {
1700 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1701 }
1702 $label .= $s;
1703 $labelhtml .= $s;
1704 }
1705
1706 if (empty($outputmode)) {
1707 if (in_array($obj->rowid, $selected)) {
1708 $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>';
1709 } else {
1710 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1711 }
1712 } else {
1713 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1714 }
1715
1716 $i++;
1717 if (($i % 10) == 0) {
1718 $out .= "\n";
1719 }
1720 }
1721 }
1722 $out .= '</select>' . "\n";
1723 if (!$forcecombo) {
1724 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1725 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1726 }
1727 } else {
1728 dol_print_error($this->db);
1729 }
1730
1731 $this->result = array('nbofthirdparties' => $num);
1732
1733 if ($outputmode) {
1734 return $outarray;
1735 }
1736 return $out;
1737 }
1738
1739
1765 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 = '')
1766 {
1767 global $conf, $user, $langs, $hookmanager, $action;
1768
1769 $langs->load('companies');
1770
1771 if (empty($htmlid)) {
1772 $htmlid = $htmlname;
1773 }
1774 $num = 0;
1775 $out = '';
1776 $outarray = array();
1777
1778 if ($selected === '') {
1779 $selected = array();
1780 } elseif (!is_array($selected)) {
1781 $selected = array((int) $selected);
1782 }
1783
1784 // Clean $filter that may contains sql conditions so sql code
1785 if (function_exists('testSqlAndScriptInject')) {
1786 if (testSqlAndScriptInject($filter, 3) > 0) {
1787 $filter = '';
1788 return 'SQLInjectionTryDetected';
1789 }
1790 }
1791
1792 if ($filter != '') { // If a filter was provided
1793 if (preg_match('/[\‍(\‍)]/', $filter)) {
1794 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1795 $errormsg = '';
1796 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1797
1798 // Redo clean $filter that may contains sql conditions so sql code
1799 if (function_exists('testSqlAndScriptInject')) {
1800 if (testSqlAndScriptInject($filter, 3) > 0) {
1801 $filter = '';
1802 return 'SQLInjectionTryDetected';
1803 }
1804 }
1805 } else {
1806 // If not, we do nothing. We already know that there is no parenthesis
1807 // TODO Disallow this case in a future by returning an error here.
1808 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1809 }
1810 }
1811
1812 if (!is_object($hookmanager)) {
1813 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1814 $hookmanager = new HookManager($this->db);
1815 }
1816
1817 // We search third parties
1818 $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";
1819 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1820 $sql .= ", s.nom as company, s.town AS company_town";
1821 }
1822 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1823 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1824 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1825 }
1826 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1827 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1828 if ($socid > 0 || $socid == -1) {
1829 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1830 }
1831 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1832 $sql .= " AND sp.statut <> 0";
1833 }
1834 if ($filter) {
1835 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1836 // if not, by testSqlAndScriptInject() only.
1837 $sql .= " AND (" . $filter . ")";
1838 }
1839 // Add where from hooks
1840 $parameters = array();
1841 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1842 $sql .= $hookmanager->resPrint;
1843 $sql .= " ORDER BY sp.lastname ASC";
1844
1845 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1846 $resql = $this->db->query($sql);
1847 if ($resql) {
1848 $num = $this->db->num_rows($resql);
1849
1850 if ($htmlname != 'none' && !$options_only) {
1851 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1852 }
1853
1854 if ($showempty && !is_numeric($showempty)) {
1855 $textforempty = $showempty;
1856 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1857 } else {
1858 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1859 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1860 }
1861 if ($showempty == 2) {
1862 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1863 }
1864 }
1865
1866 $i = 0;
1867 if ($num) {
1868 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1869 $contactstatic = new Contact($this->db);
1870
1871 while ($i < $num) {
1872 $obj = $this->db->fetch_object($resql);
1873
1874 // Set email (or phones) and town extended infos
1875 $extendedInfos = '';
1876 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1877 $extendedInfos = array();
1878 $email = trim($obj->email);
1879 if (!empty($email)) {
1880 $extendedInfos[] = $email;
1881 } else {
1882 $phone = trim($obj->phone);
1883 $phone_perso = trim($obj->phone_perso);
1884 $phone_mobile = trim($obj->phone_mobile);
1885 if (!empty($phone)) {
1886 $extendedInfos[] = $phone;
1887 }
1888 if (!empty($phone_perso)) {
1889 $extendedInfos[] = $phone_perso;
1890 }
1891 if (!empty($phone_mobile)) {
1892 $extendedInfos[] = $phone_mobile;
1893 }
1894 }
1895 $contact_town = trim($obj->contact_town);
1896 $company_town = trim($obj->company_town);
1897 if (!empty($contact_town)) {
1898 $extendedInfos[] = $contact_town;
1899 } elseif (!empty($company_town)) {
1900 $extendedInfos[] = $company_town;
1901 }
1902 $extendedInfos = implode(' - ', $extendedInfos);
1903 if (!empty($extendedInfos)) {
1904 $extendedInfos = ' - ' . $extendedInfos;
1905 }
1906 }
1907
1908 $contactstatic->id = $obj->rowid;
1909 $contactstatic->lastname = $obj->lastname;
1910 $contactstatic->firstname = $obj->firstname;
1911 if ($obj->statut == 1) {
1912 $tmplabel = '';
1913 if ($htmlname != 'none') {
1914 $disabled = 0;
1915 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1916 $disabled = 1;
1917 }
1918 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1919 $disabled = 1;
1920 }
1921 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1922 $out .= '<option value="' . $obj->rowid . '"';
1923 if ($disabled) {
1924 $out .= ' disabled';
1925 }
1926 $out .= ' selected>';
1927
1928 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1929 if ($showfunction && $obj->poste) {
1930 $tmplabel .= ' (' . $obj->poste . ')';
1931 }
1932 if (($showsoc > 0) && $obj->company) {
1933 $tmplabel .= ' - (' . $obj->company . ')';
1934 }
1935
1936 $out .= $tmplabel;
1937 $out .= '</option>';
1938 } else {
1939 $out .= '<option value="' . $obj->rowid . '"';
1940 if ($disabled) {
1941 $out .= ' disabled';
1942 }
1943 $out .= '>';
1944
1945 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1946 if ($showfunction && $obj->poste) {
1947 $tmplabel .= ' (' . $obj->poste . ')';
1948 }
1949 if (($showsoc > 0) && $obj->company) {
1950 $tmplabel .= ' - (' . $obj->company . ')';
1951 }
1952
1953 $out .= $tmplabel;
1954 $out .= '</option>';
1955 }
1956 } else {
1957 if (in_array($obj->rowid, $selected)) {
1958 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1959 if ($showfunction && $obj->poste) {
1960 $tmplabel .= ' (' . $obj->poste . ')';
1961 }
1962 if (($showsoc > 0) && $obj->company) {
1963 $tmplabel .= ' - (' . $obj->company . ')';
1964 }
1965
1966 $out .= $tmplabel;
1967 }
1968 }
1969
1970 if ($tmplabel != '') {
1971 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1972 }
1973 }
1974 $i++;
1975 }
1976 } else {
1977 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1978 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1979 $out .= $labeltoshow;
1980 $out .= '</option>';
1981 }
1982
1983 $parameters = array(
1984 'socid' => $socid,
1985 'htmlname' => $htmlname,
1986 'resql' => $resql,
1987 'out' => &$out,
1988 'showfunction' => $showfunction,
1989 'showsoc' => $showsoc,
1990 );
1991
1992 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1993
1994 if ($htmlname != 'none' && !$options_only) {
1995 $out .= '</select>';
1996 }
1997
1998 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1999 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2000 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
2001 }
2002
2003 $this->num = $num;
2004
2005 if ($options_only === 2) {
2006 // Return array of options
2007 return $outarray;
2008 } else {
2009 return $out;
2010 }
2011 } else {
2012 dol_print_error($this->db);
2013 return -1;
2014 }
2015 }
2016
2017
2018 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2019
2030 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2031 {
2032 // phpcs:enable
2033 global $langs, $conf;
2034
2035 // On recherche les remises
2036 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2037 $sql .= " re.description, re.fk_facture_source";
2038 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2039 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2040 $sql .= " AND re.entity = " . $conf->entity;
2041 if ($filter) {
2042 $sql .= " AND " . $filter;
2043 }
2044 $sql .= " ORDER BY re.description ASC";
2045
2046 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2047 $resql = $this->db->query($sql);
2048 if ($resql) {
2049 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2050 $num = $this->db->num_rows($resql);
2051
2052 $qualifiedlines = $num;
2053
2054 $i = 0;
2055 if ($num) {
2056 print '<option value="0">&nbsp;</option>';
2057 while ($i < $num) {
2058 $obj = $this->db->fetch_object($resql);
2059 $desc = dol_trunc($obj->description, 40);
2060 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2061 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2062 }
2063 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2064 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2065 }
2066 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2067 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2068 }
2069 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2070 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2071 }
2072
2073 $selectstring = '';
2074 if ($selected > 0 && $selected == $obj->rowid) {
2075 $selectstring = ' selected';
2076 }
2077
2078 $disabled = '';
2079 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2080 $qualifiedlines--;
2081 $disabled = ' disabled';
2082 }
2083
2084 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2085 $tmpfac = new Facture($this->db);
2086 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2087 $desc = $desc . ' - ' . $tmpfac->ref;
2088 }
2089 }
2090
2091 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2092 $i++;
2093 }
2094 }
2095 print '</select>';
2096 print ajax_combobox('select_' . $htmlname);
2097
2098 return $qualifiedlines;
2099 } else {
2100 dol_print_error($this->db);
2101 return -1;
2102 }
2103 }
2104
2105
2106 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2107
2123 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2124 {
2125 // phpcs:enable
2126 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2127 }
2128
2129 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2130
2155 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)
2156 {
2157 // phpcs:enable
2158 global $conf, $user, $langs, $hookmanager;
2159 global $action;
2160
2161 // If no preselected user defined, we take current user
2162 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2163 $selected = $user->id;
2164 }
2165
2166 if ($selected === '') {
2167 $selected = array();
2168 } elseif (!is_array($selected)) {
2169 $selected = array($selected);
2170 }
2171
2172 $excludeUsers = null;
2173 $includeUsers = null;
2174
2175 // Exclude some users
2176 if (is_array($exclude)) {
2177 $excludeUsers = implode(",", $exclude);
2178 }
2179 // Include some uses
2180 if (is_array($include)) {
2181 $includeUsers = implode(",", $include);
2182 } elseif ($include == 'hierarchy') {
2183 // Build list includeUsers to have only hierarchy
2184 $includeUsers = implode(",", $user->getAllChildIds(0));
2185 } elseif ($include == 'hierarchyme') {
2186 // Build list includeUsers to have only hierarchy and current user
2187 $includeUsers = implode(",", $user->getAllChildIds(1));
2188 }
2189
2190 $num = 0;
2191
2192 $out = '';
2193 $outarray = array();
2194 $outarray2 = array();
2195
2196 // Do we want to show the label of entity into the combo list ?
2197 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2198 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2199
2200 // Forge request to select users
2201 $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";
2202 if ($showlabelofentity) {
2203 $sql .= ", e.label";
2204 }
2205 $sql .= " FROM " . $this->db->prefix() . "user as u";
2206 if ($showlabelofentity) {
2207 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2208 }
2209 // Condition here should be the same than into societe->getSalesRepresentatives().
2210 if ($userissuperadminentityone && $force_entity !== 'default') {
2211 if (!empty($force_entity)) {
2212 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2213 } else {
2214 $sql .= " WHERE u.entity IS NOT NULL";
2215 }
2216 } else {
2217 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2218 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2219 } else {
2220 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2221 }
2222 }
2223
2224 if (!empty($user->socid)) {
2225 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2226 }
2227 if (is_array($exclude) && $excludeUsers) {
2228 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2229 }
2230 if ($includeUsers) {
2231 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2232 }
2233 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2234 $sql .= " AND u.statut <> 0";
2235 }
2236 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2237 $sql .= " AND u.employee <> 0";
2238 }
2239 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2240 $sql .= " AND u.fk_soc IS NULL";
2241 }
2242 if (!empty($morefilter)) {
2243 $errormessage = '';
2244 $sql .= forgeSQLFromUniversalSearchCriteria($morefilter, $errormessage);
2245 if ($errormessage) {
2246 $this->errors[] = $errormessage;
2247 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2248 if ($outputmode == 0) {
2249 return 'Error bad param $morefilter';
2250 } else {
2251 return array();
2252 }
2253 }
2254 }
2255
2256 //Add hook to filter on user (for example on usergroup define in custom modules)
2257 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2258 if (!empty($reshook)) {
2259 $sql .= $hookmanager->resPrint;
2260 }
2261
2262 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2263 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2264 } else {
2265 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2266 }
2267
2268 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2269
2270 $resql = $this->db->query($sql);
2271 if ($resql) {
2272 $num = $this->db->num_rows($resql);
2273 $i = 0;
2274 if ($num) {
2275 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2276 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2277 if ($show_empty && !$multiple) {
2278 $textforempty = ' ';
2279 if (!empty($conf->use_javascript_ajax)) {
2280 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2281 }
2282 if (!is_numeric($show_empty)) {
2283 $textforempty = $show_empty;
2284 }
2285 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2286
2287 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2288 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2289 'id' => ($show_empty < 0 ? $show_empty : -1),
2290 'label' => $textforempty,
2291 'labelhtml' => $textforempty,
2292 'color' => '',
2293 'picto' => ''
2294 );
2295 }
2296 if ($show_every) {
2297 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2298
2299 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2300 $outarray2[-2] = array(
2301 'id' => -2,
2302 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2303 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2304 'color' => '',
2305 'picto' => ''
2306 );
2307 }
2308
2309 $userstatic = new User($this->db);
2310
2311 while ($i < $num) {
2312 $obj = $this->db->fetch_object($resql);
2313
2314 $userstatic->id = $obj->rowid;
2315 $userstatic->lastname = $obj->lastname;
2316 $userstatic->firstname = $obj->firstname;
2317 $userstatic->photo = $obj->photo;
2318 $userstatic->status = $obj->status;
2319 $userstatic->entity = $obj->entity;
2320 $userstatic->admin = $obj->admin;
2321 $userstatic->gender = $obj->gender;
2322
2323 $disableline = '';
2324 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2325 $disableline = ($enableonlytext ? $enableonlytext : '1');
2326 }
2327
2328 $labeltoshow = '';
2329 $labeltoshowhtml = '';
2330
2331 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2332 $fullNameMode = 0;
2333 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2334 $fullNameMode = 1; //Firstname+lastname
2335 }
2336 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2337 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2338 if (empty($obj->firstname) && empty($obj->lastname)) {
2339 $labeltoshow .= $obj->login;
2340 $labeltoshowhtml .= $obj->login;
2341 }
2342
2343 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2344 $moreinfo = '';
2345 $moreinfohtml = '';
2346 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2347 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2348 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2349 $moreinfo .= $obj->login;
2350 $moreinfohtml .= $obj->login;
2351 }
2352 if ($showstatus >= 0) {
2353 if ($obj->status == 1 && $showstatus == 1) {
2354 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2355 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2356 }
2357 if ($obj->status == 0 && $showstatus == 1) {
2358 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2359 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2360 }
2361 }
2362 if ($showlabelofentity) {
2363 if (empty($obj->entity)) {
2364 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2365 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2366 } else {
2367 if ($obj->entity != $conf->entity) {
2368 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2369 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2370 }
2371 }
2372 }
2373 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2374 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2375 if (!empty($disableline) && $disableline != '1') {
2376 // Add text from $enableonlytext parameter
2377 $moreinfo .= ' - ' . $disableline;
2378 $moreinfohtml .= ' - ' . $disableline;
2379 }
2380 $labeltoshow .= $moreinfo;
2381 $labeltoshowhtml .= $moreinfohtml;
2382
2383 $out .= '<option value="' . $obj->rowid . '"';
2384 if (!empty($disableline)) {
2385 $out .= ' disabled';
2386 }
2387 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2388 $out .= ' selected';
2389 }
2390 $out .= ' data-html="';
2391
2392 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2393 if ($showstatus >= 0 && $obj->status == 0) {
2394 $outhtml .= '<strike class="opacitymediumxxx">';
2395 }
2396 $outhtml .= $labeltoshowhtml;
2397 if ($showstatus >= 0 && $obj->status == 0) {
2398 $outhtml .= '</strike>';
2399 }
2400 $labeltoshowhtml = $outhtml;
2401
2402 $out .= dol_escape_htmltag($outhtml);
2403 $out .= '">';
2404 $out .= $labeltoshow;
2405 $out .= '</option>';
2406
2407 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2408 $outarray2[$userstatic->id] = array(
2409 'id' => $userstatic->id,
2410 'label' => $labeltoshow,
2411 'labelhtml' => $labeltoshowhtml,
2412 'color' => '',
2413 'picto' => ''
2414 );
2415
2416 $i++;
2417 }
2418 } else {
2419 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2420 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2421 }
2422 $out .= '</select>';
2423
2424 if ($num && !$forcecombo) {
2425 // Enhance with select2
2426 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2427 $out .= ajax_combobox($htmlname);
2428 }
2429 } else {
2430 dol_print_error($this->db);
2431 }
2432
2433 $this->num = $num;
2434
2435 if ($outputmode == 2) {
2436 return $outarray2;
2437 } elseif ($outputmode) {
2438 return $outarray;
2439 }
2440
2441 return $out;
2442 }
2443
2444
2445 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2469 public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array(), $canremoveowner = 1)
2470 {
2471 // phpcs:enable
2472 global $langs, $user;
2473
2474 $userstatic = new User($this->db);
2475 $out = '';
2476
2477 if (!empty($_SESSION['assignedtouser'])) {
2478 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2479 if (!is_array($assignedtouser)) {
2480 $assignedtouser = array();
2481 }
2482 } else {
2483 $assignedtouser = array();
2484 }
2485 $nbassignetouser = count($assignedtouser);
2486
2487 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2488 if ($nbassignetouser) {
2489 $out .= '<ul class="attendees">';
2490 }
2491 $i = 0;
2492 $ownerid = 0;
2493 foreach ($assignedtouser as $key => $value) {
2494 if ($value['id'] == $ownerid) {
2495 continue;
2496 }
2497
2498 $out .= '<li>';
2499 $userstatic->fetch($value['id']);
2500 $out .= $userstatic->getNomUrl(-1);
2501 if ($i == 0) {
2502 $ownerid = $value['id'];
2503 $out .= ' (' . $langs->trans("Owner") . ')';
2504 }
2505 // Add picto to delete owner/assignee
2506 if ($nbassignetouser > 1 && $action != 'view') {
2507 $canremoveassignee = 1;
2508 if ($i == 0) {
2509 // We are on the owner of the event
2510 if (!$canremoveowner) {
2511 $canremoveassignee = 0;
2512 }
2513 if (!$user->hasRight('agenda', 'allactions', 'create')) {
2514 $canremoveassignee = 0; // Can't remove the owner
2515 }
2516 } else {
2517 // We are not on the owner of the event but on a secondary assignee
2518 }
2519 if ($canremoveassignee) {
2520 // If user has all permission, he should be ableto remove a assignee.
2521 // If user has not all permission, he can onlyremove assignee of other (he can't remove itself)
2522 $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 . '">';
2523 }
2524 }
2525 // Show my availability
2526 if ($showproperties) {
2527 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2528 $out .= '<div class="myavailability inline-block">';
2529 $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>';
2530 $out .= '</div>';
2531 }
2532 }
2533 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2534 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2535
2536 $out .= '</li>';
2537 $i++;
2538 }
2539 if ($nbassignetouser) {
2540 $out .= '</ul>';
2541 }
2542
2543 // Method with no ajax
2544 if ($action != 'view') {
2545 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2546 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2547 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2548 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2549 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2550 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2551 $out .= '});';
2552 $out .= '})</script>';
2553 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2554 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2555 $out .= '<br>';
2556 }
2557
2558 return $out;
2559 }
2560
2561 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2581 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())
2582 {
2583 // phpcs:enable
2584 global $langs;
2585
2586 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2587 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2588 $formresources = new FormResource($this->db);
2589 $resourcestatic = new Dolresource($this->db);
2590
2591 $out = '';
2592 if (!empty($_SESSION['assignedtoresource'])) {
2593 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2594 if (!is_array($assignedtoresource)) {
2595 $assignedtoresource = array();
2596 }
2597 } else {
2598 $assignedtoresource = array();
2599 }
2600 $nbassignetoresource = count($assignedtoresource);
2601
2602 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2603 if ($nbassignetoresource) {
2604 $out .= '<ul class="attendees">';
2605 }
2606 $i = 0;
2607
2608 foreach ($assignedtoresource as $key => $value) {
2609 $out .= '<li>';
2610 $resourcestatic->fetch($value['id']);
2611 $out .= $resourcestatic->getNomUrl(-1);
2612 if ($nbassignetoresource >= 1 && $action != 'view') {
2613 $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 . '">';
2614 }
2615 // Show my availability
2616 if ($showproperties) {
2617 if (is_array($listofresourceid) && count($listofresourceid)) {
2618 $out .= '<div class="myavailability inline-block">';
2619 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparencyresource'.$value['id'].'" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparencyresource'.$value['id'].'">' . $langs->trans("Busy") . '</label>';
2620 $out .= '</div>';
2621 }
2622 }
2623 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2624 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2625
2626 $out .= '</li>';
2627 $i++;
2628 }
2629 if ($nbassignetoresource) {
2630 $out .= '</ul>';
2631 }
2632
2633 // Method with no ajax
2634 if ($action != 'view') {
2635 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2636 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2637 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2638 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2639 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2640 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2641 $out .= '});';
2642 $out .= '})</script>';
2643
2644 $events = array();
2645 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2646 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2647 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2648 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2649 $out .= '<br>';
2650 }
2651
2652 return $out;
2653 }
2654
2655 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2656
2686 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)
2687 {
2688 // phpcs:enable
2689 global $langs, $conf;
2690
2691 $out = '';
2692
2693 // check parameters
2694 $price_level = (!empty($price_level) ? $price_level : 0);
2695 if (is_null($ajaxoptions)) {
2696 $ajaxoptions = array();
2697 }
2698
2699 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2700 if (isModEnabled("product") && !isModEnabled('service')) {
2701 $filtertype = '0';
2702 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2703 $filtertype = '1';
2704 }
2705 }
2706
2707 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2708 $placeholder = (is_numeric($showempty) ? '' : 'placeholder="'.dolPrintHTML($showempty).'"');
2709
2710 if ($selected && empty($selected_input_value)) {
2711 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2712 $producttmpselect = new Product($this->db);
2713 $producttmpselect->fetch($selected);
2714 $selected_input_value = $producttmpselect->ref;
2715 unset($producttmpselect);
2716 }
2717 // handle case where product or service module is disabled + no filter specified
2718 if ($filtertype == '') {
2719 if (!isModEnabled('product')) { // when product module is disabled, show services only
2720 $filtertype = 1;
2721 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2722 $filtertype = 0;
2723 }
2724 }
2725 // mode=1 means customers products
2726 $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;
2727 if ((int) $warehouseId > 0) {
2728 $urloption .= '&warehouseid=' . (int) $warehouseId;
2729 }
2730
2731 $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);
2732
2733 if (isModEnabled('variants') && is_array($selected_combinations)) {
2734 // Code to automatically insert with javascript the select of attributes under the select of product
2735 // when a parent of variant has been selected.
2736 $out .= '
2737 <!-- script to auto show attributes select tags if a variant was selected -->
2738 <script nonce="' . getNonce() . '">
2739 // auto show attributes fields
2740 selected = ' . json_encode($selected_combinations) . ';
2741 combvalues = {};
2742
2743 jQuery(document).ready(function () {
2744
2745 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2746 if (jQuery(this).val() == \'free\') {
2747 jQuery(\'div#attributes_box\').empty();
2748 }
2749 });
2750
2751 jQuery("input#' . $htmlname . '").change(function () {
2752
2753 if (!jQuery(this).val()) {
2754 jQuery(\'div#attributes_box\').empty();
2755 return;
2756 }
2757
2758 console.log("A change has started. We get variants fields to inject html select");
2759
2760 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2761 id: jQuery(this).val()
2762 }, function (data) {
2763 jQuery(\'div#attributes_box\').empty();
2764
2765 jQuery.each(data, function (key, val) {
2766
2767 combvalues[val.id] = val.values;
2768
2769 var span = jQuery(document.createElement(\'div\')).css({
2770 \'display\': \'table-row\'
2771 });
2772
2773 span.append(
2774 jQuery(document.createElement(\'div\')).text(val.label).css({
2775 \'font-weight\': \'bold\',
2776 \'display\': \'table-cell\'
2777 })
2778 );
2779
2780 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2781 \'margin-left\': \'15px\',
2782 \'white-space\': \'pre\'
2783 }).append(
2784 jQuery(document.createElement(\'option\')).val(\'\')
2785 );
2786
2787 jQuery.each(combvalues[val.id], function (key, val) {
2788 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2789
2790 if (selected[val.fk_product_attribute] == val.id) {
2791 tag.attr(\'selected\', \'selected\');
2792 }
2793
2794 html.append(tag);
2795 });
2796
2797 span.append(html);
2798 jQuery(\'div#attributes_box\').append(span);
2799 });
2800 })
2801 });
2802
2803 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2804 });
2805 </script>
2806 ';
2807 }
2808
2809 if (empty($hidelabel)) {
2810 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2811 } elseif ($hidelabel > 1) {
2812 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2813 if ($hidelabel == 2) {
2814 $out .= img_picto($langs->trans("Search"), 'search');
2815 }
2816 }
2817
2818 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2819 if ($hidelabel == 3) {
2820 $out .= img_picto($langs->trans("Search"), 'search');
2821 }
2822 } else {
2823 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2824 }
2825
2826 if (empty($nooutput)) {
2827 print $out;
2828 } else {
2829 return $out;
2830 }
2831 }
2832
2833 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2834
2850 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2851 {
2852 // phpcs:enable
2853 global $db;
2854
2855 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2856
2857 $error = 0;
2858 $out = '';
2859
2860 if (!$forcecombo) {
2861 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2862 $events = array();
2863 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2864 }
2865
2866 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2867
2868 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2869 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2870 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2871 if (!empty($status)) {
2872 $sql .= ' AND status = ' . (int) $status;
2873 }
2874 if (!empty($type)) {
2875 $sql .= ' AND bomtype = ' . (int) $type;
2876 }
2877 if (!empty($TProducts)) {
2878 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2879 }
2880 if (!empty($limit)) {
2881 $sql .= ' LIMIT ' . (int) $limit;
2882 }
2883 $resql = $db->query($sql);
2884 if ($resql) {
2885 if ($showempty) {
2886 $out .= '<option value="-1"';
2887 if (empty($selected)) {
2888 $out .= ' selected';
2889 }
2890 $out .= '>&nbsp;</option>';
2891 }
2892 while ($obj = $db->fetch_object($resql)) {
2893 $product = new Product($db);
2894 $res = $product->fetch($obj->fk_product);
2895 $out .= '<option value="' . $obj->rowid . '"';
2896 if ($obj->rowid == $selected) {
2897 $out .= 'selected';
2898 }
2899 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2900 }
2901 } else {
2902 $error++;
2903 dol_print_error($db);
2904 }
2905 $out .= '</select>';
2906 if (empty($nooutput)) {
2907 print $out;
2908 } else {
2909 return $out;
2910 }
2911 }
2912
2913 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2914
2941 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)
2942 {
2943 // phpcs:enable
2944 global $langs;
2945 global $hookmanager;
2946
2947 $out = '';
2948 $outarray = array();
2949
2950 // Units
2951 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2952 $langs->load('other');
2953 }
2954
2955 $warehouseStatusArray = array();
2956 if (!empty($warehouseStatus)) {
2957 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2958 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2959 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2960 }
2961 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2962 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2963 }
2964 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2965 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2966 }
2967 }
2968
2969 $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";
2970 if (count($warehouseStatusArray)) {
2971 $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
2972 } else {
2973 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2974 }
2975
2976 $sql = "SELECT ";
2977
2978 // Add select from hooks
2979 $parameters = array();
2980 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2981 if (empty($reshook)) {
2982 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2983 } else {
2984 $sql .= $hookmanager->resPrint;
2985 }
2986
2987 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2988 //Product category
2989 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2990 FROM " . $this->db->prefix() . "categorie_product
2991 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2992 LIMIT 1
2993 ) AS categorie_product_id ";
2994 }
2995
2996 //Price by customer
2997 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
2998 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2999 $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';
3000 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
3001 }
3002 // Units
3003 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3004 $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";
3005 $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';
3006 }
3007
3008 // Multilang : we add translation
3009 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3010 $sql .= ", pl.label as label_translated";
3011 $sql .= ", pl.description as description_translated";
3012 $selectFields .= ", label_translated";
3013 $selectFields .= ", description_translated";
3014 }
3015 // Price by quantity
3016 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3017 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
3018 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3019 $sql .= " AND price_level = " . ((int) $price_level);
3020 }
3021 $sql .= " ORDER BY date_price";
3022 $sql .= " DESC LIMIT 1) as price_rowid";
3023 $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
3024 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3025 $sql .= " AND price_level = " . ((int) $price_level);
3026 }
3027 $sql .= " ORDER BY date_price";
3028 $sql .= " DESC LIMIT 1) as price_by_qty";
3029 $selectFields .= ", price_rowid, price_by_qty";
3030 }
3031
3032 $sql .= " FROM ".$this->db->prefix()."product as p";
3033
3034 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
3035 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
3036 }
3037
3038 // Add from (left join) from hooks
3039 $parameters = array();
3040 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3041 $sql .= $hookmanager->resPrint;
3042
3043 if (count($warehouseStatusArray)) {
3044 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
3045 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3046 $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.
3047 }
3048
3049 //Price by customer
3050 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3051 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
3052 }
3053 // Units
3054 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3055 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3056 }
3057 // Multilang : we add translation
3058 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3059 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3060 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3061 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3062 $soc = new Societe($this->db);
3063 $result = $soc->fetch($socid);
3064 if ($result > 0 && !empty($soc->default_lang)) {
3065 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3066 } else {
3067 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3068 }
3069 } else {
3070 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3071 }
3072 }
3073
3074 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3075 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3076 }
3077
3078 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3079
3080 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3081 $sql .= " AND pac.rowid IS NULL";
3082 }
3083
3084 if ($finished == 0) {
3085 $sql .= " AND p.finished = " . ((int) $finished);
3086 } elseif ($finished == 1) {
3087 $sql .= " AND p.finished = ".((int) $finished);
3088 }
3089 if ($status >= 0) {
3090 $sql .= " AND p.tosell = ".((int) $status);
3091 }
3092 if ($status_purchase >= 0) {
3093 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3094 }
3095 // Filter by product type
3096 if (strval($filtertype) != '') {
3097 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3098 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3099 $sql .= " AND p.fk_product_type = 1";
3100 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3101 $sql .= " AND p.fk_product_type = 0";
3102 }
3103
3104 if ((int) $warehouseId > 0) {
3105 $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)";
3106 }
3107
3108 // Add where from hooks
3109 $parameters = array();
3110 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3111 $sql .= $hookmanager->resPrint;
3112 // Add criteria on ref/label
3113 if ($filterkey != '') {
3114 $sqlSupplierSearch= '';
3115
3116 $sql .= ' AND (';
3117 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3118 // For natural search
3119 $search_crit = explode(' ', $filterkey);
3120 $i = 0;
3121 if (count($search_crit) > 1) {
3122 $sql .= "(";
3123 }
3124 foreach ($search_crit as $crit) {
3125 if ($i > 0) {
3126 $sql .= " AND ";
3127 }
3128 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3129 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3130 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3131 }
3132 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3133 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3134 }
3135 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3136 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3137 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3138 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3139 }
3140 }
3141
3142 // include search in supplier ref
3143 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3144 $sqlSupplierSearch .= !empty($sqlSupplierSearch) ? ' AND ':'';
3145 $sqlSupplierSearch .= " pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3146 }
3147 $sql .= ")";
3148 $i++;
3149 }
3150 if (count($search_crit) > 1) {
3151 $sql .= ")";
3152 }
3153 if (isModEnabled('barcode')) {
3154 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3155 }
3156
3157 // include search in supplier ref
3158 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3159 $sql .= " OR EXISTS (SELECT pfp.fk_product FROM " . $this->db->prefix() . "product_fournisseur_price as pfp WHERE p.rowid = pfp.fk_product";
3160 $sql .= " AND (";
3161 $sql .= $sqlSupplierSearch;
3162 $sql .= "))";
3163 }
3164
3165 $sql .= ')';
3166 }
3167 if (count($warehouseStatusArray)) {
3168 $sql .= " GROUP BY " . $selectFields;
3169 }
3170
3171 //Sort by category
3172 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3173 $sql .= " ORDER BY categorie_product_id ";
3174 //ASC OR DESC order
3175 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3176 } else {
3177 $sql .= $this->db->order("p.ref");
3178 }
3179
3180 $sql .= $this->db->plimit($limit, 0);
3181
3182 // Build output string
3183 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3184 $result = $this->db->query($sql);
3185 if ($result) {
3186 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3187 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3188 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3189
3190 $num = $this->db->num_rows($result);
3191
3192 $events = array();
3193
3194 if (!$forcecombo) {
3195 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3196 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3197 }
3198
3199 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3200
3201 $textifempty = '';
3202 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3203 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3204 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3205 if ($showempty && !is_numeric($showempty)) {
3206 $textifempty = $langs->trans($showempty);
3207 } else {
3208 $textifempty .= $langs->trans("All");
3209 }
3210 } else {
3211 if ($showempty && !is_numeric($showempty)) {
3212 $textifempty = $langs->trans($showempty);
3213 }
3214 }
3215 if ($showempty) {
3216 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3217 }
3218
3219 $i = 0;
3220 while ($num && $i < $num) {
3221 $opt = '';
3222 $optJson = array();
3223 $objp = $this->db->fetch_object($result);
3224
3225 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
3226 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3227 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3228 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3229 $sql .= " ORDER BY quantity ASC";
3230
3231 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3232 $result2 = $this->db->query($sql);
3233 if ($result2) {
3234 $nb_prices = $this->db->num_rows($result2);
3235 $j = 0;
3236 while ($nb_prices && $j < $nb_prices) {
3237 $objp2 = $this->db->fetch_object($result2);
3238
3239 $objp->price_by_qty_rowid = $objp2->rowid;
3240 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3241 $objp->price_by_qty_quantity = $objp2->quantity;
3242 $objp->price_by_qty_unitprice = $objp2->unitprice;
3243 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3244 // For backward compatibility
3245 $objp->quantity = $objp2->quantity;
3246 $objp->price = $objp2->price;
3247 $objp->unitprice = $objp2->unitprice;
3248 $objp->remise_percent = $objp2->remise_percent;
3249
3250 //$objp->tva_tx is not overwritten by $objp2 value
3251 //$objp->default_vat_code is not overwritten by $objp2 value
3252
3253 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3254 '@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';
3255 $j++;
3256
3257 // Add new entry
3258 // "key" value of json key array is used by jQuery automatically as selected value
3259 // "label" value of json key array is used by jQuery automatically as text for combo box
3260 $out .= $opt;
3261 array_push($outarray, $optJson);
3262 }
3263 }
3264 } else {
3265 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3266 $price_product = new Product($this->db);
3267 $price_product->fetch($objp->rowid, '', '', 1);
3268
3269 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3270 $priceparser = new PriceParser($this->db);
3271 $price_result = $priceparser->parseProduct($price_product);
3272 if ($price_result >= 0) {
3273 $objp->price = $price_result;
3274 $objp->unitprice = $price_result;
3275 //Calculate the VAT
3276 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3277 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3278 }
3279 }
3280 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3281 $price_level = '';
3282 }
3283 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3284 // Add new entry
3285 // "key" value of json key array is used by jQuery automatically as selected value
3286 // "label" value of json key array is used by jQuery automatically as text for combo box
3287 $out .= $opt;
3288 array_push($outarray, $optJson);
3289 }
3290
3291 $i++;
3292 }
3293
3294 $out .= '</select>';
3295
3296 $this->db->free($result);
3297
3298 if (empty($outputmode)) {
3299 return $out;
3300 }
3301
3302 return $outarray;
3303 } else {
3304 dol_print_error($this->db);
3305 }
3306
3307 return '';
3308 }
3309
3325 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3326 {
3327 global $langs, $conf, $user;
3328 global $hookmanager;
3329
3330 $outkey = '';
3331 $outval = '';
3332 $outref = '';
3333 $outlabel = '';
3334 $outlabel_translated = '';
3335 $outdesc = '';
3336 $outdesc_translated = '';
3337 $outbarcode = '';
3338 $outorigin = '';
3339 $outtype = '';
3340 $outprice_ht = '';
3341 $outprice_ttc = '';
3342 $outpricebasetype = '';
3343 $outtva_tx = '';
3344 $outdefault_vat_code = '';
3345 $outqty = 1;
3346 $outdiscount = 0;
3347
3348 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3349
3350 $label = $objp->label;
3351 if (!empty($objp->label_translated)) {
3352 $label = $objp->label_translated;
3353 }
3354 if (!empty($filterkey) && $filterkey != '') {
3355 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3356 }
3357
3358 $outkey = $objp->rowid;
3359 $outref = $objp->ref;
3360 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3361 $outlabel = $objp->label;
3362 $outdesc = $objp->description;
3363 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3364 $outlabel_translated = $objp->label_translated;
3365 $outdesc_translated = $objp->description_translated;
3366 }
3367 $outbarcode = $objp->barcode;
3368 $outorigin = $objp->fk_country;
3369 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3370
3371 $outtype = $objp->fk_product_type;
3372 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3373 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3374
3375 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3376 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3377 }
3378
3379 // Units
3380 $outvalUnits = '';
3381 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3382 if (!empty($objp->unit_short)) {
3383 $outvalUnits .= ' - ' . $objp->unit_short;
3384 }
3385 }
3386 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3387 if (!empty($objp->weight) && $objp->weight_units !== null) {
3388 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3389 $outvalUnits .= ' - ' . $unitToShow;
3390 }
3391 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3392 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3393 $outvalUnits .= ' - ' . $unitToShow;
3394 }
3395 if (!empty($objp->surface) && $objp->surface_units !== null) {
3396 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3397 $outvalUnits .= ' - ' . $unitToShow;
3398 }
3399 if (!empty($objp->volume) && $objp->volume_units !== null) {
3400 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3401 $outvalUnits .= ' - ' . $unitToShow;
3402 }
3403 }
3404 if ($outdurationvalue && $outdurationunit) {
3405 $da = array(
3406 'h' => $langs->trans('Hour'),
3407 'd' => $langs->trans('Day'),
3408 'w' => $langs->trans('Week'),
3409 'm' => $langs->trans('Month'),
3410 'y' => $langs->trans('Year')
3411 );
3412 if (isset($da[$outdurationunit])) {
3413 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3414 }
3415 }
3416
3417 // Set stocktag (stock too low or not or unknown)
3418 $stocktag = 0;
3419 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3420 if ($user->hasRight('stock', 'lire')) {
3421 if ($objp->stock > 0) {
3422 $stocktag = 1;
3423 } elseif ($objp->stock <= 0) {
3424 $stocktag = -1;
3425 }
3426 }
3427 }
3428
3429 // Set $labeltoshow
3430 $labeltoshow = '';
3431 $labeltoshow .= $objp->ref;
3432 if (!empty($objp->custref)) {
3433 $labeltoshow .= ' (' . $objp->custref . ')';
3434 }
3435 if ($outbarcode) {
3436 $labeltoshow .= ' (' . $outbarcode . ')';
3437 }
3438 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3439 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3440 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3441 }
3442
3443 // Set $labltoshowhtml
3444 $labeltoshowhtml = '';
3445 $labeltoshowhtml .= $objp->ref;
3446 if (!empty($objp->custref)) {
3447 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3448 }
3449 if (!empty($filterkey) && $filterkey != '') {
3450 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3451 }
3452 if ($outbarcode) {
3453 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3454 }
3455 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3456 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3457 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3458 }
3459
3460 // Stock
3461 $labeltoshowstock = '';
3462 $labeltoshowhtmlstock = '';
3463 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3464 if ($user->hasRight('stock', 'lire')) {
3465 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3466
3467 if ($objp->stock > 0) {
3468 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3469 } elseif ($objp->stock <= 0) {
3470 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3471 }
3472 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3473 $labeltoshowhtmlstock .= '</span>';
3474
3475 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3476 $langs->load("stocks");
3477
3478 $tmpproduct = new Product($this->db);
3479 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3480 $tmpproduct->load_virtual_stock();
3481 $virtualstock = $tmpproduct->stock_theorique;
3482
3483 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3484
3485 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3486 if ($virtualstock > 0) {
3487 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3488 } elseif ($virtualstock <= 0) {
3489 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3490 }
3491 $labeltoshowhtmlstock .= $virtualstock;
3492 $labeltoshowhtmlstock .= '</span>';
3493
3494 unset($tmpproduct);
3495 }
3496 }
3497 }
3498
3499 // Price
3500 $found = 0;
3501 $labeltoshowprice = '';
3502 $labeltoshowhtmlprice = '';
3503 // If we need a particular price level (from 1 to n)
3504 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3505 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3506 $sql .= " FROM " . $this->db->prefix() . "product_price";
3507 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3508 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3509 $sql .= " AND price_level = " . ((int) $price_level);
3510 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3511 $sql .= " LIMIT 1";
3512
3513 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3514 $result2 = $this->db->query($sql);
3515 if ($result2) {
3516 $objp2 = $this->db->fetch_object($result2);
3517 if ($objp2) {
3518 $found = 1;
3519 if ($objp2->price_base_type == 'HT') {
3520 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3521 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3522 } else {
3523 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3524 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3525 }
3526 $outprice_ht = price($objp2->price);
3527 $outprice_ttc = price($objp2->price_ttc);
3528 $outpricebasetype = $objp2->price_base_type;
3529 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3530 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3531 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3532 } else {
3533 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3534 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3535 }
3536 }
3537 } else {
3538 dol_print_error($this->db);
3539 }
3540 }
3541
3542 // Price by quantity
3543 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3544 $found = 1;
3545 $outqty = $objp->quantity;
3546 $outdiscount = $objp->remise_percent;
3547 if ($objp->quantity == 1) {
3548 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3549 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3550 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3551 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3552 } else {
3553 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3554 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3555 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3556 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3557 }
3558
3559 $outprice_ht = price($objp->unitprice);
3560 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3561 $outpricebasetype = $objp->price_base_type;
3562 $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
3563 $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
3564 }
3565 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3566 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3567 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3568 }
3569 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3570 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3571 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3572 }
3573
3574 // Price by customer
3575 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3576 if (!empty($objp->idprodcustprice)) {
3577 $found = 1;
3578
3579 if ($objp->custprice_base_type == 'HT') {
3580 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3581 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3582 } else {
3583 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3584 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3585 }
3586
3587 $outprice_ht = price($objp->custprice);
3588 $outprice_ttc = price($objp->custprice_ttc);
3589 $outpricebasetype = $objp->custprice_base_type;
3590 $outtva_tx = $objp->custtva_tx;
3591 $outdefault_vat_code = $objp->custdefault_vat_code;
3592 }
3593 }
3594
3595 // If level no defined or multiprice not found, we used the default price
3596 if (empty($hidepriceinlabel) && !$found) {
3597 if ($objp->price_base_type == 'HT') {
3598 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3599 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3600 } else {
3601 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3602 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3603 }
3604 $outprice_ht = price($objp->price);
3605 $outprice_ttc = price($objp->price_ttc);
3606 $outpricebasetype = $objp->price_base_type;
3607 $outtva_tx = $objp->tva_tx;
3608 $outdefault_vat_code = $objp->default_vat_code;
3609 }
3610
3611 // Build options
3612 $opt = '<option value="' . $objp->rowid . '"';
3613 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3614 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3615 $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 . '"';
3616 }
3617 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3618 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3619 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3620 }
3621
3622 if ($stocktag == 1) {
3623 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3624 //$opt .= ' class="product_line_stock_ok"';
3625 }
3626 if ($stocktag == -1) {
3627 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3628 //$opt .= ' class="product_line_stock_too_low"';
3629 }
3630
3631 $opt .= '>';
3632
3633 // Ref, barcode, country
3634 $opt .= $labeltoshow;
3635 $outval .= $labeltoshowhtml;
3636
3637 // Units
3638 $opt .= $outvalUnits;
3639 $outval .= $outvalUnits;
3640
3641 // Price
3642 $opt .= $labeltoshowprice;
3643 $outval .= $labeltoshowhtmlprice;
3644
3645 // Stock
3646 $opt .= $labeltoshowstock;
3647 $outval .= $labeltoshowhtmlstock;
3648
3649
3650 $parameters = array('objp' => $objp);
3651 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3652 if (empty($reshook)) {
3653 $opt .= $hookmanager->resPrint;
3654 } else {
3655 $opt = $hookmanager->resPrint;
3656 }
3657
3658 $opt .= "</option>\n";
3659 $optJson = array(
3660 'key' => $outkey,
3661 'value' => $outref,
3662 'label' => $outval,
3663 'label2' => $outlabel,
3664 'desc' => $outdesc,
3665 'type' => $outtype,
3666 'price_ht' => price2num($outprice_ht),
3667 'price_ttc' => price2num($outprice_ttc),
3668 'price_ht_locale' => price(price2num($outprice_ht)),
3669 'price_ttc_locale' => price(price2num($outprice_ttc)),
3670 'pricebasetype' => $outpricebasetype,
3671 'tva_tx' => $outtva_tx,
3672 'default_vat_code' => $outdefault_vat_code,
3673 'qty' => $outqty,
3674 'discount' => $outdiscount,
3675 'duration_value' => $outdurationvalue,
3676 'duration_unit' => $outdurationunit,
3677 'pbq' => $outpbq,
3678 'labeltrans' => $outlabel_translated,
3679 'desctrans' => $outdesc_translated,
3680 'ref_customer' => $outrefcust
3681 );
3682 }
3683
3684 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3685
3701 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3702 {
3703 // phpcs:enable
3704 global $langs, $conf;
3705 global $price_level, $status, $finished;
3706
3707 if (!isset($status)) {
3708 $status = 1;
3709 }
3710
3711 $selected_input_value = '';
3712 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3713 if ($selected > 0) {
3714 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3715 $producttmpselect = new Product($this->db);
3716 $producttmpselect->fetch($selected);
3717 $selected_input_value = $producttmpselect->ref;
3718 unset($producttmpselect);
3719 }
3720
3721 // mode=2 means suppliers products
3722 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3723 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3724
3725 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3726 } else {
3727 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3728 }
3729 }
3730
3731 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3732
3751 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 = '')
3752 {
3753 // phpcs:enable
3754 global $langs, $conf, $user;
3755 global $hookmanager;
3756
3757 $out = '';
3758 $outarray = array();
3759
3760 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3761
3762 $langs->load('stocks');
3763 // Units
3764 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3765 $langs->load('other');
3766 }
3767
3768 $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,";
3769 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3770 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3771 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3772 $sql .= ", pfp.supplier_reputation";
3773 // if we use supplier description of the products
3774 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3775 $sql .= ", pfp.desc_fourn as description";
3776 } else {
3777 $sql .= ", p.description";
3778 }
3779 // Units
3780 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3781 $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";
3782 }
3783 $sql .= " FROM " . $this->db->prefix() . "product as p";
3784 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3785 if ($socid > 0) {
3786 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3787 }
3788 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3789 // Units
3790 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3791 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3792 }
3793 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3794 if ($statut != -1) {
3795 $sql .= " AND p.tobuy = " . ((int) $statut);
3796 }
3797 if (strval($filtertype) != '') {
3798 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3799 }
3800 if (!empty($filtre)) {
3801 $sql .= " " . $filtre;
3802 }
3803 // Add where from hooks
3804 $parameters = array();
3805 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3806 $sql .= $hookmanager->resPrint;
3807 // Add criteria on ref/label
3808 if ($filterkey != '') {
3809 $sql .= ' AND (';
3810 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3811 // For natural search
3812 $search_crit = explode(' ', $filterkey);
3813 $i = 0;
3814 if (count($search_crit) > 1) {
3815 $sql .= "(";
3816 }
3817 foreach ($search_crit as $crit) {
3818 if ($i > 0) {
3819 $sql .= " AND ";
3820 }
3821 $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) . "%'";
3822 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3823 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3824 }
3825 $sql .= ")";
3826 $i++;
3827 }
3828 if (count($search_crit) > 1) {
3829 $sql .= ")";
3830 }
3831 if (isModEnabled('barcode')) {
3832 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3833 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3834 }
3835 $sql .= ')';
3836 }
3837 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3838 $sql .= $this->db->plimit($limit, 0);
3839
3840 // Build output string
3841
3842 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3843 $result = $this->db->query($sql);
3844 if ($result) {
3845 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3846 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3847
3848 $num = $this->db->num_rows($result);
3849
3850 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3851 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3852 if (!$selected) {
3853 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3854 } else {
3855 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3856 }
3857
3858 $i = 0;
3859 while ($i < $num) {
3860 $objp = $this->db->fetch_object($result);
3861
3862 if (is_null($objp->idprodfournprice)) {
3863 // There is no supplier price found, we will use the vat rate for sale
3864 $objp->tva_tx = $objp->tva_tx_sale;
3865 $objp->default_vat_code = $objp->default_vat_code_sale;
3866 }
3867
3868 $outkey = $objp->idprodfournprice; // id in table of price
3869 if (!$outkey && $alsoproductwithnosupplierprice) {
3870 $outkey = 'idprod_' . $objp->rowid; // id of product
3871 }
3872
3873 $outref = $objp->ref;
3874 $outbarcode = $objp->barcode;
3875 $outqty = 1;
3876 $outdiscount = 0;
3877 $outtype = $objp->fk_product_type;
3878 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3879 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3880
3881 // Units
3882 $outvalUnits = '';
3883 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3884 if (!empty($objp->unit_short)) {
3885 $outvalUnits .= ' - ' . $objp->unit_short;
3886 }
3887 if (!empty($objp->weight) && $objp->weight_units !== null) {
3888 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3889 $outvalUnits .= ' - ' . $unitToShow;
3890 }
3891 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3892 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3893 $outvalUnits .= ' - ' . $unitToShow;
3894 }
3895 if (!empty($objp->surface) && $objp->surface_units !== null) {
3896 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3897 $outvalUnits .= ' - ' . $unitToShow;
3898 }
3899 if (!empty($objp->volume) && $objp->volume_units !== null) {
3900 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3901 $outvalUnits .= ' - ' . $unitToShow;
3902 }
3903 if ($outdurationvalue && $outdurationunit) {
3904 $da = array(
3905 'h' => $langs->trans('Hour'),
3906 'd' => $langs->trans('Day'),
3907 'w' => $langs->trans('Week'),
3908 'm' => $langs->trans('Month'),
3909 'y' => $langs->trans('Year')
3910 );
3911 if (isset($da[$outdurationunit])) {
3912 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3913 }
3914 }
3915 }
3916
3917 $objRef = $objp->ref;
3918 if ($filterkey && $filterkey != '') {
3919 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3920 }
3921 $objRefFourn = $objp->ref_fourn;
3922 if ($filterkey && $filterkey != '') {
3923 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3924 }
3925 $label = $objp->label;
3926 if ($filterkey && $filterkey != '') {
3927 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3928 }
3929
3930 switch ($objp->fk_product_type) {
3932 $picto = 'product';
3933 break;
3935 $picto = 'service';
3936 break;
3937 default:
3938 $picto = '';
3939 break;
3940 }
3941
3942 if (empty($picto)) {
3943 $optlabel = '';
3944 } else {
3945 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3946 }
3947
3948 $optlabel .= $objp->ref;
3949 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3950 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3951 }
3952 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3953 $optlabel .= ' (' . $outbarcode . ')';
3954 }
3955 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3956
3957 $outvallabel = $objRef;
3958 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3959 $outvallabel .= ' (' . $objRefFourn . ')';
3960 }
3961 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3962 $outvallabel .= ' (' . $outbarcode . ')';
3963 }
3964 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3965
3966 // Units
3967 $optlabel .= $outvalUnits;
3968 $outvallabel .= $outvalUnits;
3969
3970 if (!empty($objp->idprodfournprice)) {
3971 $outqty = $objp->quantity;
3972 $outdiscount = $objp->remise_percent;
3973 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3974 $prod_supplier = new ProductFournisseur($this->db);
3975 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3976 $prod_supplier->id = $objp->fk_product;
3977 $prod_supplier->fourn_qty = $objp->quantity;
3978 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3979 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3980
3981 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3982 $priceparser = new PriceParser($this->db);
3983 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3984 if ($price_result >= 0) {
3985 $objp->fprice = $price_result;
3986 if ($objp->quantity >= 1) {
3987 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3988 }
3989 }
3990 }
3991 if ($objp->quantity == 1) {
3992 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3993 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3994 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3995 $outvallabel .= $langs->transnoentities("Unit");
3996 } else {
3997 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3998 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3999 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
4000 $outvallabel .= ' ' . $langs->transnoentities("Units");
4001 }
4002
4003 if ($objp->quantity > 1) {
4004 $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
4005 $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
4006 }
4007 if ($objp->remise_percent >= 1) {
4008 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4009 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4010 }
4011 if ($objp->duration) {
4012 $optlabel .= " - " . $objp->duration;
4013 $outvallabel .= " - " . $objp->duration;
4014 }
4015 if (!$socid) {
4016 $optlabel .= " - " . dol_trunc($objp->name, 8);
4017 $outvallabel .= " - " . dol_trunc($objp->name, 8);
4018 }
4019 if ($objp->supplier_reputation) {
4020 //TODO dictionary
4021 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
4022
4023 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
4024 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
4025 }
4026 } else {
4027 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
4028 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
4029 }
4030
4031 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
4032 $novirtualstock = ($showstockinlist == 2);
4033
4034 if ($user->hasRight('stock', 'lire')) {
4035 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
4036
4037 if ($objp->stock > 0) {
4038 $optlabel .= ' - <span class="product_line_stock_ok">';
4039 } elseif ($objp->stock <= 0) {
4040 $optlabel .= ' - <span class="product_line_stock_too_low">';
4041 }
4042 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
4043 $optlabel .= '</span>';
4044 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
4045 $langs->load("stocks");
4046
4047 $tmpproduct = new Product($this->db);
4048 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
4049 $tmpproduct->load_virtual_stock();
4050 $virtualstock = $tmpproduct->stock_theorique;
4051
4052 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4053
4054 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4055 if ($virtualstock > 0) {
4056 $optlabel .= '<span class="product_line_stock_ok">';
4057 } elseif ($virtualstock <= 0) {
4058 $optlabel .= '<span class="product_line_stock_too_low">';
4059 }
4060 $optlabel .= $virtualstock;
4061 $optlabel .= '</span>';
4062
4063 unset($tmpproduct);
4064 }
4065 }
4066 }
4067
4068 $optstart = '<option value="' . $outkey . '"';
4069 if ($selected && $selected == $objp->idprodfournprice) {
4070 $optstart .= ' selected';
4071 }
4072 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4073 $optstart .= ' disabled';
4074 }
4075
4076 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4077 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4078 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4079 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4080 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"'; // the price with numeric international format
4081 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"'; // the price formatted in user language
4082 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
4083 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"'; // the rate with numeric international format
4084 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"'; // the rate formatted in user language
4085 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4086 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4087 if (isModEnabled('multicurrency')) {
4088 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4089 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag(price2num($objp->multicurrency_unitprice)) . '"'; // the price with numeric international format
4090 }
4091 }
4092 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4093
4094 // set $parameters to call hook
4095 $outarrayentry = array(
4096 'key' => $outkey,
4097 'value' => $outref,
4098 'label' => $outvallabel,
4099 'labelhtml' => $optlabel,
4100 'qty' => $outqty,
4101 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4102 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4103 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4104 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4105 'tva_tx' => price2num($objp->tva_tx),
4106 'default_vat_code' => $objp->default_vat_code,
4107 'supplier_ref' => $objp->ref_fourn,
4108 'discount' => $outdiscount,
4109 'type' => $outtype,
4110 'duration_value' => $outdurationvalue,
4111 'duration_unit' => $outdurationunit,
4112 'disabled' => empty($objp->idprodfournprice),
4113 'description' => $objp->description
4114 );
4115 if (isModEnabled('multicurrency')) {
4116 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4117 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4118 }
4119 $parameters = array(
4120 'objp' => &$objp,
4121 'optstart' => &$optstart,
4122 'optlabel' => &$optlabel,
4123 'outvallabel' => &$outvallabel,
4124 'outarrayentry' => &$outarrayentry,
4125 'fk_soc' => $socid
4126 );
4127 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4128
4129
4130 // Add new entry
4131 // "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
4132 // "label" value of json key array is used by jQuery automatically as text for combo box
4133 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4134 $outarraypush = array(
4135 'key' => $outkey,
4136 'value' => $outref,
4137 'label' => $outvallabel,
4138 'labelhtml' => $optlabel,
4139 'qty' => $outqty,
4140 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4141 'price_qty_ht_locale' => price($objp->fprice),
4142 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4143 'price_unit_ht_locale' => price($objp->unitprice),
4144 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4145 'tva_tx_formated' => price($objp->tva_tx),
4146 'tva_tx' => price2num($objp->tva_tx),
4147 'default_vat_code' => $objp->default_vat_code,
4148 'supplier_ref' => $objp->ref_fourn,
4149 'discount' => $outdiscount,
4150 'type' => $outtype,
4151 'duration_value' => $outdurationvalue,
4152 'duration_unit' => $outdurationunit,
4153 'disabled' => empty($objp->idprodfournprice),
4154 'description' => $objp->description
4155 );
4156 if (isModEnabled('multicurrency')) {
4157 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4158 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4159 }
4160 array_push($outarray, $outarraypush);
4161
4162 // Example of var_dump $outarray
4163 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4164 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4165 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4166 //}
4167 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4168 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4169 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4170
4171 $i++;
4172 }
4173 $out .= '</select>';
4174
4175 $this->db->free($result);
4176
4177 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4178 $out .= ajax_combobox($htmlname);
4179 } else {
4180 dol_print_error($this->db);
4181 }
4182
4183 if (empty($outputmode)) {
4184 return $out;
4185 }
4186 return $outarray;
4187 }
4188
4189 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4190
4199 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4200 {
4201 // phpcs:enable
4202 global $langs, $conf;
4203
4204 $langs->load('stocks');
4205
4206 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4207 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4208 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4209 $sql .= " FROM " . $this->db->prefix() . "product as p";
4210 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4211 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4212 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4213 $sql .= " AND p.tobuy = 1";
4214 $sql .= " AND s.fournisseur = 1";
4215 $sql .= " AND p.rowid = " . ((int) $productid);
4216 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4217 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4218 } else {
4219 $sql .= " ORDER BY pfp.unitprice ASC";
4220 }
4221
4222 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4223 $result = $this->db->query($sql);
4224
4225 if ($result) {
4226 $num = $this->db->num_rows($result);
4227
4228 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4229
4230 if (!$num) {
4231 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4232 } else {
4233 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4234 $form .= '<option value="0">&nbsp;</option>';
4235
4236 $i = 0;
4237 while ($i < $num) {
4238 $objp = $this->db->fetch_object($result);
4239
4240 $opt = '<option value="' . $objp->idprodfournprice . '"';
4241 //if there is only one supplier, preselect it
4242 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4243 $opt .= ' selected';
4244 }
4245 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4246
4247 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4248 $prod_supplier = new ProductFournisseur($this->db);
4249 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4250 $prod_supplier->id = $productid;
4251 $prod_supplier->fourn_qty = $objp->quantity;
4252 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4253 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4254
4255 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4256 $priceparser = new PriceParser($this->db);
4257 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4258 if ($price_result >= 0) {
4259 $objp->fprice = $price_result;
4260 if ($objp->quantity >= 1) {
4261 $objp->unitprice = $objp->fprice / $objp->quantity;
4262 }
4263 }
4264 }
4265 if ($objp->quantity == 1) {
4266 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4267 }
4268
4269 $opt .= $objp->quantity . ' ';
4270
4271 if ($objp->quantity == 1) {
4272 $opt .= $langs->trans("Unit");
4273 } else {
4274 $opt .= $langs->trans("Units");
4275 }
4276 if ($objp->quantity > 1) {
4277 $opt .= " - ";
4278 $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");
4279 }
4280 if ($objp->duration) {
4281 $opt .= " - " . $objp->duration;
4282 }
4283 $opt .= "</option>\n";
4284
4285 $form .= $opt;
4286 $i++;
4287 }
4288 }
4289
4290 $form .= '</select>';
4291 $this->db->free($result);
4292 return $form;
4293 } else {
4294 dol_print_error($this->db);
4295 return '';
4296 }
4297 }
4298
4299
4300 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4307 {
4308 // phpcs:enable
4309 global $langs;
4310
4311 $num = count($this->cache_conditions_paiements);
4312 if ($num > 0) {
4313 return 0; // Cache already loaded
4314 }
4315
4316 dol_syslog(__METHOD__, LOG_DEBUG);
4317
4318 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4319 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4320 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4321 $sql .= " AND active > 0";
4322 $sql .= " ORDER BY sortorder";
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("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4333 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4334 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4335 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4336 $i++;
4337 }
4338
4339 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4340
4341 return $num;
4342 } else {
4343 dol_print_error($this->db);
4344 return -1;
4345 }
4346 }
4347
4348 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4349
4355 public function load_cache_availability()
4356 {
4357 // phpcs:enable
4358 global $langs;
4359
4360 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4361 if ($num > 0) {
4362 return 0; // Cache already loaded
4363 }
4364
4365 dol_syslog(__METHOD__, LOG_DEBUG);
4366
4367 $langs->load('propal');
4368
4369 $sql = "SELECT rowid, code, label, position";
4370 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4371 $sql .= " WHERE active > 0";
4372
4373 $resql = $this->db->query($sql);
4374 if ($resql) {
4375 $num = $this->db->num_rows($resql);
4376 $i = 0;
4377 while ($i < $num) {
4378 $obj = $this->db->fetch_object($resql);
4379
4380 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4381 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4382 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4383 $this->cache_availability[$obj->rowid]['label'] = $label;
4384 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4385 $i++;
4386 }
4387
4388 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4389
4390 return $num;
4391 } else {
4392 dol_print_error($this->db);
4393 return -1;
4394 }
4395 }
4396
4407 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4408 {
4409 global $langs, $user;
4410
4411 $this->load_cache_availability();
4412
4413 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4414
4415 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4416 if ($addempty) {
4417 print '<option value="0">&nbsp;</option>';
4418 }
4419 foreach ($this->cache_availability as $id => $arrayavailability) {
4420 if ($selected == $id) {
4421 print '<option value="' . $id . '" selected>';
4422 } else {
4423 print '<option value="' . $id . '">';
4424 }
4425 print dol_escape_htmltag($arrayavailability['label']);
4426 print '</option>';
4427 }
4428 print '</select>';
4429 if ($user->admin) {
4430 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4431 }
4432 print ajax_combobox($htmlname);
4433 }
4434
4440 public function loadCacheInputReason()
4441 {
4442 global $langs;
4443
4444 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4445 if ($num > 0) {
4446 return 0; // Cache already loaded
4447 }
4448
4449 $sql = "SELECT rowid, code, label";
4450 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4451 $sql .= " WHERE active > 0";
4452
4453 $resql = $this->db->query($sql);
4454 if ($resql) {
4455 $num = $this->db->num_rows($resql);
4456 $i = 0;
4457 $tmparray = array();
4458 while ($i < $num) {
4459 $obj = $this->db->fetch_object($resql);
4460
4461 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4462 $label = ($obj->label != '-' ? $obj->label : '');
4463 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4464 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4465 }
4466 if ($langs->trans($obj->code) != $obj->code) {
4467 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4468 }
4469
4470 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4471 $tmparray[$obj->rowid]['code'] = $obj->code;
4472 $tmparray[$obj->rowid]['label'] = $label;
4473 $i++;
4474 }
4475
4476 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4477
4478 unset($tmparray);
4479 return $num;
4480 } else {
4481 dol_print_error($this->db);
4482 return -1;
4483 }
4484 }
4485
4498 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4499 {
4500 global $langs, $user;
4501
4502 $this->loadCacheInputReason();
4503
4504 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4505 if ($addempty) {
4506 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4507 }
4508 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4509 if ($arraydemandreason['code'] == $exclude) {
4510 continue;
4511 }
4512
4513 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4514 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4515 } else {
4516 print '<option value="' . $arraydemandreason['id'] . '">';
4517 }
4518 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4519 print $langs->trans($label);
4520 print '</option>';
4521 }
4522 print '</select>';
4523 if ($user->admin && empty($notooltip)) {
4524 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4525 }
4526 print ajax_combobox('select_' . $htmlname);
4527 }
4528
4529 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4530
4537 {
4538 // phpcs:enable
4539 global $langs;
4540
4541 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4542 if ($num > 0) {
4543 return $num; // Cache already loaded
4544 }
4545
4546 dol_syslog(__METHOD__, LOG_DEBUG);
4547
4548 $this->cache_types_paiements = array();
4549
4550 $sql = "SELECT id, code, libelle as label, type, active";
4551 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4552 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4553
4554 $resql = $this->db->query($sql);
4555 if ($resql) {
4556 $num = $this->db->num_rows($resql);
4557 $i = 0;
4558 while ($i < $num) {
4559 $obj = $this->db->fetch_object($resql);
4560
4561 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4562 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4563 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4564 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4565 $this->cache_types_paiements[$obj->id]['label'] = $label;
4566 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4567 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4568 $i++;
4569 }
4570
4571 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4572
4573 return $num;
4574 } else {
4575 dol_print_error($this->db);
4576 return -1;
4577 }
4578 }
4579
4580
4581 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4582
4601 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4602 {
4603 // phpcs:enable
4604 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4605 if (empty($noprint)) {
4606 print $out;
4607 } else {
4608 return $out;
4609 }
4610 }
4611
4612
4629 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4630 {
4631 global $langs, $user, $conf;
4632
4633 $out = '';
4634 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4635
4637
4638 // Set default value if not already set by caller
4639 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4640 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4641 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4642 }
4643
4644 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4645 if ($addempty) {
4646 $out .= '<option value="0">&nbsp;</option>';
4647 }
4648
4649 $selectedDepositPercent = null;
4650
4651 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4652 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4653 continue;
4654 }
4655
4656 if ($selected == $id) {
4657 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4658 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4659 } else {
4660 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4661 }
4662 $label = $arrayconditions['label'];
4663
4664 if (!empty($arrayconditions['deposit_percent'])) {
4665 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4666 }
4667
4668 $out .= $label;
4669 $out .= '</option>';
4670 }
4671 $out .= '</select>';
4672 if ($user->admin && empty($noinfoadmin)) {
4673 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4674 }
4675 $out .= ajax_combobox($htmlname);
4676
4677 if ($deposit_percent >= 0) {
4678 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4679 $out .= $langs->trans('DepositPercent') . ' : ';
4680 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4681 $out .= '</span>';
4682 $out .= '
4683 <script nonce="' . getNonce() . '">
4684 $(document).ready(function () {
4685 $("#' . $htmlname . '").change(function () {
4686 let $selected = $(this).find("option:selected");
4687 let depositPercent = $selected.attr("data-deposit_percent");
4688
4689 if (depositPercent.length > 0) {
4690 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4691 } else {
4692 $("#' . $htmlname . '_deposit_percent_container").hide();
4693 }
4694
4695 return true;
4696 });
4697 });
4698 </script>';
4699 }
4700
4701 return $out;
4702 }
4703
4704
4705 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4706
4723 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4724 {
4725 // phpcs:enable
4726 global $langs, $user, $conf;
4727
4728 $out = '';
4729
4730 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4731
4732 $filterarray = array();
4733 if ($filtertype == 'CRDT') {
4734 $filterarray = array(0, 2, 3);
4735 } elseif ($filtertype == 'DBIT') {
4736 $filterarray = array(1, 2, 3);
4737 } elseif ($filtertype != '' && $filtertype != '-1') {
4738 $filterarray = explode(',', $filtertype);
4739 }
4740
4742
4743 // Set default value if not already set by caller
4744 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4745 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4746 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4747 }
4748
4749 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4750 if ($empty) {
4751 $out .= '<option value="">&nbsp;</option>';
4752 }
4753 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4754 // If not good status
4755 if ($active >= 0 && $arraytypes['active'] != $active) {
4756 continue;
4757 }
4758
4759 // We skip of the user requested to filter on specific payment methods
4760 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4761 continue;
4762 }
4763
4764 // We discard empty lines if showempty is on because an empty line has already been output.
4765 if ($empty && empty($arraytypes['code'])) {
4766 continue;
4767 }
4768
4769 if ($format == 0) {
4770 $out .= '<option value="' . $id . '" data-code="'.$arraytypes['code'].'"';
4771 } elseif ($format == 1) {
4772 $out .= '<option value="' . $arraytypes['code'] . '"';
4773 } elseif ($format == 2) {
4774 $out .= '<option value="' . $arraytypes['code'] . '"';
4775 } elseif ($format == 3) {
4776 $out .= '<option value="' . $id . '"';
4777 }
4778 // Print attribute selected or not
4779 if ($format == 1 || $format == 2) {
4780 if ($selected == $arraytypes['code']) {
4781 $out .= ' selected';
4782 }
4783 } else {
4784 if ($selected == $id) {
4785 $out .= ' selected';
4786 }
4787 }
4788 $out .= '>';
4789 $value = '';
4790 if ($format == 0) {
4791 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4792 } elseif ($format == 1) {
4793 $value = $arraytypes['code'];
4794 } elseif ($format == 2) {
4795 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4796 } elseif ($format == 3) {
4797 $value = $arraytypes['code'];
4798 }
4799 $out .= $value ? $value : '&nbsp;';
4800 $out .= '</option>';
4801 }
4802 $out .= '</select>';
4803 if ($user->admin && !$noadmininfo) {
4804 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4805 }
4806 $out .= ajax_combobox('select' . $htmlname);
4807
4808 if (empty($nooutput)) {
4809 print $out;
4810 } else {
4811 return $out;
4812 }
4813 }
4814
4815
4824 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4825 {
4826 global $langs;
4827
4828 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4829 $options = array(
4830 'HT' => $langs->trans("HT"),
4831 'TTC' => $langs->trans("TTC")
4832 );
4833 foreach ($options as $id => $value) {
4834 if ($selected == $id) {
4835 $return .= '<option value="' . $id . '" selected>' . $value;
4836 } else {
4837 $return .= '<option value="' . $id . '">' . $value;
4838 }
4839 $return .= '</option>';
4840 }
4841 $return .= '</select>';
4842 if ($addjscombo) {
4843 $return .= ajax_combobox('select_' . $htmlname);
4844 }
4845
4846 return $return;
4847 }
4848
4849 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4850
4857 {
4858 // phpcs:enable
4859 global $langs;
4860
4861 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4862 if ($num > 0) {
4863 return $num; // Cache already loaded
4864 }
4865
4866 dol_syslog(__METHOD__, LOG_DEBUG);
4867
4868 $this->cache_transport_mode = array();
4869
4870 $sql = "SELECT rowid, code, label, active";
4871 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4872 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4873
4874 $resql = $this->db->query($sql);
4875 if ($resql) {
4876 $num = $this->db->num_rows($resql);
4877 $i = 0;
4878 while ($i < $num) {
4879 $obj = $this->db->fetch_object($resql);
4880
4881 // If traduction exist, we use it else we take the default label
4882 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4883 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4884 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4885 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4886 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4887 $i++;
4888 }
4889
4890 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4891
4892 return $num;
4893 } else {
4894 dol_print_error($this->db);
4895 return -1;
4896 }
4897 }
4898
4912 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4913 {
4914 global $langs, $user;
4915
4916 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4917
4919
4920 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4921 if ($empty) {
4922 print '<option value="">&nbsp;</option>';
4923 }
4924 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4925 // If not good status
4926 if ($active >= 0 && $arraytypes['active'] != $active) {
4927 continue;
4928 }
4929
4930 // We discard empty line if showempty is on because an empty line has already been output.
4931 if ($empty && empty($arraytypes['code'])) {
4932 continue;
4933 }
4934
4935 if ($format == 0) {
4936 print '<option value="' . $id . '"';
4937 } elseif ($format == 1) {
4938 print '<option value="' . $arraytypes['code'] . '"';
4939 } elseif ($format == 2) {
4940 print '<option value="' . $arraytypes['code'] . '"';
4941 } elseif ($format == 3) {
4942 print '<option value="' . $id . '"';
4943 }
4944 // If text is selected, we compare with code, else with id
4945 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4946 print ' selected';
4947 } elseif ($selected == $id) {
4948 print ' selected';
4949 }
4950 print '>';
4951 $value = '';
4952 if ($format == 0) {
4953 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4954 } elseif ($format == 1) {
4955 $value = $arraytypes['code'];
4956 } elseif ($format == 2) {
4957 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4958 } elseif ($format == 3) {
4959 $value = $arraytypes['code'];
4960 }
4961 print $value ? $value : '&nbsp;';
4962 print '</option>';
4963 }
4964 print '</select>';
4965
4966 print ajax_combobox("select".$htmlname);
4967
4968 if ($user->admin && !$noadmininfo) {
4969 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4970 }
4971 }
4972
4985 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4986 {
4987 global $langs, $user;
4988
4989 $langs->load("admin");
4990 $langs->load("deliveries");
4991
4992 $sql = "SELECT rowid, code, libelle as label";
4993 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4994 $sql .= " WHERE active > 0";
4995 if ($filtre) {
4996 $sql .= " AND " . $filtre;
4997 }
4998 $sql .= " ORDER BY libelle ASC";
4999
5000 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
5001 $result = $this->db->query($sql);
5002 if ($result) {
5003 $num = $this->db->num_rows($result);
5004 $i = 0;
5005 if ($num) {
5006 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5007 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5008 print '<option value="-1">&nbsp;</option>';
5009 }
5010 while ($i < $num) {
5011 $obj = $this->db->fetch_object($result);
5012 if ($selected == $obj->rowid) {
5013 print '<option value="' . $obj->rowid . '" selected>';
5014 } else {
5015 print '<option value="' . $obj->rowid . '">';
5016 }
5017 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
5018 print '</option>';
5019 $i++;
5020 }
5021 print "</select>";
5022 if ($user->admin && empty($noinfoadmin)) {
5023 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5024 }
5025
5026 print ajax_combobox('select' . $htmlname);
5027 } else {
5028 print $langs->trans("NoShippingMethodDefined");
5029 }
5030 } else {
5031 dol_print_error($this->db);
5032 }
5033 }
5034
5044 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
5045 {
5046 global $langs;
5047
5048 $langs->load("deliveries");
5049
5050 if ($htmlname != "none") {
5051 print '<form method="POST" action="' . $page . '">';
5052 print '<input type="hidden" name="action" value="setshippingmethod">';
5053 print '<input type="hidden" name="token" value="' . newToken() . '">';
5054 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5055 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5056 print '</form>';
5057 } else {
5058 if ($selected) {
5059 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5060 print $langs->trans("SendingMethod" . strtoupper($code));
5061 } else {
5062 print "&nbsp;";
5063 }
5064 }
5065 }
5066
5075 public function selectSituationInvoices($selected = '', $socid = 0)
5076 {
5077 global $langs;
5078
5079 $langs->load('bills');
5080
5081 $opt = '<option value="" selected></option>';
5082 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5083 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5084 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5085 $sql .= ' AND situation_counter >= 1';
5086 $sql .= ' AND fk_soc = ' . (int) $socid;
5087 $sql .= ' AND type <> 2';
5088 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5089 $resql = $this->db->query($sql);
5090
5091 if ($resql && $this->db->num_rows($resql) > 0) {
5092 // Last seen cycle
5093 $ref = 0;
5094 while ($obj = $this->db->fetch_object($resql)) {
5095 //Same cycle ?
5096 if ($obj->situation_cycle_ref != $ref) {
5097 // Just seen this cycle
5098 $ref = $obj->situation_cycle_ref;
5099 //not final ?
5100 if ($obj->situation_final != 1) {
5101 //Not prov?
5102 if (substr($obj->ref, 1, 4) != 'PROV') {
5103 if ($selected == $obj->rowid) {
5104 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5105 } else {
5106 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5107 }
5108 }
5109 }
5110 }
5111 }
5112 } else {
5113 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5114 }
5115 if ($opt == '<option value ="" selected></option>') {
5116 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5117 }
5118 return $opt;
5119 }
5120
5130 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5131 {
5132 global $langs;
5133
5134 $langs->load('products');
5135
5136 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5137
5138 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5139 $sql .= ' WHERE active > 0';
5140 if (!empty($unit_type)) {
5141 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5142 }
5143 $sql .= " ORDER BY sortorder";
5144
5145 $resql = $this->db->query($sql);
5146 if ($resql && $this->db->num_rows($resql) > 0) {
5147 if ($showempty) {
5148 $return .= '<option value="-1"></option>';
5149 }
5150
5151 while ($res = $this->db->fetch_object($resql)) {
5152 $unitLabel = $res->label;
5153 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5154 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5155 }
5156
5157 if ($selected == $res->rowid) {
5158 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5159 } else {
5160 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5161 }
5162 }
5163 $return .= '</select>';
5164
5165 $return .= ajax_combobox($htmlname);
5166 }
5167 return $return;
5168 }
5169
5170 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5171
5186 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5187 {
5188 // phpcs:enable
5189 global $langs;
5190
5191 $out = '';
5192
5193 $langs->loadLangs(array("admin", "banks"));
5194 $num = 0;
5195
5196 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5197 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5198 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5199 if ($status != 2) {
5200 $sql .= " AND clos = " . (int) $status;
5201 }
5202 if ($filtre) { // TODO Support USF
5203 $sql .= " AND " . $filtre;
5204 }
5205 $sql .= " ORDER BY label";
5206
5207 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5208 $result = $this->db->query($sql);
5209 if ($result) {
5210 $num = $this->db->num_rows($result);
5211 $i = 0;
5212
5213 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5214
5215 if ($num == 0) {
5216 if ($status == 0) {
5217 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5218 } else {
5219 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5220 }
5221 } else {
5222 if (!empty($useempty) && !is_numeric($useempty)) {
5223 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5224 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5225 $out .= '<option value="-1">&nbsp;</option>';
5226 }
5227 }
5228
5229 while ($i < $num) {
5230 $obj = $this->db->fetch_object($result);
5231
5232 $labeltoshow = trim($obj->label);
5233 $labeltoshowhtml = trim($obj->label);
5234 if ($showcurrency) {
5235 $labeltoshow .= ' (' . $obj->currency_code . ')';
5236 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5237 }
5238 if ($status == 2 && $obj->status == 1) {
5239 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5240 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5241 }
5242
5243 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5244 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5245 } else {
5246 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5247 }
5248 $out .= $labeltoshow;
5249 $out .= '</option>';
5250 $i++;
5251 }
5252 $out .= "</select>";
5253 $out .= ajax_combobox('select' . $htmlname);
5254 } else {
5255 dol_print_error($this->db);
5256 }
5257
5258 // Output or return
5259 if (empty($nooutput)) {
5260 print $out;
5261 } else {
5262 return $out;
5263 }
5264
5265 return $num;
5266 }
5267
5281 public function selectRib($selected = '', $htmlname = 'ribcompanyid', $filtre = '', $useempty = 0, $moreattrib = '', $showibanbic = 0, $morecss = '', $nooutput = 0)
5282 {
5283 // phpcs:enable
5284 global $langs;
5285
5286 $out = '';
5287
5288 $langs->loadLangs(array("admin", "banks"));
5289 $num = 0;
5290
5291 $sql = "SELECT rowid, label, bank, status, iban_prefix, bic";
5292 $sql .= " FROM " . $this->db->prefix() . "societe_rib";
5293 $sql .= " WHERE type = 'ban'";
5294 if ($filtre) { // TODO Support USF
5295 $sql .= " AND " . $filtre;
5296 }
5297 $sql .= " ORDER BY label";
5298 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5299 $result = $this->db->query($sql);
5300 if ($result) {
5301 $num = $this->db->num_rows($result);
5302 $i = 0;
5303
5304 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5305
5306 if ($num == 0) {
5307 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5308 } else {
5309 if (!empty($useempty) && !is_numeric($useempty)) {
5310 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5311 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5312 $out .= '<option value="-1">&nbsp;</option>';
5313 }
5314 }
5315
5316 while ($i < $num) {
5317 $obj = $this->db->fetch_object($result);
5318 $iban = dolDecrypt($obj->iban_prefix);
5319 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5320 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '" selected>';
5321 } else {
5322 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '">';
5323 }
5324 $out .= trim($obj->label);
5325 if ($showibanbic) {
5326 $out .= ' (' . $iban . '/' .$obj->bic. ')';
5327 }
5328 $out .= '</option>';
5329 $i++;
5330 }
5331 $out .= "</select>";
5332 $out .= ajax_combobox('select' . $htmlname);
5333 } else {
5334 dol_print_error($this->db);
5335 }
5336
5337 // Output or return
5338 if (empty($nooutput)) {
5339 print $out;
5340 } else {
5341 return $out;
5342 }
5343
5344 return $num;
5345 }
5346
5358 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5359 {
5360 global $langs;
5361
5362 $langs->load("admin");
5363 $num = 0;
5364
5365 $sql = "SELECT rowid, name, fk_country, status, entity";
5366 $sql .= " FROM " . $this->db->prefix() . "establishment";
5367 $sql .= " WHERE 1=1";
5368 if ($status != 2) {
5369 $sql .= " AND status = " . (int) $status;
5370 }
5371 if ($filtre) { // TODO Support USF
5372 $sql .= " AND " . $filtre;
5373 }
5374 $sql .= " ORDER BY name";
5375
5376 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5377 $result = $this->db->query($sql);
5378 if ($result) {
5379 $num = $this->db->num_rows($result);
5380 $i = 0;
5381 if ($num) {
5382 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5383 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5384 print '<option value="-1">&nbsp;</option>';
5385 }
5386
5387 while ($i < $num) {
5388 $obj = $this->db->fetch_object($result);
5389 if ($selected == $obj->rowid) {
5390 print '<option value="' . $obj->rowid . '" selected>';
5391 } else {
5392 print '<option value="' . $obj->rowid . '">';
5393 }
5394 print trim($obj->name);
5395 if ($status == 2 && $obj->status == 1) {
5396 print ' (' . $langs->trans("Closed") . ')';
5397 }
5398 print '</option>';
5399 $i++;
5400 }
5401 print "</select>";
5402 } else {
5403 if ($status == 0) {
5404 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5405 } else {
5406 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5407 }
5408 }
5409
5410 return $num;
5411 } else {
5412 dol_print_error($this->db);
5413 return -1;
5414 }
5415 }
5416
5426 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5427 {
5428 global $langs;
5429 if ($htmlname != "none") {
5430 print '<form method="POST" action="' . $page . '">';
5431 print '<input type="hidden" name="action" value="setbankaccount">';
5432 print '<input type="hidden" name="token" value="' . newToken() . '">';
5433 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5434 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5435 if ($nbaccountfound > 0) {
5436 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5437 }
5438 print '</form>';
5439 } else {
5440 $langs->load('banks');
5441
5442 if ($selected) {
5443 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5444 $bankstatic = new Account($this->db);
5445 $result = $bankstatic->fetch($selected);
5446 if ($result) {
5447 print $bankstatic->getNomUrl(1);
5448 }
5449 } else {
5450 print "&nbsp;";
5451 }
5452 }
5453 }
5454
5466 public function formRib($page, $selected = '', $htmlname = 'ribcompanyid', $filtre = '', $addempty = 0, $showibanbic = 0)
5467 {
5468 global $langs;
5469 if ($htmlname != "none") {
5470 print '<form method="POST" action="' . $page . '">';
5471 print '<input type="hidden" name="action" value="setbankaccountcustomer">';
5472 print '<input type="hidden" name="token" value="' . newToken() . '">';
5473 $nbaccountfound = $this->selectRib($selected, $htmlname, $filtre, $addempty, '', $showibanbic);
5474 if ($nbaccountfound > 0) {
5475 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5476 }
5477 print '</form>';
5478 } else {
5479 $langs->load('banks');
5480
5481 if ($selected) {
5482 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
5483 $bankstatic = new CompanyBankAccount($this->db);
5484 $result = $bankstatic->fetch($selected);
5485 if ($result) {
5486 print $bankstatic->label;
5487 if ($showibanbic) {
5488 print ' (' . $bankstatic->iban . '/' .$bankstatic->bic. ')';
5489 }
5490 }
5491 } else {
5492 print "&nbsp;";
5493 }
5494 }
5495 }
5496
5497 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5498
5518 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5519 {
5520 // phpcs:enable
5521 global $conf, $langs;
5522 $langs->load("categories");
5523
5524 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5525
5526 // For backward compatibility
5527 if (is_numeric($type)) {
5528 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5529 }
5530
5531 if ($type === Categorie::TYPE_BANK_LINE) {
5532 // TODO Move this into common category feature after migration of llx_category_bankline into llx_categorie_bankline
5533 $cat = new Categorie($this->db);
5534 $cate_arbo = array();
5535 $sql = "SELECT c.label, c.rowid";
5536 $sql .= " FROM " . $this->db->prefix() . "categorie as c";
5537 $sql .= " WHERE entity = " . $conf->entity . " AND type = " . ((int) $cat->getMapId()[$type]);
5538 $sql .= " ORDER BY c.label";
5539 $result = $this->db->query($sql);
5540 if ($result) {
5541 $num = $this->db->num_rows($result);
5542 $i = 0;
5543 while ($i < $num) {
5544 $objp = $this->db->fetch_object($result);
5545 if ($objp) {
5546 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5547 }
5548 $i++;
5549 }
5550 $this->db->free($result);
5551 } else {
5552 dol_print_error($this->db);
5553 }
5554 } else {
5555 $cat = new Categorie($this->db);
5556 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5557 }
5558
5559 $outarray = array();
5560 $outarrayrichhtml = array();
5561
5562
5563 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5564 if (is_array($cate_arbo)) {
5565 $num = count($cate_arbo);
5566
5567 if (!$num) {
5568 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5569 } else {
5570 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5571 $output .= '<option value="-1">&nbsp;</option>';
5572 }
5573 foreach ($cate_arbo as $key => $value) {
5574 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5575 $add = 'selected ';
5576 } else {
5577 $add = '';
5578 }
5579
5580 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5581 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5582
5583 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5584
5585 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5586
5587 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5588 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5589 $output .= '>';
5590 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5591 $output .= '</option>';
5592
5593 $cate_arbo[$key]['data-html'] = $labeltoshow;
5594 }
5595 }
5596 }
5597 $output .= '</select>';
5598 $output .= "\n";
5599
5600 if ($outputmode == 2) {
5601 // TODO: handle error when $cate_arbo is not an array
5602 return $cate_arbo;
5603 } elseif ($outputmode == 1) {
5604 return $outarray;
5605 } elseif ($outputmode == 3) {
5606 return $outarrayrichhtml;
5607 }
5608 return $output;
5609 }
5610
5611 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5612
5631 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5632 {
5633 // phpcs:enable
5634 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5635 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5636 }
5637
5665 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5666 {
5667 global $langs, $conf;
5668
5669 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5670 $formconfirm = '';
5671 $inputok = array();
5672 $inputko = array();
5673
5674 // Clean parameters
5675 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5676 if ($conf->browser->layout == 'phone') {
5677 $width = '95%';
5678 }
5679
5680 // Set height automatically if not defined
5681 if (empty($height)) {
5682 $height = 220;
5683 if (is_array($formquestion) && count($formquestion) > 2) {
5684 $height += ((count($formquestion) - 2) * 24);
5685 }
5686 }
5687
5688 if (is_array($formquestion) && !empty($formquestion)) {
5689 // First add hidden fields and value
5690 foreach ($formquestion as $key => $input) {
5691 if (is_array($input) && !empty($input)) {
5692 if ($input['type'] == 'hidden') {
5693 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5694 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5695
5696 $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";
5697 }
5698 }
5699 }
5700
5701 // Now add questions
5702 $moreonecolumn = '';
5703 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5704 foreach ($formquestion as $key => $input) {
5705 if (is_array($input) && !empty($input)) {
5706 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5707 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5708 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5709
5710 if ($input['type'] == 'text') {
5711 $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";
5712 } elseif ($input['type'] == 'password') {
5713 $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";
5714 } elseif ($input['type'] == 'textarea') {
5715 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5716 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5717 $more .= $input['value'];
5718 $more .= '</textarea>';
5719 $more .= '</div></div>'."\n";*/
5720 $moreonecolumn .= '<div class="margintoponly">';
5721 $moreonecolumn .= $input['label'] . '<br>';
5722 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5723 $moreonecolumn .= $input['value'];
5724 $moreonecolumn .= '</textarea>';
5725 $moreonecolumn .= '</div>';
5726 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5727 if (empty($morecss)) {
5728 $morecss = 'minwidth100';
5729 }
5730
5731 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5732 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5733 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5734 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5735 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5736 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5737 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5738
5739 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5740 if (!empty($input['label'])) {
5741 $more .= $input['label'] . '</div><div class="tagtd left">';
5742 }
5743 if ($input['type'] == 'select') {
5744 $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);
5745 } else {
5746 $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);
5747 }
5748 $more .= '</div></div>' . "\n";
5749 } elseif ($input['type'] == 'checkbox') {
5750 $more .= '<div class="tagtr">';
5751 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5752 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5753 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5754 $more .= ' checked';
5755 }
5756 if (is_bool($input['value']) && $input['value']) {
5757 $more .= ' checked';
5758 }
5759 if (isset($input['disabled'])) {
5760 $more .= ' disabled';
5761 }
5762 $more .= ' /></div>';
5763 $more .= '</div>' . "\n";
5764 } elseif ($input['type'] == 'radio') {
5765 $i = 0;
5766 foreach ($input['values'] as $selkey => $selval) {
5767 $more .= '<div class="tagtr">';
5768 if (isset($input['label'])) {
5769 if ($i == 0) {
5770 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5771 } else {
5772 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5773 }
5774 }
5775 $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;
5776 if (!empty($input['disabled'])) {
5777 $more .= ' disabled';
5778 }
5779 if (isset($input['default']) && $input['default'] === $selkey) {
5780 $more .= ' checked="checked"';
5781 }
5782 $more .= ' /> ';
5783 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5784 $more .= '</div></div>' . "\n";
5785 $i++;
5786 }
5787 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5788 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5789 $more .= '<div class="tagtd">';
5790 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5791 $h = $m = 0;
5792 if ($input['type'] == 'datetime') {
5793 $h = isset($input['hours']) ? $input['hours'] : 1;
5794 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5795 }
5796 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5797 $more .= '</div></div>'."\n";
5798 $formquestion[] = array('name' => $input['name'].'day');
5799 $formquestion[] = array('name' => $input['name'].'month');
5800 $formquestion[] = array('name' => $input['name'].'year');
5801 $formquestion[] = array('name' => $input['name'].'hour');
5802 $formquestion[] = array('name' => $input['name'].'min');
5803 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5804 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5805 if (!empty($input['label'])) {
5806 $more .= $input['label'] . '</div><div class="tagtd">';
5807 }
5808 $more .= $input['value'];
5809 $more .= '</div></div>' . "\n";
5810 } elseif ($input['type'] == 'onecolumn') {
5811 $moreonecolumn .= '<div class="margintoponly">';
5812 $moreonecolumn .= $input['value'];
5813 $moreonecolumn .= '</div>' . "\n";
5814 } elseif ($input['type'] == 'hidden') {
5815 // Do nothing more, already added by a previous loop
5816 } elseif ($input['type'] == 'separator') {
5817 $more .= '<br>';
5818 } else {
5819 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5820 }
5821 }
5822 }
5823 $more .= '</div>' . "\n";
5824 $more .= $moreonecolumn;
5825 }
5826
5827 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5828 // 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
5829 // See page product/card.php for example
5830 if (!empty($conf->dol_use_jmobile)) {
5831 $useajax = 0;
5832 }
5833 if (empty($conf->use_javascript_ajax)) {
5834 $useajax = 0;
5835 }
5836
5837 if ($useajax) {
5838 $autoOpen = true;
5839 $dialogconfirm = 'dialog-confirm';
5840 $button = '';
5841 if (!is_numeric($useajax)) {
5842 $button = $useajax;
5843 $useajax = 1;
5844 $autoOpen = false;
5845 $dialogconfirm .= '-' . $button;
5846 }
5847 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5848 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5849
5850 // Add input fields into list of fields to read during submit (inputok and inputko)
5851 if (is_array($formquestion)) {
5852 foreach ($formquestion as $key => $input) {
5853 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5854 // Add name of fields to propagate with the GET when submitting the form with button OK.
5855 if (is_array($input) && isset($input['name'])) {
5856 if (strpos($input['name'], ',') > 0) {
5857 $inputok = array_merge($inputok, explode(',', $input['name']));
5858 } else {
5859 array_push($inputok, $input['name']);
5860 }
5861 }
5862 // Add name of fields to propagate with the GET when submitting the form with button KO.
5863 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5864 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5865 array_push($inputko, $input['name']);
5866 }
5867 }
5868 }
5869
5870 // Show JQuery confirm box.
5871 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5872 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5873 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5874 }
5875 if (!empty($more)) {
5876 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5877 }
5878 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5879 $formconfirm .= '</div>' . "\n";
5880
5881 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5882 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5883 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5884 $formconfirm .= 'jQuery(document).ready(function() {
5885 $(function() {
5886 $( "#' . $dialogconfirm . '" ).dialog(
5887 {
5888 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5889 if ($newselectedchoice == 'no') {
5890 $formconfirm .= '
5891 open: function() {
5892 $(this).parent().find("button.ui-button:eq(2)").focus();
5893 },';
5894 }
5895
5896 $jsforcursor = '';
5897 if ($useajax == 1) {
5898 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5899 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5900 }
5901
5902 $postconfirmas = 'GET';
5903
5904 $formconfirm .= '
5905 resizable: false,
5906 height: \'' . dol_escape_js($height) . '\',
5907 width: \'' . dol_escape_js($width) . '\',
5908 modal: true,
5909 closeOnEscape: false,
5910 buttons: {
5911 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5912 var options = "token=' . urlencode(newToken()) . '";
5913 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5914 var page = \'' . dol_escape_js(!empty($page) ? $page : '') . '\';
5915 var pageyes = \'' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '\';
5916
5917 if (inputok.length > 0) {
5918 $.each(inputok, function(i, inputname) {
5919 var more = "";
5920 var inputvalue;
5921 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5922 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5923 } else {
5924 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5925 inputvalue = $("#" + inputname + more).val();
5926 }
5927 if (typeof inputvalue == "undefined") { inputvalue=""; }
5928 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5929 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5930 });
5931 }
5932 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5933 if (pageyes.length > 0) {';
5934 if ($postconfirmas == 'GET') {
5935 $formconfirm .= 'location.href = urljump;';
5936 } else {
5937 $formconfirm .= $jsforcursor;
5938 $formconfirm .= 'var post = $.post(
5939 pageyes,
5940 options,
5941 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5942 );';
5943 }
5944 $formconfirm .= '
5945 console.log("after post ok");
5946 }
5947 $(this).dialog("close");
5948 },
5949 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5950 var options = "token=' . urlencode(newToken()) . '";
5951 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5952 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5953 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5954 if (inputko.length > 0) {
5955 $.each(inputko, function(i, inputname) {
5956 var more = "";
5957 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5958 var inputvalue = $("#" + inputname + more).val();
5959 if (typeof inputvalue == "undefined") { inputvalue=""; }
5960 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5961 });
5962 }
5963 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5964 //alert(urljump);
5965 if (pageno.length > 0) {';
5966 if ($postconfirmas == 'GET') {
5967 $formconfirm .= 'location.href = urljump;';
5968 } else {
5969 $formconfirm .= $jsforcursor;
5970 $formconfirm .= 'var post = $.post(
5971 pageno,
5972 options,
5973 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5974 );';
5975 }
5976 $formconfirm .= '
5977 console.log("after post ko");
5978 }
5979 $(this).dialog("close");
5980 }
5981 }
5982 }
5983 );
5984
5985 var button = "' . $button . '";
5986 if (button.length > 0) {
5987 $( "#" + button ).click(function() {
5988 $("#' . $dialogconfirm . '").dialog("open");
5989 });
5990 }
5991 });
5992 });
5993 </script>';
5994 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5995 } else {
5996 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5997
5998 if (empty($disableformtag)) {
5999 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
6000 }
6001
6002 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
6003 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
6004
6005 $formconfirm .= '<table class="valid centpercent">' . "\n";
6006
6007 // Line title
6008 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
6009 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
6010 $formconfirm .= '</td></tr>' . "\n";
6011
6012 // Line text
6013 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
6014 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
6015 }
6016
6017 // Line form fields
6018 if ($more) {
6019 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
6020 $formconfirm .= $more;
6021 $formconfirm .= '</td></tr>' . "\n";
6022 }
6023
6024 // Line with question
6025 $formconfirm .= '<tr class="valid">';
6026 $formconfirm .= '<td class="valid">' . $question . '</td>';
6027 $formconfirm .= '<td class="valid center">';
6028 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
6029 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
6030 $formconfirm .= '</td>';
6031 $formconfirm .= '</tr>' . "\n";
6032
6033 $formconfirm .= '</table>' . "\n";
6034
6035 if (empty($disableformtag)) {
6036 $formconfirm .= "</form>\n";
6037 }
6038 $formconfirm .= '<br>';
6039
6040 if (!empty($conf->use_javascript_ajax)) {
6041 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
6042 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6043 $formconfirm .= '
6044 $(document).ready(function () {
6045 $(".confirmvalidatebutton").on("click", function() {
6046 console.log("We click on button confirmvalidatebutton");
6047 $(this).attr("disabled", "disabled");
6048 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
6049 //console.log($(this).closest("form"));
6050 $(this).closest("form").submit();
6051 });
6052 });
6053 ';
6054 $formconfirm .= '</script>' . "\n";
6055 }
6056
6057 $formconfirm .= "<!-- end formconfirm -->\n";
6058 }
6059
6060 return $formconfirm;
6061 }
6062
6063
6064 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6065
6081 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
6082 {
6083 // phpcs:enable
6084 global $langs;
6085
6086 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
6087 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
6088
6089 $out = '';
6090
6091 $formproject = new FormProjets($this->db);
6092
6093 $langs->load("project");
6094 if ($htmlname != "none") {
6095 $out .= '<form method="post" action="' . $page . '">';
6096 $out .= '<input type="hidden" name="action" value="classin">';
6097 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6098 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
6099 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6100 $out .= '</form>';
6101 } else {
6102 $out .= '<span class="project_head_block">';
6103 if ($selected) {
6104 $projet = new Project($this->db);
6105 $projet->fetch($selected);
6106 $out .= $projet->getNomUrl(0, '', 1);
6107 } else {
6108 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
6109 }
6110 $out .= '</span>';
6111 }
6112
6113 if (empty($nooutput)) {
6114 print $out;
6115 return '';
6116 }
6117 return $out;
6118 }
6119
6120 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6121
6137 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
6138 {
6139 // phpcs:enable
6140 global $langs;
6141
6142 $out = '';
6143
6144 if ($htmlname != "none") {
6145 $out .= '<form method="POST" action="' . $page . '">';
6146 $out .= '<input type="hidden" name="action" value="setconditions">';
6147 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6148 if ($type) {
6149 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6150 }
6151 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6152 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6153 $out .= '</form>';
6154 } else {
6155 if ($selected) {
6156 $this->load_cache_conditions_paiements();
6157 if (isset($this->cache_conditions_paiements[$selected])) {
6158 $label = $this->cache_conditions_paiements[$selected]['label'];
6159
6160 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6161 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6162 }
6163
6164 $out .= $label;
6165 } else {
6166 $langs->load('errors');
6167 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6168 }
6169 } else {
6170 $out .= '&nbsp;';
6171 }
6172 }
6173
6174 if (empty($nooutput)) {
6175 print $out;
6176 return '';
6177 }
6178 return $out;
6179 }
6180
6181 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6182
6192 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
6193 {
6194 // phpcs:enable
6195 global $langs;
6196 if ($htmlname != "none") {
6197 print '<form method="post" action="' . $page . '">';
6198 print '<input type="hidden" name="action" value="setavailability">';
6199 print '<input type="hidden" name="token" value="' . newToken() . '">';
6200 $this->selectAvailabilityDelay($selected, $htmlname, '', $addempty);
6201 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6202 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
6203 print '</form>';
6204 } else {
6205 if ($selected) {
6206 $this->load_cache_availability();
6207 print $this->cache_availability[$selected]['label'];
6208 } else {
6209 print "&nbsp;";
6210 }
6211 }
6212 }
6213
6224 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
6225 {
6226 global $langs;
6227 if ($htmlname != "none") {
6228 print '<form method="post" action="' . $page . '">';
6229 print '<input type="hidden" name="action" value="setdemandreason">';
6230 print '<input type="hidden" name="token" value="' . newToken() . '">';
6231 $this->selectInputReason($selected, $htmlname, '-1', $addempty);
6232 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6233 print '</form>';
6234 } else {
6235 if ($selected) {
6236 $this->loadCacheInputReason();
6237 foreach ($this->cache_demand_reason as $key => $val) {
6238 if ($val['id'] == $selected) {
6239 print $val['label'];
6240 break;
6241 }
6242 }
6243 } else {
6244 print "&nbsp;";
6245 }
6246 }
6247 }
6248
6249 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6250
6264 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6265 {
6266 // phpcs:enable
6267 global $langs;
6268
6269 $ret = '';
6270
6271 if ($htmlname != "none") {
6272 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6273 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6274 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6275 if ($type) {
6276 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6277 }
6278 $ret .= '<table class="nobordernopadding">';
6279 $ret .= '<tr><td>';
6280 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6281 $ret .= '</td>';
6282 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6283 $ret .= '</tr></table></form>';
6284 } else {
6285 if ($displayhour) {
6286 $ret .= dol_print_date($selected, 'dayhour');
6287 } else {
6288 $ret .= dol_print_date($selected, 'day');
6289 }
6290 }
6291
6292 if (empty($nooutput)) {
6293 print $ret;
6294 }
6295 return $ret;
6296 }
6297
6298
6299 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6300
6311 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6312 {
6313 // phpcs:enable
6314 global $langs;
6315
6316 if ($htmlname != "none") {
6317 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6318 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6319 print '<input type="hidden" name="token" value="' . newToken() . '">';
6320 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6321 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6322 print '</form>';
6323 } else {
6324 if ($selected) {
6325 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6326 $theuser = new User($this->db);
6327 $theuser->fetch($selected);
6328 print $theuser->getNomUrl(1);
6329 } else {
6330 print "&nbsp;";
6331 }
6332 }
6333 }
6334
6335
6336 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6337
6351 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6352 {
6353 // phpcs:enable
6354 global $langs;
6355
6356 $out = '';
6357 if ($htmlname != "none") {
6358 $out .= '<form method="POST" action="' . $page . '">';
6359 $out .= '<input type="hidden" name="action" value="setmode">';
6360 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6361 if ($type) {
6362 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6363 }
6364 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6365 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6366 $out .= '</form>';
6367 } else {
6368 if ($selected) {
6369 $this->load_cache_types_paiements();
6370 $out .= $this->cache_types_paiements[$selected]['label'];
6371 } else {
6372 $out .= "&nbsp;";
6373 }
6374 }
6375
6376 if ($nooutput) {
6377 return $out;
6378 } else {
6379 print $out;
6380 }
6381 return '';
6382 }
6383
6394 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6395 {
6396 global $langs;
6397 if ($htmlname != "none") {
6398 print '<form method="POST" action="' . $page . '">';
6399 print '<input type="hidden" name="action" value="settransportmode">';
6400 print '<input type="hidden" name="token" value="' . newToken() . '">';
6401 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6402 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6403 print '</form>';
6404 } else {
6405 if ($selected) {
6406 $this->load_cache_transport_mode();
6407 print $this->cache_transport_mode[$selected]['label'];
6408 } else {
6409 print "&nbsp;";
6410 }
6411 }
6412 }
6413
6414 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6415
6424 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6425 {
6426 // phpcs:enable
6427 global $langs;
6428 if ($htmlname != "none") {
6429 print '<form method="POST" action="' . $page . '">';
6430 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6431 print '<input type="hidden" name="token" value="' . newToken() . '">';
6432 print $this->selectMultiCurrency($selected, $htmlname, 0);
6433 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6434 print '</form>';
6435 } else {
6436 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6437 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6438 }
6439 }
6440
6441 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6442
6452 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6453 {
6454 // phpcs:enable
6455 global $langs, $mysoc, $conf;
6456
6457 if ($htmlname != "none") {
6458 print '<form method="POST" action="' . $page . '">';
6459 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6460 print '<input type="hidden" name="token" value="' . newToken() . '">';
6461 print '<input type="text" class="maxwidth75" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6462 print '<select name="calculation_mode" id="calculation_mode">';
6463 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6464 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6465 print '</select> ';
6466 print ajax_combobox("calculation_mode");
6467 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6468 print '</form>';
6469 } else {
6470 if (!empty($rate)) {
6471 print price($rate, 1, $langs, 0, 0);
6472 if ($currency && $rate != 1) {
6473 print ' &nbsp; <span class="opacitymedium">(' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')</span>';
6474 }
6475 } else {
6476 print 1;
6477 }
6478 }
6479 }
6480
6481 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6482
6498 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6499 {
6500 // phpcs:enable
6501 global $conf, $langs;
6502 if ($htmlname != "none") {
6503 print '<form method="post" action="' . $page . '">';
6504 print '<input type="hidden" name="action" value="setabsolutediscount">';
6505 print '<input type="hidden" name="token" value="' . newToken() . '">';
6506 print '<div class="inline-block">';
6507 if (!empty($discount_type)) {
6508 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6509 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6510 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6511 } else {
6512 $translationKey = 'HasCreditNoteFromSupplier';
6513 }
6514 } else {
6515 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6516 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6517 } else {
6518 $translationKey = 'HasCreditNoteFromSupplier';
6519 }
6520 }
6521 } else {
6522 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6523 if (!$filter || $filter == "fk_facture_source IS NULL") {
6524 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6525 } else {
6526 $translationKey = 'CompanyHasCreditNote';
6527 }
6528 } else {
6529 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6530 $translationKey = 'CompanyHasAbsoluteDiscount';
6531 } else {
6532 $translationKey = 'CompanyHasCreditNote';
6533 }
6534 }
6535 }
6536 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6537 if (empty($hidelist)) {
6538 print ' ';
6539 }
6540 print '</div>';
6541 if (empty($hidelist)) {
6542 print '<div class="inline-block" style="padding-right: 10px">';
6543 $newfilter = 'discount_type=' . intval($discount_type);
6544 if (!empty($discount_type)) {
6545 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6546 } else {
6547 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6548 }
6549 if ($filter) {
6550 $newfilter .= ' AND (' . $filter . ')';
6551 }
6552 // output the combo of discounts
6553 $nbqualifiedlines = $this->select_remises((string) $selected, $htmlname, $newfilter, $socid, $maxvalue);
6554 if ($nbqualifiedlines > 0) {
6555 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6556 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6557 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6558 }
6559 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6560 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6561 }
6562
6563 print '>';
6564 }
6565 print '</div>';
6566 }
6567 if ($more) {
6568 print '<div class="inline-block">';
6569 print $more;
6570 print '</div>';
6571 }
6572 print '</form>';
6573 } else {
6574 if ($selected) {
6575 print $selected;
6576 } else {
6577 print "0";
6578 }
6579 }
6580 }
6581
6582
6583 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6584
6594 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6595 {
6596 // phpcs:enable
6597 global $langs;
6598
6599 if ($htmlname != "none") {
6600 print '<form method="post" action="' . $page . '">';
6601 print '<input type="hidden" name="action" value="set_contact">';
6602 print '<input type="hidden" name="token" value="' . newToken() . '">';
6603 print '<table class="nobordernopadding">';
6604 print '<tr><td>';
6605 print $this->selectcontacts($societe->id, $selected, $htmlname);
6606 $num = $this->num;
6607 if ($num == 0) {
6608 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6609 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&action=create&backtoreferer=1">' . $addcontact . '</a>';
6610 }
6611 print '</td>';
6612 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6613 print '</tr></table></form>';
6614 } else {
6615 if ($selected) {
6616 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6617 $contact = new Contact($this->db);
6618 $contact->fetch($selected);
6619 print $contact->getFullName($langs);
6620 } else {
6621 print "&nbsp;";
6622 }
6623 }
6624 }
6625
6626 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6627
6644 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6645 {
6646 // phpcs:enable
6647 global $langs;
6648
6649 $out = '';
6650 if ($htmlname != "none") {
6651 $out .= '<form method="post" action="' . $page . '">';
6652 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6653 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6654 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6655 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6656 $out .= '</form>';
6657 } else {
6658 if ($selected) {
6659 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6660 $soc = new Societe($this->db);
6661 $soc->fetch($selected);
6662 $out .= $soc->getNomUrl(0, '');
6663 } else {
6664 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6665 }
6666 }
6667
6668 if ($nooutput) {
6669 return $out;
6670 } else {
6671 print $out;
6672 }
6673
6674 return '';
6675 }
6676
6677 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6678
6687 public function select_currency($selected = '', $htmlname = 'currency_id')
6688 {
6689 // phpcs:enable
6690 print $this->selectCurrency($selected, $htmlname);
6691 }
6692
6702 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6703 {
6704 global $langs, $user;
6705
6706 $langs->loadCacheCurrencies('');
6707
6708 $out = '';
6709
6710 if ($selected == 'euro' || $selected == 'euros') {
6711 $selected = 'EUR'; // Pour compatibilite
6712 }
6713
6714 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6715 if ($useempty) {
6716 $out .= '<option value="-1" selected></option>';
6717 }
6718 foreach ($langs->cache_currencies as $code_iso => $currency) {
6719 $labeltoshow = $currency['label'];
6720 if ($mode == 1) {
6721 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6722 } else {
6723 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6724 }
6725
6726 if ($selected && $selected == $code_iso) {
6727 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6728 } else {
6729 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6730 }
6731 $out .= $labeltoshow;
6732 $out .= '</option>';
6733 }
6734 $out .= '</select>';
6735 if ($user->admin) {
6736 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6737 }
6738
6739 // Make select dynamic
6740 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6741 $out .= ajax_combobox($htmlname);
6742
6743 return $out;
6744 }
6745
6758 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6759 {
6760 global $conf, $langs;
6761
6762 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6763
6764 $TCurrency = array();
6765
6766 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6767 $sql .= " WHERE entity IN ('" . getEntity('multicurrency') . "')";
6768 if ($filter) {
6769 $sql .= " AND " . $filter;
6770 }
6771 $resql = $this->db->query($sql);
6772 if ($resql) {
6773 while ($obj = $this->db->fetch_object($resql)) {
6774 $TCurrency[$obj->code] = $obj->code;
6775 }
6776 }
6777
6778 $out = '';
6779 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6780 if ($useempty) {
6781 $out .= '<option value="">&nbsp;</option>';
6782 }
6783 // If company current currency not in table, we add it into list. Should always be available.
6784 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6785 $TCurrency[$conf->currency] = $conf->currency;
6786 }
6787 if (count($TCurrency) > 0) {
6788 foreach ($langs->cache_currencies as $code_iso => $currency) {
6789 if (isset($TCurrency[$code_iso])) {
6790 if (!empty($selected) && $selected == $code_iso) {
6791 $out .= '<option value="' . $code_iso . '" selected="selected">';
6792 } else {
6793 $out .= '<option value="' . $code_iso . '">';
6794 }
6795
6796 $out .= $currency['label'];
6797 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6798 $out .= '</option>';
6799 }
6800 }
6801 }
6802
6803 $out .= '</select>';
6804
6805 // Make select dynamic
6806 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6807 $out .= ajax_combobox($htmlname);
6808
6809 return $out;
6810 }
6811
6812 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6813
6820 public function load_cache_vatrates($country_code)
6821 {
6822 // phpcs:enable
6823 global $langs, $user;
6824
6825 $num = count($this->cache_vatrates);
6826 if ($num > 0) {
6827 return $num; // Cache already loaded
6828 }
6829
6830 dol_syslog(__METHOD__, LOG_DEBUG);
6831
6832 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6833 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6834 $sql .= " WHERE t.fk_pays = c.rowid";
6835 $sql .= " AND t.active > 0";
6836 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6837 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6838 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6839
6840 $resql = $this->db->query($sql);
6841 if ($resql) {
6842 $num = $this->db->num_rows($resql);
6843 if ($num) {
6844 for ($i = 0; $i < $num; $i++) {
6845 $obj = $this->db->fetch_object($resql);
6846
6847 $tmparray = array();
6848 $tmparray['rowid'] = $obj->rowid;
6849 $tmparray['type_vat'] = ($obj->type_vat <= 0 ? 0 : $obj->type_vat); // Some version have type_vat corrupted with value -1
6850 $tmparray['code'] = $obj->code;
6851 $tmparray['txtva'] = $obj->taux;
6852 $tmparray['nprtva'] = $obj->recuperableonly;
6853 $tmparray['localtax1'] = $obj->localtax1;
6854 $tmparray['localtax1_type'] = $obj->localtax1_type;
6855 $tmparray['localtax2'] = $obj->localtax2;
6856 $tmparray['localtax2_type'] = $obj->localtax1_type;
6857 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6858 $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
6859 $positiverates = '';
6860 if ($obj->taux) {
6861 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6862 }
6863 if ($obj->localtax1) {
6864 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6865 }
6866 if ($obj->localtax2) {
6867 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6868 }
6869 if (empty($positiverates)) {
6870 $positiverates = '0';
6871 }
6872 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6873
6874 $this->cache_vatrates[$obj->rowid] = $tmparray;
6875 }
6876
6877 return $num;
6878 } else {
6879 $this->error = '<span class="error">';
6880 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6881 $reg = array();
6882 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6883 $langs->load("errors");
6884 $new_country_code = $reg[1];
6885 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid');
6886 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6887 }
6888 $this->error .= '</span>';
6889 return -1;
6890 }
6891 } else {
6892 $this->error = '<span class="error">' . $this->db->error() . '</span>';
6893 return -2;
6894 }
6895 }
6896
6897 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6898
6921 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)
6922 {
6923 // phpcs:enable
6924 global $langs, $mysoc;
6925
6926 $langs->load('errors');
6927
6928 $return = '';
6929
6930 // Define defaultnpr, defaultttx and defaultcode
6931 $defaultnpr = ($info_bits & 0x01);
6932 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6933 $defaulttx = str_replace('*', '', $selectedrate);
6934 $defaultcode = '';
6935 $reg = array();
6936 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6937 $defaultcode = $reg[1];
6938 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6939 }
6940 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6941
6942 // Check parameters
6943 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6944 if ($societe_vendeuse->id == $mysoc->id) {
6945 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6946 } else {
6947 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6948 }
6949 return $return;
6950 }
6951
6952 //var_dump($societe_acheteuse);
6953 //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";
6954 //exit;
6955
6956 // Define list of countries to use to search VAT rates to show
6957 // First we defined code_country to use to find list
6958 if (is_object($societe_vendeuse)) {
6959 $code_country = "'" . $societe_vendeuse->country_code . "'";
6960 } else {
6961 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6962 }
6963
6964 if ($societe_vendeuse == $mysoc && getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
6965 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6966 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
6967 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
6968 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
6969 if (is_object($societe_vendeuse) && is_object($societe_acheteuse) && isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
6970 // We also add the buyer country code
6971 if (is_numeric($type)) {
6972 if ($type == 1) { // We know product is a service
6973 switch ($selectVatComboMode) {
6974 case '1':
6975 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6976 break;
6977 case '2':
6978 $code_country = "'" . $societe_acheteuse->country_code . "'";
6979 break;
6980 }
6981 }
6982 } elseif (!$idprod) { // We don't know type of product
6983 switch ($selectVatComboMode) {
6984 case '1':
6985 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6986 break;
6987 case '2':
6988 $code_country = "'" . $societe_acheteuse->country_code . "'";
6989 break;
6990 }
6991 } else {
6992 $prodstatic = new Product($this->db);
6993 $prodstatic->fetch($idprod);
6994 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6995 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6996 }
6997 }
6998 }
6999 }
7000
7001 // Now we load the list of VAT
7002 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
7003
7004 // Keep only the VAT qualified for $type_vat
7005 $arrayofvatrates = array();
7006 foreach ($this->cache_vatrates as $cachevalue) {
7007 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] == $type_vat) {
7008 $arrayofvatrates[] = $cachevalue;
7009 }
7010 }
7011
7012 $num = count($arrayofvatrates);
7013 if ($num > 0) {
7014 // Define the rate to pre-select (if defaulttx not forced so is -1 or '')
7015 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7016 // Define a default thirdparty to use if the seller or buyer is not defined
7017 $tmpthirdparty = new Societe($this->db);
7018 $tmpthirdparty->country_code = $mysoc->country_code;
7019
7020 $defaulttx = get_default_tva(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7021 $defaultnpr = get_default_npr(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7022
7023 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7024 $defaultcode = $reg[1];
7025 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7026 }
7027 if (empty($defaulttx)) {
7028 $defaultnpr = 0;
7029 }
7030 }
7031
7032 // If we fails to find a default vat rate, we take the last one in list
7033 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
7034 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7035 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
7036 // We take the last one found in list
7037 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
7038 } else {
7039 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
7040 $defaulttx = '';
7041 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
7042 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
7043 }
7044 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7045 $defaultcode = $reg[1];
7046 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7047 }
7048 }
7049 }
7050
7051 // Disabled if seller is not subject to VAT
7052 $disabled = false;
7053 $title = '';
7054 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
7055 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
7056 // of using supplier invoices (this is a very bad idea !)
7057 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
7058 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
7059 $disabled = true;
7060 }
7061 }
7062
7063 if (!$options_only) {
7064 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
7065 }
7066
7067 $selectedfound = false;
7068 foreach ($arrayofvatrates as $rate) {
7069 // Keep only 0 if seller is not subject to VAT
7070 if ($disabled && $rate['txtva'] != 0) {
7071 continue;
7072 }
7073
7074 // Define key to use into select list
7075 $key = $rate['txtva'];
7076 $key .= $rate['nprtva'] ? '*' : '';
7077 if ($mode > 0 && $rate['code']) {
7078 $key .= ' (' . $rate['code'] . ')';
7079 }
7080 if ($mode < 0) {
7081 $key = $rate['rowid'];
7082 }
7083
7084 $return .= '<option value="' . $key . '"';
7085 if (!$selectedfound) {
7086 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
7087 if ($defaultcode == $rate['code']) {
7088 $return .= ' selected';
7089 $selectedfound = true;
7090 }
7091 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
7092 $return .= ' selected';
7093 $selectedfound = true;
7094 }
7095 }
7096 $return .= '>';
7097
7098 // Show label of VAT
7099 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
7100 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
7101 $return .= $rate['labelpositiverates'];
7102 } else {
7103 // Simple label
7104 $return .= vatrate($rate['label']);
7105 }
7106
7107 //$return.=($rate['code']?' '.$rate['code']:'');
7108 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
7109
7110 $return .= '</option>';
7111 }
7112
7113 if (!$options_only) {
7114 $return .= '</select>';
7115 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
7116 }
7117 } else {
7118 $return .= $this->error;
7119 }
7120
7121 $this->num = $num;
7122 return $return;
7123 }
7124
7125
7126 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7127
7152 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 = '')
7153 {
7154 // phpcs:enable
7155 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
7156 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
7157 if (!empty($nooutput)) {
7158 return $retstring;
7159 }
7160 print $retstring;
7161
7162 return '';
7163 }
7164
7180 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
7181 {
7182 global $langs;
7183
7184 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
7185 if ($forcenewline) {
7186 $ret .= '<br>';
7187 }
7188 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
7189 return $ret;
7190 }
7191
7220 public function selectDate($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '', $openinghours = '', $stepminutes = 1, $labeladddateof = '', $placeholder = '', $gm = 'auto', $calendarpicto = '')
7221 {
7222 global $conf, $langs;
7223
7224 if ($gm === 'auto') {
7225 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7226 }
7227
7228 $retstring = '';
7229
7230 if ($prefix == '') {
7231 $prefix = 're';
7232 }
7233 if ($h == '') {
7234 $h = 0;
7235 }
7236 if ($m == '') {
7237 $m = 0;
7238 }
7239 $emptydate = 0;
7240 $emptyhours = 0;
7241 if ($stepminutes <= 0 || $stepminutes > 30) {
7242 $stepminutes = 1;
7243 }
7244 if ($empty == 1) {
7245 $emptydate = 1;
7246 $emptyhours = 1;
7247 }
7248 if ($empty == 2) {
7249 $emptydate = 0;
7250 $emptyhours = 1;
7251 }
7252 $orig_set_time = $set_time;
7253
7254 if ($set_time === '' && $emptydate == 0) {
7255 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7256 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7257 $set_time = dol_now($gm);
7258 } else {
7259 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7260 }
7261 }
7262
7263 // Analysis of the pre-selection date
7264 $reg = array();
7265 $shour = '';
7266 $smin = '';
7267 $ssec = '';
7268 if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
7269 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7270 $syear = (!empty($reg[1]) ? $reg[1] : '');
7271 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7272 $sday = (!empty($reg[3]) ? $reg[3] : '');
7273 $shour = (!empty($reg[4]) ? $reg[4] : '');
7274 $smin = (!empty($reg[5]) ? $reg[5] : '');
7275 } elseif (strval($set_time) != '' && $set_time != -1) {
7276 // set_time est un timestamps (0 possible)
7277 $syear = dol_print_date($set_time, "%Y", $gm);
7278 $smonth = dol_print_date($set_time, "%m", $gm);
7279 $sday = dol_print_date($set_time, "%d", $gm);
7280 if ($orig_set_time != '') {
7281 $shour = dol_print_date($set_time, "%H", $gm);
7282 $smin = dol_print_date($set_time, "%M", $gm);
7283 $ssec = dol_print_date($set_time, "%S", $gm);
7284 }
7285 } else {
7286 // Date est '' ou vaut -1
7287 $syear = '';
7288 $smonth = '';
7289 $sday = '';
7290 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7291 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7292 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7293 }
7294 if ($h == 3 || $h == 4) {
7295 $shour = '';
7296 }
7297 if ($m == 3) {
7298 $smin = '';
7299 }
7300
7301 $nowgmt = dol_now('gmt');
7302 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7303
7304 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7305 $usecalendar = 'combo';
7306 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7307 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : getDolGlobalString("MAIN_POPUP_CALENDAR"));
7308 }
7309 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7310 // If we use a text browser or screen reader, we use the 'combo' date selector
7311 $usecalendar = 'html';
7312 }
7313
7314 if ($d) {
7315 // Show date with popup
7316 if ($usecalendar != 'combo') {
7317 $formatted_date = '';
7318 //print "e".$set_time." t ".$conf->format_date_short;
7319 if (strval($set_time) != '' && $set_time != -1) {
7320 //$formatted_date=dol_print_date($set_time,$conf->format_date_short);
7321 $formatted_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7322 }
7323
7324 // Calendrier popup version eldy
7325 if ($usecalendar == "eldy") {
7326 // Input area to enter date manually
7327 $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formatted_date . '"';
7328 $retstring .= ($disabled ? ' disabled' : '');
7329 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7330 $retstring .= ' autocomplete="off">';
7331
7332 // Icon calendar
7333 $retstringbuttom = '';
7334 if (!$disabled) {
7335 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7336 $base = DOL_URL_ROOT . '/core/';
7337 $retstringbuttom .= ' onClick="showDP(\'' . dol_escape_js($base) . '\',\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\',\'' . dol_escape_js($langs->defaultlang) . '\');"';
7338 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
7339 } else {
7340 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7341 }
7342 $retstring = $retstringbuttom . $retstring;
7343
7344 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7345 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7346 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7347 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7348 if (!$disabled && $usecalendar != 'html') {
7349 // Output javascript for datepicker
7350 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7351 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7352
7353 $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
7354 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7355 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7356 autoclose: true,
7357 todayHighlight: true,
7358 yearRange: '" . $minYear . ":" . $maxYear . "',";
7359 if (!empty($conf->dol_use_jmobile)) {
7360 $retstring .= "
7361 beforeShow: function (input, datePicker) {
7362 input.disabled = true;
7363 },
7364 onClose: function (dateText, datePicker) {
7365 this.disabled = false;
7366 },
7367 ";
7368 }
7369 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7370 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7371 $buttonImage = $calendarpicto ?: DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png";
7372 $retstring .= "
7373 showOn: 'button', /* both has problem with autocompletion */
7374 buttonImage: '" . $buttonImage . "',
7375 buttonImageOnly: true";
7376 }
7377 $retstring .= "
7378 }) });";
7379 $retstring .= "</script>";
7380 }
7381
7382 // Input area to enter date manually
7383 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7384 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="'.($usecalendar == 'html' ? "date" : "text").'" class="maxwidthdate center" maxlength="11" value="'.$formatted_date.'"';
7385 $retstring .= ($disabled ? ' disabled' : '');
7386 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7387 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7388 $retstring .= ' autocomplete="off">';
7389
7390 // Icon calendar
7391 if ($disabled) {
7392 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7393 $retstring = $retstringbutton . $retstring;
7394 }
7395
7396 $retstring .= '</div>';
7397 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7398 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7399 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7400 } else {
7401 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7402 }
7403 } else {
7404 // Show date with combo selects
7405 // Day
7406 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7407
7408 if ($emptydate || $set_time == -1) {
7409 $retstring .= '<option value="0" selected>&nbsp;</option>';
7410 }
7411
7412 for ($day = 1; $day <= 31; $day++) {
7413 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7414 }
7415
7416 $retstring .= "</select>";
7417
7418 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7419 if ($emptydate || $set_time == -1) {
7420 $retstring .= '<option value="0" selected>&nbsp;</option>';
7421 }
7422
7423 // Month
7424 for ($month = 1; $month <= 12; $month++) {
7425 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7426 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7427 $retstring .= "</option>";
7428 }
7429 $retstring .= "</select>";
7430
7431 // Year
7432 if ($emptydate || $set_time == -1) {
7433 $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 . '">';
7434 } else {
7435 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7436
7437 $syear = (int) $syear;
7438 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7439 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7440 }
7441 $retstring .= "</select>\n";
7442 }
7443 }
7444 }
7445
7446 if ($d && $h) {
7447 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7448 $retstring .= '<span class="nowraponall">';
7449 }
7450
7451 if ($h) {
7452 $hourstart = 0;
7453 $hourend = 24;
7454 if ($openinghours != '') {
7455 $openinghours = explode(',', $openinghours);
7456 $hourstart = $openinghours[0];
7457 $hourend = $openinghours[1];
7458 if ($hourend < $hourstart) {
7459 $hourend = $hourstart;
7460 }
7461 }
7462
7463 // Show hour
7464 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7465 if ($emptyhours) {
7466 $retstring .= '<option value="-1">&nbsp;</option>';
7467 }
7468 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7469 if (strlen($hour) < 2) {
7470 $hour = "0" . $hour;
7471 }
7472 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7473 $retstring .= '</option>';
7474 }
7475 $retstring .= '</select>';
7476 if ($disabled) {
7477 $retstring .= '<input type="hidden" id="' . $prefix . 'hour" name="' . $prefix . 'hour" value="' . $shour . '">' . "\n";
7478 }
7479 if ($m) {
7480 $retstring .= ":";
7481 }
7482 }
7483
7484 if ($m) {
7485 // Show minutes
7486 $retstring .= '<select ' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7487 if ($emptyhours) {
7488 $retstring .= '<option value="-1">&nbsp;</option>';
7489 }
7490 for ($min = 0; $min < 60; $min += $stepminutes) {
7491 $min_str = sprintf("%02d", $min);
7492 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7493 }
7494 $retstring .= '</select>';
7495 if ($disabled) {
7496 $retstring .= '<input type="hidden" id="' . $prefix . 'min" name="' . $prefix . 'min" value="' . $smin . '">' . "\n";
7497 }
7498 // Add also seconds
7499 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7500 }
7501
7502 if ($d && $h) {
7503 $retstring .= '</span>';
7504 }
7505
7506 // Add a "Now" link
7507 if (!empty($conf->use_javascript_ajax) && $addnowlink && !$disabled) {
7508 // Script which will be inserted in the onClick of the "Now" link
7509 $reset_scripts = "";
7510 if ($addnowlink == 2) { // local computer time
7511 // pad add leading 0 on numbers
7512 $reset_scripts .= "Number.prototype.pad = function(size) {
7513 var s = String(this);
7514 while (s.length < (size || 2)) {s = '0' + s;}
7515 return s;
7516 };
7517 var d = new Date();";
7518 }
7519
7520 // Generate the date part, depending on the use or not of the javascript calendar
7521 if ($addnowlink == 1) { // server time expressed in user time setup
7522 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7523 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7524 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7525 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7526 } elseif ($addnowlink == 2) {
7527 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7528 * This break application for foreign languages.
7529 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7530 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7531 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7532 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7533 */
7534 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7535 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7536 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7537 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7538 }
7539 /*if ($usecalendar == "eldy")
7540 {
7541 $base=DOL_URL_ROOT.'/core/';
7542 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7543 }
7544 else
7545 {
7546 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7547 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7548 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7549 }*/
7550 // Update the hour part
7551 if ($h) {
7552 if ($fullday) {
7553 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7554 }
7555 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7556 if ($addnowlink == 1) {
7557 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7558 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7559 } elseif ($addnowlink == 2) {
7560 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7561 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7562 }
7563
7564 if ($fullday) {
7565 $reset_scripts .= ' } ';
7566 }
7567 }
7568 // Update the minute part
7569 if ($m) {
7570 if ($fullday) {
7571 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7572 }
7573 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7574 if ($addnowlink == 1) {
7575 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7576 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7577 } elseif ($addnowlink == 2) {
7578 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7579 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7580 }
7581 if ($fullday) {
7582 $reset_scripts .= ' } ';
7583 }
7584 }
7585 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7586 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7587 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7588 $retstring .= $langs->trans("Now");
7589 $retstring .= '</button> ';
7590 }
7591 }
7592
7593 // Add a "Plus one hour" link
7594 if ($conf->use_javascript_ajax && $addplusone && !$disabled) {
7595 // Script which will be inserted in the onClick of the "Add plusone" link
7596 $reset_scripts = "";
7597
7598 // Generate the date part, depending on the use or not of the javascript calendar
7599 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7600 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7601 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7602 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7603 // Update the hour part
7604 if ($h) {
7605 if ($fullday) {
7606 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7607 }
7608 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7609 if ($fullday) {
7610 $reset_scripts .= ' } ';
7611 }
7612 }
7613 // Update the minute part
7614 if ($m) {
7615 if ($fullday) {
7616 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7617 }
7618 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7619 if ($fullday) {
7620 $reset_scripts .= ' } ';
7621 }
7622 }
7623 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7624 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7625 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7626 $retstring .= $langs->trans("DateStartPlusOne");
7627 $retstring .= '</button> ';
7628 }
7629 }
7630
7631 // Add a link to set data
7632 if ($conf->use_javascript_ajax && !empty($adddateof) && !$disabled) {
7633 if (!is_array($adddateof)) {
7634 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
7635 } else {
7636 $arrayofdateof = $adddateof;
7637 }
7638 foreach ($arrayofdateof as $valuedateof) {
7639 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
7640 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
7641 $tmparray = dol_getdate($tmpadddateof);
7642 if (empty($tmplabeladddateof)) {
7643 $tmplabeladddateof = $langs->trans("DateInvoice");
7644 }
7645 $reset_scripts = 'console.log(\'Click on now link\'); ';
7646 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7647 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7648 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7649 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7650 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7651 }
7652 }
7653
7654 return $retstring;
7655 }
7656
7665 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7666 {
7667 global $langs;
7668
7669 $TDurationTypes = array(
7670 'y' => $langs->trans('Years'),
7671 'm' => $langs->trans('Month'),
7672 'w' => $langs->trans('Weeks'),
7673 'd' => $langs->trans('Days'),
7674 'h' => $langs->trans('Hours'),
7675 'i' => $langs->trans('Minutes')
7676 );
7677
7678 // Removed undesired duration types
7679 foreach ($excludetypes as $value) {
7680 unset($TDurationTypes[$value]);
7681 }
7682
7683 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7684 foreach ($TDurationTypes as $key => $typeduration) {
7685 $retstring .= '<option value="' . $key . '"';
7686 if ($key == $selected) {
7687 $retstring .= " selected";
7688 }
7689 $retstring .= ">" . $typeduration . "</option>";
7690 }
7691 $retstring .= "</select>";
7692
7693 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7694
7695 return $retstring;
7696 }
7697
7698 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7699
7713 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7714 {
7715 // phpcs:enable
7716 global $langs;
7717
7718 $retstring = '<span class="nowraponall">';
7719
7720 $hourSelected = '';
7721 $minSelected = '';
7722
7723 // Hours
7724 if ($iSecond != '') {
7725 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7726
7727 $hourSelected = convertSecondToTime($iSecond, 'allhour');
7728 $minSelected = convertSecondToTime($iSecond, 'min');
7729 }
7730
7731 if ($typehour == 'select') {
7732 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7733 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7734 $retstring .= '<option value="' . $hour . '"';
7735 if (is_numeric($hourSelected) && $hourSelected == $hour) {
7736 $retstring .= " selected";
7737 }
7738 $retstring .= ">" . $hour . "</option>";
7739 }
7740 $retstring .= "</select>";
7741 } elseif ($typehour == 'text' || $typehour == 'textselect') {
7742 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7743 } else {
7744 return 'BadValueForParameterTypeHour';
7745 }
7746
7747 if ($typehour != 'text') {
7748 $retstring .= ' ' . $langs->trans('HourShort');
7749 } else {
7750 $retstring .= '<span class="">:</span>';
7751 }
7752
7753 // Minutes
7754 if ($minunderhours) {
7755 $retstring .= '<br>';
7756 } else {
7757 if ($typehour != 'text') {
7758 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7759 }
7760 }
7761
7762 if ($typehour == 'select' || $typehour == 'textselect') {
7763 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7764 for ($min = 0; $min <= 55; $min += 5) {
7765 $retstring .= '<option value="' . $min . '"';
7766 if (is_numeric($minSelected) && $minSelected == $min) {
7767 $retstring .= ' selected';
7768 }
7769 $retstring .= '>' . $min . '</option>';
7770 }
7771 $retstring .= "</select>";
7772 } elseif ($typehour == 'text') {
7773 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7774 }
7775
7776 if ($typehour != 'text') {
7777 $retstring .= ' ' . $langs->trans('MinuteShort');
7778 }
7779
7780 $retstring .= "</span>";
7781
7782 if (!empty($nooutput)) {
7783 return $retstring;
7784 }
7785
7786 print $retstring;
7787
7788 return '';
7789 }
7790
7810 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)
7811 {
7812 global $langs, $conf;
7813
7814 $out = '';
7815
7816 // check parameters
7817 if (is_null($ajaxoptions)) {
7818 $ajaxoptions = array();
7819 }
7820
7821 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7822 $placeholder = '';
7823
7824 if ($selected && empty($selected_input_value)) {
7825 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7826 $tickettmpselect = new Ticket($this->db);
7827 $tickettmpselect->fetch($selected);
7828 $selected_input_value = $tickettmpselect->ref;
7829 unset($tickettmpselect);
7830 }
7831
7832 $urloption = '';
7833 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7834
7835 if (empty($hidelabel)) {
7836 $out .= $langs->trans("RefOrLabel") . ' : ';
7837 } elseif ($hidelabel > 1) {
7838 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7839 if ($hidelabel == 2) {
7840 $out .= img_picto($langs->trans("Search"), 'search');
7841 }
7842 }
7843 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7844 if ($hidelabel == 3) {
7845 $out .= img_picto($langs->trans("Search"), 'search');
7846 }
7847 } else {
7848 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7849 }
7850
7851 if (empty($nooutput)) {
7852 print $out;
7853 } else {
7854 return $out;
7855 }
7856 return '';
7857 }
7858
7859
7876 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7877 {
7878 global $langs, $conf;
7879
7880 $out = '';
7881 $outarray = array();
7882
7883 $selectFields = " p.rowid, p.ref, p.message";
7884
7885 $sql = "SELECT ";
7886 $sql .= $selectFields;
7887 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7888 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7889
7890 // Add criteria on ref/label
7891 if ($filterkey != '') {
7892 $sql .= ' AND (';
7893 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7894 // For natural search
7895 $search_crit = explode(' ', $filterkey);
7896 $i = 0;
7897 if (count($search_crit) > 1) {
7898 $sql .= "(";
7899 }
7900 foreach ($search_crit as $crit) {
7901 if ($i > 0) {
7902 $sql .= " AND ";
7903 }
7904 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7905 $sql .= ")";
7906 $i++;
7907 }
7908 if (count($search_crit) > 1) {
7909 $sql .= ")";
7910 }
7911 $sql .= ')';
7912 }
7913
7914 $sql .= $this->db->plimit($limit, 0);
7915
7916 // Build output string
7917 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7918 $result = $this->db->query($sql);
7919 if ($result) {
7920 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7921 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7922
7923 $num = $this->db->num_rows($result);
7924
7925 $events = array();
7926
7927 if (!$forcecombo) {
7928 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7929 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('TICKET_USE_SEARCH_TO_SELECT'));
7930 }
7931
7932 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7933
7934 $textifempty = '';
7935 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7936 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7937 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7938 if ($showempty && !is_numeric($showempty)) {
7939 $textifempty = $langs->trans($showempty);
7940 } else {
7941 $textifempty .= $langs->trans("All");
7942 }
7943 } else {
7944 if ($showempty && !is_numeric($showempty)) {
7945 $textifempty = $langs->trans($showempty);
7946 }
7947 }
7948 if ($showempty) {
7949 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7950 }
7951
7952 $i = 0;
7953 while ($num && $i < $num) {
7954 $opt = '';
7955 $optJson = array();
7956 $objp = $this->db->fetch_object($result);
7957
7958 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7959 '@phan-var-force array{key:string,value:mixed,type:int} $optJson';
7960 // Add new entry
7961 // "key" value of json key array is used by jQuery automatically as selected value
7962 // "label" value of json key array is used by jQuery automatically as text for combo box
7963 $out .= $opt;
7964 array_push($outarray, $optJson);
7965
7966 $i++;
7967 }
7968
7969 $out .= '</select>';
7970
7971 $this->db->free($result);
7972
7973 if (empty($outputmode)) {
7974 return $out;
7975 }
7976 return $outarray;
7977 } else {
7978 dol_print_error($this->db);
7979 }
7980
7981 return array();
7982 }
7983
7995 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7996 {
7997 $outkey = '';
7998 $outref = '';
7999 $outtype = '';
8000
8001 $outkey = $objp->rowid;
8002 $outref = $objp->ref;
8003
8004 $opt = '<option value="' . $objp->rowid . '"';
8005 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8006 $opt .= '>';
8007 $opt .= $objp->ref;
8008 $objRef = $objp->ref;
8009 if (!empty($filterkey) && $filterkey != '') {
8010 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8011 }
8012
8013 $opt .= "</option>\n";
8014 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8015 }
8016
8036 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)
8037 {
8038 global $langs, $conf;
8039
8040 $out = '';
8041
8042 // check parameters
8043 if (is_null($ajaxoptions)) {
8044 $ajaxoptions = array();
8045 }
8046
8047 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8048 $placeholder = '';
8049
8050 if ($selected && empty($selected_input_value)) {
8051 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8052 $projecttmpselect = new Project($this->db);
8053 $projecttmpselect->fetch($selected);
8054 $selected_input_value = $projecttmpselect->ref;
8055 unset($projecttmpselect);
8056 }
8057
8058 $urloption = '';
8059 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8060
8061 if (empty($hidelabel)) {
8062 $out .= $langs->trans("RefOrLabel") . ' : ';
8063 } elseif ($hidelabel > 1) {
8064 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8065 if ($hidelabel == 2) {
8066 $out .= img_picto($langs->trans("Search"), 'search');
8067 }
8068 }
8069 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8070 if ($hidelabel == 3) {
8071 $out .= img_picto($langs->trans("Search"), 'search');
8072 }
8073 } else {
8074 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8075 }
8076
8077 if (empty($nooutput)) {
8078 print $out;
8079 } else {
8080 return $out;
8081 }
8082 return '';
8083 }
8084
8101 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8102 {
8103 global $langs, $conf;
8104
8105 $out = '';
8106 $outarray = array();
8107
8108 $selectFields = " p.rowid, p.ref";
8109
8110 $sql = "SELECT ";
8111 $sql .= $selectFields;
8112 $sql .= " FROM " . $this->db->prefix() . "projet as p";
8113 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
8114
8115 // Add criteria on ref/label
8116 if ($filterkey != '') {
8117 $sql .= ' AND (';
8118 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8119 // For natural search
8120 $search_crit = explode(' ', $filterkey);
8121 $i = 0;
8122 if (count($search_crit) > 1) {
8123 $sql .= "(";
8124 }
8125 foreach ($search_crit as $crit) {
8126 if ($i > 0) {
8127 $sql .= " AND ";
8128 }
8129 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8130 $sql .= "";
8131 $i++;
8132 }
8133 if (count($search_crit) > 1) {
8134 $sql .= ")";
8135 }
8136 $sql .= ')';
8137 }
8138
8139 $sql .= $this->db->plimit($limit, 0);
8140
8141 // Build output string
8142 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
8143 $result = $this->db->query($sql);
8144 if ($result) {
8145 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8146 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
8147
8148 $num = $this->db->num_rows($result);
8149
8150 $events = array();
8151
8152 if (!$forcecombo) {
8153 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8154 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8155 }
8156
8157 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8158
8159 $textifempty = '';
8160 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8161 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8162 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8163 if ($showempty && !is_numeric($showempty)) {
8164 $textifempty = $langs->trans($showempty);
8165 } else {
8166 $textifempty .= $langs->trans("All");
8167 }
8168 } else {
8169 if ($showempty && !is_numeric($showempty)) {
8170 $textifempty = $langs->trans($showempty);
8171 }
8172 }
8173 if ($showempty) {
8174 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8175 }
8176
8177 $i = 0;
8178 while ($num && $i < $num) {
8179 $opt = '';
8180 $optJson = array();
8181 $objp = $this->db->fetch_object($result);
8182
8183 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
8184 // Add new entry
8185 // "key" value of json key array is used by jQuery automatically as selected value
8186 // "label" value of json key array is used by jQuery automatically as text for combo box
8187 $out .= $opt;
8188 array_push($outarray, $optJson);
8189
8190 $i++;
8191 }
8192
8193 $out .= '</select>';
8194
8195 $this->db->free($result);
8196
8197 if (empty($outputmode)) {
8198 return $out;
8199 }
8200 return $outarray;
8201 } else {
8202 dol_print_error($this->db);
8203 }
8204
8205 return array();
8206 }
8207
8219 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8220 {
8221 $outkey = '';
8222 $outref = '';
8223 $outtype = '';
8224
8225 $label = $objp->label;
8226
8227 $outkey = $objp->rowid;
8228 $outref = $objp->ref;
8229 $outlabel = $objp->label;
8230 $outtype = $objp->fk_product_type;
8231
8232 $opt = '<option value="' . $objp->rowid . '"';
8233 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8234 $opt .= '>';
8235 $opt .= $objp->ref;
8236 $objRef = $objp->ref;
8237 if (!empty($filterkey) && $filterkey != '') {
8238 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8239 }
8240
8241 $opt .= "</option>\n";
8242 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8243 }
8244
8245
8265 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)
8266 {
8267 global $langs, $conf;
8268
8269 $out = '';
8270
8271 // check parameters
8272 if (is_null($ajaxoptions)) {
8273 $ajaxoptions = array();
8274 }
8275
8276 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8277 $placeholder = '';
8278
8279 if ($selected && empty($selected_input_value)) {
8280 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8281 $adherenttmpselect = new Adherent($this->db);
8282 $adherenttmpselect->fetch($selected);
8283 $selected_input_value = $adherenttmpselect->ref;
8284 unset($adherenttmpselect);
8285 }
8286
8287 $urloption = '';
8288
8289 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8290
8291 if (empty($hidelabel)) {
8292 $out .= $langs->trans("RefOrLabel") . ' : ';
8293 } elseif ($hidelabel > 1) {
8294 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8295 if ($hidelabel == 2) {
8296 $out .= img_picto($langs->trans("Search"), 'search');
8297 }
8298 }
8299 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8300 if ($hidelabel == 3) {
8301 $out .= img_picto($langs->trans("Search"), 'search');
8302 }
8303 } else {
8304 $filterkey = '';
8305
8306 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8307 }
8308
8309 if (empty($nooutput)) {
8310 print $out;
8311 } else {
8312 return $out;
8313 }
8314 return '';
8315 }
8316
8333 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8334 {
8335 global $langs, $conf;
8336
8337 $out = '';
8338 $outarray = array();
8339
8340 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8341
8342 $sql = "SELECT ";
8343 $sql .= $selectFields;
8344 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8345 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8346
8347 // Add criteria on ref/label
8348 if ($filterkey != '') {
8349 $sql .= ' AND (';
8350 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8351 // For natural search
8352 $search_crit = explode(' ', $filterkey);
8353 $i = 0;
8354 if (count($search_crit) > 1) {
8355 $sql .= "(";
8356 }
8357 foreach ($search_crit as $crit) {
8358 if ($i > 0) {
8359 $sql .= " AND ";
8360 }
8361 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8362 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8363 $i++;
8364 }
8365 if (count($search_crit) > 1) {
8366 $sql .= ")";
8367 }
8368 $sql .= ')';
8369 }
8370 if ($status != -1) {
8371 $sql .= ' AND statut = ' . ((int) $status);
8372 }
8373 $sql .= $this->db->plimit($limit, 0);
8374
8375 // Build output string
8376 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8377 $result = $this->db->query($sql);
8378 if ($result) {
8379 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8380 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8381
8382 $num = $this->db->num_rows($result);
8383
8384 $events = array();
8385
8386 if (!$forcecombo) {
8387 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8388 $out .= ajax_combobox($htmlname, $events, getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT') ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
8389 }
8390
8391 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8392
8393 $textifempty = '';
8394 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8395 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8396 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8397 if ($showempty && !is_numeric($showempty)) {
8398 $textifempty = $langs->trans($showempty);
8399 } else {
8400 $textifempty .= $langs->trans("All");
8401 }
8402 } else {
8403 if ($showempty && !is_numeric($showempty)) {
8404 $textifempty = $langs->trans($showempty);
8405 }
8406 }
8407 if ($showempty) {
8408 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8409 }
8410
8411 $i = 0;
8412 while ($num && $i < $num) {
8413 $opt = '';
8414 $optJson = array();
8415 $objp = $this->db->fetch_object($result);
8416
8417 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8418
8419 // Add new entry
8420 // "key" value of json key array is used by jQuery automatically as selected value
8421 // "label" value of json key array is used by jQuery automatically as text for combo box
8422 $out .= $opt;
8423 array_push($outarray, $optJson);
8424
8425 $i++;
8426 }
8427
8428 $out .= '</select>';
8429
8430 $this->db->free($result);
8431
8432 if (empty($outputmode)) {
8433 return $out;
8434 }
8435 return $outarray;
8436 } else {
8437 dol_print_error($this->db);
8438 }
8439
8440 return array();
8441 }
8442
8454 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8455 {
8456 $outkey = '';
8457 $outlabel = '';
8458 $outtype = '';
8459
8460 $outkey = $objp->rowid;
8461 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8462 $outtype = $objp->fk_adherent_type;
8463
8464 $opt = '<option value="' . $objp->rowid . '"';
8465 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8466 $opt .= '>';
8467 if (!empty($filterkey) && $filterkey != '') {
8468 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8469 }
8470 $opt .= $outlabel;
8471 $opt .= "</option>\n";
8472
8473 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8474 }
8475
8496 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8497 {
8498 global $conf, $extrafields, $user;
8499
8500 // Example of common usage for a link to a thirdparty
8501
8502 // We got this in a modulebuilder form of "MyObject" of module "mymodule".
8503 // ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8504 // $objectdesc = 'Societe'
8505 // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc'])
8506
8507 // We got this when showing an extrafields on resource that is a link to societe
8508 // extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)'
8509 // $objectdesc = 'Societe'
8510 // $objectfield = 'resource:options_link_to_societe'
8511
8512 // With old usage:
8513 // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))'
8514 // $objectfield = ''
8515
8516 //var_dump($objectdesc.' '.$objectfield);
8517 //debug_print_backtrace();
8518
8519 $objectdescorig = $objectdesc;
8520 $objecttmp = null;
8521 $InfoFieldList = array();
8522 $classname = '';
8523 $filter = ''; // Ensure filter has value (for static analysis)
8524 $sortfield = ''; // Ensure filter has value (for static analysis)
8525
8526 if ($objectfield) { // We must retrieve the objectdesc from the field or extrafield
8527 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8528 $tmparray = explode(':', $objectfield);
8529
8530 // Get instance of object from $element
8531 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8532
8533 if (is_object($objectforfieldstmp)) {
8534 $objectdesc = '';
8535
8536 $reg = array();
8537 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8538 // For a property in extrafields
8539 $key = $reg[1];
8540 // fetch optionals attributes and labels
8541 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8542
8543 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8544 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8545 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8546 $objectdesc = $tmpextrafields[0];
8547 }
8548 }
8549 } else {
8550 // For a property in ->fields
8551 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8552 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8553 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8554 }
8555 }
8556 }
8557 }
8558
8559 if ($objectdesc) {
8560 // Example of value for $objectdesc:
8561 // Bom:bom/class/bom.class.php:0:t.status=1
8562 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8563 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8564 $InfoFieldList = explode(":", $objectdesc, 4);
8565 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8566 $reg = array();
8567 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8568 $InfoFieldList[4] = $reg[1]; // take the sort field
8569 }
8570 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8571
8572 $classname = $InfoFieldList[0];
8573 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8574 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8575 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8576 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8577
8578 // Load object according to $id and $element
8579 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8580
8581 // Fallback to another solution to get $objecttmp
8582 if (empty($objecttmp) && !empty($classpath)) {
8583 dol_include_once($classpath);
8584
8585 if ($classname && class_exists($classname)) {
8586 $objecttmp = new $classname($this->db);
8587 }
8588 }
8589 }
8590
8591 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
8592 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
8593 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
8594 $filter = str_replace(
8595 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
8596 array($conf->entity, $sharedentities, $user->id),
8597 $filter
8598 );
8599
8600 if (!is_object($objecttmp)) {
8601 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc, LOG_WARNING);
8602 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc;
8603 }
8604 '@phan-var-force CommonObject $objecttmp';
8606 //var_dump($filter);
8607 $prefixforautocompletemode = $objecttmp->element;
8608 if ($prefixforautocompletemode == 'societe') {
8609 $prefixforautocompletemode = 'company';
8610 }
8611 if ($prefixforautocompletemode == 'product') {
8612 $prefixforautocompletemode = 'produit';
8613 }
8614 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8615
8616 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
8617
8618 // Generate the combo HTML component
8619 $out = '';
8620 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
8621 // No immediate load of all database
8622 $placeholder = '';
8623
8624 if ($preSelectedValue && empty($selected_input_value)) {
8625 $objecttmp->fetch($preSelectedValue);
8626 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
8627
8628 $oldValueForShowOnCombobox = 0;
8629 foreach ($objecttmp->fields as $fieldK => $fielV) {
8630 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
8631 continue;
8632 }
8633
8634 if (!$oldValueForShowOnCombobox) {
8635 $selected_input_value = '';
8636 }
8637
8638 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
8639 $selected_input_value .= $objecttmp->$fieldK;
8640 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
8641 }
8642 }
8643
8644 // Set url and param to call to get json of the search results
8645 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
8646 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . '&objectfield='.urlencode($objectfield) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
8647
8648 // Activate the auto complete using ajax call.
8649 $out .= ajax_autocompleter((string) $preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalInt($confkeyforautocompletemode), 0);
8650 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
8651 $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) . '"' : '') . ' />';
8652 } else {
8653 // Immediate load of table record.
8654 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
8655 }
8656
8657 return $out;
8658 }
8659
8660
8681 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
8682 {
8683 global $langs, $user, $hookmanager;
8684
8685 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
8686
8687 $prefixforautocompletemode = $objecttmp->element;
8688 if ($prefixforautocompletemode == 'societe') {
8689 $prefixforautocompletemode = 'company';
8690 }
8691 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8692
8693 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
8694 $tmpfieldstoshow = '';
8695 foreach ($objecttmp->fields as $key => $val) {
8696 if (! (int) dol_eval($val['enabled'], 1, 1, '1')) {
8697 continue;
8698 }
8699 if (!empty($val['showoncombobox'])) {
8700 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8701 }
8702 }
8703 if ($tmpfieldstoshow) {
8704 $fieldstoshow = $tmpfieldstoshow;
8705 }
8706 } elseif ($objecttmp->element === 'category') {
8707 $fieldstoshow = 't.label';
8708 } else {
8709 // For backward compatibility
8710 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8711 }
8712
8713 if (empty($fieldstoshow)) {
8714 if (!empty($objecttmp->parent_element)) {
8715 $fieldstoshow = 'o.ref';
8716 if (empty($sortfield)) {
8717 $sortfield = 'o.ref';
8718 }
8719 if (in_array($objecttmp->element, ['commandedet', 'propaldet', 'facturedet', 'expeditiondet'])) {
8720 $fieldstoshow .= ',p.ref AS p_ref,p.label,t.description';
8721 $sortfield .= ', p.ref';
8722 }
8723 } elseif (isset($objecttmp->fields['ref'])) {
8724 $fieldstoshow = 't.ref';
8725 } else {
8726 $langs->load("errors");
8727 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8728 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8729 }
8730 }
8731
8732 $out = '';
8733 $outarray = array();
8734 $tmparray = array();
8735
8736 $num = 0;
8737
8738 // Search data
8739 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . " as t";
8740 if (!empty($objecttmp->isextrafieldmanaged)) {
8741 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . "_extrafields as e ON t.rowid = e.fk_object";
8742 }
8743 if (!empty($objecttmp->parent_element)) {
8744 $parent_properties = getElementProperties($objecttmp->parent_element);
8745 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($parent_properties['table_element']) . " as o ON o.rowid = t.".$objecttmp->fk_parent_attribute;
8746 }
8747 if (in_array($objecttmp->parent_element, ['commande', 'propal', 'facture', 'expedition'])) {
8748 $sql .= " LEFT JOIN " . $this->db->prefix() . "product as p ON p.rowid = t.fk_product";
8749 }
8750 if (isset($objecttmp->ismultientitymanaged)) {
8751 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8752 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8753 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($tmparray[1]) . " as parenttable ON parenttable.rowid = t." . $this->db->sanitize($tmparray[0]);
8754 }
8755 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8756 if (!$user->hasRight('societe', 'client', 'voir')) {
8757 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8758 }
8759 }
8760 }
8761
8762 // Add where from hooks
8763 $parameters = array(
8764 'object' => $objecttmp,
8765 'htmlname' => $htmlname,
8766 'filter' => $filter,
8767 'searchkey' => $searchkey
8768 );
8769
8770 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8771 if (!empty($hookmanager->resPrint)) {
8772 $sql .= $hookmanager->resPrint;
8773 } else {
8774 $sql .= " WHERE 1=1";
8775 if (isset($objecttmp->ismultientitymanaged)) {
8776 if ($objecttmp->ismultientitymanaged == 1) {
8777 $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8778 }
8779 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8780 $sql .= " AND parenttable.entity = t." . $this->db->sanitize($tmparray[0]);
8781 }
8782 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8783 if ($objecttmp->element == 'societe') {
8784 $sql .= " AND t.rowid = " . ((int) $user->socid);
8785 } else {
8786 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8787 }
8788 }
8789 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8790 if (!$user->hasRight('societe', 'client', 'voir')) {
8791 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8792 }
8793 }
8794 }
8795 $splittedfieldstoshow = explode(',', $fieldstoshow);
8796 foreach ($splittedfieldstoshow as &$field2) {
8797 if (is_numeric($pos = strpos($field2, ' '))) {
8798 $field2 = substr($field2, 0, $pos);
8799 }
8800 }
8801 if ($searchkey != '') {
8802 $sql .= natural_search($splittedfieldstoshow, $searchkey);
8803 }
8804
8805 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8806 $errormessage = '';
8807 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8808 if ($errormessage) {
8809 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8810 }
8811 }
8812 }
8813 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8814 //$sql.=$this->db->plimit($limit, 0);
8815 //print $sql;
8816
8817 // Build output string
8818 $resql = $this->db->query($sql);
8819 if ($resql) {
8820 // Construct $out and $outarray
8821 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8822
8823 // 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
8824 $textifempty = '&nbsp;';
8825
8826 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8827 if (getDolGlobalInt($confkeyforautocompletemode)) {
8828 if ($showempty && !is_numeric($showempty)) {
8829 $textifempty = $langs->trans($showempty);
8830 } else {
8831 $textifempty .= $langs->trans("All");
8832 }
8833 }
8834 if ($showempty) {
8835 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8836 }
8837
8838 $num = $this->db->num_rows($resql);
8839 $i = 0;
8840 if ($num) {
8841 while ($i < $num) {
8842 $obj = $this->db->fetch_object($resql);
8843 $label = '';
8844 $labelhtml = '';
8845 $tmparray = explode(',', $fieldstoshow);
8846 $oldvalueforshowoncombobox = 0;
8847 foreach ($tmparray as $key => $val) {
8848 $val = preg_replace('/(t|p|o)\./', '', $val);
8849 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8850 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8851 $label .= $obj->$val;
8852 $labelhtml .= $obj->$val;
8853
8854 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8855 }
8856 if (empty($outputmode)) {
8857 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8858 $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>';
8859 } else {
8860 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8861 }
8862 } else {
8863 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8864 }
8865
8866 $i++;
8867 if (($i % 10) == 0) {
8868 $out .= "\n";
8869 }
8870 }
8871 }
8872
8873 $out .= '</select>' . "\n";
8874
8875 if (!$forcecombo) {
8876 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8877 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
8878 }
8879 } else {
8880 dol_print_error($this->db);
8881 }
8882
8883 $this->result = array('nbofelement' => $num);
8884
8885 if ($outputmode) {
8886 return $outarray;
8887 }
8888 return $out;
8889 }
8890
8891
8915 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)
8916 {
8917 global $conf, $langs;
8918
8919 // Do we want a multiselect ?
8920 //$jsbeautify = 0;
8921 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8922 $jsbeautify = 1;
8923
8924 if ($value_as_key) {
8925 $array = array_combine($array, $array);
8926 }
8927
8928 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
8929
8930 $out = '';
8931
8932 if ($addjscombo < 0) {
8933 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8934 $addjscombo = 1;
8935 } else {
8936 $addjscombo = 0;
8937 }
8938 }
8939 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8940 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8941 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8942 $out .= '>'."\n";
8943
8944 if ($show_empty) {
8945 $textforempty = ' ';
8946 if (!empty($conf->use_javascript_ajax)) {
8947 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8948 }
8949 if (!is_numeric($show_empty)) {
8950 $textforempty = $show_empty;
8951 }
8952 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8953 }
8954 if (is_array($array)) {
8955 // Translate
8956 if ($translate) {
8957 foreach ($array as $key => $value) {
8958 if (!is_array($value)) {
8959 $array[$key] = $langs->trans($value);
8960 } else {
8961 $array[$key]['label'] = $langs->trans($value['label']);
8962 }
8963 }
8964 }
8965 // Sort
8966 if ($sort == 'ASC') {
8967 asort($array);
8968 } elseif ($sort == 'DESC') {
8969 arsort($array);
8970 }
8971
8972 foreach ($array as $key => $tmpvalue) {
8973 if (is_array($tmpvalue)) {
8974 $value = $tmpvalue['label'];
8975 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
8976 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8977 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8978 } else {
8979 $value = $tmpvalue;
8980 //$valuehtml = $tmpvalue;
8981 $disabled = '';
8982 $style = '';
8983 }
8984 if (!empty($disablebademail)) {
8985 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8986 || ($disablebademail == 2 && preg_match('/---/', $value))) {
8987 $disabled = ' disabled';
8988 $style = ' class="warning"';
8989 }
8990 }
8991 if ($key_in_label) {
8992 if (empty($nohtmlescape)) {
8993 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8994 } else {
8995 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8996 }
8997 } else {
8998 if (empty($nohtmlescape)) {
8999 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
9000 } else {
9001 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
9002 }
9003 if ($value == '' || $value == '-') {
9004 $selectOptionValue = '&nbsp;';
9005 }
9006 }
9007 $out .= '<option value="' . $key . '"';
9008 $out .= $style . $disabled;
9009 if (is_array($id)) {
9010 if (in_array($key, $id) && !$disabled) {
9011 $out .= ' selected'; // To preselect a value
9012 }
9013 } else {
9014 $id = (string) $id; // if $id = 0, then $id = '0'
9015 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
9016 $out .= ' selected'; // To preselect a value
9017 }
9018 }
9019 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
9020 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
9021 }
9022
9023 if (is_array($tmpvalue)) {
9024 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
9025 if ($keyforvalue == 'labelhtml') {
9026 $keyforvalue = 'data-html';
9027 }
9028 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
9029 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
9030 }
9031 }
9032 }
9033 $out .= '>';
9034 $out .= $selectOptionValue;
9035 $out .= "</option>\n";
9036 }
9037 }
9038 $out .= "</select>";
9039
9040 // Add code for jquery to use multiselect
9041 if ($addjscombo && $jsbeautify) {
9042 // Enhance with select2
9043 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9044 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
9045 }
9046
9047 return $out;
9048 }
9049
9068 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
9069 {
9070 global $conf;
9071 global $delayedhtmlcontent; // Will be used later outside of this function
9072
9073 // TODO Use an internal dolibarr component instead of select2
9074 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9075 return '';
9076 }
9077
9078 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
9079
9080 $outdelayed = '';
9081 if (!empty($conf->use_javascript_ajax)) {
9082 $tmpplugin = 'select2';
9083 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9084 <script nonce="' . getNonce() . '">
9085 $(document).ready(function () {
9086
9087 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
9088
9089 $(".' . $htmlname . '").select2({
9090 ajax: {
9091 dir: "ltr",
9092 url: "' . $url . '",
9093 dataType: \'json\',
9094 delay: 250,
9095 data: function (params) {
9096 return {
9097 q: params.term, // search term
9098 page: params.page
9099 }
9100 },
9101 processResults: function (data) {
9102 // parse the results into the format expected by Select2.
9103 // since we are using custom formatting functions we do not need to alter the remote JSON data
9104 //console.log(data);
9105 saveRemoteData = data;
9106 /* format json result for select2 */
9107 result = []
9108 $.each( data, function( key, value ) {
9109 result.push({id: key, text: value.text});
9110 });
9111 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
9112 //console.log(result);
9113 return {results: result, more: false}
9114 },
9115 cache: true
9116 },
9117 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9118 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9119 placeholder: \'' . dol_escape_js($placeholder) . '\',
9120 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9121 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9122 formatResult: function (result, container, query, escapeMarkup) {
9123 return escapeMarkup(result.text);
9124 },
9125 });
9126
9127 ' . ($callurlonselect ? '
9128 /* Code to execute a GET when we select a value */
9129 $(".' . $htmlname . '").change(function() {
9130 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9131 console.log("We select in selectArrayAjax the entry "+selected)
9132 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9133 $.each( saveRemoteData, function( key, value ) {
9134 if (key == selected)
9135 {
9136 console.log("selectArrayAjax - Do a redirect to "+value.url)
9137 location.assign(value.url);
9138 }
9139 });
9140 });' : '') . '
9141
9142 });
9143 </script>';
9144 }
9145
9146 if ($acceptdelayedhtml) {
9147 $delayedhtmlcontent .= $outdelayed;
9148 } else {
9149 $out .= $outdelayed;
9150 }
9151 return $out;
9152 }
9153
9173 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
9174 {
9175 global $conf;
9176 global $delayedhtmlcontent; // Will be used later outside of this function
9177
9178 // TODO Use an internal dolibarr component instead of select2
9179 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9180 return '';
9181 }
9182
9183 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
9184
9185 $formattedarrayresult = array();
9186
9187 foreach ($array as $key => $value) {
9188 $o = new stdClass();
9189 $o->id = $key;
9190 $o->text = $value['text'];
9191 $o->url = $value['url'];
9192 $formattedarrayresult[] = $o;
9193 }
9194
9195 $outdelayed = '';
9196 if (!empty($conf->use_javascript_ajax)) {
9197 $tmpplugin = 'select2';
9198 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9199 <script nonce="' . getNonce() . '">
9200 $(document).ready(function () {
9201 var data = ' . json_encode($formattedarrayresult) . ';
9202
9203 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
9204
9205 $(\'.' . dol_escape_js($htmlname) . '\').select2({
9206 data: data,
9207 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9208 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9209 placeholder: \'' . dol_escape_js($placeholder) . '\',
9210 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9211 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9212 formatResult: function (result, container, query, escapeMarkup) {
9213 return escapeMarkup(result.text);
9214 },
9215 matcher: function (params, data) {
9216
9217 if(! data.id) return null;';
9218
9219 if ($callurlonselect) {
9220 // We forge the url with 'sall='
9221 $outdelayed .= '
9222
9223 var urlBase = data.url;
9224 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
9225 /* console.log("params.term="+params.term); */
9226 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
9227 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
9228 }
9229
9230 if (!$disableFiltering) {
9231 $outdelayed .= '
9232
9233 if(data.text.match(new RegExp(params.term))) {
9234 return data;
9235 }
9236
9237 return null;';
9238 } else {
9239 $outdelayed .= '
9240
9241 return data;';
9242 }
9243
9244 $outdelayed .= '
9245 }
9246 });
9247
9248 ' . ($callurlonselect ? '
9249 /* Code to execute a GET when we select a value */
9250 $(\'.' . dol_escape_js($htmlname) . '\').change(function() {
9251 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9252 console.log("We select "+selected)
9253
9254 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9255 $.each( saveRemoteData, function( key, value ) {
9256 if (key == selected)
9257 {
9258 console.log("selectArrayFilter - Do a redirect to "+value.url)
9259 location.assign(value.url);
9260 }
9261 });
9262 });' : '') . '
9263
9264 });
9265 </script>';
9266 }
9267
9268 if ($acceptdelayedhtml) {
9269 $delayedhtmlcontent .= $outdelayed;
9270 } else {
9271 $out .= $outdelayed;
9272 }
9273 return $out;
9274 }
9275
9294 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)
9295 {
9296 global $conf, $langs;
9297 $out = '';
9298
9299 if ($addjscombo < 0) {
9300 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9301 $addjscombo = 1;
9302 } else {
9303 $addjscombo = 0;
9304 }
9305 }
9306
9307 $useenhancedmultiselect = 0;
9308 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9309 if ($addjscombo) {
9310 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9311 }
9312 }
9313
9314 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9315 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9316 // submitted to nothing.
9317 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9318 // Output select component
9319 $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";
9320 if (is_array($array) && !empty($array)) {
9321 if ($value_as_key) {
9322 $array = array_combine($array, $array);
9323 }
9324
9325 if (!empty($array)) {
9326 foreach ($array as $key => $value) {
9327 $tmpkey = $key;
9328 $tmpvalue = $value;
9329 $tmpcolor = '';
9330 $tmppicto = '';
9331 $tmplabelhtml = '';
9332 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9333 $tmpkey = $value['id'];
9334 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9335 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9336 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9337 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']) : $value['labelhtml'];
9338 }
9339 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9340 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9341
9342 $out .= '<option value="' . $tmpkey . '"';
9343 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9344 $out .= ' selected';
9345 }
9346 if (!empty($tmplabelhtml)) {
9347 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9348 } else {
9349 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9350 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9351 }
9352 $out .= '>';
9353 $out .= dol_htmlentitiesbr($newval);
9354 $out .= '</option>' . "\n";
9355 }
9356 }
9357 }
9358 $out .= '</select>' . "\n";
9359
9360 // Add code for jquery to use multiselect
9361 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9362 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9363 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9364 if ($addjscombo == 1) {
9365 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
9366 $out .= 'function formatResult(record, container) {' . "\n";
9367 // If property data-html set, we decode html entities and use this.
9368 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9369 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9370 //$out .= ' console.log("aaa");';
9371 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9372 $out .= ' }'."\n";
9373 $out .= ' return record.text;';
9374 $out .= '}' . "\n";
9375 $out .= 'function formatSelection(record) {' . "\n";
9376 if ($elemtype == 'category') {
9377 $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
9378 } else {
9379 $out .= 'return record.text;';
9380 }
9381 $out .= '}' . "\n";
9382 $out .= '$(document).ready(function () {
9383 $(\'#' . dol_escape_js($htmlname) . '\').' . $tmpplugin . '({';
9384 if ($placeholder) {
9385 $out .= '
9386 placeholder: {
9387 id: \'-1\',
9388 text: \'' . dol_escape_js($placeholder) . '\'
9389 },';
9390 }
9391 $out .= ' dir: \'ltr\',
9392 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9393 dropdownCssClass: \'' . dol_escape_js($morecss) . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
9394 // Specify format function for dropdown item
9395 formatResult: formatResult,
9396 templateResult: formatResult, /* For 4.0 */
9397 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9398 // Specify format function for selected item
9399 formatSelection: formatSelection,
9400 templateSelection: formatSelection, /* For 4.0 */
9401 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage
9402 });
9403
9404 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
9405 the size only if component is not hidden by default on load */
9406 $(\'#' . dol_escape_js($htmlname) . ' + .select2\').addClass(\'' . dol_escape_js($morecss) . '\');
9407 });' . "\n";
9408 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9409 // Add other js lib
9410 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9411 // ...
9412 $out .= 'console.log(\'addjscombo=2 for htmlname=' . dol_escape_js($htmlname) . '\');';
9413 $out .= '$(document).ready(function () {
9414 $(\'#' . dol_escape_js($htmlname) . '\').multiSelect({
9415 containerHTML: \'<div class="multi-select-container">\',
9416 menuHTML: \'<div class="multi-select-menu">\',
9417 buttonHTML: \'<span class="multi-select-button ' . dol_escape_js($morecss) . '">\',
9418 menuItemHTML: \'<label class="multi-select-menuitem">\',
9419 activeClass: \'multi-select-container--open\',
9420 noneText: \'' . dol_escape_js($placeholder) . '\'
9421 });
9422 })';
9423 }
9424 $out .= '</script>';
9425 }
9426
9427 return $out;
9428 }
9429
9430
9442 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9443 {
9444 global $langs, $user;
9445
9446 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9447 return '';
9448 }
9449 if (empty($array)) {
9450 return '';
9451 }
9452
9453 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9454
9455 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9456 $tmparray = explode(',', $user->conf->$tmpvar);
9457 foreach ($array as $key => $val) {
9458 //var_dump($key);
9459 //var_dump($tmparray);
9460 if (in_array($key, $tmparray)) {
9461 $array[$key]['checked'] = 1;
9462 } else {
9463 $array[$key]['checked'] = 0;
9464 }
9465 }
9466 } else { // There is no list of fields already customized for user
9467 foreach ($array as $key => $val) {
9468 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9469 $array[$key]['checked'] = 0;
9470 }
9471 }
9472 }
9473
9474 $listoffieldsforselection = '';
9475 $listcheckedstring = '';
9476
9477 foreach ($array as $key => $val) {
9478 // var_dump($val);
9479 // var_dump(array_key_exists('enabled', $val));
9480 // var_dump(!$val['enabled']);
9481 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9482 unset($array[$key]); // We don't want this field
9483 continue;
9484 }
9485 if (!empty($val['type']) && $val['type'] == 'separate') {
9486 // Field remains in array but we don't add it into $listoffieldsforselection
9487 //$listoffieldsforselection .= '<li>-----</li>';
9488 continue;
9489 }
9490 if (!empty($val['label']) && $val['label']) {
9491 if (!empty($val['langfile']) && is_object($langs)) {
9492 $langs->load($val['langfile']);
9493 }
9494
9495 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9496 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((!array_key_exists('checked', $val) || empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . '/>';
9497 $listoffieldsforselection .= '<label for="checkbox' . $key . '">'.dol_string_nohtmltag($langs->trans($val['label'])) . '</label></li>';
9498 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9499 }
9500 }
9501
9502 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9503
9504 <dl class="dropdown">
9505 <dt>
9506 <a href="#' . $htmlname . '">
9507 ' . img_picto('', 'list') . '
9508 </a>
9509 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9510 </dt>
9511 <dd class="dropdowndd">
9512 <div class="multiselectcheckbox'.$htmlname.'">
9513 <ul class="'.$htmlname.(((string) $pos == '1' || (string) $pos == 'left') ? 'left' : '').'">
9514 <li class="liinputsearch"><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
9515 '.$listoffieldsforselection.'
9516 </ul>
9517 </div>
9518 </dd>
9519 </dl>
9520
9521 <script nonce="' . getNonce() . '" type="text/javascript">
9522 jQuery(document).ready(function () {
9523 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
9524 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9525
9526 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9527
9528 var title = $(this).val() + ",";
9529 if ($(this).is(\':checked\')) {
9530 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9531 }
9532 else {
9533 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9534 }
9535 // Now, we submit page
9536 //$(this).parents(\'form:first\').submit();
9537 });
9538 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9539 var value = $(this).val().toLowerCase();
9540 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9541 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9542 });
9543 });
9544
9545
9546 });
9547 </script>
9548
9549 ';
9550 return $out;
9551 }
9552
9562 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
9563 {
9564 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
9565
9566 $cat = new Categorie($this->db);
9567 $categories = $cat->containing($id, $type);
9568
9569 if ($rendermode == 1) {
9570 $toprint = array();
9571 foreach ($categories as $c) {
9572 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
9573 foreach ($ways as $way) {
9574 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
9575 }
9576 }
9577 if (empty($toprint)) {
9578 return '';
9579 } else {
9580 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
9581 }
9582 }
9583
9584 if ($rendermode == 0) {
9585 $arrayselected = array();
9586 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
9587 foreach ($categories as $c) {
9588 $arrayselected[] = $c->id;
9589 }
9590
9591 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
9592 }
9593
9594 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
9595 }
9596
9606 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
9607 {
9608 global $conf, $langs, $hookmanager;
9609 global $action;
9610
9611 $object->fetchObjectLinked();
9612
9613 // Bypass the default method
9614 $hookmanager->initHooks(array('commonobject'));
9615 $parameters = array(
9616 'morehtmlright' => $morehtmlright,
9617 'compatibleImportElementsList' => &$compatibleImportElementsList,
9618 );
9619 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9620
9621 $nbofdifferenttypes = count($object->linkedObjects);
9622
9623 if (empty($reshook)) {
9624 print '<!-- showLinkedObjectBlock -->';
9625 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, '', 'showlinkedobjectblock');
9626
9627
9628 print '<div class="div-table-responsive-no-min">';
9629 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
9630
9631 print '<tr class="liste_titre">';
9632 print '<td>' . $langs->trans("Type") . '</td>';
9633 print '<td>' . $langs->trans("Ref") . '</td>';
9634 print '<td class="center"></td>';
9635 print '<td class="center">' . $langs->trans("Date") . '</td>';
9636 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9637 print '<td class="right">' . $langs->trans("Status") . '</td>';
9638 print '<td></td>';
9639 print '</tr>';
9640
9641 $nboftypesoutput = 0;
9642
9643 foreach ($object->linkedObjects as $objecttype => $objects) {
9644 $tplpath = $element = $subelement = $objecttype;
9645
9646 // to display import button on tpl
9647 $showImportButton = false;
9648 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
9649 $showImportButton = true;
9650 }
9651
9652 $regs = array();
9653 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
9654 $element = $regs[1];
9655 $subelement = $regs[2];
9656 $tplpath = $element . '/' . $subelement;
9657 }
9658 $tplname = 'linkedobjectblock';
9659
9660 // To work with non standard path
9661 if ($objecttype == 'facture') {
9662 $tplpath = 'compta/' . $element;
9663 if (!isModEnabled('invoice')) {
9664 continue; // Do not show if module disabled
9665 }
9666 } elseif ($objecttype == 'facturerec') {
9667 $tplpath = 'compta/facture';
9668 $tplname = 'linkedobjectblockForRec';
9669 if (!isModEnabled('invoice')) {
9670 continue; // Do not show if module disabled
9671 }
9672 } elseif ($objecttype == 'propal') {
9673 $tplpath = 'comm/' . $element;
9674 if (!isModEnabled('propal')) {
9675 continue; // Do not show if module disabled
9676 }
9677 } elseif ($objecttype == 'supplier_proposal') {
9678 if (!isModEnabled('supplier_proposal')) {
9679 continue; // Do not show if module disabled
9680 }
9681 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
9682 $tplpath = 'expedition';
9683 if (!isModEnabled('shipping')) {
9684 continue; // Do not show if module disabled
9685 }
9686 } elseif ($objecttype == 'reception') {
9687 $tplpath = 'reception';
9688 if (!isModEnabled('reception')) {
9689 continue; // Do not show if module disabled
9690 }
9691 } elseif ($objecttype == 'delivery') {
9692 $tplpath = 'delivery';
9693 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
9694 continue; // Do not show if sub module disabled
9695 }
9696 } elseif ($objecttype == 'ficheinter') {
9697 $tplpath = 'fichinter';
9698 if (!isModEnabled('intervention')) {
9699 continue; // Do not show if module disabled
9700 }
9701 } elseif ($objecttype == 'invoice_supplier') {
9702 $tplpath = 'fourn/facture';
9703 } elseif ($objecttype == 'order_supplier') {
9704 $tplpath = 'fourn/commande';
9705 } elseif ($objecttype == 'expensereport') {
9706 $tplpath = 'expensereport';
9707 } elseif ($objecttype == 'subscription') {
9708 $tplpath = 'adherents';
9709 } elseif ($objecttype == 'conferenceorbooth') {
9710 $tplpath = 'eventorganization';
9711 } elseif ($objecttype == 'conferenceorboothattendee') {
9712 $tplpath = 'eventorganization';
9713 } elseif ($objecttype == 'mo') {
9714 $tplpath = 'mrp';
9715 if (!isModEnabled('mrp')) {
9716 continue; // Do not show if module disabled
9717 }
9718 } elseif ($objecttype == 'project_task') {
9719 $tplpath = 'projet/tasks';
9720 }
9721
9722 global $linkedObjectBlock;
9723 $linkedObjectBlock = $objects;
9724
9725 // Output template part (modules that overwrite templates must declare this into descriptor)
9726 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
9727 foreach ($dirtpls as $reldir) {
9728 $reldir = rtrim($reldir, '/');
9729 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
9730 global $noMoreLinkedObjectBlockAfter;
9731 $noMoreLinkedObjectBlockAfter = 1;
9732 }
9733
9734 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
9735 if ($res) {
9736 $nboftypesoutput++;
9737 break;
9738 }
9739 }
9740 }
9741
9742 if (!$nboftypesoutput) {
9743 print '<tr><td colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9744 }
9745
9746 print '</table>';
9747
9748 if (!empty($compatibleImportElementsList)) {
9749 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9750 }
9751
9752 print '</div>';
9753 }
9754
9755 return $nbofdifferenttypes;
9756 }
9757
9767 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array(), $nooutput = 0)
9768 {
9769 global $conf, $langs, $hookmanager, $form;
9770 global $action;
9771
9772 if (empty($form)) {
9773 $form = new Form($this->db);
9774 }
9775
9776 $linktoelem = '';
9777 $linktoelemlist = '';
9778 $listofidcompanytoscan = '';
9779
9780 if (!is_object($object->thirdparty)) {
9781 $object->fetch_thirdparty();
9782 }
9783
9784 $possiblelinks = array();
9785
9786 $dontIncludeCompletedItems = getDolGlobalString('DONT_INCLUDE_COMPLETED_ELEMENTS_LINKS');
9787
9788 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9789 $listofidcompanytoscan = (int) $object->thirdparty->id;
9790 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
9791 $listofidcompanytoscan .= ',' . (int) $object->thirdparty->parent;
9792 }
9793 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
9794 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9795 $tmpproject = new Project($this->db);
9796 $tmpproject->fetch($object->fk_project);
9797 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9798 $listofidcompanytoscan .= ',' . (int) $tmpproject->socid;
9799 }
9800 unset($tmpproject);
9801 }
9802
9803 $possiblelinks = array(
9804 'propal' => array(
9805 'enabled' => isModEnabled('propal'),
9806 'perms' => 1,
9807 'label' => 'LinkToProposal',
9808 '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' : ''),
9809 ),
9810 'shipping' => array(
9811 'enabled' => isModEnabled('shipping'),
9812 'perms' => 1,
9813 'label' => 'LinkToExpedition',
9814 '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' : ''),
9815 ),
9816 'order' => array(
9817 'enabled' => isModEnabled('order'),
9818 'perms' => 1,
9819 'label' => 'LinkToOrder',
9820 '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' : ''),
9821 'linkname' => 'commande',
9822 ),
9823 'invoice' => array(
9824 'enabled' => isModEnabled('invoice'),
9825 'perms' => 1,
9826 'label' => 'LinkToInvoice',
9827 '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' : ''),
9828 'linkname' => 'facture',
9829 ),
9830 'invoice_template' => array(
9831 'enabled' => isModEnabled('invoice'),
9832 'perms' => 1,
9833 'label' => 'LinkToTemplateInvoice',
9834 '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') . ')',
9835 ),
9836 'contrat' => array(
9837 'enabled' => isModEnabled('contract'),
9838 'perms' => 1,
9839 'label' => 'LinkToContract',
9840 '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
9841 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',
9842 ),
9843 'fichinter' => array(
9844 'enabled' => isModEnabled('intervention'),
9845 'perms' => 1,
9846 'label' => 'LinkToIntervention',
9847 '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') . ')',
9848 ),
9849 'supplier_proposal' => array(
9850 'enabled' => isModEnabled('supplier_proposal'),
9851 'perms' => 1,
9852 'label' => 'LinkToSupplierProposal',
9853 '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' : ''),
9854 ),
9855 'order_supplier' => array(
9856 'enabled' => isModEnabled("supplier_order"),
9857 'perms' => 1,
9858 'label' => 'LinkToSupplierOrder',
9859 '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' : ''),
9860 ),
9861 'invoice_supplier' => array(
9862 'enabled' => isModEnabled("supplier_invoice"),
9863 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9864 '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' : ''),
9865 ),
9866 'ticket' => array(
9867 'enabled' => isModEnabled('ticket'),
9868 'perms' => 1,
9869 'label' => 'LinkToTicket',
9870 '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' : ''),
9871 ),
9872 'mo' => array(
9873 'enabled' => isModEnabled('mrp'),
9874 'perms' => 1,
9875 'label' => 'LinkToMo',
9876 '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' : ''),
9877 ),
9878 );
9879 }
9880
9881 if ($object->table_element == 'commande_fournisseur') {
9882 $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' : '');
9883 } elseif ($object->table_element == 'mrp_mo') {
9884 $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' : '');
9885 }
9886
9887 $reshook = 0; // Ensure $reshook is defined for static analysis
9888 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9889 // Can complete the possiblelink array
9890 $hookmanager->initHooks(array('commonobject'));
9891 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9892 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9893 }
9894
9895 if (empty($reshook)) {
9896 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9897 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9898 }
9899 } elseif ($reshook > 0) {
9900 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9901 $possiblelinks = $hookmanager->resArray;
9902 }
9903 }
9904
9905 if (!empty($possiblelinks)) {
9906 $object->fetchObjectLinked();
9907 }
9908
9909 // Build the html part with possible suggested links
9910 $htmltoenteralink = '';
9911 foreach ($possiblelinks as $key => $possiblelink) {
9912 $num = 0;
9913 if (empty($possiblelink['enabled'])) {
9914 continue;
9915 }
9916
9917 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9918 $htmltoenteralink .= '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9919
9920 // Section for free ref input
9921 if (!getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9922 $htmltoenteralink .= '<br>'."\n";
9923 $htmltoenteralink .= '<!-- form to add a link from anywhere -->'."\n";
9924 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9925 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9926 $htmltoenteralink .= '<input type="hidden" name="action" value="addlinkbyref">';
9927 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9928 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9929 $htmltoenteralink .= '<table class="noborder">';
9930 $htmltoenteralink .= '<tr class="liste_titre">';
9931 //print '<td>' . $langs->trans("Ref") . '</td>';
9932 $htmltoenteralink .= '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9933 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9934 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9935 $htmltoenteralink .= '</tr>';
9936 $htmltoenteralink .= '</table>';
9937 $htmltoenteralink .= '</form>';
9938 }
9939
9940 $sql = $possiblelink['sql'];
9941
9942 $resqllist = $this->db->query($sql);
9943 if ($resqllist) {
9944 $num = $this->db->num_rows($resqllist);
9945 $i = 0;
9946
9947 if ($num > 0) {
9948 // Section for free predefined list
9949 if (getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9950 $htmltoenteralink .= '<br>';
9951 }
9952 $htmltoenteralink .= '<!-- form to add a link from object to same thirdparty -->'."\n";
9953 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9954 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9955 $htmltoenteralink .= '<input type="hidden" name="action" value="addlink">';
9956 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9957 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9958 $htmltoenteralink .= '<table class="noborder">';
9959 $htmltoenteralink .= '<tr class="liste_titre">';
9960 $htmltoenteralink .= '<td class="nowrap"></td>';
9961 $htmltoenteralink .= '<td>' . $langs->trans("Ref") . '</td>';
9962 $htmltoenteralink .= '<td>' . $langs->trans("RefCustomer") . '</td>';
9963 $htmltoenteralink .= '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9964 $htmltoenteralink .= '<td>' . $langs->trans("Company") . '</td>';
9965 $htmltoenteralink .= '</tr>';
9966 while ($i < $num) {
9967 $objp = $this->db->fetch_object($resqllist);
9968 $alreadylinked = false;
9969 if (!empty($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key])) {
9970 if (in_array($objp->rowid, array_values($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key]))) {
9971 $alreadylinked = true;
9972 }
9973 }
9974 $htmltoenteralink .= '<tr class="oddeven">';
9975 $htmltoenteralink .= '<td>';
9976 if ($alreadylinked) {
9977 $htmltoenteralink .= img_picto('', 'link');
9978 } else {
9979 $htmltoenteralink .= '<input type="checkbox" name="idtolinkto[' . $key . '_' . $objp->rowid . ']" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9980 }
9981 $htmltoenteralink .= '</td>';
9982 $htmltoenteralink .= '<td><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9983 $htmltoenteralink .= '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9984 $htmltoenteralink .= '<td class="right">';
9985 if ($possiblelink['label'] == 'LinkToContract') {
9986 $htmltoenteralink .= $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9987 }
9988 $htmltoenteralink .= '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9989 $htmltoenteralink .= '</td>';
9990 $htmltoenteralink .= '<td>' . $objp->name . '</td>';
9991 $htmltoenteralink .= '</tr>';
9992 $i++;
9993 }
9994 $htmltoenteralink .= '</table>';
9995 $htmltoenteralink .= '<div class="center">';
9996 if ($num) {
9997 $htmltoenteralink .= '<input type="submit" class="button valignmiddle marginleftonly marginrightonly smallpaddingimp" value="' . $langs->trans('ToLink') . '">';
9998 }
9999 if (empty($conf->use_javascript_ajax)) {
10000 $htmltoenteralink .= '<input type="submit" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
10001 } else {
10002 $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>';
10003 }
10004 $htmltoenteralink .= '</form>';
10005 }
10006
10007 $this->db->free($resqllist);
10008 } else {
10009 dol_print_error($this->db);
10010 }
10011 $htmltoenteralink .= '</div>';
10012
10013
10014 // Complete the list for the combo box
10015 if ($num > 0 || !getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10016 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
10017 // } else $linktoelem.=$langs->trans($possiblelink['label']);
10018 } else {
10019 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
10020 }
10021 }
10022 }
10023
10024 if ($linktoelemlist) {
10025 $linktoelem = '
10026 <dl class="dropdown" id="linktoobjectname">
10027 ';
10028 if (!empty($conf->use_javascript_ajax)) {
10029 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
10030 }
10031 $linktoelem .= '<dd>
10032 <div class="multiselectlinkto">
10033 <ul class="ulselectedfields">' . $linktoelemlist . '
10034 </ul>
10035 </div>
10036 </dd>
10037 </dl>';
10038 } else {
10039 $linktoelem = '';
10040 }
10041
10042 if (!empty($conf->use_javascript_ajax)) {
10043 print '<!-- Add js to show linkto box -->
10044 <script nonce="' . getNonce() . '">
10045 jQuery(document).ready(function() {
10046 jQuery(".linkto").click(function() {
10047 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
10048 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
10049 });
10050 });
10051 </script>
10052 ';
10053 }
10054
10055 if ($nooutput) {
10056 return array('linktoelem' => $linktoelem, 'htmltoenteralink' => $htmltoenteralink);
10057 } else {
10058 print $htmltoenteralink;
10059 }
10060
10061 return $linktoelem;
10062 }
10063
10078 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'width75', $labelyes = 'Yes', $labelno = 'No')
10079 {
10080 global $langs;
10081
10082 $yes = "yes";
10083 $no = "no";
10084 if ($option) {
10085 $yes = "1";
10086 $no = "0";
10087 }
10088
10089 $disabled = ($disabled ? ' disabled' : '');
10090
10091 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
10092 if ($useempty) {
10093 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10094 }
10095 if (("$value" == 'yes') || ($value == 1)) {
10096 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
10097 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
10098 } else {
10099 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
10100 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
10101 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
10102 }
10103 $resultyesno .= '</select>' . "\n";
10104
10105 if ($addjscombo) {
10106 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
10107 }
10108
10109 return $resultyesno;
10110 }
10111
10112 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10113
10123 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
10124 {
10125 // phpcs:enable
10126 $sql = "SELECT rowid, label";
10127 $sql .= " FROM " . $this->db->prefix() . "export_model";
10128 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
10129 $sql .= " ORDER BY rowid";
10130 $result = $this->db->query($sql);
10131 if ($result) {
10132 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
10133 if ($useempty) {
10134 print '<option value="-1">&nbsp;</option>';
10135 }
10136
10137 $num = $this->db->num_rows($result);
10138 $i = 0;
10139 while ($i < $num) {
10140 $obj = $this->db->fetch_object($result);
10141 if ($selected == $obj->rowid) {
10142 print '<option value="' . $obj->rowid . '" selected>';
10143 } else {
10144 print '<option value="' . $obj->rowid . '">';
10145 }
10146 print $obj->label;
10147 print '</option>';
10148 $i++;
10149 }
10150 print "</select>";
10151 } else {
10152 dol_print_error($this->db);
10153 }
10154 }
10155
10174 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
10175 {
10176 global $conf, $langs, $hookmanager, $extralanguages;
10177
10178 $ret = '';
10179 if (empty($fieldid)) {
10180 $fieldid = 'rowid';
10181 }
10182 if (empty($fieldref)) {
10183 $fieldref = 'ref';
10184 }
10185
10186 // Preparing gender's display if there is one
10187 $addgendertxt = '';
10188 if (property_exists($object, 'gender') && !empty($object->gender)) {
10189 $addgendertxt = ' ';
10190 switch ($object->gender) {
10191 case 'man':
10192 $addgendertxt .= '<i class="fas fa-mars valignmiddle"></i>';
10193 break;
10194 case 'woman':
10195 $addgendertxt .= '<i class="fas fa-venus valignmiddle"></i>';
10196 break;
10197 case 'other':
10198 $addgendertxt .= '<i class="fas fa-transgender valignmiddle"></i>';
10199 break;
10200 }
10201 }
10202
10203 // Add where from hooks
10204 if (is_object($hookmanager)) {
10205 $parameters = array('showrefnav' => true);
10206 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
10207 if (!empty($hookmanager->resPrint)) {
10208 if (empty($object->next_prev_filter) && preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10209 $object->next_prev_filter = preg_replace('/^\s*AND\s*/i', '', $hookmanager->resPrint);
10210 } elseif (!empty($object->next_prev_filter) && !preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10211 $object->next_prev_filter .= ' AND '.$hookmanager->resPrint;
10212 } else {
10213 $object->next_prev_filter .= $hookmanager->resPrint;
10214 }
10215 }
10216 }
10217
10218 $previous_ref = $next_ref = '';
10219 if ($shownav) {
10220 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
10221 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
10222
10223 $navurl = $_SERVER["PHP_SELF"];
10224 // Special case for project/task page
10225 if ($paramid == 'project_ref') {
10226 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
10227 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
10228 $paramid = 'ref';
10229 }
10230 }
10231
10232 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
10233 // accesskey is for Mac: CTRL + key for all browsers
10234 $stringforfirstkey = $langs->trans("KeyboardShortcut");
10235 if ($conf->browser->name == 'chrome') {
10236 $stringforfirstkey .= ' ALT +';
10237 } elseif ($conf->browser->name == 'firefox') {
10238 $stringforfirstkey .= ' ALT + SHIFT +';
10239 } else {
10240 $stringforfirstkey .= ' CTL +';
10241 }
10242
10243 $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>';
10244 $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>';
10245 }
10246
10247 //print "xx".$previous_ref."x".$next_ref;
10248 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
10249
10250 // Right part of banner
10251 if ($morehtmlright) {
10252 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
10253 }
10254
10255 if ($previous_ref || $next_ref || $morehtml) {
10256 $ret .= '<div class="pagination paginationref"><ul class="right">';
10257 }
10258 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
10259 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
10260 }
10261 if ($shownav && ($previous_ref || $next_ref)) {
10262 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
10263 $ret .= '<li class="pagination">' . $next_ref . '</li>';
10264 }
10265 if ($previous_ref || $next_ref || $morehtml) {
10266 $ret .= '</ul></div>';
10267 }
10268
10269 // Status
10270 $parameters = array('morehtmlstatus' => $morehtmlstatus);
10271 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
10272 if (empty($reshook)) {
10273 $morehtmlstatus .= $hookmanager->resPrint;
10274 } else {
10275 $morehtmlstatus = $hookmanager->resPrint;
10276 }
10277 if ($morehtmlstatus) {
10278 $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
10279 }
10280
10281 $parameters = array();
10282 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
10283 if (empty($reshook)) {
10284 $morehtmlref .= $hookmanager->resPrint;
10285 } elseif ($reshook > 0) {
10286 $morehtmlref = $hookmanager->resPrint;
10287 }
10288
10289 // Left part of banner
10290 if ($morehtmlleft) {
10291 if ($conf->browser->layout == 'phone') {
10292 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
10293 } else {
10294 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
10295 }
10296 }
10297
10298 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
10299 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
10300
10301 // For thirdparty, contact, user, member, the ref is the id, so we show something else
10302 if ($object->element == 'societe') {
10303 $ret .= dol_htmlentities($object->name);
10304
10305 // List of extra languages
10306 $arrayoflangcode = array();
10307 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
10308 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
10309 }
10310
10311 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
10312 if (!is_object($extralanguages)) {
10313 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
10314 $extralanguages = new ExtraLanguages($this->db);
10315 }
10316 $extralanguages->fetch_name_extralanguages('societe');
10317
10318 // Guard against PHP 8 'Undefined array key' when MAIN_USE_ALTERNATE_TRANSLATION_FOR
10319 // is not configured and fetch_name_extralanguages() leaves attributes empty (issue #34596).
10320 if (!empty($extralanguages->attributes['societe']) && !empty($extralanguages->attributes['societe']['name'])) {
10321 $object->fetchValuesForExtraLanguages();
10322
10323 $htmltext = '';
10324 // If there is extra languages
10325 foreach ($arrayoflangcode as $extralangcode) {
10326 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
10327 if ($object->array_languages['name'][$extralangcode]) {
10328 $htmltext .= $object->array_languages['name'][$extralangcode];
10329 } else {
10330 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
10331 }
10332 }
10333 $ret .= '<!-- Show translations of name -->' . "\n";
10334 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
10335 }
10336 }
10337 } elseif ($object->element == 'member') {
10338 '@phan-var-force Adherent $object';
10339 $ret .= $object->ref . '<br>';
10340 $fullname = $object->getFullName($langs);
10341 if ($object->morphy == 'mor' && $object->societe) {
10342 $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
10343 } else {
10344 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
10345 }
10346 } elseif (in_array($object->element, array('contact', 'user'))) {
10347 $ret .= '<span class="valignmiddle">'.dol_htmlentities($object->getFullName($langs)).'</span>'.$addgendertxt;
10348 } elseif ($object->element == 'usergroup') {
10349 $ret .= dol_htmlentities($object->name);
10350 } elseif (in_array($object->element, array('action', 'agenda'))) {
10351 '@phan-var-force ActionComm $object';
10352 $ret .= $object->ref . '<br>' . $object->label;
10353 } elseif (in_array($object->element, array('adherent_type'))) {
10354 $ret .= $object->label;
10355 } elseif ($object->element == 'ecm_directories') {
10356 $ret .= '';
10357 } elseif ($fieldref != 'none') {
10358 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
10359 }
10360 if ($morehtmlref) {
10361 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
10362 if (substr($morehtmlref, 0, 4) != '<div') {
10363 $ret .= ' ';
10364 }
10365
10366 $ret .= '<!-- morehtmlref -->'.$morehtmlref;
10367 }
10368
10369 $ret .= '</div>';
10370
10371 $ret .= '</div><!-- End banner content -->';
10372
10373 return $ret;
10374 }
10375
10376
10385 public function showbarcode(&$object, $width = 100, $morecss = '')
10386 {
10387 global $conf;
10388
10389 //Check if barcode is filled in the card
10390 if (empty($object->barcode)) {
10391 return '';
10392 }
10393
10394 // Complete object if not complete
10395 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10396 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10397 $result = $object->fetchBarCode();
10398 //Check if fetchBarCode() failed
10399 if ($result < 1) {
10400 return '<!-- ErrorFetchBarcode -->';
10401 }
10402 }
10403
10404 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10405 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10406 $out = '<!-- url barcode = ' . $url . ' -->';
10407 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10408
10409 return $out;
10410 }
10411
10429 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10430 {
10431 global $conf, $langs;
10432
10433 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10434 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10435
10436 $dir = '';
10437 $file = '';
10438 $originalfile = '';
10439 $altfile = '';
10440 $email = '';
10441 $capture = '';
10442 if ($modulepart == 'societe') {
10443 $dir = $conf->societe->multidir_output[$entity];
10444 if (!empty($object->logo)) {
10445 if (dolIsAllowedForPreview($object->logo)) {
10446 if ((string) $imagesize == 'mini') {
10447 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10448 } elseif ((string) $imagesize == 'small') {
10449 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10450 } else {
10451 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10452 }
10453 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10454 }
10455 }
10456 $email = $object->email;
10457 } elseif ($modulepart == 'contact') {
10458 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10459 if (!empty($object->photo)) {
10460 if (dolIsAllowedForPreview($object->photo)) {
10461 if ((string) $imagesize == 'mini') {
10462 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10463 } elseif ((string) $imagesize == 'small') {
10464 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10465 } else {
10466 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10467 }
10468 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10469 }
10470 }
10471 $email = $object->email;
10472 $capture = 'user';
10473 } elseif ($modulepart == 'userphoto') {
10474 $dir = $conf->user->dir_output;
10475 if (!empty($object->photo)) {
10476 if (dolIsAllowedForPreview($object->photo)) {
10477 if ((string) $imagesize == 'mini') {
10478 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10479 } elseif ((string) $imagesize == 'small') {
10480 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10481 } else {
10482 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10483 }
10484 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10485 }
10486 }
10487 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10488 $altfile = $object->id . ".jpg"; // For backward compatibility
10489 }
10490 $email = $object->email;
10491 $capture = 'user';
10492 } elseif ($modulepart == 'memberphoto') {
10493 $dir = $conf->adherent->dir_output;
10494 if (!empty($object->photo)) {
10495 if (dolIsAllowedForPreview($object->photo)) {
10496 if ((string) $imagesize == 'mini') {
10497 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10498 } elseif ((string) $imagesize == 'small') {
10499 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10500 } else {
10501 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10502 }
10503 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10504 }
10505 }
10506 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10507 $altfile = $object->id . ".jpg"; // For backward compatibility
10508 }
10509 $email = $object->email;
10510 $capture = 'user';
10511 } else {
10512 // Generic case to show photos
10513 // TODO Implement this method in previous objects so we can always use this generic method.
10514 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10515 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10516
10517 $dir = $tmpdata['dir'];
10518 $file = $tmpdata['file'];
10519 $originalfile = $tmpdata['originalfile'];
10520 $altfile = $tmpdata['altfile'];
10521 $email = $tmpdata['email'];
10522 $capture = $tmpdata['capture'];
10523 }
10524 }
10525
10526 if ($forcecapture) {
10527 $capture = $forcecapture;
10528 }
10529
10530 $ret = '';
10531
10532 if ($dir) {
10533 if ($file && file_exists($dir . "/" . $file)) {
10534 if ($addlinktofullsize) {
10535 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10536 if ($urladvanced) {
10537 $ret .= '<a href="' . $urladvanced . '">';
10538 } else {
10539 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10540 }
10541 }
10542 $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 . '">';
10543 if ($addlinktofullsize) {
10544 $ret .= '</a>';
10545 }
10546 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
10547 if ($addlinktofullsize) {
10548 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10549 if ($urladvanced) {
10550 $ret .= '<a href="' . $urladvanced . '">';
10551 } else {
10552 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10553 }
10554 }
10555 $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 . '">';
10556 if ($addlinktofullsize) {
10557 $ret .= '</a>';
10558 }
10559 } else {
10560 $nophoto = '/public/theme/common/nophoto.png';
10561 $defaultimg = 'identicon'; // For gravatar
10562 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
10563 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
10564 $nophoto = 'company';
10565 } else {
10566 $nophoto = '/public/theme/common/user_anonymous.png';
10567 if (!empty($object->gender) && $object->gender == 'man') {
10568 $nophoto = '/public/theme/common/user_man.png';
10569 }
10570 if (!empty($object->gender) && $object->gender == 'woman') {
10571 $nophoto = '/public/theme/common/user_woman.png';
10572 }
10573 }
10574 }
10575
10576 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
10577 // see https://gravatar.com/site/implement/images/php/
10578 $ret .= '<!-- Put link to gravatar -->';
10579 $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
10580 } else {
10581 if ($nophoto == 'company') {
10582 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
10583 //$ret .= '<div class="difforspanimgright"></div>';
10584 } else {
10585 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
10586 }
10587 }
10588 }
10589
10590 if ($caneditfield) {
10591 if ($object->photo) {
10592 $ret .= "<br>\n";
10593 }
10594 $ret .= '<table class="nobordernopadding centpercent">';
10595 if ($object->photo) {
10596 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
10597 }
10598 $ret .= '<tr><td class="tdoverflow">';
10599 $maxfilesizearray = getMaxFileSizeArray();
10600 $maxmin = $maxfilesizearray['maxmin'];
10601 if ($maxmin > 0) {
10602 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
10603 }
10604 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
10605 $ret .= '</td></tr>';
10606 $ret .= '</table>';
10607 }
10608 }
10609
10610 return $ret;
10611 }
10612
10613 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10614
10631 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
10632 {
10633 // phpcs:enable
10634 global $conf, $user, $langs;
10635
10636 // Allow excluding groups
10637 $excludeGroups = null;
10638 if (is_array($exclude)) {
10639 $excludeGroups = implode(",", $exclude);
10640 }
10641 // Allow including groups
10642 $includeGroups = null;
10643 if (is_array($include)) {
10644 $includeGroups = implode(",", $include);
10645 }
10646
10647 if (!is_array($selected)) {
10648 $selected = array($selected);
10649 }
10650
10651 $out = '';
10652
10653 // Build sql to search groups
10654 $sql = "SELECT ug.rowid, ug.nom as name";
10655 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10656 $sql .= ", e.label";
10657 }
10658 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
10659 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10660 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
10661 if ($force_entity) {
10662 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
10663 } else {
10664 $sql .= " WHERE ug.entity IS NOT NULL";
10665 }
10666 } else {
10667 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
10668 }
10669 if (is_array($exclude) && $excludeGroups) {
10670 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
10671 }
10672 if (is_array($include) && $includeGroups) {
10673 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
10674 }
10675 $sql .= " ORDER BY ug.nom ASC";
10676
10677 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
10678 $resql = $this->db->query($sql);
10679 if ($resql) {
10680 // Enhance with select2
10681 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10682
10683 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
10684
10685 $num = $this->db->num_rows($resql);
10686 $i = 0;
10687 if ($num) {
10688 if ($show_empty && !$multiple) {
10689 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10690 }
10691
10692 while ($i < $num) {
10693 $obj = $this->db->fetch_object($resql);
10694 $disableline = 0;
10695 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
10696 $disableline = 1;
10697 }
10698
10699 $label = $obj->name;
10700 $labelhtml = $obj->name;
10701 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
10702 $label .= " (" . $obj->label . ")";
10703 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
10704 }
10705
10706 $out .= '<option value="' . $obj->rowid . '"';
10707 if ($disableline) {
10708 $out .= ' disabled';
10709 }
10710 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
10711 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
10712 $out .= ' selected';
10713 }
10714 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
10715 $out .= '>';
10716 $out .= $label;
10717 $out .= '</option>';
10718 $i++;
10719 }
10720 } else {
10721 if ($show_empty) {
10722 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
10723 }
10724 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
10725 }
10726 $out .= '</select>';
10727
10728 $out .= ajax_combobox($htmlname);
10729 } else {
10730 dol_print_error($this->db);
10731 }
10732
10733 return $out;
10734 }
10735
10736
10743 public function showFilterButtons($pos = '')
10744 {
10745 $out = '<div class="nowraponall">';
10746 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
10747 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
10748 $out .= '</div>';
10749
10750 return $out;
10751 }
10752
10761 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10762 {
10763 global $conf;
10764
10765 $out = '';
10766
10767 if (!empty($conf->use_javascript_ajax)) {
10768 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
10769 }
10770 $out .= '<script nonce="' . getNonce() . '">
10771 $(document).ready(function() {
10772 $("#' . $cssclass . 's").click(function() {
10773 if($(this).is(\':checked\')){
10774 console.log("We check all ' . $cssclass . ' and trigger the change method");
10775 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
10776 }
10777 else
10778 {
10779 console.log("We uncheck all");
10780 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
10781 }' . "\n";
10782 if ($calljsfunction) {
10783 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
10784 }
10785 $out .= ' });
10786 $(".' . $cssclass . '").change(function() {
10787 $(this).closest("tr").toggleClass("highlight", this.checked);
10788 });
10789 });
10790 </script>';
10791
10792 return $out;
10793 }
10794
10804 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10805 {
10806 $out = $this->showFilterButtons();
10807 if ($addcheckuncheckall) {
10808 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10809 }
10810 return $out;
10811 }
10812
10826 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10827 {
10828 global $langs, $user;
10829
10830 $out = '';
10831 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10832 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10833 if (!empty($excludeid)) {
10834 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10835 }
10836 $sql .= " ORDER BY label";
10837
10838 $resql = $this->db->query($sql);
10839 if ($resql) {
10840 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10841 if ($useempty) {
10842 $out .= '<option value="0">&nbsp;</option>';
10843 }
10844
10845 while ($obj = $this->db->fetch_object($resql)) {
10846 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10847 }
10848 $out .= '</select>';
10849 $out .= ajax_combobox('select_' . $htmlname);
10850
10851 if (!empty($htmlname) && $user->admin && $info_admin) {
10852 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10853 }
10854
10855 if (!empty($target)) {
10856 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10857 $resql = $this->db->query($sql);
10858 if ($resql) {
10859 if ($this->db->num_rows($resql) > 0) {
10860 $obj = $this->db->fetch_object($resql);
10861 $out .= '<script nonce="' . getNonce() . '">
10862 $(function() {
10863 $("select[name=' . $target . ']").on("change", function() {
10864 var current_val = $(this).val();
10865 if (current_val == ' . $obj->id . ') {';
10866 if (!empty($default_selected) || !empty($selected)) {
10867 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10868 }
10869
10870 $out .= '
10871 $("select[name=' . $htmlname . ']").change();
10872 }
10873 });
10874
10875 $("select[name=' . $htmlname . ']").change(function() {
10876
10877 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10878 // get price of kilometer to fill the unit price
10879 $.ajax({
10880 method: "POST",
10881 dataType: "json",
10882 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10883 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
10884 }).done(function( data, textStatus, jqXHR ) {
10885 console.log(data);
10886 if (typeof data.up != "undefined") {
10887 $("input[name=value_unit]").val(data.up);
10888 $("select[name=' . $htmlname . ']").attr("title", data.title);
10889 } else {
10890 $("input[name=value_unit]").val("");
10891 $("select[name=' . $htmlname . ']").attr("title", "");
10892 }
10893 });
10894 }
10895 });
10896 });
10897 </script>';
10898 }
10899 }
10900 }
10901 } else {
10902 dol_print_error($this->db);
10903 }
10904
10905 return $out;
10906 }
10907
10916 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10917 {
10918 global $conf, $langs;
10919
10920 $out = '';
10921 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10922 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10923
10924 $resql = $this->db->query($sql);
10925 if ($resql) {
10926 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10927 if ($useempty) {
10928 $out .= '<option value="0"></option>';
10929 }
10930
10931 while ($obj = $this->db->fetch_object($resql)) {
10932 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10933 }
10934 $out .= '</select>';
10935 } else {
10936 dol_print_error($this->db);
10937 }
10938
10939 return $out;
10940 }
10941
10952 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10953 {
10954 global $langs;
10955
10956 $out = '';
10957 $sql = "SELECT id, code, label";
10958 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
10959 $sql .= " WHERE active = 1";
10960
10961 $resql = $this->db->query($sql);
10962 if ($resql) {
10963 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10964 if ($useempty) {
10965 $out .= '<option value="0"></option>';
10966 }
10967 if ($allchoice) {
10968 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10969 }
10970
10971 $field = 'code';
10972 if ($useid) {
10973 $field = 'id';
10974 }
10975
10976 while ($obj = $this->db->fetch_object($resql)) {
10977 $key = $langs->trans($obj->code);
10978 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10979 }
10980 $out .= '</select>';
10981
10982 $out .= ajax_combobox('select_'.$htmlname);
10983 } else {
10984 dol_print_error($this->db);
10985 }
10986
10987 return $out;
10988 }
10989
11008 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)
11009 {
11010 global $user, $conf, $langs;
11011
11012 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
11013
11014 if (is_null($usertofilter)) {
11015 $usertofilter = $user;
11016 }
11017
11018 $out = '';
11019
11020 $hideunselectables = false;
11021 if (getDolGlobalString('PROJECT_HIDE_UNSELECTABLES')) {
11022 $hideunselectables = true;
11023 }
11024
11025 if (empty($projectsListId)) {
11026 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
11027 $projectstatic = new Project($this->db);
11028 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
11029 }
11030 }
11031
11032 // Search all projects
11033 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
11034 p.title, p.fk_soc, p.fk_statut, p.public,";
11035 $sql .= ' s.nom as name';
11036 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
11037 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
11038 $sql .= ' ' . $this->db->prefix() . 'facture as f';
11039 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
11040 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
11041 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
11042 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
11043 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
11044 $sql .= " ORDER BY p.ref, f.ref ASC";
11045
11046 $resql = $this->db->query($sql);
11047 if ($resql) {
11048 // Use select2 selector
11049 if (!empty($conf->use_javascript_ajax)) {
11050 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11051 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11052 $out .= $comboenhancement;
11053 $morecss = 'minwidth200imp maxwidth500';
11054 }
11055
11056 if (empty($option_only)) {
11057 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11058 }
11059 if (!empty($show_empty)) {
11060 $out .= '<option value="0" class="optiongrey">';
11061 if (!is_numeric($show_empty)) {
11062 $out .= $show_empty;
11063 } else {
11064 $out .= '&nbsp;';
11065 }
11066 $out .= '</option>';
11067 }
11068 $num = $this->db->num_rows($resql);
11069 $i = 0;
11070 if ($num) {
11071 while ($i < $num) {
11072 $obj = $this->db->fetch_object($resql);
11073 // 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.
11074 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
11075 // Do nothing
11076 } else {
11077 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11078 $i++;
11079 continue;
11080 }
11081
11082 $labeltoshow = '';
11083
11084 if ($showproject == 'all') {
11085 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
11086 if ($obj->name) {
11087 $labeltoshow .= ' - ' . $obj->name; // Soc name
11088 }
11089
11090 $disabled = 0;
11091 if ($obj->fk_statut == Project::STATUS_DRAFT) {
11092 $disabled = 1;
11093 $labeltoshow .= ' - ' . $langs->trans("Draft");
11094 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
11095 if ($discard_closed == 2) {
11096 $disabled = 1;
11097 }
11098 $labeltoshow .= ' - ' . $langs->trans("Closed");
11099 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
11100 $disabled = 1;
11101 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
11102 }
11103 }
11104
11105 if (!empty($selected) && $selected == $obj->rowid) {
11106 $out .= '<option value="' . $obj->rowid . '" selected';
11107 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11108 $out .= '>' . $labeltoshow . '</option>';
11109 } else {
11110 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11111 $resultat = '';
11112 } else {
11113 $resultat = '<option value="' . $obj->rowid . '"';
11114 if ($disabled) {
11115 $resultat .= ' disabled';
11116 }
11117 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11118 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11119 $resultat .= '>';
11120 $resultat .= $labeltoshow;
11121 $resultat .= '</option>';
11122 }
11123 $out .= $resultat;
11124 }
11125 }
11126 $i++;
11127 }
11128 }
11129 if (empty($option_only)) {
11130 $out .= '</select>';
11131 }
11132
11133 $this->db->free($resql);
11134
11135 return $out;
11136 } else {
11137 dol_print_error($this->db);
11138 return '';
11139 }
11140 }
11141
11155 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11156 {
11157 global $conf, $langs;
11158
11159 $out = '';
11160
11161 dol_syslog('FactureRec::fetch', LOG_DEBUG);
11162
11163 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
11164 //$sql.= ', el.fk_source';
11165 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
11166 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
11167 $sql .= " ORDER BY f.titre ASC";
11168
11169 $resql = $this->db->query($sql);
11170 if ($resql) {
11171 // Use select2 selector
11172 if (!empty($conf->use_javascript_ajax)) {
11173 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11174 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11175 $out .= $comboenhancement;
11176 $morecss = 'minwidth200imp maxwidth500';
11177 }
11178
11179 if (empty($option_only)) {
11180 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11181 }
11182 if (!empty($show_empty)) {
11183 $out .= '<option value="0" class="optiongrey">';
11184 if (!is_numeric($show_empty)) {
11185 $out .= $show_empty;
11186 } else {
11187 $out .= '&nbsp;';
11188 }
11189 $out .= '</option>';
11190 }
11191 $num = $this->db->num_rows($resql);
11192 if ($num) {
11193 while ($obj = $this->db->fetch_object($resql)) {
11194 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
11195
11196 $disabled = 0;
11197 if (!empty($obj->suspended)) {
11198 $disabled = 1;
11199 $labeltoshow .= ' - ' . $langs->trans("Closed");
11200 }
11201
11202
11203 if (!empty($selected) && $selected == $obj->rowid) {
11204 $out .= '<option value="' . $obj->rowid . '" selected';
11205 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11206 $out .= '>' . $labeltoshow . '</option>';
11207 } else {
11208 if ($disabled && ($selected != $obj->rowid)) {
11209 $resultat = '';
11210 } else {
11211 $resultat = '<option value="' . $obj->rowid . '"';
11212 if ($disabled) {
11213 $resultat .= ' disabled';
11214 }
11215 $resultat .= '>';
11216 $resultat .= $labeltoshow;
11217 $resultat .= '</option>';
11218 }
11219 $out .= $resultat;
11220 }
11221 }
11222 }
11223 if (empty($option_only)) {
11224 $out .= '</select>';
11225 }
11226
11227 print $out;
11228
11229 $this->db->free($resql);
11230 return $num;
11231 } else {
11232 $this->errors[] = $this->db->lasterror;
11233 return -1;
11234 }
11235 }
11236
11247 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '', $arrayoffiltercriterias = array())
11248 {
11249 // TODO: Use $arrayoffiltercriterias param instead of $arrayofcriterias to include linked object fields in search
11250 global $langs, $form;
11251
11252 require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
11253 $formother = new FormOther($this->db);
11254
11255 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
11256 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
11257 }
11258
11259 $ret = '<!-- searchComponent -->';
11260
11261 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
11262 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
11263 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
11264 $ret .= '</a>';
11265
11266 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
11267
11268 // Show select fields as tags.
11269 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
11270
11271 if ($search_component_params_hidden) {
11272 // Split the criteria on each AND
11273 //var_dump($search_component_params_hidden);
11274
11275 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
11276
11277 // $arrayofandtags is now array( '...' , '...', ...)
11278 // Show each AND part
11279 foreach ($arrayofandtags as $tmpkey => $tmpval) {
11280 $errormessage = '';
11281 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
11282 if ($errormessage) {
11283 $this->error = 'ERROR in parsing search string: '.$errormessage;
11284 }
11285 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
11286 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
11287 $searchtags = removeGlobalParenthesis($searchtags);
11288
11289 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
11290 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
11291 $ret .= dol_escape_htmltag($searchtags);
11292 $ret .= '</span>';
11293 }
11294 }
11295
11296 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
11297
11298 //$ret .= search_component_params
11299 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
11300 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
11301
11302 $show_search_component_params_hidden = 1;
11303 if ($show_search_component_params_hidden) {
11304 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
11305 }
11306 $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%')) -->";
11307 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
11308 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
11309
11310 // TODO : Use $arrayoffiltercriterias instead of $arrayofcriterias
11311 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
11312 foreach ($arrayofcriterias as $criteria) {
11313 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
11314 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
11315 continue;
11316 }
11317 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
11318 continue;
11319 }
11320 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
11321 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
11322 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
11323 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
11324 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
11325 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
11326 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
11327 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
11328 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
11329 } else {
11330 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
11331 }
11332 }
11333 }
11334
11335 $ret .= '</div>';
11336
11337 $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";
11338 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
11339
11340 $ret .= '</div>';
11341 $ret .= '</div>';
11342
11343 $ret .= '<script>
11344 jQuery(".tagsearchdelete").click(function(e) {
11345 var filterid = $(this).parents().attr("data-ufilterid");
11346 console.log("We click to delete the criteria nb "+filterid);
11347
11348 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
11349 var newparamstring = \'\';
11350 $(\'.tagsearch\').each(function(index, element) {
11351 tmpfilterid = $(this).attr("data-ufilterid");
11352 if (tmpfilterid != filterid) {
11353 // We keep this criteria
11354 if (newparamstring == \'\') {
11355 newparamstring = $(this).attr("data-ufilter");
11356 } else {
11357 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
11358 }
11359 }
11360 });
11361 console.log("newparamstring = "+newparamstring);
11362
11363 jQuery("#search_component_params_hidden").val(newparamstring);
11364
11365 // We repost the form
11366 $(this).closest(\'form\').submit();
11367 });
11368
11369 jQuery("#search_component_params_input").keydown(function(e) {
11370 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
11371 console.log(e.which);
11372 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
11373 /* We click on back when the input field is already empty */
11374 event.preventDefault();
11375 jQuery("#divsearch_component_params .tagsearch").last().remove();
11376 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
11377 var s = "";
11378 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
11379 if (s != "") {
11380 s = s + " AND ";
11381 }
11382 s = s + $(this).attr("data-ufilter");
11383 });
11384 console.log("New value for search_component_params_hidden = "+s);
11385 jQuery("#search_component_params_hidden").val(s);
11386 }
11387 });
11388
11389 </script>
11390 ';
11391
11392 // Convert $arrayoffiltercriterias into a json object that can be used in jquery to build the search component dynamically
11393 $arrayoffiltercriterias_json = json_encode($arrayoffiltercriterias);
11394 $ret .= '<script>
11395 var arrayoffiltercriterias = ' . $arrayoffiltercriterias_json . ';
11396 </script>';
11397
11398
11399 $arrayoffilterfieldslabel = array();
11400 foreach ($arrayoffiltercriterias as $key => $val) {
11401 $arrayoffilterfieldslabel[$key]['label'] = $val['label'];
11402 $arrayoffilterfieldslabel[$key]['data-type'] = $val['type'];
11403 }
11404
11405 // Adding the div for search assistance
11406 $ret .= '<div class="search-component-assistance">';
11407 $ret .= '<div>';
11408
11409 $ret .= '<p class="assistance-title">' . img_picto('', 'filter') . ' ' . $langs->trans('FilterAssistance') . ' </p>';
11410
11411 $ret .= '<p class="assistance-errors error" style="display:none">' . $langs->trans('AllFieldsRequired') . ' </p>';
11412
11413 $ret .= '<div class="operand">';
11414 $ret .= $form->selectarray('search_filter_field', $arrayoffilterfieldslabel, '', $langs->trans("Fields"), 0, 0, '', 0, 0, 0, '', 'width200 combolargeelem', 1);
11415 $ret .= '</div>';
11416
11417 $ret .= '<span class="separator"></span>';
11418
11419 // Operator selector (will be populated dynamically)
11420 $ret .= '<div class="operator">';
11421 $ret .= '<select class="operator-selector width150" id="operator-selector"">';
11422 $ret .= '</select>';
11423 $ret .= '<script>$(document).ready(function() {';
11424 $ret .= ' $(".operator-selector").select2({';
11425 $ret .= ' placeholder: \'' . dol_escape_js($langs->trans('Operator')) . '\'';
11426 $ret .= ' });';
11427 $ret .= '});</script>';
11428 $ret .= '</div>';
11429
11430 $ret .= '<span class="separator"></span>';
11431
11432 $ret .= '<div class="value">';
11433 // Input field for entering values
11434 $ret .= '<input type="text" class="flat width100 value-input" placeholder="' . dolPrintHTML($langs->trans('Value')) . '">';
11435
11436 // Date selector
11437 $dateOne = '';
11438 $ret .= '<span class="date-one" style="display:none">';
11439 $ret .= $form->selectDate(($dateOne ? $dateOne : -1), 'dateone', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '');
11440 $ret .= '</span>';
11441
11442 // Value selector (will be populated dynamically) based on search_filter_field value if a selected value has an array of values
11443 $ret .= '<select class="value-selector width150" id="value-selector" style="display:none">';
11444 $ret .= '</select>';
11445 $ret .= '<script>
11446 $(document).ready(function() {
11447 $("#value-selector").select2({
11448 placeholder: "' . dol_escape_js($langs->trans('Value')) . '"
11449 });
11450 $("#value-selector").hide();
11451 $("#value-selector").next(".select2-container").hide();
11452 });
11453 </script>';
11454
11455 $ret .= '</div>';
11456
11457 $ret .= '<div class="btn-div">';
11458 $ret .= '<button class="button buttongen button-save add-filter-btn" type="button">' . $langs->trans("addToFilter") . '</button>';
11459 $ret .= '</div>';
11460
11461 $ret .= '</div>';
11462 //$ret .= '</tbody></table>';
11463
11464 // End of the assistance div
11465 $ret .= '</div>';
11466
11467 // Script jQuery to show/hide the floating assistance
11468 $ret .= '<script>
11469 $(document).ready(function() {
11470 $("#search_component_params_input").on("click", function() {
11471 const inputPosition = $(this).offset();
11472 const inputHeight = $(this).outerHeight();
11473 $(".search-component-assistance").css({
11474 top: inputPosition.top + inputHeight + 5 + "px",
11475 left: $("#divsearch_component_params").position().left
11476 }).slideToggle(200);
11477 });
11478 $(document).on("click", function(e) {
11479 if (!$(e.target).closest("#search_component_params_input, .search-component-assistance, #ui-datepicker-div").length) {
11480 $(".search-component-assistance").hide();
11481 }
11482 });
11483 });
11484 </script>';
11485
11486 $ret .= '<script>
11487 $(document).ready(function() {
11488 $(".search_filter_field").on("change", function() {
11489 let maybenull = 0;
11490 const selectedField = $(this).find(":selected");
11491 let fieldType = selectedField.data("type");
11492 const selectedFieldValue = selectedField.val();
11493
11494 // If the selected field has an array of values then ask toshow the value selector instead of the value input
11495 if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
11496 fieldType = "select";
11497 }
11498
11499 // If the selected field may be null then ask to append the "IsDefined" and "IsNotDefined" operators
11500 if (arrayoffiltercriterias[selectedFieldValue]["maybenull"] !== undefined) {
11501 maybenull = 1;
11502 }
11503 const operators = getOperatorsForFieldType(fieldType, maybenull);
11504 const operatorSelector = $(".operator-selector");
11505
11506 // Clear existing options
11507 operatorSelector.empty();
11508
11509 // Populate operators
11510 Object.entries(operators).forEach(function([operator, label]) {
11511 operatorSelector.append("<option value=\'" + operator + "\'>" + label + "</option>");
11512 });
11513
11514 operatorSelector.trigger("change.select2");
11515
11516 // Clear and hide all input elements initially
11517 $(".value-input, .dateone, .datemonth, .dateyear").val("").hide();
11518 $("#datemonth, #dateyear").val(null).trigger("change.select2");
11519 $("#dateone").datepicker("setDate", null);
11520 $(".date-one, .date-month, .date-year").hide();
11521 $("#value-selector").val("").hide();
11522 $("#value-selector").next(".select2-container").hide();
11523 $("#value-selector").val(null).trigger("change.select2");
11524
11525 if (fieldType === "date" || fieldType === "datetime" || fieldType === "timestamp") {
11526 $(".date-one").show();
11527 } else if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
11528 var arrayofkeyval = arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"];
11529 var valueSelector = $("#value-selector");
11530 valueSelector.empty();
11531 Object.entries(arrayofkeyval).forEach(function([key, val]) {
11532 valueSelector.append("<option value=\'" + key + "\'>" + val + "</option>");
11533 });
11534 valueSelector.trigger("change.select2");
11535
11536 $("#value-selector").show();
11537 $("#value-selector").next(".select2-container").show();
11538 } else {
11539 $(".value-input").show();
11540 }
11541 });
11542
11543 $("#operator-selector").on("change", function() {
11544 const selectedOperator = $(this).find(":selected").val();
11545 if (selectedOperator === "IsDefined" || selectedOperator === "IsNotDefined") {
11546 // Disable all value input elements
11547 $(".value-input, .dateone, .datemonth, .dateyear").val("").prop("disabled", true);
11548 $("#datemonth, #dateyear").val(null).trigger("change.select2");
11549 $("#dateone").datepicker("setDate", null).datepicker("option", "disabled", true);
11550 $(".date-one, .date-month, .date-year").prop("disabled", true);
11551 $("#value-selector").val("").prop("disabled", true);
11552 $("#value-selector").val(null).trigger("change.select2");
11553 } else {
11554 // Enable all value input elements
11555 $(".value-input, .dateone, .datemonth, .dateyear").prop("disabled", false);
11556 $(".date-one, .date-month, .date-year").prop("disabled", false);
11557 $("#dateone").datepicker("option", "disabled", false);
11558 $("#value-selector").prop("disabled", false);
11559 }
11560 });
11561
11562 $(".add-filter-btn").on("click", function(event) {
11563 event.preventDefault();
11564
11565 const field = $(".search_filter_field").val();
11566 const operator = $(".operator-selector").val();
11567 let value = $(".value-input").val();
11568 const fieldType = $(".search_filter_field").find(":selected").data("type");
11569
11570 if (["date", "datetime", "timestamp"].includes(fieldType)) {
11571 const parsedDate = new Date($("#dateone").val());
11572 if (!isNaN(parsedDate)) {
11573 const year = parsedDate.getFullYear();
11574 const month = String(parsedDate.getMonth() + 1).padStart(2, "0");
11575 const day = String(parsedDate.getDate()).padStart(2, "0");
11576 value = `${year}-${month}-${day}`;
11577 }
11578 }
11579
11580 // If the selected field has an array of values then take the selected value
11581 if (arrayoffiltercriterias[field]["arrayofkeyval"] !== undefined) {
11582 value = $("#value-selector").val();
11583 }
11584
11585 // If the operator is "IsDefined" or "IsNotDefined" then set the value to 1 (it will not be used)
11586 if (operator === "IsDefined" || operator === "IsNotDefined") {
11587 value = "1";
11588 }
11589
11590 const filterString = generateFilterString(field, operator, value, fieldType);
11591
11592 // Submit the form
11593 if (filterString !== "" && field !== "" && operator !== "" && value !== "") {
11594 $("#search_component_params_input").val($("#search_component_params_input").val() + " " + filterString);
11595 $("#search_component_params_input").closest("form").submit();
11596 } else {
11597 $(".assistance-errors").show();
11598 }
11599 });
11600 });
11601 </script>';
11602
11603 return $ret;
11604 }
11605
11616 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0, $selected = '')
11617 {
11618 global $langs, $user;
11619
11620 $retstring = '';
11621
11622 $TModels = array();
11623
11624 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
11625 $formmail = new FormMail($this->db);
11626 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
11627
11628 if ($default) {
11629 $TModels[0] = $langs->trans('DefaultMailModel');
11630 }
11631 if ($result > 0) {
11632 foreach ($formmail->lines_model as $model) {
11633 $TModels[$model->id] = $model->label;
11634 }
11635 }
11636
11637 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
11638
11639 foreach ($TModels as $id_model => $label_model) {
11640 $retstring .= '<option value="' . $id_model . '"';
11641 if (!empty($selected) && $selected == $id_model) {
11642 $retstring .= "selected";
11643 }
11644 $retstring .= ">" . $label_model . "</option>";
11645 }
11646
11647 $retstring .= "</select>";
11648
11649 if ($addjscombo) {
11650 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
11651 }
11652
11653 return $retstring;
11654 }
11655
11667 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
11668 {
11669 global $langs;
11670
11671 $buttons = array();
11672
11673 $save = array(
11674 'name' => 'save',
11675 'label_key' => $save_label,
11676 );
11677
11678 if ($save_label == 'Create' || $save_label == 'Add') {
11679 $save['name'] = 'add';
11680 } elseif ($save_label == 'Modify') {
11681 $save['name'] = 'edit';
11682 }
11683
11684 $cancel = array(
11685 'name' => 'cancel',
11686 'label_key' => 'Cancel',
11687 );
11688
11689 !empty($save_label) ? $buttons[] = $save : '';
11690
11691 if (!empty($morebuttons)) {
11692 $buttons[] = $morebuttons;
11693 }
11694
11695 !empty($cancel_label) ? $buttons[] = $cancel : '';
11696
11697 $retstring = $withoutdiv ? '' : '<div class="center">';
11698
11699 foreach ($buttons as $button) {
11700 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
11701 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
11702 }
11703 $retstring .= $withoutdiv ? '' : '</div>';
11704
11705 if ($dol_openinpopup) {
11706 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
11707 $retstring .= '<script nonce="' . getNonce() . '">';
11708 $retstring .= 'jQuery(".button-cancel").click(function(e) {
11709 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
11710 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
11711 });';
11712 $retstring .= '</script>';
11713 }
11714
11715 return $retstring;
11716 }
11717
11718
11719 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11720
11727 {
11728 // phpcs:enable
11729 global $langs;
11730
11731 $num = count($this->cache_invoice_subtype);
11732 if ($num > 0) {
11733 return 0; // Cache already loaded
11734 }
11735
11736 dol_syslog(__METHOD__, LOG_DEBUG);
11737
11738 $sql = "SELECT rowid, code, label as label";
11739 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
11740 $sql .= " WHERE active = 1";
11741
11742 $resql = $this->db->query($sql);
11743 if ($resql) {
11744 $num = $this->db->num_rows($resql);
11745 $i = 0;
11746 while ($i < $num) {
11747 $obj = $this->db->fetch_object($resql);
11748
11749 // If translation exists, we use it, otherwise we take the default wording
11750 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
11751 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
11752 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
11753 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
11754 $i++;
11755 }
11756
11757 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
11758
11759 return $num;
11760 } else {
11761 dol_print_error($this->db);
11762 return -1;
11763 }
11764 }
11765
11766
11777 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
11778 {
11779 global $langs, $user;
11780
11781 $out = '';
11782 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
11783
11784 $this->load_cache_invoice_subtype();
11785
11786 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
11787 if ($addempty) {
11788 $out .= '<option value="0">&nbsp;</option>';
11789 }
11790
11791 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
11792 $label = $subtype['label'];
11793 $out .= '<option value="' . $subtype['rowid'] . '"';
11794 if ($selected == $subtype['rowid']) {
11795 $out .= ' selected="selected"';
11796 }
11797 $out .= '>';
11798 $out .= $label;
11799 $out .= '</option>';
11800 }
11801
11802 $out .= '</select>';
11803 if ($user->admin && empty($noinfoadmin)) {
11804 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11805 }
11806 $out .= ajax_combobox($htmlname);
11807
11808 return $out;
11809 }
11810}
$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:463
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:312
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:566
$c
Definition line.php:327
$object ref
Definition info.php:89
Class to manage bank accounts.
Class to manage categories.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage bank accounts description of third parties.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
DAO Resource object.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array(), $nooutput=0)
Show block with links "to link to" other objects.
showFilterButtons($pos='')
Return HTML to show the search and clear search button.
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array(), $canremoveowner=1)
Return select list of users.
load_cache_vatrates($country_code)
Load into the cache ->cache_vatrates, all the vat rates of a country.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=array(), $title='RelatedObjects')
Show linked object block.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
select_dolresources_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofresourceid=array())
Return select list of resources.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
formRib($page, $selected='', $htmlname='ribcompanyid', $filtre='', $addempty=0, $showibanbic=0)
Display form to select bank customer account.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party This call select_thirdparty_list() or ajax depending on setu...
select_produits($selected=0, $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1, $warehouseId=0)
Return list of products for customer.
select_dolgroups($selected=0, $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly=array(), $force_entity='0', $multiple=false, $morecss='minwidth200')
Return select list of user groups.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
select_contact($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $nokeyifsocid=true, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $selected_input_value='', $filter='')
Output html form to select a contact This call select_contacts() or ajax depending on setup.
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="", $useajaxcombo=1)
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
selectRib($selected='', $htmlname='ribcompanyid', $filtre='', $useempty=0, $moreattrib='', $showibanbic=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts customer.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
getSelectInvoiceSubtype($selected=0, $htmlname='subtypeid', $addempty=0, $noinfoadmin=0, $morecss='')
Return list of invoice subtypes.
select_produits_list($selected=0, $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='maxwidth500', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1, $warehouseId=0)
Return list of products for a customer.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse=null, $societe_acheteuse=null, $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0, $type_vat=0)
Output an HTML select vat rate.
form_multicurrency_rate($page, $rate=0.0, $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
load_cache_availability()
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
selectcontacts($socid, $selected=array(), $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=0, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0, $filter='')
Return HTML code of the SELECT of list of all contacts (for a third party or all).
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=false, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0, $forcecombo=0)
Return combo list of activated countries, into language of user.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
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.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly=array(), $force_entity='0')
Return the HTML select list of users.
selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='', $openinghours='', $stepminutes=1, $labeladddateof='', $placeholder='', $gm='auto', $calendarpicto='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
textwithpicto($text, $htmltooltip, $direction=1, $type='help', $extracss='valignmiddle', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday=0, $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
load_cache_invoice_subtype()
Load into cache list of invoice subtypes.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
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.
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.
Class toolbox to validate values.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
currency_name($code_iso, $withcode=0, $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
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'.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0, $morecss='paddingrightonly')
Show EMail link formatted for HTML output.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0, $allowscript=0, $allowstyle=0, $allowphp=0)
Clean a string to keep only desirable HTML tags.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
a disabled
treeview li table
No Email.
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
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:150
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:153
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.
getMaxFileSizeArray()
Return the max allowed for file upload.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.