dolibarr 21.0.0-alpha
html.form.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13 * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18 * Copyright (C) 2014-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
27 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
28 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 3 of the License, or
32 * (at your option) any later version.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program. If not, see <https://www.gnu.org/licenses/>.
41 */
42
56class Form
57{
61 public $db;
62
66 public $error = '';
67
71 public $errors = array();
72
73 // Some properties used to return data by some methods
75 public $result;
77 public $num;
78
79 // Cache arrays
80 public $cache_types_paiements = array();
81 public $cache_conditions_paiements = array();
82 public $cache_transport_mode = array();
83 public $cache_availability = array();
84 public $cache_demand_reason = array();
85 public $cache_types_fees = array();
86 public $cache_vatrates = array();
87 public $cache_invoice_subtype = array();
88
89
95 public function __construct($db)
96 {
97 $this->db = $db;
98 }
99
116 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
117 {
118 global $langs;
119
120 $ret = '';
121
122 // TODO change for compatibility
123 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
124 if (!empty($perm)) {
125 $tmp = explode(':', $typeofdata);
126 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
127 if ($fieldrequired) {
128 $ret .= '<span class="fieldrequired">';
129 }
130 if ($help) {
131 $ret .= $this->textwithpicto($langs->trans($text), $help);
132 } else {
133 $ret .= $langs->trans($text);
134 }
135 if ($fieldrequired) {
136 $ret .= '</span>';
137 }
138 $ret .= '</div>' . "\n";
139 } else {
140 if ($fieldrequired) {
141 $ret .= '<span class="fieldrequired">';
142 }
143 if ($help) {
144 $ret .= $this->textwithpicto($langs->trans($text), $help);
145 } else {
146 $ret .= $langs->trans($text);
147 }
148 if ($fieldrequired) {
149 $ret .= '</span>';
150 }
151 }
152 } else {
153 if (empty($notabletag) && $perm) {
154 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
155 }
156 if ($fieldrequired) {
157 $ret .= '<span class="fieldrequired">';
158 }
159 if ($help) {
160 $ret .= $this->textwithpicto($langs->trans($text), $help);
161 } else {
162 $ret .= $langs->trans($text);
163 }
164 if ($fieldrequired) {
165 $ret .= '</span>';
166 }
167 if (!empty($notabletag)) {
168 $ret .= ' ';
169 }
170 if (empty($notabletag) && $perm) {
171 $ret .= '</td>';
172 }
173 if (empty($notabletag) && $perm) {
174 $ret .= '<td class="right">';
175 }
176 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
177 $ret .= '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=edit' . $htmlname . '&token=' . newToken() . '&' . $paramid . '=' . $object->id . $moreparam . '">' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . '</a>';
178 }
179 if (!empty($notabletag) && $notabletag == 1) {
180 if ($text) {
181 $ret .= ' : ';
182 } else {
183 $ret .= ' ';
184 }
185 }
186 if (!empty($notabletag) && $notabletag == 3) {
187 $ret .= ' ';
188 }
189 if (empty($notabletag) && $perm) {
190 $ret .= '</td>';
191 }
192 if (empty($notabletag) && $perm) {
193 $ret .= '</tr></table>';
194 }
195 }
196
197 return $ret;
198 }
199
223 public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '')
224 {
225 global $conf, $langs;
226
227 $ret = '';
228
229 // Check parameters
230 if (empty($typeofdata)) {
231 return 'ErrorBadParameter typeofdata is empty';
232 }
233 // Clean parameter $typeofdata
234 if ($typeofdata == 'datetime') {
235 $typeofdata = 'dayhour';
236 }
237 $reg = array();
238 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
239 if ($reg[1] == 'varchar') {
240 $typeofdata = 'string';
241 } elseif ($reg[1] == 'int') {
242 $typeofdata = 'numeric';
243 } else {
244 return 'ErrorBadParameter ' . $typeofdata;
245 }
246 }
247
248 // When option to edit inline is activated
249 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
250 $ret .= $this->editInPlace($object, $value, $htmlname, ($perm ? 1 : 0), $typeofdata, $editvalue, $extObject, $custommsg);
251 } else {
252 if ($editaction == '') {
253 $editaction = GETPOST('action', 'aZ09');
254 }
255 $editmode = ($editaction == 'edit' . $htmlname);
256 if ($editmode) { // edit mode
257 $ret .= "<!-- formeditfieldval -->\n";
258 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
259 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
260 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
261 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
262 if (empty($notabletag)) {
263 $ret .= '<table class="nobordernopadding centpercent">';
264 }
265 if (empty($notabletag)) {
266 $ret .= '<tr><td>';
267 }
268 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
269 $tmp = explode(':', $typeofdata);
270 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
271 } elseif (preg_match('/^(integer)/', $typeofdata)) {
272 $tmp = explode(':', $typeofdata);
273 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
274 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
275 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
276 $tmp = explode(':', $typeofdata);
277 $valuetoshow = price2num($editvalue ? $editvalue : $value);
278 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
279 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
280 $tmp = explode(':', $typeofdata);
281 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
282 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
283 $tmp = explode(':', $typeofdata);
284 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
285 $morealt = '';
286 if (preg_match('/%/', $cols)) {
287 $morealt = ' style="width: ' . $cols . '"';
288 $cols = '';
289 }
290 $valuetoshow = ($editvalue ? $editvalue : $value);
291 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
292 // textarea convert automatically entities chars into simple chars.
293 // So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwyg is off.
294 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
295 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
296 $ret .= '</textarea><div class="clearboth"></div>';
297 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
298 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
299 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
300 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
301 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
302 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
303 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
304 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
305 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
306 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
307 } elseif (preg_match('/^select;/', $typeofdata)) {
308 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
309 $arraylist = array();
310 foreach ($arraydata as $val) {
311 $tmp = explode(':', $val);
312 $tmpkey = str_replace('|', ':', $tmp[0]);
313 $arraylist[$tmpkey] = $tmp[1];
314 }
315 $ret .= $this->selectarray($htmlname, $arraylist, $value);
316 } elseif (preg_match('/^link/', $typeofdata)) {
317 // TODO Not yet implemented. See code for extrafields
318 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
319 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
320 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
321 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? 100 : (int) $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? false : (bool) $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? 20 : (int) $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
322 $ret .= $doleditor->Create(1);
323 } elseif ($typeofdata == 'asis') {
324 $ret .= ($editvalue ? $editvalue : $value);
325 }
326 if (empty($notabletag)) {
327 $ret .= '</td>';
328 }
329
330 // Button save-cancel
331 if (empty($notabletag)) {
332 $ret .= '<td>';
333 }
334 //else $ret.='<div class="clearboth"></div>';
335 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
336 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
337 $ret .= '<br>' . "\n";
338 }
339 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
340 if (empty($notabletag)) {
341 $ret .= '</td>';
342 }
343
344 if (empty($notabletag)) {
345 $ret .= '</tr></table>' . "\n";
346 }
347 $ret .= '</form>' . "\n";
348 } else { // view mode
349 if (preg_match('/^email/', $typeofdata)) {
350 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
351 } elseif (preg_match('/^phone/', $typeofdata)) {
352 $ret .= dol_print_phone($value, '_blank', 32, 1);
353 } elseif (preg_match('/^url/', $typeofdata)) {
354 $ret .= dol_print_url($value, '_blank', 32, 1);
355 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
356 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
357 } elseif (preg_match('/^checkbox/', $typeofdata)) {
358 $tmp = explode(':', $typeofdata);
359 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
360 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
362 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
364 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
365 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
366 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
367 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
368 } elseif (preg_match('/^select;/', $typeofdata)) {
369 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
370 $arraylist = array();
371 foreach ($arraydata as $val) {
372 $tmp = explode(':', $val);
373 $arraylist[$tmp[0]] = $tmp[1];
374 }
375 $ret .= $arraylist[$value];
376 if ($htmlname == 'fk_product_type') {
377 if ($value == 0) {
378 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
379 } else {
380 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
381 }
382 }
383 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
384 $tmpcontent = dol_htmlentitiesbr($value);
385 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
386 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
387 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
388 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
389 }
390 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
391 // clean data from some dangerous html
393 } else {
394 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
395 $ret .= dol_escape_htmltag($value);
396 } else {
397 $ret .= $value; // $value must be already html escaped.
398 }
399 }
400
401 // Custom format if parameter $formatfunc has been provided
402 if ($formatfunc && method_exists($object, $formatfunc)) {
403 $ret = $object->$formatfunc($ret);
404 }
405 }
406 }
407 return $ret;
408 }
409
421 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
422 {
423 global $conf, $langs, $extralanguages;
424
425 $result = '';
426
427 // List of extra languages
428 $arrayoflangcode = array();
429 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
430 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
431 }
432
433 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
434 if (!is_object($extralanguages)) {
435 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
436 $extralanguages = new ExtraLanguages($this->db);
437 }
438 $extralanguages->fetch_name_extralanguages('societe');
439
440 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
441 return ''; // No extralang field to show
442 }
443
444 $result .= '<!-- Widget for translation -->' . "\n";
445 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
446 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', 0, 0, 0, '', 'fa-15 editfieldlang');
447 $result .= $s;
448 $result .= '</div>';
449
450 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
451
452 $resultforextrlang = '';
453 foreach ($arrayoflangcode as $langcode) {
454 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
455 if (empty($valuetoshow)) {
456 $object->fetchValuesForExtraLanguages();
457 //var_dump($object->array_languages);
458 $valuetoshow = $object->array_languages[$fieldname][$langcode];
459 }
460
461 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
462 $resultforextrlang .= $s;
463
464 // TODO Use the showInputField() method of ExtraLanguages object
465 if ($typeofdata == 'textarea') {
466 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
467 $resultforextrlang .= $valuetoshow;
468 $resultforextrlang .= '</textarea>';
469 } else {
470 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
471 }
472 }
473 $result .= $resultforextrlang;
474
475 $result .= '</div>';
476 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
477 }
478
479 return $result;
480 }
481
495 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
496 {
497 $out = '';
498
499 // Check parameters
500 if (preg_match('/^text/', $inputType)) {
501 $value = dol_nl2br($value);
502 } elseif (preg_match('/^numeric/', $inputType)) {
503 $value = price($value);
504 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
505 $value = dol_print_date($value, 'day');
506 }
507
508 if ($condition) {
509 $element = false;
510 $table_element = false;
511 $fk_element = false;
512 $loadmethod = false;
513 $savemethod = false;
514 $ext_element = false;
515 $button_only = false;
516 $inputOption = '';
517 $rows = '';
518 $cols = '';
519
520 if (is_object($object)) {
521 $element = $object->element;
522 $table_element = $object->table_element;
523 $fk_element = $object->id;
524 }
525
526 if (is_object($extObject)) {
527 $ext_element = $extObject->element;
528 }
529
530 if (preg_match('/^(string|email|numeric)/', $inputType)) {
531 $tmp = explode(':', $inputType);
532 $inputType = $tmp[0];
533 if (!empty($tmp[1])) {
534 $inputOption = $tmp[1];
535 }
536 if (!empty($tmp[2])) {
537 $savemethod = $tmp[2];
538 }
539 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
540 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
541 $tmp = explode(':', $inputType);
542 $inputType = $tmp[0];
543 if (!empty($tmp[1])) {
544 $inputOption = $tmp[1];
545 }
546 if (!empty($tmp[2])) {
547 $savemethod = $tmp[2];
548 }
549
550 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
551 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
552 $tmp = explode(':', $inputType);
553 $inputType = $tmp[0];
554 $loadmethod = $tmp[1];
555 if (!empty($tmp[2])) {
556 $savemethod = $tmp[2];
557 }
558 if (!empty($tmp[3])) {
559 $button_only = true;
560 }
561 } elseif (preg_match('/^textarea/', $inputType)) {
562 $tmp = explode(':', $inputType);
563 $inputType = $tmp[0];
564 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
565 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
566 } elseif (preg_match('/^ckeditor/', $inputType)) {
567 $tmp = explode(':', $inputType);
568 $inputType = $tmp[0];
569 $toolbar = $tmp[1];
570 if (!empty($tmp[2])) {
571 $width = $tmp[2];
572 }
573 if (!empty($tmp[3])) {
574 $height = $tmp[3];
575 }
576 if (!empty($tmp[4])) {
577 $savemethod = $tmp[4];
578 }
579
580 if (isModEnabled('fckeditor')) {
581 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
582 } else {
583 $inputType = 'textarea';
584 }
585 }
586
587 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
588 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
589 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
590 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
591 if (!empty($savemethod)) {
592 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
593 }
594 if (!empty($ext_element)) {
595 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
596 }
597 if (!empty($custommsg)) {
598 if (is_array($custommsg)) {
599 if (!empty($custommsg['success'])) {
600 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
601 }
602 if (!empty($custommsg['error'])) {
603 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
604 }
605 } else {
606 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
607 }
608 }
609 if ($inputType == 'textarea') {
610 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
611 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
612 }
613 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
614 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
615 } else {
616 $out = $value;
617 }
618
619 return $out;
620 }
621
640 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
641 {
642 if ($incbefore) {
643 $text = $incbefore . $text;
644 }
645 if (!$htmltext) {
646 return $text;
647 }
648 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
649
650 $tag = 'td';
651 if ($notabs == 2) {
652 $tag = 'div';
653 }
654 if ($notabs == 3) {
655 $tag = 'span';
656 }
657 // Sanitize tooltip
658 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
659
660 $extrastyle = '';
661 if ($direction < 0) {
662 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
663 $extrastyle = 'padding: 0px; padding-left: 2px;';
664 }
665 if ($direction > 0) {
666 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
667 $extrastyle = 'padding: 0px; padding-right: 2px;';
668 }
669
670 $classfortooltip = 'classfortooltip';
671
672 $s = '';
673 $textfordialog = '';
674
675 if ($tooltiptrigger == '') {
676 $htmltext = str_replace('"', '&quot;', $htmltext);
677 } else {
678 $classfortooltip = 'classfortooltiponclick';
679 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
680 }
681 if ($tooltipon == 2 || $tooltipon == 3) {
682 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
683 if ($tooltiptrigger == '') {
684 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
685 } else {
686 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
687 }
688 } else {
689 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
690 }
691 if ($tooltipon == 1 || $tooltipon == 3) {
692 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
693 if ($tooltiptrigger == '') {
694 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
695 } else {
696 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
697 }
698 } else {
699 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
700 }
701 if (empty($notabs)) {
702 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
703 } elseif ($notabs == 2) {
704 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
705 }
706 // Define value if value is before
707 if ($direction < 0) {
708 $s .= '<' . $tag . $paramfortooltipimg;
709 if ($tag == 'td') {
710 $s .= ' class="valigntop" width="14"';
711 }
712 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
713 }
714 // Use another method to help avoid having a space in value in order to use this value with jquery
715 // Define label
716 if ((string) $text != '') {
717 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
718 }
719 // Define value if value is after
720 if ($direction > 0) {
721 $s .= '<' . $tag . $paramfortooltipimg;
722 if ($tag == 'td') {
723 $s .= ' class="valignmiddle" width="14"';
724 }
725 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
726 }
727 if (empty($notabs)) {
728 $s .= '</tr></table>';
729 } elseif ($notabs == 2) {
730 $s .= '</div>';
731 }
732
733 return $s;
734 }
735
750 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = 'valignmiddle', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
751 {
752 global $conf, $langs;
753
754 //For backwards compatibility
755 if ($type == '0') {
756 $type = 'info';
757 } elseif ($type == '1') {
758 $type = 'help';
759 }
760 // Clean parameters
761 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
762
763 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
764 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
765 }
766 $alt = '';
767 if ($tooltiptrigger) {
768 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
769 }
770
771 // If info or help with no javascript, show only text
772 if (empty($conf->use_javascript_ajax)) {
773 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
774 return $text;
775 } else {
776 $alt = $htmltext;
777 $htmltext = '';
778 }
779 }
780
781 // If info or help with smartphone, show only text (tooltip hover can't works)
782 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
783 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
784 return $text;
785 }
786 }
787 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
788 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
789 //{
790 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
791 //}
792
793 $img = '';
794 if ($type == 'info') {
795 $img = img_help(0, $alt);
796 } elseif ($type == 'help') {
797 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
798 } elseif ($type == 'helpclickable') {
799 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
800 } elseif ($type == 'superadmin') {
801 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
802 $img = img_picto($alt, 'redstar');
803 } elseif ($type == 'admin') {
804 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
805 $img = img_picto($alt, 'star');
806 } elseif ($type == 'warning') {
807 $img = img_warning($alt);
808 } elseif ($type != 'none') {
809 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
810 $img = img_picto($alt, $type); // $type can be an image path
811 }
812
813 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
814 }
815
826 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
827 {
828 global $conf, $langs, $hookmanager;
829
830 $disabled = 0;
831 $ret = '<div class="centpercent center">';
832 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
833
834 // Complete list with data from external modules. THe module can use $_SERVER['PHP_SELF'] to know on which page we are, or use the $parameters['currentcontext'] completed by executeHooks.
835 $parameters = array();
836 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
837 // check if there is a mass action
838
839 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
840 return;
841 }
842 if (empty($reshook)) {
843 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
844 if (is_array($arrayofaction)) {
845 foreach ($arrayofaction as $code => $label) {
846 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
847 }
848 }
849 }
850 $ret .= $hookmanager->resPrint;
851
852 $ret .= '</select>';
853
854 if (empty($conf->dol_optimize_smallscreen)) {
855 $ret .= ajax_combobox('.' . $name . 'select');
856 }
857
858 // Warning: if you set submit button to disabled, post using 'Enter' will no more work if there is no another input submit. So we add a hidden button
859 $ret .= '<input type="submit" name="confirmmassactioninvisible" style="display: none" tabindex="-1">'; // Hidden button BEFORE so it is the one used when we submit with ENTER.
860 $ret .= '<input type="submit" disabled name="confirmmassaction"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display: none"') . ' class="reposition button smallpaddingimp' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'confirmed" value="' . dol_escape_htmltag($langs->trans("Confirm")) . '">';
861 $ret .= '</div>';
862
863 if (!empty($conf->use_javascript_ajax)) {
864 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
865 <script nonce="' . getNonce() . '">
866 function initCheckForSelect(mode, name, cssclass) /* mode is 0 during init of page or click all, 1 when we click on 1 checkboxi, "name" refers to the class of the massaction button, "cssclass" to the class of the checkfor select boxes */
867 {
868 atleastoneselected=0;
869 jQuery("."+cssclass).each(function( index ) {
870 /* console.log( index + ": " + $( this ).text() ); */
871 if ($(this).is(\':checked\')) atleastoneselected++;
872 });
873
874 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
875
876 if (atleastoneselected || ' . $alwaysvisible . ')
877 {
878 jQuery("."+name).show();
879 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
880 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
881 }
882 else
883 {
884 jQuery("."+name).hide();
885 jQuery("."+name+"other").hide();
886 }
887 }
888
889 jQuery(document).ready(function () {
890 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
891 jQuery(".' . $cssclass . '").click(function() {
892 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
893 });
894 jQuery(".' . $name . 'select").change(function() {
895 var massaction = $( this ).val();
896 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
897 if (massaction == "builddoc") {
898 urlform = urlform + "#show_files";
899 }
900 $( this ).closest("form").attr("action", urlform);
901 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
902 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
903 if ($(this).val() != \'0\') {
904 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
905 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
906 jQuery(".' . $name . '"+massaction).show();
907 } else {
908 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
909 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
910 }
911 });
912 });
913 </script>
914 ';
915 }
916
917 return $ret;
918 }
919
920 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
921
938 public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0)
939 {
940 // phpcs:enable
941 global $conf, $langs, $mysoc;
942
943 $langs->load("dict");
944
945 $out = '';
946 $countryArray = array();
947 $favorite = array();
948 $label = array();
949 $atleastonefavorite = 0;
950
951 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
952 $sql .= " FROM " . $this->db->prefix() . "c_country";
953 $sql .= " WHERE active > 0";
954 //$sql.= " ORDER BY code ASC";
955
956 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
957 $resql = $this->db->query($sql);
958 if ($resql) {
959 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
960 $num = $this->db->num_rows($resql);
961 $i = 0;
962 if ($num) {
963 while ($i < $num) {
964 $obj = $this->db->fetch_object($resql);
965
966 $countryArray[$i]['rowid'] = $obj->rowid;
967 $countryArray[$i]['code_iso'] = $obj->code_iso;
968 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
969 $countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
970 $countryArray[$i]['favorite'] = $obj->favorite;
971 $countryArray[$i]['eec'] = $obj->eec;
972 $favorite[$i] = $obj->favorite;
973 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
974 $i++;
975 }
976
977 if (empty($disablefavorites)) {
978 $array1_sort_order = SORT_DESC;
979 $array2_sort_order = SORT_ASC;
980 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
981 } else {
982 $countryArray = dol_sort_array($countryArray, 'label');
983 }
984
985 if ($showempty) {
986 if (is_numeric($showempty)) {
987 $out .= '<option value="">&nbsp;</option>' . "\n";
988 } else {
989 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
990 }
991 }
992
993 if ($addspecialentries) { // Add dedicated entries for groups of countries
994 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
995 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
996 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
997 if ($mysoc->isInEEC()) {
998 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
999 }
1000 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1001 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1002 }
1003
1004 foreach ($countryArray as $row) {
1005 //if (empty($showempty) && empty($row['rowid'])) continue;
1006 if (empty($row['rowid'])) {
1007 continue;
1008 }
1009 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1010 continue; // exclude some countries
1011 }
1012
1013 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1014 $atleastonefavorite++;
1015 }
1016 if (empty($row['favorite']) && $atleastonefavorite) {
1017 $atleastonefavorite = 0;
1018 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1019 }
1020
1021 $labeltoshow = '';
1022 if ($row['label']) {
1023 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1024 } else {
1025 $labeltoshow .= '&nbsp;';
1026 }
1027 if ($row['code_iso']) {
1028 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1029 if (empty($hideflags)) {
1030 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1031 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1032 }
1033 }
1034
1035 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1036 $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1037 } else {
1038 $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1039 }
1040 $out .= $labeltoshow;
1041 $out .= '</option>' . "\n";
1042 }
1043 }
1044 $out .= '</select>';
1045 } else {
1046 dol_print_error($this->db);
1047 }
1048
1049 // Make select dynamic
1050 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1051 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1052
1053 return $out;
1054 }
1055
1056 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1057
1071 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1072 {
1073 // phpcs:enable
1074 global $conf, $langs;
1075
1076 $langs->load("dict");
1077
1078 $out = '';
1079 $moreattrib = '';
1080 $incotermArray = array();
1081
1082 $sql = "SELECT rowid, code";
1083 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1084 $sql .= " WHERE active > 0";
1085 $sql .= " ORDER BY code ASC";
1086
1087 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1088 $resql = $this->db->query($sql);
1089 if ($resql) {
1090 if ($conf->use_javascript_ajax && !$forcecombo) {
1091 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1092 $out .= ajax_combobox($htmlname, $events);
1093 }
1094
1095 if (!empty($page)) {
1096 $out .= '<form method="post" action="' . $page . '">';
1097 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1098 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1099 }
1100
1101 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1102 $out .= '<option value="0">&nbsp;</option>';
1103 $num = $this->db->num_rows($resql);
1104 $i = 0;
1105 if ($num) {
1106 while ($i < $num) {
1107 $obj = $this->db->fetch_object($resql);
1108 $incotermArray[$i]['rowid'] = $obj->rowid;
1109 $incotermArray[$i]['code'] = $obj->code;
1110 $i++;
1111 }
1112
1113 foreach ($incotermArray as $row) {
1114 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1115 $out .= '<option value="' . $row['rowid'] . '" selected>';
1116 } else {
1117 $out .= '<option value="' . $row['rowid'] . '">';
1118 }
1119
1120 if ($row['code']) {
1121 $out .= $row['code'];
1122 }
1123
1124 $out .= '</option>';
1125 }
1126 }
1127 $out .= '</select>';
1128 $out .= ajax_combobox($htmlname);
1129
1130 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1131 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1132 $moreattrib .= ' autocomplete="off"';
1133 }
1134 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1135
1136 if (!empty($page)) {
1137 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1138 }
1139 } else {
1140 dol_print_error($this->db);
1141 }
1142
1143 return $out;
1144 }
1145
1146 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1147
1160 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "")
1161 {
1162 // phpcs:enable
1163 global $langs;
1164
1165 // If product & services are enabled or both disabled.
1166 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1167 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1168 if (empty($hidetext)) {
1169 print $langs->trans("Type") . ': ';
1170 }
1171 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1172 if ($showempty) {
1173 print '<option value="-1"';
1174 if ($selected == -1) {
1175 print ' selected';
1176 }
1177 print '>';
1178 if (is_numeric($showempty)) {
1179 print '&nbsp;';
1180 } else {
1181 print $showempty;
1182 }
1183 print '</option>';
1184 }
1185
1186 print '<option value="0"';
1187 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1188 print ' selected';
1189 }
1190 print '>' . $langs->trans("Product");
1191
1192 print '<option value="1"';
1193 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1194 print ' selected';
1195 }
1196 print '>' . $langs->trans("Service");
1197
1198 print '</select>';
1199 print ajax_combobox('select_' . $htmlname);
1200 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1201 }
1202 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1203 print $langs->trans("Service");
1204 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1205 }
1206 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1207 print $langs->trans("Product");
1208 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1209 }
1210 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1211 print '<input type="hidden" name="' . $htmlname . '" value="1">'; // By default we set on service for contract. If CONTRACT_SUPPORT_PRODUCTS is set, forceall should be 1 not -1
1212 }
1213 }
1214
1215 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1216
1222 public function load_cache_types_fees()
1223 {
1224 // phpcs:enable
1225 global $langs;
1226
1227 $num = count($this->cache_types_fees);
1228 if ($num > 0) {
1229 return 0; // Cache already loaded
1230 }
1231
1232 dol_syslog(__METHOD__, LOG_DEBUG);
1233
1234 $langs->load("trips");
1235
1236 $sql = "SELECT c.code, c.label";
1237 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1238 $sql .= " WHERE active > 0";
1239
1240 $resql = $this->db->query($sql);
1241 if ($resql) {
1242 $num = $this->db->num_rows($resql);
1243 $i = 0;
1244
1245 while ($i < $num) {
1246 $obj = $this->db->fetch_object($resql);
1247
1248 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1249 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1250 $this->cache_types_fees[$obj->code] = $label;
1251 $i++;
1252 }
1253
1254 asort($this->cache_types_fees);
1255
1256 return $num;
1257 } else {
1258 dol_print_error($this->db);
1259 return -1;
1260 }
1261 }
1262
1263 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1264
1273 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1274 {
1275 // phpcs:enable
1276 global $user, $langs;
1277
1278 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1279
1280 $this->load_cache_types_fees();
1281
1282 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1283 if ($showempty) {
1284 print '<option value="-1"';
1285 if ($selected == -1) {
1286 print ' selected';
1287 }
1288 print '>&nbsp;</option>';
1289 }
1290
1291 foreach ($this->cache_types_fees as $key => $value) {
1292 print '<option value="' . $key . '"';
1293 if ($key == $selected) {
1294 print ' selected';
1295 }
1296 print '>';
1297 print $value;
1298 print '</option>';
1299 }
1300
1301 print '</select>';
1302 if ($user->admin) {
1303 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1304 }
1305 }
1306
1307
1308 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1309
1332 public function select_company($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $limit = 0, $morecss = 'minwidth100', $moreparam = '', $selected_input_value = '', $hidelabel = 1, $ajaxoptions = array(), $multiple = false, $excludeids = array(), $showcode = 0)
1333 {
1334 // phpcs:enable
1335 global $conf, $langs;
1336
1337 $out = '';
1338
1339 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1340 if (is_null($ajaxoptions)) {
1341 $ajaxoptions = array();
1342 }
1343
1344 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1345
1346 // No immediate load of all database
1347 $placeholder = '';
1348 if ($selected && empty($selected_input_value)) {
1349 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1350 $societetmp = new Societe($this->db);
1351 $societetmp->fetch($selected);
1352 $selected_input_value = $societetmp->name;
1353 unset($societetmp);
1354 }
1355
1356 // mode 1
1357 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($excludeids) ? '' : '&excludeids=' . implode(',', $excludeids)) . ($showtype ? '&showtype=' . urlencode((string) ($showtype)) : '') . ($showcode ? '&showcode=' . urlencode((string) ($showcode)) : '');
1358
1359 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1360 if (empty($hidelabel)) {
1361 $out .= $langs->trans("RefOrLabel") . ' : ';
1362 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1363 $placeholder = $langs->trans($showempty);
1364 } elseif ($hidelabel > 1) {
1365 $placeholder = $langs->trans("RefOrLabel");
1366 if ($hidelabel == 2) {
1367 $out .= img_picto($langs->trans("Search"), 'search');
1368 }
1369 }
1370 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('THIRDPARTY_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1371 if ($hidelabel == 3) {
1372 $out .= img_picto($langs->trans("Search"), 'search');
1373 }
1374
1375 $out .= ajax_event($htmlname, $events);
1376
1377 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1378 } else {
1379 // Immediate load of all database
1380 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1381 }
1382
1383 return $out;
1384 }
1385
1386
1387 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1388
1414 public function select_contact($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $nokeyifsocid = true, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $selected_input_value = '', $filter = '')
1415 {
1416 // phpcs:enable
1417
1418 global $conf, $langs;
1419
1420 $out = '';
1421
1422 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1423 if ($nokeyifsocid && $socid > 0) {
1424 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1425 }
1426
1427 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1428 if (is_null($events)) {
1429 $events = array();
1430 }
1431
1432 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1433
1434 // No immediate load of all database
1435 $placeholder = '';
1436 if ($selected && empty($selected_input_value)) {
1437 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1438 $contacttmp = new Contact($this->db);
1439 $contacttmp->fetch($selected);
1440 $selected_input_value = $contacttmp->getFullName($langs);
1441 unset($contacttmp);
1442 }
1443 if (!is_numeric($showempty)) {
1444 $placeholder = $showempty;
1445 }
1446
1447 // mode 1
1448 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1449
1450 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1451
1452 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('CONTACT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1453
1454 $out .= ajax_event($htmlname, $events);
1455
1456 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1457 } else {
1458 // Immediate load of all database
1459 $multiple = false;
1460 $disableifempty = 0;
1461 $options_only = 0;
1462 $limitto = '';
1463
1464 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1465 }
1466
1467 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1468
1469 return $out;
1470 }
1471
1472
1473 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1474
1499 public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false, $excludeids = array(), $showcode = 0)
1500 {
1501 // phpcs:enable
1502 global $user, $langs;
1503 global $hookmanager;
1504
1505 $out = '';
1506 $num = 0;
1507 $outarray = array();
1508
1509 if ($selected === '') {
1510 $selected = array();
1511 } elseif (!is_array($selected)) {
1512 $selected = array($selected);
1513 }
1514
1515 // Clean $filter that may contains sql conditions so sql code
1516 if (function_exists('testSqlAndScriptInject')) {
1517 if (testSqlAndScriptInject($filter, 3) > 0) {
1518 $filter = '';
1519 return 'SQLInjectionTryDetected';
1520 }
1521 }
1522
1523 if ($filter != '') { // If a filter was provided
1524 if (preg_match('/[\‍(\‍)]/', $filter)) {
1525 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1526 $errormsg = '';
1527 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1528
1529 // Redo clean $filter that may contains sql conditions so sql code
1530 if (function_exists('testSqlAndScriptInject')) {
1531 if (testSqlAndScriptInject($filter, 3) > 0) {
1532 $filter = '';
1533 return 'SQLInjectionTryDetected';
1534 }
1535 }
1536 } else {
1537 // If not, we do nothing. We already know that there is no parenthesis
1538 // TODO Disallow this case in a future.
1539 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1540 }
1541 }
1542
1543 // We search companies
1544 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1545 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1546 $sql .= ", s.address, s.zip, s.town";
1547 $sql .= ", dictp.code as country_code";
1548 }
1549 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1550 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1551 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1552 }
1553 if (!$user->hasRight('societe', 'client', 'voir')) {
1554 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1555 }
1556 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1557 if (!empty($user->socid)) {
1558 $sql .= " AND s.rowid = " . ((int) $user->socid);
1559 }
1560 if ($filter) {
1561 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1562 // if not, by testSqlAndScriptInject() only.
1563 $sql .= " AND (" . $filter . ")";
1564 }
1565 if (!$user->hasRight('societe', 'client', 'voir')) {
1566 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1567 }
1568 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1569 $sql .= " AND s.status <> 0";
1570 }
1571 if (!empty($excludeids)) {
1572 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1573 }
1574 // Add where from hooks
1575 $parameters = array();
1576 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1577 $sql .= $hookmanager->resPrint;
1578 // Add criteria
1579 if ($filterkey && $filterkey != '') {
1580 $sql .= " AND (";
1581 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1582 // For natural search
1583 $search_crit = explode(' ', $filterkey);
1584 $i = 0;
1585 if (count($search_crit) > 1) {
1586 $sql .= "(";
1587 }
1588 foreach ($search_crit as $crit) {
1589 if ($i > 0) {
1590 $sql .= " AND ";
1591 }
1592 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1593 $i++;
1594 }
1595 if (count($search_crit) > 1) {
1596 $sql .= ")";
1597 }
1598 if (isModEnabled('barcode')) {
1599 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1600 }
1601 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1602 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1603 $sql .= ")";
1604 }
1605 $sql .= $this->db->order("nom", "ASC");
1606 $sql .= $this->db->plimit($limit, 0);
1607
1608 // Build output string
1609 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1610 $resql = $this->db->query($sql);
1611 if ($resql) {
1612 // Construct $out and $outarray
1613 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1614
1615 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1616 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1617 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1618 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1619 if ($showempty && !is_numeric($showempty)) {
1620 $textifempty = $langs->trans($showempty);
1621 } else {
1622 $textifempty .= $langs->trans("All");
1623 }
1624 }
1625 if ($showempty) {
1626 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1627 }
1628
1629 $companytemp = new Societe($this->db);
1630
1631 $num = $this->db->num_rows($resql);
1632 $i = 0;
1633 if ($num) {
1634 while ($i < $num) {
1635 $obj = $this->db->fetch_object($resql);
1636 $label = '';
1637 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1638 if (($obj->client) && (!empty($obj->code_client))) {
1639 $label = $obj->code_client . ' - ';
1640 }
1641 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1642 $label .= $obj->code_fournisseur . ' - ';
1643 }
1644 $label .= ' ' . $obj->name;
1645 } else {
1646 $label = $obj->name;
1647 }
1648
1649 if (!empty($obj->name_alias)) {
1650 $label .= ' (' . $obj->name_alias . ')';
1651 }
1652
1653 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1654 $label .= ' - '.$obj->tva_intra;
1655 }
1656
1657 $labelhtml = $label;
1658
1659 if ($showtype) {
1660 $companytemp->id = $obj->rowid;
1661 $companytemp->client = $obj->client;
1662 $companytemp->fournisseur = $obj->fournisseur;
1663 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1664 if ($tmptype) {
1665 $labelhtml .= ' ' . $tmptype;
1666 }
1667
1668 if ($obj->client || $obj->fournisseur) {
1669 $label .= ' (';
1670 }
1671 if ($obj->client == 1 || $obj->client == 3) {
1672 $label .= $langs->trans("Customer");
1673 }
1674 if ($obj->client == 2 || $obj->client == 3) {
1675 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1676 }
1677 if ($obj->fournisseur) {
1678 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1679 }
1680 if ($obj->client || $obj->fournisseur) {
1681 $label .= ')';
1682 }
1683 }
1684
1685 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1686 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1687 if (!empty($obj->country_code)) {
1688 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1689 }
1690 $label .= $s;
1691 $labelhtml .= $s;
1692 }
1693
1694 if (empty($outputmode)) {
1695 if (in_array($obj->rowid, $selected)) {
1696 $out .= '<option value="' . $obj->rowid . '" selected data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1697 } else {
1698 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1699 }
1700 } else {
1701 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1702 }
1703
1704 $i++;
1705 if (($i % 10) == 0) {
1706 $out .= "\n";
1707 }
1708 }
1709 }
1710 $out .= '</select>' . "\n";
1711 if (!$forcecombo) {
1712 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1713 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1714 }
1715 } else {
1716 dol_print_error($this->db);
1717 }
1718
1719 $this->result = array('nbofthirdparties' => $num);
1720
1721 if ($outputmode) {
1722 return $outarray;
1723 }
1724 return $out;
1725 }
1726
1727
1753 public function selectcontacts($socid, $selected = array(), $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = 0, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0, $filter = '')
1754 {
1755 global $conf, $user, $langs, $hookmanager, $action;
1756
1757 $langs->load('companies');
1758
1759 if (empty($htmlid)) {
1760 $htmlid = $htmlname;
1761 }
1762 $num = 0;
1763 $out = '';
1764 $outarray = array();
1765
1766 if ($selected === '') {
1767 $selected = array();
1768 } elseif (!is_array($selected)) {
1769 $selected = array((int) $selected);
1770 }
1771
1772 // Clean $filter that may contains sql conditions so sql code
1773 if (function_exists('testSqlAndScriptInject')) {
1774 if (testSqlAndScriptInject($filter, 3) > 0) {
1775 $filter = '';
1776 return 'SQLInjectionTryDetected';
1777 }
1778 }
1779
1780 if ($filter != '') { // If a filter was provided
1781 if (preg_match('/[\‍(\‍)]/', $filter)) {
1782 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1783 $errormsg = '';
1784 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1785
1786 // Redo clean $filter that may contains sql conditions so sql code
1787 if (function_exists('testSqlAndScriptInject')) {
1788 if (testSqlAndScriptInject($filter, 3) > 0) {
1789 $filter = '';
1790 return 'SQLInjectionTryDetected';
1791 }
1792 }
1793 } else {
1794 // If not, we do nothing. We already know that there is no parenthesis
1795 // TODO Disallow this case in a future by returning an error here.
1796 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1797 }
1798 }
1799
1800 if (!is_object($hookmanager)) {
1801 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1802 $hookmanager = new HookManager($this->db);
1803 }
1804
1805 // We search third parties
1806 $sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste, sp.email, sp.phone, sp.phone_perso, sp.phone_mobile, sp.town AS contact_town";
1807 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1808 $sql .= ", s.nom as company, s.town AS company_town";
1809 }
1810 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1811 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1812 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1813 }
1814 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1815 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1816 if ($socid > 0 || $socid == -1) {
1817 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1818 }
1819 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1820 $sql .= " AND sp.statut <> 0";
1821 }
1822 if ($filter) {
1823 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1824 // if not, by testSqlAndScriptInject() only.
1825 $sql .= " AND (" . $filter . ")";
1826 }
1827 // Add where from hooks
1828 $parameters = array();
1829 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1830 $sql .= $hookmanager->resPrint;
1831 $sql .= " ORDER BY sp.lastname ASC";
1832
1833 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1834 $resql = $this->db->query($sql);
1835 if ($resql) {
1836 $num = $this->db->num_rows($resql);
1837
1838 if ($htmlname != 'none' && !$options_only) {
1839 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1840 }
1841
1842 if ($showempty && !is_numeric($showempty)) {
1843 $textforempty = $showempty;
1844 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1845 } else {
1846 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1847 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1848 }
1849 if ($showempty == 2) {
1850 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1851 }
1852 }
1853
1854 $i = 0;
1855 if ($num) {
1856 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1857 $contactstatic = new Contact($this->db);
1858
1859 while ($i < $num) {
1860 $obj = $this->db->fetch_object($resql);
1861
1862 // Set email (or phones) and town extended infos
1863 $extendedInfos = '';
1864 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1865 $extendedInfos = array();
1866 $email = trim($obj->email);
1867 if (!empty($email)) {
1868 $extendedInfos[] = $email;
1869 } else {
1870 $phone = trim($obj->phone);
1871 $phone_perso = trim($obj->phone_perso);
1872 $phone_mobile = trim($obj->phone_mobile);
1873 if (!empty($phone)) {
1874 $extendedInfos[] = $phone;
1875 }
1876 if (!empty($phone_perso)) {
1877 $extendedInfos[] = $phone_perso;
1878 }
1879 if (!empty($phone_mobile)) {
1880 $extendedInfos[] = $phone_mobile;
1881 }
1882 }
1883 $contact_town = trim($obj->contact_town);
1884 $company_town = trim($obj->company_town);
1885 if (!empty($contact_town)) {
1886 $extendedInfos[] = $contact_town;
1887 } elseif (!empty($company_town)) {
1888 $extendedInfos[] = $company_town;
1889 }
1890 $extendedInfos = implode(' - ', $extendedInfos);
1891 if (!empty($extendedInfos)) {
1892 $extendedInfos = ' - ' . $extendedInfos;
1893 }
1894 }
1895
1896 $contactstatic->id = $obj->rowid;
1897 $contactstatic->lastname = $obj->lastname;
1898 $contactstatic->firstname = $obj->firstname;
1899 if ($obj->statut == 1) {
1900 $tmplabel = '';
1901 if ($htmlname != 'none') {
1902 $disabled = 0;
1903 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1904 $disabled = 1;
1905 }
1906 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1907 $disabled = 1;
1908 }
1909 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1910 $out .= '<option value="' . $obj->rowid . '"';
1911 if ($disabled) {
1912 $out .= ' disabled';
1913 }
1914 $out .= ' selected>';
1915
1916 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1917 if ($showfunction && $obj->poste) {
1918 $tmplabel .= ' (' . $obj->poste . ')';
1919 }
1920 if (($showsoc > 0) && $obj->company) {
1921 $tmplabel .= ' - (' . $obj->company . ')';
1922 }
1923
1924 $out .= $tmplabel;
1925 $out .= '</option>';
1926 } else {
1927 $out .= '<option value="' . $obj->rowid . '"';
1928 if ($disabled) {
1929 $out .= ' disabled';
1930 }
1931 $out .= '>';
1932
1933 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1934 if ($showfunction && $obj->poste) {
1935 $tmplabel .= ' (' . $obj->poste . ')';
1936 }
1937 if (($showsoc > 0) && $obj->company) {
1938 $tmplabel .= ' - (' . $obj->company . ')';
1939 }
1940
1941 $out .= $tmplabel;
1942 $out .= '</option>';
1943 }
1944 } else {
1945 if (in_array($obj->rowid, $selected)) {
1946 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1947 if ($showfunction && $obj->poste) {
1948 $tmplabel .= ' (' . $obj->poste . ')';
1949 }
1950 if (($showsoc > 0) && $obj->company) {
1951 $tmplabel .= ' - (' . $obj->company . ')';
1952 }
1953
1954 $out .= $tmplabel;
1955 }
1956 }
1957
1958 if ($tmplabel != '') {
1959 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1960 }
1961 }
1962 $i++;
1963 }
1964 } else {
1965 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1966 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1967 $out .= $labeltoshow;
1968 $out .= '</option>';
1969 }
1970
1971 $parameters = array(
1972 'socid' => $socid,
1973 'htmlname' => $htmlname,
1974 'resql' => $resql,
1975 'out' => &$out,
1976 'showfunction' => $showfunction,
1977 'showsoc' => $showsoc,
1978 );
1979
1980 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1981
1982 if ($htmlname != 'none' && !$options_only) {
1983 $out .= '</select>';
1984 }
1985
1986 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1987 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1988 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
1989 }
1990
1991 $this->num = $num;
1992
1993 if ($options_only === 2) {
1994 // Return array of options
1995 return $outarray;
1996 } else {
1997 return $out;
1998 }
1999 } else {
2000 dol_print_error($this->db);
2001 return -1;
2002 }
2003 }
2004
2005
2006 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2007
2018 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2019 {
2020 // phpcs:enable
2021 global $langs, $conf;
2022
2023 // On recherche les remises
2024 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2025 $sql .= " re.description, re.fk_facture_source";
2026 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2027 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2028 $sql .= " AND re.entity = " . $conf->entity;
2029 if ($filter) {
2030 $sql .= " AND " . $filter;
2031 }
2032 $sql .= " ORDER BY re.description ASC";
2033
2034 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2035 $resql = $this->db->query($sql);
2036 if ($resql) {
2037 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2038 $num = $this->db->num_rows($resql);
2039
2040 $qualifiedlines = $num;
2041
2042 $i = 0;
2043 if ($num) {
2044 print '<option value="0">&nbsp;</option>';
2045 while ($i < $num) {
2046 $obj = $this->db->fetch_object($resql);
2047 $desc = dol_trunc($obj->description, 40);
2048 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2049 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2050 }
2051 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2052 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2053 }
2054 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2055 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2056 }
2057 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2058 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2059 }
2060
2061 $selectstring = '';
2062 if ($selected > 0 && $selected == $obj->rowid) {
2063 $selectstring = ' selected';
2064 }
2065
2066 $disabled = '';
2067 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2068 $qualifiedlines--;
2069 $disabled = ' disabled';
2070 }
2071
2072 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2073 $tmpfac = new Facture($this->db);
2074 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2075 $desc = $desc . ' - ' . $tmpfac->ref;
2076 }
2077 }
2078
2079 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2080 $i++;
2081 }
2082 }
2083 print '</select>';
2084 print ajax_combobox('select_' . $htmlname);
2085
2086 return $qualifiedlines;
2087 } else {
2088 dol_print_error($this->db);
2089 return -1;
2090 }
2091 }
2092
2093
2094 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2095
2111 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2112 {
2113 // phpcs:enable
2114 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2115 }
2116
2117 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2118
2143 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2144 {
2145 // phpcs:enable
2146 global $conf, $user, $langs, $hookmanager;
2147 global $action;
2148
2149 // If no preselected user defined, we take current user
2150 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2151 $selected = $user->id;
2152 }
2153
2154 if ($selected === '') {
2155 $selected = array();
2156 } elseif (!is_array($selected)) {
2157 $selected = array($selected);
2158 }
2159
2160 $excludeUsers = null;
2161 $includeUsers = null;
2162
2163 // Exclude some users
2164 if (is_array($exclude)) {
2165 $excludeUsers = implode(",", $exclude);
2166 }
2167 // Include some uses
2168 if (is_array($include)) {
2169 $includeUsers = implode(",", $include);
2170 } elseif ($include == 'hierarchy') {
2171 // Build list includeUsers to have only hierarchy
2172 $includeUsers = implode(",", $user->getAllChildIds(0));
2173 } elseif ($include == 'hierarchyme') {
2174 // Build list includeUsers to have only hierarchy and current user
2175 $includeUsers = implode(",", $user->getAllChildIds(1));
2176 }
2177
2178 $num = 0;
2179
2180 $out = '';
2181 $outarray = array();
2182 $outarray2 = array();
2183
2184 // Do we want to show the label of entity into the combo list ?
2185 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2186 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2187
2188 // Forge request to select users
2189 $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.gender, u.photo";
2190 if ($showlabelofentity) {
2191 $sql .= ", e.label";
2192 }
2193 $sql .= " FROM " . $this->db->prefix() . "user as u";
2194 if ($showlabelofentity) {
2195 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2196 }
2197 // Condition here should be the same than into societe->getSalesRepresentatives().
2198 if ($userissuperadminentityone && $force_entity != 'default') {
2199 if (!empty($force_entity)) {
2200 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2201 } else {
2202 $sql .= " WHERE u.entity IS NOT NULL";
2203 }
2204 } else {
2205 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2206 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2207 } else {
2208 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2209 }
2210 }
2211
2212 if (!empty($user->socid)) {
2213 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2214 }
2215 if (is_array($exclude) && $excludeUsers) {
2216 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2217 }
2218 if ($includeUsers) {
2219 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2220 }
2221 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2222 $sql .= " AND u.statut <> 0";
2223 }
2224 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2225 $sql .= " AND u.employee <> 0";
2226 }
2227 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2228 $sql .= " AND u.fk_soc IS NULL";
2229 }
2230 if (!empty($morefilter)) {
2231 $sql .= " " . $morefilter;
2232 }
2233
2234 //Add hook to filter on user (for example on usergroup define in custom modules)
2235 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2236 if (!empty($reshook)) {
2237 $sql .= $hookmanager->resPrint;
2238 }
2239
2240 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2241 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2242 } else {
2243 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2244 }
2245
2246 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2247
2248 $resql = $this->db->query($sql);
2249 if ($resql) {
2250 $num = $this->db->num_rows($resql);
2251 $i = 0;
2252 if ($num) {
2253 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2254 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2255 if ($show_empty && !$multiple) {
2256 $textforempty = ' ';
2257 if (!empty($conf->use_javascript_ajax)) {
2258 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2259 }
2260 if (!is_numeric($show_empty)) {
2261 $textforempty = $show_empty;
2262 }
2263 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2264
2265 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2266 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2267 'id' => ($show_empty < 0 ? $show_empty : -1),
2268 'label' => $textforempty,
2269 'labelhtml' => $textforempty,
2270 'color' => '',
2271 'picto' => ''
2272 );
2273 }
2274 if ($show_every) {
2275 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2276
2277 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2278 $outarray2[-2] = array(
2279 'id' => -2,
2280 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2281 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2282 'color' => '',
2283 'picto' => ''
2284 );
2285 }
2286
2287 $userstatic = new User($this->db);
2288
2289 while ($i < $num) {
2290 $obj = $this->db->fetch_object($resql);
2291
2292 $userstatic->id = $obj->rowid;
2293 $userstatic->lastname = $obj->lastname;
2294 $userstatic->firstname = $obj->firstname;
2295 $userstatic->photo = $obj->photo;
2296 $userstatic->status = $obj->status;
2297 $userstatic->entity = $obj->entity;
2298 $userstatic->admin = $obj->admin;
2299 $userstatic->gender = $obj->gender;
2300
2301 $disableline = '';
2302 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2303 $disableline = ($enableonlytext ? $enableonlytext : '1');
2304 }
2305
2306 $labeltoshow = '';
2307 $labeltoshowhtml = '';
2308
2309 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2310 $fullNameMode = 0;
2311 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2312 $fullNameMode = 1; //Firstname+lastname
2313 }
2314 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2315 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2316 if (empty($obj->firstname) && empty($obj->lastname)) {
2317 $labeltoshow .= $obj->login;
2318 $labeltoshowhtml .= $obj->login;
2319 }
2320
2321 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2322 $moreinfo = '';
2323 $moreinfohtml = '';
2324 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2325 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2326 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2327 $moreinfo .= $obj->login;
2328 $moreinfohtml .= $obj->login;
2329 }
2330 if ($showstatus >= 0) {
2331 if ($obj->status == 1 && $showstatus == 1) {
2332 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2333 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2334 }
2335 if ($obj->status == 0 && $showstatus == 1) {
2336 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2337 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2338 }
2339 }
2340 if ($showlabelofentity) {
2341 if (empty($obj->entity)) {
2342 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2343 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2344 } else {
2345 if ($obj->entity != $conf->entity) {
2346 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2347 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2348 }
2349 }
2350 }
2351 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2352 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2353 if (!empty($disableline) && $disableline != '1') {
2354 // Add text from $enableonlytext parameter
2355 $moreinfo .= ' - ' . $disableline;
2356 $moreinfohtml .= ' - ' . $disableline;
2357 }
2358 $labeltoshow .= $moreinfo;
2359 $labeltoshowhtml .= $moreinfohtml;
2360
2361 $out .= '<option value="' . $obj->rowid . '"';
2362 if (!empty($disableline)) {
2363 $out .= ' disabled';
2364 }
2365 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2366 $out .= ' selected';
2367 }
2368 $out .= ' data-html="';
2369
2370 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2371 if ($showstatus >= 0 && $obj->status == 0) {
2372 $outhtml .= '<strike class="opacitymediumxxx">';
2373 }
2374 $outhtml .= $labeltoshowhtml;
2375 if ($showstatus >= 0 && $obj->status == 0) {
2376 $outhtml .= '</strike>';
2377 }
2378 $labeltoshowhtml = $outhtml;
2379
2380 $out .= dol_escape_htmltag($outhtml);
2381 $out .= '">';
2382 $out .= $labeltoshow;
2383 $out .= '</option>';
2384
2385 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2386 $outarray2[$userstatic->id] = array(
2387 'id' => $userstatic->id,
2388 'label' => $labeltoshow,
2389 'labelhtml' => $labeltoshowhtml,
2390 'color' => '',
2391 'picto' => ''
2392 );
2393
2394 $i++;
2395 }
2396 } else {
2397 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2398 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2399 }
2400 $out .= '</select>';
2401
2402 if ($num && !$forcecombo) {
2403 // Enhance with select2
2404 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2405 $out .= ajax_combobox($htmlname);
2406 }
2407 } else {
2408 dol_print_error($this->db);
2409 }
2410
2411 $this->num = $num;
2412
2413 if ($outputmode == 2) {
2414 return $outarray2;
2415 } elseif ($outputmode) {
2416 return $outarray;
2417 }
2418
2419 return $out;
2420 }
2421
2422
2423 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2446 public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array())
2447 {
2448 // phpcs:enable
2449 global $langs;
2450
2451 $userstatic = new User($this->db);
2452 $out = '';
2453
2454 if (!empty($_SESSION['assignedtouser'])) {
2455 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2456 if (!is_array($assignedtouser)) {
2457 $assignedtouser = array();
2458 }
2459 } else {
2460 $assignedtouser = array();
2461 }
2462 $nbassignetouser = count($assignedtouser);
2463
2464 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2465 if ($nbassignetouser) {
2466 $out .= '<ul class="attendees">';
2467 }
2468 $i = 0;
2469 $ownerid = 0;
2470 foreach ($assignedtouser as $key => $value) {
2471 if ($value['id'] == $ownerid) {
2472 continue;
2473 }
2474
2475 $out .= '<li>';
2476 $userstatic->fetch($value['id']);
2477 $out .= $userstatic->getNomUrl(-1);
2478 if ($i == 0) {
2479 $ownerid = $value['id'];
2480 $out .= ' (' . $langs->trans("Owner") . ')';
2481 }
2482 if ($nbassignetouser > 1 && $action != 'view') {
2483 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $userstatic->id . '" class="removedassigned reposition" id="removedassigned_' . $userstatic->id . '" name="removedassigned_' . $userstatic->id . '">';
2484 }
2485 // Show my availability
2486 if ($showproperties) {
2487 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2488 $out .= '<div class="myavailability inline-block">';
2489 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparency" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofuserid[$ownerid]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2490 $out .= '</div>';
2491 }
2492 }
2493 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2494 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2495
2496 $out .= '</li>';
2497 $i++;
2498 }
2499 if ($nbassignetouser) {
2500 $out .= '</ul>';
2501 }
2502
2503 // Method with no ajax
2504 if ($action != 'view') {
2505 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2506 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2507 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2508 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2509 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2510 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2511 $out .= '});';
2512 $out .= '})</script>';
2513 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2514 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2515 $out .= '<br>';
2516 }
2517
2518 return $out;
2519 }
2520
2521 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2541 public function select_dolresources_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofresourceid = array())
2542 {
2543 // phpcs:enable
2544 global $langs;
2545
2546 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2547 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2548 $formresources = new FormResource($this->db);
2549 $resourcestatic = new Dolresource($this->db);
2550
2551 $out = '';
2552 if (!empty($_SESSION['assignedtoresource'])) {
2553 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2554 if (!is_array($assignedtoresource)) {
2555 $assignedtoresource = array();
2556 }
2557 } else {
2558 $assignedtoresource = array();
2559 }
2560 $nbassignetoresource = count($assignedtoresource);
2561
2562 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2563 if ($nbassignetoresource) {
2564 $out .= '<ul class="attendees">';
2565 }
2566 $i = 0;
2567
2568 foreach ($assignedtoresource as $key => $value) {
2569 $out .= '<li>';
2570 $resourcestatic->fetch($value['id']);
2571 $out .= $resourcestatic->getNomUrl(-1);
2572 if ($nbassignetoresource >= 1 && $action != 'view') {
2573 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassignedresource reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2574 }
2575 // Show my availability
2576 if ($showproperties) {
2577 if (is_array($listofresourceid) && count($listofresourceid)) {
2578 $out .= '<div class="myavailability inline-block">';
2579 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparencyresource" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2580 $out .= '</div>';
2581 }
2582 }
2583 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2584 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2585
2586 $out .= '</li>';
2587 $i++;
2588 }
2589 if ($nbassignetoresource) {
2590 $out .= '</ul>';
2591 }
2592
2593 // Method with no ajax
2594 if ($action != 'view') {
2595 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2596 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2597 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2598 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2599 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2600 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2601 $out .= '});';
2602 $out .= '})</script>';
2603
2604 $events = array();
2605 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2606 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2607 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2608 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2609 $out .= '<br>';
2610 }
2611
2612 return $out;
2613 }
2614
2615 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2616
2647 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)
2648 {
2649 // phpcs:enable
2650 global $langs, $conf;
2651
2652 $out = '';
2653
2654 // check parameters
2655 $price_level = (!empty($price_level) ? $price_level : 0);
2656 if (is_null($ajaxoptions)) {
2657 $ajaxoptions = array();
2658 }
2659
2660 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2661 if (isModEnabled("product") && !isModEnabled('service')) {
2662 $filtertype = '0';
2663 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2664 $filtertype = '1';
2665 }
2666 }
2667
2668 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2669 $placeholder = '';
2670
2671 if ($selected && empty($selected_input_value)) {
2672 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2673 $producttmpselect = new Product($this->db);
2674 $producttmpselect->fetch($selected);
2675 $selected_input_value = $producttmpselect->ref;
2676 unset($producttmpselect);
2677 }
2678 // handle case where product or service module is disabled + no filter specified
2679 if ($filtertype == '') {
2680 if (!isModEnabled('product')) { // when product module is disabled, show services only
2681 $filtertype = 1;
2682 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2683 $filtertype = 0;
2684 }
2685 }
2686 // mode=1 means customers products
2687 $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;
2688 if ((int) $warehouseId > 0) {
2689 $urloption .= '&warehouseid=' . (int) $warehouseId;
2690 }
2691 $out .= ajax_autocompleter((string) $selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), getDolGlobalInt('PRODUCT_SEARCH_AUTO_SELECT_IF_ONLY_ONE', 1), $ajaxoptions);
2692
2693 if (isModEnabled('variants') && is_array($selected_combinations)) {
2694 // Code to automatically insert with javascript the select of attributes under the select of product
2695 // when a parent of variant has been selected.
2696 $out .= '
2697 <!-- script to auto show attributes select tags if a variant was selected -->
2698 <script nonce="' . getNonce() . '">
2699 // auto show attributes fields
2700 selected = ' . json_encode($selected_combinations) . ';
2701 combvalues = {};
2702
2703 jQuery(document).ready(function () {
2704
2705 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2706 if (jQuery(this).val() == \'free\') {
2707 jQuery(\'div#attributes_box\').empty();
2708 }
2709 });
2710
2711 jQuery("input#' . $htmlname . '").change(function () {
2712
2713 if (!jQuery(this).val()) {
2714 jQuery(\'div#attributes_box\').empty();
2715 return;
2716 }
2717
2718 console.log("A change has started. We get variants fields to inject html select");
2719
2720 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2721 id: jQuery(this).val()
2722 }, function (data) {
2723 jQuery(\'div#attributes_box\').empty();
2724
2725 jQuery.each(data, function (key, val) {
2726
2727 combvalues[val.id] = val.values;
2728
2729 var span = jQuery(document.createElement(\'div\')).css({
2730 \'display\': \'table-row\'
2731 });
2732
2733 span.append(
2734 jQuery(document.createElement(\'div\')).text(val.label).css({
2735 \'font-weight\': \'bold\',
2736 \'display\': \'table-cell\'
2737 })
2738 );
2739
2740 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2741 \'margin-left\': \'15px\',
2742 \'white-space\': \'pre\'
2743 }).append(
2744 jQuery(document.createElement(\'option\')).val(\'\')
2745 );
2746
2747 jQuery.each(combvalues[val.id], function (key, val) {
2748 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2749
2750 if (selected[val.fk_product_attribute] == val.id) {
2751 tag.attr(\'selected\', \'selected\');
2752 }
2753
2754 html.append(tag);
2755 });
2756
2757 span.append(html);
2758 jQuery(\'div#attributes_box\').append(span);
2759 });
2760 })
2761 });
2762
2763 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2764 });
2765 </script>
2766 ';
2767 }
2768
2769 if (empty($hidelabel)) {
2770 $out .= $langs->trans("RefOrLabel") . ' : ';
2771 } elseif ($hidelabel > 1) {
2772 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
2773 if ($hidelabel == 2) {
2774 $out .= img_picto($langs->trans("Search"), 'search');
2775 }
2776 }
2777 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2778 if ($hidelabel == 3) {
2779 $out .= img_picto($langs->trans("Search"), 'search');
2780 }
2781 } else {
2782 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2783 }
2784
2785 if (empty($nooutput)) {
2786 print $out;
2787 } else {
2788 return $out;
2789 }
2790 }
2791
2792 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2793
2809 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2810 {
2811 // phpcs:enable
2812 global $db;
2813
2814 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2815
2816 $error = 0;
2817 $out = '';
2818
2819 if (!$forcecombo) {
2820 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2821 $events = array();
2822 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2823 }
2824
2825 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2826
2827 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2828 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2829 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2830 if (!empty($status)) {
2831 $sql .= ' AND status = ' . (int) $status;
2832 }
2833 if (!empty($type)) {
2834 $sql .= ' AND bomtype = ' . (int) $type;
2835 }
2836 if (!empty($TProducts)) {
2837 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2838 }
2839 if (!empty($limit)) {
2840 $sql .= ' LIMIT ' . (int) $limit;
2841 }
2842 $resql = $db->query($sql);
2843 if ($resql) {
2844 if ($showempty) {
2845 $out .= '<option value="-1"';
2846 if (empty($selected)) {
2847 $out .= ' selected';
2848 }
2849 $out .= '>&nbsp;</option>';
2850 }
2851 while ($obj = $db->fetch_object($resql)) {
2852 $product = new Product($db);
2853 $res = $product->fetch($obj->fk_product);
2854 $out .= '<option value="' . $obj->rowid . '"';
2855 if ($obj->rowid == $selected) {
2856 $out .= 'selected';
2857 }
2858 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2859 }
2860 } else {
2861 $error++;
2862 dol_print_error($db);
2863 }
2864 $out .= '</select>';
2865 if (empty($nooutput)) {
2866 print $out;
2867 } else {
2868 return $out;
2869 }
2870 }
2871
2872 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2873
2900 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)
2901 {
2902 // phpcs:enable
2903 global $langs;
2904 global $hookmanager;
2905
2906 $out = '';
2907 $outarray = array();
2908
2909 // Units
2910 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2911 $langs->load('other');
2912 }
2913
2914 $warehouseStatusArray = array();
2915 if (!empty($warehouseStatus)) {
2916 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2917 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2918 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2919 }
2920 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2921 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2922 }
2923 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2924 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2925 }
2926 }
2927
2928 $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";
2929 if (count($warehouseStatusArray)) {
2930 $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
2931 } else {
2932 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2933 }
2934
2935 $sql = "SELECT ";
2936
2937 // Add select from hooks
2938 $parameters = array();
2939 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2940 if (empty($reshook)) {
2941 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2942 } else {
2943 $sql .= $hookmanager->resPrint;
2944 }
2945
2946 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2947 //Product category
2948 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2949 FROM " . $this->db->prefix() . "categorie_product
2950 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2951 LIMIT 1
2952 ) AS categorie_product_id ";
2953 }
2954
2955 //Price by customer
2956 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
2957 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2958 $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';
2959 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2960 }
2961 // Units
2962 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2963 $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";
2964 $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';
2965 }
2966
2967 // Multilang : we add translation
2968 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2969 $sql .= ", pl.label as label_translated";
2970 $sql .= ", pl.description as description_translated";
2971 $selectFields .= ", label_translated";
2972 $selectFields .= ", description_translated";
2973 }
2974 // Price by quantity
2975 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2976 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2977 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2978 $sql .= " AND price_level = " . ((int) $price_level);
2979 }
2980 $sql .= " ORDER BY date_price";
2981 $sql .= " DESC LIMIT 1) as price_rowid";
2982 $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
2983 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2984 $sql .= " AND price_level = " . ((int) $price_level);
2985 }
2986 $sql .= " ORDER BY date_price";
2987 $sql .= " DESC LIMIT 1) as price_by_qty";
2988 $selectFields .= ", price_rowid, price_by_qty";
2989 }
2990
2991 $sql .= " FROM ".$this->db->prefix()."product as p";
2992
2993 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
2994 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
2995 }
2996
2997 // Add from (left join) from hooks
2998 $parameters = array();
2999 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3000 $sql .= $hookmanager->resPrint;
3001
3002 if (count($warehouseStatusArray)) {
3003 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
3004 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3005 $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.
3006 }
3007
3008 // include search in supplier ref
3009 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3010 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3011 }
3012
3013 //Price by customer
3014 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3015 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
3016 }
3017 // Units
3018 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3019 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3020 }
3021 // Multilang : we add translation
3022 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3023 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3024 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3025 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3026 $soc = new Societe($this->db);
3027 $result = $soc->fetch($socid);
3028 if ($result > 0 && !empty($soc->default_lang)) {
3029 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3030 } else {
3031 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3032 }
3033 } else {
3034 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3035 }
3036 }
3037
3038 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3039 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3040 }
3041
3042 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3043
3044 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3045 $sql .= " AND pac.rowid IS NULL";
3046 }
3047
3048 if ($finished == 0) {
3049 $sql .= " AND p.finished = " . ((int) $finished);
3050 } elseif ($finished == 1) {
3051 $sql .= " AND p.finished = ".((int) $finished);
3052 }
3053 if ($status >= 0) {
3054 $sql .= " AND p.tosell = ".((int) $status);
3055 }
3056 if ($status_purchase >= 0) {
3057 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3058 }
3059 // Filter by product type
3060 if (strval($filtertype) != '') {
3061 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3062 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3063 $sql .= " AND p.fk_product_type = 1";
3064 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3065 $sql .= " AND p.fk_product_type = 0";
3066 }
3067
3068 if ((int) $warehouseId > 0) {
3069 $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)";
3070 }
3071
3072 // Add where from hooks
3073 $parameters = array();
3074 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3075 $sql .= $hookmanager->resPrint;
3076 // Add criteria on ref/label
3077 if ($filterkey != '') {
3078 $sql .= ' AND (';
3079 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3080 // For natural search
3081 $search_crit = explode(' ', $filterkey);
3082 $i = 0;
3083 if (count($search_crit) > 1) {
3084 $sql .= "(";
3085 }
3086 foreach ($search_crit as $crit) {
3087 if ($i > 0) {
3088 $sql .= " AND ";
3089 }
3090 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3091 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3092 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3093 }
3094 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3095 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3096 }
3097 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3098 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3099 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3100 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3101 }
3102 }
3103 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3104 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3105 }
3106 $sql .= ")";
3107 $i++;
3108 }
3109 if (count($search_crit) > 1) {
3110 $sql .= ")";
3111 }
3112 if (isModEnabled('barcode')) {
3113 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3114 }
3115 $sql .= ')';
3116 }
3117 if (count($warehouseStatusArray)) {
3118 $sql .= " GROUP BY " . $selectFields;
3119 }
3120
3121 //Sort by category
3122 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3123 $sql .= " ORDER BY categorie_product_id ";
3124 //ASC OR DESC order
3125 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3126 } else {
3127 $sql .= $this->db->order("p.ref");
3128 }
3129
3130 $sql .= $this->db->plimit($limit, 0);
3131
3132 // Build output string
3133 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3134 $result = $this->db->query($sql);
3135 if ($result) {
3136 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3137 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3138 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3139
3140 $num = $this->db->num_rows($result);
3141
3142 $events = array();
3143
3144 if (!$forcecombo) {
3145 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3146 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3147 }
3148
3149 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3150
3151 $textifempty = '';
3152 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3153 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3154 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3155 if ($showempty && !is_numeric($showempty)) {
3156 $textifempty = $langs->trans($showempty);
3157 } else {
3158 $textifempty .= $langs->trans("All");
3159 }
3160 } else {
3161 if ($showempty && !is_numeric($showempty)) {
3162 $textifempty = $langs->trans($showempty);
3163 }
3164 }
3165 if ($showempty) {
3166 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3167 }
3168
3169 $i = 0;
3170 while ($num && $i < $num) {
3171 $opt = '';
3172 $optJson = array();
3173 $objp = $this->db->fetch_object($result);
3174
3175 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
3176 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3177 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3178 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3179 $sql .= " ORDER BY quantity ASC";
3180
3181 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3182 $result2 = $this->db->query($sql);
3183 if ($result2) {
3184 $nb_prices = $this->db->num_rows($result2);
3185 $j = 0;
3186 while ($nb_prices && $j < $nb_prices) {
3187 $objp2 = $this->db->fetch_object($result2);
3188
3189 $objp->price_by_qty_rowid = $objp2->rowid;
3190 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3191 $objp->price_by_qty_quantity = $objp2->quantity;
3192 $objp->price_by_qty_unitprice = $objp2->unitprice;
3193 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3194 // For backward compatibility
3195 $objp->quantity = $objp2->quantity;
3196 $objp->price = $objp2->price;
3197 $objp->unitprice = $objp2->unitprice;
3198 $objp->remise_percent = $objp2->remise_percent;
3199
3200 //$objp->tva_tx is not overwritten by $objp2 value
3201 //$objp->default_vat_code is not overwritten by $objp2 value
3202
3203 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3204 '@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';
3205 $j++;
3206
3207 // Add new entry
3208 // "key" value of json key array is used by jQuery automatically as selected value
3209 // "label" value of json key array is used by jQuery automatically as text for combo box
3210 $out .= $opt;
3211 array_push($outarray, $optJson);
3212 }
3213 }
3214 } else {
3215 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3216 $price_product = new Product($this->db);
3217 $price_product->fetch($objp->rowid, '', '', 1);
3218
3219 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3220 $priceparser = new PriceParser($this->db);
3221 $price_result = $priceparser->parseProduct($price_product);
3222 if ($price_result >= 0) {
3223 $objp->price = $price_result;
3224 $objp->unitprice = $price_result;
3225 //Calculate the VAT
3226 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3227 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3228 }
3229 }
3230 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3231 $price_level = '';
3232 }
3233 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3234 // Add new entry
3235 // "key" value of json key array is used by jQuery automatically as selected value
3236 // "label" value of json key array is used by jQuery automatically as text for combo box
3237 $out .= $opt;
3238 array_push($outarray, $optJson);
3239 }
3240
3241 $i++;
3242 }
3243
3244 $out .= '</select>';
3245
3246 $this->db->free($result);
3247
3248 if (empty($outputmode)) {
3249 return $out;
3250 }
3251
3252 return $outarray;
3253 } else {
3254 dol_print_error($this->db);
3255 }
3256
3257 return '';
3258 }
3259
3275 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3276 {
3277 global $langs, $conf, $user;
3278 global $hookmanager;
3279
3280 $outkey = '';
3281 $outval = '';
3282 $outref = '';
3283 $outlabel = '';
3284 $outlabel_translated = '';
3285 $outdesc = '';
3286 $outdesc_translated = '';
3287 $outbarcode = '';
3288 $outorigin = '';
3289 $outtype = '';
3290 $outprice_ht = '';
3291 $outprice_ttc = '';
3292 $outpricebasetype = '';
3293 $outtva_tx = '';
3294 $outdefault_vat_code = '';
3295 $outqty = 1;
3296 $outdiscount = 0;
3297
3298 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3299
3300 $label = $objp->label;
3301 if (!empty($objp->label_translated)) {
3302 $label = $objp->label_translated;
3303 }
3304 if (!empty($filterkey) && $filterkey != '') {
3305 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3306 }
3307
3308 $outkey = $objp->rowid;
3309 $outref = $objp->ref;
3310 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3311 $outlabel = $objp->label;
3312 $outdesc = $objp->description;
3313 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3314 $outlabel_translated = $objp->label_translated;
3315 $outdesc_translated = $objp->description_translated;
3316 }
3317 $outbarcode = $objp->barcode;
3318 $outorigin = $objp->fk_country;
3319 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3320
3321 $outtype = $objp->fk_product_type;
3322 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3323 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3324
3325 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3326 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3327 }
3328
3329 // Units
3330 $outvalUnits = '';
3331 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3332 if (!empty($objp->unit_short)) {
3333 $outvalUnits .= ' - ' . $objp->unit_short;
3334 }
3335 }
3336 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3337 if (!empty($objp->weight) && $objp->weight_units !== null) {
3338 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3339 $outvalUnits .= ' - ' . $unitToShow;
3340 }
3341 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3342 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3343 $outvalUnits .= ' - ' . $unitToShow;
3344 }
3345 if (!empty($objp->surface) && $objp->surface_units !== null) {
3346 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3347 $outvalUnits .= ' - ' . $unitToShow;
3348 }
3349 if (!empty($objp->volume) && $objp->volume_units !== null) {
3350 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3351 $outvalUnits .= ' - ' . $unitToShow;
3352 }
3353 }
3354 if ($outdurationvalue && $outdurationunit) {
3355 $da = array(
3356 'h' => $langs->trans('Hour'),
3357 'd' => $langs->trans('Day'),
3358 'w' => $langs->trans('Week'),
3359 'm' => $langs->trans('Month'),
3360 'y' => $langs->trans('Year')
3361 );
3362 if (isset($da[$outdurationunit])) {
3363 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3364 }
3365 }
3366
3367 // Set stocktag (stock too low or not or unknown)
3368 $stocktag = 0;
3369 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3370 if ($user->hasRight('stock', 'lire')) {
3371 if ($objp->stock > 0) {
3372 $stocktag = 1;
3373 } elseif ($objp->stock <= 0) {
3374 $stocktag = -1;
3375 }
3376 }
3377 }
3378
3379 // Set $labeltoshow
3380 $labeltoshow = '';
3381 $labeltoshow .= $objp->ref;
3382 if (!empty($objp->custref)) {
3383 $labeltoshow .= ' (' . $objp->custref . ')';
3384 }
3385 if ($outbarcode) {
3386 $labeltoshow .= ' (' . $outbarcode . ')';
3387 }
3388 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3389 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3390 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3391 }
3392
3393 // Set $labltoshowhtml
3394 $labeltoshowhtml = '';
3395 $labeltoshowhtml .= $objp->ref;
3396 if (!empty($objp->custref)) {
3397 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3398 }
3399 if (!empty($filterkey) && $filterkey != '') {
3400 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3401 }
3402 if ($outbarcode) {
3403 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3404 }
3405 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3406 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3407 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3408 }
3409
3410 // Stock
3411 $labeltoshowstock = '';
3412 $labeltoshowhtmlstock = '';
3413 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3414 if ($user->hasRight('stock', 'lire')) {
3415 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3416
3417 if ($objp->stock > 0) {
3418 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3419 } elseif ($objp->stock <= 0) {
3420 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3421 }
3422 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3423 $labeltoshowhtmlstock .= '</span>';
3424
3425 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3426 $langs->load("stocks");
3427
3428 $tmpproduct = new Product($this->db);
3429 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3430 $tmpproduct->load_virtual_stock();
3431 $virtualstock = $tmpproduct->stock_theorique;
3432
3433 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3434
3435 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3436 if ($virtualstock > 0) {
3437 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3438 } elseif ($virtualstock <= 0) {
3439 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3440 }
3441 $labeltoshowhtmlstock .= $virtualstock;
3442 $labeltoshowhtmlstock .= '</span>';
3443
3444 unset($tmpproduct);
3445 }
3446 }
3447 }
3448
3449 // Price
3450 $found = 0;
3451 $labeltoshowprice = '';
3452 $labeltoshowhtmlprice = '';
3453 // If we need a particular price level (from 1 to n)
3454 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3455 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3456 $sql .= " FROM " . $this->db->prefix() . "product_price";
3457 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3458 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3459 $sql .= " AND price_level = " . ((int) $price_level);
3460 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3461 $sql .= " LIMIT 1";
3462
3463 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3464 $result2 = $this->db->query($sql);
3465 if ($result2) {
3466 $objp2 = $this->db->fetch_object($result2);
3467 if ($objp2) {
3468 $found = 1;
3469 if ($objp2->price_base_type == 'HT') {
3470 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3471 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3472 } else {
3473 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3474 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3475 }
3476 $outprice_ht = price($objp2->price);
3477 $outprice_ttc = price($objp2->price_ttc);
3478 $outpricebasetype = $objp2->price_base_type;
3479 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3480 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3481 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3482 } else {
3483 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3484 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3485 }
3486 }
3487 } else {
3488 dol_print_error($this->db);
3489 }
3490 }
3491
3492 // Price by quantity
3493 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3494 $found = 1;
3495 $outqty = $objp->quantity;
3496 $outdiscount = $objp->remise_percent;
3497 if ($objp->quantity == 1) {
3498 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3499 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3500 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3501 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3502 } else {
3503 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3504 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3505 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3506 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3507 }
3508
3509 $outprice_ht = price($objp->unitprice);
3510 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3511 $outpricebasetype = $objp->price_base_type;
3512 $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
3513 $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
3514 }
3515 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3516 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3517 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3518 }
3519 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3520 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3521 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3522 }
3523
3524 // Price by customer
3525 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3526 if (!empty($objp->idprodcustprice)) {
3527 $found = 1;
3528
3529 if ($objp->custprice_base_type == 'HT') {
3530 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3531 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3532 } else {
3533 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3534 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3535 }
3536
3537 $outprice_ht = price($objp->custprice);
3538 $outprice_ttc = price($objp->custprice_ttc);
3539 $outpricebasetype = $objp->custprice_base_type;
3540 $outtva_tx = $objp->custtva_tx;
3541 $outdefault_vat_code = $objp->custdefault_vat_code;
3542 }
3543 }
3544
3545 // If level no defined or multiprice not found, we used the default price
3546 if (empty($hidepriceinlabel) && !$found) {
3547 if ($objp->price_base_type == 'HT') {
3548 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3549 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3550 } else {
3551 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3552 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3553 }
3554 $outprice_ht = price($objp->price);
3555 $outprice_ttc = price($objp->price_ttc);
3556 $outpricebasetype = $objp->price_base_type;
3557 $outtva_tx = $objp->tva_tx;
3558 $outdefault_vat_code = $objp->default_vat_code;
3559 }
3560
3561 // Build options
3562 $opt = '<option value="' . $objp->rowid . '"';
3563 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3564 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3565 $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 . '"';
3566 }
3567 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3568 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3569 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3570 }
3571
3572 if ($stocktag == 1) {
3573 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3574 //$opt .= ' class="product_line_stock_ok"';
3575 }
3576 if ($stocktag == -1) {
3577 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3578 //$opt .= ' class="product_line_stock_too_low"';
3579 }
3580
3581 $opt .= '>';
3582
3583 // Ref, barcode, country
3584 $opt .= $labeltoshow;
3585 $outval .= $labeltoshowhtml;
3586
3587 // Units
3588 $opt .= $outvalUnits;
3589 $outval .= $outvalUnits;
3590
3591 // Price
3592 $opt .= $labeltoshowprice;
3593 $outval .= $labeltoshowhtmlprice;
3594
3595 // Stock
3596 $opt .= $labeltoshowstock;
3597 $outval .= $labeltoshowhtmlstock;
3598
3599
3600 $parameters = array('objp' => $objp);
3601 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3602 if (empty($reshook)) {
3603 $opt .= $hookmanager->resPrint;
3604 } else {
3605 $opt = $hookmanager->resPrint;
3606 }
3607
3608 $opt .= "</option>\n";
3609 $optJson = array(
3610 'key' => $outkey,
3611 'value' => $outref,
3612 'label' => $outval,
3613 'label2' => $outlabel,
3614 'desc' => $outdesc,
3615 'type' => $outtype,
3616 'price_ht' => price2num($outprice_ht),
3617 'price_ttc' => price2num($outprice_ttc),
3618 'price_ht_locale' => price(price2num($outprice_ht)),
3619 'price_ttc_locale' => price(price2num($outprice_ttc)),
3620 'pricebasetype' => $outpricebasetype,
3621 'tva_tx' => $outtva_tx,
3622 'default_vat_code' => $outdefault_vat_code,
3623 'qty' => $outqty,
3624 'discount' => $outdiscount,
3625 'duration_value' => $outdurationvalue,
3626 'duration_unit' => $outdurationunit,
3627 'pbq' => $outpbq,
3628 'labeltrans' => $outlabel_translated,
3629 'desctrans' => $outdesc_translated,
3630 'ref_customer' => $outrefcust
3631 );
3632 }
3633
3634 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3635
3651 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3652 {
3653 // phpcs:enable
3654 global $langs, $conf;
3655 global $price_level, $status, $finished;
3656
3657 if (!isset($status)) {
3658 $status = 1;
3659 }
3660
3661 $selected_input_value = '';
3662 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3663 if ($selected > 0) {
3664 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3665 $producttmpselect = new Product($this->db);
3666 $producttmpselect->fetch($selected);
3667 $selected_input_value = $producttmpselect->ref;
3668 unset($producttmpselect);
3669 }
3670
3671 // mode=2 means suppliers products
3672 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3673 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3674
3675 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3676 } else {
3677 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3678 }
3679 }
3680
3681 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3682
3701 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 = '')
3702 {
3703 // phpcs:enable
3704 global $langs, $conf, $user;
3705 global $hookmanager;
3706
3707 $out = '';
3708 $outarray = array();
3709
3710 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3711
3712 $langs->load('stocks');
3713 // Units
3714 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3715 $langs->load('other');
3716 }
3717
3718 $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,";
3719 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3720 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3721 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3722 $sql .= ", pfp.supplier_reputation";
3723 // if we use supplier description of the products
3724 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3725 $sql .= ", pfp.desc_fourn as description";
3726 } else {
3727 $sql .= ", p.description";
3728 }
3729 // Units
3730 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3731 $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";
3732 }
3733 $sql .= " FROM " . $this->db->prefix() . "product as p";
3734 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3735 if ($socid > 0) {
3736 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3737 }
3738 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3739 // Units
3740 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3741 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3742 }
3743 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3744 if ($statut != -1) {
3745 $sql .= " AND p.tobuy = " . ((int) $statut);
3746 }
3747 if (strval($filtertype) != '') {
3748 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3749 }
3750 if (!empty($filtre)) {
3751 $sql .= " " . $filtre;
3752 }
3753 // Add where from hooks
3754 $parameters = array();
3755 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3756 $sql .= $hookmanager->resPrint;
3757 // Add criteria on ref/label
3758 if ($filterkey != '') {
3759 $sql .= ' AND (';
3760 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3761 // For natural search
3762 $search_crit = explode(' ', $filterkey);
3763 $i = 0;
3764 if (count($search_crit) > 1) {
3765 $sql .= "(";
3766 }
3767 foreach ($search_crit as $crit) {
3768 if ($i > 0) {
3769 $sql .= " AND ";
3770 }
3771 $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) . "%'";
3772 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3773 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3774 }
3775 $sql .= ")";
3776 $i++;
3777 }
3778 if (count($search_crit) > 1) {
3779 $sql .= ")";
3780 }
3781 if (isModEnabled('barcode')) {
3782 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3783 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3784 }
3785 $sql .= ')';
3786 }
3787 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3788 $sql .= $this->db->plimit($limit, 0);
3789
3790 // Build output string
3791
3792 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3793 $result = $this->db->query($sql);
3794 if ($result) {
3795 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3796 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3797
3798 $num = $this->db->num_rows($result);
3799
3800 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3801 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3802 if (!$selected) {
3803 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3804 } else {
3805 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3806 }
3807
3808 $i = 0;
3809 while ($i < $num) {
3810 $objp = $this->db->fetch_object($result);
3811
3812 if (is_null($objp->idprodfournprice)) {
3813 // There is no supplier price found, we will use the vat rate for sale
3814 $objp->tva_tx = $objp->tva_tx_sale;
3815 $objp->default_vat_code = $objp->default_vat_code_sale;
3816 }
3817
3818 $outkey = $objp->idprodfournprice; // id in table of price
3819 if (!$outkey && $alsoproductwithnosupplierprice) {
3820 $outkey = 'idprod_' . $objp->rowid; // id of product
3821 }
3822
3823 $outref = $objp->ref;
3824 $outbarcode = $objp->barcode;
3825 $outqty = 1;
3826 $outdiscount = 0;
3827 $outtype = $objp->fk_product_type;
3828 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3829 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3830
3831 // Units
3832 $outvalUnits = '';
3833 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3834 if (!empty($objp->unit_short)) {
3835 $outvalUnits .= ' - ' . $objp->unit_short;
3836 }
3837 if (!empty($objp->weight) && $objp->weight_units !== null) {
3838 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3839 $outvalUnits .= ' - ' . $unitToShow;
3840 }
3841 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3842 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3843 $outvalUnits .= ' - ' . $unitToShow;
3844 }
3845 if (!empty($objp->surface) && $objp->surface_units !== null) {
3846 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3847 $outvalUnits .= ' - ' . $unitToShow;
3848 }
3849 if (!empty($objp->volume) && $objp->volume_units !== null) {
3850 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3851 $outvalUnits .= ' - ' . $unitToShow;
3852 }
3853 if ($outdurationvalue && $outdurationunit) {
3854 $da = array(
3855 'h' => $langs->trans('Hour'),
3856 'd' => $langs->trans('Day'),
3857 'w' => $langs->trans('Week'),
3858 'm' => $langs->trans('Month'),
3859 'y' => $langs->trans('Year')
3860 );
3861 if (isset($da[$outdurationunit])) {
3862 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3863 }
3864 }
3865 }
3866
3867 $objRef = $objp->ref;
3868 if ($filterkey && $filterkey != '') {
3869 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3870 }
3871 $objRefFourn = $objp->ref_fourn;
3872 if ($filterkey && $filterkey != '') {
3873 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3874 }
3875 $label = $objp->label;
3876 if ($filterkey && $filterkey != '') {
3877 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3878 }
3879
3880 switch ($objp->fk_product_type) {
3882 $picto = 'product';
3883 break;
3885 $picto = 'service';
3886 break;
3887 default:
3888 $picto = '';
3889 break;
3890 }
3891
3892 if (empty($picto)) {
3893 $optlabel = '';
3894 } else {
3895 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3896 }
3897
3898 $optlabel .= $objp->ref;
3899 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3900 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3901 }
3902 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3903 $optlabel .= ' (' . $outbarcode . ')';
3904 }
3905 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3906
3907 $outvallabel = $objRef;
3908 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3909 $outvallabel .= ' (' . $objRefFourn . ')';
3910 }
3911 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3912 $outvallabel .= ' (' . $outbarcode . ')';
3913 }
3914 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3915
3916 // Units
3917 $optlabel .= $outvalUnits;
3918 $outvallabel .= $outvalUnits;
3919
3920 if (!empty($objp->idprodfournprice)) {
3921 $outqty = $objp->quantity;
3922 $outdiscount = $objp->remise_percent;
3923 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3924 $prod_supplier = new ProductFournisseur($this->db);
3925 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3926 $prod_supplier->id = $objp->fk_product;
3927 $prod_supplier->fourn_qty = $objp->quantity;
3928 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3929 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3930
3931 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3932 $priceparser = new PriceParser($this->db);
3933 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3934 if ($price_result >= 0) {
3935 $objp->fprice = $price_result;
3936 if ($objp->quantity >= 1) {
3937 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3938 }
3939 }
3940 }
3941 if ($objp->quantity == 1) {
3942 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3943 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3944 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3945 $outvallabel .= $langs->transnoentities("Unit");
3946 } else {
3947 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3948 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3949 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3950 $outvallabel .= ' ' . $langs->transnoentities("Units");
3951 }
3952
3953 if ($objp->quantity > 1) {
3954 $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
3955 $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
3956 }
3957 if ($objp->remise_percent >= 1) {
3958 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3959 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3960 }
3961 if ($objp->duration) {
3962 $optlabel .= " - " . $objp->duration;
3963 $outvallabel .= " - " . $objp->duration;
3964 }
3965 if (!$socid) {
3966 $optlabel .= " - " . dol_trunc($objp->name, 8);
3967 $outvallabel .= " - " . dol_trunc($objp->name, 8);
3968 }
3969 if ($objp->supplier_reputation) {
3970 //TODO dictionary
3971 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3972
3973 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3974 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3975 }
3976 } else {
3977 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3978 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3979 }
3980
3981 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3982 $novirtualstock = ($showstockinlist == 2);
3983
3984 if ($user->hasRight('stock', 'lire')) {
3985 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3986
3987 if ($objp->stock > 0) {
3988 $optlabel .= ' - <span class="product_line_stock_ok">';
3989 } elseif ($objp->stock <= 0) {
3990 $optlabel .= ' - <span class="product_line_stock_too_low">';
3991 }
3992 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3993 $optlabel .= '</span>';
3994 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3995 $langs->load("stocks");
3996
3997 $tmpproduct = new Product($this->db);
3998 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3999 $tmpproduct->load_virtual_stock();
4000 $virtualstock = $tmpproduct->stock_theorique;
4001
4002 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4003
4004 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4005 if ($virtualstock > 0) {
4006 $optlabel .= '<span class="product_line_stock_ok">';
4007 } elseif ($virtualstock <= 0) {
4008 $optlabel .= '<span class="product_line_stock_too_low">';
4009 }
4010 $optlabel .= $virtualstock;
4011 $optlabel .= '</span>';
4012
4013 unset($tmpproduct);
4014 }
4015 }
4016 }
4017
4018 $optstart = '<option value="' . $outkey . '"';
4019 if ($selected && $selected == $objp->idprodfournprice) {
4020 $optstart .= ' selected';
4021 }
4022 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4023 $optstart .= ' disabled';
4024 }
4025
4026 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4027 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4028 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4029 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4030 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
4031 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
4032 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
4033 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
4034 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
4035 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4036 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4037 if (isModEnabled('multicurrency')) {
4038 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4039 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
4040 }
4041 }
4042 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4043
4044 $outarrayentry = array(
4045 'key' => $outkey,
4046 'value' => $outref,
4047 'label' => $outvallabel,
4048 'qty' => $outqty,
4049 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4050 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4051 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4052 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4053 'tva_tx' => price2num($objp->tva_tx),
4054 'default_vat_code' => $objp->default_vat_code,
4055 'supplier_ref' => $objp->ref_fourn,
4056 'discount' => $outdiscount,
4057 'type' => $outtype,
4058 'duration_value' => $outdurationvalue,
4059 'duration_unit' => $outdurationunit,
4060 'disabled' => empty($objp->idprodfournprice),
4061 'description' => $objp->description
4062 );
4063 if (isModEnabled('multicurrency')) {
4064 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4065 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4066 }
4067
4068 $parameters = array(
4069 'objp' => &$objp,
4070 'optstart' => &$optstart,
4071 'optlabel' => &$optlabel,
4072 'outvallabel' => &$outvallabel,
4073 'outarrayentry' => &$outarrayentry,
4074 'fk_soc' => $socid
4075 );
4076 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4077
4078
4079 // Add new entry
4080 // "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
4081 // "label" value of json key array is used by jQuery automatically as text for combo box
4082 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4083 $outarraypush = array(
4084 'key' => $outkey,
4085 'value' => $outref,
4086 'label' => $outvallabel,
4087 'qty' => $outqty,
4088 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4089 'price_qty_ht_locale' => price($objp->fprice),
4090 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4091 'price_unit_ht_locale' => price($objp->unitprice),
4092 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4093 'tva_tx_formated' => price($objp->tva_tx),
4094 'tva_tx' => price2num($objp->tva_tx),
4095 'default_vat_code' => $objp->default_vat_code,
4096 'supplier_ref' => $objp->ref_fourn,
4097 'discount' => $outdiscount,
4098 'type' => $outtype,
4099 'duration_value' => $outdurationvalue,
4100 'duration_unit' => $outdurationunit,
4101 'disabled' => empty($objp->idprodfournprice),
4102 'description' => $objp->description
4103 );
4104 if (isModEnabled('multicurrency')) {
4105 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4106 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4107 }
4108 array_push($outarray, $outarraypush);
4109
4110 // Example of var_dump $outarray
4111 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4112 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4113 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4114 //}
4115 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4116 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4117 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4118
4119 $i++;
4120 }
4121 $out .= '</select>';
4122
4123 $this->db->free($result);
4124
4125 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4126 $out .= ajax_combobox($htmlname);
4127 } else {
4128 dol_print_error($this->db);
4129 }
4130
4131 if (empty($outputmode)) {
4132 return $out;
4133 }
4134 return $outarray;
4135 }
4136
4137 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4138
4147 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4148 {
4149 // phpcs:enable
4150 global $langs, $conf;
4151
4152 $langs->load('stocks');
4153
4154 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4155 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4156 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4157 $sql .= " FROM " . $this->db->prefix() . "product as p";
4158 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4159 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4160 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4161 $sql .= " AND p.tobuy = 1";
4162 $sql .= " AND s.fournisseur = 1";
4163 $sql .= " AND p.rowid = " . ((int) $productid);
4164 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4165 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4166 } else {
4167 $sql .= " ORDER BY pfp.unitprice ASC";
4168 }
4169
4170 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4171 $result = $this->db->query($sql);
4172
4173 if ($result) {
4174 $num = $this->db->num_rows($result);
4175
4176 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4177
4178 if (!$num) {
4179 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4180 } else {
4181 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4182 $form .= '<option value="0">&nbsp;</option>';
4183
4184 $i = 0;
4185 while ($i < $num) {
4186 $objp = $this->db->fetch_object($result);
4187
4188 $opt = '<option value="' . $objp->idprodfournprice . '"';
4189 //if there is only one supplier, preselect it
4190 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4191 $opt .= ' selected';
4192 }
4193 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4194
4195 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4196 $prod_supplier = new ProductFournisseur($this->db);
4197 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4198 $prod_supplier->id = $productid;
4199 $prod_supplier->fourn_qty = $objp->quantity;
4200 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4201 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4202
4203 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4204 $priceparser = new PriceParser($this->db);
4205 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4206 if ($price_result >= 0) {
4207 $objp->fprice = $price_result;
4208 if ($objp->quantity >= 1) {
4209 $objp->unitprice = $objp->fprice / $objp->quantity;
4210 }
4211 }
4212 }
4213 if ($objp->quantity == 1) {
4214 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4215 }
4216
4217 $opt .= $objp->quantity . ' ';
4218
4219 if ($objp->quantity == 1) {
4220 $opt .= $langs->trans("Unit");
4221 } else {
4222 $opt .= $langs->trans("Units");
4223 }
4224 if ($objp->quantity > 1) {
4225 $opt .= " - ";
4226 $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");
4227 }
4228 if ($objp->duration) {
4229 $opt .= " - " . $objp->duration;
4230 }
4231 $opt .= "</option>\n";
4232
4233 $form .= $opt;
4234 $i++;
4235 }
4236 }
4237
4238 $form .= '</select>';
4239 $this->db->free($result);
4240 return $form;
4241 } else {
4242 dol_print_error($this->db);
4243 return '';
4244 }
4245 }
4246
4247
4248 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4255 {
4256 // phpcs:enable
4257 global $langs;
4258
4259 $num = count($this->cache_conditions_paiements);
4260 if ($num > 0) {
4261 return 0; // Cache already loaded
4262 }
4263
4264 dol_syslog(__METHOD__, LOG_DEBUG);
4265
4266 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4267 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4268 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4269 $sql .= " AND active > 0";
4270 $sql .= " ORDER BY sortorder";
4271
4272 $resql = $this->db->query($sql);
4273 if ($resql) {
4274 $num = $this->db->num_rows($resql);
4275 $i = 0;
4276 while ($i < $num) {
4277 $obj = $this->db->fetch_object($resql);
4278
4279 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4280 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4281 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4282 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4283 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4284 $i++;
4285 }
4286
4287 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4288
4289 return $num;
4290 } else {
4291 dol_print_error($this->db);
4292 return -1;
4293 }
4294 }
4295
4296 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4297
4303 public function load_cache_availability()
4304 {
4305 // phpcs:enable
4306 global $langs;
4307
4308 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4309 if ($num > 0) {
4310 return 0; // Cache already loaded
4311 }
4312
4313 dol_syslog(__METHOD__, LOG_DEBUG);
4314
4315 $langs->load('propal');
4316
4317 $sql = "SELECT rowid, code, label, position";
4318 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4319 $sql .= " WHERE active > 0";
4320
4321 $resql = $this->db->query($sql);
4322 if ($resql) {
4323 $num = $this->db->num_rows($resql);
4324 $i = 0;
4325 while ($i < $num) {
4326 $obj = $this->db->fetch_object($resql);
4327
4328 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4329 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4330 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4331 $this->cache_availability[$obj->rowid]['label'] = $label;
4332 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4333 $i++;
4334 }
4335
4336 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4337
4338 return $num;
4339 } else {
4340 dol_print_error($this->db);
4341 return -1;
4342 }
4343 }
4344
4355 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4356 {
4357 global $langs, $user;
4358
4359 $this->load_cache_availability();
4360
4361 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4362
4363 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4364 if ($addempty) {
4365 print '<option value="0">&nbsp;</option>';
4366 }
4367 foreach ($this->cache_availability as $id => $arrayavailability) {
4368 if ($selected == $id) {
4369 print '<option value="' . $id . '" selected>';
4370 } else {
4371 print '<option value="' . $id . '">';
4372 }
4373 print dol_escape_htmltag($arrayavailability['label']);
4374 print '</option>';
4375 }
4376 print '</select>';
4377 if ($user->admin) {
4378 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4379 }
4380 print ajax_combobox($htmlname);
4381 }
4382
4388 public function loadCacheInputReason()
4389 {
4390 global $langs;
4391
4392 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4393 if ($num > 0) {
4394 return 0; // Cache already loaded
4395 }
4396
4397 $sql = "SELECT rowid, code, label";
4398 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4399 $sql .= " WHERE active > 0";
4400
4401 $resql = $this->db->query($sql);
4402 if ($resql) {
4403 $num = $this->db->num_rows($resql);
4404 $i = 0;
4405 $tmparray = array();
4406 while ($i < $num) {
4407 $obj = $this->db->fetch_object($resql);
4408
4409 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4410 $label = ($obj->label != '-' ? $obj->label : '');
4411 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4412 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4413 }
4414 if ($langs->trans($obj->code) != $obj->code) {
4415 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4416 }
4417
4418 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4419 $tmparray[$obj->rowid]['code'] = $obj->code;
4420 $tmparray[$obj->rowid]['label'] = $label;
4421 $i++;
4422 }
4423
4424 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4425
4426 unset($tmparray);
4427 return $num;
4428 } else {
4429 dol_print_error($this->db);
4430 return -1;
4431 }
4432 }
4433
4446 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4447 {
4448 global $langs, $user;
4449
4450 $this->loadCacheInputReason();
4451
4452 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4453 if ($addempty) {
4454 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4455 }
4456 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4457 if ($arraydemandreason['code'] == $exclude) {
4458 continue;
4459 }
4460
4461 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4462 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4463 } else {
4464 print '<option value="' . $arraydemandreason['id'] . '">';
4465 }
4466 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4467 print $langs->trans($label);
4468 print '</option>';
4469 }
4470 print '</select>';
4471 if ($user->admin && empty($notooltip)) {
4472 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4473 }
4474 print ajax_combobox('select_' . $htmlname);
4475 }
4476
4477 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4478
4485 {
4486 // phpcs:enable
4487 global $langs;
4488
4489 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4490 if ($num > 0) {
4491 return $num; // Cache already loaded
4492 }
4493
4494 dol_syslog(__METHOD__, LOG_DEBUG);
4495
4496 $this->cache_types_paiements = array();
4497
4498 $sql = "SELECT id, code, libelle as label, type, active";
4499 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4500 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4501
4502 $resql = $this->db->query($sql);
4503 if ($resql) {
4504 $num = $this->db->num_rows($resql);
4505 $i = 0;
4506 while ($i < $num) {
4507 $obj = $this->db->fetch_object($resql);
4508
4509 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4510 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4511 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4512 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4513 $this->cache_types_paiements[$obj->id]['label'] = $label;
4514 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4515 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4516 $i++;
4517 }
4518
4519 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4520
4521 return $num;
4522 } else {
4523 dol_print_error($this->db);
4524 return -1;
4525 }
4526 }
4527
4528
4529 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4530
4549 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4550 {
4551 // phpcs:enable
4552 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4553 if (empty($noprint)) {
4554 print $out;
4555 } else {
4556 return $out;
4557 }
4558 }
4559
4560
4577 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4578 {
4579 global $langs, $user, $conf;
4580
4581 $out = '';
4582 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4583
4585
4586 // Set default value if not already set by caller
4587 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4588 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4589 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4590 }
4591
4592 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4593 if ($addempty) {
4594 $out .= '<option value="0">&nbsp;</option>';
4595 }
4596
4597 $selectedDepositPercent = null;
4598
4599 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4600 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4601 continue;
4602 }
4603
4604 if ($selected == $id) {
4605 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4606 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4607 } else {
4608 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4609 }
4610 $label = $arrayconditions['label'];
4611
4612 if (!empty($arrayconditions['deposit_percent'])) {
4613 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4614 }
4615
4616 $out .= $label;
4617 $out .= '</option>';
4618 }
4619 $out .= '</select>';
4620 if ($user->admin && empty($noinfoadmin)) {
4621 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4622 }
4623 $out .= ajax_combobox($htmlname);
4624
4625 if ($deposit_percent >= 0) {
4626 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4627 $out .= $langs->trans('DepositPercent') . ' : ';
4628 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4629 $out .= '</span>';
4630 $out .= '
4631 <script nonce="' . getNonce() . '">
4632 $(document).ready(function () {
4633 $("#' . $htmlname . '").change(function () {
4634 let $selected = $(this).find("option:selected");
4635 let depositPercent = $selected.attr("data-deposit_percent");
4636
4637 if (depositPercent.length > 0) {
4638 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4639 } else {
4640 $("#' . $htmlname . '_deposit_percent_container").hide();
4641 }
4642
4643 return true;
4644 });
4645 });
4646 </script>';
4647 }
4648
4649 return $out;
4650 }
4651
4652
4653 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4654
4671 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4672 {
4673 // phpcs:enable
4674 global $langs, $user, $conf;
4675
4676 $out = '';
4677
4678 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4679
4680 $filterarray = array();
4681 if ($filtertype == 'CRDT') {
4682 $filterarray = array(0, 2, 3);
4683 } elseif ($filtertype == 'DBIT') {
4684 $filterarray = array(1, 2, 3);
4685 } elseif ($filtertype != '' && $filtertype != '-1') {
4686 $filterarray = explode(',', $filtertype);
4687 }
4688
4690
4691 // Set default value if not already set by caller
4692 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4693 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4694 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4695 }
4696
4697 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4698 if ($empty) {
4699 $out .= '<option value="">&nbsp;</option>';
4700 }
4701 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4702 // If not good status
4703 if ($active >= 0 && $arraytypes['active'] != $active) {
4704 continue;
4705 }
4706
4707 // We skip of the user requested to filter on specific payment methods
4708 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4709 continue;
4710 }
4711
4712 // We discard empty lines if showempty is on because an empty line has already been output.
4713 if ($empty && empty($arraytypes['code'])) {
4714 continue;
4715 }
4716
4717 if ($format == 0) {
4718 $out .= '<option value="' . $id . '"';
4719 } elseif ($format == 1) {
4720 $out .= '<option value="' . $arraytypes['code'] . '"';
4721 } elseif ($format == 2) {
4722 $out .= '<option value="' . $arraytypes['code'] . '"';
4723 } elseif ($format == 3) {
4724 $out .= '<option value="' . $id . '"';
4725 }
4726 // Print attribute selected or not
4727 if ($format == 1 || $format == 2) {
4728 if ($selected == $arraytypes['code']) {
4729 $out .= ' selected';
4730 }
4731 } else {
4732 if ($selected == $id) {
4733 $out .= ' selected';
4734 }
4735 }
4736 $out .= '>';
4737 $value = '';
4738 if ($format == 0) {
4739 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4740 } elseif ($format == 1) {
4741 $value = $arraytypes['code'];
4742 } elseif ($format == 2) {
4743 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4744 } elseif ($format == 3) {
4745 $value = $arraytypes['code'];
4746 }
4747 $out .= $value ? $value : '&nbsp;';
4748 $out .= '</option>';
4749 }
4750 $out .= '</select>';
4751 if ($user->admin && !$noadmininfo) {
4752 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4753 }
4754 $out .= ajax_combobox('select' . $htmlname);
4755
4756 if (empty($nooutput)) {
4757 print $out;
4758 } else {
4759 return $out;
4760 }
4761 }
4762
4775 public function selectTypesIban($selected = '', $htmlname = 'ribList', $empty = 0, $morecss = '', $nooutput = 0, $ribForSelection = [])
4776 {
4777 $out = '<select id="select' . $htmlname . '" class="flat selectrib' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4778 if ($empty) {
4779 $out .= '<option value="">&nbsp;</option>';
4780 }
4781
4782 foreach ($ribForSelection as $rib) {
4783 $selectedAttribute = $selected == $rib ? 'selected' : '';
4784 $out .= '<option value="' . $rib . '" '.$selectedAttribute.'>';
4785 $out .= $rib;
4786 $out .= '</option>';
4787 }
4788 $out .= '</select>';
4789 $out .= ajax_combobox('select' . $htmlname);
4790
4791 if (empty($nooutput)) {
4792 print $out;
4793 } else {
4794 return $out;
4795 }
4796 }
4797
4798
4807 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4808 {
4809 global $langs;
4810
4811 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4812 $options = array(
4813 'HT' => $langs->trans("HT"),
4814 'TTC' => $langs->trans("TTC")
4815 );
4816 foreach ($options as $id => $value) {
4817 if ($selected == $id) {
4818 $return .= '<option value="' . $id . '" selected>' . $value;
4819 } else {
4820 $return .= '<option value="' . $id . '">' . $value;
4821 }
4822 $return .= '</option>';
4823 }
4824 $return .= '</select>';
4825 if ($addjscombo) {
4826 $return .= ajax_combobox('select_' . $htmlname);
4827 }
4828
4829 return $return;
4830 }
4831
4832 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4833
4840 {
4841 // phpcs:enable
4842 global $langs;
4843
4844 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4845 if ($num > 0) {
4846 return $num; // Cache already loaded
4847 }
4848
4849 dol_syslog(__METHOD__, LOG_DEBUG);
4850
4851 $this->cache_transport_mode = array();
4852
4853 $sql = "SELECT rowid, code, label, active";
4854 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4855 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4856
4857 $resql = $this->db->query($sql);
4858 if ($resql) {
4859 $num = $this->db->num_rows($resql);
4860 $i = 0;
4861 while ($i < $num) {
4862 $obj = $this->db->fetch_object($resql);
4863
4864 // If traduction exist, we use it else we take the default label
4865 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4866 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4867 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4868 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4869 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4870 $i++;
4871 }
4872
4873 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4874
4875 return $num;
4876 } else {
4877 dol_print_error($this->db);
4878 return -1;
4879 }
4880 }
4881
4895 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4896 {
4897 global $langs, $user;
4898
4899 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4900
4902
4903 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4904 if ($empty) {
4905 print '<option value="">&nbsp;</option>';
4906 }
4907 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4908 // If not good status
4909 if ($active >= 0 && $arraytypes['active'] != $active) {
4910 continue;
4911 }
4912
4913 // We discard empty line if showempty is on because an empty line has already been output.
4914 if ($empty && empty($arraytypes['code'])) {
4915 continue;
4916 }
4917
4918 if ($format == 0) {
4919 print '<option value="' . $id . '"';
4920 } elseif ($format == 1) {
4921 print '<option value="' . $arraytypes['code'] . '"';
4922 } elseif ($format == 2) {
4923 print '<option value="' . $arraytypes['code'] . '"';
4924 } elseif ($format == 3) {
4925 print '<option value="' . $id . '"';
4926 }
4927 // If text is selected, we compare with code, else with id
4928 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4929 print ' selected';
4930 } elseif ($selected == $id) {
4931 print ' selected';
4932 }
4933 print '>';
4934 $value = '';
4935 if ($format == 0) {
4936 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4937 } elseif ($format == 1) {
4938 $value = $arraytypes['code'];
4939 } elseif ($format == 2) {
4940 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4941 } elseif ($format == 3) {
4942 $value = $arraytypes['code'];
4943 }
4944 print $value ? $value : '&nbsp;';
4945 print '</option>';
4946 }
4947 print '</select>';
4948
4949 print ajax_combobox("select".$htmlname);
4950
4951 if ($user->admin && !$noadmininfo) {
4952 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4953 }
4954 }
4955
4968 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4969 {
4970 global $langs, $user;
4971
4972 $langs->load("admin");
4973 $langs->load("deliveries");
4974
4975 $sql = "SELECT rowid, code, libelle as label";
4976 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4977 $sql .= " WHERE active > 0";
4978 if ($filtre) {
4979 $sql .= " AND " . $filtre;
4980 }
4981 $sql .= " ORDER BY libelle ASC";
4982
4983 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4984 $result = $this->db->query($sql);
4985 if ($result) {
4986 $num = $this->db->num_rows($result);
4987 $i = 0;
4988 if ($num) {
4989 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4990 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4991 print '<option value="-1">&nbsp;</option>';
4992 }
4993 while ($i < $num) {
4994 $obj = $this->db->fetch_object($result);
4995 if ($selected == $obj->rowid) {
4996 print '<option value="' . $obj->rowid . '" selected>';
4997 } else {
4998 print '<option value="' . $obj->rowid . '">';
4999 }
5000 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
5001 print '</option>';
5002 $i++;
5003 }
5004 print "</select>";
5005 if ($user->admin && empty($noinfoadmin)) {
5006 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5007 }
5008
5009 print ajax_combobox('select' . $htmlname);
5010 } else {
5011 print $langs->trans("NoShippingMethodDefined");
5012 }
5013 } else {
5014 dol_print_error($this->db);
5015 }
5016 }
5017
5027 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
5028 {
5029 global $langs;
5030
5031 $langs->load("deliveries");
5032
5033 if ($htmlname != "none") {
5034 print '<form method="POST" action="' . $page . '">';
5035 print '<input type="hidden" name="action" value="setshippingmethod">';
5036 print '<input type="hidden" name="token" value="' . newToken() . '">';
5037 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5038 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5039 print '</form>';
5040 } else {
5041 if ($selected) {
5042 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5043 print $langs->trans("SendingMethod" . strtoupper($code));
5044 } else {
5045 print "&nbsp;";
5046 }
5047 }
5048 }
5049
5058 public function selectSituationInvoices($selected = '', $socid = 0)
5059 {
5060 global $langs;
5061
5062 $langs->load('bills');
5063
5064 $opt = '<option value="" selected></option>';
5065 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5066 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5067 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5068 $sql .= ' AND situation_counter >= 1';
5069 $sql .= ' AND fk_soc = ' . (int) $socid;
5070 $sql .= ' AND type <> 2';
5071 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5072 $resql = $this->db->query($sql);
5073
5074 if ($resql && $this->db->num_rows($resql) > 0) {
5075 // Last seen cycle
5076 $ref = 0;
5077 while ($obj = $this->db->fetch_object($resql)) {
5078 //Same cycle ?
5079 if ($obj->situation_cycle_ref != $ref) {
5080 // Just seen this cycle
5081 $ref = $obj->situation_cycle_ref;
5082 //not final ?
5083 if ($obj->situation_final != 1) {
5084 //Not prov?
5085 if (substr($obj->ref, 1, 4) != 'PROV') {
5086 if ($selected == $obj->rowid) {
5087 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5088 } else {
5089 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5090 }
5091 }
5092 }
5093 }
5094 }
5095 } else {
5096 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5097 }
5098 if ($opt == '<option value ="" selected></option>') {
5099 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5100 }
5101 return $opt;
5102 }
5103
5113 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5114 {
5115 global $langs;
5116
5117 $langs->load('products');
5118
5119 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5120
5121 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5122 $sql .= ' WHERE active > 0';
5123 if (!empty($unit_type)) {
5124 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5125 }
5126 $sql .= " ORDER BY sortorder";
5127
5128 $resql = $this->db->query($sql);
5129 if ($resql && $this->db->num_rows($resql) > 0) {
5130 if ($showempty) {
5131 $return .= '<option value="none"></option>';
5132 }
5133
5134 while ($res = $this->db->fetch_object($resql)) {
5135 $unitLabel = $res->label;
5136 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5137 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5138 }
5139
5140 if ($selected == $res->rowid) {
5141 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5142 } else {
5143 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5144 }
5145 }
5146 $return .= '</select>';
5147 }
5148 return $return;
5149 }
5150
5151 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5152
5167 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5168 {
5169 // phpcs:enable
5170 global $langs;
5171
5172 $out = '';
5173
5174 $langs->load("admin");
5175 $num = 0;
5176
5177 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5178 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5179 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5180 if ($status != 2) {
5181 $sql .= " AND clos = " . (int) $status;
5182 }
5183 if ($filtre) { // TODO Support USF
5184 $sql .= " AND " . $filtre;
5185 }
5186 $sql .= " ORDER BY label";
5187
5188 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5189 $result = $this->db->query($sql);
5190 if ($result) {
5191 $num = $this->db->num_rows($result);
5192 $i = 0;
5193
5194 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5195
5196 if ($num == 0) {
5197 if ($status == 0) {
5198 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5199 } else {
5200 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountFound") . '</span>';
5201 }
5202 } else {
5203 if (!empty($useempty) && !is_numeric($useempty)) {
5204 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5205 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5206 $out .= '<option value="-1">&nbsp;</option>';
5207 }
5208 }
5209
5210 while ($i < $num) {
5211 $obj = $this->db->fetch_object($result);
5212
5213 $labeltoshow = trim($obj->label);
5214 $labeltoshowhtml = trim($obj->label);
5215 if ($showcurrency) {
5216 $labeltoshow .= ' (' . $obj->currency_code . ')';
5217 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5218 }
5219 if ($status == 2 && $obj->status == 1) {
5220 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5221 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5222 }
5223
5224 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5225 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5226 } else {
5227 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5228 }
5229 $out .= $labeltoshow;
5230 $out .= '</option>';
5231 $i++;
5232 }
5233 $out .= "</select>";
5234 $out .= ajax_combobox('select' . $htmlname);
5235 } else {
5236 dol_print_error($this->db);
5237 }
5238
5239 // Output or return
5240 if (empty($nooutput)) {
5241 print $out;
5242 } else {
5243 return $out;
5244 }
5245
5246 return $num;
5247 }
5248
5260 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5261 {
5262 global $langs;
5263
5264 $langs->load("admin");
5265 $num = 0;
5266
5267 $sql = "SELECT rowid, name, fk_country, status, entity";
5268 $sql .= " FROM " . $this->db->prefix() . "establishment";
5269 $sql .= " WHERE 1=1";
5270 if ($status != 2) {
5271 $sql .= " AND status = " . (int) $status;
5272 }
5273 if ($filtre) { // TODO Support USF
5274 $sql .= " AND " . $filtre;
5275 }
5276 $sql .= " ORDER BY name";
5277
5278 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5279 $result = $this->db->query($sql);
5280 if ($result) {
5281 $num = $this->db->num_rows($result);
5282 $i = 0;
5283 if ($num) {
5284 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5285 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5286 print '<option value="-1">&nbsp;</option>';
5287 }
5288
5289 while ($i < $num) {
5290 $obj = $this->db->fetch_object($result);
5291 if ($selected == $obj->rowid) {
5292 print '<option value="' . $obj->rowid . '" selected>';
5293 } else {
5294 print '<option value="' . $obj->rowid . '">';
5295 }
5296 print trim($obj->name);
5297 if ($status == 2 && $obj->status == 1) {
5298 print ' (' . $langs->trans("Closed") . ')';
5299 }
5300 print '</option>';
5301 $i++;
5302 }
5303 print "</select>";
5304 } else {
5305 if ($status == 0) {
5306 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5307 } else {
5308 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5309 }
5310 }
5311
5312 return $num;
5313 } else {
5314 dol_print_error($this->db);
5315 return -1;
5316 }
5317 }
5318
5328 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5329 {
5330 global $langs;
5331 if ($htmlname != "none") {
5332 print '<form method="POST" action="' . $page . '">';
5333 print '<input type="hidden" name="action" value="setbankaccount">';
5334 print '<input type="hidden" name="token" value="' . newToken() . '">';
5335 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5336 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5337 if ($nbaccountfound > 0) {
5338 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5339 }
5340 print '</form>';
5341 } else {
5342 $langs->load('banks');
5343
5344 if ($selected) {
5345 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5346 $bankstatic = new Account($this->db);
5347 $result = $bankstatic->fetch($selected);
5348 if ($result) {
5349 print $bankstatic->getNomUrl(1);
5350 }
5351 } else {
5352 print "&nbsp;";
5353 }
5354 }
5355 }
5356
5357 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5358
5378 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5379 {
5380 // phpcs:enable
5381 global $conf, $langs;
5382 $langs->load("categories");
5383
5384 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5385
5386 // For backward compatibility
5387 if (is_numeric($type)) {
5388 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5389 }
5390
5391 if ($type === Categorie::TYPE_BANK_LINE) {
5392 // TODO Move this into common category feature after migration of llx_category_bankline into llx_categorie_bankline
5393 $cat = new Categorie($this->db);
5394 $cate_arbo = array();
5395 $sql = "SELECT c.label, c.rowid";
5396 $sql .= " FROM " . $this->db->prefix() . "categorie as c";
5397 $sql .= " WHERE entity = " . $conf->entity . " AND type = " . ((int) $cat->getMapId()[$type]);
5398 $sql .= " ORDER BY c.label";
5399 $result = $this->db->query($sql);
5400 if ($result) {
5401 $num = $this->db->num_rows($result);
5402 $i = 0;
5403 while ($i < $num) {
5404 $objp = $this->db->fetch_object($result);
5405 if ($objp) {
5406 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5407 }
5408 $i++;
5409 }
5410 $this->db->free($result);
5411 } else {
5412 dol_print_error($this->db);
5413 }
5414 } else {
5415 $cat = new Categorie($this->db);
5416 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5417 }
5418
5419 $outarray = array();
5420 $outarrayrichhtml = array();
5421
5422
5423 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5424 if (is_array($cate_arbo)) {
5425 $num = count($cate_arbo);
5426
5427 if (!$num) {
5428 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5429 } else {
5430 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5431 $output .= '<option value="-1">&nbsp;</option>';
5432 }
5433 foreach ($cate_arbo as $key => $value) {
5434 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5435 $add = 'selected ';
5436 } else {
5437 $add = '';
5438 }
5439
5440 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5441 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5442
5443 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5444
5445 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5446
5447 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5448 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5449 $output .= '>';
5450 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5451 $output .= '</option>';
5452
5453 $cate_arbo[$key]['data-html'] = $labeltoshow;
5454 }
5455 }
5456 }
5457 $output .= '</select>';
5458 $output .= "\n";
5459
5460 if ($outputmode == 2) {
5461 // TODO: handle error when $cate_arbo is not an array
5462 return $cate_arbo;
5463 } elseif ($outputmode == 1) {
5464 return $outarray;
5465 } elseif ($outputmode == 3) {
5466 return $outarrayrichhtml;
5467 }
5468 return $output;
5469 }
5470
5471 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5472
5491 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5492 {
5493 // phpcs:enable
5494 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5495 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5496 }
5497
5525 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5526 {
5527 global $langs, $conf;
5528
5529 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5530 $formconfirm = '';
5531 $inputok = array();
5532 $inputko = array();
5533
5534 // Clean parameters
5535 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5536 if ($conf->browser->layout == 'phone') {
5537 $width = '95%';
5538 }
5539
5540 // Set height automatically if not defined
5541 if (empty($height)) {
5542 $height = 220;
5543 if (is_array($formquestion) && count($formquestion) > 2) {
5544 $height += ((count($formquestion) - 2) * 24);
5545 }
5546 }
5547
5548 if (is_array($formquestion) && !empty($formquestion)) {
5549 // First add hidden fields and value
5550 foreach ($formquestion as $key => $input) {
5551 if (is_array($input) && !empty($input)) {
5552 if ($input['type'] == 'hidden') {
5553 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5554 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5555
5556 $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";
5557 }
5558 }
5559 }
5560
5561 // Now add questions
5562 $moreonecolumn = '';
5563 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5564 foreach ($formquestion as $key => $input) {
5565 if (is_array($input) && !empty($input)) {
5566 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5567 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5568 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5569
5570 if ($input['type'] == 'text') {
5571 $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";
5572 } elseif ($input['type'] == 'password') {
5573 $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";
5574 } elseif ($input['type'] == 'textarea') {
5575 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5576 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5577 $more .= $input['value'];
5578 $more .= '</textarea>';
5579 $more .= '</div></div>'."\n";*/
5580 $moreonecolumn .= '<div class="margintoponly">';
5581 $moreonecolumn .= $input['label'] . '<br>';
5582 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5583 $moreonecolumn .= $input['value'];
5584 $moreonecolumn .= '</textarea>';
5585 $moreonecolumn .= '</div>';
5586 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5587 if (empty($morecss)) {
5588 $morecss = 'minwidth100';
5589 }
5590
5591 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5592 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5593 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5594 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5595 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5596 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5597 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5598
5599 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5600 if (!empty($input['label'])) {
5601 $more .= $input['label'] . '</div><div class="tagtd left">';
5602 }
5603 if ($input['type'] == 'select') {
5604 $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);
5605 } else {
5606 $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);
5607 }
5608 $more .= '</div></div>' . "\n";
5609 } elseif ($input['type'] == 'checkbox') {
5610 $more .= '<div class="tagtr">';
5611 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5612 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5613 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5614 $more .= ' checked';
5615 }
5616 if (is_bool($input['value']) && $input['value']) {
5617 $more .= ' checked';
5618 }
5619 if (isset($input['disabled'])) {
5620 $more .= ' disabled';
5621 }
5622 $more .= ' /></div>';
5623 $more .= '</div>' . "\n";
5624 } elseif ($input['type'] == 'radio') {
5625 $i = 0;
5626 foreach ($input['values'] as $selkey => $selval) {
5627 $more .= '<div class="tagtr">';
5628 if (isset($input['label'])) {
5629 if ($i == 0) {
5630 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5631 } else {
5632 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5633 }
5634 }
5635 $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;
5636 if (!empty($input['disabled'])) {
5637 $more .= ' disabled';
5638 }
5639 if (isset($input['default']) && $input['default'] === $selkey) {
5640 $more .= ' checked="checked"';
5641 }
5642 $more .= ' /> ';
5643 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5644 $more .= '</div></div>' . "\n";
5645 $i++;
5646 }
5647 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5648 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5649 $more .= '<div class="tagtd">';
5650 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5651 $h = $m = 0;
5652 if ($input['type'] == 'datetime') {
5653 $h = isset($input['hours']) ? $input['hours'] : 1;
5654 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5655 }
5656 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5657 $more .= '</div></div>'."\n";
5658 $formquestion[] = array('name' => $input['name'].'day');
5659 $formquestion[] = array('name' => $input['name'].'month');
5660 $formquestion[] = array('name' => $input['name'].'year');
5661 $formquestion[] = array('name' => $input['name'].'hour');
5662 $formquestion[] = array('name' => $input['name'].'min');
5663 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5664 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5665 if (!empty($input['label'])) {
5666 $more .= $input['label'] . '</div><div class="tagtd">';
5667 }
5668 $more .= $input['value'];
5669 $more .= '</div></div>' . "\n";
5670 } elseif ($input['type'] == 'onecolumn') {
5671 $moreonecolumn .= '<div class="margintoponly">';
5672 $moreonecolumn .= $input['value'];
5673 $moreonecolumn .= '</div>' . "\n";
5674 } elseif ($input['type'] == 'hidden') {
5675 // Do nothing more, already added by a previous loop
5676 } elseif ($input['type'] == 'separator') {
5677 $more .= '<br>';
5678 } else {
5679 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5680 }
5681 }
5682 }
5683 $more .= '</div>' . "\n";
5684 $more .= $moreonecolumn;
5685 }
5686
5687 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5688 // 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
5689 // See page product/card.php for example
5690 if (!empty($conf->dol_use_jmobile)) {
5691 $useajax = 0;
5692 }
5693 if (empty($conf->use_javascript_ajax)) {
5694 $useajax = 0;
5695 }
5696
5697 if ($useajax) {
5698 $autoOpen = true;
5699 $dialogconfirm = 'dialog-confirm';
5700 $button = '';
5701 if (!is_numeric($useajax)) {
5702 $button = $useajax;
5703 $useajax = 1;
5704 $autoOpen = false;
5705 $dialogconfirm .= '-' . $button;
5706 }
5707 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5708 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5709
5710 // Add input fields into list of fields to read during submit (inputok and inputko)
5711 if (is_array($formquestion)) {
5712 foreach ($formquestion as $key => $input) {
5713 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5714 // Add name of fields to propagate with the GET when submitting the form with button OK.
5715 if (is_array($input) && isset($input['name'])) {
5716 if (strpos($input['name'], ',') > 0) {
5717 $inputok = array_merge($inputok, explode(',', $input['name']));
5718 } else {
5719 array_push($inputok, $input['name']);
5720 }
5721 }
5722 // Add name of fields to propagate with the GET when submitting the form with button KO.
5723 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5724 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5725 array_push($inputko, $input['name']);
5726 }
5727 }
5728 }
5729
5730 // Show JQuery confirm box.
5731 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5732 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5733 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5734 }
5735 if (!empty($more)) {
5736 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5737 }
5738 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5739 $formconfirm .= '</div>' . "\n";
5740
5741 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5742 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5743 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5744 $formconfirm .= 'jQuery(document).ready(function() {
5745 $(function() {
5746 $( "#' . $dialogconfirm . '" ).dialog(
5747 {
5748 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5749 if ($newselectedchoice == 'no') {
5750 $formconfirm .= '
5751 open: function() {
5752 $(this).parent().find("button.ui-button:eq(2)").focus();
5753 },';
5754 }
5755
5756 $jsforcursor = '';
5757 if ($useajax == 1) {
5758 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5759 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5760 }
5761
5762 $postconfirmas = 'GET';
5763
5764 $formconfirm .= '
5765 resizable: false,
5766 height: "' . $height . '",
5767 width: "' . $width . '",
5768 modal: true,
5769 closeOnEscape: false,
5770 buttons: {
5771 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5772 var options = "token=' . urlencode(newToken()) . '";
5773 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5774 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5775 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5776
5777 if (inputok.length > 0) {
5778 $.each(inputok, function(i, inputname) {
5779 var more = "";
5780 var inputvalue;
5781 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5782 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5783 } else {
5784 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5785 inputvalue = $("#" + inputname + more).val();
5786 }
5787 if (typeof inputvalue == "undefined") { inputvalue=""; }
5788 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5789 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5790 });
5791 }
5792 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5793 if (pageyes.length > 0) {';
5794 if ($postconfirmas == 'GET') {
5795 $formconfirm .= 'location.href = urljump;';
5796 } else {
5797 $formconfirm .= $jsforcursor;
5798 $formconfirm .= 'var post = $.post(
5799 pageyes,
5800 options,
5801 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5802 );';
5803 }
5804 $formconfirm .= '
5805 console.log("after post ok");
5806 }
5807 $(this).dialog("close");
5808 },
5809 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5810 var options = "token=' . urlencode(newToken()) . '";
5811 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5812 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5813 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5814 if (inputko.length > 0) {
5815 $.each(inputko, function(i, inputname) {
5816 var more = "";
5817 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5818 var inputvalue = $("#" + inputname + more).val();
5819 if (typeof inputvalue == "undefined") { inputvalue=""; }
5820 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5821 });
5822 }
5823 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5824 //alert(urljump);
5825 if (pageno.length > 0) {';
5826 if ($postconfirmas == 'GET') {
5827 $formconfirm .= 'location.href = urljump;';
5828 } else {
5829 $formconfirm .= $jsforcursor;
5830 $formconfirm .= 'var post = $.post(
5831 pageno,
5832 options,
5833 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5834 );';
5835 }
5836 $formconfirm .= '
5837 console.log("after post ko");
5838 }
5839 $(this).dialog("close");
5840 }
5841 }
5842 }
5843 );
5844
5845 var button = "' . $button . '";
5846 if (button.length > 0) {
5847 $( "#" + button ).click(function() {
5848 $("#' . $dialogconfirm . '").dialog("open");
5849 });
5850 }
5851 });
5852 });
5853 </script>';
5854 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5855 } else {
5856 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5857
5858 if (empty($disableformtag)) {
5859 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
5860 }
5861
5862 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5863 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5864
5865 $formconfirm .= '<table class="valid centpercent">' . "\n";
5866
5867 // Line title
5868 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5869 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5870 $formconfirm .= '</td></tr>' . "\n";
5871
5872 // Line text
5873 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5874 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5875 }
5876
5877 // Line form fields
5878 if ($more) {
5879 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5880 $formconfirm .= $more;
5881 $formconfirm .= '</td></tr>' . "\n";
5882 }
5883
5884 // Line with question
5885 $formconfirm .= '<tr class="valid">';
5886 $formconfirm .= '<td class="valid">' . $question . '</td>';
5887 $formconfirm .= '<td class="valid center">';
5888 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5889 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5890 $formconfirm .= '</td>';
5891 $formconfirm .= '</tr>' . "\n";
5892
5893 $formconfirm .= '</table>' . "\n";
5894
5895 if (empty($disableformtag)) {
5896 $formconfirm .= "</form>\n";
5897 }
5898 $formconfirm .= '<br>';
5899
5900 if (!empty($conf->use_javascript_ajax)) {
5901 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5902 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5903 $formconfirm .= '
5904 $(document).ready(function () {
5905 $(".confirmvalidatebutton").on("click", function() {
5906 console.log("We click on button confirmvalidatebutton");
5907 $(this).attr("disabled", "disabled");
5908 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5909 //console.log($(this).closest("form"));
5910 $(this).closest("form").submit();
5911 });
5912 });
5913 ';
5914 $formconfirm .= '</script>' . "\n";
5915 }
5916
5917 $formconfirm .= "<!-- end formconfirm -->\n";
5918 }
5919
5920 return $formconfirm;
5921 }
5922
5923
5924 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5925
5941 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5942 {
5943 // phpcs:enable
5944 global $langs;
5945
5946 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
5947 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
5948
5949 $out = '';
5950
5951 $formproject = new FormProjets($this->db);
5952
5953 $langs->load("project");
5954 if ($htmlname != "none") {
5955 $out .= '<form method="post" action="' . $page . '">';
5956 $out .= '<input type="hidden" name="action" value="classin">';
5957 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5958 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5959 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5960 $out .= '</form>';
5961 } else {
5962 $out .= '<span class="project_head_block">';
5963 if ($selected) {
5964 $projet = new Project($this->db);
5965 $projet->fetch($selected);
5966 $out .= $projet->getNomUrl(0, '', 1);
5967 } else {
5968 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
5969 }
5970 $out .= '</span>';
5971 }
5972
5973 if (empty($nooutput)) {
5974 print $out;
5975 return '';
5976 }
5977 return $out;
5978 }
5979
5980 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5981
5997 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5998 {
5999 // phpcs:enable
6000 global $langs;
6001
6002 $out = '';
6003
6004 if ($htmlname != "none") {
6005 $out .= '<form method="POST" action="' . $page . '">';
6006 $out .= '<input type="hidden" name="action" value="setconditions">';
6007 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6008 if ($type) {
6009 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6010 }
6011 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6012 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6013 $out .= '</form>';
6014 } else {
6015 if ($selected) {
6017 if (isset($this->cache_conditions_paiements[$selected])) {
6018 $label = $this->cache_conditions_paiements[$selected]['label'];
6019
6020 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6021 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6022 }
6023
6024 $out .= $label;
6025 } else {
6026 $langs->load('errors');
6027 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6028 }
6029 } else {
6030 $out .= '&nbsp;';
6031 }
6032 }
6033
6034 if (empty($nooutput)) {
6035 print $out;
6036 return '';
6037 }
6038 return $out;
6039 }
6040
6041 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6042
6052 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
6053 {
6054 // phpcs:enable
6055 global $langs;
6056 if ($htmlname != "none") {
6057 print '<form method="post" action="' . $page . '">';
6058 print '<input type="hidden" name="action" value="setavailability">';
6059 print '<input type="hidden" name="token" value="' . newToken() . '">';
6060 $this->selectAvailabilityDelay($selected, $htmlname, '', $addempty);
6061 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6062 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
6063 print '</form>';
6064 } else {
6065 if ($selected) {
6066 $this->load_cache_availability();
6067 print $this->cache_availability[$selected]['label'];
6068 } else {
6069 print "&nbsp;";
6070 }
6071 }
6072 }
6073
6084 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
6085 {
6086 global $langs;
6087 if ($htmlname != "none") {
6088 print '<form method="post" action="' . $page . '">';
6089 print '<input type="hidden" name="action" value="setdemandreason">';
6090 print '<input type="hidden" name="token" value="' . newToken() . '">';
6091 $this->selectInputReason($selected, $htmlname, '-1', $addempty);
6092 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6093 print '</form>';
6094 } else {
6095 if ($selected) {
6096 $this->loadCacheInputReason();
6097 foreach ($this->cache_demand_reason as $key => $val) {
6098 if ($val['id'] == $selected) {
6099 print $val['label'];
6100 break;
6101 }
6102 }
6103 } else {
6104 print "&nbsp;";
6105 }
6106 }
6107 }
6108
6109 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6110
6124 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6125 {
6126 // phpcs:enable
6127 global $langs;
6128
6129 $ret = '';
6130
6131 if ($htmlname != "none") {
6132 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6133 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6134 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6135 if ($type) {
6136 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6137 }
6138 $ret .= '<table class="nobordernopadding">';
6139 $ret .= '<tr><td>';
6140 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6141 $ret .= '</td>';
6142 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6143 $ret .= '</tr></table></form>';
6144 } else {
6145 if ($displayhour) {
6146 $ret .= dol_print_date($selected, 'dayhour');
6147 } else {
6148 $ret .= dol_print_date($selected, 'day');
6149 }
6150 }
6151
6152 if (empty($nooutput)) {
6153 print $ret;
6154 }
6155 return $ret;
6156 }
6157
6158
6159 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6160
6171 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6172 {
6173 // phpcs:enable
6174 global $langs;
6175
6176 if ($htmlname != "none") {
6177 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6178 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6179 print '<input type="hidden" name="token" value="' . newToken() . '">';
6180 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6181 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6182 print '</form>';
6183 } else {
6184 if ($selected) {
6185 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6186 $theuser = new User($this->db);
6187 $theuser->fetch($selected);
6188 print $theuser->getNomUrl(1);
6189 } else {
6190 print "&nbsp;";
6191 }
6192 }
6193 }
6194
6195
6196 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6197
6211 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6212 {
6213 // phpcs:enable
6214 global $langs;
6215
6216 $out = '';
6217 if ($htmlname != "none") {
6218 $out .= '<form method="POST" action="' . $page . '">';
6219 $out .= '<input type="hidden" name="action" value="setmode">';
6220 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6221 if ($type) {
6222 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6223 }
6224 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6225 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6226 $out .= '</form>';
6227 } else {
6228 if ($selected) {
6230 $out .= $this->cache_types_paiements[$selected]['label'];
6231 } else {
6232 $out .= "&nbsp;";
6233 }
6234 }
6235
6236 if ($nooutput) {
6237 return $out;
6238 } else {
6239 print $out;
6240 }
6241 return '';
6242 }
6243
6254 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6255 {
6256 global $langs;
6257 if ($htmlname != "none") {
6258 print '<form method="POST" action="' . $page . '">';
6259 print '<input type="hidden" name="action" value="settransportmode">';
6260 print '<input type="hidden" name="token" value="' . newToken() . '">';
6261 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6262 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6263 print '</form>';
6264 } else {
6265 if ($selected) {
6267 print $this->cache_transport_mode[$selected]['label'];
6268 } else {
6269 print "&nbsp;";
6270 }
6271 }
6272 }
6273
6274 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6275
6284 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6285 {
6286 // phpcs:enable
6287 global $langs;
6288 if ($htmlname != "none") {
6289 print '<form method="POST" action="' . $page . '">';
6290 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6291 print '<input type="hidden" name="token" value="' . newToken() . '">';
6292 print $this->selectMultiCurrency($selected, $htmlname, 0);
6293 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6294 print '</form>';
6295 } else {
6296 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6297 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6298 }
6299 }
6300
6301 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6302
6312 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6313 {
6314 // phpcs:enable
6315 global $langs, $mysoc, $conf;
6316
6317 if ($htmlname != "none") {
6318 print '<form method="POST" action="' . $page . '">';
6319 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6320 print '<input type="hidden" name="token" value="' . newToken() . '">';
6321 print '<input type="text" class="maxwidth75" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6322 print '<select name="calculation_mode" id="calculation_mode">';
6323 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6324 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6325 print '</select> ';
6326 print ajax_combobox("calculation_mode");
6327 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6328 print '</form>';
6329 } else {
6330 if (!empty($rate)) {
6331 print price($rate, 1, $langs, 0, 0);
6332 if ($currency && $rate != 1) {
6333 print ' &nbsp; <span class="opacitymedium">(' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')</span>';
6334 }
6335 } else {
6336 print 1;
6337 }
6338 }
6339 }
6340
6352 public function formIban(string $selected = '', string $htmlname = 'ribList', int $addempty = 0, string $type = '', int $nooutput = 0, $ribForSelection = [])
6353 {
6354 $out = '';
6355 if ($htmlname != "none") {
6356 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6357 if ($type) {
6358 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6359 }
6360 $out .= $this->selectTypesIban($selected, $htmlname, $addempty, '', 1, $ribForSelection);
6361 } else {
6362 if ($selected) {
6363 $out .= $selected;
6364 } else {
6365 $out .= "&nbsp;";
6366 }
6367 }
6368
6369 if ($nooutput) {
6370 return $out;
6371 }
6372 print $out;
6373 return array_search($selected, $ribForSelection);
6374 }
6375
6376 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6377
6393 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6394 {
6395 // phpcs:enable
6396 global $conf, $langs;
6397 if ($htmlname != "none") {
6398 print '<form method="post" action="' . $page . '">';
6399 print '<input type="hidden" name="action" value="setabsolutediscount">';
6400 print '<input type="hidden" name="token" value="' . newToken() . '">';
6401 print '<div class="inline-block">';
6402 if (!empty($discount_type)) {
6403 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6404 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6405 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6406 } else {
6407 $translationKey = 'HasCreditNoteFromSupplier';
6408 }
6409 } else {
6410 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6411 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6412 } else {
6413 $translationKey = 'HasCreditNoteFromSupplier';
6414 }
6415 }
6416 } else {
6417 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6418 if (!$filter || $filter == "fk_facture_source IS NULL") {
6419 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6420 } else {
6421 $translationKey = 'CompanyHasCreditNote';
6422 }
6423 } else {
6424 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6425 $translationKey = 'CompanyHasAbsoluteDiscount';
6426 } else {
6427 $translationKey = 'CompanyHasCreditNote';
6428 }
6429 }
6430 }
6431 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6432 if (empty($hidelist)) {
6433 print ' ';
6434 }
6435 print '</div>';
6436 if (empty($hidelist)) {
6437 print '<div class="inline-block" style="padding-right: 10px">';
6438 $newfilter = 'discount_type=' . intval($discount_type);
6439 if (!empty($discount_type)) {
6440 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6441 } else {
6442 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6443 }
6444 if ($filter) {
6445 $newfilter .= ' AND (' . $filter . ')';
6446 }
6447 // output the combo of discounts
6448 $nbqualifiedlines = $this->select_remises((string) $selected, $htmlname, $newfilter, $socid, $maxvalue);
6449 if ($nbqualifiedlines > 0) {
6450 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6451 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6452 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6453 }
6454 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6455 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6456 }
6457
6458 print '>';
6459 }
6460 print '</div>';
6461 }
6462 if ($more) {
6463 print '<div class="inline-block">';
6464 print $more;
6465 print '</div>';
6466 }
6467 print '</form>';
6468 } else {
6469 if ($selected) {
6470 print $selected;
6471 } else {
6472 print "0";
6473 }
6474 }
6475 }
6476
6477
6478 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6479
6489 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6490 {
6491 // phpcs:enable
6492 global $langs;
6493
6494 if ($htmlname != "none") {
6495 print '<form method="post" action="' . $page . '">';
6496 print '<input type="hidden" name="action" value="set_contact">';
6497 print '<input type="hidden" name="token" value="' . newToken() . '">';
6498 print '<table class="nobordernopadding">';
6499 print '<tr><td>';
6500 print $this->selectcontacts($societe->id, $selected, $htmlname);
6501 $num = $this->num;
6502 if ($num == 0) {
6503 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6504 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&amp;action=create&amp;backtoreferer=1">' . $addcontact . '</a>';
6505 }
6506 print '</td>';
6507 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6508 print '</tr></table></form>';
6509 } else {
6510 if ($selected) {
6511 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6512 $contact = new Contact($this->db);
6513 $contact->fetch($selected);
6514 print $contact->getFullName($langs);
6515 } else {
6516 print "&nbsp;";
6517 }
6518 }
6519 }
6520
6521 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6522
6539 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6540 {
6541 // phpcs:enable
6542 global $langs;
6543
6544 $out = '';
6545 if ($htmlname != "none") {
6546 $out .= '<form method="post" action="' . $page . '">';
6547 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6548 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6549 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6550 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6551 $out .= '</form>';
6552 } else {
6553 if ($selected) {
6554 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6555 $soc = new Societe($this->db);
6556 $soc->fetch($selected);
6557 $out .= $soc->getNomUrl(0, '');
6558 } else {
6559 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6560 }
6561 }
6562
6563 if ($nooutput) {
6564 return $out;
6565 } else {
6566 print $out;
6567 }
6568
6569 return '';
6570 }
6571
6572 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6573
6582 public function select_currency($selected = '', $htmlname = 'currency_id')
6583 {
6584 // phpcs:enable
6585 print $this->selectCurrency($selected, $htmlname);
6586 }
6587
6597 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6598 {
6599 global $langs, $user;
6600
6601 $langs->loadCacheCurrencies('');
6602
6603 $out = '';
6604
6605 if ($selected == 'euro' || $selected == 'euros') {
6606 $selected = 'EUR'; // Pour compatibilite
6607 }
6608
6609 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6610 if ($useempty) {
6611 $out .= '<option value="-1" selected></option>';
6612 }
6613 foreach ($langs->cache_currencies as $code_iso => $currency) {
6614 $labeltoshow = $currency['label'];
6615 if ($mode == 1) {
6616 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6617 } else {
6618 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6619 }
6620
6621 if ($selected && $selected == $code_iso) {
6622 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6623 } else {
6624 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6625 }
6626 $out .= $labeltoshow;
6627 $out .= '</option>';
6628 }
6629 $out .= '</select>';
6630 if ($user->admin) {
6631 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6632 }
6633
6634 // Make select dynamic
6635 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6636 $out .= ajax_combobox($htmlname);
6637
6638 return $out;
6639 }
6640
6653 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6654 {
6655 global $conf, $langs;
6656
6657 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6658
6659 $TCurrency = array();
6660
6661 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6662 $sql .= " WHERE entity IN ('" . getEntity('mutlicurrency') . "')";
6663 if ($filter) {
6664 $sql .= " AND " . $filter;
6665 }
6666 $resql = $this->db->query($sql);
6667 if ($resql) {
6668 while ($obj = $this->db->fetch_object($resql)) {
6669 $TCurrency[$obj->code] = $obj->code;
6670 }
6671 }
6672
6673 $out = '';
6674 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6675 if ($useempty) {
6676 $out .= '<option value="">&nbsp;</option>';
6677 }
6678 // If company current currency not in table, we add it into list. Should always be available.
6679 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6680 $TCurrency[$conf->currency] = $conf->currency;
6681 }
6682 if (count($TCurrency) > 0) {
6683 foreach ($langs->cache_currencies as $code_iso => $currency) {
6684 if (isset($TCurrency[$code_iso])) {
6685 if (!empty($selected) && $selected == $code_iso) {
6686 $out .= '<option value="' . $code_iso . '" selected="selected">';
6687 } else {
6688 $out .= '<option value="' . $code_iso . '">';
6689 }
6690
6691 $out .= $currency['label'];
6692 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6693 $out .= '</option>';
6694 }
6695 }
6696 }
6697
6698 $out .= '</select>';
6699
6700 // Make select dynamic
6701 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6702 $out .= ajax_combobox($htmlname);
6703
6704 return $out;
6705 }
6706
6707 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6708
6715 public function load_cache_vatrates($country_code)
6716 {
6717 // phpcs:enable
6718 global $langs, $user;
6719
6720 $num = count($this->cache_vatrates);
6721 if ($num > 0) {
6722 return $num; // Cache already loaded
6723 }
6724
6725 dol_syslog(__METHOD__, LOG_DEBUG);
6726
6727 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6728 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6729 $sql .= " WHERE t.fk_pays = c.rowid";
6730 $sql .= " AND t.active > 0";
6731 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6732 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6733 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6734
6735 $resql = $this->db->query($sql);
6736 if ($resql) {
6737 $num = $this->db->num_rows($resql);
6738 if ($num) {
6739 for ($i = 0; $i < $num; $i++) {
6740 $obj = $this->db->fetch_object($resql);
6741
6742 $tmparray = array();
6743 $tmparray['rowid'] = $obj->rowid;
6744 $tmparray['type_vat'] = $obj->type_vat;
6745 $tmparray['code'] = $obj->code;
6746 $tmparray['txtva'] = $obj->taux;
6747 $tmparray['nprtva'] = $obj->recuperableonly;
6748 $tmparray['localtax1'] = $obj->localtax1;
6749 $tmparray['localtax1_type'] = $obj->localtax1_type;
6750 $tmparray['localtax2'] = $obj->localtax2;
6751 $tmparray['localtax2_type'] = $obj->localtax1_type;
6752 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6753 $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
6754 $positiverates = '';
6755 if ($obj->taux) {
6756 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6757 }
6758 if ($obj->localtax1) {
6759 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6760 }
6761 if ($obj->localtax2) {
6762 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6763 }
6764 if (empty($positiverates)) {
6765 $positiverates = '0';
6766 }
6767 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6768
6769 $this->cache_vatrates[$obj->rowid] = $tmparray;
6770 }
6771
6772 return $num;
6773 } else {
6774 $this->error = '<span class="error">';
6775 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6776 $reg = array();
6777 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6778 $langs->load("errors");
6779 $new_country_code = $reg[1];
6780 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid');
6781 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6782 }
6783 $this->error .= '</span>';
6784 return -1;
6785 }
6786 } else {
6787 $this->error = '<span class="error">' . $this->db->error() . '</span>';
6788 return -2;
6789 }
6790 }
6791
6792 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6793
6816 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)
6817 {
6818 // phpcs:enable
6819 global $langs, $mysoc;
6820
6821 $langs->load('errors');
6822
6823 $return = '';
6824
6825 // Define defaultnpr, defaultttx and defaultcode
6826 $defaultnpr = ($info_bits & 0x01);
6827 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6828 $defaulttx = str_replace('*', '', $selectedrate);
6829 $defaultcode = '';
6830 $reg = array();
6831 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6832 $defaultcode = $reg[1];
6833 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6834 }
6835 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6836
6837 // Check parameters
6838 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6839 if ($societe_vendeuse->id == $mysoc->id) {
6840 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6841 } else {
6842 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6843 }
6844 return $return;
6845 }
6846
6847 //var_dump($societe_acheteuse);
6848 //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";
6849 //exit;
6850
6851 // Define list of countries to use to search VAT rates to show
6852 // First we defined code_country to use to find list
6853 if (is_object($societe_vendeuse)) {
6854 $code_country = "'" . $societe_vendeuse->country_code . "'";
6855 } else {
6856 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6857 }
6858 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
6859 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6860 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
6861 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
6862 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
6863 if (isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
6864 // We also add the buyer country code
6865 if (is_numeric($type)) {
6866 if ($type == 1) { // We know product is a service
6867 switch ($selectVatComboMode) {
6868 case '1':
6869 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6870 break;
6871 case '2':
6872 $code_country = "'" . $societe_acheteuse->country_code . "'";
6873 break;
6874 }
6875 }
6876 } elseif (!$idprod) { // We don't know type of product
6877 switch ($selectVatComboMode) {
6878 case '1':
6879 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6880 break;
6881 case '2':
6882 $code_country = "'" . $societe_acheteuse->country_code . "'";
6883 break;
6884 }
6885 } else {
6886 $prodstatic = new Product($this->db);
6887 $prodstatic->fetch($idprod);
6888 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6889 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6890 }
6891 }
6892 }
6893 }
6894
6895 // Now we load the list of VAT
6896 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6897
6898 // Keep only the VAT qualified for $type_vat
6899 $arrayofvatrates = array();
6900 foreach ($this->cache_vatrates as $cachevalue) {
6901 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] != $type_vat) {
6902 $arrayofvatrates[] = $cachevalue;
6903 }
6904 }
6905
6906 $num = count($arrayofvatrates);
6907
6908 if ($num > 0) {
6909 // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6910 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6911 $tmpthirdparty = new Societe($this->db);
6912
6913 $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6914 $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6915
6916 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6917 $defaultcode = $reg[1];
6918 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6919 }
6920 if (empty($defaulttx)) {
6921 $defaultnpr = 0;
6922 }
6923 }
6924
6925 // If we fails to find a default vat rate, we take the last one in list
6926 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
6927 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6928 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6929 // We take the last one found in list
6930 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
6931 } else {
6932 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
6933 $defaulttx = '';
6934 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6935 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
6936 }
6937 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6938 $defaultcode = $reg[1];
6939 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6940 }
6941 }
6942 }
6943
6944 // Disabled if seller is not subject to VAT
6945 $disabled = false;
6946 $title = '';
6947 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6948 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6949 // of using supplier invoices (this is a very bad idea !)
6950 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
6951 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
6952 $disabled = true;
6953 }
6954 }
6955
6956 if (!$options_only) {
6957 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
6958 }
6959
6960 $selectedfound = false;
6961 foreach ($arrayofvatrates as $rate) {
6962 // Keep only 0 if seller is not subject to VAT
6963 if ($disabled && $rate['txtva'] != 0) {
6964 continue;
6965 }
6966
6967 // Define key to use into select list
6968 $key = $rate['txtva'];
6969 $key .= $rate['nprtva'] ? '*' : '';
6970 if ($mode > 0 && $rate['code']) {
6971 $key .= ' (' . $rate['code'] . ')';
6972 }
6973 if ($mode < 0) {
6974 $key = $rate['rowid'];
6975 }
6976
6977 $return .= '<option value="' . $key . '"';
6978 if (!$selectedfound) {
6979 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6980 if ($defaultcode == $rate['code']) {
6981 $return .= ' selected';
6982 $selectedfound = true;
6983 }
6984 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6985 $return .= ' selected';
6986 $selectedfound = true;
6987 }
6988 }
6989 $return .= '>';
6990
6991 // Show label of VAT
6992 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
6993 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
6994 $return .= $rate['labelpositiverates'];
6995 } else {
6996 // Simple label
6997 $return .= vatrate($rate['label']);
6998 }
6999
7000 //$return.=($rate['code']?' '.$rate['code']:'');
7001 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
7002
7003 $return .= '</option>';
7004 }
7005
7006 if (!$options_only) {
7007 $return .= '</select>';
7008 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
7009 }
7010 } else {
7011 $return .= $this->error;
7012 }
7013
7014 $this->num = $num;
7015 return $return;
7016 }
7017
7018
7019 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7020
7045 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 = '')
7046 {
7047 // phpcs:enable
7048 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
7049 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
7050 if (!empty($nooutput)) {
7051 return $retstring;
7052 }
7053 print $retstring;
7054
7055 return '';
7056 }
7057
7073 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
7074 {
7075 global $langs;
7076
7077 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
7078 if ($forcenewline) {
7079 $ret .= '<br>';
7080 }
7081 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
7082 return $ret;
7083 }
7084
7112 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')
7113 {
7114 global $conf, $langs;
7115
7116 if ($gm === 'auto') {
7117 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7118 }
7119
7120 $retstring = '';
7121
7122 if ($prefix == '') {
7123 $prefix = 're';
7124 }
7125 if ($h == '') {
7126 $h = 0;
7127 }
7128 if ($m == '') {
7129 $m = 0;
7130 }
7131 $emptydate = 0;
7132 $emptyhours = 0;
7133 if ($stepminutes <= 0 || $stepminutes > 30) {
7134 $stepminutes = 1;
7135 }
7136 if ($empty == 1) {
7137 $emptydate = 1;
7138 $emptyhours = 1;
7139 }
7140 if ($empty == 2) {
7141 $emptydate = 0;
7142 $emptyhours = 1;
7143 }
7144 $orig_set_time = $set_time;
7145
7146 if ($set_time === '' && $emptydate == 0) {
7147 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7148 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7149 $set_time = dol_now($gm);
7150 } else {
7151 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7152 }
7153 }
7154
7155 // Analysis of the pre-selection date
7156 $reg = array();
7157 $shour = '';
7158 $smin = '';
7159 $ssec = '';
7160 if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
7161 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7162 $syear = (!empty($reg[1]) ? $reg[1] : '');
7163 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7164 $sday = (!empty($reg[3]) ? $reg[3] : '');
7165 $shour = (!empty($reg[4]) ? $reg[4] : '');
7166 $smin = (!empty($reg[5]) ? $reg[5] : '');
7167 } elseif (strval($set_time) != '' && $set_time != -1) {
7168 // set_time est un timestamps (0 possible)
7169 $syear = dol_print_date($set_time, "%Y", $gm);
7170 $smonth = dol_print_date($set_time, "%m", $gm);
7171 $sday = dol_print_date($set_time, "%d", $gm);
7172 if ($orig_set_time != '') {
7173 $shour = dol_print_date($set_time, "%H", $gm);
7174 $smin = dol_print_date($set_time, "%M", $gm);
7175 $ssec = dol_print_date($set_time, "%S", $gm);
7176 }
7177 } else {
7178 // Date est '' ou vaut -1
7179 $syear = '';
7180 $smonth = '';
7181 $sday = '';
7182 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7183 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7184 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7185 }
7186 if ($h == 3 || $h == 4) {
7187 $shour = '';
7188 }
7189 if ($m == 3) {
7190 $smin = '';
7191 }
7192
7193 $nowgmt = dol_now('gmt');
7194 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7195
7196 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7197 $usecalendar = 'combo';
7198 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7199 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
7200 }
7201 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7202 // If we use a text browser or screen reader, we use the 'combo' date selector
7203 $usecalendar = 'html';
7204 }
7205
7206 if ($d) {
7207 // Show date with popup
7208 if ($usecalendar != 'combo') {
7209 $formated_date = '';
7210 //print "e".$set_time." t ".$conf->format_date_short;
7211 if (strval($set_time) != '' && $set_time != -1) {
7212 //$formated_date=dol_print_date($set_time,$conf->format_date_short);
7213 $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7214 }
7215
7216 // Calendrier popup version eldy
7217 if ($usecalendar == "eldy") {
7218 // Input area to enter date manually
7219 $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formated_date . '"';
7220 $retstring .= ($disabled ? ' disabled' : '');
7221 $retstring .= ' onChange="dpChangeDay(\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7222 $retstring .= ' autocomplete="off">';
7223
7224 // Icon calendar
7225 $retstringbuttom = '';
7226 if (!$disabled) {
7227 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7228 $base = DOL_URL_ROOT . '/core/';
7229 $retstringbuttom .= ' onClick="showDP(\'' . $base . '\',\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\',\'' . $langs->defaultlang . '\');"';
7230 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
7231 } else {
7232 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7233 }
7234 $retstring = $retstringbuttom . $retstring;
7235
7236 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7237 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7238 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7239 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7240 if (!$disabled && $usecalendar != 'html') {
7241 // Output javascript for datepicker
7242 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7243 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7244
7245 $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
7246 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7247 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7248 autoclose: true,
7249 todayHighlight: true,
7250 yearRange: '" . $minYear . ":" . $maxYear . "',";
7251 if (!empty($conf->dol_use_jmobile)) {
7252 $retstring .= "
7253 beforeShow: function (input, datePicker) {
7254 input.disabled = true;
7255 },
7256 onClose: function (dateText, datePicker) {
7257 this.disabled = false;
7258 },
7259 ";
7260 }
7261 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7262 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7263 $retstring .= "
7264 showOn: 'button', /* both has problem with autocompletion */
7265 buttonImage: '" . DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png',
7266 buttonImageOnly: true";
7267 }
7268 $retstring .= "
7269 }) });";
7270 $retstring .= "</script>";
7271 }
7272
7273 // Input area to enter date manually
7274 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7275 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate center" maxlength="11" value="'.$formated_date.'"';
7276 $retstring .= ($disabled ? ' disabled' : '');
7277 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7278 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7279 $retstring .= ' autocomplete="off">';
7280
7281 // Icone calendrier
7282 if ($disabled) {
7283 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7284 $retstring = $retstringbutton . $retstring;
7285 }
7286
7287 $retstring .= '</div>';
7288 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7289 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7290 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7291 } else {
7292 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7293 }
7294 } else {
7295 // Show date with combo selects
7296 // Day
7297 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7298
7299 if ($emptydate || $set_time == -1) {
7300 $retstring .= '<option value="0" selected>&nbsp;</option>';
7301 }
7302
7303 for ($day = 1; $day <= 31; $day++) {
7304 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7305 }
7306
7307 $retstring .= "</select>";
7308
7309 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7310 if ($emptydate || $set_time == -1) {
7311 $retstring .= '<option value="0" selected>&nbsp;</option>';
7312 }
7313
7314 // Month
7315 for ($month = 1; $month <= 12; $month++) {
7316 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7317 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7318 $retstring .= "</option>";
7319 }
7320 $retstring .= "</select>";
7321
7322 // Year
7323 if ($emptydate || $set_time == -1) {
7324 $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 . '">';
7325 } else {
7326 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7327
7328 $syear = (int) $syear;
7329 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7330 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7331 }
7332 $retstring .= "</select>\n";
7333 }
7334 }
7335 }
7336
7337 if ($d && $h) {
7338 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7339 $retstring .= '<span class="nowraponall">';
7340 }
7341
7342 if ($h) {
7343 $hourstart = 0;
7344 $hourend = 24;
7345 if ($openinghours != '') {
7346 $openinghours = explode(',', $openinghours);
7347 $hourstart = $openinghours[0];
7348 $hourend = $openinghours[1];
7349 if ($hourend < $hourstart) {
7350 $hourend = $hourstart;
7351 }
7352 }
7353 // Show hour
7354 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7355 if ($emptyhours) {
7356 $retstring .= '<option value="-1">&nbsp;</option>';
7357 }
7358 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7359 if (strlen($hour) < 2) {
7360 $hour = "0" . $hour;
7361 }
7362 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7363 //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
7364 $retstring .= '</option>';
7365 }
7366 $retstring .= '</select>';
7367 //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
7368 if ($m) {
7369 $retstring .= ":";
7370 }
7371 }
7372
7373 if ($m) {
7374 // Show minutes
7375 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7376 if ($emptyhours) {
7377 $retstring .= '<option value="-1">&nbsp;</option>';
7378 }
7379 for ($min = 0; $min < 60; $min += $stepminutes) {
7380 $min_str = sprintf("%02d", $min);
7381 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7382 }
7383 $retstring .= '</select>';
7384
7385 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7386 }
7387
7388 if ($d && $h) {
7389 $retstring .= '</span>';
7390 }
7391
7392 // Add a "Now" link
7393 if (!empty($conf->use_javascript_ajax) && $addnowlink) {
7394 // Script which will be inserted in the onClick of the "Now" link
7395 $reset_scripts = "";
7396 if ($addnowlink == 2) { // local computer time
7397 // pad add leading 0 on numbers
7398 $reset_scripts .= "Number.prototype.pad = function(size) {
7399 var s = String(this);
7400 while (s.length < (size || 2)) {s = '0' + s;}
7401 return s;
7402 };
7403 var d = new Date();";
7404 }
7405
7406 // Generate the date part, depending on the use or not of the javascript calendar
7407 if ($addnowlink == 1) { // server time expressed in user time setup
7408 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7409 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7410 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7411 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7412 } elseif ($addnowlink == 2) {
7413 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7414 * This break application for foreign languages.
7415 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7416 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7417 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7418 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7419 */
7420 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7421 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7422 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7423 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7424 }
7425 /*if ($usecalendar == "eldy")
7426 {
7427 $base=DOL_URL_ROOT.'/core/';
7428 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7429 }
7430 else
7431 {
7432 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7433 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7434 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7435 }*/
7436 // Update the hour part
7437 if ($h) {
7438 if ($fullday) {
7439 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7440 }
7441 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7442 if ($addnowlink == 1) {
7443 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7444 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7445 } elseif ($addnowlink == 2) {
7446 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7447 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7448 }
7449
7450 if ($fullday) {
7451 $reset_scripts .= ' } ';
7452 }
7453 }
7454 // Update the minute part
7455 if ($m) {
7456 if ($fullday) {
7457 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7458 }
7459 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7460 if ($addnowlink == 1) {
7461 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7462 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7463 } elseif ($addnowlink == 2) {
7464 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7465 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7466 }
7467 if ($fullday) {
7468 $reset_scripts .= ' } ';
7469 }
7470 }
7471 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7472 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7473 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7474 $retstring .= $langs->trans("Now");
7475 $retstring .= '</button> ';
7476 }
7477 }
7478
7479 // Add a "Plus one hour" link
7480 if ($conf->use_javascript_ajax && $addplusone) {
7481 // Script which will be inserted in the onClick of the "Add plusone" link
7482 $reset_scripts = "";
7483
7484 // Generate the date part, depending on the use or not of the javascript calendar
7485 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7486 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7487 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7488 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7489 // Update the hour part
7490 if ($h) {
7491 if ($fullday) {
7492 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7493 }
7494 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7495 if ($fullday) {
7496 $reset_scripts .= ' } ';
7497 }
7498 }
7499 // Update the minute part
7500 if ($m) {
7501 if ($fullday) {
7502 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7503 }
7504 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7505 if ($fullday) {
7506 $reset_scripts .= ' } ';
7507 }
7508 }
7509 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7510 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7511 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7512 $retstring .= $langs->trans("DateStartPlusOne");
7513 $retstring .= '</button> ';
7514 }
7515 }
7516
7517 // Add a link to set data
7518 if ($conf->use_javascript_ajax && !empty($adddateof)) {
7519 if (!is_array($adddateof)) {
7520 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
7521 } else {
7522 $arrayofdateof = $adddateof;
7523 }
7524 foreach ($arrayofdateof as $valuedateof) {
7525 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
7526 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
7527 $tmparray = dol_getdate($tmpadddateof);
7528 if (empty($tmplabeladddateof)) {
7529 $tmplabeladddateof = $langs->trans("DateInvoice");
7530 }
7531 $reset_scripts = 'console.log(\'Click on now link\'); ';
7532 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7533 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7534 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7535 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7536 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7537 }
7538 }
7539
7540 return $retstring;
7541 }
7542
7551 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7552 {
7553 global $langs;
7554
7555 $TDurationTypes = array(
7556 'y' => $langs->trans('Years'),
7557 'm' => $langs->trans('Month'),
7558 'w' => $langs->trans('Weeks'),
7559 'd' => $langs->trans('Days'),
7560 'h' => $langs->trans('Hours'),
7561 'i' => $langs->trans('Minutes')
7562 );
7563
7564 // Removed undesired duration types
7565 foreach ($excludetypes as $value) {
7566 unset($TDurationTypes[$value]);
7567 }
7568
7569 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7570 foreach ($TDurationTypes as $key => $typeduration) {
7571 $retstring .= '<option value="' . $key . '"';
7572 if ($key == $selected) {
7573 $retstring .= " selected";
7574 }
7575 $retstring .= ">" . $typeduration . "</option>";
7576 }
7577 $retstring .= "</select>";
7578
7579 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7580
7581 return $retstring;
7582 }
7583
7584 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7585
7599 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7600 {
7601 // phpcs:enable
7602 global $langs;
7603
7604 $retstring = '<span class="nowraponall">';
7605
7606 $hourSelected = '';
7607 $minSelected = '';
7608
7609 // Hours
7610 if ($iSecond != '') {
7611 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7612
7613 $hourSelected = convertSecondToTime($iSecond, 'allhour');
7614 $minSelected = convertSecondToTime($iSecond, 'min');
7615 }
7616
7617 if ($typehour == 'select') {
7618 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7619 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7620 $retstring .= '<option value="' . $hour . '"';
7621 if (is_numeric($hourSelected) && $hourSelected == $hour) {
7622 $retstring .= " selected";
7623 }
7624 $retstring .= ">" . $hour . "</option>";
7625 }
7626 $retstring .= "</select>";
7627 } elseif ($typehour == 'text' || $typehour == 'textselect') {
7628 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7629 } else {
7630 return 'BadValueForParameterTypeHour';
7631 }
7632
7633 if ($typehour != 'text') {
7634 $retstring .= ' ' . $langs->trans('HourShort');
7635 } else {
7636 $retstring .= '<span class="">:</span>';
7637 }
7638
7639 // Minutes
7640 if ($minunderhours) {
7641 $retstring .= '<br>';
7642 } else {
7643 if ($typehour != 'text') {
7644 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7645 }
7646 }
7647
7648 if ($typehour == 'select' || $typehour == 'textselect') {
7649 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7650 for ($min = 0; $min <= 55; $min += 5) {
7651 $retstring .= '<option value="' . $min . '"';
7652 if (is_numeric($minSelected) && $minSelected == $min) {
7653 $retstring .= ' selected';
7654 }
7655 $retstring .= '>' . $min . '</option>';
7656 }
7657 $retstring .= "</select>";
7658 } elseif ($typehour == 'text') {
7659 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7660 }
7661
7662 if ($typehour != 'text') {
7663 $retstring .= ' ' . $langs->trans('MinuteShort');
7664 }
7665
7666 $retstring .= "</span>";
7667
7668 if (!empty($nooutput)) {
7669 return $retstring;
7670 }
7671
7672 print $retstring;
7673
7674 return '';
7675 }
7676
7696 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)
7697 {
7698 global $langs, $conf;
7699
7700 $out = '';
7701
7702 // check parameters
7703 if (is_null($ajaxoptions)) {
7704 $ajaxoptions = array();
7705 }
7706
7707 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7708 $placeholder = '';
7709
7710 if ($selected && empty($selected_input_value)) {
7711 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7712 $tickettmpselect = new Ticket($this->db);
7713 $tickettmpselect->fetch($selected);
7714 $selected_input_value = $tickettmpselect->ref;
7715 unset($tickettmpselect);
7716 }
7717
7718 $urloption = '';
7719 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7720
7721 if (empty($hidelabel)) {
7722 $out .= $langs->trans("RefOrLabel") . ' : ';
7723 } elseif ($hidelabel > 1) {
7724 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7725 if ($hidelabel == 2) {
7726 $out .= img_picto($langs->trans("Search"), 'search');
7727 }
7728 }
7729 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7730 if ($hidelabel == 3) {
7731 $out .= img_picto($langs->trans("Search"), 'search');
7732 }
7733 } else {
7734 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7735 }
7736
7737 if (empty($nooutput)) {
7738 print $out;
7739 } else {
7740 return $out;
7741 }
7742 return '';
7743 }
7744
7745
7762 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7763 {
7764 global $langs, $conf;
7765
7766 $out = '';
7767 $outarray = array();
7768
7769 $selectFields = " p.rowid, p.ref, p.message";
7770
7771 $sql = "SELECT ";
7772 $sql .= $selectFields;
7773 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7774 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7775
7776 // Add criteria on ref/label
7777 if ($filterkey != '') {
7778 $sql .= ' AND (';
7779 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7780 // For natural search
7781 $search_crit = explode(' ', $filterkey);
7782 $i = 0;
7783 if (count($search_crit) > 1) {
7784 $sql .= "(";
7785 }
7786 foreach ($search_crit as $crit) {
7787 if ($i > 0) {
7788 $sql .= " AND ";
7789 }
7790 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7791 $sql .= ")";
7792 $i++;
7793 }
7794 if (count($search_crit) > 1) {
7795 $sql .= ")";
7796 }
7797 $sql .= ')';
7798 }
7799
7800 $sql .= $this->db->plimit($limit, 0);
7801
7802 // Build output string
7803 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7804 $result = $this->db->query($sql);
7805 if ($result) {
7806 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7807 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7808
7809 $num = $this->db->num_rows($result);
7810
7811 $events = array();
7812
7813 if (!$forcecombo) {
7814 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7815 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('TICKET_USE_SEARCH_TO_SELECT'));
7816 }
7817
7818 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7819
7820 $textifempty = '';
7821 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7822 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7823 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7824 if ($showempty && !is_numeric($showempty)) {
7825 $textifempty = $langs->trans($showempty);
7826 } else {
7827 $textifempty .= $langs->trans("All");
7828 }
7829 } else {
7830 if ($showempty && !is_numeric($showempty)) {
7831 $textifempty = $langs->trans($showempty);
7832 }
7833 }
7834 if ($showempty) {
7835 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7836 }
7837
7838 $i = 0;
7839 while ($num && $i < $num) {
7840 $opt = '';
7841 $optJson = array();
7842 $objp = $this->db->fetch_object($result);
7843
7844 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7845 '@phan-var-force array{key:string,value:mixed,type:int} $optJson';
7846 // Add new entry
7847 // "key" value of json key array is used by jQuery automatically as selected value
7848 // "label" value of json key array is used by jQuery automatically as text for combo box
7849 $out .= $opt;
7850 array_push($outarray, $optJson);
7851
7852 $i++;
7853 }
7854
7855 $out .= '</select>';
7856
7857 $this->db->free($result);
7858
7859 if (empty($outputmode)) {
7860 return $out;
7861 }
7862 return $outarray;
7863 } else {
7864 dol_print_error($this->db);
7865 }
7866
7867 return array();
7868 }
7869
7881 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7882 {
7883 $outkey = '';
7884 $outref = '';
7885 $outtype = '';
7886
7887 $outkey = $objp->rowid;
7888 $outref = $objp->ref;
7889
7890 $opt = '<option value="' . $objp->rowid . '"';
7891 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7892 $opt .= '>';
7893 $opt .= $objp->ref;
7894 $objRef = $objp->ref;
7895 if (!empty($filterkey) && $filterkey != '') {
7896 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7897 }
7898
7899 $opt .= "</option>\n";
7900 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7901 }
7902
7922 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)
7923 {
7924 global $langs, $conf;
7925
7926 $out = '';
7927
7928 // check parameters
7929 if (is_null($ajaxoptions)) {
7930 $ajaxoptions = array();
7931 }
7932
7933 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7934 $placeholder = '';
7935
7936 if ($selected && empty($selected_input_value)) {
7937 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7938 $projecttmpselect = new Project($this->db);
7939 $projecttmpselect->fetch($selected);
7940 $selected_input_value = $projecttmpselect->ref;
7941 unset($projecttmpselect);
7942 }
7943
7944 $urloption = '';
7945 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7946
7947 if (empty($hidelabel)) {
7948 $out .= $langs->trans("RefOrLabel") . ' : ';
7949 } elseif ($hidelabel > 1) {
7950 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7951 if ($hidelabel == 2) {
7952 $out .= img_picto($langs->trans("Search"), 'search');
7953 }
7954 }
7955 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7956 if ($hidelabel == 3) {
7957 $out .= img_picto($langs->trans("Search"), 'search');
7958 }
7959 } else {
7960 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7961 }
7962
7963 if (empty($nooutput)) {
7964 print $out;
7965 } else {
7966 return $out;
7967 }
7968 return '';
7969 }
7970
7987 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7988 {
7989 global $langs, $conf;
7990
7991 $out = '';
7992 $outarray = array();
7993
7994 $selectFields = " p.rowid, p.ref";
7995
7996 $sql = "SELECT ";
7997 $sql .= $selectFields;
7998 $sql .= " FROM " . $this->db->prefix() . "projet as p";
7999 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
8000
8001 // Add criteria on ref/label
8002 if ($filterkey != '') {
8003 $sql .= ' AND (';
8004 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8005 // For natural search
8006 $search_crit = explode(' ', $filterkey);
8007 $i = 0;
8008 if (count($search_crit) > 1) {
8009 $sql .= "(";
8010 }
8011 foreach ($search_crit as $crit) {
8012 if ($i > 0) {
8013 $sql .= " AND ";
8014 }
8015 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8016 $sql .= "";
8017 $i++;
8018 }
8019 if (count($search_crit) > 1) {
8020 $sql .= ")";
8021 }
8022 $sql .= ')';
8023 }
8024
8025 $sql .= $this->db->plimit($limit, 0);
8026
8027 // Build output string
8028 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
8029 $result = $this->db->query($sql);
8030 if ($result) {
8031 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8032 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
8033
8034 $num = $this->db->num_rows($result);
8035
8036 $events = array();
8037
8038 if (!$forcecombo) {
8039 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8040 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8041 }
8042
8043 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8044
8045 $textifempty = '';
8046 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8047 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8048 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8049 if ($showempty && !is_numeric($showempty)) {
8050 $textifempty = $langs->trans($showempty);
8051 } else {
8052 $textifempty .= $langs->trans("All");
8053 }
8054 } else {
8055 if ($showempty && !is_numeric($showempty)) {
8056 $textifempty = $langs->trans($showempty);
8057 }
8058 }
8059 if ($showempty) {
8060 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8061 }
8062
8063 $i = 0;
8064 while ($num && $i < $num) {
8065 $opt = '';
8066 $optJson = array();
8067 $objp = $this->db->fetch_object($result);
8068
8069 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
8070 // Add new entry
8071 // "key" value of json key array is used by jQuery automatically as selected value
8072 // "label" value of json key array is used by jQuery automatically as text for combo box
8073 $out .= $opt;
8074 array_push($outarray, $optJson);
8075
8076 $i++;
8077 }
8078
8079 $out .= '</select>';
8080
8081 $this->db->free($result);
8082
8083 if (empty($outputmode)) {
8084 return $out;
8085 }
8086 return $outarray;
8087 } else {
8088 dol_print_error($this->db);
8089 }
8090
8091 return array();
8092 }
8093
8105 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8106 {
8107 $outkey = '';
8108 $outref = '';
8109 $outtype = '';
8110
8111 $label = $objp->label;
8112
8113 $outkey = $objp->rowid;
8114 $outref = $objp->ref;
8115 $outlabel = $objp->label;
8116 $outtype = $objp->fk_product_type;
8117
8118 $opt = '<option value="' . $objp->rowid . '"';
8119 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8120 $opt .= '>';
8121 $opt .= $objp->ref;
8122 $objRef = $objp->ref;
8123 if (!empty($filterkey) && $filterkey != '') {
8124 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8125 }
8126
8127 $opt .= "</option>\n";
8128 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8129 }
8130
8131
8151 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)
8152 {
8153 global $langs, $conf;
8154
8155 $out = '';
8156
8157 // check parameters
8158 if (is_null($ajaxoptions)) {
8159 $ajaxoptions = array();
8160 }
8161
8162 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8163 $placeholder = '';
8164
8165 if ($selected && empty($selected_input_value)) {
8166 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8167 $adherenttmpselect = new Adherent($this->db);
8168 $adherenttmpselect->fetch($selected);
8169 $selected_input_value = $adherenttmpselect->ref;
8170 unset($adherenttmpselect);
8171 }
8172
8173 $urloption = '';
8174
8175 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8176
8177 if (empty($hidelabel)) {
8178 $out .= $langs->trans("RefOrLabel") . ' : ';
8179 } elseif ($hidelabel > 1) {
8180 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8181 if ($hidelabel == 2) {
8182 $out .= img_picto($langs->trans("Search"), 'search');
8183 }
8184 }
8185 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8186 if ($hidelabel == 3) {
8187 $out .= img_picto($langs->trans("Search"), 'search');
8188 }
8189 } else {
8190 $filterkey = '';
8191
8192 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8193 }
8194
8195 if (empty($nooutput)) {
8196 print $out;
8197 } else {
8198 return $out;
8199 }
8200 return '';
8201 }
8202
8219 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8220 {
8221 global $langs, $conf;
8222
8223 $out = '';
8224 $outarray = array();
8225
8226 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8227
8228 $sql = "SELECT ";
8229 $sql .= $selectFields;
8230 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8231 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8232
8233 // Add criteria on ref/label
8234 if ($filterkey != '') {
8235 $sql .= ' AND (';
8236 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8237 // For natural search
8238 $search_crit = explode(' ', $filterkey);
8239 $i = 0;
8240 if (count($search_crit) > 1) {
8241 $sql .= "(";
8242 }
8243 foreach ($search_crit as $crit) {
8244 if ($i > 0) {
8245 $sql .= " AND ";
8246 }
8247 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8248 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8249 $i++;
8250 }
8251 if (count($search_crit) > 1) {
8252 $sql .= ")";
8253 }
8254 $sql .= ')';
8255 }
8256 if ($status != -1) {
8257 $sql .= ' AND statut = ' . ((int) $status);
8258 }
8259 $sql .= $this->db->plimit($limit, 0);
8260
8261 // Build output string
8262 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8263 $result = $this->db->query($sql);
8264 if ($result) {
8265 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8266 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8267
8268 $num = $this->db->num_rows($result);
8269
8270 $events = array();
8271
8272 if (!$forcecombo) {
8273 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8274 $out .= ajax_combobox($htmlname, $events, getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT') ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
8275 }
8276
8277 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8278
8279 $textifempty = '';
8280 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8281 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8282 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8283 if ($showempty && !is_numeric($showempty)) {
8284 $textifempty = $langs->trans($showempty);
8285 } else {
8286 $textifempty .= $langs->trans("All");
8287 }
8288 } else {
8289 if ($showempty && !is_numeric($showempty)) {
8290 $textifempty = $langs->trans($showempty);
8291 }
8292 }
8293 if ($showempty) {
8294 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8295 }
8296
8297 $i = 0;
8298 while ($num && $i < $num) {
8299 $opt = '';
8300 $optJson = array();
8301 $objp = $this->db->fetch_object($result);
8302
8303 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8304
8305 // Add new entry
8306 // "key" value of json key array is used by jQuery automatically as selected value
8307 // "label" value of json key array is used by jQuery automatically as text for combo box
8308 $out .= $opt;
8309 array_push($outarray, $optJson);
8310
8311 $i++;
8312 }
8313
8314 $out .= '</select>';
8315
8316 $this->db->free($result);
8317
8318 if (empty($outputmode)) {
8319 return $out;
8320 }
8321 return $outarray;
8322 } else {
8323 dol_print_error($this->db);
8324 }
8325
8326 return array();
8327 }
8328
8340 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8341 {
8342 $outkey = '';
8343 $outlabel = '';
8344 $outtype = '';
8345
8346 $outkey = $objp->rowid;
8347 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8348 $outtype = $objp->fk_adherent_type;
8349
8350 $opt = '<option value="' . $objp->rowid . '"';
8351 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8352 $opt .= '>';
8353 if (!empty($filterkey) && $filterkey != '') {
8354 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8355 }
8356 $opt .= $outlabel;
8357 $opt .= "</option>\n";
8358
8359 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8360 }
8361
8382 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8383 {
8384 global $conf, $extrafields, $user;
8385
8386 // Example of common usage for a link to a thirdparty
8387
8388 // We got this in a modulebuilder form of "MyObject" of module "mymodule".
8389 // ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8390 // $objectdesc = 'Societe'
8391 // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc'])
8392
8393 // We got this when showing an extrafields on resource that is a link to societe
8394 // extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)'
8395 // $objectdesc = 'Societe'
8396 // $objectfield = 'resource:options_link_to_societe'
8397
8398 // With old usage:
8399 // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))'
8400 // $objectfield = ''
8401
8402 //var_dump($objectdesc.' '.$objectfield);
8403 //debug_print_backtrace();
8404
8405 $objectdescorig = $objectdesc;
8406 $objecttmp = null;
8407 $InfoFieldList = array();
8408 $classname = '';
8409 $filter = ''; // Ensure filter has value (for static analysis)
8410 $sortfield = ''; // Ensure filter has value (for static analysis)
8411
8412 if ($objectfield) { // We must retrieve the objectdesc from the field or extrafield
8413 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8414 $tmparray = explode(':', $objectfield);
8415
8416 // Get instance of object from $element
8417 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8418
8419 if (is_object($objectforfieldstmp)) {
8420 $objectdesc = '';
8421
8422 $reg = array();
8423 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8424 // For a property in extrafields
8425 $key = $reg[1];
8426 // fetch optionals attributes and labels
8427 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8428
8429 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8430 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8431 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8432 $objectdesc = $tmpextrafields[0];
8433 }
8434 }
8435 } else {
8436 // For a property in ->fields
8437 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8438 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8439 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8440 }
8441 }
8442 }
8443 }
8444
8445 if ($objectdesc) {
8446 // Example of value for $objectdesc:
8447 // Bom:bom/class/bom.class.php:0:t.status=1
8448 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8449 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8450 $InfoFieldList = explode(":", $objectdesc, 4);
8451 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8452 $reg = array();
8453 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8454 $InfoFieldList[4] = $reg[1]; // take the sort field
8455 }
8456 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8457
8458 $classname = $InfoFieldList[0];
8459 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8460 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8461 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8462 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8463
8464 // Load object according to $id and $element
8465 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8466
8467 // Fallback to another solution to get $objecttmp
8468 if (empty($objecttmp) && !empty($classpath)) {
8469 dol_include_once($classpath);
8470
8471 if ($classname && class_exists($classname)) {
8472 $objecttmp = new $classname($this->db);
8473 }
8474 }
8475 }
8476
8477 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
8478 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
8479 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
8480 $filter = str_replace(
8481 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
8482 array($conf->entity, $sharedentities, $user->id),
8483 $filter
8484 );
8485
8486 if (!is_object($objecttmp)) {
8487 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc, LOG_WARNING);
8488 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc;
8489 }
8490 '@phan-var-force CommonObject $objecttmp';
8491
8492 //var_dump($filter);
8493 $prefixforautocompletemode = $objecttmp->element;
8494 if ($prefixforautocompletemode == 'societe') {
8495 $prefixforautocompletemode = 'company';
8496 }
8497 if ($prefixforautocompletemode == 'product') {
8498 $prefixforautocompletemode = 'produit';
8499 }
8500 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8501
8502 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
8503
8504 // Generate the combo HTML component
8505 $out = '';
8506 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
8507 // No immediate load of all database
8508 $placeholder = '';
8509
8510 if ($preSelectedValue && empty($selected_input_value)) {
8511 $objecttmp->fetch($preSelectedValue);
8512 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
8513
8514 $oldValueForShowOnCombobox = 0;
8515 foreach ($objecttmp->fields as $fieldK => $fielV) {
8516 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
8517 continue;
8518 }
8519
8520 if (!$oldValueForShowOnCombobox) {
8521 $selected_input_value = '';
8522 }
8523
8524 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
8525 $selected_input_value .= $objecttmp->$fieldK;
8526 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
8527 }
8528 }
8529
8530 // Set url and param to call to get json of the search results
8531 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
8532 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . '&objectfield='.urlencode($objectfield) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
8533
8534 // Activate the auto complete using ajax call.
8535 $out .= ajax_autocompleter((string) $preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalInt($confkeyforautocompletemode), 0);
8536 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
8537 $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) . '"' : '') . ' />';
8538 } else {
8539 // Immediate load of table record.
8540 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
8541 }
8542
8543 return $out;
8544 }
8545
8546
8567 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
8568 {
8569 global $langs, $user, $hookmanager;
8570
8571 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
8572
8573 $prefixforautocompletemode = $objecttmp->element;
8574 if ($prefixforautocompletemode == 'societe') {
8575 $prefixforautocompletemode = 'company';
8576 }
8577 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8578
8579 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
8580 $tmpfieldstoshow = '';
8581 foreach ($objecttmp->fields as $key => $val) {
8582 if (! (int) dol_eval($val['enabled'], 1, 1, '1')) {
8583 continue;
8584 }
8585 if (!empty($val['showoncombobox'])) {
8586 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8587 }
8588 }
8589 if ($tmpfieldstoshow) {
8590 $fieldstoshow = $tmpfieldstoshow;
8591 }
8592 } else {
8593 // For backward compatibility
8594 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8595 }
8596
8597 if (empty($fieldstoshow)) {
8598 if (!empty($objecttmp->parent_element)) {
8599 $fieldstoshow = 'o.ref';
8600 if (empty($sortfield)) {
8601 $sortfield = 'o.ref';
8602 }
8603 if (in_array($objecttmp->element, ['commandedet', 'propaldet', 'facturedet', 'expeditiondet'])) {
8604 $fieldstoshow .= ',p.ref AS p_ref,p.label,t.description';
8605 $sortfield .= ', p.ref';
8606 }
8607 } elseif (isset($objecttmp->fields['ref'])) {
8608 $fieldstoshow = 't.ref';
8609 } else {
8610 $langs->load("errors");
8611 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8612 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8613 }
8614 }
8615
8616 $out = '';
8617 $outarray = array();
8618 $tmparray = array();
8619
8620 $num = 0;
8621
8622 // Search data
8623 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . " as t";
8624 if (!empty($objecttmp->isextrafieldmanaged)) {
8625 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . "_extrafields as e ON t.rowid = e.fk_object";
8626 }
8627 if (!empty($objecttmp->parent_element)) {
8628 $parent_properties = getElementProperties($objecttmp->parent_element);
8629 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($parent_properties['table_element']) . " as o ON o.rowid = t.".$objecttmp->fk_parent_attribute;
8630 }
8631 if (in_array($objecttmp->parent_element, ['commande', 'propal', 'facture', 'expedition'])) {
8632 $sql .= " LEFT JOIN " . $this->db->prefix() . "product as p ON p.rowid = t.fk_product";
8633 }
8634 if (isset($objecttmp->ismultientitymanaged)) {
8635 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8636 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8637 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($tmparray[1]) . " as parenttable ON parenttable.rowid = t." . $this->db->sanitize($tmparray[0]);
8638 }
8639 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8640 if (!$user->hasRight('societe', 'client', 'voir')) {
8641 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8642 }
8643 }
8644 }
8645
8646 // Add where from hooks
8647 $parameters = array(
8648 'object' => $objecttmp,
8649 'htmlname' => $htmlname,
8650 'filter' => $filter,
8651 'searchkey' => $searchkey
8652 );
8653
8654 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8655 if (!empty($hookmanager->resPrint)) {
8656 $sql .= $hookmanager->resPrint;
8657 } else {
8658 $sql .= " WHERE 1=1";
8659 if (isset($objecttmp->ismultientitymanaged)) {
8660 if ($objecttmp->ismultientitymanaged == 1) {
8661 $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8662 }
8663 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8664 $sql .= " AND parenttable.entity = t." . $this->db->sanitize($tmparray[0]);
8665 }
8666 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8667 if ($objecttmp->element == 'societe') {
8668 $sql .= " AND t.rowid = " . ((int) $user->socid);
8669 } else {
8670 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8671 }
8672 }
8673 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8674 if (!$user->hasRight('societe', 'client', 'voir')) {
8675 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8676 }
8677 }
8678 }
8679 $splittedfieldstoshow = explode(',', $fieldstoshow);
8680 foreach ($splittedfieldstoshow as &$field2) {
8681 if (is_numeric($pos=strpos($field2, ' '))) {
8682 $field2 = substr($field2, 0, $pos);
8683 }
8684 }
8685 if ($searchkey != '') {
8686 $sql .= natural_search($splittedfieldstoshow, $searchkey);
8687 }
8688
8689 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8690 $errormessage = '';
8691 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8692 if ($errormessage) {
8693 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8694 }
8695 }
8696 }
8697 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8698 //$sql.=$this->db->plimit($limit, 0);
8699 //print $sql;
8700
8701 // Build output string
8702 $resql = $this->db->query($sql);
8703 if ($resql) {
8704 // Construct $out and $outarray
8705 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8706
8707 // 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
8708 $textifempty = '&nbsp;';
8709
8710 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8711 if (getDolGlobalInt($confkeyforautocompletemode)) {
8712 if ($showempty && !is_numeric($showempty)) {
8713 $textifempty = $langs->trans($showempty);
8714 } else {
8715 $textifempty .= $langs->trans("All");
8716 }
8717 }
8718 if ($showempty) {
8719 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8720 }
8721
8722 $num = $this->db->num_rows($resql);
8723 $i = 0;
8724 if ($num) {
8725 while ($i < $num) {
8726 $obj = $this->db->fetch_object($resql);
8727 $label = '';
8728 $labelhtml = '';
8729 $tmparray = explode(',', $fieldstoshow);
8730 $oldvalueforshowoncombobox = 0;
8731 foreach ($tmparray as $key => $val) {
8732 $val = preg_replace('/(t|p|o)\./', '', $val);
8733 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8734 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8735 $label .= $obj->$val;
8736 $labelhtml .= $obj->$val;
8737
8738 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8739 }
8740 if (empty($outputmode)) {
8741 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8742 $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>';
8743 } else {
8744 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8745 }
8746 } else {
8747 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8748 }
8749
8750 $i++;
8751 if (($i % 10) == 0) {
8752 $out .= "\n";
8753 }
8754 }
8755 }
8756
8757 $out .= '</select>' . "\n";
8758
8759 if (!$forcecombo) {
8760 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8761 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
8762 }
8763 } else {
8764 dol_print_error($this->db);
8765 }
8766
8767 $this->result = array('nbofelement' => $num);
8768
8769 if ($outputmode) {
8770 return $outarray;
8771 }
8772 return $out;
8773 }
8774
8775
8799 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)
8800 {
8801 global $conf, $langs;
8802
8803 // Do we want a multiselect ?
8804 //$jsbeautify = 0;
8805 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8806 $jsbeautify = 1;
8807
8808 if ($value_as_key) {
8809 $array = array_combine($array, $array);
8810 }
8811
8812 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
8813
8814 $out = '';
8815
8816 if ($addjscombo < 0) {
8817 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8818 $addjscombo = 1;
8819 } else {
8820 $addjscombo = 0;
8821 }
8822 }
8823 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8824 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8825 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8826 $out .= '>'."\n";
8827
8828 if ($show_empty) {
8829 $textforempty = ' ';
8830 if (!empty($conf->use_javascript_ajax)) {
8831 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8832 }
8833 if (!is_numeric($show_empty)) {
8834 $textforempty = $show_empty;
8835 }
8836 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8837 }
8838 if (is_array($array)) {
8839 // Translate
8840 if ($translate) {
8841 foreach ($array as $key => $value) {
8842 if (!is_array($value)) {
8843 $array[$key] = $langs->trans($value);
8844 } else {
8845 $array[$key]['label'] = $langs->trans($value['label']);
8846 }
8847 }
8848 }
8849 // Sort
8850 if ($sort == 'ASC') {
8851 asort($array);
8852 } elseif ($sort == 'DESC') {
8853 arsort($array);
8854 }
8855
8856 foreach ($array as $key => $tmpvalue) {
8857 if (is_array($tmpvalue)) {
8858 $value = $tmpvalue['label'];
8859 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
8860 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8861 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8862 } else {
8863 $value = $tmpvalue;
8864 //$valuehtml = $tmpvalue;
8865 $disabled = '';
8866 $style = '';
8867 }
8868 if (!empty($disablebademail)) {
8869 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8870 || ($disablebademail == 2 && preg_match('/---/', $value))) {
8871 $disabled = ' disabled';
8872 $style = ' class="warning"';
8873 }
8874 }
8875 if ($key_in_label) {
8876 if (empty($nohtmlescape)) {
8877 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8878 } else {
8879 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8880 }
8881 } else {
8882 if (empty($nohtmlescape)) {
8883 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
8884 } else {
8885 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8886 }
8887 if ($value == '' || $value == '-') {
8888 $selectOptionValue = '&nbsp;';
8889 }
8890 }
8891 $out .= '<option value="' . $key . '"';
8892 $out .= $style . $disabled;
8893 if (is_array($id)) {
8894 if (in_array($key, $id) && !$disabled) {
8895 $out .= ' selected'; // To preselect a value
8896 }
8897 } else {
8898 $id = (string) $id; // if $id = 0, then $id = '0'
8899 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8900 $out .= ' selected'; // To preselect a value
8901 }
8902 }
8903 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
8904 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
8905 }
8906
8907 if (is_array($tmpvalue)) {
8908 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
8909 if ($keyforvalue == 'labelhtml') {
8910 $keyforvalue = 'data-html';
8911 }
8912 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
8913 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
8914 }
8915 }
8916 }
8917 $out .= '>';
8918 $out .= $selectOptionValue;
8919 $out .= "</option>\n";
8920 }
8921 }
8922 $out .= "</select>";
8923
8924 // Add code for jquery to use multiselect
8925 if ($addjscombo && $jsbeautify) {
8926 // Enhance with select2
8927 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8928 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
8929 }
8930
8931 return $out;
8932 }
8933
8952 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8953 {
8954 global $conf, $langs;
8955 global $delayedhtmlcontent; // Will be used later outside of this function
8956
8957 // TODO Use an internal dolibarr component instead of select2
8958 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8959 return '';
8960 }
8961
8962 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
8963
8964 $outdelayed = '';
8965 if (!empty($conf->use_javascript_ajax)) {
8966 $tmpplugin = 'select2';
8967 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8968 <script nonce="' . getNonce() . '">
8969 $(document).ready(function () {
8970
8971 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
8972
8973 $(".' . $htmlname . '").select2({
8974 ajax: {
8975 dir: "ltr",
8976 url: "' . $url . '",
8977 dataType: \'json\',
8978 delay: 250,
8979 data: function (params) {
8980 return {
8981 q: params.term, // search term
8982 page: params.page
8983 }
8984 },
8985 processResults: function (data) {
8986 // parse the results into the format expected by Select2.
8987 // since we are using custom formatting functions we do not need to alter the remote JSON data
8988 //console.log(data);
8989 saveRemoteData = data;
8990 /* format json result for select2 */
8991 result = []
8992 $.each( data, function( key, value ) {
8993 result.push({id: key, text: value.text});
8994 });
8995 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
8996 //console.log(result);
8997 return {results: result, more: false}
8998 },
8999 cache: true
9000 },
9001 language: select2arrayoflanguage,
9002 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9003 placeholder: "' . dol_escape_js($placeholder) . '",
9004 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9005 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9006 formatResult: function (result, container, query, escapeMarkup) {
9007 return escapeMarkup(result.text);
9008 },
9009 });
9010
9011 ' . ($callurlonselect ? '
9012 /* Code to execute a GET when we select a value */
9013 $(".' . $htmlname . '").change(function() {
9014 var selected = $(".' . $htmlname . '").val();
9015 console.log("We select in selectArrayAjax the entry "+selected)
9016 $(".' . $htmlname . '").val(""); /* reset visible combo value */
9017 $.each( saveRemoteData, function( key, value ) {
9018 if (key == selected)
9019 {
9020 console.log("selectArrayAjax - Do a redirect to "+value.url)
9021 location.assign(value.url);
9022 }
9023 });
9024 });' : '') . '
9025
9026 });
9027 </script>';
9028 }
9029
9030 if ($acceptdelayedhtml) {
9031 $delayedhtmlcontent .= $outdelayed;
9032 } else {
9033 $out .= $outdelayed;
9034 }
9035 return $out;
9036 }
9037
9057 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
9058 {
9059 global $conf, $langs;
9060 global $delayedhtmlcontent; // Will be used later outside of this function
9061
9062 // TODO Use an internal dolibarr component instead of select2
9063 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9064 return '';
9065 }
9066
9067 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
9068
9069 $formattedarrayresult = array();
9070
9071 foreach ($array as $key => $value) {
9072 $o = new stdClass();
9073 $o->id = $key;
9074 $o->text = $value['text'];
9075 $o->url = $value['url'];
9076 $formattedarrayresult[] = $o;
9077 }
9078
9079 $outdelayed = '';
9080 if (!empty($conf->use_javascript_ajax)) {
9081 $tmpplugin = 'select2';
9082 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9083 <script nonce="' . getNonce() . '">
9084 $(document).ready(function () {
9085 var data = ' . json_encode($formattedarrayresult) . ';
9086
9087 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
9088
9089 $(".' . $htmlname . '").select2({
9090 data: data,
9091 language: select2arrayoflanguage,
9092 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9093 placeholder: "' . dol_escape_js($placeholder) . '",
9094 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9095 minimumInputLength: ' . $minimumInputLength . ',
9096 formatResult: function (result, container, query, escapeMarkup) {
9097 return escapeMarkup(result.text);
9098 },
9099 matcher: function (params, data) {
9100
9101 if(! data.id) return null;';
9102
9103 if ($callurlonselect) {
9104 // We forge the url with 'sall='
9105 $outdelayed .= '
9106
9107 var urlBase = data.url;
9108 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
9109 /* console.log("params.term="+params.term); */
9110 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
9111 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
9112 }
9113
9114 if (!$disableFiltering) {
9115 $outdelayed .= '
9116
9117 if(data.text.match(new RegExp(params.term))) {
9118 return data;
9119 }
9120
9121 return null;';
9122 } else {
9123 $outdelayed .= '
9124
9125 return data;';
9126 }
9127
9128 $outdelayed .= '
9129 }
9130 });
9131
9132 ' . ($callurlonselect ? '
9133 /* Code to execute a GET when we select a value */
9134 $(".' . $htmlname . '").change(function() {
9135 var selected = $(".' . $htmlname . '").val();
9136 console.log("We select "+selected)
9137
9138 $(".' . $htmlname . '").val(""); /* reset visible combo value */
9139 $.each( saveRemoteData, function( key, value ) {
9140 if (key == selected)
9141 {
9142 console.log("selectArrayFilter - Do a redirect to "+value.url)
9143 location.assign(value.url);
9144 }
9145 });
9146 });' : '') . '
9147
9148 });
9149 </script>';
9150 }
9151
9152 if ($acceptdelayedhtml) {
9153 $delayedhtmlcontent .= $outdelayed;
9154 } else {
9155 $out .= $outdelayed;
9156 }
9157 return $out;
9158 }
9159
9178 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)
9179 {
9180 global $conf, $langs;
9181
9182 $out = '';
9183
9184 if ($addjscombo < 0) {
9185 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9186 $addjscombo = 1;
9187 } else {
9188 $addjscombo = 0;
9189 }
9190 }
9191
9192 $useenhancedmultiselect = 0;
9193 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9194 if ($addjscombo) {
9195 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9196 }
9197 }
9198
9199 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9200 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9201 // submitted to nothing.
9202 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9203 // Output select component
9204 $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";
9205 if (is_array($array) && !empty($array)) {
9206 if ($value_as_key) {
9207 $array = array_combine($array, $array);
9208 }
9209
9210 if (!empty($array)) {
9211 foreach ($array as $key => $value) {
9212 $tmpkey = $key;
9213 $tmpvalue = $value;
9214 $tmpcolor = '';
9215 $tmppicto = '';
9216 $tmplabelhtml = '';
9217 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9218 $tmpkey = $value['id'];
9219 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9220 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9221 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9222 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']) : $value['labelhtml'];
9223 }
9224 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9225 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9226
9227 $out .= '<option value="' . $tmpkey . '"';
9228 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9229 $out .= ' selected';
9230 }
9231 if (!empty($tmplabelhtml)) {
9232 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9233 } else {
9234 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9235 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9236 }
9237 $out .= '>';
9238 $out .= dol_htmlentitiesbr($newval);
9239 $out .= '</option>' . "\n";
9240 }
9241 }
9242 }
9243 $out .= '</select>' . "\n";
9244
9245 // Add code for jquery to use multiselect
9246 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9247 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9248 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9249 if ($addjscombo == 1) {
9250 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
9251 $out .= 'function formatResult(record, container) {' . "\n";
9252 // If property data-html set, we decode html entities and use this.
9253 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9254 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9255 //$out .= ' console.log("aaa");';
9256 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9257 $out .= ' }'."\n";
9258 $out .= ' return record.text;';
9259 $out .= '}' . "\n";
9260 $out .= 'function formatSelection(record) {' . "\n";
9261 if ($elemtype == 'category') {
9262 $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
9263 } else {
9264 $out .= 'return record.text;';
9265 }
9266 $out .= '}' . "\n";
9267 $out .= '$(document).ready(function () {
9268 $(\'#' . $htmlname . '\').' . $tmpplugin . '({';
9269 if ($placeholder) {
9270 $out .= '
9271 placeholder: {
9272 id: \'-1\',
9273 text: \'' . dol_escape_js($placeholder) . '\'
9274 },';
9275 }
9276 $out .= ' dir: \'ltr\',
9277 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9278 dropdownCssClass: \'' . $morecss . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
9279 // Specify format function for dropdown item
9280 formatResult: formatResult,
9281 templateResult: formatResult, /* For 4.0 */
9282 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9283 // Specify format function for selected item
9284 formatSelection: formatSelection,
9285 templateSelection: formatSelection /* For 4.0 */
9286 });
9287
9288 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
9289 the size only if component is not hidden by default on load */
9290 $(\'#' . $htmlname . ' + .select2\').addClass(\'' . $morecss . '\');
9291 });' . "\n";
9292 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9293 // Add other js lib
9294 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9295 // ...
9296 $out .= 'console.log(\'addjscombo=2 for htmlname=' . $htmlname . '\');';
9297 $out .= '$(document).ready(function () {
9298 $(\'#' . $htmlname . '\').multiSelect({
9299 containerHTML: \'<div class="multi-select-container">\',
9300 menuHTML: \'<div class="multi-select-menu">\',
9301 buttonHTML: \'<span class="multi-select-button ' . $morecss . '">\',
9302 menuItemHTML: \'<label class="multi-select-menuitem">\',
9303 activeClass: \'multi-select-container--open\',
9304 noneText: \'' . $placeholder . '\'
9305 });
9306 })';
9307 }
9308 $out .= '</script>';
9309 }
9310
9311 return $out;
9312 }
9313
9314
9326 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9327 {
9328 global $langs, $user;
9329
9330 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9331 return '';
9332 }
9333 if (empty($array)) {
9334 return '';
9335 }
9336
9337 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9338
9339 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9340 $tmparray = explode(',', $user->conf->$tmpvar);
9341 foreach ($array as $key => $val) {
9342 //var_dump($key);
9343 //var_dump($tmparray);
9344 if (in_array($key, $tmparray)) {
9345 $array[$key]['checked'] = 1;
9346 } else {
9347 $array[$key]['checked'] = 0;
9348 }
9349 }
9350 } else { // There is no list of fields already customized for user
9351 foreach ($array as $key => $val) {
9352 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9353 $array[$key]['checked'] = 0;
9354 }
9355 }
9356 }
9357
9358 $listoffieldsforselection = '';
9359 $listcheckedstring = '';
9360
9361 foreach ($array as $key => $val) {
9362 // var_dump($val);
9363 // var_dump(array_key_exists('enabled', $val));
9364 // var_dump(!$val['enabled']);
9365 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9366 unset($array[$key]); // We don't want this field
9367 continue;
9368 }
9369 if (!empty($val['type']) && $val['type'] == 'separate') {
9370 // Field remains in array but we don't add it into $listoffieldsforselection
9371 //$listoffieldsforselection .= '<li>-----</li>';
9372 continue;
9373 }
9374 if (!empty($val['label']) && $val['label']) {
9375 if (!empty($val['langfile']) && is_object($langs)) {
9376 $langs->load($val['langfile']);
9377 }
9378
9379 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9380 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((!array_key_exists('checked', $val) || empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . '/><label for="checkbox' . $key . '">' . dol_escape_htmltag($langs->trans($val['label'])) . '</label></li>';
9381 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9382 }
9383 }
9384
9385 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9386
9387 <dl class="dropdown">
9388 <dt>
9389 <a href="#' . $htmlname . '">
9390 ' . img_picto('', 'list') . '
9391 </a>
9392 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9393 </dt>
9394 <dd class="dropdowndd">
9395 <div class="multiselectcheckbox'.$htmlname.'">
9396 <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
9397 <li class="liinputsearch"><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
9398 '.$listoffieldsforselection.'
9399 </ul>
9400 </div>
9401 </dd>
9402 </dl>
9403
9404 <script nonce="' . getNonce() . '" type="text/javascript">
9405 jQuery(document).ready(function () {
9406 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
9407 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9408
9409 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9410
9411 var title = $(this).val() + ",";
9412 if ($(this).is(\':checked\')) {
9413 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9414 }
9415 else {
9416 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9417 }
9418 // Now, we submit page
9419 //$(this).parents(\'form:first\').submit();
9420 });
9421 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9422 var value = $(this).val().toLowerCase();
9423 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9424 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9425 });
9426 });
9427
9428
9429 });
9430 </script>
9431
9432 ';
9433 return $out;
9434 }
9435
9445 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
9446 {
9447 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
9448
9449 $cat = new Categorie($this->db);
9450 $categories = $cat->containing($id, $type);
9451
9452 if ($rendermode == 1) {
9453 $toprint = array();
9454 foreach ($categories as $c) {
9455 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
9456 foreach ($ways as $way) {
9457 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
9458 }
9459 }
9460 if (empty($toprint)) {
9461 return '';
9462 } else {
9463 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
9464 }
9465 }
9466
9467 if ($rendermode == 0) {
9468 $arrayselected = array();
9469 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
9470 foreach ($categories as $c) {
9471 $arrayselected[] = $c->id;
9472 }
9473
9474 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
9475 }
9476
9477 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
9478 }
9479
9489 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
9490 {
9491 global $conf, $langs, $hookmanager;
9492 global $action;
9493
9494 $object->fetchObjectLinked();
9495
9496 // Bypass the default method
9497 $hookmanager->initHooks(array('commonobject'));
9498 $parameters = array(
9499 'morehtmlright' => $morehtmlright,
9500 'compatibleImportElementsList' => &$compatibleImportElementsList,
9501 );
9502 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9503
9504 $nbofdifferenttypes = count($object->linkedObjects);
9505
9506 if (empty($reshook)) {
9507 print '<!-- showLinkedObjectBlock -->';
9508 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, '', 'showlinkedobjectblock');
9509
9510
9511 print '<div class="div-table-responsive-no-min">';
9512 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
9513
9514 print '<tr class="liste_titre">';
9515 print '<td>' . $langs->trans("Type") . '</td>';
9516 print '<td>' . $langs->trans("Ref") . '</td>';
9517 print '<td class="center"></td>';
9518 print '<td class="center">' . $langs->trans("Date") . '</td>';
9519 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9520 print '<td class="right">' . $langs->trans("Status") . '</td>';
9521 print '<td></td>';
9522 print '</tr>';
9523
9524 $nboftypesoutput = 0;
9525
9526 foreach ($object->linkedObjects as $objecttype => $objects) {
9527 $tplpath = $element = $subelement = $objecttype;
9528
9529 // to display import button on tpl
9530 $showImportButton = false;
9531 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
9532 $showImportButton = true;
9533 }
9534
9535 $regs = array();
9536 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
9537 $element = $regs[1];
9538 $subelement = $regs[2];
9539 $tplpath = $element . '/' . $subelement;
9540 }
9541 $tplname = 'linkedobjectblock';
9542
9543 // To work with non standard path
9544 if ($objecttype == 'facture') {
9545 $tplpath = 'compta/' . $element;
9546 if (!isModEnabled('invoice')) {
9547 continue; // Do not show if module disabled
9548 }
9549 } elseif ($objecttype == 'facturerec') {
9550 $tplpath = 'compta/facture';
9551 $tplname = 'linkedobjectblockForRec';
9552 if (!isModEnabled('invoice')) {
9553 continue; // Do not show if module disabled
9554 }
9555 } elseif ($objecttype == 'propal') {
9556 $tplpath = 'comm/' . $element;
9557 if (!isModEnabled('propal')) {
9558 continue; // Do not show if module disabled
9559 }
9560 } elseif ($objecttype == 'supplier_proposal') {
9561 if (!isModEnabled('supplier_proposal')) {
9562 continue; // Do not show if module disabled
9563 }
9564 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
9565 $tplpath = 'expedition';
9566 if (!isModEnabled('shipping')) {
9567 continue; // Do not show if module disabled
9568 }
9569 } elseif ($objecttype == 'reception') {
9570 $tplpath = 'reception';
9571 if (!isModEnabled('reception')) {
9572 continue; // Do not show if module disabled
9573 }
9574 } elseif ($objecttype == 'delivery') {
9575 $tplpath = 'delivery';
9576 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
9577 continue; // Do not show if sub module disabled
9578 }
9579 } elseif ($objecttype == 'ficheinter') {
9580 $tplpath = 'fichinter';
9581 if (!isModEnabled('intervention')) {
9582 continue; // Do not show if module disabled
9583 }
9584 } elseif ($objecttype == 'invoice_supplier') {
9585 $tplpath = 'fourn/facture';
9586 } elseif ($objecttype == 'order_supplier') {
9587 $tplpath = 'fourn/commande';
9588 } elseif ($objecttype == 'expensereport') {
9589 $tplpath = 'expensereport';
9590 } elseif ($objecttype == 'subscription') {
9591 $tplpath = 'adherents';
9592 } elseif ($objecttype == 'conferenceorbooth') {
9593 $tplpath = 'eventorganization';
9594 } elseif ($objecttype == 'conferenceorboothattendee') {
9595 $tplpath = 'eventorganization';
9596 } elseif ($objecttype == 'mo') {
9597 $tplpath = 'mrp';
9598 if (!isModEnabled('mrp')) {
9599 continue; // Do not show if module disabled
9600 }
9601 } elseif ($objecttype == 'project_task') {
9602 $tplpath = 'projet/tasks';
9603 }
9604
9605 global $linkedObjectBlock;
9606 $linkedObjectBlock = $objects;
9607
9608 // Output template part (modules that overwrite templates must declare this into descriptor)
9609 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
9610 foreach ($dirtpls as $reldir) {
9611 $reldir = rtrim($reldir, '/');
9612 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
9613 global $noMoreLinkedObjectBlockAfter;
9614 $noMoreLinkedObjectBlockAfter = 1;
9615 }
9616
9617 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
9618 if ($res) {
9619 $nboftypesoutput++;
9620 break;
9621 }
9622 }
9623 }
9624
9625 if (!$nboftypesoutput) {
9626 print '<tr><td colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9627 }
9628
9629 print '</table>';
9630
9631 if (!empty($compatibleImportElementsList)) {
9632 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9633 }
9634
9635 print '</div>';
9636 }
9637
9638 return $nbofdifferenttypes;
9639 }
9640
9650 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array(), $nooutput = 0)
9651 {
9652 global $conf, $langs, $hookmanager;
9653 global $action;
9654
9655 $form = new Form($this->db);
9656
9657 $linktoelem = '';
9658 $linktoelemlist = '';
9659 $listofidcompanytoscan = '';
9660
9661 if (!is_object($object->thirdparty)) {
9662 $object->fetch_thirdparty();
9663 }
9664
9665 $possiblelinks = array();
9666
9667 $dontIncludeCompletedItems = getDolGlobalString('DONT_INCLUDE_COMPLETED_ELEMENTS_LINKS');
9668
9669 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9670 $listofidcompanytoscan = $object->thirdparty->id;
9671 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
9672 $listofidcompanytoscan .= ',' . $object->thirdparty->parent;
9673 }
9674 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
9675 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9676 $tmpproject = new Project($this->db);
9677 $tmpproject->fetch($object->fk_project);
9678 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9679 $listofidcompanytoscan .= ',' . $tmpproject->socid;
9680 }
9681 unset($tmpproject);
9682 }
9683
9684 $possiblelinks = array(
9685 'propal' => array(
9686 'enabled' => isModEnabled('propal'),
9687 'perms' => 1,
9688 'label' => 'LinkToProposal',
9689 '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' : '')),
9690 'shipping' => array(
9691 'enabled' => isModEnabled('shipping'),
9692 'perms' => 1,
9693 'label' => 'LinkToExpedition',
9694 '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' : '')),
9695 'order' => array(
9696 'enabled' => isModEnabled('order'),
9697 'perms' => 1,
9698 'label' => 'LinkToOrder',
9699 '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' : '')),
9700 'invoice' => array(
9701 'enabled' => isModEnabled('invoice'),
9702 'perms' => 1,
9703 'label' => 'LinkToInvoice',
9704 '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' : '')),
9705 'invoice_template' => array(
9706 'enabled' => isModEnabled('invoice'),
9707 'perms' => 1,
9708 'label' => 'LinkToTemplateInvoice',
9709 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('invoice') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : '')),
9710 'contrat' => array(
9711 'enabled' => isModEnabled('contract'),
9712 'perms' => 1,
9713 'label' => 'LinkToContract',
9714 '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
9715 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'
9716 ),
9717 'fichinter' => array(
9718 'enabled' => isModEnabled('intervention'),
9719 'perms' => 1,
9720 'label' => 'LinkToIntervention',
9721 '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') . ')'),
9722 'supplier_proposal' => array(
9723 'enabled' => isModEnabled('supplier_proposal'),
9724 'perms' => 1,
9725 'label' => 'LinkToSupplierProposal',
9726 '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' : '')),
9727 'order_supplier' => array(
9728 'enabled' => isModEnabled("supplier_order"),
9729 'perms' => 1,
9730 'label' => 'LinkToSupplierOrder',
9731 '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' : '')),
9732 'invoice_supplier' => array(
9733 'enabled' => isModEnabled("supplier_invoice"),
9734 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9735 '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' : '')),
9736 'ticket' => array(
9737 'enabled' => isModEnabled('ticket'),
9738 'perms' => 1,
9739 'label' => 'LinkToTicket',
9740 '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' : '')),
9741 'mo' => array(
9742 'enabled' => isModEnabled('mrp'),
9743 'perms' => 1,
9744 'label' => 'LinkToMo',
9745 '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' : ''))
9746 );
9747 }
9748
9749 if ($object->table_element == 'commande_fournisseur') {
9750 $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' : '');
9751 } elseif ($object->table_element == 'mrp_mo') {
9752 $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' : '');
9753 }
9754
9755 $reshook = 0; // Ensure $reshook is defined for static analysis
9756 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9757 // Can complete the possiblelink array
9758 $hookmanager->initHooks(array('commonobject'));
9759 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9760 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9761 }
9762
9763 if (empty($reshook)) {
9764 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9765 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9766 }
9767 } elseif ($reshook > 0) {
9768 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9769 $possiblelinks = $hookmanager->resArray;
9770 }
9771 }
9772
9773 // Build the html part with possible suggested links
9774 $htmltoenteralink = '';
9775 foreach ($possiblelinks as $key => $possiblelink) {
9776 $num = 0;
9777
9778 if (empty($possiblelink['enabled'])) {
9779 continue;
9780 }
9781
9782 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9783 $htmltoenteralink .= '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9784
9785 // Section for free ref input
9786 if (!getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9787 $htmltoenteralink .= '<br>'."\n";
9788 $htmltoenteralink .= '<!-- form to add a link from anywhere -->'."\n";
9789 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9790 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9791 $htmltoenteralink .= '<input type="hidden" name="action" value="addlinkbyref">';
9792 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9793 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9794 $htmltoenteralink .= '<table class="noborder">';
9795 $htmltoenteralink .= '<tr class="liste_titre">';
9796 //print '<td>' . $langs->trans("Ref") . '</td>';
9797 $htmltoenteralink .= '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9798 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9799 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9800 $htmltoenteralink .= '</tr>';
9801 $htmltoenteralink .= '</table>';
9802 $htmltoenteralink .= '</form>';
9803 }
9804
9805 $sql = $possiblelink['sql'];
9806
9807 $resqllist = $this->db->query($sql);
9808 if ($resqllist) {
9809 $num = $this->db->num_rows($resqllist);
9810 $i = 0;
9811
9812 if ($num > 0) {
9813 // Section for free predefined list
9814 if (getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9815 $htmltoenteralink .= '<br>';
9816 }
9817 $htmltoenteralink .= '<!-- form to add a link from object to same thirdparty -->'."\n";
9818 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9819 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9820 $htmltoenteralink .= '<input type="hidden" name="action" value="addlink">';
9821 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9822 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9823 $htmltoenteralink .= '<table class="noborder">';
9824 $htmltoenteralink .= '<tr class="liste_titre">';
9825 $htmltoenteralink .= '<td class="nowrap"></td>';
9826 $htmltoenteralink .= '<td>' . $langs->trans("Ref") . '</td>';
9827 $htmltoenteralink .= '<td>' . $langs->trans("RefCustomer") . '</td>';
9828 $htmltoenteralink .= '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9829 $htmltoenteralink .= '<td>' . $langs->trans("Company") . '</td>';
9830 $htmltoenteralink .= '</tr>';
9831 while ($i < $num) {
9832 $objp = $this->db->fetch_object($resqllist);
9833
9834 $htmltoenteralink .= '<tr class="oddeven">';
9835 $htmltoenteralink .= '<td>';
9836 $htmltoenteralink .= '<input type="checkbox" name="idtolinkto[' . $key . '_' . $objp->rowid . ']" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9837 $htmltoenteralink .= '</td>';
9838 $htmltoenteralink .= '<td><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9839 $htmltoenteralink .= '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9840 $htmltoenteralink .= '<td class="right">';
9841 if ($possiblelink['label'] == 'LinkToContract') {
9842 $htmltoenteralink .= $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9843 }
9844 $htmltoenteralink .= '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9845 $htmltoenteralink .= '</td>';
9846 $htmltoenteralink .= '<td>' . $objp->name . '</td>';
9847 $htmltoenteralink .= '</tr>';
9848 $i++;
9849 }
9850 $htmltoenteralink .= '</table>';
9851 $htmltoenteralink .= '<div class="center">';
9852 if ($num) {
9853 $htmltoenteralink .= '<input type="submit" class="button valignmiddle marginleftonly marginrightonly smallpaddingimp" value="' . $langs->trans('ToLink') . '">';
9854 }
9855 if (empty($conf->use_javascript_ajax)) {
9856 $htmltoenteralink .= '<input type="submit" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9857 } else {
9858 $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>';
9859 }
9860 $htmltoenteralink .= '</form>';
9861 }
9862
9863 $this->db->free($resqllist);
9864 } else {
9865 dol_print_error($this->db);
9866 }
9867 $htmltoenteralink .= '</div>';
9868
9869
9870 // Complete the list for the combo box
9871 if ($num > 0 || !getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9872 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
9873 // } else $linktoelem.=$langs->trans($possiblelink['label']);
9874 } else {
9875 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
9876 }
9877 }
9878 }
9879
9880 if ($linktoelemlist) {
9881 $linktoelem = '
9882 <dl class="dropdown" id="linktoobjectname">
9883 ';
9884 if (!empty($conf->use_javascript_ajax)) {
9885 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
9886 }
9887 $linktoelem .= '<dd>
9888 <div class="multiselectlinkto">
9889 <ul class="ulselectedfields">' . $linktoelemlist . '
9890 </ul>
9891 </div>
9892 </dd>
9893 </dl>';
9894 } else {
9895 $linktoelem = '';
9896 }
9897
9898 if (!empty($conf->use_javascript_ajax)) {
9899 print '<!-- Add js to show linkto box -->
9900 <script nonce="' . getNonce() . '">
9901 jQuery(document).ready(function() {
9902 jQuery(".linkto").click(function() {
9903 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
9904 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
9905 });
9906 });
9907 </script>
9908 ';
9909 }
9910
9911 if ($nooutput) {
9912 return array('linktoelem' => $linktoelem, 'htmltoenteralink' => $htmltoenteralink);
9913 } else {
9914 print $htmltoenteralink;
9915 }
9916
9917 return $linktoelem;
9918 }
9919
9934 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'width75', $labelyes = 'Yes', $labelno = 'No')
9935 {
9936 global $langs;
9937
9938 $yes = "yes";
9939 $no = "no";
9940 if ($option) {
9941 $yes = "1";
9942 $no = "0";
9943 }
9944
9945 $disabled = ($disabled ? ' disabled' : '');
9946
9947 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
9948 if ($useempty) {
9949 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
9950 }
9951 if (("$value" == 'yes') || ($value == 1)) {
9952 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
9953 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
9954 } else {
9955 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
9956 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
9957 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
9958 }
9959 $resultyesno .= '</select>' . "\n";
9960
9961 if ($addjscombo) {
9962 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
9963 }
9964
9965 return $resultyesno;
9966 }
9967
9968 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9969
9979 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
9980 {
9981 // phpcs:enable
9982 $sql = "SELECT rowid, label";
9983 $sql .= " FROM " . $this->db->prefix() . "export_model";
9984 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
9985 $sql .= " ORDER BY rowid";
9986 $result = $this->db->query($sql);
9987 if ($result) {
9988 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
9989 if ($useempty) {
9990 print '<option value="-1">&nbsp;</option>';
9991 }
9992
9993 $num = $this->db->num_rows($result);
9994 $i = 0;
9995 while ($i < $num) {
9996 $obj = $this->db->fetch_object($result);
9997 if ($selected == $obj->rowid) {
9998 print '<option value="' . $obj->rowid . '" selected>';
9999 } else {
10000 print '<option value="' . $obj->rowid . '">';
10001 }
10002 print $obj->label;
10003 print '</option>';
10004 $i++;
10005 }
10006 print "</select>";
10007 } else {
10008 dol_print_error($this->db);
10009 }
10010 }
10011
10030 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
10031 {
10032 global $conf, $langs, $hookmanager, $extralanguages;
10033
10034 $ret = '';
10035 if (empty($fieldid)) {
10036 $fieldid = 'rowid';
10037 }
10038 if (empty($fieldref)) {
10039 $fieldref = 'ref';
10040 }
10041
10042 // Preparing gender's display if there is one
10043 $addgendertxt = '';
10044 if (property_exists($object, 'gender') && !empty($object->gender)) {
10045 $addgendertxt = ' ';
10046 switch ($object->gender) {
10047 case 'man':
10048 $addgendertxt .= '<i class="fas fa-mars valignmiddle"></i>';
10049 break;
10050 case 'woman':
10051 $addgendertxt .= '<i class="fas fa-venus valignmiddle"></i>';
10052 break;
10053 case 'other':
10054 $addgendertxt .= '<i class="fas fa-transgender valignmiddle"></i>';
10055 break;
10056 }
10057 }
10058
10059 // Add where from hooks
10060 if (is_object($hookmanager)) {
10061 $parameters = array('showrefnav' => true);
10062 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
10063 $object->next_prev_filter .= $hookmanager->resPrint;
10064 }
10065
10066 $previous_ref = $next_ref = '';
10067 if ($shownav) {
10068 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
10069 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
10070
10071 $navurl = $_SERVER["PHP_SELF"];
10072 // Special case for project/task page
10073 if ($paramid == 'project_ref') {
10074 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
10075 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
10076 $paramid = 'ref';
10077 }
10078 }
10079
10080 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
10081 // accesskey is for Mac: CTRL + key for all browsers
10082 $stringforfirstkey = $langs->trans("KeyboardShortcut");
10083 if ($conf->browser->name == 'chrome') {
10084 $stringforfirstkey .= ' ALT +';
10085 } elseif ($conf->browser->name == 'firefox') {
10086 $stringforfirstkey .= ' ALT + SHIFT +';
10087 } else {
10088 $stringforfirstkey .= ' CTL +';
10089 }
10090
10091 $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>';
10092 $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>';
10093 }
10094
10095 //print "xx".$previous_ref."x".$next_ref;
10096 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
10097
10098 // Right part of banner
10099 if ($morehtmlright) {
10100 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
10101 }
10102
10103 if ($previous_ref || $next_ref || $morehtml) {
10104 $ret .= '<div class="pagination paginationref"><ul class="right">';
10105 }
10106 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
10107 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
10108 }
10109 if ($shownav && ($previous_ref || $next_ref)) {
10110 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
10111 $ret .= '<li class="pagination">' . $next_ref . '</li>';
10112 }
10113 if ($previous_ref || $next_ref || $morehtml) {
10114 $ret .= '</ul></div>';
10115 }
10116
10117 // Status
10118 $parameters = array('morehtmlstatus' => $morehtmlstatus);
10119 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
10120 if (empty($reshook)) {
10121 $morehtmlstatus .= $hookmanager->resPrint;
10122 } else {
10123 $morehtmlstatus = $hookmanager->resPrint;
10124 }
10125 if ($morehtmlstatus) {
10126 $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
10127 }
10128
10129 $parameters = array();
10130 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
10131 if (empty($reshook)) {
10132 $morehtmlref .= $hookmanager->resPrint;
10133 } elseif ($reshook > 0) {
10134 $morehtmlref = $hookmanager->resPrint;
10135 }
10136
10137 // Left part of banner
10138 if ($morehtmlleft) {
10139 if ($conf->browser->layout == 'phone') {
10140 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
10141 } else {
10142 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
10143 }
10144 }
10145
10146 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
10147 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
10148
10149 // For thirdparty, contact, user, member, the ref is the id, so we show something else
10150 if ($object->element == 'societe') {
10151 $ret .= dol_htmlentities($object->name);
10152
10153 // List of extra languages
10154 $arrayoflangcode = array();
10155 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
10156 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
10157 }
10158
10159 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
10160 if (!is_object($extralanguages)) {
10161 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
10162 $extralanguages = new ExtraLanguages($this->db);
10163 }
10164 $extralanguages->fetch_name_extralanguages('societe');
10165
10166 if (!empty($extralanguages->attributes['societe']['name'])) {
10167 $object->fetchValuesForExtraLanguages();
10168
10169 $htmltext = '';
10170 // If there is extra languages
10171 foreach ($arrayoflangcode as $extralangcode) {
10172 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
10173 if ($object->array_languages['name'][$extralangcode]) {
10174 $htmltext .= $object->array_languages['name'][$extralangcode];
10175 } else {
10176 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
10177 }
10178 }
10179 $ret .= '<!-- Show translations of name -->' . "\n";
10180 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
10181 }
10182 }
10183 } elseif ($object->element == 'member') {
10184 '@phan-var-force Adherent $object';
10185 $ret .= $object->ref . '<br>';
10186 $fullname = $object->getFullName($langs);
10187 if ($object->morphy == 'mor' && $object->societe) {
10188 $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
10189 } else {
10190 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
10191 }
10192 } elseif (in_array($object->element, array('contact', 'user'))) {
10193 $ret .= '<span class="valignmiddle">'.dol_htmlentities($object->getFullName($langs)).'</span>'.$addgendertxt;
10194 } elseif ($object->element == 'usergroup') {
10195 $ret .= dol_htmlentities($object->name);
10196 } elseif (in_array($object->element, array('action', 'agenda'))) {
10197 '@phan-var-force ActionComm $object';
10198 $ret .= $object->ref . '<br>' . $object->label;
10199 } elseif (in_array($object->element, array('adherent_type'))) {
10200 $ret .= $object->label;
10201 } elseif ($object->element == 'ecm_directories') {
10202 $ret .= '';
10203 } elseif ($fieldref != 'none') {
10204 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
10205 }
10206 if ($morehtmlref) {
10207 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
10208 if (substr($morehtmlref, 0, 4) != '<div') {
10209 $ret .= ' ';
10210 }
10211
10212 $ret .= '<!-- morehtmlref -->'.$morehtmlref;
10213 }
10214
10215 $ret .= '</div>';
10216
10217 $ret .= '</div><!-- End banner content -->';
10218
10219 return $ret;
10220 }
10221
10222
10231 public function showbarcode(&$object, $width = 100, $morecss = '')
10232 {
10233 global $conf;
10234
10235 //Check if barcode is filled in the card
10236 if (empty($object->barcode)) {
10237 return '';
10238 }
10239
10240 // Complete object if not complete
10241 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10242 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10243 $result = $object->fetch_barcode();
10244 //Check if fetch_barcode() failed
10245 if ($result < 1) {
10246 return '<!-- ErrorFetchBarcode -->';
10247 }
10248 }
10249
10250 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10251 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10252 $out = '<!-- url barcode = ' . $url . ' -->';
10253 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10254
10255 return $out;
10256 }
10257
10275 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10276 {
10277 global $conf, $langs;
10278
10279 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10280 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10281
10282 $dir = '';
10283 $file = '';
10284 $originalfile = '';
10285 $altfile = '';
10286 $email = '';
10287 $capture = '';
10288 if ($modulepart == 'societe') {
10289 $dir = $conf->societe->multidir_output[$entity];
10290 if (!empty($object->logo)) {
10291 if (dolIsAllowedForPreview($object->logo)) {
10292 if ((string) $imagesize == 'mini') {
10293 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10294 } elseif ((string) $imagesize == 'small') {
10295 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10296 } else {
10297 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10298 }
10299 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10300 }
10301 }
10302 $email = $object->email;
10303 } elseif ($modulepart == 'contact') {
10304 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10305 if (!empty($object->photo)) {
10306 if (dolIsAllowedForPreview($object->photo)) {
10307 if ((string) $imagesize == 'mini') {
10308 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10309 } elseif ((string) $imagesize == 'small') {
10310 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10311 } else {
10312 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10313 }
10314 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10315 }
10316 }
10317 $email = $object->email;
10318 $capture = 'user';
10319 } elseif ($modulepart == 'userphoto') {
10320 $dir = $conf->user->dir_output;
10321 if (!empty($object->photo)) {
10322 if (dolIsAllowedForPreview($object->photo)) {
10323 if ((string) $imagesize == 'mini') {
10324 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10325 } elseif ((string) $imagesize == 'small') {
10326 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10327 } else {
10328 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10329 }
10330 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10331 }
10332 }
10333 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10334 $altfile = $object->id . ".jpg"; // For backward compatibility
10335 }
10336 $email = $object->email;
10337 $capture = 'user';
10338 } elseif ($modulepart == 'memberphoto') {
10339 $dir = $conf->adherent->dir_output;
10340 if (!empty($object->photo)) {
10341 if (dolIsAllowedForPreview($object->photo)) {
10342 if ((string) $imagesize == 'mini') {
10343 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10344 } elseif ((string) $imagesize == 'small') {
10345 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10346 } else {
10347 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10348 }
10349 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10350 }
10351 }
10352 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10353 $altfile = $object->id . ".jpg"; // For backward compatibility
10354 }
10355 $email = $object->email;
10356 $capture = 'user';
10357 } else {
10358 // Generic case to show photos
10359 // TODO Implement this method in previous objects so we can always use this generic method.
10360 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10361 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10362
10363 $dir = $tmpdata['dir'];
10364 $file = $tmpdata['file'];
10365 $originalfile = $tmpdata['originalfile'];
10366 $altfile = $tmpdata['altfile'];
10367 $email = $tmpdata['email'];
10368 $capture = $tmpdata['capture'];
10369 }
10370 }
10371
10372 if ($forcecapture) {
10373 $capture = $forcecapture;
10374 }
10375
10376 $ret = '';
10377
10378 if ($dir) {
10379 if ($file && file_exists($dir . "/" . $file)) {
10380 if ($addlinktofullsize) {
10381 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10382 if ($urladvanced) {
10383 $ret .= '<a href="' . $urladvanced . '">';
10384 } else {
10385 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10386 }
10387 }
10388 $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 . '">';
10389 if ($addlinktofullsize) {
10390 $ret .= '</a>';
10391 }
10392 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
10393 if ($addlinktofullsize) {
10394 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10395 if ($urladvanced) {
10396 $ret .= '<a href="' . $urladvanced . '">';
10397 } else {
10398 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10399 }
10400 }
10401 $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 . '">';
10402 if ($addlinktofullsize) {
10403 $ret .= '</a>';
10404 }
10405 } else {
10406 $nophoto = '/public/theme/common/nophoto.png';
10407 $defaultimg = 'identicon'; // For gravatar
10408 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
10409 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
10410 $nophoto = 'company';
10411 } else {
10412 $nophoto = '/public/theme/common/user_anonymous.png';
10413 if (!empty($object->gender) && $object->gender == 'man') {
10414 $nophoto = '/public/theme/common/user_man.png';
10415 }
10416 if (!empty($object->gender) && $object->gender == 'woman') {
10417 $nophoto = '/public/theme/common/user_woman.png';
10418 }
10419 }
10420 }
10421
10422 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
10423 // see https://gravatar.com/site/implement/images/php/
10424 $ret .= '<!-- Put link to gravatar -->';
10425 $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
10426 } else {
10427 if ($nophoto == 'company') {
10428 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
10429 //$ret .= '<div class="difforspanimgright"></div>';
10430 } else {
10431 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
10432 }
10433 }
10434 }
10435
10436 if ($caneditfield) {
10437 if ($object->photo) {
10438 $ret .= "<br>\n";
10439 }
10440 $ret .= '<table class="nobordernopadding centpercent">';
10441 if ($object->photo) {
10442 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
10443 }
10444 $ret .= '<tr><td class="tdoverflow">';
10445 $maxfilesizearray = getMaxFileSizeArray();
10446 $maxmin = $maxfilesizearray['maxmin'];
10447 if ($maxmin > 0) {
10448 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
10449 }
10450 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
10451 $ret .= '</td></tr>';
10452 $ret .= '</table>';
10453 }
10454 }
10455
10456 return $ret;
10457 }
10458
10459 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10460
10477 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
10478 {
10479 // phpcs:enable
10480 global $conf, $user, $langs;
10481
10482 // Allow excluding groups
10483 $excludeGroups = null;
10484 if (is_array($exclude)) {
10485 $excludeGroups = implode(",", $exclude);
10486 }
10487 // Allow including groups
10488 $includeGroups = null;
10489 if (is_array($include)) {
10490 $includeGroups = implode(",", $include);
10491 }
10492
10493 if (!is_array($selected)) {
10494 $selected = array($selected);
10495 }
10496
10497 $out = '';
10498
10499 // Build sql to search groups
10500 $sql = "SELECT ug.rowid, ug.nom as name";
10501 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10502 $sql .= ", e.label";
10503 }
10504 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
10505 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10506 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
10507 if ($force_entity) {
10508 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
10509 } else {
10510 $sql .= " WHERE ug.entity IS NOT NULL";
10511 }
10512 } else {
10513 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
10514 }
10515 if (is_array($exclude) && $excludeGroups) {
10516 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
10517 }
10518 if (is_array($include) && $includeGroups) {
10519 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
10520 }
10521 $sql .= " ORDER BY ug.nom ASC";
10522
10523 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
10524 $resql = $this->db->query($sql);
10525 if ($resql) {
10526 // Enhance with select2
10527 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10528
10529 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
10530
10531 $num = $this->db->num_rows($resql);
10532 $i = 0;
10533 if ($num) {
10534 if ($show_empty && !$multiple) {
10535 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10536 }
10537
10538 while ($i < $num) {
10539 $obj = $this->db->fetch_object($resql);
10540 $disableline = 0;
10541 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
10542 $disableline = 1;
10543 }
10544
10545 $label = $obj->name;
10546 $labelhtml = $obj->name;
10547 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
10548 $label .= " (" . $obj->label . ")";
10549 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
10550 }
10551
10552 $out .= '<option value="' . $obj->rowid . '"';
10553 if ($disableline) {
10554 $out .= ' disabled';
10555 }
10556 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
10557 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
10558 $out .= ' selected';
10559 }
10560 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
10561 $out .= '>';
10562 $out .= $label;
10563 $out .= '</option>';
10564 $i++;
10565 }
10566 } else {
10567 if ($show_empty) {
10568 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
10569 }
10570 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
10571 }
10572 $out .= '</select>';
10573
10574 $out .= ajax_combobox($htmlname);
10575 } else {
10576 dol_print_error($this->db);
10577 }
10578
10579 return $out;
10580 }
10581
10582
10589 public function showFilterButtons($pos = '')
10590 {
10591 $out = '<div class="nowraponall">';
10592 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
10593 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
10594 $out .= '</div>';
10595
10596 return $out;
10597 }
10598
10607 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10608 {
10609 global $conf;
10610
10611 $out = '';
10612
10613 if (!empty($conf->use_javascript_ajax)) {
10614 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
10615 }
10616 $out .= '<script nonce="' . getNonce() . '">
10617 $(document).ready(function() {
10618 $("#' . $cssclass . 's").click(function() {
10619 if($(this).is(\':checked\')){
10620 console.log("We check all ' . $cssclass . ' and trigger the change method");
10621 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
10622 }
10623 else
10624 {
10625 console.log("We uncheck all");
10626 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
10627 }' . "\n";
10628 if ($calljsfunction) {
10629 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
10630 }
10631 $out .= ' });
10632 $(".' . $cssclass . '").change(function() {
10633 $(this).closest("tr").toggleClass("highlight", this.checked);
10634 });
10635 });
10636 </script>';
10637
10638 return $out;
10639 }
10640
10650 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10651 {
10652 $out = $this->showFilterButtons();
10653 if ($addcheckuncheckall) {
10654 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10655 }
10656 return $out;
10657 }
10658
10672 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10673 {
10674 global $langs, $user;
10675
10676 $out = '';
10677 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10678 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10679 if (!empty($excludeid)) {
10680 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10681 }
10682 $sql .= " ORDER BY label";
10683
10684 $resql = $this->db->query($sql);
10685 if ($resql) {
10686 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10687 if ($useempty) {
10688 $out .= '<option value="0">&nbsp;</option>';
10689 }
10690
10691 while ($obj = $this->db->fetch_object($resql)) {
10692 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10693 }
10694 $out .= '</select>';
10695 $out .= ajax_combobox('select_' . $htmlname);
10696
10697 if (!empty($htmlname) && $user->admin && $info_admin) {
10698 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10699 }
10700
10701 if (!empty($target)) {
10702 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10703 $resql = $this->db->query($sql);
10704 if ($resql) {
10705 if ($this->db->num_rows($resql) > 0) {
10706 $obj = $this->db->fetch_object($resql);
10707 $out .= '<script nonce="' . getNonce() . '">
10708 $(function() {
10709 $("select[name=' . $target . ']").on("change", function() {
10710 var current_val = $(this).val();
10711 if (current_val == ' . $obj->id . ') {';
10712 if (!empty($default_selected) || !empty($selected)) {
10713 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10714 }
10715
10716 $out .= '
10717 $("select[name=' . $htmlname . ']").change();
10718 }
10719 });
10720
10721 $("select[name=' . $htmlname . ']").change(function() {
10722
10723 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10724 // get price of kilometer to fill the unit price
10725 $.ajax({
10726 method: "POST",
10727 dataType: "json",
10728 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10729 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
10730 }).done(function( data, textStatus, jqXHR ) {
10731 console.log(data);
10732 if (typeof data.up != "undefined") {
10733 $("input[name=value_unit]").val(data.up);
10734 $("select[name=' . $htmlname . ']").attr("title", data.title);
10735 } else {
10736 $("input[name=value_unit]").val("");
10737 $("select[name=' . $htmlname . ']").attr("title", "");
10738 }
10739 });
10740 }
10741 });
10742 });
10743 </script>';
10744 }
10745 }
10746 }
10747 } else {
10748 dol_print_error($this->db);
10749 }
10750
10751 return $out;
10752 }
10753
10762 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10763 {
10764 global $conf, $langs;
10765
10766 $out = '';
10767 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10768 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10769
10770 $resql = $this->db->query($sql);
10771 if ($resql) {
10772 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10773 if ($useempty) {
10774 $out .= '<option value="0"></option>';
10775 }
10776
10777 while ($obj = $this->db->fetch_object($resql)) {
10778 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10779 }
10780 $out .= '</select>';
10781 } else {
10782 dol_print_error($this->db);
10783 }
10784
10785 return $out;
10786 }
10787
10798 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10799 {
10800 global $langs;
10801
10802 $out = '';
10803 $sql = "SELECT id, code, label";
10804 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
10805 $sql .= " WHERE active = 1";
10806
10807 $resql = $this->db->query($sql);
10808 if ($resql) {
10809 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10810 if ($useempty) {
10811 $out .= '<option value="0"></option>';
10812 }
10813 if ($allchoice) {
10814 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10815 }
10816
10817 $field = 'code';
10818 if ($useid) {
10819 $field = 'id';
10820 }
10821
10822 while ($obj = $this->db->fetch_object($resql)) {
10823 $key = $langs->trans($obj->code);
10824 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10825 }
10826 $out .= '</select>';
10827
10828 $out .= ajax_combobox('select_'.$htmlname);
10829 } else {
10830 dol_print_error($this->db);
10831 }
10832
10833 return $out;
10834 }
10835
10854 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)
10855 {
10856 global $user, $conf, $langs;
10857
10858 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10859
10860 if (is_null($usertofilter)) {
10861 $usertofilter = $user;
10862 }
10863
10864 $out = '';
10865
10866 $hideunselectables = false;
10867 if (getDolGlobalString('PROJECT_HIDE_UNSELECTABLES')) {
10868 $hideunselectables = true;
10869 }
10870
10871 if (empty($projectsListId)) {
10872 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
10873 $projectstatic = new Project($this->db);
10874 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10875 }
10876 }
10877
10878 // Search all projects
10879 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10880 p.title, p.fk_soc, p.fk_statut, p.public,";
10881 $sql .= ' s.nom as name';
10882 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
10883 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
10884 $sql .= ' ' . $this->db->prefix() . 'facture as f';
10885 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
10886 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
10887 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
10888 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
10889 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
10890 $sql .= " ORDER BY p.ref, f.ref ASC";
10891
10892 $resql = $this->db->query($sql);
10893 if ($resql) {
10894 // Use select2 selector
10895 if (!empty($conf->use_javascript_ajax)) {
10896 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10897 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
10898 $out .= $comboenhancement;
10899 $morecss = 'minwidth200imp maxwidth500';
10900 }
10901
10902 if (empty($option_only)) {
10903 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10904 }
10905 if (!empty($show_empty)) {
10906 $out .= '<option value="0" class="optiongrey">';
10907 if (!is_numeric($show_empty)) {
10908 $out .= $show_empty;
10909 } else {
10910 $out .= '&nbsp;';
10911 }
10912 $out .= '</option>';
10913 }
10914 $num = $this->db->num_rows($resql);
10915 $i = 0;
10916 if ($num) {
10917 while ($i < $num) {
10918 $obj = $this->db->fetch_object($resql);
10919 // 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.
10920 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
10921 // Do nothing
10922 } else {
10923 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
10924 $i++;
10925 continue;
10926 }
10927
10928 $labeltoshow = '';
10929
10930 if ($showproject == 'all') {
10931 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
10932 if ($obj->name) {
10933 $labeltoshow .= ' - ' . $obj->name; // Soc name
10934 }
10935
10936 $disabled = 0;
10937 if ($obj->fk_statut == Project::STATUS_DRAFT) {
10938 $disabled = 1;
10939 $labeltoshow .= ' - ' . $langs->trans("Draft");
10940 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
10941 if ($discard_closed == 2) {
10942 $disabled = 1;
10943 }
10944 $labeltoshow .= ' - ' . $langs->trans("Closed");
10945 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
10946 $disabled = 1;
10947 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
10948 }
10949 }
10950
10951 if (!empty($selected) && $selected == $obj->rowid) {
10952 $out .= '<option value="' . $obj->rowid . '" selected';
10953 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10954 $out .= '>' . $labeltoshow . '</option>';
10955 } else {
10956 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
10957 $resultat = '';
10958 } else {
10959 $resultat = '<option value="' . $obj->rowid . '"';
10960 if ($disabled) {
10961 $resultat .= ' disabled';
10962 }
10963 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
10964 //else $labeltoshow.=' ('.$langs->trans("Private").')';
10965 $resultat .= '>';
10966 $resultat .= $labeltoshow;
10967 $resultat .= '</option>';
10968 }
10969 $out .= $resultat;
10970 }
10971 }
10972 $i++;
10973 }
10974 }
10975 if (empty($option_only)) {
10976 $out .= '</select>';
10977 }
10978
10979 $this->db->free($resql);
10980
10981 return $out;
10982 } else {
10983 dol_print_error($this->db);
10984 return '';
10985 }
10986 }
10987
11001 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11002 {
11003 global $conf, $langs;
11004
11005 $out = '';
11006
11007 dol_syslog('FactureRec::fetch', LOG_DEBUG);
11008
11009 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
11010 //$sql.= ', el.fk_source';
11011 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
11012 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
11013 $sql .= " ORDER BY f.titre ASC";
11014
11015 $resql = $this->db->query($sql);
11016 if ($resql) {
11017 // Use select2 selector
11018 if (!empty($conf->use_javascript_ajax)) {
11019 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11020 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11021 $out .= $comboenhancement;
11022 $morecss = 'minwidth200imp maxwidth500';
11023 }
11024
11025 if (empty($option_only)) {
11026 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11027 }
11028 if (!empty($show_empty)) {
11029 $out .= '<option value="0" class="optiongrey">';
11030 if (!is_numeric($show_empty)) {
11031 $out .= $show_empty;
11032 } else {
11033 $out .= '&nbsp;';
11034 }
11035 $out .= '</option>';
11036 }
11037 $num = $this->db->num_rows($resql);
11038 if ($num) {
11039 while ($obj = $this->db->fetch_object($resql)) {
11040 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
11041
11042 $disabled = 0;
11043 if (!empty($obj->suspended)) {
11044 $disabled = 1;
11045 $labeltoshow .= ' - ' . $langs->trans("Closed");
11046 }
11047
11048
11049 if (!empty($selected) && $selected == $obj->rowid) {
11050 $out .= '<option value="' . $obj->rowid . '" selected';
11051 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11052 $out .= '>' . $labeltoshow . '</option>';
11053 } else {
11054 if ($disabled && ($selected != $obj->rowid)) {
11055 $resultat = '';
11056 } else {
11057 $resultat = '<option value="' . $obj->rowid . '"';
11058 if ($disabled) {
11059 $resultat .= ' disabled';
11060 }
11061 $resultat .= '>';
11062 $resultat .= $labeltoshow;
11063 $resultat .= '</option>';
11064 }
11065 $out .= $resultat;
11066 }
11067 }
11068 }
11069 if (empty($option_only)) {
11070 $out .= '</select>';
11071 }
11072
11073 print $out;
11074
11075 $this->db->free($resql);
11076 return $num;
11077 } else {
11078 $this->errors[] = $this->db->lasterror;
11079 return -1;
11080 }
11081 }
11082
11093 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '', $arrayoffiltercriterias = array())
11094 {
11095 // TODO: Use $arrayoffiltercriterias param instead of $arrayofcriterias to include linked object fields in search
11096 global $langs, $form;
11097
11098 require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
11099 $formother = new FormOther($this->db);
11100
11101 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
11102 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
11103 }
11104
11105 $ret = '';
11106
11107 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
11108 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
11109 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
11110 $ret .= '</a>';
11111
11112 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
11113
11114 // Show select fields as tags.
11115 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
11116
11117 if ($search_component_params_hidden) {
11118 // Split the criteria on each AND
11119 //var_dump($search_component_params_hidden);
11120
11121 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
11122
11123 // $arrayofandtags is now array( '...' , '...', ...)
11124 // Show each AND part
11125 foreach ($arrayofandtags as $tmpkey => $tmpval) {
11126 $errormessage = '';
11127 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
11128 if ($errormessage) {
11129 $this->error = 'ERROR in parsing search string: '.$errormessage;
11130 }
11131 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
11132 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
11133 $searchtags = removeGlobalParenthesis($searchtags);
11134
11135 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
11136 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
11137 $ret .= dol_escape_htmltag($searchtags);
11138 $ret .= '</span>';
11139 }
11140 }
11141
11142 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
11143
11144 //$ret .= search_component_params
11145 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
11146 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
11147
11148 $show_search_component_params_hidden = 1;
11149 if ($show_search_component_params_hidden) {
11150 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
11151 }
11152 $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%')) -->";
11153 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
11154 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
11155
11156 // TODO : Use $arrayoffiltercriterias instead of $arrayofcriterias
11157 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
11158 foreach ($arrayofcriterias as $criteria) {
11159 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
11160 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
11161 continue;
11162 }
11163 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
11164 continue;
11165 }
11166 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
11167 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
11168 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
11169 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
11170 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
11171 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
11172 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
11173 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
11174 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
11175 } else {
11176 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
11177 }
11178 }
11179 }
11180
11181 $ret .= '</div>';
11182
11183 $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";
11184 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
11185
11186 $ret .= '</div>';
11187 $ret .= '</div>';
11188
11189 $ret .= '<script>
11190 jQuery(".tagsearchdelete").click(function(e) {
11191 var filterid = $(this).parents().attr("data-ufilterid");
11192 console.log("We click to delete the criteria nb "+filterid);
11193
11194 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
11195 var newparamstring = \'\';
11196 $(\'.tagsearch\').each(function(index, element) {
11197 tmpfilterid = $(this).attr("data-ufilterid");
11198 if (tmpfilterid != filterid) {
11199 // We keep this criteria
11200 if (newparamstring == \'\') {
11201 newparamstring = $(this).attr("data-ufilter");
11202 } else {
11203 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
11204 }
11205 }
11206 });
11207 console.log("newparamstring = "+newparamstring);
11208
11209 jQuery("#search_component_params_hidden").val(newparamstring);
11210
11211 // We repost the form
11212 $(this).closest(\'form\').submit();
11213 });
11214
11215 jQuery("#search_component_params_input").keydown(function(e) {
11216 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
11217 console.log(e.which);
11218 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
11219 /* We click on back when the input field is already empty */
11220 event.preventDefault();
11221 jQuery("#divsearch_component_params .tagsearch").last().remove();
11222 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
11223 var s = "";
11224 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
11225 if (s != "") {
11226 s = s + " AND ";
11227 }
11228 s = s + $(this).attr("data-ufilter");
11229 });
11230 console.log("New value for search_component_params_hidden = "+s);
11231 jQuery("#search_component_params_hidden").val(s);
11232 }
11233 });
11234
11235 </script>
11236 ';
11237
11238 $arrayoffilterfieldslabel = array();
11239 foreach ($arrayoffiltercriterias as $key => $val) {
11240 $arrayoffilterfieldslabel[$key]['label'] = $val['label'];
11241 $arrayoffilterfieldslabel[$key]['data-type'] = $val['type'];
11242 }
11243
11244 // Adding the div for search assistance
11245 $ret .= '<div class="search-component-assistance">';
11246
11247 $ret .= '<table><tbody>';
11248
11249 $ret .= '<p class="assistance-title">' . img_picto('', 'help') . ' ' . $langs->trans('FilterAssistance') . ' </p>';
11250
11251 $ret .= '<p class="assistance-errors error" style="display:none">' . $langs->trans('AllFieldsRequired') . ' </p>';
11252
11253 $ret .= '<tr><td>';
11254 $ret .= $form->selectarray('search_filter_field', $arrayoffilterfieldslabel, '', $langs->trans("Fields"), 0, 0, '', 0, 0, 0, '', 'maxwidth250', 1);
11255 $ret .= '</td>';
11256
11257 $ret .= '<td><span class="separator"></span>';
11258 // Operator selector (will be populated dynamically)
11259 $ret .= '<select class="operator-selector" id="operator-selector"">';
11260 $ret .= '</select>';
11261 $ret .= '<script>$(document).ready(function() {';
11262 $ret .= ' $(".operator-selector").select2({';
11263 $ret .= ' placeholder: "' . $langs->trans('Operator') . '"';
11264 $ret .= ' });';
11265 $ret .= '});</script>';
11266 $ret .= '</td>';
11267
11268 $ret .= '<td><span class="separator"></span>';
11269 // Input field for entering values
11270 $ret .= '<input type="text" class="flat width100 value-input" placeholder="' . $langs->trans('Value') . '">';
11271
11272 // Date selector
11273 $dateOne = '';
11274 $ret .= '<span class="date-one" style="display:none">';
11275 $ret .= $form->selectDate(($dateOne ? $dateOne : -1), 'dateone', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '');
11276 $ret .= '</span>';
11277
11278 $ret .= '<span class="end-separator"></span> </td>';
11279
11280 $ret .= '<td>';
11281 $ret .= '<button class="button buttongen button-save small add-filter-btn" type="button">' . $langs->trans("addToFilter") . '</button>';
11282 $ret .= '</td>';
11283
11284 $ret .= '</tr>';
11285 $ret .= '</tbody></table>';
11286
11287 // End of the assistance div
11288 $ret .= '</div>';
11289
11290 // Script jQuery to show/hide the floating assistance
11291 $ret .= '<script>
11292 $(document).ready(function() {
11293 $("#search_component_params_input").on("click", function() {
11294 const inputPosition = $(this).offset();
11295 const inputHeight = $(this).outerHeight();
11296 $(".search-component-assistance").css({
11297 top: inputPosition.top + inputHeight + 5 + "px",
11298 left: $("#divadvancedsearchfieldcompinput").css("left")
11299 }).slideToggle(200);
11300 });
11301 $(document).on("click", function(e) {
11302 if (!$(e.target).closest("#search_component_params_input, .search-component-assistance, #ui-datepicker-div").length) {
11303 $(".search-component-assistance").hide();
11304 }
11305 });
11306 });
11307 </script>';
11308
11309 $ret .= '<script>
11310 $(document).ready(function() {
11311 $(".search_filter_field").on("change", function() {
11312 const selectedField = $(this).find(":selected");
11313 const fieldType = selectedField.data("type");
11314 const selectedFieldValue = selectedField.val();
11315 const operators = getOperatorsForFieldType(fieldType);
11316 const operatorSelector = $(".operator-selector");
11317
11318 // Clear existing options
11319 operatorSelector.empty();
11320
11321 // Populate operators
11322 Object.entries(operators).forEach(function([operator, label]) {
11323 operatorSelector.append("<option value=\'" + operator + "\'>" + label + "</option>");
11324 });
11325
11326 operatorSelector.trigger("change.select2");
11327
11328 // Clear and hide all input elements initially
11329 $(".value-input, .dateone, .datemonth, .dateyear").val("").hide();
11330 $("#datemonth, #dateyear").val(null).trigger("change.select2");
11331 $("#dateone").datepicker("setDate", null);
11332 $(".date-one, .date-month, .date-year").hide();
11333
11334 if (fieldType === "date" || fieldType === "datetime" || fieldType === "timestamp") {
11335 $(".date-one").show();
11336 } else {
11337 $(".value-input").show();
11338 }
11339 });
11340
11341 $(".add-filter-btn").on("click", function(event) {
11342 event.preventDefault();
11343
11344 const field = $(".search_filter_field").val();
11345 const operator = $(".operator-selector").val();
11346 let value = $(".value-input").val();
11347 const fieldType = $(".search_filter_field").find(":selected").data("type");
11348
11349 if (["date", "datetime", "timestamp"].includes(fieldType)) {
11350 const parsedDate = new Date($("#dateone").val());
11351 if (!isNaN(parsedDate)) {
11352 const year = parsedDate.getFullYear();
11353 const month = String(parsedDate.getMonth() + 1).padStart(2, "0");
11354 const day = String(parsedDate.getDate()).padStart(2, "0");
11355 value = `${year}-${month}-${day}`;
11356 }
11357 }
11358 const filterString = generateFilterString(field, operator, value, fieldType);
11359
11360 // Submit the form
11361 if (filterString !== "" && field !== "" && operator !== "" && value !== "") {
11362 $("#search_component_params_input").val($("#search_component_params_input").val() + " " + filterString);
11363 $("#search_component_params_input").closest("form").submit();
11364 } else {
11365 $(".assistance-errors").show();
11366 }
11367 });
11368 });
11369 </script>';
11370
11371 return $ret;
11372 }
11373
11384 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0, $selected = '')
11385 {
11386 global $langs, $user;
11387
11388 $retstring = '';
11389
11390 $TModels = array();
11391
11392 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
11393 $formmail = new FormMail($this->db);
11394 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
11395
11396 if ($default) {
11397 $TModels[0] = $langs->trans('DefaultMailModel');
11398 }
11399 if ($result > 0) {
11400 foreach ($formmail->lines_model as $model) {
11401 $TModels[$model->id] = $model->label;
11402 }
11403 }
11404
11405 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
11406
11407 foreach ($TModels as $id_model => $label_model) {
11408 $retstring .= '<option value="' . $id_model . '"';
11409 if (!empty($selected) && $selected == $id_model) {
11410 $retstring .= "selected";
11411 }
11412 $retstring .= ">" . $label_model . "</option>";
11413 }
11414
11415 $retstring .= "</select>";
11416
11417 if ($addjscombo) {
11418 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
11419 }
11420
11421 return $retstring;
11422 }
11423
11435 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
11436 {
11437 global $langs;
11438
11439 $buttons = array();
11440
11441 $save = array(
11442 'name' => 'save',
11443 'label_key' => $save_label,
11444 );
11445
11446 if ($save_label == 'Create' || $save_label == 'Add') {
11447 $save['name'] = 'add';
11448 } elseif ($save_label == 'Modify') {
11449 $save['name'] = 'edit';
11450 }
11451
11452 $cancel = array(
11453 'name' => 'cancel',
11454 'label_key' => 'Cancel',
11455 );
11456
11457 !empty($save_label) ? $buttons[] = $save : '';
11458
11459 if (!empty($morebuttons)) {
11460 $buttons[] = $morebuttons;
11461 }
11462
11463 !empty($cancel_label) ? $buttons[] = $cancel : '';
11464
11465 $retstring = $withoutdiv ? '' : '<div class="center">';
11466
11467 foreach ($buttons as $button) {
11468 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
11469 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
11470 }
11471 $retstring .= $withoutdiv ? '' : '</div>';
11472
11473 if ($dol_openinpopup) {
11474 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
11475 $retstring .= '<script nonce="' . getNonce() . '">';
11476 $retstring .= 'jQuery(".button-cancel").click(function(e) {
11477 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
11478 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
11479 });';
11480 $retstring .= '</script>';
11481 }
11482
11483 return $retstring;
11484 }
11485
11486
11487 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11488
11495 {
11496 // phpcs:enable
11497 global $langs;
11498
11499 $num = count($this->cache_invoice_subtype);
11500 if ($num > 0) {
11501 return 0; // Cache already loaded
11502 }
11503
11504 dol_syslog(__METHOD__, LOG_DEBUG);
11505
11506 $sql = "SELECT rowid, code, label as label";
11507 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
11508 $sql .= " WHERE active = 1";
11509
11510 $resql = $this->db->query($sql);
11511 if ($resql) {
11512 $num = $this->db->num_rows($resql);
11513 $i = 0;
11514 while ($i < $num) {
11515 $obj = $this->db->fetch_object($resql);
11516
11517 // If translation exists, we use it, otherwise we take the default wording
11518 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
11519 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
11520 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
11521 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
11522 $i++;
11523 }
11524
11525 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
11526
11527 return $num;
11528 } else {
11529 dol_print_error($this->db);
11530 return -1;
11531 }
11532 }
11533
11534
11545 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
11546 {
11547 global $langs, $user;
11548
11549 $out = '';
11550 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
11551
11553
11554 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
11555 if ($addempty) {
11556 $out .= '<option value="0">&nbsp;</option>';
11557 }
11558
11559 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
11560 $label = $subtype['label'];
11561 $out .= '<option value="' . $subtype['rowid'] . '"';
11562 if ($selected == $subtype['rowid']) {
11563 $out .= ' selected="selected"';
11564 }
11565 $out .= '>';
11566 $out .= $label;
11567 $out .= '</option>';
11568 }
11569
11570 $out .= '</select>';
11571 if ($user->admin && empty($noinfoadmin)) {
11572 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11573 }
11574 $out .= ajax_combobox($htmlname);
11575
11576 return $out;
11577 }
11578}
$id
Definition account.php:39
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
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:457
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:306
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:560
$object ref
Definition info.php:79
Class to manage bank accounts.
Class to manage categories.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
DAO Resource object.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array(), $nooutput=0)
Show block with links "to link to" other objects.
showFilterButtons($pos='')
Return HTML to show the search and clear search button.
load_cache_vatrates($country_code)
Load into the cache ->cache_vatrates, all the vat rates of a country.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=array(), $title='RelatedObjects')
Show linked object block.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
select_dolresources_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofresourceid=array())
Return select list of resources.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party This call select_thirdparty_list() or ajax depending on setu...
select_produits($selected=0, $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1, $warehouseId=0)
Return list of products for customer.
select_dolgroups($selected=0, $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly=array(), $force_entity='0', $multiple=false, $morecss='minwidth200')
Return select list of groups.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array())
Return select list of users.
select_contact($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $nokeyifsocid=true, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $selected_input_value='', $filter='')
Output html form to select a contact This call select_contacts() or ajax depending on setup.
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='', $openinghours='', $stepminutes=1, $labeladddateof='', $placeholder='', $gm='auto')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
getSelectInvoiceSubtype($selected=0, $htmlname='subtypeid', $addempty=0, $noinfoadmin=0, $morecss='')
Return list of invoice subtypes.
select_produits_list($selected=0, $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='maxwidth500', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1, $warehouseId=0)
Return list of products for a customer.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse=null, $societe_acheteuse=null, $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0, $type_vat=0)
Output an HTML select vat rate.
form_multicurrency_rate($page, $rate=0.0, $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
load_cache_availability()
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
selectcontacts($socid, $selected=array(), $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=0, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0, $filter='')
Return HTML code of the SELECT of list of all contacts (for a third party or all).
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
selectMembersList($selected='', $htmlname='adherentid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of adherents.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
selectTicketsList($selected='', $htmlname='ticketid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of tickets.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=false, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
selectProjectsList($selected='', $htmlname='projectid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of projects.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0, $selected='')
selectModelMail
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1, $noprint=0)
print list of payment modes.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
form_confirm($page, $title, $question, $action, $formquestion=array(), $selectedchoice="", $useajax=0, $height=170, $width=500)
load_cache_conditions_paiements()
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier=0)
Return list of suppliers prices for a product.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='width75', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0)
Return combo list of activated countries, into language of user.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="")
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
formIban(string $selected='', string $htmlname='ribList', int $addempty=0, string $type='', int $nooutput=0, $ribForSelection=[])
Show form with IBAN.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly=array(), $force_entity='0')
Return the HTML select list of users.
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
static selectArrayFilter($htmlname, $array, $id='', $moreparam='', $disableFiltering=0, $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0, $textfortitle='')
Return a HTML select string, built from an array of key+value, but content returned into select is de...
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday=0, $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
load_cache_invoice_subtype()
Load into cache list of invoice subtypes.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $elemtype='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
textwithpicto($text, $htmltext, $direction=1, $type='help', $extracss='valignmiddle', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
load_cache_types_paiements()
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Return the list of type of delay available.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
selectTypesIban($selected='', $htmlname='ribList', $empty=0, $morecss='', $nooutput=0, $ribForSelection=[])
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='', $arrayoffiltercriterias=array())
Output the component to make advanced search criteries.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class permettant la generation de composants html autre Only common components are here.
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage hooks.
Class for MyObject.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:162
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
currency_name($code_iso, $withcode=0, $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0, $allowscript=0, $allowstyle=0)
Clean a string to keep only desirable HTML tags.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0, $morecss='paddingrightonly')
Show EMail link formatted for HTML output.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
a disabled
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition main.inc.php:123
measuringUnitString($unit, $measuring_style='', $scale='', $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:137
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:140
getMaxFileSizeArray()
Return the max allowed for file upload.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.