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 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 3 of the License, or
31 * (at your option) any later version.
32 *
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program. If not, see <https://www.gnu.org/licenses/>.
40 */
41
55class Form
56{
60 public $db;
61
65 public $error = '';
66
70 public $errors = array();
71
72 // Some properties used to return data by some methods
74 public $result;
76 public $num;
77
78 // Cache arrays
79 public $cache_types_paiements = array();
80 public $cache_conditions_paiements = array();
81 public $cache_transport_mode = array();
82 public $cache_availability = array();
83 public $cache_demand_reason = array();
84 public $cache_types_fees = array();
85 public $cache_vatrates = array();
86 public $cache_invoice_subtype = array();
87
88
94 public function __construct($db)
95 {
96 $this->db = $db;
97 }
98
115 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
116 {
117 global $langs;
118
119 $ret = '';
120
121 // TODO change for compatibility
122 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
123 if (!empty($perm)) {
124 $tmp = explode(':', $typeofdata);
125 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
126 if ($fieldrequired) {
127 $ret .= '<span class="fieldrequired">';
128 }
129 if ($help) {
130 $ret .= $this->textwithpicto($langs->trans($text), $help);
131 } else {
132 $ret .= $langs->trans($text);
133 }
134 if ($fieldrequired) {
135 $ret .= '</span>';
136 }
137 $ret .= '</div>' . "\n";
138 } else {
139 if ($fieldrequired) {
140 $ret .= '<span class="fieldrequired">';
141 }
142 if ($help) {
143 $ret .= $this->textwithpicto($langs->trans($text), $help);
144 } else {
145 $ret .= $langs->trans($text);
146 }
147 if ($fieldrequired) {
148 $ret .= '</span>';
149 }
150 }
151 } else {
152 if (empty($notabletag) && $perm) {
153 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
154 }
155 if ($fieldrequired) {
156 $ret .= '<span class="fieldrequired">';
157 }
158 if ($help) {
159 $ret .= $this->textwithpicto($langs->trans($text), $help);
160 } else {
161 $ret .= $langs->trans($text);
162 }
163 if ($fieldrequired) {
164 $ret .= '</span>';
165 }
166 if (!empty($notabletag)) {
167 $ret .= ' ';
168 }
169 if (empty($notabletag) && $perm) {
170 $ret .= '</td>';
171 }
172 if (empty($notabletag) && $perm) {
173 $ret .= '<td class="right">';
174 }
175 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
176 $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>';
177 }
178 if (!empty($notabletag) && $notabletag == 1) {
179 if ($text) {
180 $ret .= ' : ';
181 } else {
182 $ret .= ' ';
183 }
184 }
185 if (!empty($notabletag) && $notabletag == 3) {
186 $ret .= ' ';
187 }
188 if (empty($notabletag) && $perm) {
189 $ret .= '</td>';
190 }
191 if (empty($notabletag) && $perm) {
192 $ret .= '</tr></table>';
193 }
194 }
195
196 return $ret;
197 }
198
222 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 = '')
223 {
224 global $conf, $langs;
225
226 $ret = '';
227
228 // Check parameters
229 if (empty($typeofdata)) {
230 return 'ErrorBadParameter typeofdata is empty';
231 }
232 // Clean parameter $typeofdata
233 if ($typeofdata == 'datetime') {
234 $typeofdata = 'dayhour';
235 }
236 $reg = array();
237 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
238 if ($reg[1] == 'varchar') {
239 $typeofdata = 'string';
240 } elseif ($reg[1] == 'int') {
241 $typeofdata = 'numeric';
242 } else {
243 return 'ErrorBadParameter ' . $typeofdata;
244 }
245 }
246
247 // When option to edit inline is activated
248 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
249 $ret .= $this->editInPlace($object, $value, $htmlname, ($perm ? 1 : 0), $typeofdata, $editvalue, $extObject, $custommsg);
250 } else {
251 if ($editaction == '') {
252 $editaction = GETPOST('action', 'aZ09');
253 }
254 $editmode = ($editaction == 'edit' . $htmlname);
255 if ($editmode) { // edit mode
256 $ret .= "\n";
257 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
258 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
259 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
260 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
261 if (empty($notabletag)) {
262 $ret .= '<table class="nobordernopadding centpercent">';
263 }
264 if (empty($notabletag)) {
265 $ret .= '<tr><td>';
266 }
267 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
268 $tmp = explode(':', $typeofdata);
269 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
270 } elseif (preg_match('/^(integer)/', $typeofdata)) {
271 $tmp = explode(':', $typeofdata);
272 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
273 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
274 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
275 $tmp = explode(':', $typeofdata);
276 $valuetoshow = price2num($editvalue ? $editvalue : $value);
277 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
278 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
279 $tmp = explode(':', $typeofdata);
280 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
281 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
282 $tmp = explode(':', $typeofdata);
283 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
284 $morealt = '';
285 if (preg_match('/%/', $cols)) {
286 $morealt = ' style="width: ' . $cols . '"';
287 $cols = '';
288 }
289 $valuetoshow = ($editvalue ? $editvalue : $value);
290 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
291 // textarea convert automatically entities chars into simple chars.
292 // 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.
293 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
294 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
295 $ret .= '</textarea>';
296 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
297 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
298 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
299 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
300 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
301 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
302 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
303 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
304 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
305 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
306 } elseif (preg_match('/^select;/', $typeofdata)) {
307 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
308 $arraylist = array();
309 foreach ($arraydata as $val) {
310 $tmp = explode(':', $val);
311 $tmpkey = str_replace('|', ':', $tmp[0]);
312 $arraylist[$tmpkey] = $tmp[1];
313 }
314 $ret .= $this->selectarray($htmlname, $arraylist, $value);
315 } elseif (preg_match('/^link/', $typeofdata)) {
316 // TODO Not yet implemented. See code for extrafields
317 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
318 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
319 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
320 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? '100' : $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? 0 : $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? '20' : $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
321 $ret .= $doleditor->Create(1);
322 } elseif ($typeofdata == 'asis') {
323 $ret .= ($editvalue ? $editvalue : $value);
324 }
325 if (empty($notabletag)) {
326 $ret .= '</td>';
327 }
328
329 // Button save-cancel
330 if (empty($notabletag)) {
331 $ret .= '<td>';
332 }
333 //else $ret.='<div class="clearboth"></div>';
334 $ret .= '<input type="submit" class="smallpaddingimp button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
335 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
336 $ret .= '<br>' . "\n";
337 }
338 $ret .= '<input type="submit" class="smallpaddingimp button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
339 if (empty($notabletag)) {
340 $ret .= '</td>';
341 }
342
343 if (empty($notabletag)) {
344 $ret .= '</tr></table>' . "\n";
345 }
346 $ret .= '</form>' . "\n";
347 } else { // view mode
348 if (preg_match('/^email/', $typeofdata)) {
349 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
350 } elseif (preg_match('/^phone/', $typeofdata)) {
351 $ret .= dol_print_phone($value, '_blank', 32, 1);
352 } elseif (preg_match('/^url/', $typeofdata)) {
353 $ret .= dol_print_url($value, '_blank', 32, 1);
354 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
355 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
356 } elseif (preg_match('/^checkbox/', $typeofdata)) {
357 $tmp = explode(':', $typeofdata);
358 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
359 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
361 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
363 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
364 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
365 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
366 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
367 } elseif (preg_match('/^select;/', $typeofdata)) {
368 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
369 $arraylist = array();
370 foreach ($arraydata as $val) {
371 $tmp = explode(':', $val);
372 $arraylist[$tmp[0]] = $tmp[1];
373 }
374 $ret .= $arraylist[$value];
375 if ($htmlname == 'fk_product_type') {
376 if ($value == 0) {
377 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
378 } else {
379 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
380 }
381 }
382 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
383 $tmpcontent = dol_htmlentitiesbr($value);
384 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
385 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
386 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
387 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
388 }
389 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
390 // clean data from some dangerous html
392 } else {
393 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
394 $ret .= dol_escape_htmltag($value);
395 } else {
396 $ret .= $value; // $value must be already html escaped.
397 }
398 }
399
400 // Custom format if parameter $formatfunc has been provided
401 if ($formatfunc && method_exists($object, $formatfunc)) {
402 $ret = $object->$formatfunc($ret);
403 }
404 }
405 }
406 return $ret;
407 }
408
420 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
421 {
422 global $conf, $langs, $extralanguages;
423
424 $result = '';
425
426 // List of extra languages
427 $arrayoflangcode = array();
428 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
429 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
430 }
431
432 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
433 if (!is_object($extralanguages)) {
434 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
435 $extralanguages = new ExtraLanguages($this->db);
436 }
437 $extralanguages->fetch_name_extralanguages('societe');
438
439 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
440 return ''; // No extralang field to show
441 }
442
443 $result .= '<!-- Widget for translation -->' . "\n";
444 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
445 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
446 $result .= $s;
447 $result .= '</div>';
448
449 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
450
451 $resultforextrlang = '';
452 foreach ($arrayoflangcode as $langcode) {
453 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
454 if (empty($valuetoshow)) {
455 $object->fetchValuesForExtraLanguages();
456 //var_dump($object->array_languages);
457 $valuetoshow = $object->array_languages[$fieldname][$langcode];
458 }
459
460 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
461 $resultforextrlang .= $s;
462
463 // TODO Use the showInputField() method of ExtraLanguages object
464 if ($typeofdata == 'textarea') {
465 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
466 $resultforextrlang .= $valuetoshow;
467 $resultforextrlang .= '</textarea>';
468 } else {
469 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
470 }
471 }
472 $result .= $resultforextrlang;
473
474 $result .= '</div>';
475 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
476 }
477
478 return $result;
479 }
480
494 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
495 {
496 $out = '';
497
498 // Check parameters
499 if (preg_match('/^text/', $inputType)) {
500 $value = dol_nl2br($value);
501 } elseif (preg_match('/^numeric/', $inputType)) {
502 $value = price($value);
503 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
504 $value = dol_print_date($value, 'day');
505 }
506
507 if ($condition) {
508 $element = false;
509 $table_element = false;
510 $fk_element = false;
511 $loadmethod = false;
512 $savemethod = false;
513 $ext_element = false;
514 $button_only = false;
515 $inputOption = '';
516 $rows = '';
517 $cols = '';
518
519 if (is_object($object)) {
520 $element = $object->element;
521 $table_element = $object->table_element;
522 $fk_element = $object->id;
523 }
524
525 if (is_object($extObject)) {
526 $ext_element = $extObject->element;
527 }
528
529 if (preg_match('/^(string|email|numeric)/', $inputType)) {
530 $tmp = explode(':', $inputType);
531 $inputType = $tmp[0];
532 if (!empty($tmp[1])) {
533 $inputOption = $tmp[1];
534 }
535 if (!empty($tmp[2])) {
536 $savemethod = $tmp[2];
537 }
538 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
539 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
540 $tmp = explode(':', $inputType);
541 $inputType = $tmp[0];
542 if (!empty($tmp[1])) {
543 $inputOption = $tmp[1];
544 }
545 if (!empty($tmp[2])) {
546 $savemethod = $tmp[2];
547 }
548
549 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
550 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
551 $tmp = explode(':', $inputType);
552 $inputType = $tmp[0];
553 $loadmethod = $tmp[1];
554 if (!empty($tmp[2])) {
555 $savemethod = $tmp[2];
556 }
557 if (!empty($tmp[3])) {
558 $button_only = true;
559 }
560 } elseif (preg_match('/^textarea/', $inputType)) {
561 $tmp = explode(':', $inputType);
562 $inputType = $tmp[0];
563 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
564 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
565 } elseif (preg_match('/^ckeditor/', $inputType)) {
566 $tmp = explode(':', $inputType);
567 $inputType = $tmp[0];
568 $toolbar = $tmp[1];
569 if (!empty($tmp[2])) {
570 $width = $tmp[2];
571 }
572 if (!empty($tmp[3])) {
573 $height = $tmp[3];
574 }
575 if (!empty($tmp[4])) {
576 $savemethod = $tmp[4];
577 }
578
579 if (isModEnabled('fckeditor')) {
580 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
581 } else {
582 $inputType = 'textarea';
583 }
584 }
585
586 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
587 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
588 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
589 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
590 if (!empty($savemethod)) {
591 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
592 }
593 if (!empty($ext_element)) {
594 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
595 }
596 if (!empty($custommsg)) {
597 if (is_array($custommsg)) {
598 if (!empty($custommsg['success'])) {
599 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
600 }
601 if (!empty($custommsg['error'])) {
602 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
603 }
604 } else {
605 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
606 }
607 }
608 if ($inputType == 'textarea') {
609 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
610 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
611 }
612 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
613 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
614 } else {
615 $out = $value;
616 }
617
618 return $out;
619 }
620
639 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
640 {
641 if ($incbefore) {
642 $text = $incbefore . $text;
643 }
644 if (!$htmltext) {
645 return $text;
646 }
647 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
648
649 $tag = 'td';
650 if ($notabs == 2) {
651 $tag = 'div';
652 }
653 if ($notabs == 3) {
654 $tag = 'span';
655 }
656 // Sanitize tooltip
657 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
658
659 $extrastyle = '';
660 if ($direction < 0) {
661 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
662 $extrastyle = 'padding: 0px; padding-left: 2px;';
663 }
664 if ($direction > 0) {
665 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
666 $extrastyle = 'padding: 0px; padding-right: 2px;';
667 }
668
669 $classfortooltip = 'classfortooltip';
670
671 $s = '';
672 $textfordialog = '';
673
674 if ($tooltiptrigger == '') {
675 $htmltext = str_replace('"', '&quot;', $htmltext);
676 } else {
677 $classfortooltip = 'classfortooltiponclick';
678 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
679 }
680 if ($tooltipon == 2 || $tooltipon == 3) {
681 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
682 if ($tooltiptrigger == '') {
683 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
684 } else {
685 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
686 }
687 } else {
688 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
689 }
690 if ($tooltipon == 1 || $tooltipon == 3) {
691 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
692 if ($tooltiptrigger == '') {
693 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
694 } else {
695 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
696 }
697 } else {
698 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
699 }
700 if (empty($notabs)) {
701 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
702 } elseif ($notabs == 2) {
703 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
704 }
705 // Define value if value is before
706 if ($direction < 0) {
707 $s .= '<' . $tag . $paramfortooltipimg;
708 if ($tag == 'td') {
709 $s .= ' class="valigntop" width="14"';
710 }
711 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
712 }
713 // Use another method to help avoid having a space in value in order to use this value with jquery
714 // Define label
715 if ((string) $text != '') {
716 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
717 }
718 // Define value if value is after
719 if ($direction > 0) {
720 $s .= '<' . $tag . $paramfortooltipimg;
721 if ($tag == 'td') {
722 $s .= ' class="valignmiddle" width="14"';
723 }
724 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
725 }
726 if (empty($notabs)) {
727 $s .= '</tr></table>';
728 } elseif ($notabs == 2) {
729 $s .= '</div>';
730 }
731
732 return $s;
733 }
734
749 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
750 {
751 global $conf, $langs;
752
753 //For backwards compatibility
754 if ($type == '0') {
755 $type = 'info';
756 } elseif ($type == '1') {
757 $type = 'help';
758 }
759 // Clean parameters
760 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
761
762 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
763 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
764 }
765 $alt = '';
766 if ($tooltiptrigger) {
767 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
768 }
769
770 // If info or help with no javascript, show only text
771 if (empty($conf->use_javascript_ajax)) {
772 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
773 return $text;
774 } else {
775 $alt = $htmltext;
776 $htmltext = '';
777 }
778 }
779
780 // If info or help with smartphone, show only text (tooltip hover can't works)
781 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
782 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
783 return $text;
784 }
785 }
786 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
787 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
788 //{
789 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
790 //}
791
792 $img = '';
793 if ($type == 'info') {
794 $img = img_help(0, $alt);
795 } elseif ($type == 'help') {
796 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
797 } elseif ($type == 'helpclickable') {
798 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
799 } elseif ($type == 'superadmin') {
800 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
801 $img = img_picto($alt, 'redstar');
802 } elseif ($type == 'admin') {
803 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
804 $img = img_picto($alt, 'star');
805 } elseif ($type == 'warning') {
806 $img = img_warning($alt);
807 } elseif ($type != 'none') {
808 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
809 $img = img_picto($alt, $type); // $type can be an image path
810 }
811
812 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
813 }
814
825 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
826 {
827 global $conf, $langs, $hookmanager;
828
829 $disabled = 0;
830 $ret = '<div class="centpercent center">';
831 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
832
833 // 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.
834 $parameters = array();
835 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
836 // check if there is a mass action
837
838 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
839 return;
840 }
841 if (empty($reshook)) {
842 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
843 if (is_array($arrayofaction)) {
844 foreach ($arrayofaction as $code => $label) {
845 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
846 }
847 }
848 }
849 $ret .= $hookmanager->resPrint;
850
851 $ret .= '</select>';
852
853 if (empty($conf->dol_optimize_smallscreen)) {
854 $ret .= ajax_combobox('.' . $name . 'select');
855 }
856
857 // 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
858 $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.
859 $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")) . '">';
860 $ret .= '</div>';
861
862 if (!empty($conf->use_javascript_ajax)) {
863 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
864 <script nonce="' . getNonce() . '">
865 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 */
866 {
867 atleastoneselected=0;
868 jQuery("."+cssclass).each(function( index ) {
869 /* console.log( index + ": " + $( this ).text() ); */
870 if ($(this).is(\':checked\')) atleastoneselected++;
871 });
872
873 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
874
875 if (atleastoneselected || ' . $alwaysvisible . ')
876 {
877 jQuery("."+name).show();
878 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
879 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
880 }
881 else
882 {
883 jQuery("."+name).hide();
884 jQuery("."+name+"other").hide();
885 }
886 }
887
888 jQuery(document).ready(function () {
889 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
890 jQuery(".' . $cssclass . '").click(function() {
891 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
892 });
893 jQuery(".' . $name . 'select").change(function() {
894 var massaction = $( this ).val();
895 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
896 if (massaction == "builddoc")
897 {
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 {
905 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
906 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
907 jQuery(".' . $name . '"+massaction).show();
908 }
909 else
910 {
911 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
912 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
913 }
914 });
915 });
916 </script>
917 ';
918 }
919
920 return $ret;
921 }
922
923 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
924
941 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)
942 {
943 // phpcs:enable
944 global $conf, $langs, $mysoc;
945
946 $langs->load("dict");
947
948 $out = '';
949 $countryArray = array();
950 $favorite = array();
951 $label = array();
952 $atleastonefavorite = 0;
953
954 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
955 $sql .= " FROM " . $this->db->prefix() . "c_country";
956 $sql .= " WHERE active > 0";
957 //$sql.= " ORDER BY code ASC";
958
959 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
960 $resql = $this->db->query($sql);
961 if ($resql) {
962 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
963 $num = $this->db->num_rows($resql);
964 $i = 0;
965 if ($num) {
966 while ($i < $num) {
967 $obj = $this->db->fetch_object($resql);
968
969 $countryArray[$i]['rowid'] = $obj->rowid;
970 $countryArray[$i]['code_iso'] = $obj->code_iso;
971 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
972 $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 : ''));
973 $countryArray[$i]['favorite'] = $obj->favorite;
974 $countryArray[$i]['eec'] = $obj->eec;
975 $favorite[$i] = $obj->favorite;
976 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
977 $i++;
978 }
979
980 if (empty($disablefavorites)) {
981 $array1_sort_order = SORT_DESC;
982 $array2_sort_order = SORT_ASC;
983 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
984 } else {
985 $countryArray = dol_sort_array($countryArray, 'label');
986 }
987
988 if ($showempty) {
989 if (is_numeric($showempty)) {
990 $out .= '<option value="">&nbsp;</option>' . "\n";
991 } else {
992 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
993 }
994 }
995
996 if ($addspecialentries) { // Add dedicated entries for groups of countries
997 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
998 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
999 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
1000 if ($mysoc->isInEEC()) {
1001 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1002 }
1003 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1004 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1005 }
1006
1007 foreach ($countryArray as $row) {
1008 //if (empty($showempty) && empty($row['rowid'])) continue;
1009 if (empty($row['rowid'])) {
1010 continue;
1011 }
1012 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1013 continue; // exclude some countries
1014 }
1015
1016 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1017 $atleastonefavorite++;
1018 }
1019 if (empty($row['favorite']) && $atleastonefavorite) {
1020 $atleastonefavorite = 0;
1021 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1022 }
1023
1024 $labeltoshow = '';
1025 if ($row['label']) {
1026 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1027 } else {
1028 $labeltoshow .= '&nbsp;';
1029 }
1030 if ($row['code_iso']) {
1031 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1032 if (empty($hideflags)) {
1033 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1034 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1035 }
1036 }
1037
1038 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1039 $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']) . '">';
1040 } else {
1041 $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']) . '">';
1042 }
1043 $out .= $labeltoshow;
1044 $out .= '</option>' . "\n";
1045 }
1046 }
1047 $out .= '</select>';
1048 } else {
1049 dol_print_error($this->db);
1050 }
1051
1052 // Make select dynamic
1053 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1054 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1055
1056 return $out;
1057 }
1058
1059 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1060
1074 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1075 {
1076 // phpcs:enable
1077 global $conf, $langs;
1078
1079 $langs->load("dict");
1080
1081 $out = '';
1082 $moreattrib = '';
1083 $incotermArray = array();
1084
1085 $sql = "SELECT rowid, code";
1086 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1087 $sql .= " WHERE active > 0";
1088 $sql .= " ORDER BY code ASC";
1089
1090 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1091 $resql = $this->db->query($sql);
1092 if ($resql) {
1093 if ($conf->use_javascript_ajax && !$forcecombo) {
1094 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1095 $out .= ajax_combobox($htmlname, $events);
1096 }
1097
1098 if (!empty($page)) {
1099 $out .= '<form method="post" action="' . $page . '">';
1100 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1101 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1102 }
1103
1104 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1105 $out .= '<option value="0">&nbsp;</option>';
1106 $num = $this->db->num_rows($resql);
1107 $i = 0;
1108 if ($num) {
1109 while ($i < $num) {
1110 $obj = $this->db->fetch_object($resql);
1111 $incotermArray[$i]['rowid'] = $obj->rowid;
1112 $incotermArray[$i]['code'] = $obj->code;
1113 $i++;
1114 }
1115
1116 foreach ($incotermArray as $row) {
1117 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1118 $out .= '<option value="' . $row['rowid'] . '" selected>';
1119 } else {
1120 $out .= '<option value="' . $row['rowid'] . '">';
1121 }
1122
1123 if ($row['code']) {
1124 $out .= $row['code'];
1125 }
1126
1127 $out .= '</option>';
1128 }
1129 }
1130 $out .= '</select>';
1131
1132 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1133 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1134 $moreattrib .= ' autocomplete="off"';
1135 }
1136 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1137
1138 if (!empty($page)) {
1139 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1140 }
1141 } else {
1142 dol_print_error($this->db);
1143 }
1144
1145 return $out;
1146 }
1147
1148 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1149
1162 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "")
1163 {
1164 // phpcs:enable
1165 global $langs;
1166
1167 // If product & services are enabled or both disabled.
1168 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1169 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1170 if (empty($hidetext)) {
1171 print $langs->trans("Type") . ': ';
1172 }
1173 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1174 if ($showempty) {
1175 print '<option value="-1"';
1176 if ($selected == -1) {
1177 print ' selected';
1178 }
1179 print '>';
1180 if (is_numeric($showempty)) {
1181 print '&nbsp;';
1182 } else {
1183 print $showempty;
1184 }
1185 print '</option>';
1186 }
1187
1188 print '<option value="0"';
1189 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1190 print ' selected';
1191 }
1192 print '>' . $langs->trans("Product");
1193
1194 print '<option value="1"';
1195 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1196 print ' selected';
1197 }
1198 print '>' . $langs->trans("Service");
1199
1200 print '</select>';
1201 print ajax_combobox('select_' . $htmlname);
1202 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1203 }
1204 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1205 print $langs->trans("Service");
1206 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1207 }
1208 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1209 print $langs->trans("Product");
1210 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1211 }
1212 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1213 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
1214 }
1215 }
1216
1217 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1218
1224 public function load_cache_types_fees()
1225 {
1226 // phpcs:enable
1227 global $langs;
1228
1229 $num = count($this->cache_types_fees);
1230 if ($num > 0) {
1231 return 0; // Cache already loaded
1232 }
1233
1234 dol_syslog(__METHOD__, LOG_DEBUG);
1235
1236 $langs->load("trips");
1237
1238 $sql = "SELECT c.code, c.label";
1239 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1240 $sql .= " WHERE active > 0";
1241
1242 $resql = $this->db->query($sql);
1243 if ($resql) {
1244 $num = $this->db->num_rows($resql);
1245 $i = 0;
1246
1247 while ($i < $num) {
1248 $obj = $this->db->fetch_object($resql);
1249
1250 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1251 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1252 $this->cache_types_fees[$obj->code] = $label;
1253 $i++;
1254 }
1255
1256 asort($this->cache_types_fees);
1257
1258 return $num;
1259 } else {
1260 dol_print_error($this->db);
1261 return -1;
1262 }
1263 }
1264
1265 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1266
1275 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1276 {
1277 // phpcs:enable
1278 global $user, $langs;
1279
1280 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1281
1282 $this->load_cache_types_fees();
1283
1284 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1285 if ($showempty) {
1286 print '<option value="-1"';
1287 if ($selected == -1) {
1288 print ' selected';
1289 }
1290 print '>&nbsp;</option>';
1291 }
1292
1293 foreach ($this->cache_types_fees as $key => $value) {
1294 print '<option value="' . $key . '"';
1295 if ($key == $selected) {
1296 print ' selected';
1297 }
1298 print '>';
1299 print $value;
1300 print '</option>';
1301 }
1302
1303 print '</select>';
1304 if ($user->admin) {
1305 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1306 }
1307 }
1308
1309
1310 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1311
1334 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)
1335 {
1336 // phpcs:enable
1337 global $conf, $langs;
1338
1339 $out = '';
1340
1341 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1342 if (is_null($ajaxoptions)) {
1343 $ajaxoptions = array();
1344 }
1345
1346 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1347
1348 // No immediate load of all database
1349 $placeholder = '';
1350 if ($selected && empty($selected_input_value)) {
1351 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1352 $societetmp = new Societe($this->db);
1353 $societetmp->fetch($selected);
1354 $selected_input_value = $societetmp->name;
1355 unset($societetmp);
1356 }
1357
1358 // mode 1
1359 $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)) : '');
1360
1361 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1362 if (empty($hidelabel)) {
1363 print $langs->trans("RefOrLabel") . ' : ';
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, getDolGlobalString('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, getDolGlobalString('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
1754 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 = '')
1755 {
1756 global $conf, $langs, $hookmanager, $action;
1757
1758 $langs->load('companies');
1759
1760 if (empty($htmlid)) {
1761 $htmlid = $htmlname;
1762 }
1763 $num = 0;
1764 $out = '';
1765 $outarray = array();
1766
1767 if ($selected === '') {
1768 $selected = array();
1769 } elseif (!is_array($selected)) {
1770 $selected = array((int) $selected);
1771 }
1772
1773 // Clean $filter that may contains sql conditions so sql code
1774 if (function_exists('testSqlAndScriptInject')) {
1775 if (testSqlAndScriptInject($filter, 3) > 0) {
1776 $filter = '';
1777 return 'SQLInjectionTryDetected';
1778 }
1779 }
1780
1781 if ($filter != '') { // If a filter was provided
1782 if (preg_match('/[\‍(\‍)]/', $filter)) {
1783 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1784 $errormsg = '';
1785 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1786
1787 // Redo clean $filter that may contains sql conditions so sql code
1788 if (function_exists('testSqlAndScriptInject')) {
1789 if (testSqlAndScriptInject($filter, 3) > 0) {
1790 $filter = '';
1791 return 'SQLInjectionTryDetected';
1792 }
1793 }
1794 } else {
1795 // If not, we do nothing. We already know that there is no parenthesis
1796 // TODO Disallow this case in a future.
1797 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1798 }
1799 }
1800
1801 if (!is_object($hookmanager)) {
1802 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1803 $hookmanager = new HookManager($this->db);
1804 }
1805
1806 // We search third parties
1807 $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";
1808 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1809 $sql .= ", s.nom as company, s.town AS company_town";
1810 }
1811 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1812 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1813 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1814 }
1815 $sql .= " WHERE sp.entity IN (" . getEntity('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 if ($show_every) {
2266 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2267 }
2268
2269 $userstatic = new User($this->db);
2270
2271 while ($i < $num) {
2272 $obj = $this->db->fetch_object($resql);
2273
2274 $userstatic->id = $obj->rowid;
2275 $userstatic->lastname = $obj->lastname;
2276 $userstatic->firstname = $obj->firstname;
2277 $userstatic->photo = $obj->photo;
2278 $userstatic->status = $obj->status;
2279 $userstatic->entity = $obj->entity;
2280 $userstatic->admin = $obj->admin;
2281 $userstatic->gender = $obj->gender;
2282
2283 $disableline = '';
2284 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2285 $disableline = ($enableonlytext ? $enableonlytext : '1');
2286 }
2287
2288 $labeltoshow = '';
2289 $labeltoshowhtml = '';
2290
2291 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2292 $fullNameMode = 0;
2293 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2294 $fullNameMode = 1; //Firstname+lastname
2295 }
2296 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2297 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2298 if (empty($obj->firstname) && empty($obj->lastname)) {
2299 $labeltoshow .= $obj->login;
2300 $labeltoshowhtml .= $obj->login;
2301 }
2302
2303 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2304 $moreinfo = '';
2305 $moreinfohtml = '';
2306 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2307 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2308 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2309 $moreinfo .= $obj->login;
2310 $moreinfohtml .= $obj->login;
2311 }
2312 if ($showstatus >= 0) {
2313 if ($obj->status == 1 && $showstatus == 1) {
2314 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2315 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2316 }
2317 if ($obj->status == 0 && $showstatus == 1) {
2318 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2319 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2320 }
2321 }
2322 if ($showlabelofentity) {
2323 if (empty($obj->entity)) {
2324 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2325 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2326 } else {
2327 if ($obj->entity != $conf->entity) {
2328 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2329 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2330 }
2331 }
2332 }
2333 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2334 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2335 if (!empty($disableline) && $disableline != '1') {
2336 // Add text from $enableonlytext parameter
2337 $moreinfo .= ' - ' . $disableline;
2338 $moreinfohtml .= ' - ' . $disableline;
2339 }
2340 $labeltoshow .= $moreinfo;
2341 $labeltoshowhtml .= $moreinfohtml;
2342
2343 $out .= '<option value="' . $obj->rowid . '"';
2344 if (!empty($disableline)) {
2345 $out .= ' disabled';
2346 }
2347 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2348 $out .= ' selected';
2349 }
2350 $out .= ' data-html="';
2351
2352 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2353 if ($showstatus >= 0 && $obj->status == 0) {
2354 $outhtml .= '<strike class="opacitymediumxxx">';
2355 }
2356 $outhtml .= $labeltoshowhtml;
2357 if ($showstatus >= 0 && $obj->status == 0) {
2358 $outhtml .= '</strike>';
2359 }
2360 $labeltoshowhtml = $outhtml;
2361
2362 $out .= dol_escape_htmltag($outhtml);
2363 $out .= '">';
2364 $out .= $labeltoshow;
2365 $out .= '</option>';
2366
2367 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2368 $outarray2[$userstatic->id] = array(
2369 'id' => $userstatic->id,
2370 'label' => $labeltoshow,
2371 'labelhtml' => $labeltoshowhtml,
2372 'color' => '',
2373 'picto' => ''
2374 );
2375
2376 $i++;
2377 }
2378 } else {
2379 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2380 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2381 }
2382 $out .= '</select>';
2383
2384 if ($num && !$forcecombo) {
2385 // Enhance with select2
2386 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2387 $out .= ajax_combobox($htmlname);
2388 }
2389 } else {
2390 dol_print_error($this->db);
2391 }
2392
2393 $this->num = $num;
2394
2395 if ($outputmode == 2) {
2396 return $outarray2;
2397 } elseif ($outputmode) {
2398 return $outarray;
2399 }
2400
2401 return $out;
2402 }
2403
2404
2405 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2428 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())
2429 {
2430 // phpcs:enable
2431 global $langs;
2432
2433 $userstatic = new User($this->db);
2434 $out = '';
2435
2436 if (!empty($_SESSION['assignedtouser'])) {
2437 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2438 if (!is_array($assignedtouser)) {
2439 $assignedtouser = array();
2440 }
2441 } else {
2442 $assignedtouser = array();
2443 }
2444 $nbassignetouser = count($assignedtouser);
2445
2446 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2447 if ($nbassignetouser) {
2448 $out .= '<ul class="attendees">';
2449 }
2450 $i = 0;
2451 $ownerid = 0;
2452 foreach ($assignedtouser as $key => $value) {
2453 if ($value['id'] == $ownerid) {
2454 continue;
2455 }
2456
2457 $out .= '<li>';
2458 $userstatic->fetch($value['id']);
2459 $out .= $userstatic->getNomUrl(-1);
2460 if ($i == 0) {
2461 $ownerid = $value['id'];
2462 $out .= ' (' . $langs->trans("Owner") . ')';
2463 }
2464 if ($nbassignetouser > 1 && $action != 'view') {
2465 $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 . '">';
2466 }
2467 // Show my availability
2468 if ($showproperties) {
2469 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2470 $out .= '<div class="myavailability inline-block">';
2471 $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>';
2472 $out .= '</div>';
2473 }
2474 }
2475 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2476 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2477
2478 $out .= '</li>';
2479 $i++;
2480 }
2481 if ($nbassignetouser) {
2482 $out .= '</ul>';
2483 }
2484
2485 // Method with no ajax
2486 if ($action != 'view') {
2487 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2488 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2489 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2490 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2491 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2492 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2493 $out .= '});';
2494 $out .= '})</script>';
2495 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2496 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2497 $out .= '<br>';
2498 }
2499
2500 return $out;
2501 }
2502
2503 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2523 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())
2524 {
2525 // phpcs:enable
2526 global $langs;
2527
2528 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2529 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2530 $formresources = new FormResource($this->db);
2531 $resourcestatic = new Dolresource($this->db);
2532
2533 $out = '';
2534 if (!empty($_SESSION['assignedtoresource'])) {
2535 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2536 if (!is_array($assignedtoresource)) {
2537 $assignedtoresource = array();
2538 }
2539 } else {
2540 $assignedtoresource = array();
2541 }
2542 $nbassignetoresource = count($assignedtoresource);
2543
2544 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2545 if ($nbassignetoresource) {
2546 $out .= '<ul class="attendees">';
2547 }
2548 $i = 0;
2549
2550 foreach ($assignedtoresource as $key => $value) {
2551 $out .= '<li>';
2552 $resourcestatic->fetch($value['id']);
2553 $out .= $resourcestatic->getNomUrl(-1);
2554 if ($nbassignetoresource > 1 && $action != 'view') {
2555 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassigned reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2556 }
2557 // Show my availability
2558 if ($showproperties) {
2559 if (is_array($listofresourceid) && count($listofresourceid)) {
2560 $out .= '<div class="myavailability inline-block">';
2561 $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>';
2562 $out .= '</div>';
2563 }
2564 }
2565 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2566 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2567
2568 $out .= '</li>';
2569 $i++;
2570 }
2571 if ($nbassignetoresource) {
2572 $out .= '</ul>';
2573 }
2574
2575 // Method with no ajax
2576 if ($action != 'view') {
2577 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassignedresource" value="">';
2578 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2579 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2580 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2581 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2582 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2583 $out .= '});';
2584 $out .= '})</script>';
2585
2586 $events = array();
2587 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2588 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2589 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2590 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2591 $out .= '<br>';
2592 }
2593
2594 return $out;
2595 }
2596
2597 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2598
2627 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)
2628 {
2629 // phpcs:enable
2630 global $langs, $conf;
2631
2632 $out = '';
2633
2634 // check parameters
2635 $price_level = (!empty($price_level) ? $price_level : 0);
2636 if (is_null($ajaxoptions)) {
2637 $ajaxoptions = array();
2638 }
2639
2640 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2641 if (isModEnabled("product") && !isModEnabled('service')) {
2642 $filtertype = '0';
2643 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2644 $filtertype = '1';
2645 }
2646 }
2647
2648 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2649 $placeholder = '';
2650
2651 if ($selected && empty($selected_input_value)) {
2652 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2653 $producttmpselect = new Product($this->db);
2654 $producttmpselect->fetch($selected);
2655 $selected_input_value = $producttmpselect->ref;
2656 unset($producttmpselect);
2657 }
2658 // handle case where product or service module is disabled + no filter specified
2659 if ($filtertype == '') {
2660 if (!isModEnabled('product')) { // when product module is disabled, show services only
2661 $filtertype = 1;
2662 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2663 $filtertype = 0;
2664 }
2665 }
2666 // mode=1 means customers products
2667 $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;
2668 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2669
2670 if (isModEnabled('variants') && is_array($selected_combinations)) {
2671 // Code to automatically insert with javascript the select of attributes under the select of product
2672 // when a parent of variant has been selected.
2673 $out .= '
2674 <!-- script to auto show attributes select tags if a variant was selected -->
2675 <script nonce="' . getNonce() . '">
2676 // auto show attributes fields
2677 selected = ' . json_encode($selected_combinations) . ';
2678 combvalues = {};
2679
2680 jQuery(document).ready(function () {
2681
2682 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2683 if (jQuery(this).val() == \'free\') {
2684 jQuery(\'div#attributes_box\').empty();
2685 }
2686 });
2687
2688 jQuery("input#' . $htmlname . '").change(function () {
2689
2690 if (!jQuery(this).val()) {
2691 jQuery(\'div#attributes_box\').empty();
2692 return;
2693 }
2694
2695 console.log("A change has started. We get variants fields to inject html select");
2696
2697 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2698 id: jQuery(this).val()
2699 }, function (data) {
2700 jQuery(\'div#attributes_box\').empty();
2701
2702 jQuery.each(data, function (key, val) {
2703
2704 combvalues[val.id] = val.values;
2705
2706 var span = jQuery(document.createElement(\'div\')).css({
2707 \'display\': \'table-row\'
2708 });
2709
2710 span.append(
2711 jQuery(document.createElement(\'div\')).text(val.label).css({
2712 \'font-weight\': \'bold\',
2713 \'display\': \'table-cell\'
2714 })
2715 );
2716
2717 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2718 \'margin-left\': \'15px\',
2719 \'white-space\': \'pre\'
2720 }).append(
2721 jQuery(document.createElement(\'option\')).val(\'\')
2722 );
2723
2724 jQuery.each(combvalues[val.id], function (key, val) {
2725 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2726
2727 if (selected[val.fk_product_attribute] == val.id) {
2728 tag.attr(\'selected\', \'selected\');
2729 }
2730
2731 html.append(tag);
2732 });
2733
2734 span.append(html);
2735 jQuery(\'div#attributes_box\').append(span);
2736 });
2737 })
2738 });
2739
2740 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2741 });
2742 </script>
2743 ';
2744 }
2745
2746 if (empty($hidelabel)) {
2747 $out .= $langs->trans("RefOrLabel") . ' : ';
2748 } elseif ($hidelabel > 1) {
2749 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
2750 if ($hidelabel == 2) {
2751 $out .= img_picto($langs->trans("Search"), 'search');
2752 }
2753 }
2754 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2755 if ($hidelabel == 3) {
2756 $out .= img_picto($langs->trans("Search"), 'search');
2757 }
2758 } else {
2759 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2760 }
2761
2762 if (empty($nooutput)) {
2763 print $out;
2764 } else {
2765 return $out;
2766 }
2767 }
2768
2769 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2770
2786 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2787 {
2788 // phpcs:enable
2789 global $db;
2790
2791 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2792
2793 $error = 0;
2794 $out = '';
2795
2796 if (!$forcecombo) {
2797 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2798 $events = array();
2799 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2800 }
2801
2802 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2803
2804 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2805 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2806 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2807 if (!empty($status)) {
2808 $sql .= ' AND status = ' . (int) $status;
2809 }
2810 if (!empty($type)) {
2811 $sql .= ' AND bomtype = ' . (int) $type;
2812 }
2813 if (!empty($TProducts)) {
2814 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2815 }
2816 if (!empty($limit)) {
2817 $sql .= ' LIMIT ' . (int) $limit;
2818 }
2819 $resql = $db->query($sql);
2820 if ($resql) {
2821 if ($showempty) {
2822 $out .= '<option value="-1"';
2823 if (empty($selected)) {
2824 $out .= ' selected';
2825 }
2826 $out .= '>&nbsp;</option>';
2827 }
2828 while ($obj = $db->fetch_object($resql)) {
2829 $product = new Product($db);
2830 $res = $product->fetch($obj->fk_product);
2831 $out .= '<option value="' . $obj->rowid . '"';
2832 if ($obj->rowid == $selected) {
2833 $out .= 'selected';
2834 }
2835 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2836 }
2837 } else {
2838 $error++;
2839 dol_print_error($db);
2840 }
2841 $out .= '</select>';
2842 if (empty($nooutput)) {
2843 print $out;
2844 } else {
2845 return $out;
2846 }
2847 }
2848
2849 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2850
2876 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)
2877 {
2878 // phpcs:enable
2879 global $langs;
2880 global $hookmanager;
2881
2882 $out = '';
2883 $outarray = array();
2884
2885 // Units
2886 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2887 $langs->load('other');
2888 }
2889
2890 $warehouseStatusArray = array();
2891 if (!empty($warehouseStatus)) {
2892 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2893 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2894 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2895 }
2896 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2897 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2898 }
2899 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2900 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2901 }
2902 }
2903
2904 $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";
2905 if (count($warehouseStatusArray)) {
2906 $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
2907 } else {
2908 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2909 }
2910
2911 $sql = "SELECT ";
2912
2913 // Add select from hooks
2914 $parameters = array();
2915 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2916 if (empty($reshook)) {
2917 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2918 } else {
2919 $sql .= $hookmanager->resPrint;
2920 }
2921
2922 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2923 //Product category
2924 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2925 FROM " . $this->db->prefix() . "categorie_product
2926 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2927 LIMIT 1
2928 ) AS categorie_product_id ";
2929 }
2930
2931 //Price by customer
2932 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2933 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2934 $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';
2935 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2936 }
2937 // Units
2938 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2939 $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";
2940 $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';
2941 }
2942
2943 // Multilang : we add translation
2944 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2945 $sql .= ", pl.label as label_translated";
2946 $sql .= ", pl.description as description_translated";
2947 $selectFields .= ", label_translated";
2948 $selectFields .= ", description_translated";
2949 }
2950 // Price by quantity
2951 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2952 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2953 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2954 $sql .= " AND price_level = " . ((int) $price_level);
2955 }
2956 $sql .= " ORDER BY date_price";
2957 $sql .= " DESC LIMIT 1) as price_rowid";
2958 $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
2959 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2960 $sql .= " AND price_level = " . ((int) $price_level);
2961 }
2962 $sql .= " ORDER BY date_price";
2963 $sql .= " DESC LIMIT 1) as price_by_qty";
2964 $selectFields .= ", price_rowid, price_by_qty";
2965 }
2966
2967 $sql .= " FROM ".$this->db->prefix()."product as p";
2968
2969 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
2970 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
2971 }
2972
2973 // Add from (left join) from hooks
2974 $parameters = array();
2975 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
2976 $sql .= $hookmanager->resPrint;
2977
2978 if (count($warehouseStatusArray)) {
2979 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
2980 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
2981 $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.
2982 }
2983
2984 // include search in supplier ref
2985 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
2986 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2987 }
2988
2989 //Price by customer
2990 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2991 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
2992 }
2993 // Units
2994 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2995 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
2996 }
2997 // Multilang : we add translation
2998 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2999 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3000 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3001 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3002 $soc = new Societe($this->db);
3003 $result = $soc->fetch($socid);
3004 if ($result > 0 && !empty($soc->default_lang)) {
3005 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3006 } else {
3007 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3008 }
3009 } else {
3010 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3011 }
3012 }
3013
3014 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3015 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3016 }
3017
3018 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3019
3020 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3021 $sql .= " AND pac.rowid IS NULL";
3022 }
3023
3024 if ($finished == 0) {
3025 $sql .= " AND p.finished = " . ((int) $finished);
3026 } elseif ($finished == 1) {
3027 $sql .= " AND p.finished = ".((int) $finished);
3028 }
3029 if ($status >= 0) {
3030 $sql .= " AND p.tosell = ".((int) $status);
3031 }
3032 if ($status_purchase >= 0) {
3033 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3034 }
3035 // Filter by product type
3036 if (strval($filtertype) != '') {
3037 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3038 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3039 $sql .= " AND p.fk_product_type = 1";
3040 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3041 $sql .= " AND p.fk_product_type = 0";
3042 }
3043 // Add where from hooks
3044 $parameters = array();
3045 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3046 $sql .= $hookmanager->resPrint;
3047 // Add criteria on ref/label
3048 if ($filterkey != '') {
3049 $sql .= ' AND (';
3050 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3051 // For natural search
3052 $search_crit = explode(' ', $filterkey);
3053 $i = 0;
3054 if (count($search_crit) > 1) {
3055 $sql .= "(";
3056 }
3057 foreach ($search_crit as $crit) {
3058 if ($i > 0) {
3059 $sql .= " AND ";
3060 }
3061 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3062 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3063 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3064 }
3065 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
3066 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3067 }
3068 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3069 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3070 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3071 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3072 }
3073 }
3074 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3075 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3076 }
3077 $sql .= ")";
3078 $i++;
3079 }
3080 if (count($search_crit) > 1) {
3081 $sql .= ")";
3082 }
3083 if (isModEnabled('barcode')) {
3084 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3085 }
3086 $sql .= ')';
3087 }
3088 if (count($warehouseStatusArray)) {
3089 $sql .= " GROUP BY " . $selectFields;
3090 }
3091
3092 //Sort by category
3093 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3094 $sql .= " ORDER BY categorie_product_id ";
3095 //ASC OR DESC order
3096 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3097 } else {
3098 $sql .= $this->db->order("p.ref");
3099 }
3100
3101 $sql .= $this->db->plimit($limit, 0);
3102
3103 // Build output string
3104 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3105 $result = $this->db->query($sql);
3106 if ($result) {
3107 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3108 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3109 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3110
3111 $num = $this->db->num_rows($result);
3112
3113 $events = array();
3114
3115 if (!$forcecombo) {
3116 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3117 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3118 }
3119
3120 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3121
3122 $textifempty = '';
3123 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3124 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3125 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3126 if ($showempty && !is_numeric($showempty)) {
3127 $textifempty = $langs->trans($showempty);
3128 } else {
3129 $textifempty .= $langs->trans("All");
3130 }
3131 } else {
3132 if ($showempty && !is_numeric($showempty)) {
3133 $textifempty = $langs->trans($showempty);
3134 }
3135 }
3136 if ($showempty) {
3137 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3138 }
3139
3140 $i = 0;
3141 while ($num && $i < $num) {
3142 $opt = '';
3143 $optJson = array();
3144 $objp = $this->db->fetch_object($result);
3145
3146 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
3147 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3148 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3149 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3150 $sql .= " ORDER BY quantity ASC";
3151
3152 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3153 $result2 = $this->db->query($sql);
3154 if ($result2) {
3155 $nb_prices = $this->db->num_rows($result2);
3156 $j = 0;
3157 while ($nb_prices && $j < $nb_prices) {
3158 $objp2 = $this->db->fetch_object($result2);
3159
3160 $objp->price_by_qty_rowid = $objp2->rowid;
3161 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3162 $objp->price_by_qty_quantity = $objp2->quantity;
3163 $objp->price_by_qty_unitprice = $objp2->unitprice;
3164 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3165 // For backward compatibility
3166 $objp->quantity = $objp2->quantity;
3167 $objp->price = $objp2->price;
3168 $objp->unitprice = $objp2->unitprice;
3169 $objp->remise_percent = $objp2->remise_percent;
3170
3171 //$objp->tva_tx is not overwritten by $objp2 value
3172 //$objp->default_vat_code is not overwritten by $objp2 value
3173
3174 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3175
3176 $j++;
3177
3178 // Add new entry
3179 // "key" value of json key array is used by jQuery automatically as selected value
3180 // "label" value of json key array is used by jQuery automatically as text for combo box
3181 $out .= $opt;
3182 array_push($outarray, $optJson);
3183 }
3184 }
3185 } else {
3186 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3187 $price_product = new Product($this->db);
3188 $price_product->fetch($objp->rowid, '', '', 1);
3189
3190 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3191 $priceparser = new PriceParser($this->db);
3192 $price_result = $priceparser->parseProduct($price_product);
3193 if ($price_result >= 0) {
3194 $objp->price = $price_result;
3195 $objp->unitprice = $price_result;
3196 //Calculate the VAT
3197 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3198 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3199 }
3200 }
3201
3202 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3203 // Add new entry
3204 // "key" value of json key array is used by jQuery automatically as selected value
3205 // "label" value of json key array is used by jQuery automatically as text for combo box
3206 $out .= $opt;
3207 array_push($outarray, $optJson);
3208 }
3209
3210 $i++;
3211 }
3212
3213 $out .= '</select>';
3214
3215 $this->db->free($result);
3216
3217 if (empty($outputmode)) {
3218 return $out;
3219 }
3220
3221 return $outarray;
3222 } else {
3223 dol_print_error($this->db);
3224 }
3225
3226 return '';
3227 }
3228
3244 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3245 {
3246 global $langs, $conf, $user;
3247 global $hookmanager;
3248
3249 $outkey = '';
3250 $outval = '';
3251 $outref = '';
3252 $outlabel = '';
3253 $outlabel_translated = '';
3254 $outdesc = '';
3255 $outdesc_translated = '';
3256 $outbarcode = '';
3257 $outorigin = '';
3258 $outtype = '';
3259 $outprice_ht = '';
3260 $outprice_ttc = '';
3261 $outpricebasetype = '';
3262 $outtva_tx = '';
3263 $outdefault_vat_code = '';
3264 $outqty = 1;
3265 $outdiscount = 0;
3266
3267 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3268
3269 $label = $objp->label;
3270 if (!empty($objp->label_translated)) {
3271 $label = $objp->label_translated;
3272 }
3273 if (!empty($filterkey) && $filterkey != '') {
3274 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3275 }
3276
3277 $outkey = $objp->rowid;
3278 $outref = $objp->ref;
3279 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3280 $outlabel = $objp->label;
3281 $outdesc = $objp->description;
3282 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3283 $outlabel_translated = $objp->label_translated;
3284 $outdesc_translated = $objp->description_translated;
3285 }
3286 $outbarcode = $objp->barcode;
3287 $outorigin = $objp->fk_country;
3288 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3289
3290 $outtype = $objp->fk_product_type;
3291 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3292 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3293
3294 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3295 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3296 }
3297
3298 // Units
3299 $outvalUnits = '';
3300 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3301 if (!empty($objp->unit_short)) {
3302 $outvalUnits .= ' - ' . $objp->unit_short;
3303 }
3304 }
3305 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3306 if (!empty($objp->weight) && $objp->weight_units !== null) {
3307 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3308 $outvalUnits .= ' - ' . $unitToShow;
3309 }
3310 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3311 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3312 $outvalUnits .= ' - ' . $unitToShow;
3313 }
3314 if (!empty($objp->surface) && $objp->surface_units !== null) {
3315 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3316 $outvalUnits .= ' - ' . $unitToShow;
3317 }
3318 if (!empty($objp->volume) && $objp->volume_units !== null) {
3319 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3320 $outvalUnits .= ' - ' . $unitToShow;
3321 }
3322 }
3323 if ($outdurationvalue && $outdurationunit) {
3324 $da = array(
3325 'h' => $langs->trans('Hour'),
3326 'd' => $langs->trans('Day'),
3327 'w' => $langs->trans('Week'),
3328 'm' => $langs->trans('Month'),
3329 'y' => $langs->trans('Year')
3330 );
3331 if (isset($da[$outdurationunit])) {
3332 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3333 }
3334 }
3335
3336 // Set stocktag (stock too low or not or unknown)
3337 $stocktag = 0;
3338 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3339 if ($user->hasRight('stock', 'lire')) {
3340 if ($objp->stock > 0) {
3341 $stocktag = 1;
3342 } elseif ($objp->stock <= 0) {
3343 $stocktag = -1;
3344 }
3345 }
3346 }
3347
3348 // Set $labeltoshow
3349 $labeltoshow = '';
3350 $labeltoshow .= $objp->ref;
3351 if (!empty($objp->custref)) {
3352 $labeltoshow .= ' (' . $objp->custref . ')';
3353 }
3354 if ($outbarcode) {
3355 $labeltoshow .= ' (' . $outbarcode . ')';
3356 }
3357 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3358 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3359 $labeltoshow .= ' (' . getCountry($outorigin, 1) . ')';
3360 }
3361
3362 // Set $labltoshowhtml
3363 $labeltoshowhtml = '';
3364 $labeltoshowhtml .= $objp->ref;
3365 if (!empty($objp->custref)) {
3366 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3367 }
3368 if (!empty($filterkey) && $filterkey != '') {
3369 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3370 }
3371 if ($outbarcode) {
3372 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3373 }
3374 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3375 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3376 $labeltoshowhtml .= ' (' . getCountry($outorigin, 1) . ')';
3377 }
3378
3379 // Stock
3380 $labeltoshowstock = '';
3381 $labeltoshowhtmlstock = '';
3382 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3383 if ($user->hasRight('stock', 'lire')) {
3384 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3385
3386 if ($objp->stock > 0) {
3387 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3388 } elseif ($objp->stock <= 0) {
3389 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3390 }
3391 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3392 $labeltoshowhtmlstock .= '</span>';
3393
3394 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3395 $langs->load("stocks");
3396
3397 $tmpproduct = new Product($this->db);
3398 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3399 $tmpproduct->load_virtual_stock();
3400 $virtualstock = $tmpproduct->stock_theorique;
3401
3402 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3403
3404 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3405 if ($virtualstock > 0) {
3406 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3407 } elseif ($virtualstock <= 0) {
3408 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3409 }
3410 $labeltoshowhtmlstock .= $virtualstock;
3411 $labeltoshowhtmlstock .= '</span>';
3412
3413 unset($tmpproduct);
3414 }
3415 }
3416 }
3417
3418 // Price
3419 $found = 0;
3420 $labeltoshowprice = '';
3421 $labeltoshowhtmlprice = '';
3422 // If we need a particular price level (from 1 to n)
3423 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3424 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3425 $sql .= " FROM " . $this->db->prefix() . "product_price";
3426 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3427 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3428 $sql .= " AND price_level = " . ((int) $price_level);
3429 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3430 $sql .= " LIMIT 1";
3431
3432 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3433 $result2 = $this->db->query($sql);
3434 if ($result2) {
3435 $objp2 = $this->db->fetch_object($result2);
3436 if ($objp2) {
3437 $found = 1;
3438 if ($objp2->price_base_type == 'HT') {
3439 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3440 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3441 } else {
3442 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3443 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3444 }
3445 $outprice_ht = price($objp2->price);
3446 $outprice_ttc = price($objp2->price_ttc);
3447 $outpricebasetype = $objp2->price_base_type;
3448 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3449 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3450 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3451 } else {
3452 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3453 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3454 }
3455 }
3456 } else {
3457 dol_print_error($this->db);
3458 }
3459 }
3460
3461 // Price by quantity
3462 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3463 $found = 1;
3464 $outqty = $objp->quantity;
3465 $outdiscount = $objp->remise_percent;
3466 if ($objp->quantity == 1) {
3467 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3468 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3469 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3470 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3471 } else {
3472 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3473 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3474 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3475 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3476 }
3477
3478 $outprice_ht = price($objp->unitprice);
3479 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3480 $outpricebasetype = $objp->price_base_type;
3481 $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
3482 $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
3483 }
3484 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3485 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3486 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3487 }
3488 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3489 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3490 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3491 }
3492
3493 // Price by customer
3494 if (empty($hidepriceinlabel) && getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
3495 if (!empty($objp->idprodcustprice)) {
3496 $found = 1;
3497
3498 if ($objp->custprice_base_type == 'HT') {
3499 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3500 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3501 } else {
3502 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3503 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3504 }
3505
3506 $outprice_ht = price($objp->custprice);
3507 $outprice_ttc = price($objp->custprice_ttc);
3508 $outpricebasetype = $objp->custprice_base_type;
3509 $outtva_tx = $objp->custtva_tx;
3510 $outdefault_vat_code = $objp->custdefault_vat_code;
3511 }
3512 }
3513
3514 // If level no defined or multiprice not found, we used the default price
3515 if (empty($hidepriceinlabel) && !$found) {
3516 if ($objp->price_base_type == 'HT') {
3517 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3518 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3519 } else {
3520 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3521 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3522 }
3523 $outprice_ht = price($objp->price);
3524 $outprice_ttc = price($objp->price_ttc);
3525 $outpricebasetype = $objp->price_base_type;
3526 $outtva_tx = $objp->tva_tx;
3527 $outdefault_vat_code = $objp->default_vat_code;
3528 }
3529
3530
3531 // Build options
3532 $opt = '<option value="' . $objp->rowid . '"';
3533 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3534 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3535 $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 . '"';
3536 }
3537 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3538 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3539 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3540 }
3541
3542 if ($stocktag == 1) {
3543 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3544 //$opt .= ' class="product_line_stock_ok"';
3545 }
3546 if ($stocktag == -1) {
3547 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3548 //$opt .= ' class="product_line_stock_too_low"';
3549 }
3550
3551 $opt .= '>';
3552
3553 // Ref, barcode, country
3554 $opt .= $labeltoshow;
3555 $outval .= $labeltoshowhtml;
3556
3557 // Units
3558 $opt .= $outvalUnits;
3559 $outval .= $outvalUnits;
3560
3561 // Price
3562 $opt .= $labeltoshowprice;
3563 $outval .= $labeltoshowhtmlprice;
3564
3565 // Stock
3566 $opt .= $labeltoshowstock;
3567 $outval .= $labeltoshowhtmlstock;
3568
3569
3570 $parameters = array('objp' => $objp);
3571 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3572 if (empty($reshook)) {
3573 $opt .= $hookmanager->resPrint;
3574 } else {
3575 $opt = $hookmanager->resPrint;
3576 }
3577
3578 $opt .= "</option>\n";
3579 $optJson = array(
3580 'key' => $outkey,
3581 'value' => $outref,
3582 'label' => $outval,
3583 'label2' => $outlabel,
3584 'desc' => $outdesc,
3585 'type' => $outtype,
3586 'price_ht' => price2num($outprice_ht),
3587 'price_ttc' => price2num($outprice_ttc),
3588 'price_ht_locale' => price(price2num($outprice_ht)),
3589 'price_ttc_locale' => price(price2num($outprice_ttc)),
3590 'pricebasetype' => $outpricebasetype,
3591 'tva_tx' => $outtva_tx,
3592 'default_vat_code' => $outdefault_vat_code,
3593 'qty' => $outqty,
3594 'discount' => $outdiscount,
3595 'duration_value' => $outdurationvalue,
3596 'duration_unit' => $outdurationunit,
3597 'pbq' => $outpbq,
3598 'labeltrans' => $outlabel_translated,
3599 'desctrans' => $outdesc_translated,
3600 'ref_customer' => $outrefcust
3601 );
3602 }
3603
3604 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3605
3621 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3622 {
3623 // phpcs:enable
3624 global $langs, $conf;
3625 global $price_level, $status, $finished;
3626
3627 if (!isset($status)) {
3628 $status = 1;
3629 }
3630
3631 $selected_input_value = '';
3632 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3633 if ($selected > 0) {
3634 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3635 $producttmpselect = new Product($this->db);
3636 $producttmpselect->fetch($selected);
3637 $selected_input_value = $producttmpselect->ref;
3638 unset($producttmpselect);
3639 }
3640
3641 // mode=2 means suppliers products
3642 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3643 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3644
3645 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3646 } else {
3647 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3648 }
3649 }
3650
3651 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3652
3671 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 = '')
3672 {
3673 // phpcs:enable
3674 global $langs, $conf, $user;
3675 global $hookmanager;
3676
3677 $out = '';
3678 $outarray = array();
3679
3680 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3681
3682 $langs->load('stocks');
3683 // Units
3684 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3685 $langs->load('other');
3686 }
3687
3688 $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,";
3689 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3690 if (isModEnabled('multicurrency')) {
3691 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3692 }
3693 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3694 $sql .= ", pfp.supplier_reputation";
3695 // if we use supplier description of the products
3696 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3697 $sql .= ", pfp.desc_fourn as description";
3698 } else {
3699 $sql .= ", p.description";
3700 }
3701 // Units
3702 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3703 $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";
3704 }
3705 $sql .= " FROM " . $this->db->prefix() . "product as p";
3706 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3707 if ($socid > 0) {
3708 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3709 }
3710 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3711 // Units
3712 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3713 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3714 }
3715 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3716 if ($statut != -1) {
3717 $sql .= " AND p.tobuy = " . ((int) $statut);
3718 }
3719 if (strval($filtertype) != '') {
3720 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3721 }
3722 if (!empty($filtre)) {
3723 $sql .= " " . $filtre;
3724 }
3725 // Add where from hooks
3726 $parameters = array();
3727 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3728 $sql .= $hookmanager->resPrint;
3729 // Add criteria on ref/label
3730 if ($filterkey != '') {
3731 $sql .= ' AND (';
3732 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3733 // For natural search
3734 $search_crit = explode(' ', $filterkey);
3735 $i = 0;
3736 if (count($search_crit) > 1) {
3737 $sql .= "(";
3738 }
3739 foreach ($search_crit as $crit) {
3740 if ($i > 0) {
3741 $sql .= " AND ";
3742 }
3743 $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) . "%'";
3744 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3745 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3746 }
3747 $sql .= ")";
3748 $i++;
3749 }
3750 if (count($search_crit) > 1) {
3751 $sql .= ")";
3752 }
3753 if (isModEnabled('barcode')) {
3754 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3755 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3756 }
3757 $sql .= ')';
3758 }
3759 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3760 $sql .= $this->db->plimit($limit, 0);
3761
3762 // Build output string
3763
3764 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3765 $result = $this->db->query($sql);
3766 if ($result) {
3767 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3768 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3769
3770 $num = $this->db->num_rows($result);
3771
3772 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3773 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3774 if (!$selected) {
3775 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3776 } else {
3777 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3778 }
3779
3780 $i = 0;
3781 while ($i < $num) {
3782 $objp = $this->db->fetch_object($result);
3783
3784 if (is_null($objp->idprodfournprice)) {
3785 // There is no supplier price found, we will use the vat rate for sale
3786 $objp->tva_tx = $objp->tva_tx_sale;
3787 $objp->default_vat_code = $objp->default_vat_code_sale;
3788 }
3789
3790 $outkey = $objp->idprodfournprice; // id in table of price
3791 if (!$outkey && $alsoproductwithnosupplierprice) {
3792 $outkey = 'idprod_' . $objp->rowid; // id of product
3793 }
3794
3795 $outref = $objp->ref;
3796 $outbarcode = $objp->barcode;
3797 $outqty = 1;
3798 $outdiscount = 0;
3799 $outtype = $objp->fk_product_type;
3800 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3801 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3802
3803 // Units
3804 $outvalUnits = '';
3805 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3806 if (!empty($objp->unit_short)) {
3807 $outvalUnits .= ' - ' . $objp->unit_short;
3808 }
3809 if (!empty($objp->weight) && $objp->weight_units !== null) {
3810 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3811 $outvalUnits .= ' - ' . $unitToShow;
3812 }
3813 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3814 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3815 $outvalUnits .= ' - ' . $unitToShow;
3816 }
3817 if (!empty($objp->surface) && $objp->surface_units !== null) {
3818 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3819 $outvalUnits .= ' - ' . $unitToShow;
3820 }
3821 if (!empty($objp->volume) && $objp->volume_units !== null) {
3822 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3823 $outvalUnits .= ' - ' . $unitToShow;
3824 }
3825 if ($outdurationvalue && $outdurationunit) {
3826 $da = array(
3827 'h' => $langs->trans('Hour'),
3828 'd' => $langs->trans('Day'),
3829 'w' => $langs->trans('Week'),
3830 'm' => $langs->trans('Month'),
3831 'y' => $langs->trans('Year')
3832 );
3833 if (isset($da[$outdurationunit])) {
3834 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3835 }
3836 }
3837 }
3838
3839 $objRef = $objp->ref;
3840 if ($filterkey && $filterkey != '') {
3841 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3842 }
3843 $objRefFourn = $objp->ref_fourn;
3844 if ($filterkey && $filterkey != '') {
3845 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3846 }
3847 $label = $objp->label;
3848 if ($filterkey && $filterkey != '') {
3849 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3850 }
3851
3852 switch ($objp->fk_product_type) {
3854 $picto = 'product';
3855 break;
3857 $picto = 'service';
3858 break;
3859 default:
3860 $picto = '';
3861 break;
3862 }
3863
3864 if (empty($picto)) {
3865 $optlabel = '';
3866 } else {
3867 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3868 }
3869
3870 $optlabel .= $objp->ref;
3871 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3872 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3873 }
3874 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3875 $optlabel .= ' (' . $outbarcode . ')';
3876 }
3877 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3878
3879 $outvallabel = $objRef;
3880 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3881 $outvallabel .= ' (' . $objRefFourn . ')';
3882 }
3883 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3884 $outvallabel .= ' (' . $outbarcode . ')';
3885 }
3886 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3887
3888 // Units
3889 $optlabel .= $outvalUnits;
3890 $outvallabel .= $outvalUnits;
3891
3892 if (!empty($objp->idprodfournprice)) {
3893 $outqty = $objp->quantity;
3894 $outdiscount = $objp->remise_percent;
3895 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3896 $prod_supplier = new ProductFournisseur($this->db);
3897 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3898 $prod_supplier->id = $objp->fk_product;
3899 $prod_supplier->fourn_qty = $objp->quantity;
3900 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3901 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3902
3903 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3904 $priceparser = new PriceParser($this->db);
3905 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3906 if ($price_result >= 0) {
3907 $objp->fprice = $price_result;
3908 if ($objp->quantity >= 1) {
3909 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3910 }
3911 }
3912 }
3913 if ($objp->quantity == 1) {
3914 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3915 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3916 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3917 $outvallabel .= $langs->transnoentities("Unit");
3918 } else {
3919 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3920 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3921 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3922 $outvallabel .= ' ' . $langs->transnoentities("Units");
3923 }
3924
3925 if ($objp->quantity > 1) {
3926 $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
3927 $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
3928 }
3929 if ($objp->remise_percent >= 1) {
3930 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3931 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3932 }
3933 if ($objp->duration) {
3934 $optlabel .= " - " . $objp->duration;
3935 $outvallabel .= " - " . $objp->duration;
3936 }
3937 if (!$socid) {
3938 $optlabel .= " - " . dol_trunc($objp->name, 8);
3939 $outvallabel .= " - " . dol_trunc($objp->name, 8);
3940 }
3941 if ($objp->supplier_reputation) {
3942 //TODO dictionary
3943 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3944
3945 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3946 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3947 }
3948 } else {
3949 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3950 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3951 }
3952
3953 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3954 $novirtualstock = ($showstockinlist == 2);
3955
3956 if ($user->hasRight('stock', 'lire')) {
3957 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3958
3959 if ($objp->stock > 0) {
3960 $optlabel .= ' - <span class="product_line_stock_ok">';
3961 } elseif ($objp->stock <= 0) {
3962 $optlabel .= ' - <span class="product_line_stock_too_low">';
3963 }
3964 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3965 $optlabel .= '</span>';
3966 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3967 $langs->load("stocks");
3968
3969 $tmpproduct = new Product($this->db);
3970 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3971 $tmpproduct->load_virtual_stock();
3972 $virtualstock = $tmpproduct->stock_theorique;
3973
3974 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3975
3976 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3977 if ($virtualstock > 0) {
3978 $optlabel .= '<span class="product_line_stock_ok">';
3979 } elseif ($virtualstock <= 0) {
3980 $optlabel .= '<span class="product_line_stock_too_low">';
3981 }
3982 $optlabel .= $virtualstock;
3983 $optlabel .= '</span>';
3984
3985 unset($tmpproduct);
3986 }
3987 }
3988 }
3989
3990 $optstart = '<option value="' . $outkey . '"';
3991 if ($selected && $selected == $objp->idprodfournprice) {
3992 $optstart .= ' selected';
3993 }
3994 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3995 $optstart .= ' disabled';
3996 }
3997
3998 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3999 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4000 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4001 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4002 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
4003 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
4004 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
4005 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
4006 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
4007 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4008 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4009 if (isModEnabled('multicurrency')) {
4010 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4011 $optstart .= ' data-multicurrency-up="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
4012 }
4013 }
4014 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4015
4016 $outarrayentry = array(
4017 'key' => $outkey,
4018 'value' => $outref,
4019 'label' => $outvallabel,
4020 'qty' => $outqty,
4021 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4022 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4023 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4024 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4025 'tva_tx' => price2num($objp->tva_tx),
4026 'default_vat_code' => $objp->default_vat_code,
4027 'supplier_ref' => $objp->ref_fourn,
4028 'discount' => $outdiscount,
4029 'type' => $outtype,
4030 'duration_value' => $outdurationvalue,
4031 'duration_unit' => $outdurationunit,
4032 'disabled' => empty($objp->idprodfournprice),
4033 'description' => $objp->description
4034 );
4035 if (isModEnabled('multicurrency')) {
4036 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4037 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4038 }
4039
4040 $parameters = array(
4041 'objp' => &$objp,
4042 'optstart' => &$optstart,
4043 'optlabel' => &$optlabel,
4044 'outvallabel' => &$outvallabel,
4045 'outarrayentry' => &$outarrayentry
4046 );
4047 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4048
4049
4050 // Add new entry
4051 // "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
4052 // "label" value of json key array is used by jQuery automatically as text for combo box
4053 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4054 $outarraypush = array(
4055 'key' => $outkey,
4056 'value' => $outref,
4057 'label' => $outvallabel,
4058 'qty' => $outqty,
4059 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4060 'price_qty_ht_locale' => price($objp->fprice),
4061 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4062 'price_unit_ht_locale' => price($objp->unitprice),
4063 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4064 'tva_tx_formated' => price($objp->tva_tx),
4065 'tva_tx' => price2num($objp->tva_tx),
4066 'default_vat_code' => $objp->default_vat_code,
4067 'supplier_ref' => $objp->ref_fourn,
4068 'discount' => $outdiscount,
4069 'type' => $outtype,
4070 'duration_value' => $outdurationvalue,
4071 'duration_unit' => $outdurationunit,
4072 'disabled' => empty($objp->idprodfournprice),
4073 'description' => $objp->description
4074 );
4075 if (isModEnabled('multicurrency')) {
4076 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4077 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4078 }
4079 array_push($outarray, $outarraypush);
4080
4081 // Example of var_dump $outarray
4082 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4083 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4084 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4085 //}
4086 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4087 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4088 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4089
4090 $i++;
4091 }
4092 $out .= '</select>';
4093
4094 $this->db->free($result);
4095
4096 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4097 $out .= ajax_combobox($htmlname);
4098 } else {
4099 dol_print_error($this->db);
4100 }
4101
4102 if (empty($outputmode)) {
4103 return $out;
4104 }
4105 return $outarray;
4106 }
4107
4108 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4109
4118 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4119 {
4120 // phpcs:enable
4121 global $langs, $conf;
4122
4123 $langs->load('stocks');
4124
4125 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4126 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4127 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4128 $sql .= " FROM " . $this->db->prefix() . "product as p";
4129 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4130 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4131 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4132 $sql .= " AND p.tobuy = 1";
4133 $sql .= " AND s.fournisseur = 1";
4134 $sql .= " AND p.rowid = " . ((int) $productid);
4135 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4136 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4137 } else {
4138 $sql .= " ORDER BY pfp.unitprice ASC";
4139 }
4140
4141 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4142 $result = $this->db->query($sql);
4143
4144 if ($result) {
4145 $num = $this->db->num_rows($result);
4146
4147 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4148
4149 if (!$num) {
4150 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4151 } else {
4152 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4153 $form .= '<option value="0">&nbsp;</option>';
4154
4155 $i = 0;
4156 while ($i < $num) {
4157 $objp = $this->db->fetch_object($result);
4158
4159 $opt = '<option value="' . $objp->idprodfournprice . '"';
4160 //if there is only one supplier, preselect it
4161 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4162 $opt .= ' selected';
4163 }
4164 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4165
4166 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4167 $prod_supplier = new ProductFournisseur($this->db);
4168 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4169 $prod_supplier->id = $productid;
4170 $prod_supplier->fourn_qty = $objp->quantity;
4171 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4172 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4173
4174 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4175 $priceparser = new PriceParser($this->db);
4176 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4177 if ($price_result >= 0) {
4178 $objp->fprice = $price_result;
4179 if ($objp->quantity >= 1) {
4180 $objp->unitprice = $objp->fprice / $objp->quantity;
4181 }
4182 }
4183 }
4184 if ($objp->quantity == 1) {
4185 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4186 }
4187
4188 $opt .= $objp->quantity . ' ';
4189
4190 if ($objp->quantity == 1) {
4191 $opt .= $langs->trans("Unit");
4192 } else {
4193 $opt .= $langs->trans("Units");
4194 }
4195 if ($objp->quantity > 1) {
4196 $opt .= " - ";
4197 $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");
4198 }
4199 if ($objp->duration) {
4200 $opt .= " - " . $objp->duration;
4201 }
4202 $opt .= "</option>\n";
4203
4204 $form .= $opt;
4205 $i++;
4206 }
4207 }
4208
4209 $form .= '</select>';
4210 $this->db->free($result);
4211 return $form;
4212 } else {
4213 dol_print_error($this->db);
4214 return '';
4215 }
4216 }
4217
4218
4219 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4226 {
4227 // phpcs:enable
4228 global $langs;
4229
4230 $num = count($this->cache_conditions_paiements);
4231 if ($num > 0) {
4232 return 0; // Cache already loaded
4233 }
4234
4235 dol_syslog(__METHOD__, LOG_DEBUG);
4236
4237 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4238 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4239 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4240 $sql .= " AND active > 0";
4241 $sql .= " ORDER BY sortorder";
4242
4243 $resql = $this->db->query($sql);
4244 if ($resql) {
4245 $num = $this->db->num_rows($resql);
4246 $i = 0;
4247 while ($i < $num) {
4248 $obj = $this->db->fetch_object($resql);
4249
4250 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4251 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4252 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4253 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4254 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4255 $i++;
4256 }
4257
4258 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4259
4260 return $num;
4261 } else {
4262 dol_print_error($this->db);
4263 return -1;
4264 }
4265 }
4266
4267 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4268
4274 public function load_cache_availability()
4275 {
4276 // phpcs:enable
4277 global $langs;
4278
4279 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4280 if ($num > 0) {
4281 return 0; // Cache already loaded
4282 }
4283
4284 dol_syslog(__METHOD__, LOG_DEBUG);
4285
4286 $langs->load('propal');
4287
4288 $sql = "SELECT rowid, code, label, position";
4289 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4290 $sql .= " WHERE active > 0";
4291
4292 $resql = $this->db->query($sql);
4293 if ($resql) {
4294 $num = $this->db->num_rows($resql);
4295 $i = 0;
4296 while ($i < $num) {
4297 $obj = $this->db->fetch_object($resql);
4298
4299 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4300 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4301 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4302 $this->cache_availability[$obj->rowid]['label'] = $label;
4303 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4304 $i++;
4305 }
4306
4307 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4308
4309 return $num;
4310 } else {
4311 dol_print_error($this->db);
4312 return -1;
4313 }
4314 }
4315
4326 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4327 {
4328 global $langs, $user;
4329
4330 $this->load_cache_availability();
4331
4332 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4333
4334 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4335 if ($addempty) {
4336 print '<option value="0">&nbsp;</option>';
4337 }
4338 foreach ($this->cache_availability as $id => $arrayavailability) {
4339 if ($selected == $id) {
4340 print '<option value="' . $id . '" selected>';
4341 } else {
4342 print '<option value="' . $id . '">';
4343 }
4344 print dol_escape_htmltag($arrayavailability['label']);
4345 print '</option>';
4346 }
4347 print '</select>';
4348 if ($user->admin) {
4349 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4350 }
4351 print ajax_combobox($htmlname);
4352 }
4353
4359 public function loadCacheInputReason()
4360 {
4361 global $langs;
4362
4363 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4364 if ($num > 0) {
4365 return 0; // Cache already loaded
4366 }
4367
4368 $sql = "SELECT rowid, code, label";
4369 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4370 $sql .= " WHERE active > 0";
4371
4372 $resql = $this->db->query($sql);
4373 if ($resql) {
4374 $num = $this->db->num_rows($resql);
4375 $i = 0;
4376 $tmparray = array();
4377 while ($i < $num) {
4378 $obj = $this->db->fetch_object($resql);
4379
4380 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4381 $label = ($obj->label != '-' ? $obj->label : '');
4382 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4383 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4384 }
4385 if ($langs->trans($obj->code) != $obj->code) {
4386 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4387 }
4388
4389 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4390 $tmparray[$obj->rowid]['code'] = $obj->code;
4391 $tmparray[$obj->rowid]['label'] = $label;
4392 $i++;
4393 }
4394
4395 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4396
4397 unset($tmparray);
4398 return $num;
4399 } else {
4400 dol_print_error($this->db);
4401 return -1;
4402 }
4403 }
4404
4417 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4418 {
4419 global $langs, $user;
4420
4421 $this->loadCacheInputReason();
4422
4423 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4424 if ($addempty) {
4425 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4426 }
4427 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4428 if ($arraydemandreason['code'] == $exclude) {
4429 continue;
4430 }
4431
4432 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4433 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4434 } else {
4435 print '<option value="' . $arraydemandreason['id'] . '">';
4436 }
4437 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4438 print $langs->trans($label);
4439 print '</option>';
4440 }
4441 print '</select>';
4442 if ($user->admin && empty($notooltip)) {
4443 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4444 }
4445 print ajax_combobox('select_' . $htmlname);
4446 }
4447
4448 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4449
4456 {
4457 // phpcs:enable
4458 global $langs;
4459
4460 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4461 if ($num > 0) {
4462 return $num; // Cache already loaded
4463 }
4464
4465 dol_syslog(__METHOD__, LOG_DEBUG);
4466
4467 $this->cache_types_paiements = array();
4468
4469 $sql = "SELECT id, code, libelle as label, type, active";
4470 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4471 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4472
4473 $resql = $this->db->query($sql);
4474 if ($resql) {
4475 $num = $this->db->num_rows($resql);
4476 $i = 0;
4477 while ($i < $num) {
4478 $obj = $this->db->fetch_object($resql);
4479
4480 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4481 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4482 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4483 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4484 $this->cache_types_paiements[$obj->id]['label'] = $label;
4485 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4486 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4487 $i++;
4488 }
4489
4490 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4491
4492 return $num;
4493 } else {
4494 dol_print_error($this->db);
4495 return -1;
4496 }
4497 }
4498
4499
4500 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4501
4520 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4521 {
4522 // phpcs:enable
4523 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4524 if (empty($noprint)) {
4525 print $out;
4526 } else {
4527 return $out;
4528 }
4529 }
4530
4531
4548 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4549 {
4550 global $langs, $user, $conf;
4551
4552 $out = '';
4553 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4554
4556
4557 // Set default value if not already set by caller
4558 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4559 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4560 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4561 }
4562
4563 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4564 if ($addempty) {
4565 $out .= '<option value="0">&nbsp;</option>';
4566 }
4567
4568 $selectedDepositPercent = null;
4569
4570 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4571 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4572 continue;
4573 }
4574
4575 if ($selected == $id) {
4576 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4577 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4578 } else {
4579 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4580 }
4581 $label = $arrayconditions['label'];
4582
4583 if (!empty($arrayconditions['deposit_percent'])) {
4584 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4585 }
4586
4587 $out .= $label;
4588 $out .= '</option>';
4589 }
4590 $out .= '</select>';
4591 if ($user->admin && empty($noinfoadmin)) {
4592 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4593 }
4594 $out .= ajax_combobox($htmlname);
4595
4596 if ($deposit_percent >= 0) {
4597 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4598 $out .= $langs->trans('DepositPercent') . ' : ';
4599 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4600 $out .= '</span>';
4601 $out .= '
4602 <script nonce="' . getNonce() . '">
4603 $(document).ready(function () {
4604 $("#' . $htmlname . '").change(function () {
4605 let $selected = $(this).find("option:selected");
4606 let depositPercent = $selected.attr("data-deposit_percent");
4607
4608 if (depositPercent.length > 0) {
4609 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4610 } else {
4611 $("#' . $htmlname . '_deposit_percent_container").hide();
4612 }
4613
4614 return true;
4615 });
4616 });
4617 </script>';
4618 }
4619
4620 return $out;
4621 }
4622
4623
4624 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4625
4642 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4643 {
4644 // phpcs:enable
4645 global $langs, $user, $conf;
4646
4647 $out = '';
4648
4649 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4650
4651 $filterarray = array();
4652 if ($filtertype == 'CRDT') {
4653 $filterarray = array(0, 2, 3);
4654 } elseif ($filtertype == 'DBIT') {
4655 $filterarray = array(1, 2, 3);
4656 } elseif ($filtertype != '' && $filtertype != '-1') {
4657 $filterarray = explode(',', $filtertype);
4658 }
4659
4661
4662 // Set default value if not already set by caller
4663 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4664 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4665 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4666 }
4667
4668 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4669 if ($empty) {
4670 $out .= '<option value="">&nbsp;</option>';
4671 }
4672 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4673 // If not good status
4674 if ($active >= 0 && $arraytypes['active'] != $active) {
4675 continue;
4676 }
4677
4678 // We skip of the user requested to filter on specific payment methods
4679 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4680 continue;
4681 }
4682
4683 // We discard empty lines if showempty is on because an empty line has already been output.
4684 if ($empty && empty($arraytypes['code'])) {
4685 continue;
4686 }
4687
4688 if ($format == 0) {
4689 $out .= '<option value="' . $id . '"';
4690 } elseif ($format == 1) {
4691 $out .= '<option value="' . $arraytypes['code'] . '"';
4692 } elseif ($format == 2) {
4693 $out .= '<option value="' . $arraytypes['code'] . '"';
4694 } elseif ($format == 3) {
4695 $out .= '<option value="' . $id . '"';
4696 }
4697 // Print attribute selected or not
4698 if ($format == 1 || $format == 2) {
4699 if ($selected == $arraytypes['code']) {
4700 $out .= ' selected';
4701 }
4702 } else {
4703 if ($selected == $id) {
4704 $out .= ' selected';
4705 }
4706 }
4707 $out .= '>';
4708 $value = '';
4709 if ($format == 0) {
4710 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4711 } elseif ($format == 1) {
4712 $value = $arraytypes['code'];
4713 } elseif ($format == 2) {
4714 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4715 } elseif ($format == 3) {
4716 $value = $arraytypes['code'];
4717 }
4718 $out .= $value ? $value : '&nbsp;';
4719 $out .= '</option>';
4720 }
4721 $out .= '</select>';
4722 if ($user->admin && !$noadmininfo) {
4723 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4724 }
4725 $out .= ajax_combobox('select' . $htmlname);
4726
4727 if (empty($nooutput)) {
4728 print $out;
4729 } else {
4730 return $out;
4731 }
4732 }
4733
4734
4743 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4744 {
4745 global $langs;
4746
4747 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4748 $options = array(
4749 'HT' => $langs->trans("HT"),
4750 'TTC' => $langs->trans("TTC")
4751 );
4752 foreach ($options as $id => $value) {
4753 if ($selected == $id) {
4754 $return .= '<option value="' . $id . '" selected>' . $value;
4755 } else {
4756 $return .= '<option value="' . $id . '">' . $value;
4757 }
4758 $return .= '</option>';
4759 }
4760 $return .= '</select>';
4761 if ($addjscombo) {
4762 $return .= ajax_combobox('select_' . $htmlname);
4763 }
4764
4765 return $return;
4766 }
4767
4768 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4769
4776 {
4777 // phpcs:enable
4778 global $langs;
4779
4780 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4781 if ($num > 0) {
4782 return $num; // Cache already loaded
4783 }
4784
4785 dol_syslog(__METHOD__, LOG_DEBUG);
4786
4787 $this->cache_transport_mode = array();
4788
4789 $sql = "SELECT rowid, code, label, active";
4790 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4791 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4792
4793 $resql = $this->db->query($sql);
4794 if ($resql) {
4795 $num = $this->db->num_rows($resql);
4796 $i = 0;
4797 while ($i < $num) {
4798 $obj = $this->db->fetch_object($resql);
4799
4800 // If traduction exist, we use it else we take the default label
4801 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4802 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4803 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4804 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4805 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4806 $i++;
4807 }
4808
4809 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4810
4811 return $num;
4812 } else {
4813 dol_print_error($this->db);
4814 return -1;
4815 }
4816 }
4817
4831 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4832 {
4833 global $langs, $user;
4834
4835 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4836
4838
4839 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4840 if ($empty) {
4841 print '<option value="">&nbsp;</option>';
4842 }
4843 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4844 // If not good status
4845 if ($active >= 0 && $arraytypes['active'] != $active) {
4846 continue;
4847 }
4848
4849 // We discard empty line if showempty is on because an empty line has already been output.
4850 if ($empty && empty($arraytypes['code'])) {
4851 continue;
4852 }
4853
4854 if ($format == 0) {
4855 print '<option value="' . $id . '"';
4856 } elseif ($format == 1) {
4857 print '<option value="' . $arraytypes['code'] . '"';
4858 } elseif ($format == 2) {
4859 print '<option value="' . $arraytypes['code'] . '"';
4860 } elseif ($format == 3) {
4861 print '<option value="' . $id . '"';
4862 }
4863 // If text is selected, we compare with code, else with id
4864 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4865 print ' selected';
4866 } elseif ($selected == $id) {
4867 print ' selected';
4868 }
4869 print '>';
4870 $value = '';
4871 if ($format == 0) {
4872 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4873 } elseif ($format == 1) {
4874 $value = $arraytypes['code'];
4875 } elseif ($format == 2) {
4876 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4877 } elseif ($format == 3) {
4878 $value = $arraytypes['code'];
4879 }
4880 print $value ? $value : '&nbsp;';
4881 print '</option>';
4882 }
4883 print '</select>';
4884 if ($user->admin && !$noadmininfo) {
4885 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4886 }
4887 }
4888
4901 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4902 {
4903 global $langs, $user;
4904
4905 $langs->load("admin");
4906 $langs->load("deliveries");
4907
4908 $sql = "SELECT rowid, code, libelle as label";
4909 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4910 $sql .= " WHERE active > 0";
4911 if ($filtre) {
4912 $sql .= " AND " . $filtre;
4913 }
4914 $sql .= " ORDER BY libelle ASC";
4915
4916 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4917 $result = $this->db->query($sql);
4918 if ($result) {
4919 $num = $this->db->num_rows($result);
4920 $i = 0;
4921 if ($num) {
4922 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4923 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4924 print '<option value="-1">&nbsp;</option>';
4925 }
4926 while ($i < $num) {
4927 $obj = $this->db->fetch_object($result);
4928 if ($selected == $obj->rowid) {
4929 print '<option value="' . $obj->rowid . '" selected>';
4930 } else {
4931 print '<option value="' . $obj->rowid . '">';
4932 }
4933 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
4934 print '</option>';
4935 $i++;
4936 }
4937 print "</select>";
4938 if ($user->admin && empty($noinfoadmin)) {
4939 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4940 }
4941
4942 print ajax_combobox('select' . $htmlname);
4943 } else {
4944 print $langs->trans("NoShippingMethodDefined");
4945 }
4946 } else {
4947 dol_print_error($this->db);
4948 }
4949 }
4950
4960 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4961 {
4962 global $langs;
4963
4964 $langs->load("deliveries");
4965
4966 if ($htmlname != "none") {
4967 print '<form method="POST" action="' . $page . '">';
4968 print '<input type="hidden" name="action" value="setshippingmethod">';
4969 print '<input type="hidden" name="token" value="' . newToken() . '">';
4970 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4971 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
4972 print '</form>';
4973 } else {
4974 if ($selected) {
4975 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4976 print $langs->trans("SendingMethod" . strtoupper($code));
4977 } else {
4978 print "&nbsp;";
4979 }
4980 }
4981 }
4982
4991 public function selectSituationInvoices($selected = '', $socid = 0)
4992 {
4993 global $langs;
4994
4995 $langs->load('bills');
4996
4997 $opt = '<option value="" selected></option>';
4998 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4999 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5000 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5001 $sql .= ' AND situation_counter >= 1';
5002 $sql .= ' AND fk_soc = ' . (int) $socid;
5003 $sql .= ' AND type <> 2';
5004 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5005 $resql = $this->db->query($sql);
5006
5007 if ($resql && $this->db->num_rows($resql) > 0) {
5008 // Last seen cycle
5009 $ref = 0;
5010 while ($obj = $this->db->fetch_object($resql)) {
5011 //Same cycle ?
5012 if ($obj->situation_cycle_ref != $ref) {
5013 // Just seen this cycle
5014 $ref = $obj->situation_cycle_ref;
5015 //not final ?
5016 if ($obj->situation_final != 1) {
5017 //Not prov?
5018 if (substr($obj->ref, 1, 4) != 'PROV') {
5019 if ($selected == $obj->rowid) {
5020 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5021 } else {
5022 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5023 }
5024 }
5025 }
5026 }
5027 }
5028 } else {
5029 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5030 }
5031 if ($opt == '<option value ="" selected></option>') {
5032 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5033 }
5034 return $opt;
5035 }
5036
5046 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5047 {
5048 global $langs;
5049
5050 $langs->load('products');
5051
5052 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5053
5054 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5055 $sql .= ' WHERE active > 0';
5056 if (!empty($unit_type)) {
5057 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5058 }
5059 $sql .= " ORDER BY sortorder";
5060
5061 $resql = $this->db->query($sql);
5062 if ($resql && $this->db->num_rows($resql) > 0) {
5063 if ($showempty) {
5064 $return .= '<option value="none"></option>';
5065 }
5066
5067 while ($res = $this->db->fetch_object($resql)) {
5068 $unitLabel = $res->label;
5069 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5070 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5071 }
5072
5073 if ($selected == $res->rowid) {
5074 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5075 } else {
5076 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5077 }
5078 }
5079 $return .= '</select>';
5080 }
5081 return $return;
5082 }
5083
5084 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5085
5100 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5101 {
5102 // phpcs:enable
5103 global $langs;
5104
5105 $out = '';
5106
5107 $langs->load("admin");
5108 $num = 0;
5109
5110 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5111 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5112 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5113 if ($status != 2) {
5114 $sql .= " AND clos = " . (int) $status;
5115 }
5116 if ($filtre) { // TODO Support USF
5117 $sql .= " AND " . $filtre;
5118 }
5119 $sql .= " ORDER BY label";
5120
5121 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5122 $result = $this->db->query($sql);
5123 if ($result) {
5124 $num = $this->db->num_rows($result);
5125 $i = 0;
5126 if ($num) {
5127 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5128
5129 if (!empty($useempty) && !is_numeric($useempty)) {
5130 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5131 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5132 $out .= '<option value="-1">&nbsp;</option>';
5133 }
5134
5135 while ($i < $num) {
5136 $obj = $this->db->fetch_object($result);
5137 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5138 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" selected>';
5139 } else {
5140 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '">';
5141 }
5142 $out .= trim($obj->label);
5143 if ($showcurrency) {
5144 $out .= ' (' . $obj->currency_code . ')';
5145 }
5146 if ($status == 2 && $obj->status == 1) {
5147 $out .= ' (' . $langs->trans("Closed") . ')';
5148 }
5149 $out .= '</option>';
5150 $i++;
5151 }
5152 $out .= "</select>";
5153 $out .= ajax_combobox('select' . $htmlname);
5154 } else {
5155 if ($status == 0) {
5156 $out .= '<span class="opacitymedium">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5157 } else {
5158 $out .= '<span class="opacitymedium">' . $langs->trans("NoBankAccountFound") . '</span>';
5159 }
5160 }
5161 } else {
5162 dol_print_error($this->db);
5163 }
5164
5165 // Output or return
5166 if (empty($nooutput)) {
5167 print $out;
5168 } else {
5169 return $out;
5170 }
5171
5172 return $num;
5173 }
5174
5186 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5187 {
5188 global $langs;
5189
5190 $langs->load("admin");
5191 $num = 0;
5192
5193 $sql = "SELECT rowid, name, fk_country, status, entity";
5194 $sql .= " FROM " . $this->db->prefix() . "establishment";
5195 $sql .= " WHERE 1=1";
5196 if ($status != 2) {
5197 $sql .= " AND status = " . (int) $status;
5198 }
5199 if ($filtre) { // TODO Support USF
5200 $sql .= " AND " . $filtre;
5201 }
5202 $sql .= " ORDER BY name";
5203
5204 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5205 $result = $this->db->query($sql);
5206 if ($result) {
5207 $num = $this->db->num_rows($result);
5208 $i = 0;
5209 if ($num) {
5210 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5211 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5212 print '<option value="-1">&nbsp;</option>';
5213 }
5214
5215 while ($i < $num) {
5216 $obj = $this->db->fetch_object($result);
5217 if ($selected == $obj->rowid) {
5218 print '<option value="' . $obj->rowid . '" selected>';
5219 } else {
5220 print '<option value="' . $obj->rowid . '">';
5221 }
5222 print trim($obj->name);
5223 if ($status == 2 && $obj->status == 1) {
5224 print ' (' . $langs->trans("Closed") . ')';
5225 }
5226 print '</option>';
5227 $i++;
5228 }
5229 print "</select>";
5230 } else {
5231 if ($status == 0) {
5232 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5233 } else {
5234 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5235 }
5236 }
5237
5238 return $num;
5239 } else {
5240 dol_print_error($this->db);
5241 return -1;
5242 }
5243 }
5244
5254 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5255 {
5256 global $langs;
5257 if ($htmlname != "none") {
5258 print '<form method="POST" action="' . $page . '">';
5259 print '<input type="hidden" name="action" value="setbankaccount">';
5260 print '<input type="hidden" name="token" value="' . newToken() . '">';
5261 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5262 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5263 if ($nbaccountfound > 0) {
5264 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5265 }
5266 print '</form>';
5267 } else {
5268 $langs->load('banks');
5269
5270 if ($selected) {
5271 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5272 $bankstatic = new Account($this->db);
5273 $result = $bankstatic->fetch($selected);
5274 if ($result) {
5275 print $bankstatic->getNomUrl(1);
5276 }
5277 } else {
5278 print "&nbsp;";
5279 }
5280 }
5281 }
5282
5283 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5284
5304 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5305 {
5306 // phpcs:enable
5307 global $conf, $langs;
5308 $langs->load("categories");
5309
5310 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5311
5312 // For backward compatibility
5313 if (is_numeric($type)) {
5314 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5315 }
5316
5317 if ($type === Categorie::TYPE_BANK_LINE) {
5318 // TODO Move this into common category feature
5319 $cate_arbo = array();
5320 $sql = "SELECT c.label, c.rowid";
5321 $sql .= " FROM " . $this->db->prefix() . "category_bank as c";
5322 $sql .= " WHERE entity = " . $conf->entity;
5323 $sql .= " ORDER BY c.label";
5324 $result = $this->db->query($sql);
5325 if ($result) {
5326 $num = $this->db->num_rows($result);
5327 $i = 0;
5328 while ($i < $num) {
5329 $objp = $this->db->fetch_object($result);
5330 if ($objp) {
5331 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5332 }
5333 $i++;
5334 }
5335 $this->db->free($result);
5336 } else {
5337 dol_print_error($this->db);
5338 }
5339 } else {
5340 $cat = new Categorie($this->db);
5341 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5342 }
5343
5344 $outarray = array();
5345 $outarrayrichhtml = array();
5346
5347
5348 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5349 if (is_array($cate_arbo)) {
5350 $num = count($cate_arbo);
5351
5352 if (!$num) {
5353 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5354 } else {
5355 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5356 $output .= '<option value="-1">&nbsp;</option>';
5357 }
5358 foreach ($cate_arbo as $key => $value) {
5359 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5360 $add = 'selected ';
5361 } else {
5362 $add = '';
5363 }
5364
5365 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5366 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5367
5368 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5369
5370 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5371
5372 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5373 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5374 $output .= '>';
5375 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5376 $output .= '</option>';
5377
5378 $cate_arbo[$key]['data-html'] = $labeltoshow;
5379 }
5380 }
5381 }
5382 $output .= '</select>';
5383 $output .= "\n";
5384
5385 if ($outputmode == 2) {
5386 // TODO: handle error when $cate_arbo is not an array
5387 return $cate_arbo;
5388 } elseif ($outputmode == 1) {
5389 return $outarray;
5390 } elseif ($outputmode == 3) {
5391 return $outarrayrichhtml;
5392 }
5393 return $output;
5394 }
5395
5396 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5397
5414 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5415 {
5416 // phpcs:enable
5417 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5418 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5419 }
5420
5448 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5449 {
5450 global $langs, $conf;
5451
5452 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5453 $formconfirm = '';
5454 $inputok = array();
5455 $inputko = array();
5456
5457 // Clean parameters
5458 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5459 if ($conf->browser->layout == 'phone') {
5460 $width = '95%';
5461 }
5462
5463 // Set height automatically if not defined
5464 if (empty($height)) {
5465 $height = 220;
5466 if (is_array($formquestion) && count($formquestion) > 2) {
5467 $height += ((count($formquestion) - 2) * 24);
5468 }
5469 }
5470
5471 if (is_array($formquestion) && !empty($formquestion)) {
5472 // First add hidden fields and value
5473 foreach ($formquestion as $key => $input) {
5474 if (is_array($input) && !empty($input)) {
5475 if ($input['type'] == 'hidden') {
5476 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5477 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5478
5479 $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";
5480 }
5481 }
5482 }
5483
5484 // Now add questions
5485 $moreonecolumn = '';
5486 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5487 foreach ($formquestion as $key => $input) {
5488 if (is_array($input) && !empty($input)) {
5489 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5490 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5491 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5492
5493 if ($input['type'] == 'text') {
5494 $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";
5495 } elseif ($input['type'] == 'password') {
5496 $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";
5497 } elseif ($input['type'] == 'textarea') {
5498 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5499 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5500 $more .= $input['value'];
5501 $more .= '</textarea>';
5502 $more .= '</div></div>'."\n";*/
5503 $moreonecolumn .= '<div class="margintoponly">';
5504 $moreonecolumn .= $input['label'] . '<br>';
5505 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5506 $moreonecolumn .= $input['value'];
5507 $moreonecolumn .= '</textarea>';
5508 $moreonecolumn .= '</div>';
5509 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5510 if (empty($morecss)) {
5511 $morecss = 'minwidth100';
5512 }
5513
5514 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5515 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5516 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5517 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5518 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5519 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5520 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5521
5522 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5523 if (!empty($input['label'])) {
5524 $more .= $input['label'] . '</div><div class="tagtd left">';
5525 }
5526 if ($input['type'] == 'select') {
5527 $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);
5528 } else {
5529 $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);
5530 }
5531 $more .= '</div></div>' . "\n";
5532 } elseif ($input['type'] == 'checkbox') {
5533 $more .= '<div class="tagtr">';
5534 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5535 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5536 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5537 $more .= ' checked';
5538 }
5539 if (is_bool($input['value']) && $input['value']) {
5540 $more .= ' checked';
5541 }
5542 if (isset($input['disabled'])) {
5543 $more .= ' disabled';
5544 }
5545 $more .= ' /></div>';
5546 $more .= '</div>' . "\n";
5547 } elseif ($input['type'] == 'radio') {
5548 $i = 0;
5549 foreach ($input['values'] as $selkey => $selval) {
5550 $more .= '<div class="tagtr">';
5551 if (isset($input['label'])) {
5552 if ($i == 0) {
5553 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5554 } else {
5555 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5556 }
5557 }
5558 $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;
5559 if (!empty($input['disabled'])) {
5560 $more .= ' disabled';
5561 }
5562 if (isset($input['default']) && $input['default'] === $selkey) {
5563 $more .= ' checked="checked"';
5564 }
5565 $more .= ' /> ';
5566 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5567 $more .= '</div></div>' . "\n";
5568 $i++;
5569 }
5570 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5571 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5572 $more .= '<div class="tagtd">';
5573 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5574 $h = $m = 0;
5575 if ($input['type'] == 'datetime') {
5576 $h = isset($input['hours']) ? $input['hours'] : 1;
5577 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5578 }
5579 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5580 $more .= '</div></div>'."\n";
5581 $formquestion[] = array('name' => $input['name'].'day');
5582 $formquestion[] = array('name' => $input['name'].'month');
5583 $formquestion[] = array('name' => $input['name'].'year');
5584 $formquestion[] = array('name' => $input['name'].'hour');
5585 $formquestion[] = array('name' => $input['name'].'min');
5586 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5587 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5588 if (!empty($input['label'])) {
5589 $more .= $input['label'] . '</div><div class="tagtd">';
5590 }
5591 $more .= $input['value'];
5592 $more .= '</div></div>' . "\n";
5593 } elseif ($input['type'] == 'onecolumn') {
5594 $moreonecolumn .= '<div class="margintoponly">';
5595 $moreonecolumn .= $input['value'];
5596 $moreonecolumn .= '</div>' . "\n";
5597 } elseif ($input['type'] == 'hidden') {
5598 // Do nothing more, already added by a previous loop
5599 } elseif ($input['type'] == 'separator') {
5600 $more .= '<br>';
5601 } else {
5602 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5603 }
5604 }
5605 }
5606 $more .= '</div>' . "\n";
5607 $more .= $moreonecolumn;
5608 }
5609
5610 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5611 // 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
5612 // See page product/card.php for example
5613 if (!empty($conf->dol_use_jmobile)) {
5614 $useajax = 0;
5615 }
5616 if (empty($conf->use_javascript_ajax)) {
5617 $useajax = 0;
5618 }
5619
5620 if ($useajax) {
5621 $autoOpen = true;
5622 $dialogconfirm = 'dialog-confirm';
5623 $button = '';
5624 if (!is_numeric($useajax)) {
5625 $button = $useajax;
5626 $useajax = 1;
5627 $autoOpen = false;
5628 $dialogconfirm .= '-' . $button;
5629 }
5630 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5631 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5632
5633 // Add input fields into list of fields to read during submit (inputok and inputko)
5634 if (is_array($formquestion)) {
5635 foreach ($formquestion as $key => $input) {
5636 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5637 // Add name of fields to propagate with the GET when submitting the form with button OK.
5638 if (is_array($input) && isset($input['name'])) {
5639 if (strpos($input['name'], ',') > 0) {
5640 $inputok = array_merge($inputok, explode(',', $input['name']));
5641 } else {
5642 array_push($inputok, $input['name']);
5643 }
5644 }
5645 // Add name of fields to propagate with the GET when submitting the form with button KO.
5646 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5647 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5648 array_push($inputko, $input['name']);
5649 }
5650 }
5651 }
5652
5653 // Show JQuery confirm box.
5654 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5655 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5656 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5657 }
5658 if (!empty($more)) {
5659 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5660 }
5661 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5662 $formconfirm .= '</div>' . "\n";
5663
5664 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5665 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5666 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5667 $formconfirm .= 'jQuery(document).ready(function() {
5668 $(function() {
5669 $( "#' . $dialogconfirm . '" ).dialog(
5670 {
5671 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5672 if ($newselectedchoice == 'no') {
5673 $formconfirm .= '
5674 open: function() {
5675 $(this).parent().find("button.ui-button:eq(2)").focus();
5676 },';
5677 }
5678
5679 $jsforcursor = '';
5680 if ($useajax == 1) {
5681 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5682 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5683 }
5684
5685 $postconfirmas = 'GET';
5686
5687 $formconfirm .= '
5688 resizable: false,
5689 height: "' . $height . '",
5690 width: "' . $width . '",
5691 modal: true,
5692 closeOnEscape: false,
5693 buttons: {
5694 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5695 var options = "token=' . urlencode(newToken()) . '";
5696 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5697 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5698 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5699
5700 if (inputok.length > 0) {
5701 $.each(inputok, function(i, inputname) {
5702 var more = "";
5703 var inputvalue;
5704 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5705 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5706 } else {
5707 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5708 inputvalue = $("#" + inputname + more).val();
5709 }
5710 if (typeof inputvalue == "undefined") { inputvalue=""; }
5711 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5712 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5713 });
5714 }
5715 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5716 if (pageyes.length > 0) {';
5717 if ($postconfirmas == 'GET') {
5718 $formconfirm .= 'location.href = urljump;';
5719 } else {
5720 $formconfirm .= $jsforcursor;
5721 $formconfirm .= 'var post = $.post(
5722 pageyes,
5723 options,
5724 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5725 );';
5726 }
5727 $formconfirm .= '
5728 console.log("after post ok");
5729 }
5730 $(this).dialog("close");
5731 },
5732 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5733 var options = "token=' . urlencode(newToken()) . '";
5734 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5735 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5736 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5737 if (inputko.length > 0) {
5738 $.each(inputko, function(i, inputname) {
5739 var more = "";
5740 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5741 var inputvalue = $("#" + inputname + more).val();
5742 if (typeof inputvalue == "undefined") { inputvalue=""; }
5743 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5744 });
5745 }
5746 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5747 //alert(urljump);
5748 if (pageno.length > 0) {';
5749 if ($postconfirmas == 'GET') {
5750 $formconfirm .= 'location.href = urljump;';
5751 } else {
5752 $formconfirm .= $jsforcursor;
5753 $formconfirm .= 'var post = $.post(
5754 pageno,
5755 options,
5756 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5757 );';
5758 }
5759 $formconfirm .= '
5760 console.log("after post ko");
5761 }
5762 $(this).dialog("close");
5763 }
5764 }
5765 }
5766 );
5767
5768 var button = "' . $button . '";
5769 if (button.length > 0) {
5770 $( "#" + button ).click(function() {
5771 $("#' . $dialogconfirm . '").dialog("open");
5772 });
5773 }
5774 });
5775 });
5776 </script>';
5777 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5778 } else {
5779 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5780
5781 if (empty($disableformtag)) {
5782 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftroright">' . "\n";
5783 }
5784
5785 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5786 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5787
5788 $formconfirm .= '<table class="valid centpercent">' . "\n";
5789
5790 // Line title
5791 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5792 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5793 $formconfirm .= '</td></tr>' . "\n";
5794
5795 // Line text
5796 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5797 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5798 }
5799
5800 // Line form fields
5801 if ($more) {
5802 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5803 $formconfirm .= $more;
5804 $formconfirm .= '</td></tr>' . "\n";
5805 }
5806
5807 // Line with question
5808 $formconfirm .= '<tr class="valid">';
5809 $formconfirm .= '<td class="valid">' . $question . '</td>';
5810 $formconfirm .= '<td class="valid center">';
5811 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5812 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5813 $formconfirm .= '</td>';
5814 $formconfirm .= '</tr>' . "\n";
5815
5816 $formconfirm .= '</table>' . "\n";
5817
5818 if (empty($disableformtag)) {
5819 $formconfirm .= "</form>\n";
5820 }
5821 $formconfirm .= '<br>';
5822
5823 if (!empty($conf->use_javascript_ajax)) {
5824 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5825 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5826 $formconfirm .= '
5827 $(document).ready(function () {
5828 $(".confirmvalidatebutton").on("click", function() {
5829 console.log("We click on button confirmvalidatebutton");
5830 $(this).attr("disabled", "disabled");
5831 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5832 //console.log($(this).closest("form"));
5833 $(this).closest("form").submit();
5834 });
5835 });
5836 ';
5837 $formconfirm .= '</script>' . "\n";
5838 }
5839
5840 $formconfirm .= "<!-- end formconfirm -->\n";
5841 }
5842
5843 return $formconfirm;
5844 }
5845
5846
5847 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5848
5864 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5865 {
5866 // phpcs:enable
5867 global $langs;
5868
5869 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
5870 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
5871
5872 $out = '';
5873
5874 $formproject = new FormProjets($this->db);
5875
5876 $langs->load("project");
5877 if ($htmlname != "none") {
5878 $out .= '<form method="post" action="' . $page . '">';
5879 $out .= '<input type="hidden" name="action" value="classin">';
5880 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5881 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5882 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5883 $out .= '</form>';
5884 } else {
5885 $out .= '<span class="project_head_block">';
5886 if ($selected) {
5887 $projet = new Project($this->db);
5888 $projet->fetch($selected);
5889 $out .= $projet->getNomUrl(0, '', 1);
5890 } else {
5891 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
5892 }
5893 $out .= '</span>';
5894 }
5895
5896 if (empty($nooutput)) {
5897 print $out;
5898 return '';
5899 }
5900 return $out;
5901 }
5902
5903 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5904
5920 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5921 {
5922 // phpcs:enable
5923 global $langs;
5924
5925 $out = '';
5926
5927 if ($htmlname != "none") {
5928 $out .= '<form method="POST" action="' . $page . '">';
5929 $out .= '<input type="hidden" name="action" value="setconditions">';
5930 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5931 if ($type) {
5932 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5933 }
5934 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5935 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5936 $out .= '</form>';
5937 } else {
5938 if ($selected) {
5940 if (isset($this->cache_conditions_paiements[$selected])) {
5941 $label = $this->cache_conditions_paiements[$selected]['label'];
5942
5943 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5944 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5945 }
5946
5947 $out .= $label;
5948 } else {
5949 $langs->load('errors');
5950 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
5951 }
5952 } else {
5953 $out .= '&nbsp;';
5954 }
5955 }
5956
5957 if (empty($nooutput)) {
5958 print $out;
5959 return '';
5960 }
5961 return $out;
5962 }
5963
5964 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5965
5975 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5976 {
5977 // phpcs:enable
5978 global $langs;
5979 if ($htmlname != "none") {
5980 print '<form method="post" action="' . $page . '">';
5981 print '<input type="hidden" name="action" value="setavailability">';
5982 print '<input type="hidden" name="token" value="' . newToken() . '">';
5983 $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5984 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5985 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
5986 print '</form>';
5987 } else {
5988 if ($selected) {
5989 $this->load_cache_availability();
5990 print $this->cache_availability[$selected]['label'];
5991 } else {
5992 print "&nbsp;";
5993 }
5994 }
5995 }
5996
6007 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
6008 {
6009 global $langs;
6010 if ($htmlname != "none") {
6011 print '<form method="post" action="' . $page . '">';
6012 print '<input type="hidden" name="action" value="setdemandreason">';
6013 print '<input type="hidden" name="token" value="' . newToken() . '">';
6014 $this->selectInputReason($selected, $htmlname, -1, $addempty);
6015 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6016 print '</form>';
6017 } else {
6018 if ($selected) {
6019 $this->loadCacheInputReason();
6020 foreach ($this->cache_demand_reason as $key => $val) {
6021 if ($val['id'] == $selected) {
6022 print $val['label'];
6023 break;
6024 }
6025 }
6026 } else {
6027 print "&nbsp;";
6028 }
6029 }
6030 }
6031
6032 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6033
6047 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6048 {
6049 // phpcs:enable
6050 global $langs;
6051
6052 $ret = '';
6053
6054 if ($htmlname != "none") {
6055 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6056 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6057 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6058 if ($type) {
6059 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6060 }
6061 $ret .= '<table class="nobordernopadding">';
6062 $ret .= '<tr><td>';
6063 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6064 $ret .= '</td>';
6065 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6066 $ret .= '</tr></table></form>';
6067 } else {
6068 if ($displayhour) {
6069 $ret .= dol_print_date($selected, 'dayhour');
6070 } else {
6071 $ret .= dol_print_date($selected, 'day');
6072 }
6073 }
6074
6075 if (empty($nooutput)) {
6076 print $ret;
6077 }
6078 return $ret;
6079 }
6080
6081
6082 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6083
6094 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6095 {
6096 // phpcs:enable
6097 global $langs;
6098
6099 if ($htmlname != "none") {
6100 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6101 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6102 print '<input type="hidden" name="token" value="' . newToken() . '">';
6103 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6104 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6105 print '</form>';
6106 } else {
6107 if ($selected) {
6108 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6109 $theuser = new User($this->db);
6110 $theuser->fetch($selected);
6111 print $theuser->getNomUrl(1);
6112 } else {
6113 print "&nbsp;";
6114 }
6115 }
6116 }
6117
6118
6119 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6120
6134 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6135 {
6136 // phpcs:enable
6137 global $langs;
6138
6139 $out = '';
6140 if ($htmlname != "none") {
6141 $out .= '<form method="POST" action="' . $page . '">';
6142 $out .= '<input type="hidden" name="action" value="setmode">';
6143 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6144 if ($type) {
6145 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6146 }
6147 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6148 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6149 $out .= '</form>';
6150 } else {
6151 if ($selected) {
6153 $out .= $this->cache_types_paiements[$selected]['label'];
6154 } else {
6155 $out .= "&nbsp;";
6156 }
6157 }
6158
6159 if ($nooutput) {
6160 return $out;
6161 } else {
6162 print $out;
6163 }
6164 return '';
6165 }
6166
6177 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6178 {
6179 global $langs;
6180 if ($htmlname != "none") {
6181 print '<form method="POST" action="' . $page . '">';
6182 print '<input type="hidden" name="action" value="settransportmode">';
6183 print '<input type="hidden" name="token" value="' . newToken() . '">';
6184 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6185 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6186 print '</form>';
6187 } else {
6188 if ($selected) {
6190 print $this->cache_transport_mode[$selected]['label'];
6191 } else {
6192 print "&nbsp;";
6193 }
6194 }
6195 }
6196
6197 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6198
6207 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6208 {
6209 // phpcs:enable
6210 global $langs;
6211 if ($htmlname != "none") {
6212 print '<form method="POST" action="' . $page . '">';
6213 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6214 print '<input type="hidden" name="token" value="' . newToken() . '">';
6215 print $this->selectMultiCurrency($selected, $htmlname, 0);
6216 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6217 print '</form>';
6218 } else {
6219 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6220 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6221 }
6222 }
6223
6224 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6225
6235 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6236 {
6237 // phpcs:enable
6238 global $langs, $mysoc, $conf;
6239
6240 if ($htmlname != "none") {
6241 print '<form method="POST" action="' . $page . '">';
6242 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6243 print '<input type="hidden" name="token" value="' . newToken() . '">';
6244 print '<input type="text" class="maxwidth100" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6245 print '<select name="calculation_mode">';
6246 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6247 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6248 print '</select> ';
6249 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6250 print '</form>';
6251 } else {
6252 if (!empty($rate)) {
6253 print price($rate, 1, $langs, 0, 0);
6254 if ($currency && $rate != 1) {
6255 print ' &nbsp; (' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')';
6256 }
6257 } else {
6258 print 1;
6259 }
6260 }
6261 }
6262
6263
6264 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6265
6281 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6282 {
6283 // phpcs:enable
6284 global $conf, $langs;
6285 if ($htmlname != "none") {
6286 print '<form method="post" action="' . $page . '">';
6287 print '<input type="hidden" name="action" value="setabsolutediscount">';
6288 print '<input type="hidden" name="token" value="' . newToken() . '">';
6289 print '<div class="inline-block">';
6290 if (!empty($discount_type)) {
6291 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6292 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6293 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6294 } else {
6295 $translationKey = 'HasCreditNoteFromSupplier';
6296 }
6297 } else {
6298 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6299 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6300 } else {
6301 $translationKey = 'HasCreditNoteFromSupplier';
6302 }
6303 }
6304 } else {
6305 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6306 if (!$filter || $filter == "fk_facture_source IS NULL") {
6307 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6308 } else {
6309 $translationKey = 'CompanyHasCreditNote';
6310 }
6311 } else {
6312 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6313 $translationKey = 'CompanyHasAbsoluteDiscount';
6314 } else {
6315 $translationKey = 'CompanyHasCreditNote';
6316 }
6317 }
6318 }
6319 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6320 if (empty($hidelist)) {
6321 print ' ';
6322 }
6323 print '</div>';
6324 if (empty($hidelist)) {
6325 print '<div class="inline-block" style="padding-right: 10px">';
6326 $newfilter = 'discount_type=' . intval($discount_type);
6327 if (!empty($discount_type)) {
6328 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6329 } else {
6330 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6331 }
6332 if ($filter) {
6333 $newfilter .= ' AND (' . $filter . ')';
6334 }
6335 // output the combo of discounts
6336 $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
6337 if ($nbqualifiedlines > 0) {
6338 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6339 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6340 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6341 }
6342 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6343 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6344 }
6345
6346 print '>';
6347 }
6348 print '</div>';
6349 }
6350 if ($more) {
6351 print '<div class="inline-block">';
6352 print $more;
6353 print '</div>';
6354 }
6355 print '</form>';
6356 } else {
6357 if ($selected) {
6358 print $selected;
6359 } else {
6360 print "0";
6361 }
6362 }
6363 }
6364
6365
6366 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6367
6377 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6378 {
6379 // phpcs:enable
6380 global $langs;
6381
6382 if ($htmlname != "none") {
6383 print '<form method="post" action="' . $page . '">';
6384 print '<input type="hidden" name="action" value="set_contact">';
6385 print '<input type="hidden" name="token" value="' . newToken() . '">';
6386 print '<table class="nobordernopadding">';
6387 print '<tr><td>';
6388 print $this->selectcontacts($societe->id, $selected, $htmlname);
6389 $num = $this->num;
6390 if ($num == 0) {
6391 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6392 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&amp;action=create&amp;backtoreferer=1">' . $addcontact . '</a>';
6393 }
6394 print '</td>';
6395 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6396 print '</tr></table></form>';
6397 } else {
6398 if ($selected) {
6399 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6400 $contact = new Contact($this->db);
6401 $contact->fetch($selected);
6402 print $contact->getFullName($langs);
6403 } else {
6404 print "&nbsp;";
6405 }
6406 }
6407 }
6408
6409 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6410
6427 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6428 {
6429 // phpcs:enable
6430 global $langs;
6431
6432 $out = '';
6433 if ($htmlname != "none") {
6434 $out .= '<form method="post" action="' . $page . '">';
6435 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6436 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6437 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6438 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6439 $out .= '</form>';
6440 } else {
6441 if ($selected) {
6442 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6443 $soc = new Societe($this->db);
6444 $soc->fetch($selected);
6445 $out .= $soc->getNomUrl(0, '');
6446 } else {
6447 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6448 }
6449 }
6450
6451 if ($nooutput) {
6452 return $out;
6453 } else {
6454 print $out;
6455 }
6456
6457 return '';
6458 }
6459
6460 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6461
6470 public function select_currency($selected = '', $htmlname = 'currency_id')
6471 {
6472 // phpcs:enable
6473 print $this->selectCurrency($selected, $htmlname);
6474 }
6475
6485 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6486 {
6487 global $langs, $user;
6488
6489 $langs->loadCacheCurrencies('');
6490
6491 $out = '';
6492
6493 if ($selected == 'euro' || $selected == 'euros') {
6494 $selected = 'EUR'; // Pour compatibilite
6495 }
6496
6497 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6498 if ($useempty) {
6499 $out .= '<option value="-1" selected></option>';
6500 }
6501 foreach ($langs->cache_currencies as $code_iso => $currency) {
6502 $labeltoshow = $currency['label'];
6503 if ($mode == 1) {
6504 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6505 } else {
6506 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6507 }
6508
6509 if ($selected && $selected == $code_iso) {
6510 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6511 } else {
6512 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6513 }
6514 $out .= $labeltoshow;
6515 $out .= '</option>';
6516 }
6517 $out .= '</select>';
6518 if ($user->admin) {
6519 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6520 }
6521
6522 // Make select dynamic
6523 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6524 $out .= ajax_combobox($htmlname);
6525
6526 return $out;
6527 }
6528
6541 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6542 {
6543 global $conf, $langs;
6544
6545 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6546
6547 $TCurrency = array();
6548
6549 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6550 $sql .= " WHERE entity IN ('" . getEntity('mutlicurrency') . "')";
6551 if ($filter) {
6552 $sql .= " AND " . $filter;
6553 }
6554 $resql = $this->db->query($sql);
6555 if ($resql) {
6556 while ($obj = $this->db->fetch_object($resql)) {
6557 $TCurrency[$obj->code] = $obj->code;
6558 }
6559 }
6560
6561 $out = '';
6562 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6563 if ($useempty) {
6564 $out .= '<option value="">&nbsp;</option>';
6565 }
6566 // If company current currency not in table, we add it into list. Should always be available.
6567 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6568 $TCurrency[$conf->currency] = $conf->currency;
6569 }
6570 if (count($TCurrency) > 0) {
6571 foreach ($langs->cache_currencies as $code_iso => $currency) {
6572 if (isset($TCurrency[$code_iso])) {
6573 if (!empty($selected) && $selected == $code_iso) {
6574 $out .= '<option value="' . $code_iso . '" selected="selected">';
6575 } else {
6576 $out .= '<option value="' . $code_iso . '">';
6577 }
6578
6579 $out .= $currency['label'];
6580 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6581 $out .= '</option>';
6582 }
6583 }
6584 }
6585
6586 $out .= '</select>';
6587
6588 // Make select dynamic
6589 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6590 $out .= ajax_combobox($htmlname);
6591
6592 return $out;
6593 }
6594
6595 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6596
6603 public function load_cache_vatrates($country_code)
6604 {
6605 // phpcs:enable
6606 global $langs, $user;
6607
6608 $num = count($this->cache_vatrates);
6609 if ($num > 0) {
6610 return $num; // Cache already loaded
6611 }
6612
6613 dol_syslog(__METHOD__, LOG_DEBUG);
6614
6615 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6616 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6617 $sql .= " WHERE t.fk_pays = c.rowid";
6618 $sql .= " AND t.active > 0";
6619 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6620 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6621 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6622
6623 $resql = $this->db->query($sql);
6624 if ($resql) {
6625 $num = $this->db->num_rows($resql);
6626 if ($num) {
6627 for ($i = 0; $i < $num; $i++) {
6628 $obj = $this->db->fetch_object($resql);
6629
6630 $tmparray = array();
6631 $tmparray['rowid'] = $obj->rowid;
6632 $tmparray['type_vat'] = $obj->type_vat;
6633 $tmparray['code'] = $obj->code;
6634 $tmparray['txtva'] = $obj->taux;
6635 $tmparray['nprtva'] = $obj->recuperableonly;
6636 $tmparray['localtax1'] = $obj->localtax1;
6637 $tmparray['localtax1_type'] = $obj->localtax1_type;
6638 $tmparray['localtax2'] = $obj->localtax2;
6639 $tmparray['localtax2_type'] = $obj->localtax1_type;
6640 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6641 $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
6642 $positiverates = '';
6643 if ($obj->taux) {
6644 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6645 }
6646 if ($obj->localtax1) {
6647 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6648 }
6649 if ($obj->localtax2) {
6650 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6651 }
6652 if (empty($positiverates)) {
6653 $positiverates = '0';
6654 }
6655 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6656
6657 $this->cache_vatrates[$obj->rowid] = $tmparray;
6658 }
6659
6660 return $num;
6661 } else {
6662 $this->error = '<span class="error">';
6663 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6664 $reg = array();
6665 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6666 $langs->load("errors");
6667 $new_country_code = $reg[1];
6668 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid');
6669 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6670 }
6671 $this->error .= '</span>';
6672 return -1;
6673 }
6674 } else {
6675 $this->error = '<span class="error">' . $this->db->error() . '</span>';
6676 return -2;
6677 }
6678 }
6679
6680 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6681
6704 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)
6705 {
6706 // phpcs:enable
6707 global $langs, $mysoc;
6708
6709 $langs->load('errors');
6710
6711 $return = '';
6712
6713 // Define defaultnpr, defaultttx and defaultcode
6714 $defaultnpr = ($info_bits & 0x01);
6715 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6716 $defaulttx = str_replace('*', '', $selectedrate);
6717 $defaultcode = '';
6718 $reg = array();
6719 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6720 $defaultcode = $reg[1];
6721 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6722 }
6723 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6724
6725 // Check parameters
6726 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6727 if ($societe_vendeuse->id == $mysoc->id) {
6728 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6729 } else {
6730 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6731 }
6732 return $return;
6733 }
6734
6735 //var_dump($societe_acheteuse);
6736 //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";
6737 //exit;
6738
6739 // Define list of countries to use to search VAT rates to show
6740 // First we defined code_country to use to find list
6741 if (is_object($societe_vendeuse)) {
6742 $code_country = "'" . $societe_vendeuse->country_code . "'";
6743 } else {
6744 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6745 }
6746 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
6747 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6748 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
6749 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
6750 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
6751 if (isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
6752 // We also add the buyer country code
6753 if (is_numeric($type)) {
6754 if ($type == 1) { // We know product is a service
6755 switch ($selectVatComboMode) {
6756 case '1':
6757 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6758 break;
6759 case '2':
6760 $code_country = "'" . $societe_acheteuse->country_code . "'";
6761 break;
6762 }
6763 }
6764 } elseif (!$idprod) { // We don't know type of product
6765 switch ($selectVatComboMode) {
6766 case '1':
6767 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6768 break;
6769 case '2':
6770 $code_country = "'" . $societe_acheteuse->country_code . "'";
6771 break;
6772 }
6773 } else {
6774 $prodstatic = new Product($this->db);
6775 $prodstatic->fetch($idprod);
6776 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6777 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6778 }
6779 }
6780 }
6781 }
6782
6783 // Now we load the list of VAT
6784 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6785
6786 // Keep only the VAT qualified for $type_vat
6787 $arrayofvatrates = array();
6788 foreach ($this->cache_vatrates as $cachevalue) {
6789 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] != $type_vat) {
6790 $arrayofvatrates[] = $cachevalue;
6791 }
6792 }
6793
6794 $num = count($arrayofvatrates);
6795
6796 if ($num > 0) {
6797 // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6798 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6799 $tmpthirdparty = new Societe($this->db);
6800
6801 $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6802 $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6803
6804 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6805 $defaultcode = $reg[1];
6806 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6807 }
6808 if (empty($defaulttx)) {
6809 $defaultnpr = 0;
6810 }
6811 }
6812
6813 // If we fails to find a default vat rate, we take the last one in list
6814 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
6815 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6816 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6817 // We take the last one found in list
6818 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
6819 } else {
6820 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
6821 $defaulttx = '';
6822 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6823 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
6824 }
6825 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6826 $defaultcode = $reg[1];
6827 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6828 }
6829 }
6830 }
6831
6832 // Disabled if seller is not subject to VAT
6833 $disabled = false;
6834 $title = '';
6835 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6836 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6837 // of using supplier invoices (this is a very bad idea !)
6838 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
6839 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
6840 $disabled = true;
6841 }
6842 }
6843
6844 if (!$options_only) {
6845 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
6846 }
6847
6848 $selectedfound = false;
6849 foreach ($arrayofvatrates as $rate) {
6850 // Keep only 0 if seller is not subject to VAT
6851 if ($disabled && $rate['txtva'] != 0) {
6852 continue;
6853 }
6854
6855 // Define key to use into select list
6856 $key = $rate['txtva'];
6857 $key .= $rate['nprtva'] ? '*' : '';
6858 if ($mode > 0 && $rate['code']) {
6859 $key .= ' (' . $rate['code'] . ')';
6860 }
6861 if ($mode < 0) {
6862 $key = $rate['rowid'];
6863 }
6864
6865 $return .= '<option value="' . $key . '"';
6866 if (!$selectedfound) {
6867 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6868 if ($defaultcode == $rate['code']) {
6869 $return .= ' selected';
6870 $selectedfound = true;
6871 }
6872 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6873 $return .= ' selected';
6874 $selectedfound = true;
6875 }
6876 }
6877 $return .= '>';
6878
6879 // Show label of VAT
6880 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
6881 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
6882 $return .= $rate['labelpositiverates'];
6883 } else {
6884 // Simple label
6885 $return .= vatrate($rate['label']);
6886 }
6887
6888 //$return.=($rate['code']?' '.$rate['code']:'');
6889 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
6890
6891 $return .= '</option>';
6892 }
6893
6894 if (!$options_only) {
6895 $return .= '</select>';
6896 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
6897 }
6898 } else {
6899 $return .= $this->error;
6900 }
6901
6902 $this->num = $num;
6903 return $return;
6904 }
6905
6906
6907 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6908
6933 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 = '')
6934 {
6935 // phpcs:enable
6936 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
6937 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
6938 if (!empty($nooutput)) {
6939 return $retstring;
6940 }
6941 print $retstring;
6942
6943 return '';
6944 }
6945
6961 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
6962 {
6963 global $langs;
6964
6965 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6966 if ($forcenewline) {
6967 $ret .= '<br>';
6968 }
6969 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6970 return $ret;
6971 }
6972
7000 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')
7001 {
7002 global $conf, $langs;
7003
7004 if ($gm === 'auto') {
7005 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7006 }
7007
7008 $retstring = '';
7009
7010 if ($prefix == '') {
7011 $prefix = 're';
7012 }
7013 if ($h == '') {
7014 $h = 0;
7015 }
7016 if ($m == '') {
7017 $m = 0;
7018 }
7019 $emptydate = 0;
7020 $emptyhours = 0;
7021 if ($stepminutes <= 0 || $stepminutes > 30) {
7022 $stepminutes = 1;
7023 }
7024 if ($empty == 1) {
7025 $emptydate = 1;
7026 $emptyhours = 1;
7027 }
7028 if ($empty == 2) {
7029 $emptydate = 0;
7030 $emptyhours = 1;
7031 }
7032 $orig_set_time = $set_time;
7033
7034 if ($set_time === '' && $emptydate == 0) {
7035 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7036 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7037 $set_time = dol_now($gm);
7038 } else {
7039 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7040 }
7041 }
7042
7043 // Analysis of the pre-selection date
7044 $reg = array();
7045 $shour = '';
7046 $smin = '';
7047 $ssec = '';
7048 if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
7049 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7050 $syear = (!empty($reg[1]) ? $reg[1] : '');
7051 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7052 $sday = (!empty($reg[3]) ? $reg[3] : '');
7053 $shour = (!empty($reg[4]) ? $reg[4] : '');
7054 $smin = (!empty($reg[5]) ? $reg[5] : '');
7055 } elseif (strval($set_time) != '' && $set_time != -1) {
7056 // set_time est un timestamps (0 possible)
7057 $syear = dol_print_date($set_time, "%Y", $gm);
7058 $smonth = dol_print_date($set_time, "%m", $gm);
7059 $sday = dol_print_date($set_time, "%d", $gm);
7060 if ($orig_set_time != '') {
7061 $shour = dol_print_date($set_time, "%H", $gm);
7062 $smin = dol_print_date($set_time, "%M", $gm);
7063 $ssec = dol_print_date($set_time, "%S", $gm);
7064 }
7065 } else {
7066 // Date est '' ou vaut -1
7067 $syear = '';
7068 $smonth = '';
7069 $sday = '';
7070 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7071 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7072 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7073 }
7074 if ($h == 3 || $h == 4) {
7075 $shour = '';
7076 }
7077 if ($m == 3) {
7078 $smin = '';
7079 }
7080
7081 $nowgmt = dol_now('gmt');
7082 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7083
7084 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7085 $usecalendar = 'combo';
7086 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7087 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
7088 }
7089 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7090 // If we use a text browser or screen reader, we use the 'combo' date selector
7091 $usecalendar = 'html';
7092 }
7093
7094 if ($d) {
7095 // Show date with popup
7096 if ($usecalendar != 'combo') {
7097 $formated_date = '';
7098 //print "e".$set_time." t ".$conf->format_date_short;
7099 if (strval($set_time) != '' && $set_time != -1) {
7100 //$formated_date=dol_print_date($set_time,$conf->format_date_short);
7101 $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7102 }
7103
7104 // Calendrier popup version eldy
7105 if ($usecalendar == "eldy") {
7106 // Input area to enter date manually
7107 $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formated_date . '"';
7108 $retstring .= ($disabled ? ' disabled' : '');
7109 $retstring .= ' onChange="dpChangeDay(\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7110 $retstring .= ' autocomplete="off">';
7111
7112 // Icon calendar
7113 $retstringbuttom = '';
7114 if (!$disabled) {
7115 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7116 $base = DOL_URL_ROOT . '/core/';
7117 $retstringbuttom .= ' onClick="showDP(\'' . $base . '\',\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\',\'' . $langs->defaultlang . '\');"';
7118 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
7119 } else {
7120 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7121 }
7122 $retstring = $retstringbuttom . $retstring;
7123
7124 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7125 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7126 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7127 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7128 if (!$disabled && $usecalendar != 'html') {
7129 // Output javascript for datepicker
7130 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7131 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7132
7133 $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
7134 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7135 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7136 autoclose: true,
7137 todayHighlight: true,
7138 yearRange: '" . $minYear . ":" . $maxYear . "',";
7139 if (!empty($conf->dol_use_jmobile)) {
7140 $retstring .= "
7141 beforeShow: function (input, datePicker) {
7142 input.disabled = true;
7143 },
7144 onClose: function (dateText, datePicker) {
7145 this.disabled = false;
7146 },
7147 ";
7148 }
7149 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7150 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7151 $retstring .= "
7152 showOn: 'button', /* both has problem with autocompletion */
7153 buttonImage: '" . DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png',
7154 buttonImageOnly: true";
7155 }
7156 $retstring .= "
7157 }) });";
7158 $retstring .= "</script>";
7159 }
7160
7161 // Input area to enter date manually
7162 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7163 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate center" maxlength="11" value="'.$formated_date.'"';
7164 $retstring .= ($disabled ? ' disabled' : '');
7165 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7166 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7167 $retstring .= ' autocomplete="off">';
7168
7169 // Icone calendrier
7170 if ($disabled) {
7171 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7172 $retstring = $retstringbutton . $retstring;
7173 }
7174
7175 $retstring .= '</div>';
7176 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7177 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7178 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7179 } else {
7180 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7181 }
7182 } else {
7183 // Show date with combo selects
7184 // Day
7185 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7186
7187 if ($emptydate || $set_time == -1) {
7188 $retstring .= '<option value="0" selected>&nbsp;</option>';
7189 }
7190
7191 for ($day = 1; $day <= 31; $day++) {
7192 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7193 }
7194
7195 $retstring .= "</select>";
7196
7197 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7198 if ($emptydate || $set_time == -1) {
7199 $retstring .= '<option value="0" selected>&nbsp;</option>';
7200 }
7201
7202 // Month
7203 for ($month = 1; $month <= 12; $month++) {
7204 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7205 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7206 $retstring .= "</option>";
7207 }
7208 $retstring .= "</select>";
7209
7210 // Year
7211 if ($emptydate || $set_time == -1) {
7212 $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 . '">';
7213 } else {
7214 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7215
7216 $syear = (int) $syear;
7217 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7218 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7219 }
7220 $retstring .= "</select>\n";
7221 }
7222 }
7223 }
7224
7225 if ($d && $h) {
7226 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7227 $retstring .= '<span class="nowraponall">';
7228 }
7229
7230 if ($h) {
7231 $hourstart = 0;
7232 $hourend = 24;
7233 if ($openinghours != '') {
7234 $openinghours = explode(',', $openinghours);
7235 $hourstart = $openinghours[0];
7236 $hourend = $openinghours[1];
7237 if ($hourend < $hourstart) {
7238 $hourend = $hourstart;
7239 }
7240 }
7241 // Show hour
7242 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7243 if ($emptyhours) {
7244 $retstring .= '<option value="-1">&nbsp;</option>';
7245 }
7246 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7247 if (strlen($hour) < 2) {
7248 $hour = "0" . $hour;
7249 }
7250 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7251 //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
7252 $retstring .= '</option>';
7253 }
7254 $retstring .= '</select>';
7255 //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
7256 if ($m) {
7257 $retstring .= ":";
7258 }
7259 }
7260
7261 if ($m) {
7262 // Show minutes
7263 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7264 if ($emptyhours) {
7265 $retstring .= '<option value="-1">&nbsp;</option>';
7266 }
7267 for ($min = 0; $min < 60; $min += $stepminutes) {
7268 $min_str = sprintf("%02d", $min);
7269 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7270 }
7271 $retstring .= '</select>';
7272
7273 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7274 }
7275
7276 if ($d && $h) {
7277 $retstring .= '</span>';
7278 }
7279
7280 // Add a "Now" link
7281 if (!empty($conf->use_javascript_ajax) && $addnowlink) {
7282 // Script which will be inserted in the onClick of the "Now" link
7283 $reset_scripts = "";
7284 if ($addnowlink == 2) { // local computer time
7285 // pad add leading 0 on numbers
7286 $reset_scripts .= "Number.prototype.pad = function(size) {
7287 var s = String(this);
7288 while (s.length < (size || 2)) {s = '0' + s;}
7289 return s;
7290 };
7291 var d = new Date();";
7292 }
7293
7294 // Generate the date part, depending on the use or not of the javascript calendar
7295 if ($addnowlink == 1) { // server time expressed in user time setup
7296 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7297 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7298 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7299 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7300 } elseif ($addnowlink == 2) {
7301 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7302 * This break application for foreign languages.
7303 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7304 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7305 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7306 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7307 */
7308 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7309 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7310 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7311 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7312 }
7313 /*if ($usecalendar == "eldy")
7314 {
7315 $base=DOL_URL_ROOT.'/core/';
7316 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7317 }
7318 else
7319 {
7320 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7321 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7322 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7323 }*/
7324 // Update the hour part
7325 if ($h) {
7326 if ($fullday) {
7327 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7328 }
7329 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7330 if ($addnowlink == 1) {
7331 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7332 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7333 } elseif ($addnowlink == 2) {
7334 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7335 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7336 }
7337
7338 if ($fullday) {
7339 $reset_scripts .= ' } ';
7340 }
7341 }
7342 // Update the minute part
7343 if ($m) {
7344 if ($fullday) {
7345 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7346 }
7347 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7348 if ($addnowlink == 1) {
7349 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7350 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7351 } elseif ($addnowlink == 2) {
7352 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7353 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7354 }
7355 if ($fullday) {
7356 $reset_scripts .= ' } ';
7357 }
7358 }
7359 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7360 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7361 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7362 $retstring .= $langs->trans("Now");
7363 $retstring .= '</button> ';
7364 }
7365 }
7366
7367 // Add a "Plus one hour" link
7368 if ($conf->use_javascript_ajax && $addplusone) {
7369 // Script which will be inserted in the onClick of the "Add plusone" link
7370 $reset_scripts = "";
7371
7372 // Generate the date part, depending on the use or not of the javascript calendar
7373 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7374 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7375 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7376 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7377 // Update the hour part
7378 if ($h) {
7379 if ($fullday) {
7380 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7381 }
7382 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7383 if ($fullday) {
7384 $reset_scripts .= ' } ';
7385 }
7386 }
7387 // Update the minute part
7388 if ($m) {
7389 if ($fullday) {
7390 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7391 }
7392 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7393 if ($fullday) {
7394 $reset_scripts .= ' } ';
7395 }
7396 }
7397 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7398 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7399 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7400 $retstring .= $langs->trans("DateStartPlusOne");
7401 $retstring .= '</button> ';
7402 }
7403 }
7404
7405 // Add a link to set data
7406 if ($conf->use_javascript_ajax && !empty($adddateof)) {
7407 if (!is_array($adddateof)) {
7408 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
7409 } else {
7410 $arrayofdateof = $adddateof;
7411 }
7412 foreach ($arrayofdateof as $valuedateof) {
7413 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
7414 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
7415 $tmparray = dol_getdate($tmpadddateof);
7416 if (empty($tmplabeladddateof)) {
7417 $tmplabeladddateof = $langs->trans("DateInvoice");
7418 }
7419 $reset_scripts = 'console.log(\'Click on now link\'); ';
7420 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7421 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7422 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7423 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7424 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7425 }
7426 }
7427
7428 return $retstring;
7429 }
7430
7439 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7440 {
7441 global $langs;
7442
7443 $TDurationTypes = array(
7444 'y' => $langs->trans('Years'),
7445 'm' => $langs->trans('Month'),
7446 'w' => $langs->trans('Weeks'),
7447 'd' => $langs->trans('Days'),
7448 'h' => $langs->trans('Hours'),
7449 'i' => $langs->trans('Minutes')
7450 );
7451
7452 // Removed undesired duration types
7453 foreach ($excludetypes as $value) {
7454 unset($TDurationTypes[$value]);
7455 }
7456
7457 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7458 foreach ($TDurationTypes as $key => $typeduration) {
7459 $retstring .= '<option value="' . $key . '"';
7460 if ($key == $selected) {
7461 $retstring .= " selected";
7462 }
7463 $retstring .= ">" . $typeduration . "</option>";
7464 }
7465 $retstring .= "</select>";
7466
7467 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7468
7469 return $retstring;
7470 }
7471
7472 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7473
7487 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7488 {
7489 // phpcs:enable
7490 global $langs;
7491
7492 $retstring = '<span class="nowraponall">';
7493
7494 $hourSelected = '';
7495 $minSelected = '';
7496
7497 // Hours
7498 if ($iSecond != '') {
7499 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7500
7501 $hourSelected = convertSecondToTime($iSecond, 'allhour');
7502 $minSelected = convertSecondToTime($iSecond, 'min');
7503 }
7504
7505 if ($typehour == 'select') {
7506 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7507 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7508 $retstring .= '<option value="' . $hour . '"';
7509 if (is_numeric($hourSelected) && $hourSelected == $hour) {
7510 $retstring .= " selected";
7511 }
7512 $retstring .= ">" . $hour . "</option>";
7513 }
7514 $retstring .= "</select>";
7515 } elseif ($typehour == 'text' || $typehour == 'textselect') {
7516 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7517 } else {
7518 return 'BadValueForParameterTypeHour';
7519 }
7520
7521 if ($typehour != 'text') {
7522 $retstring .= ' ' . $langs->trans('HourShort');
7523 } else {
7524 $retstring .= '<span class="">:</span>';
7525 }
7526
7527 // Minutes
7528 if ($minunderhours) {
7529 $retstring .= '<br>';
7530 } else {
7531 if ($typehour != 'text') {
7532 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7533 }
7534 }
7535
7536 if ($typehour == 'select' || $typehour == 'textselect') {
7537 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7538 for ($min = 0; $min <= 55; $min += 5) {
7539 $retstring .= '<option value="' . $min . '"';
7540 if (is_numeric($minSelected) && $minSelected == $min) {
7541 $retstring .= ' selected';
7542 }
7543 $retstring .= '>' . $min . '</option>';
7544 }
7545 $retstring .= "</select>";
7546 } elseif ($typehour == 'text') {
7547 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7548 }
7549
7550 if ($typehour != 'text') {
7551 $retstring .= ' ' . $langs->trans('MinuteShort');
7552 }
7553
7554 $retstring .= "</span>";
7555
7556 if (!empty($nooutput)) {
7557 return $retstring;
7558 }
7559
7560 print $retstring;
7561
7562 return '';
7563 }
7564
7584 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)
7585 {
7586 global $langs, $conf;
7587
7588 $out = '';
7589
7590 // check parameters
7591 if (is_null($ajaxoptions)) {
7592 $ajaxoptions = array();
7593 }
7594
7595 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7596 $placeholder = '';
7597
7598 if ($selected && empty($selected_input_value)) {
7599 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7600 $tickettmpselect = new Ticket($this->db);
7601 $tickettmpselect->fetch($selected);
7602 $selected_input_value = $tickettmpselect->ref;
7603 unset($tickettmpselect);
7604 }
7605
7606 $urloption = '';
7607 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7608
7609 if (empty($hidelabel)) {
7610 $out .= $langs->trans("RefOrLabel") . ' : ';
7611 } elseif ($hidelabel > 1) {
7612 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7613 if ($hidelabel == 2) {
7614 $out .= img_picto($langs->trans("Search"), 'search');
7615 }
7616 }
7617 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7618 if ($hidelabel == 3) {
7619 $out .= img_picto($langs->trans("Search"), 'search');
7620 }
7621 } else {
7622 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7623 }
7624
7625 if (empty($nooutput)) {
7626 print $out;
7627 } else {
7628 return $out;
7629 }
7630 return '';
7631 }
7632
7633
7650 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7651 {
7652 global $langs, $conf;
7653
7654 $out = '';
7655 $outarray = array();
7656
7657 $selectFields = " p.rowid, p.ref, p.message";
7658
7659 $sql = "SELECT ";
7660 $sql .= $selectFields;
7661 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7662 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7663
7664 // Add criteria on ref/label
7665 if ($filterkey != '') {
7666 $sql .= ' AND (';
7667 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7668 // For natural search
7669 $search_crit = explode(' ', $filterkey);
7670 $i = 0;
7671 if (count($search_crit) > 1) {
7672 $sql .= "(";
7673 }
7674 foreach ($search_crit as $crit) {
7675 if ($i > 0) {
7676 $sql .= " AND ";
7677 }
7678 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7679 $sql .= ")";
7680 $i++;
7681 }
7682 if (count($search_crit) > 1) {
7683 $sql .= ")";
7684 }
7685 $sql .= ')';
7686 }
7687
7688 $sql .= $this->db->plimit($limit, 0);
7689
7690 // Build output string
7691 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7692 $result = $this->db->query($sql);
7693 if ($result) {
7694 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7695 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7696
7697 $num = $this->db->num_rows($result);
7698
7699 $events = array();
7700
7701 if (!$forcecombo) {
7702 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7703 $out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
7704 }
7705
7706 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7707
7708 $textifempty = '';
7709 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7710 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7711 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7712 if ($showempty && !is_numeric($showempty)) {
7713 $textifempty = $langs->trans($showempty);
7714 } else {
7715 $textifempty .= $langs->trans("All");
7716 }
7717 } else {
7718 if ($showempty && !is_numeric($showempty)) {
7719 $textifempty = $langs->trans($showempty);
7720 }
7721 }
7722 if ($showempty) {
7723 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7724 }
7725
7726 $i = 0;
7727 while ($num && $i < $num) {
7728 $opt = '';
7729 $optJson = array();
7730 $objp = $this->db->fetch_object($result);
7731
7732 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7733 // Add new entry
7734 // "key" value of json key array is used by jQuery automatically as selected value
7735 // "label" value of json key array is used by jQuery automatically as text for combo box
7736 $out .= $opt;
7737 array_push($outarray, $optJson);
7738
7739 $i++;
7740 }
7741
7742 $out .= '</select>';
7743
7744 $this->db->free($result);
7745
7746 if (empty($outputmode)) {
7747 return $out;
7748 }
7749 return $outarray;
7750 } else {
7751 dol_print_error($this->db);
7752 }
7753
7754 return array();
7755 }
7756
7768 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7769 {
7770 $outkey = '';
7771 $outref = '';
7772 $outtype = '';
7773
7774 $outkey = $objp->rowid;
7775 $outref = $objp->ref;
7776 $outtype = $objp->fk_product_type;
7777
7778 $opt = '<option value="' . $objp->rowid . '"';
7779 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7780 $opt .= '>';
7781 $opt .= $objp->ref;
7782 $objRef = $objp->ref;
7783 if (!empty($filterkey) && $filterkey != '') {
7784 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7785 }
7786
7787 $opt .= "</option>\n";
7788 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7789 }
7790
7810 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)
7811 {
7812 global $langs, $conf;
7813
7814 $out = '';
7815
7816 // check parameters
7817 if (is_null($ajaxoptions)) {
7818 $ajaxoptions = array();
7819 }
7820
7821 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7822 $placeholder = '';
7823
7824 if ($selected && empty($selected_input_value)) {
7825 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7826 $projecttmpselect = new Project($this->db);
7827 $projecttmpselect->fetch($selected);
7828 $selected_input_value = $projecttmpselect->ref;
7829 unset($projecttmpselect);
7830 }
7831
7832 $urloption = '';
7833 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7834
7835 if (empty($hidelabel)) {
7836 $out .= $langs->trans("RefOrLabel") . ' : ';
7837 } elseif ($hidelabel > 1) {
7838 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7839 if ($hidelabel == 2) {
7840 $out .= img_picto($langs->trans("Search"), 'search');
7841 }
7842 }
7843 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7844 if ($hidelabel == 3) {
7845 $out .= img_picto($langs->trans("Search"), 'search');
7846 }
7847 } else {
7848 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7849 }
7850
7851 if (empty($nooutput)) {
7852 print $out;
7853 } else {
7854 return $out;
7855 }
7856 return '';
7857 }
7858
7875 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7876 {
7877 global $langs, $conf;
7878
7879 $out = '';
7880 $outarray = array();
7881
7882 $selectFields = " p.rowid, p.ref";
7883
7884 $sql = "SELECT ";
7885 $sql .= $selectFields;
7886 $sql .= " FROM " . $this->db->prefix() . "projet as p";
7887 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
7888
7889 // Add criteria on ref/label
7890 if ($filterkey != '') {
7891 $sql .= ' AND (';
7892 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7893 // For natural search
7894 $search_crit = explode(' ', $filterkey);
7895 $i = 0;
7896 if (count($search_crit) > 1) {
7897 $sql .= "(";
7898 }
7899 foreach ($search_crit as $crit) {
7900 if ($i > 0) {
7901 $sql .= " AND ";
7902 }
7903 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7904 $sql .= "";
7905 $i++;
7906 }
7907 if (count($search_crit) > 1) {
7908 $sql .= ")";
7909 }
7910 $sql .= ')';
7911 }
7912
7913 $sql .= $this->db->plimit($limit, 0);
7914
7915 // Build output string
7916 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
7917 $result = $this->db->query($sql);
7918 if ($result) {
7919 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7920 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
7921
7922 $num = $this->db->num_rows($result);
7923
7924 $events = array();
7925
7926 if (!$forcecombo) {
7927 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7928 $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7929 }
7930
7931 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7932
7933 $textifempty = '';
7934 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7935 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7936 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
7937 if ($showempty && !is_numeric($showempty)) {
7938 $textifempty = $langs->trans($showempty);
7939 } else {
7940 $textifempty .= $langs->trans("All");
7941 }
7942 } else {
7943 if ($showempty && !is_numeric($showempty)) {
7944 $textifempty = $langs->trans($showempty);
7945 }
7946 }
7947 if ($showempty) {
7948 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7949 }
7950
7951 $i = 0;
7952 while ($num && $i < $num) {
7953 $opt = '';
7954 $optJson = array();
7955 $objp = $this->db->fetch_object($result);
7956
7957 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
7958 // Add new entry
7959 // "key" value of json key array is used by jQuery automatically as selected value
7960 // "label" value of json key array is used by jQuery automatically as text for combo box
7961 $out .= $opt;
7962 array_push($outarray, $optJson);
7963
7964 $i++;
7965 }
7966
7967 $out .= '</select>';
7968
7969 $this->db->free($result);
7970
7971 if (empty($outputmode)) {
7972 return $out;
7973 }
7974 return $outarray;
7975 } else {
7976 dol_print_error($this->db);
7977 }
7978
7979 return array();
7980 }
7981
7993 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7994 {
7995 $outkey = '';
7996 $outref = '';
7997 $outtype = '';
7998
7999 $label = $objp->label;
8000
8001 $outkey = $objp->rowid;
8002 $outref = $objp->ref;
8003 $outlabel = $objp->label;
8004 $outtype = $objp->fk_product_type;
8005
8006 $opt = '<option value="' . $objp->rowid . '"';
8007 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8008 $opt .= '>';
8009 $opt .= $objp->ref;
8010 $objRef = $objp->ref;
8011 if (!empty($filterkey) && $filterkey != '') {
8012 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8013 }
8014
8015 $opt .= "</option>\n";
8016 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8017 }
8018
8019
8039 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)
8040 {
8041 global $langs, $conf;
8042
8043 $out = '';
8044
8045 // check parameters
8046 if (is_null($ajaxoptions)) {
8047 $ajaxoptions = array();
8048 }
8049
8050 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8051 $placeholder = '';
8052
8053 if ($selected && empty($selected_input_value)) {
8054 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8055 $adherenttmpselect = new Adherent($this->db);
8056 $adherenttmpselect->fetch($selected);
8057 $selected_input_value = $adherenttmpselect->ref;
8058 unset($adherenttmpselect);
8059 }
8060
8061 $urloption = '';
8062
8063 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8064
8065 if (empty($hidelabel)) {
8066 $out .= $langs->trans("RefOrLabel") . ' : ';
8067 } elseif ($hidelabel > 1) {
8068 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8069 if ($hidelabel == 2) {
8070 $out .= img_picto($langs->trans("Search"), 'search');
8071 }
8072 }
8073 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8074 if ($hidelabel == 3) {
8075 $out .= img_picto($langs->trans("Search"), 'search');
8076 }
8077 } else {
8078 $filterkey = '';
8079
8080 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8081 }
8082
8083 if (empty($nooutput)) {
8084 print $out;
8085 } else {
8086 return $out;
8087 }
8088 return '';
8089 }
8090
8107 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8108 {
8109 global $langs, $conf;
8110
8111 $out = '';
8112 $outarray = array();
8113
8114 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8115
8116 $sql = "SELECT ";
8117 $sql .= $selectFields;
8118 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8119 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8120
8121 // Add criteria on ref/label
8122 if ($filterkey != '') {
8123 $sql .= ' AND (';
8124 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8125 // For natural search
8126 $search_crit = explode(' ', $filterkey);
8127 $i = 0;
8128 if (count($search_crit) > 1) {
8129 $sql .= "(";
8130 }
8131 foreach ($search_crit as $crit) {
8132 if ($i > 0) {
8133 $sql .= " AND ";
8134 }
8135 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8136 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8137 $i++;
8138 }
8139 if (count($search_crit) > 1) {
8140 $sql .= ")";
8141 }
8142 $sql .= ')';
8143 }
8144 if ($status != -1) {
8145 $sql .= ' AND statut = ' . ((int) $status);
8146 }
8147 $sql .= $this->db->plimit($limit, 0);
8148
8149 // Build output string
8150 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8151 $result = $this->db->query($sql);
8152 if ($result) {
8153 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8154 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8155
8156 $num = $this->db->num_rows($result);
8157
8158 $events = array();
8159
8160 if (!$forcecombo) {
8161 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8162 $out .= ajax_combobox($htmlname, $events, getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT') ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
8163 }
8164
8165 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8166
8167 $textifempty = '';
8168 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8169 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8170 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8171 if ($showempty && !is_numeric($showempty)) {
8172 $textifempty = $langs->trans($showempty);
8173 } else {
8174 $textifempty .= $langs->trans("All");
8175 }
8176 } else {
8177 if ($showempty && !is_numeric($showempty)) {
8178 $textifempty = $langs->trans($showempty);
8179 }
8180 }
8181 if ($showempty) {
8182 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8183 }
8184
8185 $i = 0;
8186 while ($num && $i < $num) {
8187 $opt = '';
8188 $optJson = array();
8189 $objp = $this->db->fetch_object($result);
8190
8191 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8192
8193 // Add new entry
8194 // "key" value of json key array is used by jQuery automatically as selected value
8195 // "label" value of json key array is used by jQuery automatically as text for combo box
8196 $out .= $opt;
8197 array_push($outarray, $optJson);
8198
8199 $i++;
8200 }
8201
8202 $out .= '</select>';
8203
8204 $this->db->free($result);
8205
8206 if (empty($outputmode)) {
8207 return $out;
8208 }
8209 return $outarray;
8210 } else {
8211 dol_print_error($this->db);
8212 }
8213
8214 return array();
8215 }
8216
8228 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8229 {
8230 $outkey = '';
8231 $outlabel = '';
8232 $outtype = '';
8233
8234 $outkey = $objp->rowid;
8235 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8236 $outtype = $objp->fk_adherent_type;
8237
8238 $opt = '<option value="' . $objp->rowid . '"';
8239 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8240 $opt .= '>';
8241 if (!empty($filterkey) && $filterkey != '') {
8242 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8243 }
8244 $opt .= $outlabel;
8245 $opt .= "</option>\n";
8246
8247 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8248 }
8249
8270 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8271 {
8272 global $conf, $extrafields, $user;
8273
8274 //var_dump($objectdesc); debug_print_backtrace();
8275
8276 $objectdescorig = $objectdesc;
8277 $objecttmp = null;
8278 $InfoFieldList = array();
8279 $classname = '';
8280 $filter = ''; // Ensure filter has value (for static analysis)
8281 $sortfield = ''; // Ensure filter has value (for static analysis)
8282
8283 if ($objectfield) { // We must retrieve the objectdesc from the field or extrafield
8284 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8285 $tmparray = explode(':', $objectfield);
8286
8287 // Get instance of object from $element
8288 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8289
8290 if (is_object($objectforfieldstmp)) {
8291 $objectdesc = '';
8292
8293 $reg = array();
8294 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8295 // For a property in extrafields
8296 $key = $reg[1];
8297 // fetch optionals attributes and labels
8298 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8299
8300 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8301 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8302 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8303 $objectdesc = $tmpextrafields[0];
8304 }
8305 }
8306 } else {
8307 // For a property in ->fields
8308 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8309 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8310 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8311 }
8312 }
8313 }
8314 }
8315
8316 if ($objectdesc) {
8317 // Example of value for $objectdesc:
8318 // Bom:bom/class/bom.class.php:0:t.status=1
8319 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8320 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8321 $InfoFieldList = explode(":", $objectdesc, 4);
8322 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8323 $reg = array();
8324 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8325 $InfoFieldList[4] = $reg[1]; // take the sort field
8326 }
8327 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8328
8329 $classname = $InfoFieldList[0];
8330 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8331 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8332 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8333 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8334
8335 // Load object according to $id and $element
8336 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8337
8338 // Fallback to another solution to get $objecttmp
8339 if (empty($objecttmp) && !empty($classpath)) {
8340 dol_include_once($classpath);
8341
8342 if ($classname && class_exists($classname)) {
8343 $objecttmp = new $classname($this->db);
8344 }
8345 }
8346 }
8347
8348 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
8349 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
8350 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
8351 $filter = str_replace(
8352 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
8353 array($conf->entity, $sharedentities, $user->id),
8354 $filter
8355 );
8356
8357 if (!is_object($objecttmp)) {
8358 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc, LOG_WARNING);
8359 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc;
8360 }
8361 '@phan-var-force CommonObject $objecttmp';
8362
8363 //var_dump($filter);
8364 $prefixforautocompletemode = $objecttmp->element;
8365 if ($prefixforautocompletemode == 'societe') {
8366 $prefixforautocompletemode = 'company';
8367 }
8368 if ($prefixforautocompletemode == 'product') {
8369 $prefixforautocompletemode = 'produit';
8370 }
8371 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8372
8373 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
8374
8375 // Generate the combo HTML component
8376 $out = '';
8377 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
8378 // No immediate load of all database
8379 $placeholder = '';
8380
8381 if ($preSelectedValue && empty($selected_input_value)) {
8382 $objecttmp->fetch($preSelectedValue);
8383 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
8384
8385 $oldValueForShowOnCombobox = 0;
8386 foreach ($objecttmp->fields as $fieldK => $fielV) {
8387 if (empty($fielV['showoncombobox']) || empty($objecttmp->$fieldK)) {
8388 continue;
8389 }
8390
8391 if (!$oldValueForShowOnCombobox) {
8392 $selected_input_value = '';
8393 }
8394
8395 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
8396 $selected_input_value .= $objecttmp->$fieldK;
8397 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
8398 }
8399 }
8400
8401 // Set url and param to call to get json of the search results
8402 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
8403 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . '&objectfield='.urlencode($objectfield) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
8404
8405 // Activate the auto complete using ajax call.
8406 $out .= ajax_autocompleter($preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalString($confkeyforautocompletemode), 0);
8407 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
8408 $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) . '"' : '') . ' />';
8409 } else {
8410 // Immediate load of table record.
8411 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
8412 }
8413
8414 return $out;
8415 }
8416
8417
8438 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
8439 {
8440 global $langs, $user, $hookmanager;
8441
8442 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
8443
8444 $prefixforautocompletemode = $objecttmp->element;
8445 if ($prefixforautocompletemode == 'societe') {
8446 $prefixforautocompletemode = 'company';
8447 }
8448 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8449
8450 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
8451 $tmpfieldstoshow = '';
8452 foreach ($objecttmp->fields as $key => $val) {
8453 if (! (int) dol_eval($val['enabled'], 1, 1, '1')) {
8454 continue;
8455 }
8456 if (!empty($val['showoncombobox'])) {
8457 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8458 }
8459 }
8460 if ($tmpfieldstoshow) {
8461 $fieldstoshow = $tmpfieldstoshow;
8462 }
8463 } else {
8464 // For backward compatibility
8465 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8466 }
8467
8468 if (empty($fieldstoshow)) {
8469 if (isset($objecttmp->fields['ref'])) {
8470 $fieldstoshow = 't.ref';
8471 } else {
8472 $langs->load("errors");
8473 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8474 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8475 }
8476 }
8477
8478 $out = '';
8479 $outarray = array();
8480 $tmparray = array();
8481
8482 $num = 0;
8483
8484 // Search data
8485 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $objecttmp->table_element . " as t";
8486 if (!empty($objecttmp->isextrafieldmanaged)) {
8487 $sql .= " LEFT JOIN " . $this->db->prefix() . $objecttmp->table_element . "_extrafields as e ON t.rowid=e.fk_object";
8488 }
8489 if (isset($objecttmp->ismultientitymanaged)) {
8490 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8491 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8492 $sql .= " INNER JOIN " . $this->db->prefix() . $tmparray[1] . " as parenttable ON parenttable.rowid = t." . $tmparray[0];
8493 }
8494 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8495 if (!$user->hasRight('societe', 'client', 'voir')) {
8496 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8497 }
8498 }
8499 }
8500
8501 // Add where from hooks
8502 $parameters = array(
8503 'object' => $objecttmp,
8504 'htmlname' => $htmlname,
8505 'filter' => $filter,
8506 'searchkey' => $searchkey
8507 );
8508
8509 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8510 if (!empty($hookmanager->resPrint)) {
8511 $sql .= $hookmanager->resPrint;
8512 } else {
8513 $sql .= " WHERE 1=1";
8514 if (isset($objecttmp->ismultientitymanaged)) {
8515 if ($objecttmp->ismultientitymanaged == 1) {
8516 $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8517 }
8518 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8519 $sql .= " AND parenttable.entity = t." . $tmparray[0];
8520 }
8521 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8522 if ($objecttmp->element == 'societe') {
8523 $sql .= " AND t.rowid = " . ((int) $user->socid);
8524 } else {
8525 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8526 }
8527 }
8528 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8529 if (!$user->hasRight('societe', 'client', 'voir')) {
8530 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8531 }
8532 }
8533 }
8534 if ($searchkey != '') {
8535 $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
8536 }
8537
8538 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8539 $errormessage = '';
8540 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8541 if ($errormessage) {
8542 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8543 }
8544 }
8545 }
8546 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8547 //$sql.=$this->db->plimit($limit, 0);
8548 //print $sql;
8549
8550 // Build output string
8551 $resql = $this->db->query($sql);
8552 if ($resql) {
8553 // Construct $out and $outarray
8554 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8555
8556 // 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
8557 $textifempty = '&nbsp;';
8558
8559 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8560 if (getDolGlobalInt($confkeyforautocompletemode)) {
8561 if ($showempty && !is_numeric($showempty)) {
8562 $textifempty = $langs->trans($showempty);
8563 } else {
8564 $textifempty .= $langs->trans("All");
8565 }
8566 }
8567 if ($showempty) {
8568 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8569 }
8570
8571 $num = $this->db->num_rows($resql);
8572 $i = 0;
8573 if ($num) {
8574 while ($i < $num) {
8575 $obj = $this->db->fetch_object($resql);
8576 $label = '';
8577 $labelhtml = '';
8578 $tmparray = explode(',', $fieldstoshow);
8579 $oldvalueforshowoncombobox = 0;
8580 foreach ($tmparray as $key => $val) {
8581 $val = preg_replace('/t\./', '', $val);
8582 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8583 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8584 $label .= $obj->$val;
8585 $labelhtml .= $obj->$val;
8586
8587 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8588 }
8589 if (empty($outputmode)) {
8590 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8591 $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>';
8592 } else {
8593 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8594 }
8595 } else {
8596 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8597 }
8598
8599 $i++;
8600 if (($i % 10) == 0) {
8601 $out .= "\n";
8602 }
8603 }
8604 }
8605
8606 $out .= '</select>' . "\n";
8607
8608 if (!$forcecombo) {
8609 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8610 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
8611 }
8612 } else {
8613 dol_print_error($this->db);
8614 }
8615
8616 $this->result = array('nbofelement' => $num);
8617
8618 if ($outputmode) {
8619 return $outarray;
8620 }
8621 return $out;
8622 }
8623
8624
8648 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)
8649 {
8650 global $conf, $langs;
8651
8652 // Do we want a multiselect ?
8653 //$jsbeautify = 0;
8654 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8655 $jsbeautify = 1;
8656
8657 if ($value_as_key) {
8658 $array = array_combine($array, $array);
8659 }
8660
8661 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
8662
8663 $out = '';
8664
8665 if ($addjscombo < 0) {
8666 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8667 $addjscombo = 1;
8668 } else {
8669 $addjscombo = 0;
8670 }
8671 }
8672 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8673 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8674 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8675 $out .= '>'."\n";
8676
8677 if ($show_empty) {
8678 $textforempty = ' ';
8679 if (!empty($conf->use_javascript_ajax)) {
8680 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8681 }
8682 if (!is_numeric($show_empty)) {
8683 $textforempty = $show_empty;
8684 }
8685 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8686 }
8687 if (is_array($array)) {
8688 // Translate
8689 if ($translate) {
8690 foreach ($array as $key => $value) {
8691 if (!is_array($value)) {
8692 $array[$key] = $langs->trans($value);
8693 } else {
8694 $array[$key]['label'] = $langs->trans($value['label']);
8695 }
8696 }
8697 }
8698 // Sort
8699 if ($sort == 'ASC') {
8700 asort($array);
8701 } elseif ($sort == 'DESC') {
8702 arsort($array);
8703 }
8704
8705 foreach ($array as $key => $tmpvalue) {
8706 if (is_array($tmpvalue)) {
8707 $value = $tmpvalue['label'];
8708 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
8709 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8710 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8711 } else {
8712 $value = $tmpvalue;
8713 //$valuehtml = $tmpvalue;
8714 $disabled = '';
8715 $style = '';
8716 }
8717 if (!empty($disablebademail)) {
8718 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8719 || ($disablebademail == 2 && preg_match('/---/', $value))) {
8720 $disabled = ' disabled';
8721 $style = ' class="warning"';
8722 }
8723 }
8724 if ($key_in_label) {
8725 if (empty($nohtmlescape)) {
8726 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8727 } else {
8728 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8729 }
8730 } else {
8731 if (empty($nohtmlescape)) {
8732 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
8733 } else {
8734 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8735 }
8736 if ($value == '' || $value == '-') {
8737 $selectOptionValue = '&nbsp;';
8738 }
8739 }
8740 $out .= '<option value="' . $key . '"';
8741 $out .= $style . $disabled;
8742 if (is_array($id)) {
8743 if (in_array($key, $id) && !$disabled) {
8744 $out .= ' selected'; // To preselect a value
8745 }
8746 } else {
8747 $id = (string) $id; // if $id = 0, then $id = '0'
8748 if ($id != '' && ($id == $key || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8749 $out .= ' selected'; // To preselect a value
8750 }
8751 }
8752 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
8753 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
8754 }
8755
8756 if (is_array($tmpvalue)) {
8757 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
8758 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
8759 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
8760 }
8761 }
8762 }
8763 $out .= '>';
8764 $out .= $selectOptionValue;
8765 $out .= "</option>\n";
8766 }
8767 }
8768 $out .= "</select>";
8769
8770 // Add code for jquery to use multiselect
8771 if ($addjscombo && $jsbeautify) {
8772 // Enhance with select2
8773 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8774 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
8775 }
8776
8777 return $out;
8778 }
8779
8798 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8799 {
8800 global $conf, $langs;
8801 global $delayedhtmlcontent; // Will be used later outside of this function
8802
8803 // TODO Use an internal dolibarr component instead of select2
8804 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8805 return '';
8806 }
8807
8808 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
8809
8810 $outdelayed = '';
8811 if (!empty($conf->use_javascript_ajax)) {
8812 $tmpplugin = 'select2';
8813 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8814 <script nonce="' . getNonce() . '">
8815 $(document).ready(function () {
8816
8817 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
8818
8819 $(".' . $htmlname . '").select2({
8820 ajax: {
8821 dir: "ltr",
8822 url: "' . $url . '",
8823 dataType: \'json\',
8824 delay: 250,
8825 data: function (params) {
8826 return {
8827 q: params.term, // search term
8828 page: params.page
8829 }
8830 },
8831 processResults: function (data) {
8832 // parse the results into the format expected by Select2.
8833 // since we are using custom formatting functions we do not need to alter the remote JSON data
8834 //console.log(data);
8835 saveRemoteData = data;
8836 /* format json result for select2 */
8837 result = []
8838 $.each( data, function( key, value ) {
8839 result.push({id: key, text: value.text});
8840 });
8841 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
8842 //console.log(result);
8843 return {results: result, more: false}
8844 },
8845 cache: true
8846 },
8847 language: select2arrayoflanguage,
8848 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8849 placeholder: "' . dol_escape_js($placeholder) . '",
8850 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8851 minimumInputLength: ' . ((int) $minimumInputLength) . ',
8852 formatResult: function (result, container, query, escapeMarkup) {
8853 return escapeMarkup(result.text);
8854 },
8855 });
8856
8857 ' . ($callurlonselect ? '
8858 /* Code to execute a GET when we select a value */
8859 $(".' . $htmlname . '").change(function() {
8860 var selected = $(".' . $htmlname . '").val();
8861 console.log("We select in selectArrayAjax the entry "+selected)
8862 $(".' . $htmlname . '").val(""); /* reset visible combo value */
8863 $.each( saveRemoteData, function( key, value ) {
8864 if (key == selected)
8865 {
8866 console.log("selectArrayAjax - Do a redirect to "+value.url)
8867 location.assign(value.url);
8868 }
8869 });
8870 });' : '') . '
8871
8872 });
8873 </script>';
8874 }
8875
8876 if ($acceptdelayedhtml) {
8877 $delayedhtmlcontent .= $outdelayed;
8878 } else {
8879 $out .= $outdelayed;
8880 }
8881 return $out;
8882 }
8883
8903 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
8904 {
8905 global $conf, $langs;
8906 global $delayedhtmlcontent; // Will be used later outside of this function
8907
8908 // TODO Use an internal dolibarr component instead of select2
8909 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8910 return '';
8911 }
8912
8913 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
8914
8915 $formattedarrayresult = array();
8916
8917 foreach ($array as $key => $value) {
8918 $o = new stdClass();
8919 $o->id = $key;
8920 $o->text = $value['text'];
8921 $o->url = $value['url'];
8922 $formattedarrayresult[] = $o;
8923 }
8924
8925 $outdelayed = '';
8926 if (!empty($conf->use_javascript_ajax)) {
8927 $tmpplugin = 'select2';
8928 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8929 <script nonce="' . getNonce() . '">
8930 $(document).ready(function () {
8931 var data = ' . json_encode($formattedarrayresult) . ';
8932
8933 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
8934
8935 $(".' . $htmlname . '").select2({
8936 data: data,
8937 language: select2arrayoflanguage,
8938 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8939 placeholder: "' . dol_escape_js($placeholder) . '",
8940 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8941 minimumInputLength: ' . $minimumInputLength . ',
8942 formatResult: function (result, container, query, escapeMarkup) {
8943 return escapeMarkup(result.text);
8944 },
8945 matcher: function (params, data) {
8946
8947 if(! data.id) return null;';
8948
8949 if ($callurlonselect) {
8950 // We forge the url with 'sall='
8951 $outdelayed .= '
8952
8953 var urlBase = data.url;
8954 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
8955 /* console.log("params.term="+params.term); */
8956 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
8957 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
8958 }
8959
8960 if (!$disableFiltering) {
8961 $outdelayed .= '
8962
8963 if(data.text.match(new RegExp(params.term))) {
8964 return data;
8965 }
8966
8967 return null;';
8968 } else {
8969 $outdelayed .= '
8970
8971 return data;';
8972 }
8973
8974 $outdelayed .= '
8975 }
8976 });
8977
8978 ' . ($callurlonselect ? '
8979 /* Code to execute a GET when we select a value */
8980 $(".' . $htmlname . '").change(function() {
8981 var selected = $(".' . $htmlname . '").val();
8982 console.log("We select "+selected)
8983
8984 $(".' . $htmlname . '").val(""); /* reset visible combo value */
8985 $.each( saveRemoteData, function( key, value ) {
8986 if (key == selected)
8987 {
8988 console.log("selectArrayFilter - Do a redirect to "+value.url)
8989 location.assign(value.url);
8990 }
8991 });
8992 });' : '') . '
8993
8994 });
8995 </script>';
8996 }
8997
8998 if ($acceptdelayedhtml) {
8999 $delayedhtmlcontent .= $outdelayed;
9000 } else {
9001 $out .= $outdelayed;
9002 }
9003 return $out;
9004 }
9005
9024 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)
9025 {
9026 global $conf, $langs;
9027
9028 $out = '';
9029
9030 if ($addjscombo < 0) {
9031 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9032 $addjscombo = 1;
9033 } else {
9034 $addjscombo = 0;
9035 }
9036 }
9037
9038 $useenhancedmultiselect = 0;
9039 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9040 if ($addjscombo) {
9041 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9042 }
9043 }
9044
9045 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9046 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9047 // submitted to nothing.
9048 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9049 // Output select component
9050 $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";
9051 if (is_array($array) && !empty($array)) {
9052 if ($value_as_key) {
9053 $array = array_combine($array, $array);
9054 }
9055
9056 if (!empty($array)) {
9057 foreach ($array as $key => $value) {
9058 $tmpkey = $key;
9059 $tmpvalue = $value;
9060 $tmpcolor = '';
9061 $tmppicto = '';
9062 $tmplabelhtml = '';
9063 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9064 $tmpkey = $value['id'];
9065 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9066 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9067 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9068 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']): $value['labelhtml'];
9069 }
9070 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9071 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9072
9073 $out .= '<option value="' . $tmpkey . '"';
9074 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9075 $out .= ' selected';
9076 }
9077 if (!empty($tmplabelhtml)) {
9078 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9079 } else {
9080 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9081 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9082 }
9083 $out .= '>';
9084 $out .= dol_htmlentitiesbr($newval);
9085 $out .= '</option>' . "\n";
9086 }
9087 }
9088 }
9089 $out .= '</select>' . "\n";
9090
9091 // Add code for jquery to use multiselect
9092 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9093 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9094 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9095 if ($addjscombo == 1) {
9096 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
9097 $out .= 'function formatResult(record, container) {' . "\n";
9098 // If property data-html set, we decode html entities and use this.
9099 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9100 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9101 //$out .= ' console.log("aaa");';
9102 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9103 $out .= ' }'."\n";
9104 $out .= ' return record.text;';
9105 $out .= '}' . "\n";
9106 $out .= 'function formatSelection(record) {' . "\n";
9107 if ($elemtype == 'category') {
9108 $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
9109 } else {
9110 $out .= 'return record.text;';
9111 }
9112 $out .= '}' . "\n";
9113 $out .= '$(document).ready(function () {
9114 $(\'#' . $htmlname . '\').' . $tmpplugin . '({';
9115 if ($placeholder) {
9116 $out .= '
9117 placeholder: {
9118 id: \'-1\',
9119 text: \'' . dol_escape_js($placeholder) . '\'
9120 },';
9121 }
9122 $out .= ' dir: \'ltr\',
9123 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9124 dropdownCssClass: \'' . $morecss . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
9125 // Specify format function for dropdown item
9126 formatResult: formatResult,
9127 templateResult: formatResult, /* For 4.0 */
9128 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9129 // Specify format function for selected item
9130 formatSelection: formatSelection,
9131 templateSelection: formatSelection /* For 4.0 */
9132 });
9133
9134 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
9135 the size only if component is not hidden by default on load */
9136 $(\'#' . $htmlname . ' + .select2\').addClass(\'' . $morecss . '\');
9137 });' . "\n";
9138 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9139 // Add other js lib
9140 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9141 // ...
9142 $out .= 'console.log(\'addjscombo=2 for htmlname=' . $htmlname . '\');';
9143 $out .= '$(document).ready(function () {
9144 $(\'#' . $htmlname . '\').multiSelect({
9145 containerHTML: \'<div class="multi-select-container">\',
9146 menuHTML: \'<div class="multi-select-menu">\',
9147 buttonHTML: \'<span class="multi-select-button ' . $morecss . '">\',
9148 menuItemHTML: \'<label class="multi-select-menuitem">\',
9149 activeClass: \'multi-select-container--open\',
9150 noneText: \'' . $placeholder . '\'
9151 });
9152 })';
9153 }
9154 $out .= '</script>';
9155 }
9156
9157 return $out;
9158 }
9159
9160
9172 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9173 {
9174 global $langs, $user;
9175
9176 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9177 return '';
9178 }
9179 if (empty($array)) {
9180 return '';
9181 }
9182
9183 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9184
9185 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9186 $tmparray = explode(',', $user->conf->$tmpvar);
9187 foreach ($array as $key => $val) {
9188 //var_dump($key);
9189 //var_dump($tmparray);
9190 if (in_array($key, $tmparray)) {
9191 $array[$key]['checked'] = 1;
9192 } else {
9193 $array[$key]['checked'] = 0;
9194 }
9195 }
9196 } else { // There is no list of fields already customized for user
9197 foreach ($array as $key => $val) {
9198 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9199 $array[$key]['checked'] = 0;
9200 }
9201 }
9202 }
9203
9204 $listoffieldsforselection = '';
9205 $listcheckedstring = '';
9206
9207 foreach ($array as $key => $val) {
9208 // var_dump($val);
9209 // var_dump(array_key_exists('enabled', $val));
9210 // var_dump(!$val['enabled']);
9211 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9212 unset($array[$key]); // We don't want this field
9213 continue;
9214 }
9215 if (!empty($val['type']) && $val['type'] == 'separate') {
9216 // Field remains in array but we don't add it into $listoffieldsforselection
9217 //$listoffieldsforselection .= '<li>-----</li>';
9218 continue;
9219 }
9220 if (!empty($val['label']) && $val['label']) {
9221 if (!empty($val['langfile']) && is_object($langs)) {
9222 $langs->load($val['langfile']);
9223 }
9224
9225 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9226 $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>';
9227 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9228 }
9229 }
9230
9231 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9232
9233 <dl class="dropdown">
9234 <dt>
9235 <a href="#' . $htmlname . '">
9236 ' . img_picto('', 'list') . '
9237 </a>
9238 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9239 </dt>
9240 <dd class="dropdowndd">
9241 <div class="multiselectcheckbox'.$htmlname.'">
9242 <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
9243 <li><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
9244 '.$listoffieldsforselection.'
9245 </ul>
9246 </div>
9247 </dd>
9248 </dl>
9249
9250 <script nonce="' . getNonce() . '" type="text/javascript">
9251 jQuery(document).ready(function () {
9252 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
9253 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9254
9255 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9256
9257 var title = $(this).val() + ",";
9258 if ($(this).is(\':checked\')) {
9259 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9260 }
9261 else {
9262 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9263 }
9264 // Now, we submit page
9265 //$(this).parents(\'form:first\').submit();
9266 });
9267 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9268 var value = $(this).val().toLowerCase();
9269 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9270 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9271 });
9272 });
9273
9274
9275 });
9276 </script>
9277
9278 ';
9279 return $out;
9280 }
9281
9291 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
9292 {
9293 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
9294
9295 $cat = new Categorie($this->db);
9296 $categories = $cat->containing($id, $type);
9297
9298 if ($rendermode == 1) {
9299 $toprint = array();
9300 foreach ($categories as $c) {
9301 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
9302 foreach ($ways as $way) {
9303 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
9304 }
9305 }
9306 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
9307 }
9308
9309 if ($rendermode == 0) {
9310 $arrayselected = array();
9311 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
9312 foreach ($categories as $c) {
9313 $arrayselected[] = $c->id;
9314 }
9315
9316 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
9317 }
9318
9319 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
9320 }
9321
9331 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
9332 {
9333 global $conf, $langs, $hookmanager;
9334 global $bc, $action;
9335
9336 $object->fetchObjectLinked();
9337
9338 // Bypass the default method
9339 $hookmanager->initHooks(array('commonobject'));
9340 $parameters = array(
9341 'morehtmlright' => $morehtmlright,
9342 'compatibleImportElementsList' => &$compatibleImportElementsList,
9343 );
9344 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9345
9346 $nbofdifferenttypes = count($object->linkedObjects);
9347
9348 if (empty($reshook)) {
9349 print '<!-- showLinkedObjectBlock -->';
9350 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
9351
9352
9353 print '<div class="div-table-responsive-no-min">';
9354 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
9355
9356 print '<tr class="liste_titre">';
9357 print '<td>' . $langs->trans("Type") . '</td>';
9358 print '<td>' . $langs->trans("Ref") . '</td>';
9359 print '<td class="center"></td>';
9360 print '<td class="center">' . $langs->trans("Date") . '</td>';
9361 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9362 print '<td class="right">' . $langs->trans("Status") . '</td>';
9363 print '<td></td>';
9364 print '</tr>';
9365
9366 $nboftypesoutput = 0;
9367
9368 foreach ($object->linkedObjects as $objecttype => $objects) {
9369 $tplpath = $element = $subelement = $objecttype;
9370
9371 // to display import button on tpl
9372 $showImportButton = false;
9373 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
9374 $showImportButton = true;
9375 }
9376
9377 $regs = array();
9378 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
9379 $element = $regs[1];
9380 $subelement = $regs[2];
9381 $tplpath = $element . '/' . $subelement;
9382 }
9383 $tplname = 'linkedobjectblock';
9384
9385 // To work with non standard path
9386 if ($objecttype == 'facture') {
9387 $tplpath = 'compta/' . $element;
9388 if (!isModEnabled('invoice')) {
9389 continue; // Do not show if module disabled
9390 }
9391 } elseif ($objecttype == 'facturerec') {
9392 $tplpath = 'compta/facture';
9393 $tplname = 'linkedobjectblockForRec';
9394 if (!isModEnabled('invoice')) {
9395 continue; // Do not show if module disabled
9396 }
9397 } elseif ($objecttype == 'propal') {
9398 $tplpath = 'comm/' . $element;
9399 if (!isModEnabled('propal')) {
9400 continue; // Do not show if module disabled
9401 }
9402 } elseif ($objecttype == 'supplier_proposal') {
9403 if (!isModEnabled('supplier_proposal')) {
9404 continue; // Do not show if module disabled
9405 }
9406 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
9407 $tplpath = 'expedition';
9408 if (!isModEnabled('shipping')) {
9409 continue; // Do not show if module disabled
9410 }
9411 } elseif ($objecttype == 'reception') {
9412 $tplpath = 'reception';
9413 if (!isModEnabled('reception')) {
9414 continue; // Do not show if module disabled
9415 }
9416 } elseif ($objecttype == 'delivery') {
9417 $tplpath = 'delivery';
9418 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
9419 continue; // Do not show if sub module disabled
9420 }
9421 } elseif ($objecttype == 'ficheinter') {
9422 $tplpath = 'fichinter';
9423 if (!isModEnabled('intervention')) {
9424 continue; // Do not show if module disabled
9425 }
9426 } elseif ($objecttype == 'invoice_supplier') {
9427 $tplpath = 'fourn/facture';
9428 } elseif ($objecttype == 'order_supplier') {
9429 $tplpath = 'fourn/commande';
9430 } elseif ($objecttype == 'expensereport') {
9431 $tplpath = 'expensereport';
9432 } elseif ($objecttype == 'subscription') {
9433 $tplpath = 'adherents';
9434 } elseif ($objecttype == 'conferenceorbooth') {
9435 $tplpath = 'eventorganization';
9436 } elseif ($objecttype == 'conferenceorboothattendee') {
9437 $tplpath = 'eventorganization';
9438 } elseif ($objecttype == 'mo') {
9439 $tplpath = 'mrp';
9440 if (!isModEnabled('mrp')) {
9441 continue; // Do not show if module disabled
9442 }
9443 }
9444
9445 global $linkedObjectBlock;
9446 $linkedObjectBlock = $objects;
9447
9448 // Output template part (modules that overwrite templates must declare this into descriptor)
9449 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
9450 foreach ($dirtpls as $reldir) {
9451 $reldir = rtrim($reldir, '/');
9452 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
9453 global $noMoreLinkedObjectBlockAfter;
9454 $noMoreLinkedObjectBlockAfter = 1;
9455 }
9456
9457 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
9458 if ($res) {
9459 $nboftypesoutput++;
9460 break;
9461 }
9462 }
9463 }
9464
9465 if (!$nboftypesoutput) {
9466 print '<tr><td class="impair" colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9467 }
9468
9469 print '</table>';
9470
9471 if (!empty($compatibleImportElementsList)) {
9472 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9473 }
9474
9475 print '</div>';
9476 }
9477
9478 return $nbofdifferenttypes;
9479 }
9480
9489 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
9490 {
9491 global $conf, $langs, $hookmanager;
9492 global $action;
9493
9494 $linktoelem = '';
9495 $linktoelemlist = '';
9496 $listofidcompanytoscan = '';
9497
9498 if (!is_object($object->thirdparty)) {
9499 $object->fetch_thirdparty();
9500 }
9501
9502 $possiblelinks = array();
9503 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9504 $listofidcompanytoscan = $object->thirdparty->id;
9505 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
9506 $listofidcompanytoscan .= ',' . $object->thirdparty->parent;
9507 }
9508 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
9509 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9510 $tmpproject = new Project($this->db);
9511 $tmpproject->fetch($object->fk_project);
9512 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9513 $listofidcompanytoscan .= ',' . $tmpproject->socid;
9514 }
9515 unset($tmpproject);
9516 }
9517
9518 $possiblelinks = array(
9519 'propal' => array(
9520 'enabled' => isModEnabled('propal'),
9521 'perms' => 1,
9522 'label' => 'LinkToProposal',
9523 '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') . ')'),
9524 'shipping' => array(
9525 'enabled' => isModEnabled('shipping'),
9526 'perms' => 1,
9527 'label' => 'LinkToExpedition',
9528 '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') . ')'),
9529 'order' => array(
9530 'enabled' => isModEnabled('order'),
9531 'perms' => 1,
9532 'label' => 'LinkToOrder',
9533 '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') . ')'),
9534 'invoice' => array(
9535 'enabled' => isModEnabled('invoice'),
9536 'perms' => 1,
9537 'label' => 'LinkToInvoice',
9538 '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') . ')'),
9539 'invoice_template' => array(
9540 'enabled' => isModEnabled('invoice'),
9541 'perms' => 1,
9542 'label' => 'LinkToTemplateInvoice',
9543 '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') . ')'),
9544 'contrat' => array(
9545 'enabled' => isModEnabled('contract'),
9546 'perms' => 1,
9547 'label' => 'LinkToContract',
9548 '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
9549 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'
9550 ),
9551 'fichinter' => array(
9552 'enabled' => isModEnabled('intervention'),
9553 'perms' => 1,
9554 'label' => 'LinkToIntervention',
9555 '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') . ')'),
9556 'supplier_proposal' => array(
9557 'enabled' => isModEnabled('supplier_proposal'),
9558 'perms' => 1,
9559 'label' => 'LinkToSupplierProposal',
9560 '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') . ')'),
9561 'order_supplier' => array(
9562 'enabled' => isModEnabled("supplier_order"),
9563 'perms' => 1,
9564 'label' => 'LinkToSupplierOrder',
9565 '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') . ')'),
9566 'invoice_supplier' => array(
9567 'enabled' => isModEnabled("supplier_invoice"),
9568 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9569 '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') . ')'),
9570 'ticket' => array(
9571 'enabled' => isModEnabled('ticket'),
9572 'perms' => 1,
9573 'label' => 'LinkToTicket',
9574 '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') . ')'),
9575 'mo' => array(
9576 'enabled' => isModEnabled('mrp'),
9577 'perms' => 1,
9578 'label' => 'LinkToMo',
9579 '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') . ')')
9580 );
9581 }
9582
9583 if ($object->table_element == 'commande_fournisseur') {
9584 $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').')';
9585 } elseif ($object->table_element == 'mrp_mo') {
9586 $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').')';
9587 }
9588
9589 $reshook = 0; // Ensure $reshook is defined for static analysis
9590 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9591 // Can complete the possiblelink array
9592 $hookmanager->initHooks(array('commonobject'));
9593 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9594 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9595 }
9596
9597 if (empty($reshook)) {
9598 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9599 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9600 }
9601 } elseif ($reshook > 0) {
9602 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9603 $possiblelinks = $hookmanager->resArray;
9604 }
9605 }
9606
9607 foreach ($possiblelinks as $key => $possiblelink) {
9608 $num = 0;
9609
9610 if (empty($possiblelink['enabled'])) {
9611 continue;
9612 }
9613
9614 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9615 print '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9616
9617 if (getDolGlobalString('MAIN_LINK_BY_REF_IN_LINKTO')) {
9618 print '<br>'."\n";
9619 print '<!-- form to add a link from anywhere -->'."\n";
9620 print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9621 print '<input type="hidden" name="id" value="' . $object->id . '">';
9622 print '<input type="hidden" name="action" value="addlinkbyref">';
9623 print '<input type="hidden" name="token" value="' . newToken() . '">';
9624 print '<input type="hidden" name="addlink" value="' . $key . '">';
9625 print '<table class="noborder">';
9626 print '<tr>';
9627 //print '<td>' . $langs->trans("Ref") . '</td>';
9628 print '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9629 print '<input type="submit" class="button small valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9630 print '<input type="submit" class="button small" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9631 print '</tr>';
9632 print '</table>';
9633 print '</form>';
9634 }
9635
9636 $sql = $possiblelink['sql'];
9637
9638 $resqllist = $this->db->query($sql);
9639 if ($resqllist) {
9640 $num = $this->db->num_rows($resqllist);
9641 $i = 0;
9642
9643 print '<br>';
9644 print '<!-- form to add a link from object to same thirdparty -->'."\n";
9645 print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9646 print '<input type="hidden" name="action" value="addlink">';
9647 print '<input type="hidden" name="token" value="' . newToken() . '">';
9648 print '<input type="hidden" name="id" value="' . $object->id . '">';
9649 print '<input type="hidden" name="addlink" value="' . $key . '">';
9650 print '<table class="noborder">';
9651 print '<tr class="liste_titre">';
9652 print '<td class="nowrap"></td>';
9653 print '<td class="center">' . $langs->trans("Ref") . '</td>';
9654 print '<td class="left">' . $langs->trans("RefCustomer") . '</td>';
9655 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9656 print '<td class="left">' . $langs->trans("Company") . '</td>';
9657 print '</tr>';
9658 while ($i < $num) {
9659 $objp = $this->db->fetch_object($resqllist);
9660
9661 print '<tr class="oddeven">';
9662 print '<td class="left">';
9663 print '<input type="radio" name="idtolinkto" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9664 print '</td>';
9665 print '<td class="center"><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9666 print '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9667 print '<td class="right">';
9668 if ($possiblelink['label'] == 'LinkToContract') {
9669 $form = new Form($this->db);
9670 print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9671 }
9672 print '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9673 print '</td>';
9674 print '<td>' . $objp->name . '</td>';
9675 print '</tr>';
9676 $i++;
9677 }
9678 print '</table>';
9679 print '<div class="center">';
9680 if ($num) {
9681 print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly small" value="' . $langs->trans('ToLink') . '">';
9682 }
9683 if (empty($conf->use_javascript_ajax)) {
9684 print '<input type="submit" class="button button-cancel marginleftonly marginrightonly small" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9685 } else {
9686 print '<input type="submit" onclick="jQuery(\'#' . $key . 'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly small" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9687 }
9688 print '</form>';
9689 $this->db->free($resqllist);
9690 } else {
9691 dol_print_error($this->db);
9692 }
9693 print '</div>';
9694
9695 //$linktoelem.=($linktoelem?' &nbsp; ':'');
9696 if ($num > 0 || getDolGlobalString('MAIN_LINK_BY_REF_IN_LINKTO')) {
9697 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
9698 // } else $linktoelem.=$langs->trans($possiblelink['label']);
9699 } else {
9700 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
9701 }
9702 }
9703 }
9704
9705 if ($linktoelemlist) {
9706 $linktoelem = '
9707 <dl class="dropdown" id="linktoobjectname">
9708 ';
9709 if (!empty($conf->use_javascript_ajax)) {
9710 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
9711 }
9712 $linktoelem .= '<dd>
9713 <div class="multiselectlinkto">
9714 <ul class="ulselectedfields">' . $linktoelemlist . '
9715 </ul>
9716 </div>
9717 </dd>
9718 </dl>';
9719 } else {
9720 $linktoelem = '';
9721 }
9722
9723 if (!empty($conf->use_javascript_ajax)) {
9724 print '<!-- Add js to show linkto box -->
9725 <script nonce="' . getNonce() . '">
9726 jQuery(document).ready(function() {
9727 jQuery(".linkto").click(function() {
9728 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
9729 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
9730 });
9731 });
9732 </script>
9733 ';
9734 }
9735
9736 return $linktoelem;
9737 }
9738
9753 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'width75', $labelyes = 'Yes', $labelno = 'No')
9754 {
9755 global $langs;
9756
9757 $yes = "yes";
9758 $no = "no";
9759 if ($option) {
9760 $yes = "1";
9761 $no = "0";
9762 }
9763
9764 $disabled = ($disabled ? ' disabled' : '');
9765
9766 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
9767 if ($useempty) {
9768 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
9769 }
9770 if (("$value" == 'yes') || ($value == 1)) {
9771 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
9772 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
9773 } else {
9774 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
9775 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
9776 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
9777 }
9778 $resultyesno .= '</select>' . "\n";
9779
9780 if ($addjscombo) {
9781 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
9782 }
9783
9784 return $resultyesno;
9785 }
9786
9787 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9788
9798 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
9799 {
9800 // phpcs:enable
9801 $sql = "SELECT rowid, label";
9802 $sql .= " FROM " . $this->db->prefix() . "export_model";
9803 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
9804 $sql .= " ORDER BY rowid";
9805 $result = $this->db->query($sql);
9806 if ($result) {
9807 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
9808 if ($useempty) {
9809 print '<option value="-1">&nbsp;</option>';
9810 }
9811
9812 $num = $this->db->num_rows($result);
9813 $i = 0;
9814 while ($i < $num) {
9815 $obj = $this->db->fetch_object($result);
9816 if ($selected == $obj->rowid) {
9817 print '<option value="' . $obj->rowid . '" selected>';
9818 } else {
9819 print '<option value="' . $obj->rowid . '">';
9820 }
9821 print $obj->label;
9822 print '</option>';
9823 $i++;
9824 }
9825 print "</select>";
9826 } else {
9827 dol_print_error($this->db);
9828 }
9829 }
9830
9849 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
9850 {
9851 global $conf, $langs, $hookmanager, $extralanguages;
9852
9853 $ret = '';
9854 if (empty($fieldid)) {
9855 $fieldid = 'rowid';
9856 }
9857 if (empty($fieldref)) {
9858 $fieldref = 'ref';
9859 }
9860
9861 // Preparing gender's display if there is one
9862 $addgendertxt = '';
9863 if (property_exists($object, 'gender') && !empty($object->gender)) {
9864 $addgendertxt = ' ';
9865 switch ($object->gender) {
9866 case 'man':
9867 $addgendertxt .= '<i class="fas fa-mars"></i>';
9868 break;
9869 case 'woman':
9870 $addgendertxt .= '<i class="fas fa-venus"></i>';
9871 break;
9872 case 'other':
9873 $addgendertxt .= '<i class="fas fa-transgender"></i>';
9874 break;
9875 }
9876 }
9877
9878 // Add where from hooks
9879 if (is_object($hookmanager)) {
9880 $parameters = array('showrefnav' => true);
9881 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
9882 $object->next_prev_filter .= $hookmanager->resPrint;
9883 }
9884
9885 $previous_ref = $next_ref = '';
9886 if ($shownav) {
9887 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
9888 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
9889
9890 $navurl = $_SERVER["PHP_SELF"];
9891 // Special case for project/task page
9892 if ($paramid == 'project_ref') {
9893 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
9894 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
9895 $paramid = 'ref';
9896 }
9897 }
9898
9899 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
9900 // accesskey is for Mac: CTRL + key for all browsers
9901 $stringforfirstkey = $langs->trans("KeyboardShortcut");
9902 if ($conf->browser->name == 'chrome') {
9903 $stringforfirstkey .= ' ALT +';
9904 } elseif ($conf->browser->name == 'firefox') {
9905 $stringforfirstkey .= ' ALT + SHIFT +';
9906 } else {
9907 $stringforfirstkey .= ' CTL +';
9908 }
9909
9910 $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>';
9911 $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>';
9912 }
9913
9914 //print "xx".$previous_ref."x".$next_ref;
9915 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
9916
9917 // Right part of banner
9918 if ($morehtmlright) {
9919 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
9920 }
9921
9922 if ($previous_ref || $next_ref || $morehtml) {
9923 $ret .= '<div class="pagination paginationref"><ul class="right">';
9924 }
9925 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
9926 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
9927 }
9928 if ($shownav && ($previous_ref || $next_ref)) {
9929 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
9930 $ret .= '<li class="pagination">' . $next_ref . '</li>';
9931 }
9932 if ($previous_ref || $next_ref || $morehtml) {
9933 $ret .= '</ul></div>';
9934 }
9935
9936 // Status
9937 $parameters = array('morehtmlstatus' => $morehtmlstatus);
9938 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
9939 if (empty($reshook)) {
9940 $morehtmlstatus .= $hookmanager->resPrint;
9941 } else {
9942 $morehtmlstatus = $hookmanager->resPrint;
9943 }
9944 if ($morehtmlstatus) {
9945 $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
9946 }
9947
9948 $parameters = array();
9949 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
9950 if (empty($reshook)) {
9951 $morehtmlref .= $hookmanager->resPrint;
9952 } elseif ($reshook > 0) {
9953 $morehtmlref = $hookmanager->resPrint;
9954 }
9955
9956 // Left part of banner
9957 if ($morehtmlleft) {
9958 if ($conf->browser->layout == 'phone') {
9959 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
9960 } else {
9961 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
9962 }
9963 }
9964
9965 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
9966 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
9967
9968 // For thirdparty, contact, user, member, the ref is the id, so we show something else
9969 if ($object->element == 'societe') {
9970 $ret .= dol_htmlentities($object->name);
9971
9972 // List of extra languages
9973 $arrayoflangcode = array();
9974 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
9975 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
9976 }
9977
9978 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
9979 if (!is_object($extralanguages)) {
9980 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
9981 $extralanguages = new ExtraLanguages($this->db);
9982 }
9983 $extralanguages->fetch_name_extralanguages('societe');
9984
9985 if (!empty($extralanguages->attributes['societe']['name'])) {
9986 $object->fetchValuesForExtraLanguages();
9987
9988 $htmltext = '';
9989 // If there is extra languages
9990 foreach ($arrayoflangcode as $extralangcode) {
9991 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
9992 if ($object->array_languages['name'][$extralangcode]) {
9993 $htmltext .= $object->array_languages['name'][$extralangcode];
9994 } else {
9995 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
9996 }
9997 }
9998 $ret .= '<!-- Show translations of name -->' . "\n";
9999 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
10000 }
10001 }
10002 } elseif ($object->element == 'member') {
10003 '@phan-var-force Adherent $object';
10004 $ret .= $object->ref . '<br>';
10005 $fullname = $object->getFullName($langs);
10006 if ($object->morphy == 'mor' && $object->societe) {
10007 $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
10008 } else {
10009 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
10010 }
10011 } elseif (in_array($object->element, array('contact', 'user'))) {
10012 $ret .= dol_htmlentities($object->getFullName($langs)) . $addgendertxt;
10013 } elseif ($object->element == 'usergroup') {
10014 $ret .= dol_htmlentities($object->name);
10015 } elseif (in_array($object->element, array('action', 'agenda'))) {
10016 '@phan-var-force ActionComm $object';
10017 $ret .= $object->ref . '<br>' . $object->label;
10018 } elseif (in_array($object->element, array('adherent_type'))) {
10019 $ret .= $object->label;
10020 } elseif ($object->element == 'ecm_directories') {
10021 $ret .= '';
10022 } elseif ($fieldref != 'none') {
10023 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
10024 }
10025 if ($morehtmlref) {
10026 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
10027 if (substr($morehtmlref, 0, 4) != '<div') {
10028 $ret .= ' ';
10029 }
10030
10031 $ret .= $morehtmlref;
10032 }
10033
10034 $ret .= '</div>';
10035
10036 $ret .= '</div><!-- End banner content -->';
10037
10038 return $ret;
10039 }
10040
10041
10050 public function showbarcode(&$object, $width = 100, $morecss = '')
10051 {
10052 global $conf;
10053
10054 //Check if barcode is filled in the card
10055 if (empty($object->barcode)) {
10056 return '';
10057 }
10058
10059 // Complete object if not complete
10060 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10061 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10062 $result = $object->fetch_barcode();
10063 //Check if fetch_barcode() failed
10064 if ($result < 1) {
10065 return '<!-- ErrorFetchBarcode -->';
10066 }
10067 }
10068
10069 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10070 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10071 $out = '<!-- url barcode = ' . $url . ' -->';
10072 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10073
10074 return $out;
10075 }
10076
10094 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10095 {
10096 global $conf, $langs;
10097
10098 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10099 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10100
10101 $dir = '';
10102 $file = '';
10103 $originalfile = '';
10104 $altfile = '';
10105 $email = '';
10106 $capture = '';
10107 if ($modulepart == 'societe') {
10108 $dir = $conf->societe->multidir_output[$entity];
10109 if (!empty($object->logo)) {
10110 if (dolIsAllowedForPreview($object->logo)) {
10111 if ((string) $imagesize == 'mini') {
10112 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10113 } elseif ((string) $imagesize == 'small') {
10114 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10115 } else {
10116 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10117 }
10118 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10119 }
10120 }
10121 $email = $object->email;
10122 } elseif ($modulepart == 'contact') {
10123 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10124 if (!empty($object->photo)) {
10125 if (dolIsAllowedForPreview($object->photo)) {
10126 if ((string) $imagesize == 'mini') {
10127 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10128 } elseif ((string) $imagesize == 'small') {
10129 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10130 } else {
10131 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10132 }
10133 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10134 }
10135 }
10136 $email = $object->email;
10137 $capture = 'user';
10138 } elseif ($modulepart == 'userphoto') {
10139 $dir = $conf->user->dir_output;
10140 if (!empty($object->photo)) {
10141 if (dolIsAllowedForPreview($object->photo)) {
10142 if ((string) $imagesize == 'mini') {
10143 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10144 } elseif ((string) $imagesize == 'small') {
10145 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10146 } else {
10147 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10148 }
10149 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10150 }
10151 }
10152 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10153 $altfile = $object->id . ".jpg"; // For backward compatibility
10154 }
10155 $email = $object->email;
10156 $capture = 'user';
10157 } elseif ($modulepart == 'memberphoto') {
10158 $dir = $conf->adherent->dir_output;
10159 if (!empty($object->photo)) {
10160 if (dolIsAllowedForPreview($object->photo)) {
10161 if ((string) $imagesize == 'mini') {
10162 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10163 } elseif ((string) $imagesize == 'small') {
10164 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10165 } else {
10166 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10167 }
10168 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10169 }
10170 }
10171 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10172 $altfile = $object->id . ".jpg"; // For backward compatibility
10173 }
10174 $email = $object->email;
10175 $capture = 'user';
10176 } else {
10177 // Generic case to show photos
10178 // TODO Implement this method in previous objects so we can always use this generic method.
10179 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10180 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10181
10182 $dir = $tmpdata['dir'];
10183 $file = $tmpdata['file'];
10184 $originalfile = $tmpdata['originalfile'];
10185 $altfile = $tmpdata['altfile'];
10186 $email = $tmpdata['email'];
10187 $capture = $tmpdata['capture'];
10188 }
10189 }
10190
10191 if ($forcecapture) {
10192 $capture = $forcecapture;
10193 }
10194
10195 $ret = '';
10196
10197 if ($dir) {
10198 if ($file && file_exists($dir . "/" . $file)) {
10199 if ($addlinktofullsize) {
10200 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10201 if ($urladvanced) {
10202 $ret .= '<a href="' . $urladvanced . '">';
10203 } else {
10204 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10205 }
10206 }
10207 $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 . '">';
10208 if ($addlinktofullsize) {
10209 $ret .= '</a>';
10210 }
10211 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
10212 if ($addlinktofullsize) {
10213 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10214 if ($urladvanced) {
10215 $ret .= '<a href="' . $urladvanced . '">';
10216 } else {
10217 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10218 }
10219 }
10220 $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 . '">';
10221 if ($addlinktofullsize) {
10222 $ret .= '</a>';
10223 }
10224 } else {
10225 $nophoto = '/public/theme/common/nophoto.png';
10226 $defaultimg = 'identicon'; // For gravatar
10227 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
10228 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
10229 $nophoto = 'company';
10230 } else {
10231 $nophoto = '/public/theme/common/user_anonymous.png';
10232 if (!empty($object->gender) && $object->gender == 'man') {
10233 $nophoto = '/public/theme/common/user_man.png';
10234 }
10235 if (!empty($object->gender) && $object->gender == 'woman') {
10236 $nophoto = '/public/theme/common/user_woman.png';
10237 }
10238 }
10239 }
10240
10241 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
10242 // see https://gravatar.com/site/implement/images/php/
10243 $ret .= '<!-- Put link to gravatar -->';
10244 $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
10245 } else {
10246 if ($nophoto == 'company') {
10247 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
10248 //$ret .= '<div class="difforspanimgright"></div>';
10249 } else {
10250 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
10251 }
10252 }
10253 }
10254
10255 if ($caneditfield) {
10256 if ($object->photo) {
10257 $ret .= "<br>\n";
10258 }
10259 $ret .= '<table class="nobordernopadding centpercent">';
10260 if ($object->photo) {
10261 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
10262 }
10263 $ret .= '<tr><td class="tdoverflow">';
10264 $maxfilesizearray = getMaxFileSizeArray();
10265 $maxmin = $maxfilesizearray['maxmin'];
10266 if ($maxmin > 0) {
10267 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
10268 }
10269 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
10270 $ret .= '</td></tr>';
10271 $ret .= '</table>';
10272 }
10273 }
10274
10275 return $ret;
10276 }
10277
10278 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10279
10296 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
10297 {
10298 // phpcs:enable
10299 global $conf, $user, $langs;
10300
10301 // Allow excluding groups
10302 $excludeGroups = null;
10303 if (is_array($exclude)) {
10304 $excludeGroups = implode(",", $exclude);
10305 }
10306 // Allow including groups
10307 $includeGroups = null;
10308 if (is_array($include)) {
10309 $includeGroups = implode(",", $include);
10310 }
10311
10312 if (!is_array($selected)) {
10313 $selected = array($selected);
10314 }
10315
10316 $out = '';
10317
10318 // Build sql to search groups
10319 $sql = "SELECT ug.rowid, ug.nom as name";
10320 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10321 $sql .= ", e.label";
10322 }
10323 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
10324 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10325 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
10326 if ($force_entity) {
10327 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
10328 } else {
10329 $sql .= " WHERE ug.entity IS NOT NULL";
10330 }
10331 } else {
10332 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
10333 }
10334 if (is_array($exclude) && $excludeGroups) {
10335 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
10336 }
10337 if (is_array($include) && $includeGroups) {
10338 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
10339 }
10340 $sql .= " ORDER BY ug.nom ASC";
10341
10342 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
10343 $resql = $this->db->query($sql);
10344 if ($resql) {
10345 // Enhance with select2
10346 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10347
10348 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
10349
10350 $num = $this->db->num_rows($resql);
10351 $i = 0;
10352 if ($num) {
10353 if ($show_empty && !$multiple) {
10354 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10355 }
10356
10357 while ($i < $num) {
10358 $obj = $this->db->fetch_object($resql);
10359 $disableline = 0;
10360 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
10361 $disableline = 1;
10362 }
10363
10364 $label = $obj->name;
10365 $labelhtml = $obj->name;
10366 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
10367 $label .= " (" . $obj->label . ")";
10368 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
10369 }
10370
10371 $out .= '<option value="' . $obj->rowid . '"';
10372 if ($disableline) {
10373 $out .= ' disabled';
10374 }
10375 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
10376 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
10377 $out .= ' selected';
10378 }
10379 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
10380 $out .= '>';
10381 $out .= $label;
10382 $out .= '</option>';
10383 $i++;
10384 }
10385 } else {
10386 if ($show_empty) {
10387 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
10388 }
10389 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
10390 }
10391 $out .= '</select>';
10392
10393 $out .= ajax_combobox($htmlname);
10394 } else {
10395 dol_print_error($this->db);
10396 }
10397
10398 return $out;
10399 }
10400
10401
10408 public function showFilterButtons($pos = '')
10409 {
10410 $out = '<div class="nowraponall">';
10411 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
10412 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
10413 $out .= '</div>';
10414
10415 return $out;
10416 }
10417
10426 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10427 {
10428 global $conf;
10429
10430 $out = '';
10431
10432 if (!empty($conf->use_javascript_ajax)) {
10433 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
10434 }
10435 $out .= '<script nonce="' . getNonce() . '">
10436 $(document).ready(function() {
10437 $("#' . $cssclass . 's").click(function() {
10438 if($(this).is(\':checked\')){
10439 console.log("We check all ' . $cssclass . ' and trigger the change method");
10440 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
10441 }
10442 else
10443 {
10444 console.log("We uncheck all");
10445 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
10446 }' . "\n";
10447 if ($calljsfunction) {
10448 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
10449 }
10450 $out .= ' });
10451 $(".' . $cssclass . '").change(function() {
10452 $(this).closest("tr").toggleClass("highlight", this.checked);
10453 });
10454 });
10455 </script>';
10456
10457 return $out;
10458 }
10459
10469 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10470 {
10471 $out = $this->showFilterButtons();
10472 if ($addcheckuncheckall) {
10473 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10474 }
10475 return $out;
10476 }
10477
10491 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10492 {
10493 global $langs, $user;
10494
10495 $out = '';
10496 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10497 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10498 if (!empty($excludeid)) {
10499 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10500 }
10501 $sql .= " ORDER BY label";
10502
10503 $resql = $this->db->query($sql);
10504 if ($resql) {
10505 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10506 if ($useempty) {
10507 $out .= '<option value="0">&nbsp;</option>';
10508 }
10509
10510 while ($obj = $this->db->fetch_object($resql)) {
10511 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10512 }
10513 $out .= '</select>';
10514 $out .= ajax_combobox('select_' . $htmlname);
10515
10516 if (!empty($htmlname) && $user->admin && $info_admin) {
10517 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10518 }
10519
10520 if (!empty($target)) {
10521 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10522 $resql = $this->db->query($sql);
10523 if ($resql) {
10524 if ($this->db->num_rows($resql) > 0) {
10525 $obj = $this->db->fetch_object($resql);
10526 $out .= '<script nonce="' . getNonce() . '">
10527 $(function() {
10528 $("select[name=' . $target . ']").on("change", function() {
10529 var current_val = $(this).val();
10530 if (current_val == ' . $obj->id . ') {';
10531 if (!empty($default_selected) || !empty($selected)) {
10532 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10533 }
10534
10535 $out .= '
10536 $("select[name=' . $htmlname . ']").change();
10537 }
10538 });
10539
10540 $("select[name=' . $htmlname . ']").change(function() {
10541
10542 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10543 // get price of kilometer to fill the unit price
10544 $.ajax({
10545 method: "POST",
10546 dataType: "json",
10547 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10548 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
10549 }).done(function( data, textStatus, jqXHR ) {
10550 console.log(data);
10551 if (typeof data.up != "undefined") {
10552 $("input[name=value_unit]").val(data.up);
10553 $("select[name=' . $htmlname . ']").attr("title", data.title);
10554 } else {
10555 $("input[name=value_unit]").val("");
10556 $("select[name=' . $htmlname . ']").attr("title", "");
10557 }
10558 });
10559 }
10560 });
10561 });
10562 </script>';
10563 }
10564 }
10565 }
10566 } else {
10567 dol_print_error($this->db);
10568 }
10569
10570 return $out;
10571 }
10572
10581 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10582 {
10583 global $conf, $langs;
10584
10585 $out = '';
10586 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10587 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10588
10589 $resql = $this->db->query($sql);
10590 if ($resql) {
10591 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10592 if ($useempty) {
10593 $out .= '<option value="0"></option>';
10594 }
10595
10596 while ($obj = $this->db->fetch_object($resql)) {
10597 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10598 }
10599 $out .= '</select>';
10600 } else {
10601 dol_print_error($this->db);
10602 }
10603
10604 return $out;
10605 }
10606
10617 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10618 {
10619 global $langs;
10620
10621 $out = '';
10622 $sql = "SELECT id, code, label";
10623 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
10624 $sql .= " WHERE active = 1";
10625
10626 $resql = $this->db->query($sql);
10627 if ($resql) {
10628 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10629 if ($useempty) {
10630 $out .= '<option value="0"></option>';
10631 }
10632 if ($allchoice) {
10633 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10634 }
10635
10636 $field = 'code';
10637 if ($useid) {
10638 $field = 'id';
10639 }
10640
10641 while ($obj = $this->db->fetch_object($resql)) {
10642 $key = $langs->trans($obj->code);
10643 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10644 }
10645 $out .= '</select>';
10646
10647 $out .= ajax_combobox('select_'.$htmlname);
10648 } else {
10649 dol_print_error($this->db);
10650 }
10651
10652 return $out;
10653 }
10654
10673 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)
10674 {
10675 global $user, $conf, $langs;
10676
10677 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10678
10679 if (is_null($usertofilter)) {
10680 $usertofilter = $user;
10681 }
10682
10683 $out = '';
10684
10685 $hideunselectables = false;
10686 if (getDolGlobalString('PROJECT_HIDE_UNSELECTABLES')) {
10687 $hideunselectables = true;
10688 }
10689
10690 if (empty($projectsListId)) {
10691 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
10692 $projectstatic = new Project($this->db);
10693 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10694 }
10695 }
10696
10697 // Search all projects
10698 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10699 p.title, p.fk_soc, p.fk_statut, p.public,";
10700 $sql .= ' s.nom as name';
10701 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
10702 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
10703 $sql .= ' ' . $this->db->prefix() . 'facture as f';
10704 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
10705 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
10706 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
10707 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
10708 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
10709 $sql .= " ORDER BY p.ref, f.ref ASC";
10710
10711 $resql = $this->db->query($sql);
10712 if ($resql) {
10713 // Use select2 selector
10714 if (!empty($conf->use_javascript_ajax)) {
10715 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10716 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
10717 $out .= $comboenhancement;
10718 $morecss = 'minwidth200imp maxwidth500';
10719 }
10720
10721 if (empty($option_only)) {
10722 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10723 }
10724 if (!empty($show_empty)) {
10725 $out .= '<option value="0" class="optiongrey">';
10726 if (!is_numeric($show_empty)) {
10727 $out .= $show_empty;
10728 } else {
10729 $out .= '&nbsp;';
10730 }
10731 $out .= '</option>';
10732 }
10733 $num = $this->db->num_rows($resql);
10734 $i = 0;
10735 if ($num) {
10736 while ($i < $num) {
10737 $obj = $this->db->fetch_object($resql);
10738 // 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.
10739 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
10740 // Do nothing
10741 } else {
10742 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
10743 $i++;
10744 continue;
10745 }
10746
10747 $labeltoshow = '';
10748
10749 if ($showproject == 'all') {
10750 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
10751 if ($obj->name) {
10752 $labeltoshow .= ' - ' . $obj->name; // Soc name
10753 }
10754
10755 $disabled = 0;
10756 if ($obj->fk_statut == Project::STATUS_DRAFT) {
10757 $disabled = 1;
10758 $labeltoshow .= ' - ' . $langs->trans("Draft");
10759 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
10760 if ($discard_closed == 2) {
10761 $disabled = 1;
10762 }
10763 $labeltoshow .= ' - ' . $langs->trans("Closed");
10764 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
10765 $disabled = 1;
10766 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
10767 }
10768 }
10769
10770 if (!empty($selected) && $selected == $obj->rowid) {
10771 $out .= '<option value="' . $obj->rowid . '" selected';
10772 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10773 $out .= '>' . $labeltoshow . '</option>';
10774 } else {
10775 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
10776 $resultat = '';
10777 } else {
10778 $resultat = '<option value="' . $obj->rowid . '"';
10779 if ($disabled) {
10780 $resultat .= ' disabled';
10781 }
10782 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
10783 //else $labeltoshow.=' ('.$langs->trans("Private").')';
10784 $resultat .= '>';
10785 $resultat .= $labeltoshow;
10786 $resultat .= '</option>';
10787 }
10788 $out .= $resultat;
10789 }
10790 }
10791 $i++;
10792 }
10793 }
10794 if (empty($option_only)) {
10795 $out .= '</select>';
10796 }
10797
10798 $this->db->free($resql);
10799
10800 return $out;
10801 } else {
10802 dol_print_error($this->db);
10803 return '';
10804 }
10805 }
10806
10820 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
10821 {
10822 global $conf, $langs;
10823
10824 $out = '';
10825
10826 dol_syslog('FactureRec::fetch', LOG_DEBUG);
10827
10828 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
10829 //$sql.= ', el.fk_source';
10830 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
10831 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
10832 $sql .= " ORDER BY f.titre ASC";
10833
10834 $resql = $this->db->query($sql);
10835 if ($resql) {
10836 // Use select2 selector
10837 if (!empty($conf->use_javascript_ajax)) {
10838 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10839 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
10840 $out .= $comboenhancement;
10841 $morecss = 'minwidth200imp maxwidth500';
10842 }
10843
10844 if (empty($option_only)) {
10845 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10846 }
10847 if (!empty($show_empty)) {
10848 $out .= '<option value="0" class="optiongrey">';
10849 if (!is_numeric($show_empty)) {
10850 $out .= $show_empty;
10851 } else {
10852 $out .= '&nbsp;';
10853 }
10854 $out .= '</option>';
10855 }
10856 $num = $this->db->num_rows($resql);
10857 if ($num) {
10858 while ($obj = $this->db->fetch_object($resql)) {
10859 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
10860
10861 $disabled = 0;
10862 if (!empty($obj->suspended)) {
10863 $disabled = 1;
10864 $labeltoshow .= ' - ' . $langs->trans("Closed");
10865 }
10866
10867
10868 if (!empty($selected) && $selected == $obj->rowid) {
10869 $out .= '<option value="' . $obj->rowid . '" selected';
10870 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10871 $out .= '>' . $labeltoshow . '</option>';
10872 } else {
10873 if ($disabled && ($selected != $obj->rowid)) {
10874 $resultat = '';
10875 } else {
10876 $resultat = '<option value="' . $obj->rowid . '"';
10877 if ($disabled) {
10878 $resultat .= ' disabled';
10879 }
10880 $resultat .= '>';
10881 $resultat .= $labeltoshow;
10882 $resultat .= '</option>';
10883 }
10884 $out .= $resultat;
10885 }
10886 }
10887 }
10888 if (empty($option_only)) {
10889 $out .= '</select>';
10890 }
10891
10892 print $out;
10893
10894 $this->db->free($resql);
10895 return $num;
10896 } else {
10897 $this->errors[] = $this->db->lasterror;
10898 return -1;
10899 }
10900 }
10901
10911 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '')
10912 {
10913 global $langs;
10914
10915 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
10916 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
10917 }
10918
10919 $ret = '';
10920
10921 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
10922 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
10923 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
10924 $ret .= '</a>';
10925
10926 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
10927
10928 // Show select fields as tags.
10929 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
10930
10931 if ($search_component_params_hidden) {
10932 // Split the criteria on each AND
10933 //var_dump($search_component_params_hidden);
10934
10935 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
10936
10937 // $arrayofandtags is now array( '...' , '...', ...)
10938 // Show each AND part
10939 foreach ($arrayofandtags as $tmpkey => $tmpval) {
10940 $errormessage = '';
10941 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
10942 if ($errormessage) {
10943 $this->error = 'ERROR in parsing search string: '.$errormessage;
10944 }
10945 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
10946 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
10947 $searchtags = removeGlobalParenthesis($searchtags);
10948
10949 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
10950 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
10951 $ret .= dol_escape_htmltag($searchtags);
10952 $ret .= '</span>';
10953 }
10954 }
10955
10956 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
10957
10958 //$ret .= search_component_params
10959 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
10960 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
10961
10962 $show_search_component_params_hidden = 1;
10963 if ($show_search_component_params_hidden) {
10964 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
10965 }
10966 $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%')) -->";
10967 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
10968 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
10969
10970 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
10971 foreach ($arrayofcriterias as $criteria) {
10972 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
10973 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
10974 continue;
10975 }
10976 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
10977 continue;
10978 }
10979 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
10980 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
10981 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
10982 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
10983 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
10984 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
10985 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
10986 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
10987 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
10988 } else {
10989 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
10990 }
10991 }
10992 }
10993
10994 $ret .= '</div>';
10995
10996 $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";
10997 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
10998
10999 $ret .= '</div>';
11000 $ret .= '</div>';
11001
11002 $ret .= '<script>
11003 jQuery(".tagsearchdelete").click(function(e) {
11004 var filterid = $(this).parents().attr("data-ufilterid");
11005 console.log("We click to delete the criteria nb "+filterid);
11006
11007 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
11008 var newparamstring = \'\';
11009 $(\'.tagsearch\').each(function(index, element) {
11010 tmpfilterid = $(this).attr("data-ufilterid");
11011 if (tmpfilterid != filterid) {
11012 // We keep this criteria
11013 if (newparamstring == \'\') {
11014 newparamstring = $(this).attr("data-ufilter");
11015 } else {
11016 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
11017 }
11018 }
11019 });
11020 console.log("newparamstring = "+newparamstring);
11021
11022 jQuery("#search_component_params_hidden").val(newparamstring);
11023
11024 // We repost the form
11025 $(this).closest(\'form\').submit();
11026 });
11027
11028 jQuery("#search_component_params_input").keydown(function(e) {
11029 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
11030 console.log(e.which);
11031 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
11032 /* We click on back when the input field is already empty */
11033 event.preventDefault();
11034 jQuery("#divsearch_component_params .tagsearch").last().remove();
11035 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
11036 var s = "";
11037 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
11038 if (s != "") {
11039 s = s + " AND ";
11040 }
11041 s = s + $(this).attr("data-ufilter");
11042 });
11043 console.log("New value for search_component_params_hidden = "+s);
11044 jQuery("#search_component_params_hidden").val(s);
11045 }
11046 });
11047
11048 </script>
11049 ';
11050
11051 return $ret;
11052 }
11053
11063 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
11064 {
11065 global $langs, $user;
11066
11067 $retstring = '';
11068
11069 $TModels = array();
11070
11071 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
11072 $formmail = new FormMail($this->db);
11073 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
11074
11075 if ($default) {
11076 $TModels[0] = $langs->trans('DefaultMailModel');
11077 }
11078 if ($result > 0) {
11079 foreach ($formmail->lines_model as $model) {
11080 $TModels[$model->id] = $model->label;
11081 }
11082 }
11083
11084 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
11085
11086 foreach ($TModels as $id_model => $label_model) {
11087 $retstring .= '<option value="' . $id_model . '"';
11088 $retstring .= ">" . $label_model . "</option>";
11089 }
11090
11091 $retstring .= "</select>";
11092
11093 if ($addjscombo) {
11094 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
11095 }
11096
11097 return $retstring;
11098 }
11099
11111 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
11112 {
11113 global $langs;
11114
11115 $buttons = array();
11116
11117 $save = array(
11118 'name' => 'save',
11119 'label_key' => $save_label,
11120 );
11121
11122 if ($save_label == 'Create' || $save_label == 'Add') {
11123 $save['name'] = 'add';
11124 } elseif ($save_label == 'Modify') {
11125 $save['name'] = 'edit';
11126 }
11127
11128 $cancel = array(
11129 'name' => 'cancel',
11130 'label_key' => 'Cancel',
11131 );
11132
11133 !empty($save_label) ? $buttons[] = $save : '';
11134
11135 if (!empty($morebuttons)) {
11136 $buttons[] = $morebuttons;
11137 }
11138
11139 !empty($cancel_label) ? $buttons[] = $cancel : '';
11140
11141 $retstring = $withoutdiv ? '' : '<div class="center">';
11142
11143 foreach ($buttons as $button) {
11144 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
11145 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
11146 }
11147 $retstring .= $withoutdiv ? '' : '</div>';
11148
11149 if ($dol_openinpopup) {
11150 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . $dol_openinpopup . ' context, so we enable the close of dialog on cancel -->' . "\n";
11151 $retstring .= '<script nonce="' . getNonce() . '">';
11152 $retstring .= 'jQuery(".button-cancel").click(function(e) {
11153 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . $dol_openinpopup . '\');
11154 window.parent.jQuery(\'#idfordialog' . $dol_openinpopup . '\').dialog(\'close\');
11155 });';
11156 $retstring .= '</script>';
11157 }
11158
11159 return $retstring;
11160 }
11161
11162
11163 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11164
11171 {
11172 // phpcs:enable
11173 global $langs;
11174
11175 $num = count($this->cache_invoice_subtype);
11176 if ($num > 0) {
11177 return 0; // Cache already loaded
11178 }
11179
11180 dol_syslog(__METHOD__, LOG_DEBUG);
11181
11182 $sql = "SELECT rowid, code, label as label";
11183 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
11184 $sql .= " WHERE active = 1";
11185
11186 $resql = $this->db->query($sql);
11187 if ($resql) {
11188 $num = $this->db->num_rows($resql);
11189 $i = 0;
11190 while ($i < $num) {
11191 $obj = $this->db->fetch_object($resql);
11192
11193 // If translation exists, we use it, otherwise we take the default wording
11194 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
11195 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
11196 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
11197 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
11198 $i++;
11199 }
11200
11201 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
11202
11203 return $num;
11204 } else {
11205 dol_print_error($this->db);
11206 return -1;
11207 }
11208 }
11209
11210
11221 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
11222 {
11223 global $langs, $user;
11224
11225 $out = '';
11226 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
11227
11228 $this->load_cache_invoice_subtype();
11229
11230 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
11231 if ($addempty) {
11232 $out .= '<option value="0">&nbsp;</option>';
11233 }
11234
11235 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
11236 $label = $subtype['label'];
11237 $out .= '<option value="' . $subtype['rowid'] . '"';
11238 if ($selected == $subtype['rowid']) {
11239 $out .= ' selected="selected"';
11240 }
11241 $out .= '>';
11242 $out .= $label;
11243 $out .= '</option>';
11244 }
11245
11246 $out .= '</select>';
11247 if ($user->admin && empty($noinfoadmin)) {
11248 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11249 }
11250 $out .= ajax_combobox($htmlname);
11251
11252 return $out;
11253 }
11254}
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:48
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:456
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:305
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:559
$object ref
Definition info.php:79
Class to manage bank accounts.
Class to manage categories.
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.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0)
selectModelMail
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.
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)
Return list of products for customer.
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...
textwithpicto($text, $htmltext, $direction=1, $type='help', $extracss='', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
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_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)
Return list of products for a customer.
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.
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.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array())
Show block with links to link to other objects.
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='')
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.
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1, $noprint=0)
print list of payment modes.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
form_confirm($page, $title, $question, $action, $formquestion=array(), $selectedchoice="", $useajax=0, $height=170, $width=500)
load_cache_conditions_paiements()
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier=0)
Return list of suppliers prices for a product.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='width75', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0)
Return combo list of activated countries, into language of user.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="")
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly=array(), $force_entity='0')
Return the HTML select list of users.
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
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.
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='')
Output the component to make advanced search criteries.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $elemtype='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
load_cache_types_paiements()
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Return the list of type of delay available.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage hooks.
Class 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.
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:85
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.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='')
Format phone numbers according to country.
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)
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_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
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_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
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.
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.
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 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:139
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:142
getMaxFileSizeArray()
Return the max allowed for file upload.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e rowid
Definition invoice.php:1929