dolibarr 22.0.5
html.form.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13 * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18 * Copyright (C) 2014-2026 Alexandre Spangaro <alexandre@inovea-conseil.com>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
27 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
28 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 3 of the License, or
32 * (at your option) any later version.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program. If not, see <https://www.gnu.org/licenses/>.
41 */
42
56class Form
57{
61 public $db;
62
66 public $error = '';
67
71 public $errors = array();
72
73 // Some properties used to return data by some methods
75 public $result;
76
78 public $num;
79
80 // Cache arrays
81 public $cache_types_paiements = array();
82 public $cache_conditions_paiements = array();
83 public $cache_transport_mode = array();
85 public $cache_availability = array();
86 public $cache_demand_reason = array();
87 public $cache_types_fees = array();
88 public $cache_vatrates = array();
89 public $cache_invoice_subtype = array();
91 public $cache_rule_for_lines_dates = array();
92
93
99 public function __construct($db)
100 {
101 $this->db = $db;
102 }
103
120 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
121 {
122 global $langs;
123
124 $ret = '';
125
126 // TODO change for compatibility
127 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
128 if ($perm) {
129 $tmp = explode(':', $typeofdata);
130 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
131 if ($fieldrequired) {
132 $ret .= '<span class="fieldrequired">';
133 }
134 if ($help) {
135 $ret .= $this->textwithpicto($langs->trans($text), $help);
136 } else {
137 $ret .= $langs->trans($text);
138 }
139 if ($fieldrequired) {
140 $ret .= '</span>';
141 }
142 $ret .= '</div>' . "\n";
143 } else {
144 if ($fieldrequired) {
145 $ret .= '<span class="fieldrequired">';
146 }
147 if ($help) {
148 $ret .= $this->textwithpicto($langs->trans($text), $help);
149 } else {
150 $ret .= $langs->trans($text);
151 }
152 if ($fieldrequired) {
153 $ret .= '</span>';
154 }
155 }
156 } else {
157 if (empty($notabletag) && $perm) {
158 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
159 }
160 if ($fieldrequired) {
161 $ret .= '<span class="fieldrequired">';
162 }
163 if ($help) {
164 $ret .= $this->textwithpicto($langs->trans($text), $help);
165 } else {
166 $ret .= $langs->trans($text);
167 }
168 if ($fieldrequired) {
169 $ret .= '</span>';
170 }
171 if (!empty($notabletag)) {
172 $ret .= ' ';
173 }
174 if (empty($notabletag) && $perm) {
175 $ret .= '</td>';
176 }
177 if (empty($notabletag) && $perm) {
178 $ret .= '<td class="right">';
179 }
180 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
181 $ret .= '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=edit' . $htmlname . '&token=' . newToken() . '&' . $paramid . '=' . $object->id . $moreparam . '">' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . '</a>';
182 }
183 if (!empty($notabletag) && $notabletag == 1) {
184 if ($text) {
185 $ret .= ' : ';
186 } else {
187 $ret .= ' ';
188 }
189 }
190 if (!empty($notabletag) && $notabletag == 3) {
191 $ret .= ' ';
192 }
193 if (empty($notabletag) && $perm) {
194 $ret .= '</td>';
195 }
196 if (empty($notabletag) && $perm) {
197 $ret .= '</tr></table>';
198 }
199 }
200
201 return $ret;
202 }
203
227 public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '')
228 {
229 global $conf, $langs;
230
231 $ret = '';
232
233 // Check parameters
234 if (empty($typeofdata)) {
235 return 'ErrorBadParameter typeofdata is empty';
236 }
237 // Clean parameter $typeofdata
238 if ($typeofdata == 'datetime') {
239 $typeofdata = 'dayhour';
240 }
241 $reg = array();
242 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
243 if ($reg[1] == 'varchar') {
244 $typeofdata = 'string';
245 } elseif ($reg[1] == 'int') {
246 $typeofdata = 'numeric';
247 } else {
248 return 'ErrorBadParameter ' . $typeofdata;
249 }
250 }
251
252 // When option to edit inline is activated
253 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
254 $ret .= $this->editInPlace($object, $value, $htmlname, ($perm ? 1 : 0), $typeofdata, $editvalue, $extObject, $custommsg);
255 } else {
256 if ($editaction == '') {
257 $editaction = GETPOST('action', 'aZ09');
258 }
259 $editmode = ($editaction == 'edit' . $htmlname);
260 if ($editmode) { // edit mode
261 $ret .= "<!-- formeditfieldval -->\n";
262 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
263 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
264 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
265 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
266 if (empty($notabletag)) {
267 $ret .= '<table class="nobordernopadding centpercent">';
268 }
269 if (empty($notabletag)) {
270 $ret .= '<tr><td>';
271 }
272 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
273 $tmp = explode(':', $typeofdata);
274 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
275 } elseif (preg_match('/^(integer)/', $typeofdata)) {
276 $tmp = explode(':', $typeofdata);
277 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
278 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
279 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
280 $tmp = explode(':', $typeofdata);
281 $valuetoshow = price2num($editvalue ? $editvalue : $value);
282 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
283 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
284 $tmp = explode(':', $typeofdata);
285 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
286 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
287 $tmp = explode(':', $typeofdata);
288 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
289 $morealt = '';
290 if (preg_match('/%/', $cols)) {
291 $morealt = ' style="width: ' . $cols . '"';
292 $cols = '';
293 }
294 $valuetoshow = ($editvalue ? $editvalue : $value);
295 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
296 // textarea convert automatically entities chars into simple chars.
297 // So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwyg is off.
298 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
299 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
300 $ret .= '</textarea><div class="clearboth"></div>';
301 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
302 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
303 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
304 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
305 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
306 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
307 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
308 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
309 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
310 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
311 } elseif (preg_match('/^select;/', $typeofdata)) {
312 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
313 $arraylist = array();
314 foreach ($arraydata as $val) {
315 $tmp = explode(':', $val);
316 $tmpkey = str_replace('|', ':', $tmp[0]);
317 $arraylist[$tmpkey] = $tmp[1];
318 }
319 $ret .= $this->selectarray($htmlname, $arraylist, $value);
320 } elseif (preg_match('/^link/', $typeofdata)) {
321 // TODO Not yet implemented. See code for extrafields
322 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
323 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
324 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
325 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? 100 : (int) $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? false : (bool) $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? 20 : (int) $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
326 $ret .= $doleditor->Create(1);
327 } elseif ($typeofdata == 'asis') {
328 $ret .= ($editvalue ? $editvalue : $value);
329 }
330 if (empty($notabletag)) {
331 $ret .= '</td>';
332 }
333
334 // Button save-cancel
335 if (empty($notabletag)) {
336 $ret .= '<td>';
337 }
338 //else $ret.='<div class="clearboth"></div>';
339 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Save") . '">';
340 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
341 $ret .= '<br>' . "\n";
342 }
343 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
344 if (empty($notabletag)) {
345 $ret .= '</td>';
346 }
347
348 if (empty($notabletag)) {
349 $ret .= '</tr></table>' . "\n";
350 }
351 $ret .= '</form>' . "\n";
352 } else { // view mode
353 if (preg_match('/^email/', $typeofdata)) {
354 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
355 } elseif (preg_match('/^phone/', $typeofdata)) {
356 $ret .= dol_print_phone($value, '_blank', 32, 1);
357 } elseif (preg_match('/^url/', $typeofdata)) {
358 $ret .= dol_print_url($value, '_blank', 32, 1);
359 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
360 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
361 } elseif (preg_match('/^checkbox/', $typeofdata)) {
362 $tmp = explode(':', $typeofdata);
363 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
364 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
366 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
368 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
369 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
370 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
371 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
372 } elseif (preg_match('/^select;/', $typeofdata)) {
373 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
374 $arraylist = array();
375 foreach ($arraydata as $val) {
376 $tmp = explode(':', $val);
377 $arraylist[$tmp[0]] = $tmp[1];
378 }
379 $ret .= $arraylist[$value];
380 if ($htmlname == 'fk_product_type') {
381 if ($value == 0) {
382 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
383 } else {
384 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
385 }
386 }
387 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
388 $tmpcontent = dol_htmlentitiesbr($value);
389 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
390 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
391 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
392 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
393 }
394 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
395 // clean data from some dangerous html
397 } else {
398 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
399 $ret .= dol_escape_htmltag($value);
400 } else {
401 $ret .= $value; // $value must be already html escaped.
402 }
403 }
404
405 // Custom format if parameter $formatfunc has been provided
406 if ($formatfunc && method_exists($object, $formatfunc)) {
407 $ret = $object->$formatfunc($ret);
408 }
409 }
410 }
411 return $ret;
412 }
413
425 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
426 {
427 global $conf, $langs, $extralanguages;
428
429 $result = '';
430
431 // List of extra languages
432 $arrayoflangcode = array();
433 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
434 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
435 }
436
437 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
438 if (!is_object($extralanguages)) {
439 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
440 $extralanguages = new ExtraLanguages($this->db);
441 }
442 $extralanguages->fetch_name_extralanguages('societe');
443
444 // ExtraLanguages::fetch_name_extralanguages() leaves $this->attributes empty
445 // when MAIN_USE_ALTERNATE_TRANSLATION_FOR is not configured, so PHP 8 raises
446 // 'Undefined array key' on the read below if we do not guard it (issue #34596).
447 if (empty($extralanguages->attributes[$object->element]) || !is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
448 return ''; // No extralang field to show
449 }
450
451 $result .= '<!-- Widget for translation -->' . "\n";
452 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
453 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', 0, 0, 0, '', 'fa-15 editfieldlang');
454 $result .= $s;
455 $result .= '</div>';
456
457 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
458
459 $resultforextrlang = '';
460 foreach ($arrayoflangcode as $langcode) {
461 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
462 if (empty($valuetoshow)) {
463 $object->fetchValuesForExtraLanguages();
464 //var_dump($object->array_languages);
465 $valuetoshow = $object->array_languages[$fieldname][$langcode];
466 }
467
468 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
469 $resultforextrlang .= $s;
470
471 // TODO Use the showInputField() method of ExtraLanguages object
472 if ($typeofdata == 'textarea') {
473 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
474 $resultforextrlang .= $valuetoshow;
475 $resultforextrlang .= '</textarea>';
476 } else {
477 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
478 }
479 }
480 $result .= $resultforextrlang;
481
482 $result .= '</div>';
483 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
484 }
485
486 return $result;
487 }
488
502 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
503 {
504 $out = '';
505
506 // Check parameters
507 if (preg_match('/^text/', $inputType)) {
508 $value = dol_nl2br($value);
509 } elseif (preg_match('/^numeric/', $inputType)) {
510 $value = price($value);
511 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
512 $value = dol_print_date($value, 'day');
513 }
514
515 if ($condition) {
516 $element = false;
517 $table_element = false;
518 $fk_element = false;
519 $loadmethod = false;
520 $savemethod = false;
521 $ext_element = false;
522 $button_only = false;
523 $inputOption = '';
524 $rows = '';
525 $cols = '';
526
527 if (is_object($object)) {
528 $element = $object->element;
529 $table_element = $object->table_element;
530 $fk_element = $object->id;
531 }
532
533 if (is_object($extObject)) {
534 $ext_element = $extObject->element;
535 }
536
537 if (preg_match('/^(string|email|numeric)/', $inputType)) {
538 $tmp = explode(':', $inputType);
539 $inputType = $tmp[0];
540 if (!empty($tmp[1])) {
541 $inputOption = $tmp[1];
542 }
543 if (!empty($tmp[2])) {
544 $savemethod = $tmp[2];
545 }
546 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
547 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
548 $tmp = explode(':', $inputType);
549 $inputType = $tmp[0];
550 if (!empty($tmp[1])) {
551 $inputOption = $tmp[1];
552 }
553 if (!empty($tmp[2])) {
554 $savemethod = $tmp[2];
555 }
556
557 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
558 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
559 $tmp = explode(':', $inputType);
560 $inputType = $tmp[0];
561 $loadmethod = $tmp[1];
562 if (!empty($tmp[2])) {
563 $savemethod = $tmp[2];
564 }
565 if (!empty($tmp[3])) {
566 $button_only = true;
567 }
568 } elseif (preg_match('/^textarea/', $inputType)) {
569 $tmp = explode(':', $inputType);
570 $inputType = $tmp[0];
571 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
572 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
573 } elseif (preg_match('/^ckeditor/', $inputType)) {
574 $tmp = explode(':', $inputType);
575 $inputType = $tmp[0];
576 $toolbar = $tmp[1];
577 if (!empty($tmp[2])) {
578 $width = $tmp[2];
579 }
580 if (!empty($tmp[3])) {
581 $height = $tmp[3];
582 }
583 if (!empty($tmp[4])) {
584 $savemethod = $tmp[4];
585 }
586
587 if (isModEnabled('fckeditor')) {
588 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
589 } else {
590 $inputType = 'textarea';
591 }
592 }
593
594 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
595 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
596 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
597 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
598 if (!empty($savemethod)) {
599 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
600 }
601 if (!empty($ext_element)) {
602 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
603 }
604 if (!empty($custommsg)) {
605 if (is_array($custommsg)) {
606 if (!empty($custommsg['success'])) {
607 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
608 }
609 if (!empty($custommsg['error'])) {
610 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
611 }
612 } else {
613 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
614 }
615 }
616 if ($inputType == 'textarea') {
617 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
618 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
619 }
620 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
621 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
622 } else {
623 $out = $value;
624 }
625
626 return $out;
627 }
628
647 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
648 {
649 if ($incbefore) {
650 $text = $incbefore . $text;
651 }
652 if (!$htmltext) {
653 return $text;
654 }
655 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
656
657 $tag = 'td';
658 if ($notabs == 2) {
659 $tag = 'div';
660 }
661 if ($notabs == 3) {
662 $tag = 'span';
663 }
664 // Sanitize tooltip
665 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
666
667 $extrastyle = '';
668 if ($direction < 0) {
669 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
670 $extrastyle = 'padding: 0px; padding-left: 2px;';
671 }
672 if ($direction > 0) {
673 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
674 $extrastyle = 'padding: 0px; padding-right: 2px;';
675 }
676
677 $classfortooltip = 'classfortooltip';
678
679 $s = '';
680 $textfordialog = '';
681
682 if ($tooltiptrigger == '') {
683 $htmltext = str_replace('"', '&quot;', $htmltext);
684 } else {
685 $classfortooltip = 'classfortooltiponclick';
686 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext"';
687 // Set default title of dialog
688 global $langs;
689 if ($langs instanceof Translate) {
690 $textfordialog .= ' title="'.$langs->trans("Note").'"';
691 }
692 $textfordialog .= '>' . $htmltext . '</div>';
693 }
694 if ($tooltipon == 2 || $tooltipon == 3) {
695 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
696 if ($tooltiptrigger == '') {
697 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
698 } else {
699 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
700 }
701 } else {
702 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
703 }
704 if ($tooltipon == 1 || $tooltipon == 3) {
705 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ($tag != 'td' ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
706 if ($tooltiptrigger == '') {
707 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
708 } else {
709 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
710 }
711 } else {
712 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
713 }
714 if (empty($notabs)) {
715 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
716 } elseif ($notabs == 2) {
717 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
718 }
719 // Define value if value is before
720 if ($direction < 0) {
721 $s .= '<' . $tag . $paramfortooltipimg;
722 if ($tag == 'td') {
723 $s .= ' class="valigntop" width="14"';
724 }
725 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
726 }
727 // Use another method to help avoid having a space in value in order to use this value with jquery
728 // Define label
729 if ((string) $text != '') {
730 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
731 }
732 // Define value if value is after
733 if ($direction > 0) {
734 $s .= '<' . $tag . $paramfortooltipimg;
735 if ($tag == 'td') {
736 $s .= ' class="valignmiddle" width="14"';
737 }
738 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
739 }
740 if (empty($notabs)) {
741 $s .= '</tr></table>';
742 } elseif ($notabs == 2) {
743 $s .= '</div>';
744 }
745
746 return $s;
747 }
748
763 public function textwithpicto($text, $htmltooltip, $direction = 1, $type = 'help', $extracss = 'valignmiddle', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
764 {
765 global $conf, $langs;
766
767 //For backwards compatibility
768 if ($type == '0') {
769 $type = 'info';
770 } elseif ($type == '1') {
771 $type = 'help';
772 }
773 // Clean parameters
774 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
775
776 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
777 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
778 }
779 $alt = '';
780 if ($tooltiptrigger) {
781 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
782 }
783
784 // If info or help with no javascript, show only text
785 if (empty($conf->use_javascript_ajax)) {
786 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
787 return $text;
788 } else {
789 $alt = $htmltooltip;
790 $htmltooltip = '';
791 }
792 }
793
794 // If info or help with smartphone, show only text (tooltip hover can't works)
795 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
796 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
797 return $text;
798 }
799 }
800 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
801 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
802 //{
803 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
804 //}
805
806 $img = '';
807 if ($type == 'info') {
808 $img = img_help(($tooltiptrigger != '' ? 2 : 0), $alt);
809 } elseif ($type == 'help') {
810 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
811 } elseif ($type == 'helpclickable') {
812 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
813 } elseif ($type == 'superadmin') {
814 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
815 $img = img_picto($alt, 'redstar');
816 } elseif ($type == 'admin') {
817 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
818 $img = img_picto($alt, 'star');
819 } elseif ($type == 'warning') {
820 $img = img_warning($alt);
821 } elseif ($type != 'none') {
822 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
823 $img = img_picto($alt, $type); // $type can be an image path
824 }
825
826 $tooltipon = ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2);
827
828 return $this->textwithtooltip($text, $htmltooltip, $tooltipon, $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
829 }
830
841 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
842 {
843 global $conf, $langs, $hookmanager;
844
845 $disabled = 0;
846 $ret = '<div class="centpercent center">';
847 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
848
849 // 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.
850 $parameters = array();
851 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
852 // check if there is a mass action
853
854 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
855 return;
856 }
857 if (empty($reshook)) {
858 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
859 if (is_array($arrayofaction)) {
860 foreach ($arrayofaction as $code => $label) {
861 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
862 }
863 }
864 }
865 $ret .= $hookmanager->resPrint;
866
867 $ret .= '</select>';
868
869 if (empty($conf->dol_optimize_smallscreen)) {
870 $ret .= ajax_combobox('.' . $name . 'select');
871 }
872
873 // 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
874 $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.
875 $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")) . '">';
876 $ret .= '</div>';
877
878 if (!empty($conf->use_javascript_ajax)) {
879 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
880 <script nonce="' . getNonce() . '">
881 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 */
882 atleastoneselected=0;
883 jQuery("."+cssclass).each(function( index ) {
884 /* console.log( index + ": " + $( this ).text() ); */
885 if ($(this).is(\':checked\')) atleastoneselected++;
886 });
887
888 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
889
890 if (atleastoneselected || ' . ((int) $alwaysvisible) . ') {
891 jQuery("."+name).show();
892 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
893 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
894 } else {
895 jQuery("."+name).hide();
896 jQuery("."+name+"other").hide();
897 }
898 }
899
900 jQuery(document).ready(function () {
901 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
902 jQuery(".' . $cssclass . '").click(function() {
903 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
904 });
905 jQuery(".' . $name . 'select").change(function() {
906 var massaction = $( this ).val();
907 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
908 if (massaction == "builddoc") {
909 urlform = urlform + "#show_files";
910 }
911 $( this ).closest("form").attr("action", urlform);
912 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
913 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
914 if ($(this).val() != \'0\') {
915 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
916 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
917 jQuery(".' . $name . '"+massaction).show();
918 } else {
919 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
920 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
921 }
922 });
923 });
924 </script>
925 ';
926 }
927
928 return $ret;
929 }
930
931 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
932
950 public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0, $forcecombo = 0)
951 {
952 // phpcs:enable
953 global $langs, $mysoc;
954
955 $langs->load("dict");
956
957 $out = '';
958 $countryArray = array();
959 $favorite = array();
960 $label = array();
961 $atleastonefavorite = 0;
962
963 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
964 $sql .= " FROM " . $this->db->prefix() . "c_country";
965 $sql .= " WHERE active > 0";
966 //$sql.= " ORDER BY code ASC";
967
968 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
969 $resql = $this->db->query($sql);
970 if ($resql) {
971 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
972 $num = $this->db->num_rows($resql);
973 $i = 0;
974 if ($num) {
975 while ($i < $num) {
976 $obj = $this->db->fetch_object($resql);
977
978 $countryArray[$i]['rowid'] = $obj->rowid;
979 $countryArray[$i]['code_iso'] = $obj->code_iso;
980 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
981 $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 : ''));
982 $countryArray[$i]['favorite'] = $obj->favorite;
983 $countryArray[$i]['eec'] = $obj->eec;
984 $favorite[$i] = $obj->favorite;
985 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
986 $i++;
987 }
988
989 if (empty($disablefavorites)) {
990 $array1_sort_order = SORT_DESC;
991 $array2_sort_order = SORT_ASC;
992 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
993 } else {
994 $countryArray = dol_sort_array($countryArray, 'label');
995 }
996
997 if ($showempty) {
998 if (is_numeric($showempty)) {
999 $out .= '<option value="">&nbsp;</option>' . "\n";
1000 } else {
1001 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
1002 }
1003 }
1004
1005 if ($addspecialentries) { // Add dedicated entries for groups of countries
1006 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
1007 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1008 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
1009 if ($mysoc->isInEEC()) {
1010 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1011 }
1012 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1013 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1014 }
1015
1016 foreach ($countryArray as $row) {
1017 //if (empty($showempty) && empty($row['rowid'])) continue;
1018 if (empty($row['rowid'])) {
1019 continue;
1020 }
1021 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1022 continue; // exclude some countries
1023 }
1024
1025 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1026 $atleastonefavorite++;
1027 }
1028 if (empty($row['favorite']) && $atleastonefavorite) {
1029 $atleastonefavorite = 0;
1030 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1031 }
1032
1033 $labeltoshow = '';
1034 if ($row['label']) {
1035 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1036 } else {
1037 $labeltoshow .= '&nbsp;';
1038 }
1039 if ($row['code_iso']) {
1040 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1041 if (empty($hideflags)) {
1042 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1043 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1044 }
1045 }
1046
1047 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1048 $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']) . '">';
1049 } else {
1050 $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']) . '">';
1051 }
1052 $out .= dol_string_nohtmltag($labeltoshow);
1053 $out .= '</option>' . "\n";
1054 }
1055 }
1056 $out .= '</select>';
1057 } else {
1058 dol_print_error($this->db);
1059 }
1060
1061 // Make select dynamic
1062 if (empty($forcecombo)) {
1063 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1064 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1065 }
1066
1067 return $out;
1068 }
1069
1070 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1071
1085 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1086 {
1087 // phpcs:enable
1088 global $conf, $langs;
1089
1090 $langs->load("dict");
1091
1092 $out = '';
1093 //$moreattrib = '';
1094 $incotermArray = array();
1095
1096 $sql = "SELECT rowid, code";
1097 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1098 $sql .= " WHERE active > 0";
1099 $sql .= " ORDER BY code ASC";
1100
1101 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1102 $resql = $this->db->query($sql);
1103 if ($resql) {
1104 if ($conf->use_javascript_ajax && !$forcecombo) {
1105 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1106 $out .= ajax_combobox($htmlname, $events);
1107 }
1108
1109 if (!empty($page)) {
1110 $out .= '<form method="post" action="' . $page . '">';
1111 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1112 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1113 }
1114
1115 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1116 $out .= '<option value="0">&nbsp;</option>';
1117 $num = $this->db->num_rows($resql);
1118 $i = 0;
1119 if ($num) {
1120 while ($i < $num) {
1121 $obj = $this->db->fetch_object($resql);
1122 $incotermArray[$i]['rowid'] = $obj->rowid;
1123 $incotermArray[$i]['code'] = $obj->code;
1124 $i++;
1125 }
1126
1127 foreach ($incotermArray as $row) {
1128 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1129 $out .= '<option value="' . $row['rowid'] . '" selected>';
1130 } else {
1131 $out .= '<option value="' . $row['rowid'] . '">';
1132 }
1133
1134 if ($row['code']) {
1135 $out .= $row['code'];
1136 }
1137
1138 $out .= '</option>';
1139 }
1140 }
1141 $out .= '</select>';
1142 $out .= ajax_combobox($htmlname);
1143
1144 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1145 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1146 //$moreattrib .= ' autocomplete="off"';
1147 }
1148 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone heightofcombo" type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1149
1150 if (!empty($page)) {
1151 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1152 }
1153 } else {
1154 dol_print_error($this->db);
1155 }
1156
1157 return $out;
1158 }
1159
1160 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1161
1175 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "", $useajaxcombo = 1)
1176 {
1177 // phpcs:enable
1178 global $langs;
1179
1180 // If product & services are enabled or both disabled.
1181 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1182 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1183 if (empty($hidetext)) {
1184 print $langs->trans("Type").'...';
1185 }
1186 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1187 if ($showempty) {
1188 print '<option value="-1" class="opacitymedium"'.($useajaxcombo ? '' : ' disabled="disabled"');
1189 if ($selected == -1) {
1190 print ' selected';
1191 }
1192 print '>';
1193 if (is_numeric($showempty)) {
1194 print '&nbsp;';
1195 } else {
1196 print $showempty;
1197 }
1198 print '</option>';
1199 }
1200
1201 print '<option value="0"';
1202 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1203 print ' selected';
1204 }
1205 print '>' . $langs->trans("Product");
1206
1207 print '<option value="1"';
1208 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1209 print ' selected';
1210 }
1211 print '>' . $langs->trans("Service");
1212
1213 print '</select>';
1214
1215 if ($useajaxcombo) {
1216 print ajax_combobox('select_' . $htmlname);
1217 }
1218 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1219 }
1220 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1221 print $langs->trans("Service");
1222 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1223 }
1224 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1225 print $langs->trans("Product");
1226 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1227 }
1228 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1229 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
1230 }
1231 }
1232
1233 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1234
1240 public function load_cache_types_fees()
1241 {
1242 // phpcs:enable
1243 global $langs;
1244
1245 $num = count($this->cache_types_fees);
1246 if ($num > 0) {
1247 return 0; // Cache already loaded
1248 }
1249
1250 dol_syslog(__METHOD__, LOG_DEBUG);
1251
1252 $langs->load("trips");
1253
1254 $sql = "SELECT c.code, c.label";
1255 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1256 $sql .= " WHERE active > 0";
1257
1258 $resql = $this->db->query($sql);
1259 if ($resql) {
1260 $num = $this->db->num_rows($resql);
1261 $i = 0;
1262
1263 while ($i < $num) {
1264 $obj = $this->db->fetch_object($resql);
1265
1266 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1267 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1268 $this->cache_types_fees[$obj->code] = $label;
1269 $i++;
1270 }
1271
1272 asort($this->cache_types_fees);
1273
1274 return $num;
1275 } else {
1276 dol_print_error($this->db);
1277 return -1;
1278 }
1279 }
1280
1281 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1282
1291 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1292 {
1293 // phpcs:enable
1294 global $user, $langs;
1295
1296 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1297
1298 $this->load_cache_types_fees();
1299
1300 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1301 if ($showempty) {
1302 print '<option value="-1"';
1303 if ($selected == -1) {
1304 print ' selected';
1305 }
1306 print '>&nbsp;</option>';
1307 }
1308
1309 foreach ($this->cache_types_fees as $key => $value) {
1310 print '<option value="' . $key . '"';
1311 if ($key == $selected) {
1312 print ' selected';
1313 }
1314 print '>';
1315 print $value;
1316 print '</option>';
1317 }
1318
1319 print '</select>';
1320 if ($user->admin) {
1321 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1322 }
1323 }
1324
1325
1326 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1327
1350 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)
1351 {
1352 // phpcs:enable
1353 global $conf, $langs;
1354
1355 $out = '';
1356
1357 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1358 if (is_null($ajaxoptions)) {
1359 $ajaxoptions = array();
1360 }
1361
1362 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1363
1364 // No immediate load of all database
1365 $placeholder = '';
1366 if ($selected && empty($selected_input_value)) {
1367 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1368 $societetmp = new Societe($this->db);
1369 $societetmp->fetch($selected);
1370 $selected_input_value = $societetmp->name;
1371 unset($societetmp);
1372 }
1373
1374 // mode 1
1375 $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)) : '');
1376
1377 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1378 if (empty($hidelabel)) {
1379 $out .= $langs->trans("RefOrLabel") . ' : ';
1380 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1381 $placeholder = $langs->trans($showempty);
1382 } elseif ($hidelabel > 1) {
1383 $placeholder = $langs->trans("RefOrLabel");
1384 if ($hidelabel == 2) {
1385 $out .= img_picto($langs->trans("Search"), 'search');
1386 }
1387 }
1388 $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' : '') . ' />';
1389 if ($hidelabel == 3) {
1390 $out .= img_picto($langs->trans("Search"), 'search');
1391 }
1392
1393 $out .= ajax_event($htmlname, $events);
1394
1395 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1396 } else {
1397 // Immediate load of all database
1398 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1399 }
1400
1401 return $out;
1402 }
1403
1404
1405 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1406
1432 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 = '')
1433 {
1434 // phpcs:enable
1435
1436 global $conf, $langs;
1437
1438 $out = '';
1439
1440 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1441 if ($nokeyifsocid && $socid > 0) {
1442 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1443 }
1444
1445 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1446 if (is_null($events)) {
1447 $events = array();
1448 }
1449
1450 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1451
1452 // No immediate load of all database
1453 $placeholder = '';
1454 if ($selected && empty($selected_input_value)) {
1455 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1456 $contacttmp = new Contact($this->db);
1457 $contacttmp->fetch($selected);
1458 $selected_input_value = $contacttmp->getFullName($langs);
1459 unset($contacttmp);
1460 }
1461 if (!is_numeric($showempty)) {
1462 $placeholder = $showempty;
1463 }
1464
1465 // mode 1
1466 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1467
1468 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1469
1470 $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' : '') . ' />';
1471
1472 $out .= ajax_event($htmlname, $events);
1473
1474 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1475 } else {
1476 // Immediate load of all database
1477 $multiple = false;
1478 $disableifempty = 0;
1479 $options_only = 0;
1480 $limitto = '';
1481
1482 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1483 }
1484
1485 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1486
1487 return $out;
1488 }
1489
1490
1491 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1492
1517 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)
1518 {
1519 // phpcs:enable
1520 global $user, $langs;
1521 global $hookmanager;
1522
1523 $langs->loadLangs(array("companies", "suppliers"));
1524
1525 $out = '';
1526 $num = 0;
1527 $outarray = array();
1528
1529 if ($selected === '') {
1530 $selected = array();
1531 } elseif (!is_array($selected)) {
1532 $selected = array($selected);
1533 }
1534
1535 // Clean $filter that may contains sql conditions so sql code
1536 if (function_exists('testSqlAndScriptInject')) {
1537 if (testSqlAndScriptInject($filter, 3) > 0) {
1538 $filter = '';
1539 return 'SQLInjectionTryDetected';
1540 }
1541 }
1542
1543 if ($filter != '') { // If a filter was provided
1544 if (preg_match('/[\‍(\‍)]/', $filter)) {
1545 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1546 $errormsg = '';
1547 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1548
1549 // Redo clean $filter that may contains sql conditions so sql code
1550 if (function_exists('testSqlAndScriptInject')) {
1551 if (testSqlAndScriptInject($filter, 3) > 0) {
1552 $filter = '';
1553 return 'SQLInjectionTryDetected';
1554 }
1555 }
1556 } else {
1557 // If not, we do nothing. We already know that there is no parenthesis
1558 // TODO Disallow this case in a future.
1559 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1560 }
1561 }
1562
1563 // We search companies
1564 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1565 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1566 $sql .= ", s.address, s.zip, s.town";
1567 $sql .= ", dictp.code as country_code";
1568 }
1569 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1570 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1571 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1572 }
1573 if (!$user->hasRight('societe', 'client', 'voir')) {
1574 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1575 }
1576 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1577 if (!empty($user->socid)) {
1578 $sql .= " AND s.rowid = " . ((int) $user->socid);
1579 }
1580 if ($filter) {
1581 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1582 // if not, by testSqlAndScriptInject() only.
1583 $sql .= " AND (" . $filter . ")";
1584 }
1585 if (!$user->hasRight('societe', 'client', 'voir')) {
1586 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1587 }
1588 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1589 $sql .= " AND s.status <> 0";
1590 }
1591 if (!empty($excludeids)) {
1592 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1593 }
1594 // Add where from hooks
1595 $parameters = array();
1596 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1597 $sql .= $hookmanager->resPrint;
1598 // Add criteria
1599 if ($filterkey && $filterkey != '') {
1600 $sql .= " AND (";
1601 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1602 // For natural search
1603 $search_crit = explode(' ', $filterkey);
1604 $i = 0;
1605 if (count($search_crit) > 1) {
1606 $sql .= "(";
1607 }
1608 foreach ($search_crit as $crit) {
1609 if ($i > 0) {
1610 $sql .= " AND ";
1611 }
1612 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1613 $i++;
1614 }
1615 if (count($search_crit) > 1) {
1616 $sql .= ")";
1617 }
1618 if (isModEnabled('barcode')) {
1619 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1620 }
1621 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1622 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1623 $sql .= ")";
1624 }
1625 $sql .= $this->db->order("nom", "ASC");
1626 $sql .= $this->db->plimit($limit, 0);
1627
1628 // Build output string
1629 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1630 $resql = $this->db->query($sql);
1631 if ($resql) {
1632 // Construct $out and $outarray
1633 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1634
1635 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1636 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1637 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1638 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1639 if ($showempty && !is_numeric($showempty)) {
1640 $textifempty = $langs->trans($showempty);
1641 } else {
1642 $textifempty .= $langs->trans("All");
1643 }
1644 }
1645 if ($showempty) {
1646 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1647 }
1648
1649 $companytemp = new Societe($this->db);
1650
1651 $num = $this->db->num_rows($resql);
1652 $i = 0;
1653 if ($num) {
1654 while ($i < $num) {
1655 $obj = $this->db->fetch_object($resql);
1656 $label = '';
1657 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1658 if (($obj->client) && (!empty($obj->code_client))) {
1659 $label = $obj->code_client . ' - ';
1660 }
1661 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1662 $label .= $obj->code_fournisseur . ' - ';
1663 }
1664 $label .= ' ' . $obj->name;
1665 } else {
1666 $label = $obj->name;
1667 }
1668
1669 if (!empty($obj->name_alias)) {
1670 $label .= ' (' . $obj->name_alias . ')';
1671 }
1672
1673 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1674 $label .= ' - '.$obj->tva_intra;
1675 }
1676
1677 $labelhtml = $label;
1678
1679 if ($showtype) {
1680 $companytemp->id = $obj->rowid;
1681 $companytemp->client = $obj->client;
1682 $companytemp->fournisseur = $obj->fournisseur;
1683 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1684 if ($tmptype) {
1685 $labelhtml .= ' ' . $tmptype;
1686 }
1687
1688 if ($obj->client || $obj->fournisseur) {
1689 $label .= ' (';
1690 }
1691 if ($obj->client == 1 || $obj->client == 3) {
1692 $label .= $langs->trans("Customer");
1693 }
1694 if ($obj->client == 2 || $obj->client == 3) {
1695 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1696 }
1697 if ($obj->fournisseur) {
1698 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1699 }
1700 if ($obj->client || $obj->fournisseur) {
1701 $label .= ')';
1702 }
1703 }
1704
1705 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1706 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1707 if (!empty($obj->country_code)) {
1708 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1709 }
1710 $label .= $s;
1711 $labelhtml .= $s;
1712 }
1713
1714 if (empty($outputmode)) {
1715 if (in_array($obj->rowid, $selected)) {
1716 $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>';
1717 } else {
1718 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1719 }
1720 } else {
1721 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1722 }
1723
1724 $i++;
1725 if (($i % 10) == 0) {
1726 $out .= "\n";
1727 }
1728 }
1729 }
1730 $out .= '</select>' . "\n";
1731 if (!$forcecombo) {
1732 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1733 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1734 }
1735 } else {
1736 dol_print_error($this->db);
1737 }
1738
1739 $this->result = array('nbofthirdparties' => $num);
1740
1741 if ($outputmode) {
1742 return $outarray;
1743 }
1744 return $out;
1745 }
1746
1747
1773 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 = '')
1774 {
1775 global $conf, $user, $langs, $hookmanager, $action;
1776
1777 $langs->load('companies');
1778
1779 if (empty($htmlid)) {
1780 $htmlid = $htmlname;
1781 }
1782 $num = 0;
1783 $out = '';
1784 $outarray = array();
1785
1786 if ($selected === '') {
1787 $selected = array();
1788 } elseif (!is_array($selected)) {
1789 $selected = array((int) $selected);
1790 }
1791
1792 // Clean $filter that may contains sql conditions so sql code
1793 if (function_exists('testSqlAndScriptInject')) {
1794 if (testSqlAndScriptInject($filter, 3) > 0) {
1795 $filter = '';
1796 return 'SQLInjectionTryDetected';
1797 }
1798 }
1799
1800 if ($filter != '') { // If a filter was provided
1801 if (preg_match('/[\‍(\‍)]/', $filter)) {
1802 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1803 $errormsg = '';
1804 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1805
1806 // Redo clean $filter that may contains sql conditions so sql code
1807 if (function_exists('testSqlAndScriptInject')) {
1808 if (testSqlAndScriptInject($filter, 3) > 0) {
1809 $filter = '';
1810 return 'SQLInjectionTryDetected';
1811 }
1812 }
1813 } else {
1814 // If not, we do nothing. We already know that there is no parenthesis
1815 // TODO Disallow this case in a future by returning an error here.
1816 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1817 }
1818 }
1819
1820 if (!is_object($hookmanager)) {
1821 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1822 $hookmanager = new HookManager($this->db);
1823 }
1824
1825 // We search third parties
1826 $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";
1827 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1828 $sql .= ", s.nom as company, s.town AS company_town";
1829 }
1830 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1831 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1832 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON s.rowid = sp.fk_soc";
1833 }
1834 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1835 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1836 if ($socid > 0 || $socid == -1) {
1837 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1838 }
1839 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1840 $sql .= " AND sp.statut <> 0";
1841 }
1842 // filter user access
1843 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
1844 $sql .= " AND EXISTS (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = sp.fk_soc AND sc.fk_user = ".(int) $user->id .")";
1845 }
1846 if ($user->socid > 0) {
1847 $sql .= " AND sp.fk_soc = ".((int) $user->socid);
1848 }
1849 if ($filter) {
1850 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1851 // if not, by testSqlAndScriptInject() only.
1852 $sql .= " AND (" . $filter . ")";
1853 }
1854 // Add where from hooks
1855 $parameters = array();
1856 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1857 $sql .= $hookmanager->resPrint;
1858 $sql .= " ORDER BY sp.lastname ASC";
1859
1860 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1861 $resql = $this->db->query($sql);
1862 if ($resql) {
1863 $num = $this->db->num_rows($resql);
1864
1865 if ($htmlname != 'none' && !$options_only) {
1866 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1867 }
1868
1869 if ($showempty && !is_numeric($showempty)) {
1870 $textforempty = $showempty;
1871 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1872 } else {
1873 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1874 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1875 }
1876 if ($showempty == 2) {
1877 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1878 }
1879 }
1880
1881 $i = 0;
1882 if ($num) {
1883 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1884 $contactstatic = new Contact($this->db);
1885
1886 while ($i < $num) {
1887 $obj = $this->db->fetch_object($resql);
1888
1889 // Set email (or phones) and town extended infos
1890 $extendedInfos = '';
1891 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1892 $extendedInfos = array();
1893 $email = trim($obj->email);
1894 if (!empty($email)) {
1895 $extendedInfos[] = $email;
1896 } else {
1897 $phone = trim($obj->phone);
1898 $phone_perso = trim($obj->phone_perso);
1899 $phone_mobile = trim($obj->phone_mobile);
1900 if (!empty($phone)) {
1901 $extendedInfos[] = $phone;
1902 }
1903 if (!empty($phone_perso)) {
1904 $extendedInfos[] = $phone_perso;
1905 }
1906 if (!empty($phone_mobile)) {
1907 $extendedInfos[] = $phone_mobile;
1908 }
1909 }
1910 $contact_town = trim($obj->contact_town);
1911 $company_town = trim($obj->company_town);
1912 if (!empty($contact_town)) {
1913 $extendedInfos[] = $contact_town;
1914 } elseif (!empty($company_town)) {
1915 $extendedInfos[] = $company_town;
1916 }
1917 $extendedInfos = implode(' - ', $extendedInfos);
1918 if (!empty($extendedInfos)) {
1919 $extendedInfos = ' - ' . $extendedInfos;
1920 }
1921 }
1922
1923 $contactstatic->id = $obj->rowid;
1924 $contactstatic->lastname = $obj->lastname;
1925 $contactstatic->firstname = $obj->firstname;
1926 if ($obj->statut == 1) {
1927 $tmplabel = '';
1928 if ($htmlname != 'none') {
1929 $disabled = 0;
1930 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1931 $disabled = 1;
1932 }
1933 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1934 $disabled = 1;
1935 }
1936 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1937 $out .= '<option value="' . $obj->rowid . '"';
1938 if ($disabled) {
1939 $out .= ' disabled';
1940 }
1941 $out .= ' selected>';
1942
1943 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1944 if ($showfunction && $obj->poste) {
1945 $tmplabel .= ' (' . $obj->poste . ')';
1946 }
1947 if (($showsoc > 0) && $obj->company) {
1948 $tmplabel .= ' - (' . $obj->company . ')';
1949 }
1950
1951 $out .= $tmplabel;
1952 $out .= '</option>';
1953 } else {
1954 $out .= '<option value="' . $obj->rowid . '"';
1955 if ($disabled) {
1956 $out .= ' disabled';
1957 }
1958 $out .= '>';
1959
1960 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1961 if ($showfunction && $obj->poste) {
1962 $tmplabel .= ' (' . $obj->poste . ')';
1963 }
1964 if (($showsoc > 0) && $obj->company) {
1965 $tmplabel .= ' - (' . $obj->company . ')';
1966 }
1967
1968 $out .= $tmplabel;
1969 $out .= '</option>';
1970 }
1971 } else {
1972 if (in_array($obj->rowid, $selected)) {
1973 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1974 if ($showfunction && $obj->poste) {
1975 $tmplabel .= ' (' . $obj->poste . ')';
1976 }
1977 if (($showsoc > 0) && $obj->company) {
1978 $tmplabel .= ' - (' . $obj->company . ')';
1979 }
1980
1981 $out .= $tmplabel;
1982 }
1983 }
1984
1985 if ($tmplabel != '') {
1986 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1987 }
1988 }
1989 $i++;
1990 }
1991 } else {
1992 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1993 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1994 $out .= $labeltoshow;
1995 $out .= '</option>';
1996 }
1997
1998 $parameters = array(
1999 'socid' => $socid,
2000 'htmlname' => $htmlname,
2001 'resql' => $resql,
2002 'out' => &$out,
2003 'showfunction' => $showfunction,
2004 'showsoc' => $showsoc,
2005 );
2006
2007 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2008
2009 if ($htmlname != 'none' && !$options_only) {
2010 $out .= '</select>';
2011 }
2012
2013 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
2014 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2015 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
2016 }
2017
2018 $this->num = $num;
2019
2020 if ($options_only === 2) {
2021 // Return array of options
2022 return $outarray;
2023 } else {
2024 return $out;
2025 }
2026 } else {
2027 dol_print_error($this->db);
2028 return -1;
2029 }
2030 }
2031
2032
2033 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2034
2045 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2046 {
2047 // phpcs:enable
2048 global $langs, $conf;
2049
2050 // On recherche les remises
2051 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2052 $sql .= " re.description, re.fk_facture_source";
2053 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2054 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2055 $sql .= " AND re.entity = " . $conf->entity;
2056 if ($filter) {
2057 $sql .= " AND " . $filter;
2058 }
2059 $sql .= " ORDER BY re.description ASC";
2060
2061 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2062 $resql = $this->db->query($sql);
2063 if ($resql) {
2064 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2065 $num = $this->db->num_rows($resql);
2066
2067 $qualifiedlines = $num;
2068
2069 $i = 0;
2070 if ($num) {
2071 print '<option value="0">&nbsp;</option>';
2072 while ($i < $num) {
2073 $obj = $this->db->fetch_object($resql);
2074 $desc = dol_trunc($obj->description, 40);
2075 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2076 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2077 }
2078 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2079 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2080 }
2081 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2082 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2083 }
2084 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2085 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2086 }
2087
2088 $selectstring = '';
2089 if ($selected > 0 && $selected == $obj->rowid) {
2090 $selectstring = ' selected';
2091 }
2092
2093 $disabled = '';
2094 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2095 $qualifiedlines--;
2096 $disabled = ' disabled';
2097 }
2098
2099 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2100 $tmpfac = new Facture($this->db);
2101 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2102 $desc = $desc . ' - ' . $tmpfac->ref;
2103 }
2104 }
2105
2106 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2107 $i++;
2108 }
2109 }
2110 print '</select>';
2111 print ajax_combobox('select_' . $htmlname);
2112
2113 return $qualifiedlines;
2114 } else {
2115 dol_print_error($this->db);
2116 return -1;
2117 }
2118 }
2119
2120
2121 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2122
2138 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2139 {
2140 // phpcs:enable
2141 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2142 }
2143
2144 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2145
2170 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '', $maxlength = 0, $showstatus = 0, $morefilter = '', $showalso = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2171 {
2172 // phpcs:enable
2173 global $conf, $user, $langs, $hookmanager;
2174 global $action;
2175
2176 // If no preselected user defined, we take current user
2177 if ((is_numeric($selected) && ($selected < -3 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2178 $selected = $user->id;
2179 }
2180
2181 if ($selected === '') {
2182 $selected = array();
2183 } elseif (!is_array($selected)) {
2184 $selected = array($selected);
2185 }
2186
2187 // Exclude some users in $excludeUsers string
2188 $excludeUsers = null;
2189 if (is_array($exclude)) {
2190 $excludeUsers = implode(",", $exclude);
2191 }
2192
2193 // Include some users in $includeUsers string
2194 $includeUsers = null;
2195 $includeUsersArray = array();
2196 if (is_array($include)) {
2197 $includeUsersArray = $include;
2198 } elseif ($include == 'hierarchy') {
2199 // Build list includeUsersArray to have only hierarchy
2200 $includeUsersArray = $user->getAllChildIds(0);
2201 } elseif ($include == 'hierarchyme') {
2202 // Build list includeUsersArray to have only hierarchy and current user
2203 $includeUsersArray = $user->getAllChildIds(1);
2204 }
2205 // Get list of allowed users
2206 /* We do not limit list of users. Because we should limit this only for combo list into HR features where we may be allowed to
2207 * see all other users and element in other. For example in agenda, we can have permission to read all event of otherusers.
2208 * So we disable this.
2209 if (!$user->hasRight('user', 'user', 'lire')) {
2210 if (empty($includeUsersArray)) {
2211 $includeUsers = implode(",", $user->getAllChildIds(1));
2212 } else {
2213 $includeUsers = implode(",", array_intersect($includeUsersArray, $user->getAllChildIds(1)));
2214 }
2215 } else {
2216 $includeUsers = implode(",", $includeUsersArray);
2217 } */
2218 $includeUsers = implode(",", $includeUsersArray);
2219
2220 $num = 0;
2221
2222 $out = '';
2223 $outarray = array();
2224 $outarray2 = array();
2225
2226 // Do we want to show the label of entity into the combo list ?
2227 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity) && !preg_match('/^search_/', $htmlname);
2228 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2229
2230 // Forge request to select users
2231 $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";
2232 if ($showlabelofentity) {
2233 $sql .= ", e.label";
2234 }
2235 $sql .= " FROM " . $this->db->prefix() . "user as u";
2236 if ($showlabelofentity) {
2237 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2238 }
2239 // Condition here should be the same than into societe->getSalesRepresentatives().
2240 if ($userissuperadminentityone && $force_entity !== 'default') {
2241 if (!empty($force_entity)) {
2242 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2243 } else {
2244 $sql .= " WHERE u.entity IS NOT NULL";
2245 }
2246 } else {
2247 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2248 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2249 } else {
2250 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2251 }
2252 }
2253
2254 if (!empty($user->socid)) {
2255 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2256 }
2257 if (is_array($exclude) && $excludeUsers) {
2258 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2259 }
2260 if ($includeUsers) {
2261 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2262 }
2263 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2264 $sql .= " AND u.statut <> 0";
2265 }
2266 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2267 $sql .= " AND u.employee <> 0";
2268 }
2269 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2270 $sql .= " AND u.fk_soc IS NULL";
2271 }
2272 if (!empty($morefilter)) {
2273 $errormessage = '';
2274 $sql .= forgeSQLFromUniversalSearchCriteria($morefilter, $errormessage);
2275 if ($errormessage) {
2276 $this->errors[] = $errormessage;
2277 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2278 if ($outputmode == 0) {
2279 return 'Error bad param $morefilter';
2280 } else {
2281 return array();
2282 }
2283 }
2284 }
2285
2286 //Add hook to filter on user (for example on usergroup define in custom modules)
2287 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2288 if (!empty($reshook)) {
2289 $sql .= $hookmanager->resPrint;
2290 }
2291
2292 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2293 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2294 } else {
2295 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2296 }
2297
2298 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2299
2300 $resql = $this->db->query($sql);
2301 if ($resql) {
2302 $num = $this->db->num_rows($resql);
2303 $i = 0;
2304 if ($num) {
2305 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2306 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2307 if ($show_empty && !$multiple) {
2308 $textforempty = ' ';
2309 if (!empty($conf->use_javascript_ajax)) {
2310 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2311 }
2312 if (!is_numeric($show_empty)) {
2313 $textforempty = $show_empty;
2314 }
2315 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2316
2317 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2318 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2319 'id' => ($show_empty < 0 ? $show_empty : -1),
2320 'label' => $textforempty,
2321 'labelhtml' => $textforempty,
2322 'color' => '',
2323 'picto' => ''
2324 );
2325 }
2326 if ($showalso == 2 || $showalso == 3) {
2327 $out .= '<option value="-3"' . ((in_array(-3, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("MyTeam") . ' --</option>' . "\n";
2328
2329 $hasAtLeastOneSubordinate = (count($user->getAllChildIds(1)) > 1);
2330 if ($hasAtLeastOneSubordinate) {
2331 //$sql = "SELECT rowid FROM".MAIN_DB_PREFIX."user "
2332 $outarray[-3] = '-- ' . $langs->trans("MyTeam") . ' --';
2333 $outarray2[-3] = array(
2334 'id' => -3,
2335 'label' => '-- ' . $langs->trans("MyTeam") . ' --',
2336 'labelhtml' => '-- ' . $langs->trans("MyTeam") . ' --',
2337 'color' => '',
2338 'picto' => ''
2339 );
2340 }
2341 }
2342 if ($showalso == 1 || $showalso == 3) {
2343 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2344
2345 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2346 $outarray2[-2] = array(
2347 'id' => -2,
2348 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2349 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2350 'color' => '',
2351 'picto' => ''
2352 );
2353 }
2354
2355 $userstatic = new User($this->db);
2356
2357 while ($i < $num) {
2358 $obj = $this->db->fetch_object($resql);
2359
2360 $userstatic->id = $obj->rowid;
2361 $userstatic->lastname = $obj->lastname;
2362 $userstatic->firstname = $obj->firstname;
2363 $userstatic->photo = $obj->photo;
2364 $userstatic->status = $obj->status;
2365 $userstatic->entity = $obj->entity;
2366 $userstatic->admin = $obj->admin;
2367 $userstatic->gender = $obj->gender;
2368
2369 $disableline = '';
2370 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2371 $disableline = ($enableonlytext ? $enableonlytext : '1');
2372 }
2373
2374 $labeltoshow = '';
2375 $labeltoshowhtml = '';
2376
2377 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2378 $fullNameMode = 0;
2379 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2380 $fullNameMode = 1; //Firstname+lastname
2381 }
2382 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2383 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2384 if (empty($obj->firstname) && empty($obj->lastname)) {
2385 $labeltoshow .= $obj->login;
2386 $labeltoshowhtml .= $obj->login;
2387 }
2388
2389 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2390 $moreinfo = '';
2391 $moreinfohtml = '';
2392 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2393 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2394 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2395 $moreinfo .= $obj->login;
2396 $moreinfohtml .= $obj->login;
2397 }
2398 if ($showstatus >= 0) {
2399 if ($obj->status == 1 && $showstatus == 1) {
2400 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2401 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2402 }
2403 if ($obj->status == 0 && $showstatus == 1) {
2404 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2405 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2406 }
2407 }
2408 if ($showlabelofentity) {
2409 if (empty($obj->entity)) {
2410 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2411 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2412 } else {
2413 if ($obj->entity != $conf->entity) {
2414 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2415 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2416 }
2417 }
2418 }
2419 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2420 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2421 if (!empty($disableline) && $disableline != '1') {
2422 // Add text from $enableonlytext parameter
2423 $moreinfo .= ' - ' . $disableline;
2424 $moreinfohtml .= ' - ' . $disableline;
2425 }
2426 $labeltoshow .= $moreinfo;
2427 $labeltoshowhtml .= $moreinfohtml;
2428
2429 $out .= '<option value="' . $obj->rowid . '"';
2430 if (!empty($disableline)) {
2431 $out .= ' disabled';
2432 }
2433 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2434 $out .= ' selected';
2435 }
2436 $out .= ' data-html="';
2437
2438 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2439 if ($showstatus >= 0 && $obj->status == 0) {
2440 $outhtml .= '<strike class="opacitymediumxxx">';
2441 }
2442 $outhtml .= $labeltoshowhtml;
2443 if ($showstatus >= 0 && $obj->status == 0) {
2444 $outhtml .= '</strike>';
2445 }
2446 $labeltoshowhtml = $outhtml;
2447
2448 $out .= dol_escape_htmltag($outhtml);
2449 $out .= '">';
2450 $out .= $labeltoshow;
2451 $out .= '</option>';
2452
2453 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2454 $outarray2[$userstatic->id] = array(
2455 'id' => $userstatic->id,
2456 'label' => $labeltoshow,
2457 'labelhtml' => $labeltoshowhtml,
2458 'color' => '',
2459 'picto' => ''
2460 );
2461
2462 $i++;
2463 }
2464 } else {
2465 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2466 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2467 }
2468 $out .= '</select>';
2469
2470 if ($num && !$forcecombo) {
2471 // Enhance with select2
2472 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2473 $out .= ajax_combobox($htmlname);
2474 }
2475 } else {
2476 dol_print_error($this->db);
2477 }
2478
2479 $this->num = $num;
2480
2481 if ($outputmode == 2) {
2482 return $outarray2;
2483 } elseif ($outputmode) {
2484 return $outarray;
2485 }
2486
2487 return $out;
2488 }
2489
2490
2491 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2515 public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array(), $canremoveowner = 1)
2516 {
2517 // phpcs:enable
2518 global $langs, $user;
2519
2520 $userstatic = new User($this->db);
2521 $out = '';
2522
2523 if (!empty($_SESSION['assignedtouser'])) {
2524 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2525 if (!is_array($assignedtouser)) {
2526 $assignedtouser = array();
2527 }
2528 } else {
2529 $assignedtouser = array();
2530 }
2531 $nbassignetouser = count($assignedtouser);
2532
2533 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2534 if ($nbassignetouser) {
2535 $out .= '<ul class="attendees">';
2536 }
2537 $i = 0;
2538 $ownerid = 0;
2539 foreach ($assignedtouser as $key => $value) {
2540 if ($value['id'] == $ownerid) {
2541 continue;
2542 }
2543
2544 $out .= '<li>';
2545 $userstatic->fetch($value['id']);
2546 $out .= $userstatic->getNomUrl(-1);
2547 if ($i == 0) {
2548 $ownerid = $value['id'];
2549 $out .= ' (' . $langs->trans("Owner") . ')';
2550 }
2551 // Add picto to delete owner/assignee
2552 if ($nbassignetouser > 1 && $action != 'view') {
2553 $canremoveassignee = 1;
2554 if ($i == 0) {
2555 // We are on the owner of the event
2556 if (!$canremoveowner) {
2557 $canremoveassignee = 0;
2558 }
2559 if (!$user->hasRight('agenda', 'allactions', 'create')) {
2560 $canremoveassignee = 0; // Can't remove the owner
2561 }
2562 } else {
2563 // We are not on the owner of the event but on a secondary assignee
2564 }
2565 if ($canremoveassignee) {
2566 // If user has all permission, he should be ableto remove a assignee.
2567 // If user has not all permission, he can onlyremove assignee of other (he can't remove itself)
2568 $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 . '">';
2569 }
2570 }
2571 // Show my availability
2572 if ($showproperties) {
2573 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2574 $out .= '<div class="myavailability inline-block">';
2575 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;';
2576 //$out .= '<span class="opacitymedium">' . $langs->trans("Availability") . ':</span>';
2577 $out .= '</span>';
2578 $out .= ' <input title="'.$langs->trans("Availability").'" id="transparency" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofuserid[$ownerid]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2579 $out .= '</div>';
2580 }
2581 }
2582 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2583 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2584
2585 $out .= '</li>';
2586 $i++;
2587 }
2588 if ($nbassignetouser) {
2589 $out .= '</ul>';
2590 }
2591
2592 // Method with no ajax
2593 if ($action != 'view') {
2594 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2595 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2596 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2597 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2598 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2599 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2600 $out .= '});';
2601 $out .= '})</script>';
2602 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2603 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2604 $out .= '<br>';
2605 }
2606
2607 return $out;
2608 }
2609
2610 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2630 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())
2631 {
2632 // phpcs:enable
2633 global $langs;
2634
2635 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2636 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2637 $formresources = new FormResource($this->db);
2638 $resourcestatic = new Dolresource($this->db);
2639
2640 $out = '';
2641 if (!empty($_SESSION['assignedtoresource'])) {
2642 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2643 if (!is_array($assignedtoresource)) {
2644 $assignedtoresource = array();
2645 }
2646 } else {
2647 $assignedtoresource = array();
2648 }
2649 $nbassignetoresource = count($assignedtoresource);
2650
2651 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2652 if ($nbassignetoresource) {
2653 $out .= '<ul class="attendees">';
2654 }
2655 $i = 0;
2656
2657 foreach ($assignedtoresource as $key => $value) {
2658 $out .= '<li>';
2659 $resourcestatic->fetch($value['id']);
2660 $out .= $resourcestatic->getNomUrl(-1);
2661 if ($nbassignetoresource >= 1 && $action != 'view') {
2662 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassignedresource reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2663 }
2664 // Show my availability
2665 if ($showproperties) {
2666 if (is_array($listofresourceid) && count($listofresourceid)) {
2667 $out .= '<div class="myavailability inline-block">';
2668 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;';
2669 //$out .= '<span class="opacitymedium">' . $langs->trans("Availability") . ': </span>';
2670 $out .= '</span>';
2671 $out .= ' <input title="'.$langs->trans("Availability").'" id="transparencyresource'.$value['id'].'" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparencyresource'.$value['id'].'">' . $langs->trans("Busy") . '</label>';
2672 $out .= '</div>';
2673 }
2674 }
2675 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2676 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2677
2678 $out .= '</li>';
2679 $i++;
2680 }
2681 if ($nbassignetoresource) {
2682 $out .= '</ul>';
2683 }
2684
2685 // Method with no ajax
2686 if ($action != 'view') {
2687 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2688 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2689 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2690 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2691 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2692 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2693 $out .= '});';
2694 $out .= '})</script>';
2695
2696 $events = array();
2697 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2698 $out .= $formresources->select_resource_list(0, $htmlname, '', 1, 1, 0, $events, '', 2, 0);
2699 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2700 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2701 $out .= '<br>';
2702 }
2703
2704 return $out;
2705 }
2706
2707 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2708
2738 public function select_produits($selected = 0, $htmlname = 'productid', $filtertype = '', $limit = 0, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = null, $nooutput = 0, $status_purchase = -1, $warehouseId = 0)
2739 {
2740 // phpcs:enable
2741 global $langs, $conf;
2742
2743 $out = '';
2744
2745 // check parameters
2746 $price_level = (!empty($price_level) ? $price_level : 0);
2747 if (is_null($ajaxoptions)) {
2748 $ajaxoptions = array();
2749 }
2750
2751 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2752 if (isModEnabled("product") && !isModEnabled('service')) {
2753 $filtertype = '0';
2754 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2755 $filtertype = '1';
2756 }
2757 }
2758
2759 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2760 $placeholder = (is_numeric($showempty) ? '' : 'placeholder="'.dolPrintHTML($showempty).'"');
2761
2762 if ($selected && empty($selected_input_value)) {
2763 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2764 $producttmpselect = new Product($this->db);
2765 $producttmpselect->fetch($selected);
2766 $selected_input_value = $producttmpselect->ref;
2767 unset($producttmpselect);
2768 }
2769 // handle case where product or service module is disabled + no filter specified
2770 if ($filtertype == '') {
2771 if (!isModEnabled('product')) { // when product module is disabled, show services only
2772 $filtertype = 1;
2773 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2774 $filtertype = 0;
2775 }
2776 }
2777 // mode=1 means customers products
2778 $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;
2779 if ((int) $warehouseId > 0) {
2780 $urloption .= '&warehouseid=' . (int) $warehouseId;
2781 }
2782
2783 if (isModEnabled('variants') && is_array($selected_combinations)) {
2784 // Code to automatically insert with javascript the select of attributes under the select of product
2785 // when a parent of variant has been selected.
2786 // Note: Samecode than for product input using select
2787 $htmltag = 'input';
2788 $out .= '
2789 <!-- script to auto show attributes select tags if a variant was selected -->
2790 <script nonce="' . getNonce() . '">
2791 // auto show attributes fields
2792 selected = ' . json_encode($selected_combinations) . ';
2793 combvalues = {};
2794
2795 jQuery(document).ready(function () {
2796
2797 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2798 if (jQuery(this).val() == \'free\') {
2799 jQuery(\'div#attributes_box\').empty();
2800 }
2801 });
2802
2803 jQuery("'.$htmltag.'#' . $htmlname . '").change(function () {
2804
2805 if (!jQuery(this).val()) {
2806 jQuery(\'div#attributes_box\').empty();
2807 return;
2808 }
2809
2810 console.log("A change has started. We get variants fields to inject html select");
2811
2812 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2813 id: jQuery(this).val()
2814 }, function (data) {
2815 jQuery(\'div#attributes_box\').empty();
2816
2817 jQuery.each(data, function (key, val) {
2818
2819 combvalues[val.id] = val.values;
2820
2821 var span = jQuery(document.createElement(\'div\')).css({
2822 \'display\': \'table-row\'
2823 });
2824
2825 span.append(
2826 jQuery(document.createElement(\'div\')).text(val.label).css({
2827 \'font-weight\': \'bold\',
2828 \'display\': \'table-cell\'
2829 })
2830 );
2831
2832 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2833 \'margin-left\': \'15px\',
2834 \'white-space\': \'pre\'
2835 }).append(
2836 jQuery(document.createElement(\'option\')).val(\'\')
2837 );
2838
2839 jQuery.each(combvalues[val.id], function (key, val) {
2840 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2841
2842 if (selected[val.fk_product_attribute] == val.id) {
2843 tag.attr(\'selected\', \'selected\');
2844 }
2845
2846 html.append(tag);
2847 });
2848
2849 span.append(html);
2850 jQuery(\'div#attributes_box\').append(span);
2851 });
2852 })
2853 });
2854
2855 ' . ($selected ? 'jQuery("'.$htmltag.'#' . $htmlname . '").change();' : '') . '
2856 });
2857 </script>
2858 ';
2859 }
2860
2861 if (empty($hidelabel)) {
2862 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2863 } elseif ($hidelabel > 1) {
2864 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2865 if ($hidelabel == 2) {
2866 $out .= img_picto($langs->trans("Search"), 'search');
2867 }
2868 }
2869
2870 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2871 if ($hidelabel == 3) {
2872 $out .= img_picto($langs->trans("Search"), 'search');
2873 }
2874
2875 $out .= ajax_autocompleter((string) $selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), getDolGlobalInt('PRODUCT_SEARCH_AUTO_SELECT_IF_ONLY_ONE', 1), $ajaxoptions);
2876 } else {
2877 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2878
2879 if (isModEnabled('variants') && is_array($selected_combinations)) {
2880 // Code to automatically insert with javascript the select of attributes under the select of product
2881 // when a parent of variant has been selected.
2882 // Note: Samecode than for product input using Ajax
2883 $htmltag = 'select';
2884 $out .= '
2885 <!-- script to auto show attributes select tags if a variant was selected -->
2886 <script nonce="' . getNonce() . '">
2887 // auto show attributes fields
2888 selected = ' . json_encode($selected_combinations) . ';
2889 combvalues = {};
2890
2891 jQuery(document).ready(function () {
2892
2893 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2894 if (jQuery(this).val() == \'free\') {
2895 jQuery(\'div#attributes_box\').empty();
2896 }
2897 });
2898
2899 jQuery("'.$htmltag.'#' . $htmlname . '").change(function () {
2900
2901 if (!jQuery(this).val()) {
2902 jQuery(\'div#attributes_box\').empty();
2903 return;
2904 }
2905
2906 console.log("A change has started. We get variants fields to inject html select");
2907
2908 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2909 id: jQuery(this).val()
2910 }, function (data) {
2911 jQuery(\'div#attributes_box\').empty();
2912
2913 jQuery.each(data, function (key, val) {
2914
2915 combvalues[val.id] = val.values;
2916
2917 var span = jQuery(document.createElement(\'div\')).css({
2918 \'display\': \'table-row\'
2919 });
2920
2921 span.append(
2922 jQuery(document.createElement(\'div\')).text(val.label).css({
2923 \'font-weight\': \'bold\',
2924 \'display\': \'table-cell\'
2925 })
2926 );
2927
2928 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2929 \'margin-left\': \'15px\',
2930 \'white-space\': \'pre\'
2931 }).append(
2932 jQuery(document.createElement(\'option\')).val(\'\')
2933 );
2934
2935 jQuery.each(combvalues[val.id], function (key, val) {
2936 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2937
2938 if (selected[val.fk_product_attribute] == val.id) {
2939 tag.attr(\'selected\', \'selected\');
2940 }
2941
2942 html.append(tag);
2943 });
2944
2945 span.append(html);
2946 jQuery(\'div#attributes_box\').append(span);
2947 });
2948 })
2949 });
2950
2951 ' . ($selected ? 'jQuery("'.$htmltag.'#' . $htmlname . '").change();' : '') . '
2952 });
2953 </script>
2954 ';
2955 }
2956 }
2957
2958 if (empty($nooutput)) {
2959 print $out;
2960 } else {
2961 return $out;
2962 }
2963 }
2964
2965 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2966
2982 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2983 {
2984 // phpcs:enable
2985 global $db;
2986
2987 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2988
2989 $error = 0;
2990 $out = '';
2991
2992 if (!$forcecombo) {
2993 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2994 $events = array();
2995 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("BOM_USE_SEARCH_TO_SELECT"));
2996 }
2997
2998 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2999
3000 $sql = 'SELECT b.rowid, b.ref, b.label as bomLabel, p.label as productLabel';
3001 $sql .= ' FROM ' . $this->db->prefix() . 'bom_bom as b';
3002 $sql .= ' INNER JOIN ' . $this->db->prefix() . 'product as p ON b.fk_product = p.rowid';
3003 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
3004 if (!empty($status)) {
3005 $sql .= ' AND status = ' . (int) $status;
3006 }
3007 if (!empty($type)) {
3008 $sql .= ' AND bomtype = ' . (int) $type;
3009 }
3010 if (!empty($TProducts)) {
3011 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
3012 }
3013 if (!empty($limit)) {
3014 $sql .= ' LIMIT ' . (int) $limit;
3015 }
3016 $resql = $db->query($sql);
3017 if ($resql) {
3018 if ($showempty) {
3019 $out .= '<option value="-1"';
3020 if (empty($selected)) {
3021 $out .= ' selected';
3022 }
3023 $out .= '>&nbsp;</option>';
3024 }
3025 while ($obj = $db->fetch_object($resql)) {
3026 $out .= '<option value="' . $obj->rowid . '"';
3027 if ($obj->rowid == $selected) {
3028 $out .= 'selected';
3029 }
3030 $out .= '>' . $obj->ref . ' - ' . $obj->productLabel . ' - ' . $obj->bomLabel . '</option>';
3031 }
3032 } else {
3033 $error++;
3034 dol_print_error($db);
3035 }
3036 $out .= '</select>';
3037 if (empty($nooutput)) {
3038 print $out;
3039 } else {
3040 return $out;
3041 }
3042 }
3043
3044 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3045
3072 public function select_produits_list($selected = 0, $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = 'maxwidth500', $hidepriceinlabel = 0, $warehouseStatus = '', $status_purchase = -1, $warehouseId = 0)
3073 {
3074 // phpcs:enable
3075 global $langs;
3076 global $hookmanager;
3077
3078 $out = '';
3079 $outarray = array();
3080
3081 // Units
3082 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3083 $langs->load('other');
3084 }
3085
3086 $warehouseStatusArray = array();
3087 if (!empty($warehouseStatus)) {
3088 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
3089 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
3090 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
3091 }
3092 if (preg_match('/warehouseopen/', $warehouseStatus)) {
3093 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
3094 }
3095 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
3096 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
3097 }
3098 }
3099
3100 $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";
3101 if (count($warehouseStatusArray)) {
3102 $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
3103 } else {
3104 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", '0', "p.stock") . " AS stock";
3105 }
3106
3107 $sql = "SELECT ";
3108
3109 // Add select from hooks
3110 $parameters = array();
3111 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
3112 if (empty($reshook)) {
3113 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
3114 } else {
3115 $sql .= $hookmanager->resPrint;
3116 }
3117
3118 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3119 //Product category
3120 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
3121 FROM " . $this->db->prefix() . "categorie_product
3122 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
3123 LIMIT 1
3124 ) AS categorie_product_id ";
3125 }
3126
3127 //Price by customer
3128 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3129 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
3130 $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.default_vat_code as custdefault_vat_code, pcp.ref_customer as custref, pcp.discount_percent as custdiscount_percent';
3131 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref, custdiscount_percent";
3132 }
3133 // Units
3134 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3135 $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";
3136 $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';
3137 }
3138
3139 // Multilang : we add translation
3140 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3141 $sql .= ", pl.label as label_translated";
3142 $sql .= ", pl.description as description_translated";
3143 $selectFields .= ", label_translated";
3144 $selectFields .= ", description_translated";
3145 }
3146 // Price by quantity
3147 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3148 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
3149 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3150 $sql .= " AND price_level = " . ((int) $price_level);
3151 }
3152 $sql .= " ORDER BY date_price";
3153 $sql .= " DESC LIMIT 1) as price_rowid";
3154 $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
3155 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3156 $sql .= " AND price_level = " . ((int) $price_level);
3157 }
3158 $sql .= " ORDER BY date_price";
3159 $sql .= " DESC LIMIT 1) as price_by_qty";
3160 $selectFields .= ", price_rowid, price_by_qty";
3161 }
3162
3163 $sql .= " FROM ".$this->db->prefix()."product as p";
3164
3165 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
3166 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
3167 }
3168
3169 // Add from (left join) from hooks
3170 $parameters = array(
3171 'socid' => $socid,
3172 );
3173 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3174 $sql .= $hookmanager->resPrint;
3175
3176 if (count($warehouseStatusArray)) {
3177 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
3178 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3179 $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.
3180 }
3181
3182 //Price by customer
3183 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3184 $now = dol_now();
3185 $sql .= " LEFT JOIN (";
3186 $sql .= " SELECT pcp1.*";
3187 $sql .= " FROM " . $this->db->prefix() . "product_customer_price AS pcp1";
3188 $sql .= " LEFT JOIN (";
3189 $sql .= " SELECT fk_soc, fk_product, MIN(date_begin) AS date_begin";
3190 $sql .= " FROM " . $this->db->prefix() . "product_customer_price";
3191 $sql .= " WHERE fk_soc = " . ((int) $socid);
3192 $sql .= " AND date_begin <= '" . $this->db->idate($now) . "'";
3193 $sql .= " AND (date_end IS NULL OR '" . $this->db->idate($now) . "' <= date_end)";
3194 $sql .= " GROUP BY fk_soc, fk_product";
3195 $sql .= " ) AS pcp2 ON pcp1.fk_soc = pcp2.fk_soc AND pcp1.fk_product = pcp2.fk_product AND pcp1.date_begin = pcp2.date_begin";
3196 $sql .= " WHERE pcp2.fk_soc IS NOT NULL";
3197 $sql .= " ) AS pcp ON pcp.fk_soc = " . ((int) $socid) . " AND pcp.fk_product = p.rowid";
3198 }
3199 // Units
3200 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3201 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3202 }
3203 // Multilang : we add translation
3204 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3205 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3206 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3207 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3208 $soc = new Societe($this->db);
3209 $result = $soc->fetch($socid);
3210 if ($result > 0 && !empty($soc->default_lang)) {
3211 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3212 } else {
3213 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3214 }
3215 } else {
3216 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3217 }
3218 }
3219
3220 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3221 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3222 }
3223
3224 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3225
3226 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3227 $sql .= " AND pac.rowid IS NULL";
3228 }
3229
3230 if ($finished == 0) {
3231 $sql .= " AND p.finished = " . ((int) $finished);
3232 } elseif ($finished == 1) {
3233 $sql .= " AND p.finished = ".((int) $finished);
3234 }
3235 if ($status >= 0) {
3236 $sql .= " AND p.tosell = ".((int) $status);
3237 }
3238 if ($status_purchase >= 0) {
3239 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3240 }
3241 // Filter by product type
3242 if (strval($filtertype) != '') {
3243 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3244 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3245 $sql .= " AND p.fk_product_type = 1";
3246 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3247 $sql .= " AND p.fk_product_type = 0";
3248 }
3249
3250 if ((int) $warehouseId > 0) {
3251 $sql .= " AND EXISTS (SELECT psw.fk_product FROM " . $this->db->prefix() . "product_stock as psw WHERE psw.reel>0 AND psw.fk_entrepot=".(int) $warehouseId." AND psw.fk_product = p.rowid)";
3252 }
3253
3254 // Add where from hooks
3255 $parameters = array(
3256 'filterkey' => &$filterkey,
3257 'socid' => $socid,
3258 );
3259 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3260 $sql .= $hookmanager->resPrint;
3261 // Add criteria on ref/label
3262 if ($filterkey != '') {
3263 $sqlSupplierSearch = '';
3264
3265 $sql .= ' AND (';
3266 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3267 // For natural search
3268 $search_crit = explode(' ', $filterkey);
3269 $i = 0;
3270 if (count($search_crit) > 1) {
3271 $sql .= "(";
3272 }
3273 foreach ($search_crit as $crit) {
3274 if ($i > 0) {
3275 $sql .= " AND ";
3276 }
3277 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3278 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3279 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3280 }
3281 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3282 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3283 }
3284 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3285 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3286 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3287 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3288 }
3289 }
3290
3291 // include search in supplier ref
3292 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3293 $sqlSupplierSearch .= !empty($sqlSupplierSearch) ? ' AND ':'';
3294 $sqlSupplierSearch .= " pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3295 }
3296 $sql .= ")";
3297 $i++;
3298 }
3299 if (count($search_crit) > 1) {
3300 $sql .= ")";
3301 }
3302 if (isModEnabled('barcode')) {
3303 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3304 }
3305
3306 // include search in supplier ref
3307 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3308 $sql .= " OR EXISTS (SELECT pfp.fk_product FROM " . $this->db->prefix() . "product_fournisseur_price as pfp WHERE p.rowid = pfp.fk_product";
3309 $sql .= " AND (";
3310 $sql .= $sqlSupplierSearch;
3311 $sql .= "))";
3312 }
3313
3314 $sql .= ')';
3315 }
3316 if (count($warehouseStatusArray)) {
3317 $sql .= " GROUP BY " . $selectFields;
3318 }
3319
3320 //Sort by category
3321 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3322 $sql .= " ORDER BY categorie_product_id ";
3323 //ASC OR DESC order
3324 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3325 } else {
3326 $sql .= $this->db->order("p.ref");
3327 }
3328
3329 $limit = getDolGlobalInt('SEARCH_LIMIT_AJAX') ?: $limit;
3330 $sql .= $this->db->plimit($limit, 0);
3331
3332 // Build output string
3333 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3334 $result = $this->db->query($sql);
3335 if ($result) {
3336 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3337 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3338 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3339
3340 $num = $this->db->num_rows($result);
3341
3342 $events = array();
3343
3344 if (!$forcecombo) {
3345 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3346 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3347 }
3348
3349 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3350
3351 $textifempty = '';
3352 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3353 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3354 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3355 if ($showempty && !is_numeric($showempty)) {
3356 $textifempty = $langs->trans($showempty);
3357 } else {
3358 $textifempty .= $langs->trans("All");
3359 }
3360 } else {
3361 if ($showempty && !is_numeric($showempty)) {
3362 $textifempty = $langs->trans($showempty);
3363 }
3364 }
3365 if ($showempty) {
3366 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3367 }
3368
3369 $i = 0;
3370 while ($num && $i < $num) {
3371 $opt = '';
3372 $optJson = array();
3373 $objp = $this->db->fetch_object($result);
3374
3375 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
3376 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3377 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3378 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3379 $sql .= " ORDER BY quantity ASC";
3380
3381 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3382 $result2 = $this->db->query($sql);
3383 if ($result2) {
3384 $nb_prices = $this->db->num_rows($result2);
3385 $j = 0;
3386 while ($nb_prices && $j < $nb_prices) {
3387 $objp2 = $this->db->fetch_object($result2);
3388
3389 $objp->price_by_qty_rowid = $objp2->rowid;
3390 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3391 $objp->price_by_qty_quantity = $objp2->quantity;
3392 $objp->price_by_qty_unitprice = $objp2->unitprice;
3393 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3394 // For backward compatibility
3395 $objp->quantity = $objp2->quantity;
3396 $objp->price = $objp2->price;
3397 $objp->unitprice = $objp2->unitprice;
3398 $objp->remise_percent = $objp2->remise_percent;
3399
3400 //$objp->tva_tx is not overwritten by $objp2 value
3401 //$objp->default_vat_code is not overwritten by $objp2 value
3402
3403 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3404 '@phan-var-force array{key:string,value:string,label:string,label2:string,desc:string,type:string,price_ht:string,price_ttc:string,price_ht_locale:string,price_ttc_locale:string,pricebasetype:string,tva_tx:string,default_vat_code:string,qty:string,discount:string,duration_value:string,duration_unit:string,pbq:string,labeltrans:string,desctrans:string,ref_customer:string} $optJson';
3405 $j++;
3406
3407 // Add new entry
3408 // "key" value of json key array is used by jQuery automatically as selected value
3409 // "label" value of json key array is used by jQuery automatically as text for combo box
3410 $out .= $opt;
3411 array_push($outarray, $optJson);
3412 }
3413 }
3414 } else {
3415 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3416 $price_product = new Product($this->db);
3417 $price_product->fetch($objp->rowid, '', '', '1');
3418
3419 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3420 $priceparser = new PriceParser($this->db);
3421 $price_result = $priceparser->parseProduct($price_product);
3422 if ($price_result >= 0) {
3423 $objp->price = $price_result;
3424 $objp->unitprice = $price_result;
3425 //Calculate the VAT
3426 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3427 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3428 }
3429 }
3430 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3431 $price_level = '';
3432 }
3433 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3434 // Add new entry
3435 // "key" value of json key array is used by jQuery automatically as selected value
3436 // "label" value of json key array is used by jQuery automatically as text for combo box
3437 $out .= $opt;
3438 array_push($outarray, $optJson);
3439 }
3440
3441 $i++;
3442 }
3443
3444 $out .= '</select>';
3445
3446 $this->db->free($result);
3447
3448 if (empty($outputmode)) {
3449 return $out;
3450 }
3451
3452 return $outarray;
3453 } else {
3454 dol_print_error($this->db);
3455 }
3456
3457 return '';
3458 }
3459
3475 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3476 {
3477 global $langs, $conf, $user;
3478 global $hookmanager;
3479
3480 $outkey = '';
3481 $outval = '';
3482 $outref = '';
3483 $outlabel = '';
3484 $outlabel_translated = '';
3485 $outdesc = '';
3486 $outdesc_translated = '';
3487 $outbarcode = '';
3488 $outorigin = '';
3489 $outtype = '';
3490 $outprice_ht = '';
3491 $outprice_ttc = '';
3492 $outpricebasetype = '';
3493 $outtva_tx = '';
3494 $outdefault_vat_code = '';
3495 $outqty = 1;
3496 $outdiscount = '0';
3497
3498 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3499
3500 $label = $objp->label;
3501 if (!empty($objp->label_translated)) {
3502 $label = $objp->label_translated;
3503 }
3504 if (!empty($filterkey) && $filterkey != '') {
3505 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3506 }
3507
3508 $outkey = $objp->rowid;
3509 $outref = $objp->ref;
3510 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3511 $outlabel = $objp->label;
3512 $outdesc = $objp->description;
3513 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3514 $outlabel_translated = $objp->label_translated;
3515 $outdesc_translated = $objp->description_translated;
3516 }
3517 $outbarcode = $objp->barcode;
3518 $outorigin = $objp->fk_country;
3519 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3520
3521 $outtype = $objp->fk_product_type;
3522 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3523 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3524
3525 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3526 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3527 }
3528
3529 // Units
3530 $outvalUnits = '';
3531 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3532 if (!empty($objp->unit_short)) {
3533 $outvalUnits .= ' - ' . $objp->unit_short;
3534 }
3535 }
3536 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3537 if (!empty($objp->weight) && $objp->weight_units !== null) {
3538 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3539 $outvalUnits .= ' - ' . $unitToShow;
3540 }
3541 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3542 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3543 $outvalUnits .= ' - ' . $unitToShow;
3544 }
3545 if (!empty($objp->surface) && $objp->surface_units !== null) {
3546 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3547 $outvalUnits .= ' - ' . $unitToShow;
3548 }
3549 if (!empty($objp->volume) && $objp->volume_units !== null) {
3550 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3551 $outvalUnits .= ' - ' . $unitToShow;
3552 }
3553 }
3554 if ($outdurationvalue && $outdurationunit) {
3555 $da = array(
3556 'h' => $langs->trans('Hour'),
3557 'd' => $langs->trans('Day'),
3558 'w' => $langs->trans('Week'),
3559 'm' => $langs->trans('Month'),
3560 'y' => $langs->trans('Year')
3561 );
3562 if (isset($da[$outdurationunit])) {
3563 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3564 }
3565 }
3566
3567 // Set stocktag (stock too low or not or unknown)
3568 $stocktag = 0;
3569 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3570 if ($user->hasRight('stock', 'lire')) {
3571 if ($objp->stock > 0) {
3572 $stocktag = 1;
3573 } elseif ($objp->stock <= 0) {
3574 $stocktag = -1;
3575 }
3576 }
3577 }
3578
3579 // Set $labeltoshow
3580 $labeltoshow = '';
3581 $labeltoshow .= $objp->ref;
3582 if (!empty($objp->custref)) {
3583 $labeltoshow .= ' (' . $objp->custref . ')';
3584 }
3585 if ($outbarcode) {
3586 $labeltoshow .= ' (' . $outbarcode . ')';
3587 }
3588 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3589 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3590 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3591 }
3592
3593 // Set $labltoshowhtml
3594 $labeltoshowhtml = '';
3595 $labeltoshowhtml .= $objp->ref;
3596 if (!empty($objp->custref)) {
3597 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3598 }
3599 if (!empty($filterkey) && $filterkey != '') {
3600 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3601 }
3602 if ($outbarcode) {
3603 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3604 }
3605 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3606 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3607 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3608 }
3609
3610 // Stock
3611 $labeltoshowstock = '';
3612 $labeltoshowhtmlstock = '';
3613 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3614 if ($user->hasRight('stock', 'lire')) {
3615 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3616
3617 if ($objp->stock > 0) {
3618 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3619 } elseif ($objp->stock <= 0) {
3620 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3621 }
3622 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3623 $labeltoshowhtmlstock .= '</span>';
3624
3625 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3626 $langs->load("stocks");
3627
3628 $tmpproduct = new Product($this->db);
3629 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3630 $tmpproduct->load_virtual_stock();
3631 $virtualstock = $tmpproduct->stock_theorique;
3632
3633 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3634
3635 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3636 if ($virtualstock > 0) {
3637 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3638 } elseif ($virtualstock <= 0) {
3639 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3640 }
3641 $labeltoshowhtmlstock .= $virtualstock;
3642 $labeltoshowhtmlstock .= '</span>';
3643
3644 unset($tmpproduct);
3645 }
3646 }
3647 }
3648
3649 // Price
3650 $found = 0;
3651 $labeltoshowprice = '';
3652 $labeltoshowhtmlprice = '';
3653 // If we need a particular price level (from 1 to n)
3654 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3655 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3656 $sql .= " FROM " . $this->db->prefix() . "product_price";
3657 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3658 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3659 $sql .= " AND price_level = " . ((int) $price_level);
3660 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3661 $sql .= " LIMIT 1";
3662
3663 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3664 $result2 = $this->db->query($sql);
3665 if ($result2) {
3666 $objp2 = $this->db->fetch_object($result2);
3667 if ($objp2) {
3668 $found = 1;
3669 if ($objp2->price_base_type == 'HT') {
3670 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3671 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3672 } else {
3673 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3674 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3675 }
3676 $outprice_ht = price($objp2->price);
3677 $outprice_ttc = price($objp2->price_ttc);
3678 $outpricebasetype = $objp2->price_base_type;
3679 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3680 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3681 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3682 } else {
3683 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3684 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3685 }
3686 }
3687 } else {
3688 dol_print_error($this->db);
3689 }
3690 }
3691
3692 // Price by quantity
3693 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3694 $found = 1;
3695 $outqty = $objp->quantity;
3696 $outdiscount = $objp->remise_percent;
3697 if ($objp->quantity == 1) {
3698 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3699 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3700 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3701 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3702 } else {
3703 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3704 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3705 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3706 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3707 }
3708
3709 $outprice_ht = price($objp->unitprice);
3710 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3711 $outpricebasetype = $objp->price_base_type;
3712 $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
3713 $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
3714 }
3715 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3716 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3717 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3718 }
3719 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3720 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3721 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3722 }
3723
3724 // Price by customer
3725 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3726 if (!empty($objp->idprodcustprice)) {
3727 $found = 1;
3728
3729 if ($objp->custprice_base_type == 'HT') {
3730 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3731 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3732 } else {
3733 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3734 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3735 }
3736
3737 $outprice_ht = price($objp->custprice);
3738 $outprice_ttc = price($objp->custprice_ttc);
3739 $outpricebasetype = $objp->custprice_base_type;
3740 $outtva_tx = $objp->custtva_tx;
3741 $outdefault_vat_code = $objp->custdefault_vat_code;
3742 $outdiscount = $objp->custdiscount_percent;
3743 }
3744 }
3745
3746 // If level no defined or multiprice not found, we used the default price
3747 if (empty($hidepriceinlabel) && !$found) {
3748 if ($objp->price_base_type == 'HT') {
3749 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3750 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3751 } else {
3752 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3753 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3754 }
3755 $outprice_ht = price($objp->price);
3756 $outprice_ttc = price($objp->price_ttc);
3757 $outpricebasetype = $objp->price_base_type;
3758 $outtva_tx = $objp->tva_tx;
3759 $outdefault_vat_code = $objp->default_vat_code;
3760 }
3761
3762 // Build options
3763 $opt = '<option value="' . $objp->rowid . '"';
3764 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3765 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3766 $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 . '"';
3767 }
3768 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3769 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3770 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3771 }
3772
3773 if ($stocktag == 1) {
3774 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3775 //$opt .= ' class="product_line_stock_ok"';
3776 }
3777 if ($stocktag == -1) {
3778 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3779 //$opt .= ' class="product_line_stock_too_low"';
3780 }
3781
3782 $opt .= '>';
3783
3784 // Ref, barcode, country
3785 $opt .= $labeltoshow;
3786 $outval .= $labeltoshowhtml;
3787
3788 // Units
3789 $opt .= $outvalUnits;
3790 $outval .= $outvalUnits;
3791
3792 // Price
3793 $opt .= $labeltoshowprice;
3794 $outval .= $labeltoshowhtmlprice;
3795
3796 // Stock
3797 $opt .= $labeltoshowstock;
3798 $outval .= $labeltoshowhtmlstock;
3799
3800
3801 $parameters = array('objp' => $objp);
3802 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3803 if (empty($reshook)) {
3804 $opt .= $hookmanager->resPrint;
3805 } else {
3806 $opt = $hookmanager->resPrint;
3807 }
3808
3809 $opt .= "</option>\n";
3810 $optJson = array(
3811 'key' => $outkey,
3812 'value' => $outref,
3813 'label' => $outval,
3814 'label2' => $outlabel,
3815 'desc' => $outdesc,
3816 'type' => $outtype,
3817 'price_ht' => price2num($outprice_ht),
3818 'price_ttc' => price2num($outprice_ttc),
3819 'price_ht_locale' => price(price2num($outprice_ht)),
3820 'price_ttc_locale' => price(price2num($outprice_ttc)),
3821 'pricebasetype' => $outpricebasetype,
3822 'tva_tx' => $outtva_tx,
3823 'default_vat_code' => $outdefault_vat_code,
3824 'qty' => $outqty,
3825 'discount' => $outdiscount,
3826 'duration_value' => $outdurationvalue,
3827 'duration_unit' => $outdurationunit,
3828 'pbq' => $outpbq,
3829 'labeltrans' => $outlabel_translated,
3830 'desctrans' => $outdesc_translated,
3831 'ref_customer' => $outrefcust
3832 );
3833 }
3834
3835 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3836
3853 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '', $nooutput = 0)
3854 {
3855 // phpcs:enable
3856 global $langs, $conf;
3857 global $price_level, $status, $finished;
3858
3859 if (!isset($status)) {
3860 $status = 1;
3861 }
3862
3863 $selected_input_value = '';
3864 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3865 if ((int) $selected > 0) {
3866 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3867 $producttmpselect = new Product($this->db);
3868 $producttmpselect->fetch((int) $selected);
3869 $selected_input_value = $producttmpselect->ref;
3870 unset($producttmpselect);
3871 }
3872
3873 // mode=2 means suppliers products
3874 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3875
3876 $s = ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3877
3878 $s .= ($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3879 } else {
3880 $s = $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, getDolGlobalInt('SUPPLIER_SHOW_STOCK_IN_PRODUCTS_COMBO'), $placeholder);
3881 }
3882
3883 if ($nooutput) {
3884 return $s;
3885 } else {
3886 print $s;
3887 }
3888 }
3889
3890 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3891
3910 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 = '')
3911 {
3912 // phpcs:enable
3913 global $langs, $conf, $user;
3914 global $hookmanager;
3915
3916 $out = '';
3917 $outarray = array();
3918
3919 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3920
3921 $langs->load('stocks');
3922 // Units
3923 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3924 $langs->load('other');
3925 }
3926
3927 $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,";
3928 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3929 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3930 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3931 $sql .= ", pfp.supplier_reputation";
3932 // if we use supplier description of the products
3933 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3934 $sql .= ", pfp.desc_fourn as description";
3935 } else {
3936 $sql .= ", p.description";
3937 }
3938 // Units
3939 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3940 $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";
3941 }
3942
3943 // Add select from hooks
3944 $parameters = [];
3945 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
3946 $sql .= $hookmanager->resPrint;
3947
3948 $sql .= " FROM " . $this->db->prefix() . "product as p";
3949
3950 // Add join from hooks
3951 $parameters = [];
3952 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3953 $sql .= $hookmanager->resPrint;
3954
3955 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3956 if ($socid > 0) {
3957 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3958 }
3959 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3960 // Units
3961 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3962 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3963 }
3964 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3965 if ($statut != -1) {
3966 $sql .= " AND p.tobuy = " . ((int) $statut);
3967 }
3968 if (strval($filtertype) != '') {
3969 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3970 }
3971 if (!empty($filtre)) {
3972 $sql .= " " . $filtre;
3973 }
3974 // Add where from hooks
3975 $parameters = array();
3976 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3977 $sql .= $hookmanager->resPrint;
3978 // Add criteria on ref/label
3979 if ($filterkey != '') {
3980 $sql .= ' AND (';
3981 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3982 // For natural search
3983 $search_crit = explode(' ', $filterkey);
3984 $i = 0;
3985 if (count($search_crit) > 1) {
3986 $sql .= "(";
3987 }
3988 foreach ($search_crit as $crit) {
3989 if ($i > 0) {
3990 $sql .= " AND ";
3991 }
3992 $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) . "%'";
3993 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3994 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3995 }
3996 $sql .= ")";
3997 $i++;
3998 }
3999 if (count($search_crit) > 1) {
4000 $sql .= ")";
4001 }
4002 if (isModEnabled('barcode')) {
4003 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
4004 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
4005 }
4006 $sql .= ')';
4007 }
4008 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
4009 $sql .= $this->db->plimit($limit, 0);
4010
4011 // Build output string
4012
4013 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
4014 $result = $this->db->query($sql);
4015 if ($result) {
4016 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4017 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
4018
4019 $num = $this->db->num_rows($result);
4020
4021 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
4022 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
4023 if (!$selected) {
4024 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
4025 } else {
4026 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
4027 }
4028
4029 $i = 0;
4030 while ($i < $num) {
4031 $objp = $this->db->fetch_object($result);
4032
4033 if (is_null($objp->idprodfournprice)) {
4034 // There is no supplier price found, we will use the vat rate for sale
4035 $objp->tva_tx = $objp->tva_tx_sale;
4036 $objp->default_vat_code = $objp->default_vat_code_sale;
4037 }
4038
4039 $outkey = $objp->idprodfournprice; // id in table of price
4040 if (!$outkey && $alsoproductwithnosupplierprice) {
4041 $outkey = 'idprod_' . $objp->rowid; // id of product
4042 }
4043
4044 $outref = $objp->ref;
4045 $outbarcode = $objp->barcode;
4046 $outqty = 1;
4047 $outdiscount = 0;
4048 $outtype = $objp->fk_product_type;
4049 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
4050 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
4051
4052 // Units
4053 $outvalUnits = '';
4054 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
4055 if (!empty($objp->unit_short)) {
4056 $outvalUnits .= ' - ' . $objp->unit_short;
4057 }
4058 if (!empty($objp->weight) && $objp->weight_units !== null) {
4059 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
4060 $outvalUnits .= ' - ' . $unitToShow;
4061 }
4062 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
4063 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
4064 $outvalUnits .= ' - ' . $unitToShow;
4065 }
4066 if (!empty($objp->surface) && $objp->surface_units !== null) {
4067 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
4068 $outvalUnits .= ' - ' . $unitToShow;
4069 }
4070 if (!empty($objp->volume) && $objp->volume_units !== null) {
4071 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
4072 $outvalUnits .= ' - ' . $unitToShow;
4073 }
4074 if ($outdurationvalue && $outdurationunit) {
4075 $da = array(
4076 'h' => $langs->trans('Hour'),
4077 'd' => $langs->trans('Day'),
4078 'w' => $langs->trans('Week'),
4079 'm' => $langs->trans('Month'),
4080 'y' => $langs->trans('Year')
4081 );
4082 if (isset($da[$outdurationunit])) {
4083 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
4084 }
4085 }
4086 }
4087
4088 $objRef = $objp->ref;
4089 if ($filterkey && $filterkey != '') {
4090 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
4091 }
4092 $objRefFourn = $objp->ref_fourn;
4093 if ($filterkey && $filterkey != '') {
4094 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
4095 }
4096 $label = $objp->label;
4097 if ($filterkey && $filterkey != '') {
4098 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
4099 }
4100
4101 switch ($objp->fk_product_type) {
4103 $picto = 'product';
4104 break;
4106 $picto = 'service';
4107 break;
4108 default:
4109 $picto = '';
4110 break;
4111 }
4112
4113 if (empty($picto)) {
4114 $optlabel = '';
4115 } else {
4116 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
4117 }
4118
4119 $optlabel .= $objp->ref;
4120 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
4121 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
4122 }
4123 if (isModEnabled('barcode') && !empty($objp->barcode)) {
4124 $optlabel .= ' (' . $outbarcode . ')';
4125 }
4126 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
4127
4128 $outvallabel = $objRef;
4129 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
4130 $outvallabel .= ' (' . $objRefFourn . ')';
4131 }
4132 if (isModEnabled('barcode') && !empty($objp->barcode)) {
4133 $outvallabel .= ' (' . $outbarcode . ')';
4134 }
4135 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
4136
4137 // Units
4138 $optlabel .= $outvalUnits;
4139 $outvallabel .= $outvalUnits;
4140
4141 if (!empty($objp->idprodfournprice)) {
4142 $outqty = $objp->quantity;
4143 $outdiscount = $objp->remise_percent;
4144 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4145 $prod_supplier = new ProductFournisseur($this->db);
4146 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4147 $prod_supplier->id = $objp->fk_product;
4148 $prod_supplier->fourn_qty = $objp->quantity;
4149 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4150 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4151
4152 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4153 $priceparser = new PriceParser($this->db);
4154 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4155 if ($price_result >= 0) {
4156 $objp->fprice = $price_result;
4157 if ($objp->quantity >= 1) {
4158 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
4159 }
4160 }
4161 }
4162 if ($objp->quantity == 1) {
4163 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4164 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
4165 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
4166 $outvallabel .= $langs->transnoentities("Unit");
4167 } else {
4168 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
4169 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
4170 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
4171 $outvallabel .= ' ' . $langs->transnoentities("Units");
4172 }
4173
4174 if ($objp->quantity != 1) {
4175 $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
4176 $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
4177 }
4178 if ($objp->remise_percent >= 1) {
4179 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4180 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4181 }
4182 if ($objp->duration) {
4183 $optlabel .= " - " . $objp->duration;
4184 $outvallabel .= " - " . $objp->duration;
4185 }
4186 if (!$socid) {
4187 $optlabel .= " - " . dol_trunc($objp->name, 8);
4188 $outvallabel .= " - " . dol_trunc($objp->name, 8);
4189 }
4190 if ($objp->supplier_reputation) {
4191 //TODO dictionary
4192 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
4193
4194 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
4195 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
4196 }
4197 } else {
4198 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
4199 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
4200 }
4201
4202 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
4203 $novirtualstock = ($showstockinlist == 2);
4204
4205 if ($user->hasRight('stock', 'lire')) {
4206 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
4207
4208 if ($objp->stock > 0) {
4209 $optlabel .= ' - <span class="product_line_stock_ok">';
4210 } elseif ($objp->stock <= 0) {
4211 $optlabel .= ' - <span class="product_line_stock_too_low">';
4212 }
4213 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
4214 $optlabel .= '</span>';
4215 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
4216 $langs->load("stocks");
4217
4218 $tmpproduct = new Product($this->db);
4219 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
4220 $tmpproduct->load_virtual_stock();
4221 $virtualstock = $tmpproduct->stock_theorique;
4222
4223 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4224
4225 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4226 if ($virtualstock > 0) {
4227 $optlabel .= '<span class="product_line_stock_ok">';
4228 } elseif ($virtualstock <= 0) {
4229 $optlabel .= '<span class="product_line_stock_too_low">';
4230 }
4231 $optlabel .= $virtualstock;
4232 $optlabel .= '</span>';
4233
4234 unset($tmpproduct);
4235 }
4236 }
4237 }
4238
4239 $optstart = '<option value="' . $outkey . '"';
4240 if ($selected && preg_match('/^idprod_/', (string) $selected) && (string) $selected == 'idprod_'.$objp->rowid) {
4241 $optstart .= ' selected';
4242 } elseif ($selected && (string) $selected == (string) $objp->idprodfournprice) {
4243 $optstart .= ' selected';
4244 }
4245
4246 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4247 $optstart .= ' disabled';
4248 }
4249
4250 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4251 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4252 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4253 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4254 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"'; // the price with numeric international format
4255 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"'; // the price formatted in user language
4256 $optstart .= ' data-discount="' . dol_escape_htmltag((string) $outdiscount) . '"';
4257 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"'; // the rate with numeric international format
4258 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"'; // the rate formatted in user language
4259 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4260 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4261 if (isModEnabled('multicurrency')) {
4262 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4263 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag(price2num($objp->multicurrency_unitprice)) . '"'; // the price with numeric international format
4264 }
4265 }
4266 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4267
4268 // set $parameters to call hook
4269 $outarrayentry = array(
4270 'key' => $outkey,
4271 'value' => $outref,
4272 'label' => $outvallabel,
4273 'labelhtml' => $optlabel,
4274 'qty' => $outqty,
4275 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4276 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4277 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4278 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4279 'tva_tx' => price2num($objp->tva_tx),
4280 'default_vat_code' => $objp->default_vat_code,
4281 'supplier_ref' => $objp->ref_fourn,
4282 'discount' => $outdiscount,
4283 'type' => $outtype,
4284 'duration_value' => $outdurationvalue,
4285 'duration_unit' => $outdurationunit,
4286 'disabled' => empty($objp->idprodfournprice),
4287 'description' => $objp->description
4288 );
4289 if (isModEnabled('multicurrency')) {
4290 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4291 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4292 }
4293 $parameters = array(
4294 'objp' => &$objp,
4295 'optstart' => &$optstart,
4296 'optlabel' => &$optlabel,
4297 'outvallabel' => &$outvallabel,
4298 'outarrayentry' => &$outarrayentry,
4299 'fk_soc' => $socid
4300 );
4301 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4302
4303
4304 // Add new entry
4305 // "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
4306 // "label" value of json key array is used by jQuery automatically as text for combo box
4307 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4308 $outarraypush = array(
4309 'key' => $outkey,
4310 'value' => $outref,
4311 'label' => $outvallabel,
4312 'labelhtml' => $optlabel,
4313 'qty' => $outqty,
4314 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4315 'price_qty_ht_locale' => price($objp->fprice),
4316 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4317 'price_unit_ht_locale' => price($objp->unitprice),
4318 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4319 'tva_tx_formated' => price($objp->tva_tx),
4320 'tva_tx' => price2num($objp->tva_tx),
4321 'default_vat_code' => $objp->default_vat_code,
4322 'supplier_ref' => $objp->ref_fourn,
4323 'discount' => $outdiscount,
4324 'type' => $outtype,
4325 'duration_value' => $outdurationvalue,
4326 'duration_unit' => $outdurationunit,
4327 'disabled' => empty($objp->idprodfournprice),
4328 'description' => $objp->description
4329 );
4330 if (isModEnabled('multicurrency')) {
4331 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4332 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4333 }
4334 array_push($outarray, $outarraypush);
4335
4336 // Example of var_dump $outarray
4337 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4338 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4339 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4340 //}
4341 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4342 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4343 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4344
4345 $i++;
4346 }
4347 $out .= '</select>';
4348
4349 $this->db->free($result);
4350
4351 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4352 $out .= ajax_combobox($htmlname);
4353 } else {
4354 dol_print_error($this->db);
4355 }
4356
4357 if (empty($outputmode)) {
4358 return $out;
4359 }
4360 return $outarray;
4361 }
4362
4363 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4364
4373 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4374 {
4375 // phpcs:enable
4376 global $langs, $conf;
4377
4378 $langs->load('stocks');
4379
4380 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4381 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4382 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4383 $sql .= " FROM " . $this->db->prefix() . "product as p";
4384 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4385 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4386 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4387 $sql .= " AND p.tobuy = 1";
4388 $sql .= " AND s.fournisseur = 1";
4389 $sql .= " AND p.rowid = " . ((int) $productid);
4390 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4391 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4392 } else {
4393 $sql .= " ORDER BY pfp.unitprice ASC";
4394 }
4395
4396 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4397 $result = $this->db->query($sql);
4398
4399 if ($result) {
4400 $num = $this->db->num_rows($result);
4401
4402 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4403
4404 if (!$num) {
4405 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4406 } else {
4407 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4408 $form .= '<option value="0">&nbsp;</option>';
4409
4410 $i = 0;
4411 while ($i < $num) {
4412 $objp = $this->db->fetch_object($result);
4413
4414 $opt = '<option value="' . $objp->idprodfournprice . '"';
4415 //if there is only one supplier, preselect it
4416 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4417 $opt .= ' selected';
4418 }
4419 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4420
4421 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4422 $prod_supplier = new ProductFournisseur($this->db);
4423 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4424 $prod_supplier->id = $productid;
4425 $prod_supplier->fourn_qty = $objp->quantity;
4426 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4427 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4428
4429 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4430 $priceparser = new PriceParser($this->db);
4431 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4432 if ($price_result >= 0) {
4433 $objp->fprice = $price_result;
4434 if ($objp->quantity >= 1) {
4435 $objp->unitprice = $objp->fprice / $objp->quantity;
4436 }
4437 }
4438 }
4439 if ($objp->quantity == 1) {
4440 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4441 }
4442
4443 $opt .= $objp->quantity . ' ';
4444
4445 if ($objp->quantity == 1) {
4446 $opt .= $langs->trans("Unit");
4447 } else {
4448 $opt .= $langs->trans("Units");
4449 }
4450 if ($objp->quantity > 1) {
4451 $opt .= " - ";
4452 $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");
4453 }
4454 if ($objp->duration) {
4455 $opt .= " - " . $objp->duration;
4456 }
4457 $opt .= "</option>\n";
4458
4459 $form .= $opt;
4460 $i++;
4461 }
4462 }
4463
4464 $form .= '</select>';
4465 $this->db->free($result);
4466 return $form;
4467 } else {
4468 dol_print_error($this->db);
4469 return '';
4470 }
4471 }
4472
4473
4474 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4481 {
4482 // phpcs:enable
4483 global $langs, $hookmanager;
4484
4485 $num = count($this->cache_conditions_paiements);
4486 if ($num > 0) {
4487 return 0; // Cache already loaded
4488 }
4489
4490 dol_syslog(__METHOD__, LOG_DEBUG);
4491
4492 $this->cache_conditions_paiements = array();
4493
4494 $sql = "SELECT rowid, code, libelle as label, deposit_percent, entity";
4495 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4496 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4497 $sql .= " AND active > 0";
4498 $sql .= " ORDER BY sortorder";
4499
4500 $resql = $this->db->query($sql);
4501 if ($resql) {
4502 $num = $this->db->num_rows($resql);
4503 $i = 0;
4504 while ($i < $num) {
4505 $obj = $this->db->fetch_object($resql);
4506
4507 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4508 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4509 $this->cache_conditions_paiements[$obj->rowid]['code'] = (string) $obj->code;
4510 $this->cache_conditions_paiements[$obj->rowid]['label'] = (string) $label;
4511 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = (string) $obj->deposit_percent;
4512 $this->cache_conditions_paiements[$obj->rowid]['entity'] = (int) $obj->entity;
4513 $i++;
4514 }
4515
4516 $parameters = array('context' => 'paymentterm');
4517 $reshook = $hookmanager->executeHooks('loadDictionaryCache', $parameters, $this); // Note that $action and $object may have been modified by hook
4518 if (empty($reshook)) {
4519 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
4520 $this->cache_conditions_paiements = array_merge($this->cache_conditions_paiements, $hookmanager->resArray);
4521 }
4522 } else {
4523 $this->cache_conditions_paiements = $hookmanager->resArray;
4524 }
4525
4526 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4527
4528 return $num;
4529 } else {
4530 dol_print_error($this->db);
4531 return -1;
4532 }
4533 }
4534
4535 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4536
4543 {
4544 // phpcs:enable
4545 $factureRec = new FactureRec($this->db);
4546
4547 $this->cache_rule_for_lines_dates = $factureRec->fields['rule_for_lines_dates']['arrayofkeyval'];
4548
4549 if (empty($this->cache_rule_for_lines_dates)) {
4550 return -1;
4551 }
4552
4553 return 1;
4554 }
4555
4556 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4557
4563 public function load_cache_availability()
4564 {
4565 // phpcs:enable
4566 global $langs;
4567
4568 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4569 if ($num > 0) {
4570 return 0; // Cache already loaded
4571 }
4572
4573 dol_syslog(__METHOD__, LOG_DEBUG);
4574
4575 $this->cache_availability = array();
4576
4577 $langs->load('propal');
4578
4579 $sql = "SELECT rowid, code, label, position";
4580 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4581 $sql .= " WHERE active > 0";
4582
4583 $resql = $this->db->query($sql);
4584 if ($resql) {
4585 $num = $this->db->num_rows($resql);
4586 $i = 0;
4587 while ($i < $num) {
4588 $obj = $this->db->fetch_object($resql);
4589
4590 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4591 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4592 $this->cache_availability[$obj->rowid]['code'] = (string) $obj->code;
4593 $this->cache_availability[$obj->rowid]['label'] = (string) $label;
4594 $this->cache_availability[$obj->rowid]['position'] = (int) $obj->position;
4595 $i++;
4596 }
4597
4598 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4599
4600 return $num;
4601 } else {
4602 dol_print_error($this->db);
4603 return -1;
4604 }
4605 }
4606
4617 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4618 {
4619 global $langs, $user;
4620
4621 $this->load_cache_availability();
4622
4623 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4624
4625 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4626 if ($addempty) {
4627 print '<option value="0">&nbsp;</option>';
4628 }
4629 foreach ($this->cache_availability as $id => $arrayavailability) {
4630 if ($selected == $id) {
4631 print '<option value="' . $id . '" selected>';
4632 } else {
4633 print '<option value="' . $id . '">';
4634 }
4635 print dol_escape_htmltag($arrayavailability['label']);
4636 print '</option>';
4637 }
4638 print '</select>';
4639 if ($user->admin) {
4640 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4641 }
4642 print ajax_combobox($htmlname);
4643 }
4644
4650 public function loadCacheInputReason()
4651 {
4652 global $langs;
4653
4654 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4655 if ($num > 0) {
4656 return 0; // Cache already loaded
4657 }
4658
4659 $sql = "SELECT rowid, code, label";
4660 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4661 $sql .= " WHERE active > 0";
4662
4663 $resql = $this->db->query($sql);
4664 if ($resql) {
4665 $num = $this->db->num_rows($resql);
4666 $i = 0;
4667 $tmparray = array();
4668 while ($i < $num) {
4669 $obj = $this->db->fetch_object($resql);
4670
4671 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4672 $label = ($obj->label != '-' ? $obj->label : '');
4673 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4674 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4675 }
4676 if ($langs->trans($obj->code) != $obj->code) {
4677 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4678 }
4679
4680 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4681 $tmparray[$obj->rowid]['code'] = $obj->code;
4682 $tmparray[$obj->rowid]['label'] = $label;
4683 $i++;
4684 }
4685
4686 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4687
4688 unset($tmparray);
4689 return $num;
4690 } else {
4691 dol_print_error($this->db);
4692 return -1;
4693 }
4694 }
4695
4708 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4709 {
4710 global $langs, $user;
4711
4712 $this->loadCacheInputReason();
4713
4714 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4715 if ($addempty) {
4716 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4717 }
4718 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4719 if ($arraydemandreason['code'] == $exclude) {
4720 continue;
4721 }
4722
4723 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4724 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4725 } else {
4726 print '<option value="' . $arraydemandreason['id'] . '">';
4727 }
4728 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4729 print $langs->trans($label);
4730 print '</option>';
4731 }
4732 print '</select>';
4733 if ($user->admin && empty($notooltip)) {
4734 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4735 }
4736 print ajax_combobox('select_' . $htmlname);
4737 }
4738
4739 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4740
4747 {
4748 // phpcs:enable
4749 global $langs, $hookmanager;
4750
4751 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4752 if ($num > 0) {
4753 return $num; // Cache already loaded
4754 }
4755
4756 dol_syslog(__METHOD__, LOG_DEBUG);
4757
4758 $this->cache_types_paiements = array();
4759
4760 $sql = "SELECT id, code, libelle as label, type, entity, active";
4761 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4762 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4763
4764 $resql = $this->db->query($sql);
4765 if ($resql) {
4766 $num = $this->db->num_rows($resql);
4767 $i = 0;
4768 while ($i < $num) {
4769 $obj = $this->db->fetch_object($resql);
4770
4771 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4772 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4773 $this->cache_types_paiements[$obj->id]['id'] = (int) $obj->id;
4774 $this->cache_types_paiements[$obj->id]['code'] = (string) $obj->code;
4775 $this->cache_types_paiements[$obj->id]['label'] = (string) $label;
4776 $this->cache_types_paiements[$obj->id]['type'] = (int) $obj->type;
4777 $this->cache_types_paiements[$obj->id]['entity'] = (int) $obj->entity;
4778 $this->cache_types_paiements[$obj->id]['active'] = (int) $obj->active;
4779 $i++;
4780 }
4781
4782 $parameters = array('context' => 'paymenttype');
4783 $reshook = $hookmanager->executeHooks('loadDictionaryCache', $parameters, $this); // Note that $action and $object may have been modified by hook
4784 if (empty($reshook)) {
4785 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
4786 $this->cache_types_paiements = array_merge($this->cache_types_paiements, $hookmanager->resArray);
4787 }
4788 } else {
4789 $this->cache_types_paiements = $hookmanager->resArray;
4790 }
4791
4792 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4793
4794 return $num;
4795 } else {
4796 dol_print_error($this->db);
4797 return -1;
4798 }
4799 }
4800
4801
4802 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4803
4822 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4823 {
4824 // phpcs:enable
4825 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4826 if (empty($noprint)) {
4827 print $out;
4828 } else {
4829 return $out;
4830 }
4831 }
4832
4833
4850 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4851 {
4852 global $langs, $user, $conf;
4853
4854 $out = '';
4855 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4856
4858
4859 // Set default value if not already set by caller
4860 if (empty($selected) && strpos($htmlname, 'search_') !== 0 && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4861 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4862 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4863 }
4864
4865 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4866 if ($addempty) {
4867 $out .= '<option value="0">&nbsp;</option>';
4868 }
4869
4870 $selectedDepositPercent = null;
4871
4872 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4873 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4874 continue;
4875 }
4876
4877 if ($selected == $id) {
4878 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4879 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4880 } else {
4881 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4882 }
4883 $label = $arrayconditions['label'];
4884
4885 if (!empty($arrayconditions['deposit_percent'])) {
4886 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4887 }
4888
4889 $out .= $label;
4890 $out .= '</option>';
4891 }
4892 $out .= '</select>';
4893 if ($user->admin && empty($noinfoadmin)) {
4894 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4895 }
4896 $out .= ajax_combobox($htmlname);
4897
4898 if ($deposit_percent >= 0) {
4899 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4900 $out .= $langs->trans('DepositPercent') . ' : ';
4901 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4902 $out .= '</span>';
4903 $out .= '
4904 <script nonce="' . getNonce() . '">
4905 $(document).ready(function () {
4906 $("#' . $htmlname . '").change(function () {
4907 let $selected = $(this).find("option:selected");
4908 let depositPercent = $selected.attr("data-deposit_percent");
4909
4910 if (depositPercent.length > 0) {
4911 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4912 } else {
4913 $("#' . $htmlname . '_deposit_percent_container").hide();
4914 }
4915
4916 return true;
4917 });
4918 });
4919 </script>';
4920 }
4921
4922 return $out;
4923 }
4924
4925
4934 public function getSelectRuleForLinesDates($selected = '', $htmlname = 'rule_for_lines_dates', $addempty = 0)
4935 {
4936 global $langs;
4937
4938 $out = '';
4939
4941
4942 $out .= '<select id="' . $htmlname . '" class="flat selectbillingterm" name="' . $htmlname . '">';
4943 if ($addempty) {
4944 $out .= '<option value="-1">&nbsp;</option>';
4945 }
4946
4947
4948 foreach ($this->cache_rule_for_lines_dates as $rule_for_lines_dates_key => $rule_for_lines_dates_name) {
4949 if ($selected == $rule_for_lines_dates_key) {
4950 $out .= '<option value="' . $rule_for_lines_dates_key . '" selected>';
4951 } else {
4952 $out .= '<option value="' . $rule_for_lines_dates_key . '">';
4953 }
4954
4955 $out .= $langs->trans($rule_for_lines_dates_name);
4956 $out .= '</option>';
4957 }
4958 $out .= '</select>';
4959
4960 $out .= ajax_combobox($htmlname);
4961
4962 return $out;
4963 }
4964
4965
4966 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4967
4984 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4985 {
4986 // phpcs:enable
4987 global $langs, $user, $conf;
4988
4989 $out = '';
4990
4991 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4992
4993 $filterarray = array();
4994 if ($filtertype == 'CRDT') {
4995 $filterarray = array(0, 2, 3);
4996 } elseif ($filtertype == 'DBIT') {
4997 $filterarray = array(1, 2, 3);
4998 } elseif ($filtertype != '' && $filtertype != '-1') {
4999 $filterarray = explode(',', $filtertype);
5000 }
5001
5003
5004 // Set default value if not already set by caller
5005 if (empty($selected) && strpos($htmlname, 'search_') !== 0 && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
5006 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
5007 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
5008 }
5009
5010 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
5011 if ($empty) {
5012 $out .= '<option value="">&nbsp;</option>';
5013 }
5014 foreach ($this->cache_types_paiements as $id => $arraytypes) {
5015 // If not good status
5016 if ($active >= 0 && $arraytypes['active'] != $active) {
5017 continue;
5018 }
5019
5020 // We skip of the user requested to filter on specific payment methods
5021 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
5022 continue;
5023 }
5024
5025 // We discard empty lines if showempty is on because an empty line has already been output.
5026 if ($empty && empty($arraytypes['code'])) {
5027 continue;
5028 }
5029
5030 if ($format == 0) {
5031 $out .= '<option value="' . $id . '" data-code="'.$arraytypes['code'].'"';
5032 } elseif ($format == 1) {
5033 $out .= '<option value="' . $arraytypes['code'] . '"';
5034 } elseif ($format == 2) {
5035 $out .= '<option value="' . $arraytypes['code'] . '"';
5036 } elseif ($format == 3) {
5037 $out .= '<option value="' . $id . '"';
5038 }
5039 // Print attribute selected or not
5040 if ($format == 1 || $format == 2) {
5041 if ($selected == $arraytypes['code']) {
5042 $out .= ' selected';
5043 }
5044 } else {
5045 if ($selected == $id) {
5046 $out .= ' selected';
5047 }
5048 }
5049 $out .= '>';
5050 $value = '';
5051 if ($format == 0) {
5052 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5053 } elseif ($format == 1) {
5054 $value = $arraytypes['code'];
5055 } elseif ($format == 2) {
5056 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5057 } elseif ($format == 3) {
5058 $value = $arraytypes['code'];
5059 }
5060 $out .= $value ? $value : '&nbsp;';
5061 $out .= '</option>';
5062 }
5063 $out .= '</select>';
5064 if ($user->admin && !$noadmininfo) {
5065 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5066 }
5067 $out .= ajax_combobox('select' . $htmlname);
5068
5069 if (empty($nooutput)) {
5070 print $out;
5071 } else {
5072 return $out;
5073 }
5074 }
5075
5076
5085 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
5086 {
5087 global $langs;
5088
5089 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
5090 $options = array(
5091 'HT' => $langs->trans("HT"),
5092 'TTC' => $langs->trans("TTC")
5093 );
5094 foreach ($options as $id => $value) {
5095 if ($selected == $id) {
5096 $return .= '<option value="' . $id . '" selected>' . $value;
5097 } else {
5098 $return .= '<option value="' . $id . '">' . $value;
5099 }
5100 $return .= '</option>';
5101 }
5102 $return .= '</select>';
5103 if ($addjscombo) {
5104 $return .= ajax_combobox('select_' . $htmlname);
5105 }
5106
5107 return $return;
5108 }
5109
5110 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5111
5118 {
5119 // phpcs:enable
5120 global $langs;
5121
5122 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
5123 if ($num > 0) {
5124 return $num; // Cache already loaded
5125 }
5126
5127 dol_syslog(__METHOD__, LOG_DEBUG);
5128
5129 $this->cache_transport_mode = array();
5130
5131 $sql = "SELECT rowid, code, label, active";
5132 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
5133 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
5134
5135 $resql = $this->db->query($sql);
5136 if ($resql) {
5137 $num = $this->db->num_rows($resql);
5138 $i = 0;
5139 while ($i < $num) {
5140 $obj = $this->db->fetch_object($resql);
5141
5142 // If traduction exist, we use it else we take the default label
5143 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
5144 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
5145 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
5146 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
5147 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
5148 $i++;
5149 }
5150
5151 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
5152
5153 return $num;
5154 } else {
5155 dol_print_error($this->db);
5156 return -1;
5157 }
5158 }
5159
5173 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
5174 {
5175 global $langs, $user;
5176
5177 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
5178
5180
5181 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
5182 if ($empty) {
5183 print '<option value="">&nbsp;</option>';
5184 }
5185 foreach ($this->cache_transport_mode as $id => $arraytypes) {
5186 // If not good status
5187 if ($active >= 0 && $arraytypes['active'] != $active) {
5188 continue;
5189 }
5190
5191 // We discard empty line if showempty is on because an empty line has already been output.
5192 if ($empty && empty($arraytypes['code'])) {
5193 continue;
5194 }
5195
5196 if ($format == 0) {
5197 print '<option value="' . $id . '"';
5198 } elseif ($format == 1) {
5199 print '<option value="' . $arraytypes['code'] . '"';
5200 } elseif ($format == 2) {
5201 print '<option value="' . $arraytypes['code'] . '"';
5202 } elseif ($format == 3) {
5203 print '<option value="' . $id . '"';
5204 }
5205 // If text is selected, we compare with code, else with id
5206 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
5207 print ' selected';
5208 } elseif ($selected == $id) {
5209 print ' selected';
5210 }
5211 print '>';
5212 $value = '';
5213 if ($format == 0) {
5214 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5215 } elseif ($format == 1) {
5216 $value = $arraytypes['code'];
5217 } elseif ($format == 2) {
5218 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
5219 } elseif ($format == 3) {
5220 $value = $arraytypes['code'];
5221 }
5222 print $value ? $value : '&nbsp;';
5223 print '</option>';
5224 }
5225 print '</select>';
5226
5227 print ajax_combobox("select".$htmlname);
5228
5229 if ($user->admin && !$noadmininfo) {
5230 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5231 }
5232 }
5233
5246 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
5247 {
5248 global $langs, $user;
5249
5250 $langs->load("admin");
5251 $langs->load("deliveries");
5252
5253 $sql = "SELECT rowid, code, libelle as label";
5254 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
5255 $sql .= " WHERE active > 0";
5256 if ($filtre) {
5257 $sql .= " AND " . $filtre;
5258 }
5259 $sql .= " ORDER BY libelle ASC";
5260
5261 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
5262 $result = $this->db->query($sql);
5263 if ($result) {
5264 $num = $this->db->num_rows($result);
5265 $i = 0;
5266 if ($num) {
5267 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5268 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5269 print '<option value="-1">&nbsp;</option>';
5270 }
5271 while ($i < $num) {
5272 $obj = $this->db->fetch_object($result);
5273 if ($selected == $obj->rowid) {
5274 print '<option value="' . $obj->rowid . '" selected>';
5275 } else {
5276 print '<option value="' . $obj->rowid . '">';
5277 }
5278 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
5279 print '</option>';
5280 $i++;
5281 }
5282 print "</select>";
5283 if ($user->admin && empty($noinfoadmin)) {
5284 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5285 }
5286
5287 print ajax_combobox('select' . $htmlname);
5288 } else {
5289 print $langs->trans("NoShippingMethodDefined");
5290 }
5291 } else {
5292 dol_print_error($this->db);
5293 }
5294 }
5295
5305 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
5306 {
5307 global $langs;
5308
5309 $langs->load("deliveries");
5310
5311 if ($htmlname != "none") {
5312 print '<form method="POST" action="' . $page . '">';
5313 print '<input type="hidden" name="action" value="setshippingmethod">';
5314 print '<input type="hidden" name="token" value="' . newToken() . '">';
5315 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5316 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5317 print '</form>';
5318 } else {
5319 if ($selected) {
5320 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5321 print $langs->trans("SendingMethod" . strtoupper($code));
5322 } else {
5323 print "&nbsp;";
5324 }
5325 }
5326 }
5327
5336 public function selectSituationInvoices($selected = '', $socid = 0)
5337 {
5338 global $langs;
5339
5340 $langs->load('bills');
5341
5342 $opt = '';
5343
5344 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5345 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5346 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5347 $sql .= ' AND situation_counter >= 1';
5348 $sql .= ' AND fk_soc = ' . (int) $socid;
5349 $sql .= ' AND type <> 2';
5350 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5351 $resql = $this->db->query($sql);
5352
5353 $nbSituationInvoiceForThirdparty = 0;
5354
5355 if ($resql && $this->db->num_rows($resql) > 0) {
5356 // Last seen cycle
5357 $ref = 0;
5358 while ($obj = $this->db->fetch_object($resql)) {
5359 //Same cycle ?
5360 if ($obj->situation_cycle_ref != $ref) {
5361 // Just seen this cycle
5362 $ref = $obj->situation_cycle_ref;
5363 //not final ?
5364 if ($obj->situation_final != 1) {
5365 //Not prov?
5366 if (substr($obj->ref, 1, 4) != 'PROV') {
5367 $nbSituationInvoiceForThirdparty++;
5368
5369 if ($selected == $obj->rowid) {
5370 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5371 } else {
5372 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5373 }
5374 }
5375 }
5376 }
5377 }
5378 } else {
5379 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5380 }
5381
5382 if ($nbSituationInvoiceForThirdparty > 0) {
5383 $opt = '<option class="minwidth100" value="" selected>&nbsp;</option>'.$opt;
5384 } else {
5385 $opt = '<option class="minwidth100" value="-1" selected>'.$langs->trans('NoSituations').'</option>';
5386 }
5387
5388 return $opt;
5389 }
5390
5400 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5401 {
5402 global $langs;
5403
5404 $langs->load('products');
5405
5406 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5407
5408 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5409 $sql .= ' WHERE active > 0';
5410 if (!empty($unit_type)) {
5411 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5412 }
5413 $sql .= " ORDER BY sortorder";
5414
5415 $resql = $this->db->query($sql);
5416 if ($resql && $this->db->num_rows($resql) > 0) {
5417 if ($showempty) {
5418 $return .= '<option value="-1"></option>';
5419 }
5420
5421 while ($res = $this->db->fetch_object($resql)) {
5422 $unitLabel = $res->label;
5423 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5424 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5425 }
5426
5427 if ($selected == $res->rowid) {
5428 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5429 } else {
5430 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5431 }
5432 }
5433 $return .= '</select>';
5434
5435 $return .= ajax_combobox($htmlname);
5436 }
5437 return $return;
5438 }
5439
5440 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5441
5456 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5457 {
5458 // phpcs:enable
5459 global $langs;
5460
5461 $out = '';
5462
5463 $langs->loadLangs(array("admin", "banks"));
5464 $num = 0;
5465
5466 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5467 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5468 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5469 if ($status != 2) {
5470 $sql .= " AND clos = " . (int) $status;
5471 }
5472 if ($filtre) { // TODO Support USF
5473 $sql .= " AND " . $filtre;
5474 }
5475 $sql .= " ORDER BY label";
5476
5477 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5478 $result = $this->db->query($sql);
5479 if ($result) {
5480 $num = $this->db->num_rows($result);
5481 $i = 0;
5482
5483 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5484
5485 if ($num == 0) {
5486 if ($status == 0) {
5487 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5488 } else {
5489 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5490 }
5491 } else {
5492 if (!empty($useempty) && !is_numeric($useempty)) {
5493 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5494 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5495 $out .= '<option value="-1">&nbsp;</option>';
5496 }
5497 }
5498
5499 while ($i < $num) {
5500 $obj = $this->db->fetch_object($result);
5501
5502 $labeltoshow = trim($obj->label);
5503 $labeltoshowhtml = trim($obj->label);
5504 if ($showcurrency) {
5505 $labeltoshow .= ' (' . $obj->currency_code . ')';
5506 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5507 }
5508 if ($status == 2 && $obj->status == 1) {
5509 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5510 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5511 }
5512
5513 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5514 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5515 } else {
5516 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5517 }
5518 $out .= $labeltoshow;
5519 $out .= '</option>';
5520 $i++;
5521 }
5522 $out .= "</select>";
5523 $out .= ajax_combobox('select' . $htmlname);
5524 } else {
5525 dol_print_error($this->db);
5526 }
5527
5528 // Output or return
5529 if (empty($nooutput)) {
5530 print $out;
5531 } else {
5532 return $out;
5533 }
5534
5535 return $num;
5536 }
5537
5551 public function selectRib($selected = '', $htmlname = 'ribcompanyid', $filtre = '', $useempty = 0, $moreattrib = '', $showibanbic = 0, $morecss = '', $nooutput = 0)
5552 {
5553 // phpcs:enable
5554 global $langs;
5555
5556 $out = '';
5557
5558 $langs->loadLangs(array("admin", "banks"));
5559 $num = 0;
5560
5561 $sql = "SELECT rowid, label, bank, status, iban_prefix, bic";
5562 $sql .= " FROM " . $this->db->prefix() . "societe_rib";
5563 $sql .= " WHERE type = 'ban'";
5564 if ($filtre) { // TODO Support USF
5565 $sql .= " AND " . $filtre;
5566 }
5567 $sql .= " ORDER BY label";
5568 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5569 $result = $this->db->query($sql);
5570 if ($result) {
5571 $num = $this->db->num_rows($result);
5572 $i = 0;
5573
5574 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5575
5576 if ($num == 0) {
5577 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5578 } else {
5579 if (!empty($useempty) && !is_numeric($useempty)) {
5580 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5581 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5582 $out .= '<option value="-1">&nbsp;</option>';
5583 }
5584 }
5585
5586 while ($i < $num) {
5587 $obj = $this->db->fetch_object($result);
5588 $iban = dolDecrypt($obj->iban_prefix);
5589 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5590 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '" selected>';
5591 } else {
5592 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '">';
5593 }
5594 $out .= trim($obj->label);
5595 if ($showibanbic) {
5596 $out .= ' (' . $iban . '/' .$obj->bic. ')';
5597 }
5598 $out .= '</option>';
5599 $i++;
5600 }
5601 $out .= "</select>";
5602 $out .= ajax_combobox('select' . $htmlname);
5603 } else {
5604 dol_print_error($this->db);
5605 }
5606
5607 // Output or return
5608 if (empty($nooutput)) {
5609 print $out;
5610 } else {
5611 return $out;
5612 }
5613
5614 return $num;
5615 }
5616
5628 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5629 {
5630 global $langs;
5631
5632 $langs->load("admin");
5633 $num = 0;
5634
5635 $sql = "SELECT rowid, name, fk_country, status, entity";
5636 $sql .= " FROM " . $this->db->prefix() . "establishment";
5637 $sql .= " WHERE 1=1";
5638 if ($status != 2) {
5639 $sql .= " AND status = " . (int) $status;
5640 }
5641 if ($filtre) { // TODO Support USF
5642 $sql .= " AND " . $filtre;
5643 }
5644 $sql .= " ORDER BY name";
5645
5646 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5647 $result = $this->db->query($sql);
5648 if ($result) {
5649 $num = $this->db->num_rows($result);
5650 $i = 0;
5651 if ($num) {
5652 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5653 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5654 print '<option value="-1">&nbsp;</option>';
5655 }
5656
5657 while ($i < $num) {
5658 $obj = $this->db->fetch_object($result);
5659 if ($selected == $obj->rowid) {
5660 print '<option value="' . $obj->rowid . '" selected>';
5661 } else {
5662 print '<option value="' . $obj->rowid . '">';
5663 }
5664 print trim($obj->name);
5665 if ($status == 2 && $obj->status == 1) {
5666 print ' (' . $langs->trans("Closed") . ')';
5667 }
5668 print '</option>';
5669 $i++;
5670 }
5671 print "</select>";
5672 } else {
5673 if ($status == 0) {
5674 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5675 } else {
5676 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5677 }
5678 }
5679
5680 return $num;
5681 } else {
5682 dol_print_error($this->db);
5683 return -1;
5684 }
5685 }
5686
5696 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5697 {
5698 global $langs;
5699 if ($htmlname != "none") {
5700 print '<form method="POST" action="' . $page . '">';
5701 print '<input type="hidden" name="action" value="setbankaccount">';
5702 print '<input type="hidden" name="token" value="' . newToken() . '">';
5703 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5704 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5705 if ($nbaccountfound > 0) {
5706 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5707 }
5708 print '</form>';
5709 } else {
5710 $langs->load('banks');
5711
5712 if ($selected) {
5713 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5714 $bankstatic = new Account($this->db);
5715 $result = $bankstatic->fetch((int) $selected);
5716 if ($result) {
5717 print $bankstatic->getNomUrl(1);
5718 }
5719 } else {
5720 print "&nbsp;";
5721 }
5722 }
5723 }
5724
5736 public function formRib($page, $selected = '', $htmlname = 'ribcompanyid', $filtre = '', $addempty = 0, $showibanbic = 0)
5737 {
5738 global $langs;
5739 if ($htmlname != "none") {
5740 print '<form method="POST" action="' . $page . '">';
5741 print '<input type="hidden" name="action" value="setbankaccountcustomer">';
5742 print '<input type="hidden" name="token" value="' . newToken() . '">';
5743 $nbaccountfound = $this->selectRib($selected, $htmlname, $filtre, $addempty, '', $showibanbic);
5744 if ($nbaccountfound > 0) {
5745 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5746 }
5747 print '</form>';
5748 } else {
5749 $langs->load('banks');
5750
5751 if ($selected) {
5752 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
5753 $bankstatic = new CompanyBankAccount($this->db);
5754 $result = $bankstatic->fetch((int) $selected);
5755 if ($result) {
5756 print $bankstatic->label;
5757 if ($showibanbic) {
5758 print ' (' . $bankstatic->iban . '/' .$bankstatic->bic. ')';
5759 }
5760 }
5761 } else {
5762 print "&nbsp;";
5763 }
5764 }
5765 }
5766
5767 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5768
5778 public function selectCategories($categtype, $htmlname, $object = null)
5779 {
5780 global $langs;
5781
5782 $out = '';
5783
5784 $cate_arbo = $this->select_all_categories($categtype, '', '', 64, 0, 3);
5785
5786 $arrayselected = array();
5787 if (GETPOSTISARRAY($htmlname)) {
5788 $arrayselected = GETPOST($htmlname, 'array:int');
5789 } elseif (is_object($object) && $object->id > 0) {
5790 $c = new Categorie($this->db);
5791 $cats = $c->containing($object->id, $categtype);
5792 $arrayselected = array();
5793 foreach ($cats as $cat) {
5794 $arrayselected[] = $cat->id;
5795 }
5796 }
5797
5798 $out .= img_picto('', 'category', 'class="pictofixedwidth"');
5799 $out .= $this->multiselectarray($htmlname, $cate_arbo, $arrayselected, 0, 0, 'minwidth100 widthcentpercentminusxx', 0, 0);
5800
5801 if (!getDolGlobalString('CATEGORY_EDIT_IN_MENU_NOT_IN_POPUP')) {
5802 // Add html code to add the edit button and go back
5803 $jsonclose = 'doJsCodeAfterPopupClose'.$htmlname.'()';
5804 $urltoopen = '/categories/categorie_list.php?type='.urlencode($categtype).'&nosearch=1';
5805
5806 $s = dolButtonToOpenUrlInDialogPopup($htmlname, $langs->transnoentitiesnoconv("Categories"), img_picto('', 'add', 'class="editfielda"'), $urltoopen, '', '', '', $jsonclose);
5807 $out .= $s;
5808 // Add js code to add the edit button and go back
5809 $out .= '<!-- Add js code to open the popup for category/edit/add -->'."\n";
5810 $out .= '<script>function doJsCodeAfterPopupClose'.$htmlname.'() {
5811 console.log("doJsCodeAfterPopupClose'.$htmlname.' has been called, we refresh the combo content + refresh select2...");
5812
5813 // Call an ajax to reload values and update the select
5814 // $("#'.dol_escape_js($htmlname).'").append(new Option("Option 4", "4"));
5815
5816 // Refresh select2 to take account of new values (enough for small change)
5817
5818 $.ajax({
5819 url: \''.DOL_URL_ROOT.'/core/ajax/fetchCategories.php\',
5820 data: {
5821 action: \'getCategories\',
5822 type: \''.dol_escape_htmltag($categtype).'\'
5823 },
5824 type: \'GET\',
5825 dataType: \'json\',
5826 success: function (data) {
5827 var $select = $(\'#'.dol_escape_js($htmlname).'\');
5828 var selectedValues = $select.val(); // This is an array of selected values
5829 console.log(selectedValues);
5830 $select.empty();
5831 $.each(data, function (index, item) {
5832 $select.append(\'<option value="\' + item.id + \'" data-html="\' + item.htmlforattribute + \'">\' + item.htmlforoption + \'</option>\');
5833 });
5834 $select.val(selectedValues);
5835 },
5836 error: function (xhr, status, error) {
5837 console.log("Error when loading ajax page : " + error);
5838 }
5839 });
5840
5841 $("#'.dol_escape_js($htmlname).'").trigger("change");
5842 // Alternative if change in select is complex
5843 /*
5844 $("#'.dol_escape_js($htmlname).'").select2("destroy");
5845 $("#'.dol_escape_js($htmlname).'").select2();
5846 */
5847 }</script>';
5848 }
5849
5850 return $out;
5851 }
5852
5853
5873 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5874 {
5875 // phpcs:enable
5876 global $langs;
5877
5878 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5879
5880 $cat = new Categorie($this->db);
5881
5882 if (is_numeric($type)) {
5883 $type = array_search($type, $cat->MAP_ID); // For backward compatibility
5884 }
5885
5886 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5887
5888 $outarray = array();
5889 $outarrayrichhtml = array();
5890
5891
5892 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5893 if (is_array($cate_arbo)) {
5894 $num = count($cate_arbo);
5895
5896 if (!$num) {
5897 $langs->load("categories");
5898 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5899 } else {
5900 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5901 $output .= '<option value="-1">&nbsp;</option>';
5902 }
5903 foreach ($cate_arbo as $key => $value) {
5904 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5905 $add = 'selected ';
5906 } else {
5907 $add = '';
5908 }
5909
5910 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth"'.(empty($cate_arbo[$key]['color']) ? '' : ' style="color: #' . $cate_arbo[$key]['color'] . '"'));
5911 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5912
5913 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5914
5915 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5916
5917 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5918 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5919 $output .= '>';
5920 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5921 $output .= '</option>';
5922
5923 $cate_arbo[$key]['data-html'] = $labeltoshow;
5924 }
5925 }
5926 }
5927 $output .= '</select>';
5928 $output .= "\n";
5929
5930 $this->num = count($cate_arbo);
5931
5932 if ($outputmode == 2) {
5933 // TODO: handle error when $cate_arbo is not an array
5934 return $cate_arbo;
5935 } elseif ($outputmode == 1) {
5936 return $outarray;
5937 } elseif ($outputmode == 3) {
5938 return $outarrayrichhtml;
5939 }
5940 return $output;
5941 }
5942
5943 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5944
5963 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5964 {
5965 // phpcs:enable
5966 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5967 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5968 }
5969
5996 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5997 {
5998 global $langs, $conf;
5999
6000 $more = '';
6001 $formconfirm = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
6002
6003 $inputok = array();
6004 $inputko = array();
6005
6006 // Clean parameters
6007 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
6008 if ($conf->browser->layout == 'phone') {
6009 $width = '95%';
6010 }
6011
6012 // Set height automatically if not defined
6013 if (empty($height)) {
6014 $height = 250;
6015 if (is_array($formquestion) && count($formquestion) > 2) {
6016 $height += ((count($formquestion) - 2) * 24);
6017 }
6018 }
6019
6020 if (is_array($formquestion) && !empty($formquestion)) {
6021 // First add hidden fields and value
6022 foreach ($formquestion as $key => $input) {
6023 if (is_array($input) && !empty($input)) {
6024 if ($input['type'] == 'hidden') {
6025 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
6026 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
6027
6028 $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";
6029 }
6030 }
6031 }
6032
6033 // Now add questions
6034 $moreonecolumn = '';
6035 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
6036 foreach ($formquestion as $key => $input) {
6037 if (is_array($input) && !empty($input)) {
6038 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
6039 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
6040 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
6041
6042 if ($input['type'] == 'text' || $input['type'] == 'input') { // traditional input
6043 $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";
6044 } elseif ($input['type'] == 'password') {
6045 $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";
6046 } elseif ($input['type'] == 'textarea') {
6047 $moreonecolumn .= '<div class="margintoponly">';
6048 $moreonecolumn .= $input['label'] . '<br>';
6049 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
6050 $moreonecolumn .= $input['value'];
6051 $moreonecolumn .= '</textarea>';
6052 $moreonecolumn .= '</div>';
6053 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
6054 if (empty($morecss)) {
6055 $morecss = 'minwidth100';
6056 }
6057
6058 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
6059 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
6060 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
6061 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
6062 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
6063 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
6064 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
6065
6066 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
6067 if (!empty($input['label'])) {
6068 $more .= $input['label'] . '</div><div class="tagtd left">';
6069 }
6070 if ($input['type'] == 'select') {
6071 $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);
6072 } else {
6073 $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);
6074 }
6075 $more .= '</div></div>' . "\n";
6076 } elseif ($input['type'] == 'checkbox') {
6077 $more .= '<div class="tagtr">';
6078 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
6079 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
6080 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
6081 $more .= ' checked';
6082 }
6083 if (is_bool($input['value']) && $input['value']) {
6084 $more .= ' checked';
6085 }
6086 if (isset($input['disabled'])) {
6087 $more .= ' disabled';
6088 }
6089 $more .= ' /></div>';
6090 $more .= '</div>' . "\n";
6091 } elseif ($input['type'] == 'radio') {
6092 $i = 0;
6093 foreach ($input['values'] as $selkey => $selval) {
6094 $more .= '<div class="tagtr">';
6095 if (isset($input['label'])) {
6096 if ($i == 0) {
6097 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
6098 } else {
6099 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
6100 }
6101 }
6102 $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;
6103 if (!empty($input['disabled'])) {
6104 $more .= ' disabled';
6105 }
6106 if (isset($input['default']) && $input['default'] === $selkey) {
6107 $more .= ' checked="checked"';
6108 }
6109 $more .= ' /> ';
6110 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
6111 $more .= '</div></div>' . "\n";
6112 $i++;
6113 }
6114 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
6115 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
6116 $more .= '<div class="tagtd">';
6117 $addnowlink = (empty($input['datenow']) ? 0 : 1);
6118 $h = $m = 0;
6119 if ($input['type'] == 'datetime') {
6120 $h = isset($input['hours']) ? $input['hours'] : 1;
6121 $m = isset($input['minutes']) ? $input['minutes'] : 1;
6122 }
6123 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
6124 $more .= '</div></div>'."\n";
6125 $formquestion[] = array('name' => $input['name'].'day');
6126 $formquestion[] = array('name' => $input['name'].'month');
6127 $formquestion[] = array('name' => $input['name'].'year');
6128 $formquestion[] = array('name' => $input['name'].'hour');
6129 $formquestion[] = array('name' => $input['name'].'min');
6130 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
6131 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
6132 if (!empty($input['label'])) {
6133 $more .= $input['label'] . '</div><div class="tagtd">';
6134 }
6135 if (!empty($input['value'])) {
6136 $more .= $input['value'];
6137 }
6138 $more .= '</div></div>' . "\n";
6139 } elseif ($input['type'] == 'onecolumn') {
6140 $moreonecolumn .= '<div class="margintoponly">';
6141 $moreonecolumn .= $input['value'];
6142 $moreonecolumn .= '</div>' . "\n";
6143 } elseif ($input['type'] == 'hidden') {
6144 // Do nothing more, already added by a previous loop
6145 } elseif ($input['type'] == 'separator') {
6146 $more .= '<br>';
6147 } else {
6148 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
6149 }
6150 }
6151 }
6152 $more .= '</div>' . "\n";
6153 $more .= $moreonecolumn;
6154 }
6155
6156 // JQUERY method dialog is broken with smartphone, we use standard HTML.
6157 // 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
6158 // See page product/card.php for example
6159 if (!empty($conf->dol_use_jmobile)) {
6160 $useajax = 0;
6161 }
6162 if (empty($conf->use_javascript_ajax)) {
6163 $useajax = 0;
6164 }
6165
6166 if ($useajax) {
6167 $autoOpen = true;
6168 $dialogconfirm = 'dialog-confirm';
6169 $button = '';
6170 if (!is_numeric($useajax)) {
6171 $button = $useajax;
6172 $useajax = 1;
6173 $autoOpen = false;
6174 $dialogconfirm .= '-' . $button;
6175 }
6176 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
6177 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
6178
6179 // Add input fields into list of fields to read during submit (inputok and inputko)
6180 if (is_array($formquestion)) {
6181 foreach ($formquestion as $key => $input) {
6182 //print "xx ".$key." rr ".is_array($input)."<br>\n";
6183 // Add name of fields to propagate with the GET when submitting the form with button OK.
6184 if (is_array($input) && isset($input['name'])) {
6185 if (strpos($input['name'], ',') > 0) {
6186 $inputok = array_merge($inputok, explode(',', $input['name']));
6187 } else {
6188 array_push($inputok, $input['name']);
6189 }
6190 }
6191 // Add name of fields to propagate with the GET when submitting the form with button KO.
6192 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
6193 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
6194 array_push($inputko, $input['name']);
6195 }
6196 }
6197 }
6198
6199 // Show JQuery confirm box.
6200 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
6201 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
6202 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
6203 }
6204 if (!empty($more)) {
6205 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
6206 }
6207 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
6208 $formconfirm .= '</div>' . "\n";
6209
6210 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
6211 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6212 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
6213 $formconfirm .= 'jQuery(document).ready(function() {
6214 $(function() {
6215 $( "#' . $dialogconfirm . '" ).dialog(
6216 {
6217 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
6218 if ($newselectedchoice == 'no') {
6219 $formconfirm .= '
6220 open: function() {
6221 $(this).parent().find("button.ui-button:eq(2)").focus();
6222 },';
6223 }
6224
6225 $jsforcursor = '';
6226 if ($useajax == 1) {
6227 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
6228 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
6229 }
6230
6231 $postconfirmas = 'GET';
6232
6233 $formconfirm .= '
6234 resizable: false,
6235 height: \'' . dol_escape_js($height) . '\',
6236 width: \'' . dol_escape_js($width) . '\',
6237 modal: true,
6238 closeOnEscape: false,
6239 buttons: {
6240 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
6241 var options = "token=' . urlencode(newToken()) . '";
6242 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
6243 var page = \'' . dol_escape_js(!empty($page) ? $page : '') . '\';
6244 var pageyes = \'' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '\';
6245
6246 if (inputok.length > 0) {
6247 $.each(inputok, function(i, inputname) {
6248 var more = "";
6249 var inputvalue;
6250 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
6251 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
6252 } else {
6253 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
6254 inputvalue = $("#" + inputname + more).val();
6255 }
6256 if (typeof inputvalue == "undefined") { inputvalue=""; }
6257 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
6258 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
6259 });
6260 }
6261 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
6262 if (pageyes.length > 0) {';
6263 if ($postconfirmas == 'GET') {
6264 $formconfirm .= 'location.href = urljump;';
6265 } else {
6266 $formconfirm .= $jsforcursor;
6267 $formconfirm .= 'var post = $.post(
6268 pageyes,
6269 options,
6270 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
6271 );';
6272 }
6273 $formconfirm .= '
6274 console.log("after post ok");
6275 }
6276 $(this).dialog("close");
6277 },
6278 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
6279 var options = "token=' . urlencode(newToken()) . '";
6280 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
6281 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
6282 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
6283 if (inputko.length > 0) {
6284 $.each(inputko, function(i, inputname) {
6285 var more = "";
6286 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
6287 var inputvalue = $("#" + inputname + more).val();
6288 if (typeof inputvalue == "undefined") { inputvalue=""; }
6289 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
6290 });
6291 }
6292 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
6293 //alert(urljump);
6294 if (pageno.length > 0) {';
6295 if ($postconfirmas == 'GET') {
6296 $formconfirm .= 'location.href = urljump;';
6297 } else {
6298 $formconfirm .= $jsforcursor;
6299 $formconfirm .= 'var post = $.post(
6300 pageno,
6301 options,
6302 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
6303 );';
6304 }
6305 $formconfirm .= '
6306 console.log("after post ko");
6307 }
6308 $(this).dialog("close");
6309 }
6310 }
6311 }
6312 );
6313
6314 var button = "' . $button . '";
6315 if (button.length > 0) {
6316 $( "#" + button ).click(function() {
6317 $("#' . $dialogconfirm . '").dialog("open");
6318 });
6319 }
6320 });
6321 });
6322 </script>';
6323 $formconfirm .= "<!-- end ajax formconfirm -->\n";
6324 } else {
6325 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
6326
6327 if (empty($disableformtag)) {
6328 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
6329 }
6330
6331 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
6332 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
6333
6334 $formconfirm .= '<table class="valid centpercent">' . "\n";
6335
6336 // Line title
6337 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
6338 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
6339 $formconfirm .= '</td></tr>' . "\n";
6340
6341 // Line text
6342 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
6343 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
6344 }
6345
6346 // Line form fields
6347 if ($more) {
6348 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
6349 $formconfirm .= $more;
6350 $formconfirm .= '</td></tr>' . "\n";
6351 }
6352
6353 // Line with question
6354 $formconfirm .= '<tr class="valid">';
6355 $formconfirm .= '<td class="valid">' . $question . '</td>';
6356 $formconfirm .= '<td class="valid center">';
6357 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
6358 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
6359 $formconfirm .= '</td>';
6360 $formconfirm .= '</tr>' . "\n";
6361
6362 $formconfirm .= '</table>' . "\n";
6363
6364 if (empty($disableformtag)) {
6365 $formconfirm .= "</form>\n";
6366 }
6367 $formconfirm .= '<br>';
6368
6369 if (!empty($conf->use_javascript_ajax)) {
6370 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
6371 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6372 $formconfirm .= '
6373 $(document).ready(function () {
6374 $(".confirmvalidatebutton").on("click", function() {
6375 console.log("We click on button confirmvalidatebutton");
6376 $(this).attr("disabled", "disabled");
6377 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
6378 //console.log($(this).closest("form"));
6379 $(this).closest("form").submit();
6380 });
6381 });
6382 ';
6383 $formconfirm .= '</script>' . "\n";
6384 }
6385
6386 $formconfirm .= "<!-- end formconfirm -->\n";
6387 }
6388
6389 return $formconfirm;
6390 }
6391
6392
6393 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6394
6410 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
6411 {
6412 // phpcs:enable
6413 global $langs;
6414
6415 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
6416 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
6417
6418 $out = '';
6419
6420 $formproject = new FormProjets($this->db);
6421
6422 $langs->load("project");
6423 if ($htmlname != "none") {
6424 $out .= '<form method="post" action="' . $page . '">';
6425 $out .= '<input type="hidden" name="action" value="classin">';
6426 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6427 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
6428 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6429 $out .= '</form>';
6430 } else {
6431 $out .= '<span class="project_head_block">';
6432 if ($selected) {
6433 $projet = new Project($this->db);
6434 $projet->fetch((int) $selected);
6435 $out .= $projet->getNomUrl(0, '', 1);
6436 } else {
6437 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
6438 }
6439 $out .= '</span>';
6440 }
6441
6442 if (empty($nooutput)) {
6443 print $out;
6444 return '';
6445 }
6446 return $out;
6447 }
6448
6449 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6450
6466 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
6467 {
6468 // phpcs:enable
6469 global $langs;
6470
6471 $out = '';
6472
6473 if ($htmlname != "none") {
6474 $out .= '<form method="POST" action="' . $page . '">';
6475 $out .= '<input type="hidden" name="action" value="setconditions">';
6476 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6477 if ($type) {
6478 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6479 }
6480 $out .= $this->getSelectConditionsPaiements((int) $selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6481 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6482 $out .= '</form>';
6483 } else {
6484 if ($selected) {
6485 $this->load_cache_conditions_paiements();
6486 if (isset($this->cache_conditions_paiements[$selected])) {
6487 $label = $this->cache_conditions_paiements[$selected]['label'];
6488
6489 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6490 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6491 }
6492
6493 $out .= $label;
6494 } else {
6495 $langs->load('errors');
6496 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6497 }
6498 } else {
6499 $out .= '&nbsp;';
6500 }
6501 }
6502
6503 if (empty($nooutput)) {
6504 print $out;
6505 return '';
6506 }
6507 return $out;
6508 }
6509
6510 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6511
6522 public function form_rule_for_lines_dates($page, $selected = '', $htmlname = 'rule_for_lines_dates', $addempty = 0, $nooutput = 0): string
6523 {
6524 global $langs;
6525
6526 $out = '';
6527
6528 if ($htmlname != 'none') {
6529 $out .= '<form method="POST" action="' . $page . '">';
6530 $out .= '<input type="hidden" name="action" value="setruleforlinesdates">';
6531 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6532 $out .= $this->getSelectRuleForLinesDates($selected, $htmlname, $addempty);
6533 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6534 $out .= '</form>';
6535 } else {
6536 if (isset($selected)) {
6537 $this->load_cache_rule_for_lines_dates();
6538 if (isset($this->cache_rule_for_lines_dates[$selected])) {
6539 $label = $this->cache_rule_for_lines_dates[$selected];
6540 $out .= $langs->trans($label);
6541 }
6542 } else {
6543 $out .= '&nbsp;';
6544 }
6545 }
6546
6547 if (empty($nooutput)) {
6548 print $out;
6549 return '';
6550 }
6551
6552 return $out;
6553 }
6554
6555 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6556
6566 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
6567 {
6568 // phpcs:enable
6569 global $langs;
6570 if ($htmlname != "none") {
6571 print '<form method="post" action="' . $page . '">';
6572 print '<input type="hidden" name="action" value="setavailability">';
6573 print '<input type="hidden" name="token" value="' . newToken() . '">';
6574 $this->selectAvailabilityDelay($selected, $htmlname, '', $addempty);
6575 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6576 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
6577 print '</form>';
6578 } else {
6579 if ($selected) {
6580 $this->load_cache_availability();
6581 print $this->cache_availability[$selected]['label'];
6582 } else {
6583 print "&nbsp;";
6584 }
6585 }
6586 }
6587
6598 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
6599 {
6600 global $langs;
6601 if ($htmlname != "none") {
6602 print '<form method="post" action="' . $page . '">';
6603 print '<input type="hidden" name="action" value="setdemandreason">';
6604 print '<input type="hidden" name="token" value="' . newToken() . '">';
6605 $this->selectInputReason($selected, $htmlname, '-1', $addempty);
6606 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6607 print '</form>';
6608 } else {
6609 if ($selected) {
6610 $this->loadCacheInputReason();
6611 foreach ($this->cache_demand_reason as $key => $val) {
6612 if ($val['id'] == $selected) {
6613 print $val['label'];
6614 break;
6615 }
6616 }
6617 } else {
6618 print "&nbsp;";
6619 }
6620 }
6621 }
6622
6623 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6624
6638 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6639 {
6640 // phpcs:enable
6641 global $langs;
6642
6643 $ret = '';
6644
6645 if ($htmlname != "none") {
6646 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6647 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6648 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6649 if ($type) {
6650 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6651 }
6652 $ret .= '<table class="nobordernopadding">';
6653 $ret .= '<tr><td>';
6654 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6655 $ret .= '</td>';
6656 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6657 $ret .= '</tr></table></form>';
6658 } else {
6659 if ($displayhour) {
6660 $ret .= dol_print_date($selected, 'dayhour');
6661 } else {
6662 $ret .= dol_print_date($selected, 'day');
6663 }
6664 }
6665
6666 if (empty($nooutput)) {
6667 print $ret;
6668 }
6669 return $ret;
6670 }
6671
6672
6673 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6674
6685 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6686 {
6687 // phpcs:enable
6688 global $langs;
6689
6690 if ($htmlname != "none") {
6691 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6692 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6693 print '<input type="hidden" name="token" value="' . newToken() . '">';
6694 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6695 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6696 print '</form>';
6697 } else {
6698 if ($selected) {
6699 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6700 $theuser = new User($this->db);
6701 $theuser->fetch((int) $selected);
6702 print $theuser->getNomUrl(1);
6703 } else {
6704 print "&nbsp;";
6705 }
6706 }
6707 }
6708
6709
6710 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6711
6725 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6726 {
6727 // phpcs:enable
6728 global $langs;
6729
6730 $out = '';
6731 if ($htmlname != "none") {
6732 $out .= '<form method="POST" action="' . $page . '">';
6733 $out .= '<input type="hidden" name="action" value="setmode">';
6734 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6735 if ($type) {
6736 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6737 }
6738 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6739 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6740 $out .= '</form>';
6741 } else {
6742 if ($selected) {
6743 $this->load_cache_types_paiements();
6744 $out .= $this->cache_types_paiements[$selected]['label'];
6745 } else {
6746 $out .= "&nbsp;";
6747 }
6748 }
6749
6750 if ($nooutput) {
6751 return $out;
6752 } else {
6753 print $out;
6754 }
6755 return '';
6756 }
6757
6768 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6769 {
6770 global $langs;
6771 if ($htmlname != "none") {
6772 print '<form method="POST" action="' . $page . '">';
6773 print '<input type="hidden" name="action" value="settransportmode">';
6774 print '<input type="hidden" name="token" value="' . newToken() . '">';
6775 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6776 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6777 print '</form>';
6778 } else {
6779 if ($selected) {
6780 $this->load_cache_transport_mode();
6781 print $this->cache_transport_mode[$selected]['label'];
6782 } else {
6783 print "&nbsp;";
6784 }
6785 }
6786 }
6787
6788 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6789
6798 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6799 {
6800 // phpcs:enable
6801 global $langs;
6802 if ($htmlname != "none") {
6803 print '<form method="POST" action="' . $page . '">';
6804 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6805 print '<input type="hidden" name="token" value="' . newToken() . '">';
6806 print $this->selectMultiCurrency($selected, $htmlname, 0);
6807 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6808 print '</form>';
6809 } else {
6810 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6811 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6812 }
6813 }
6814
6815 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6816
6826 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6827 {
6828 // phpcs:enable
6829 global $langs, $conf;
6830
6831 if ($htmlname != "none") {
6832 print '<form method="POST" action="' . $page . '">';
6833 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6834 print '<input type="hidden" name="token" value="' . newToken() . '">';
6835 print '<input type="text" class="maxwidth75" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6836 print '<select name="calculation_mode" id="calculation_mode">';
6837 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6838 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6839 print '</select> ';
6840 print ajax_combobox("calculation_mode");
6841 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6842 print '</form>';
6843 } else {
6844 if (!empty($rate)) {
6845 print price($rate, 1, $langs, 0, 0);
6846 if ($currency && $rate != 1) {
6847 print ' &nbsp; <span class="opacitymedium">(' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')</span>';
6848 }
6849 } else {
6850 print 1;
6851 }
6852 }
6853 }
6854
6855 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6856
6872 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6873 {
6874 // phpcs:enable
6875 global $conf, $langs;
6876
6877 if ($htmlname != "none") {
6878 print '<form method="post" action="' . $page . '">';
6879 print '<input type="hidden" name="action" value="setabsolutediscount">';
6880 print '<input type="hidden" name="token" value="' . newToken() . '">';
6881 print '<div class="inline-block">';
6882 if (!empty($discount_type)) {
6883 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6884 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6885 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6886 } else {
6887 $translationKey = 'HasCreditNoteFromSupplier';
6888 }
6889 } else {
6890 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6891 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6892 } else {
6893 $translationKey = 'HasCreditNoteFromSupplier';
6894 }
6895 }
6896 } else {
6897 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6898 if (!$filter || $filter == "fk_facture_source IS NULL") {
6899 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6900 } else {
6901 $translationKey = 'CompanyHasCreditNote';
6902 }
6903 } else {
6904 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6905 $translationKey = 'CompanyHasAbsoluteDiscount';
6906 } else {
6907 $translationKey = 'CompanyHasCreditNote';
6908 }
6909 }
6910 }
6911 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6912 if (empty($hidelist)) {
6913 print ' ';
6914 }
6915 print '</div>';
6916 if (empty($hidelist)) {
6917 print '<div class="inline-block" style="padding-right: 10px">';
6918 $newfilter = 'discount_type=' . intval($discount_type);
6919 if (!empty($discount_type)) {
6920 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6921 } else {
6922 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6923 }
6924 if ($filter) {
6925 $newfilter .= ' AND (' . $filter . ')';
6926 }
6927 // output the combo of discounts
6928 $nbqualifiedlines = $this->select_remises((string) $selected, $htmlname, $newfilter, $socid, $maxvalue);
6929 if ($nbqualifiedlines > 0) {
6930 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6931 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6932 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6933 }
6934 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6935 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6936 }
6937
6938 print '>';
6939 }
6940 print '</div>';
6941 }
6942 if ($more) {
6943 print '<div class="inline-block">';
6944 print $more;
6945 print '</div>';
6946 }
6947 print '</form>';
6948 } else {
6949 if ($selected) {
6950 print $selected;
6951 } else {
6952 print "0";
6953 }
6954 }
6955 }
6956
6957
6958 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6959
6969 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6970 {
6971 // phpcs:enable
6972 global $langs;
6973
6974 if ($htmlname != "none") {
6975 print '<form method="post" action="' . $page . '">';
6976 print '<input type="hidden" name="action" value="set_contact">';
6977 print '<input type="hidden" name="token" value="' . newToken() . '">';
6978 print '<table class="nobordernopadding">';
6979 print '<tr><td>';
6980 print $this->selectcontacts($societe->id, $selected, $htmlname);
6981 $num = $this->num;
6982 if ($num == 0) {
6983 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6984 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&action=create&backtoreferer=1">' . $addcontact . '</a>';
6985 }
6986 print '</td>';
6987 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6988 print '</tr></table></form>';
6989 } else {
6990 if ($selected) {
6991 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6992 $contact = new Contact($this->db);
6993 $contact->fetch((int) $selected);
6994 print $contact->getFullName($langs);
6995 } else {
6996 print "&nbsp;";
6997 }
6998 }
6999 }
7000
7001 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7002
7019 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
7020 {
7021 // phpcs:enable
7022 global $langs;
7023
7024 $out = '';
7025 if ($htmlname != "none") {
7026 $out .= '<form method="post" action="' . $page . '">';
7027 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
7028 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
7029 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
7030 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
7031 $out .= '</form>';
7032 } else {
7033 if ($selected) {
7034 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
7035 $soc = new Societe($this->db);
7036 $soc->fetch((int) $selected);
7037 $out .= $soc->getNomUrl(0, '');
7038 } else {
7039 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
7040 }
7041 }
7042
7043 if ($nooutput) {
7044 return $out;
7045 } else {
7046 print $out;
7047 }
7048
7049 return '';
7050 }
7051
7052 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7053
7062 public function select_currency($selected = '', $htmlname = 'currency_id')
7063 {
7064 // phpcs:enable
7065 print $this->selectCurrency($selected, $htmlname);
7066 }
7067
7077 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
7078 {
7079 global $langs, $user;
7080
7081 $langs->loadCacheCurrencies('');
7082
7083 $out = '';
7084
7085 if ($selected == 'euro' || $selected == 'euros') {
7086 $selected = 'EUR'; // Pour compatibilite
7087 }
7088
7089 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
7090 if ($useempty) {
7091 $out .= '<option value="-1" selected></option>';
7092 }
7093 foreach ($langs->cache_currencies as $code_iso => $currency) {
7094 $labeltoshow = $currency['label'];
7095 if ($mode == 1) {
7096 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
7097 } else {
7098 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
7099 }
7100
7101 if ($selected && $selected == $code_iso) {
7102 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
7103 } else {
7104 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
7105 }
7106 $out .= dol_string_nohtmltag($labeltoshow);
7107 $out .= '</option>';
7108 }
7109 $out .= '</select>';
7110 if ($user->admin) {
7111 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
7112 }
7113
7114 // Make select dynamic
7115 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7116 $out .= ajax_combobox($htmlname);
7117
7118 return $out;
7119 }
7120
7133 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = 'maxwidth200 widthcentpercentminusx')
7134 {
7135 global $conf, $langs;
7136
7137 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
7138
7139 $TCurrency = array();
7140
7141 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
7142 $sql .= " WHERE entity IN ('" . getEntity('multicurrency') . "')";
7143 if ($filter) {
7144 $sql .= " AND " . $filter;
7145 }
7146 $resql = $this->db->query($sql);
7147 if ($resql) {
7148 while ($obj = $this->db->fetch_object($resql)) {
7149 $TCurrency[$obj->code] = $obj->code;
7150 }
7151 }
7152
7153 $out = '';
7154 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7155 if ($useempty) {
7156 $out .= '<option value="">&nbsp;</option>';
7157 }
7158 // If company current currency not in table, we add it into list. Should always be available.
7159 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
7160 $TCurrency[$conf->currency] = $conf->currency;
7161 }
7162 if (count($TCurrency) > 0) {
7163 foreach ($langs->cache_currencies as $code_iso => $currency) {
7164 if (isset($TCurrency[$code_iso])) {
7165 if (!empty($selected) && $selected == $code_iso) {
7166 $out .= '<option value="' . $code_iso . '" selected="selected">';
7167 } else {
7168 $out .= '<option value="' . $code_iso . '">';
7169 }
7170
7171 $out .= $currency['label'];
7172 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
7173 $out .= '</option>';
7174 }
7175 }
7176 }
7177
7178 $out .= '</select>';
7179
7180 // Make select dynamic
7181 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7182 $out .= ajax_combobox($htmlname);
7183
7184 return $out;
7185 }
7186
7187 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7188
7195 public function load_cache_vatrates($country_code)
7196 {
7197 // phpcs:enable
7198 global $langs, $user;
7199
7200 $num = count($this->cache_vatrates);
7201 if ($num > 0) {
7202 return $num; // Cache already loaded
7203 }
7204
7205 dol_syslog(__METHOD__, LOG_DEBUG);
7206
7207 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
7208 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
7209 $sql .= " WHERE t.fk_pays = c.rowid";
7210 $sql .= " AND t.active > 0";
7211 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
7212 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
7213 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
7214
7215 $resql = $this->db->query($sql);
7216 if ($resql) {
7217 $num = $this->db->num_rows($resql);
7218 if ($num) {
7219 for ($i = 0; $i < $num; $i++) {
7220 $obj = $this->db->fetch_object($resql);
7221
7222 $tmparray = array();
7223 $tmparray['rowid'] = $obj->rowid;
7224 $tmparray['type_vat'] = ($obj->type_vat <= 0 ? 0 : $obj->type_vat); // Some version have type_vat corrupted with value -1
7225 $tmparray['code'] = $obj->code;
7226 $tmparray['txtva'] = $obj->taux;
7227 $tmparray['nprtva'] = $obj->recuperableonly;
7228 $tmparray['localtax1'] = $obj->localtax1;
7229 $tmparray['localtax1_type'] = $obj->localtax1_type;
7230 $tmparray['localtax2'] = $obj->localtax2;
7231 $tmparray['localtax2_type'] = $obj->localtax1_type;
7232 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
7233 $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
7234 $positiverates = '';
7235 if ($obj->taux) {
7236 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
7237 }
7238 if ($obj->localtax1) {
7239 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
7240 }
7241 if ($obj->localtax2) {
7242 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
7243 }
7244 if (empty($positiverates)) {
7245 $positiverates = '0';
7246 }
7247 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
7248
7249 $this->cache_vatrates[$obj->rowid] = $tmparray;
7250 }
7251
7252 return $num;
7253 } else {
7254 $this->error = '<span class="error">';
7255 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
7256 $reg = array();
7257 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
7258 $langs->load("errors");
7259 $new_country_code = $reg[1];
7260 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid');
7261 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
7262 }
7263 $this->error .= '</span>';
7264 return -1;
7265 }
7266 } else {
7267 $this->error = '<span class="error">' . $this->db->error() . '</span>';
7268 return -2;
7269 }
7270 }
7271
7272 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7273
7296 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)
7297 {
7298 // phpcs:enable
7299 global $langs, $mysoc, $hookmanager;
7300
7301 $langs->load('errors');
7302
7303 $return = '';
7304 // Bypass the default method
7305 $hookmanager->initHooks(array('commonobject'));
7306 $info_bits == 1 ? $is_npr = 1 : $is_npr = 0;
7307 $parameters = array(
7308 'seller' => $societe_vendeuse,
7309 'buyer' => $societe_acheteuse,
7310 'idprod' => $idprod,
7311 'is_npr' => $is_npr,
7312 'type' => $type,
7313 'options_only' => $options_only,
7314 'mode' => $mode,
7315 'type_vat' => $type_vat
7316 );
7317 $reshook = $hookmanager->executeHooks('load_tva', $parameters);
7318 if ($reshook > 0) {
7319 return $hookmanager->resPrint;
7320 } elseif ($reshook === 0) {
7321 $return .= $hookmanager->resPrint;
7322 }
7323
7324 // Define defaultnpr, defaultttx and defaultcode
7325 $defaultnpr = ($info_bits & 0x01);
7326 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
7327 $defaulttx = str_replace('*', '', $selectedrate);
7328 $defaultcode = '';
7329 $reg = array();
7330 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7331 $defaultcode = $reg[1];
7332 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7333 }
7334 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
7335
7336 // Check parameters
7337 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
7338 if ($societe_vendeuse->id == $mysoc->id) {
7339 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
7340 } else {
7341 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
7342 }
7343 return $return;
7344 }
7345
7346 //var_dump($societe_acheteuse);
7347 //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";
7348 //exit;
7349
7350 // Define list of countries to use to search VAT rates to show
7351 // First we defined code_country to use to find list
7352 if (is_object($societe_vendeuse)) {
7353 $code_country = "'" . $societe_vendeuse->country_code . "'";
7354 } else {
7355 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
7356 }
7357
7358 if ($societe_vendeuse == $mysoc && getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
7359 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
7360 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
7361 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
7362 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
7363 if (is_object($societe_vendeuse) && is_object($societe_acheteuse) && isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
7364 // We also add the buyer country code
7365 if (is_numeric($type)) {
7366 if ($type == 1) { // We know product is a service
7367 switch ($selectVatComboMode) {
7368 case '1':
7369 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7370 break;
7371 case '2':
7372 $code_country = "'" . $societe_acheteuse->country_code . "'";
7373 break;
7374 }
7375 }
7376 } elseif (!$idprod) { // We don't know type of product
7377 switch ($selectVatComboMode) {
7378 case '1':
7379 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7380 break;
7381 case '2':
7382 $code_country = "'" . $societe_acheteuse->country_code . "'";
7383 break;
7384 }
7385 } else {
7386 $prodstatic = new Product($this->db);
7387 $prodstatic->fetch($idprod);
7388 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
7389 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
7390 }
7391 }
7392 }
7393 }
7394
7395 // Now we load the list of VAT
7396 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
7397
7398 // Keep only the VAT qualified for $type_vat
7399 $arrayofvatrates = array();
7400 foreach ($this->cache_vatrates as $cachevalue) {
7401 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] == $type_vat) {
7402 $arrayofvatrates[] = $cachevalue;
7403 }
7404 }
7405
7406 $num = count($arrayofvatrates);
7407 if ($num > 0) {
7408 // Define the vat rate to pre-select (if defaulttx not forced so is -1 or '')
7409 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7410 // Define a default thirdparty to use if the seller or buyer is not defined
7411 $tmpthirdparty = new Societe($this->db);
7412 $tmpthirdparty->country_code = $mysoc->country_code;
7413
7414 $defaulttx = get_default_tva(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7415 $defaultnpr = get_default_npr(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7416
7417 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7418 $defaultcode = $reg[1];
7419 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7420 }
7421 if (empty($defaulttx)) {
7422 $defaultnpr = 0;
7423 }
7424 }
7425
7426 // If we fails to find a default vat rate, we take the last one in list
7427 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
7428 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7429 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
7430 // We take the last one found in list
7431 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
7432 } else {
7433 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
7434 $defaulttx = '';
7435 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
7436 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
7437 }
7438 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7439 $defaultcode = $reg[1];
7440 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7441 }
7442 }
7443 }
7444
7445 // Disabled is true if the seller is not subject to VAT
7446 $disabled = false;
7447 $title = '';
7448 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && empty($societe_vendeuse->tva_assuj)) {
7449 // When we are seller and we do not use VAT, we want to force to disable VAT selection, except if EXPENSEREPORT_OVERRIDE_VAT is set
7450 // EXPENSEREPORT_OVERRIDE_VAT is a strange option that allow to override/enable VAT regardless of sellet vat option - needed for expense report if
7451 // expense report used for business expenses instead of using supplier invoices (but this is a very bad idea !)
7452 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
7453 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
7454 $disabled = true;
7455 }
7456 }
7457
7458 if (!$options_only) {
7459 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
7460 }
7461
7462 $selectedfound = false;
7463 foreach ($arrayofvatrates as $rate) {
7464 // Keep only 0 if seller is not subject to VAT
7465 if ($disabled && $rate['txtva'] != 0) {
7466 continue;
7467 }
7468
7469 // Define key to use into select list
7470 $key = $rate['txtva'];
7471 $key .= $rate['nprtva'] ? '*' : '';
7472 if ($mode > 0 && $rate['code']) {
7473 $key .= ' (' . $rate['code'] . ')';
7474 }
7475 if ($mode < 0) {
7476 $key = $rate['rowid'];
7477 }
7478
7479 $return .= '<option value="' . $key . '"';
7480 if (!$selectedfound) {
7481 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
7482 if ($defaultcode == $rate['code']) {
7483 $return .= ' selected';
7484 $selectedfound = true;
7485 }
7486 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
7487 $return .= ' selected';
7488 $selectedfound = true;
7489 }
7490 }
7491 $return .= '>';
7492
7493 // Show label of VAT
7494 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
7495 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
7496 $return .= $rate['labelpositiverates'];
7497 } else {
7498 // Simple label
7499 $return .= vatrate($rate['label']);
7500 }
7501
7502 //$return.=($rate['code']?' '.$rate['code']:'');
7503 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
7504
7505 $return .= '</option>';
7506 }
7507
7508 if (!$options_only) {
7509 $return .= '</select>';
7510 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
7511 }
7512 } else {
7513 $return .= $this->error;
7514 }
7515
7516 $this->num = $num;
7517 return $return;
7518 }
7519
7520
7521 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7522
7547 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 = '')
7548 {
7549 // phpcs:enable
7550 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
7551 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
7552 if (!empty($nooutput)) {
7553 return $retstring;
7554 }
7555 print $retstring;
7556
7557 return '';
7558 }
7559
7575 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
7576 {
7577 global $langs;
7578
7579 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
7580 if ($forcenewline) {
7581 $ret .= '<br>';
7582 }
7583 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
7584 return $ret;
7585 }
7586
7615 public function selectDate($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '', $openinghours = '', $stepminutes = 1, $labeladddateof = '', $placeholder = '', $gm = 'auto', $calendarpicto = '')
7616 {
7617 global $conf, $langs;
7618
7619 if ($gm === 'auto') {
7620 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7621 }
7622
7623 $retstring = '';
7624
7625 if ($prefix == '') {
7626 $prefix = 're';
7627 }
7628 if ($h == '') {
7629 $h = 0;
7630 }
7631 if ($m == '') {
7632 $m = 0;
7633 }
7634 $emptydate = 0;
7635 $emptyhours = 0;
7636 if ($stepminutes <= 0 || $stepminutes > 30) {
7637 $stepminutes = 1;
7638 }
7639 if ($empty == 1) {
7640 $emptydate = 1;
7641 $emptyhours = 1;
7642 }
7643 if ($empty == 2) {
7644 $emptydate = 0;
7645 $emptyhours = 1;
7646 }
7647 $orig_set_time = $set_time;
7648
7649 if ($set_time === '' && $emptydate == 0) {
7650 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7651 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7652 $set_time = dol_now($gm);
7653 } else {
7654 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7655 }
7656 }
7657
7658 // Analysis of the pre-selection date
7659 $reg = array();
7660 $shour = '';
7661 $smin = '';
7662 $ssec = '';
7663 if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', (string) $set_time, $reg)) { // deprecated usage
7664 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7665 $syear = (!empty($reg[1]) ? $reg[1] : '');
7666 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7667 $sday = (!empty($reg[3]) ? $reg[3] : '');
7668 $shour = (!empty($reg[4]) ? $reg[4] : '');
7669 $smin = (!empty($reg[5]) ? $reg[5] : '');
7670 } elseif (strval($set_time) != '' && $set_time != -1) {
7671 // set_time est un timestamps (0 possible)
7672 $syear = dol_print_date($set_time, "%Y", $gm);
7673 $smonth = dol_print_date($set_time, "%m", $gm);
7674 $sday = dol_print_date($set_time, "%d", $gm);
7675 if ($orig_set_time != '') {
7676 $shour = dol_print_date($set_time, "%H", $gm);
7677 $smin = dol_print_date($set_time, "%M", $gm);
7678 $ssec = dol_print_date($set_time, "%S", $gm);
7679 }
7680 } else {
7681 // Date est '' ou vaut -1
7682 $syear = '';
7683 $smonth = '';
7684 $sday = '';
7685 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7686 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7687 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7688 }
7689 if ($h == 3 || $h == 4) {
7690 $shour = '';
7691 }
7692 if ($m == 3) {
7693 $smin = '';
7694 }
7695
7696 $nowgmt = dol_now('gmt');
7697 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7698
7699 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7700 $usecalendar = 'combo';
7701 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7702 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : getDolGlobalString("MAIN_POPUP_CALENDAR"));
7703 }
7704 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7705 // If we use a text browser or screen reader, we use the 'combo' date selector
7706 $usecalendar = 'html';
7707 }
7708
7709 if ($d) {
7710 // Show date with popup
7711 if ($usecalendar != 'combo') {
7712 $formatted_date = '';
7713 //print "e".$set_time." t ".$conf->format_date_short;
7714 if (strval($set_time) != '' && $set_time != -1) {
7715 //$formatted_date=dol_print_date($set_time,$conf->format_date_short);
7716 $formatted_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7717 }
7718
7719 // Calendrier popup version eldy
7720 if ($usecalendar == "eldy") {
7721 // To have this manager working back, you must retrieve all functions showDP child found into the lib_head.js of v4 for example
7722 // and use load the js so the call of showDP will works.
7723
7724 /*
7725 // Input area to enter date manually
7726 $retstring .= '<!-- datepicker usecalendar=eldy --><input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formatted_date . '"';
7727 $retstring .= ($disabled ? ' disabled' : '');
7728 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7729 $retstring .= ' autocomplete="off">';
7730
7731 // Icon calendar
7732 $retstringbuttom = '';
7733 if (!$disabled) {
7734 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7735 $base = DOL_URL_ROOT . '/core/';
7736 $retstringbuttom .= ' onClick="showDP(\'' . dol_escape_js($base) . '\',\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\',\'' . dol_escape_js($langs->defaultlang) . '\');"';
7737 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink paddingright"') . '</button>';
7738 } else {
7739 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink paddingright"') . '</button>';
7740 }
7741 $retstring = $retstringbuttom . $retstring;
7742
7743 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7744 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7745 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7746 */
7747 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7748 if (!$disabled && $usecalendar != 'html') {
7749 // Output javascript for datepicker
7750 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7751 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7752
7753 $retstring .= '<!-- datepicker usecalendar='.$usecalendar.' --><script nonce="' . getNonce() . '" type="text/javascript">';
7754 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7755 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7756 autoclose: true,
7757 todayHighlight: true,
7758 yearRange: '" . $minYear . ":" . $maxYear . "',";
7759 if (!empty($conf->dol_use_jmobile)) {
7760 $retstring .= "
7761 beforeShow: function (input, datePicker) {
7762 input.disabled = true;
7763 },
7764 onClose: function (dateText, datePicker) {
7765 this.disabled = false;
7766 },
7767 ";
7768 }
7769 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7770 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7771 $buttonImage = $calendarpicto ?: DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png";
7772 $retstring .= "
7773 showOn: 'button', /* both has problem with autocompletion */
7774 buttonImage: '" . $buttonImage . "',
7775 buttonImageOnly: true";
7776 }
7777 $retstring .= "
7778 }) });";
7779 $retstring .= "</script>";
7780 }
7781
7782 // Input area to enter date manually
7783 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7784 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="'.($usecalendar == 'html' ? "date" : "text").'" class="maxwidthdate center" maxlength="11" value="'.$formatted_date.'"';
7785 $retstring .= ($disabled ? ' disabled' : '');
7786 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7787 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($usecalendar == 'html' ? 'yyyy-MM-dd' : $langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7788 $retstring .= ' autocomplete="off">';
7789
7790 // Icon calendar
7791 if ($disabled) {
7792 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7793 $retstring = $retstringbutton . $retstring;
7794 }
7795
7796 $retstring .= '</div>';
7797 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7798 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7799 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7800 } else {
7801 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7802 }
7803 } else {
7804 // Show date with combo selects
7805 // Day
7806 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7807
7808 if ($emptydate || $set_time == -1) {
7809 $retstring .= '<option value="0" selected>&nbsp;</option>';
7810 }
7811
7812 for ($day = 1; $day <= 31; $day++) {
7813 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7814 }
7815
7816 $retstring .= "</select>";
7817
7818 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7819 if ($emptydate || $set_time == -1) {
7820 $retstring .= '<option value="0" selected>&nbsp;</option>';
7821 }
7822
7823 // Month
7824 for ($month = 1; $month <= 12; $month++) {
7825 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7826 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7827 $retstring .= "</option>";
7828 }
7829 $retstring .= "</select>";
7830
7831 // Year
7832 if ($emptydate || $set_time == -1) {
7833 $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 . '">';
7834 } else {
7835 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7836
7837 $syear = (int) $syear;
7838 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7839 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7840 }
7841 $retstring .= "</select>\n";
7842 }
7843 }
7844 }
7845
7846 if ($d && $h) {
7847 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7848 $retstring .= '<span class="nowraponall">';
7849 }
7850
7851 if ($h) {
7852 $hourstart = 0;
7853 $hourend = 24;
7854 if ($openinghours != '') {
7855 $openinghours = explode(',', $openinghours);
7856 $hourstart = $openinghours[0];
7857 $hourend = $openinghours[1];
7858 if ($hourend < $hourstart) {
7859 $hourend = $hourstart;
7860 }
7861 }
7862
7863 // Show hour
7864 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7865 if ($emptyhours) {
7866 $retstring .= '<option value="-1">&nbsp;</option>';
7867 }
7868 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7869 if (strlen($hour) < 2) {
7870 $hour = "0" . $hour;
7871 }
7872 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7873 $retstring .= '</option>';
7874 }
7875 $retstring .= '</select>';
7876
7877 if ($disabled) {
7878 $retstring .= '<input type="hidden" id="' . $prefix . 'hour" name="' . $prefix . 'hour" value="' . $shour . '">' . "\n";
7879 }
7880 if ($m) {
7881 $retstring .= ":";
7882 }
7883 }
7884
7885 if ($m) {
7886 // Show minutes
7887 $retstring .= '<select ' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7888 if ($emptyhours) {
7889 $retstring .= '<option value="-1">&nbsp;</option>';
7890 }
7891 for ($min = 0; $min < 60; $min += $stepminutes) {
7892 $min_str = sprintf("%02d", $min);
7893 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7894 }
7895 $retstring .= '</select>';
7896 if ($disabled) {
7897 $retstring .= '<input type="hidden" id="' . $prefix . 'min" name="' . $prefix . 'min" value="' . $smin . '">' . "\n";
7898 }
7899 // Add also seconds
7900 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7901 }
7902
7903 if ($d && $h) {
7904 $retstring .= '</span>';
7905 }
7906
7907 // Add a "Now" link
7908 if (!empty($conf->use_javascript_ajax) && $addnowlink && !$disabled) {
7909 // Script which will be inserted in the onClick of the "Now" link
7910 $reset_scripts = "";
7911 if ($addnowlink == 2) { // local computer time
7912 // pad add leading 0 on numbers
7913 $reset_scripts .= "Number.prototype.pad = function(size) {
7914 var s = String(this);
7915 while (s.length < (size || 2)) {s = '0' + s;}
7916 return s;
7917 };
7918 var d = new Date();";
7919 }
7920
7921 // Generate the date part, depending on the use or not of the javascript calendar
7922 if ($addnowlink == 1) { // server time expressed in user time setup
7923 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7924 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7925 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7926 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7927 } elseif ($addnowlink == 2) {
7928 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7929 * This break application for foreign languages.
7930 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7931 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7932 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7933 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7934 */
7935 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7936 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7937 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7938 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7939 }
7940 /*if ($usecalendar == "eldy")
7941 {
7942 $base=DOL_URL_ROOT.'/core/';
7943 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7944 }
7945 else
7946 {
7947 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7948 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7949 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7950 }*/
7951 // Update the hour part
7952 if ($h) {
7953 if ($fullday) {
7954 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7955 }
7956 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7957 if ($addnowlink == 1) {
7958 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7959 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7960 } elseif ($addnowlink == 2) {
7961 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7962 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7963 }
7964
7965 if ($fullday) {
7966 $reset_scripts .= ' } ';
7967 }
7968 }
7969 // Update the minute part
7970 if ($m) {
7971 if ($fullday) {
7972 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7973 }
7974 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7975 if ($addnowlink == 1) {
7976 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7977 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7978 } elseif ($addnowlink == 2) {
7979 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7980 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7981 }
7982 if ($fullday) {
7983 $reset_scripts .= ' } ';
7984 }
7985 }
7986 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7987 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7988 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7989 $retstring .= $langs->trans("Now");
7990 $retstring .= '</button> ';
7991 }
7992 }
7993
7994 // Add a "Plus one hour" link
7995 if ($conf->use_javascript_ajax && $addplusone && !$disabled) {
7996 // Script which will be inserted in the onClick of the "Add plusone" link
7997 $reset_scripts = "";
7998
7999 // Generate the date part, depending on the use or not of the javascript calendar
8000 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
8001 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
8002 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
8003 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
8004 // Update the hour part
8005 if ($h) {
8006 if ($fullday) {
8007 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
8008 }
8009 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
8010 if ($fullday) {
8011 $reset_scripts .= ' } ';
8012 }
8013 }
8014 // Update the minute part
8015 if ($m) {
8016 if ($fullday) {
8017 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
8018 }
8019 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
8020 if ($fullday) {
8021 $reset_scripts .= ' } ';
8022 }
8023 }
8024 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
8025 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
8026 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
8027 $retstring .= $langs->trans("DateStartPlusOne");
8028 $retstring .= '</button> ';
8029 }
8030 }
8031
8032 // Add a link to set data
8033 if ($conf->use_javascript_ajax && !empty($adddateof) && !$disabled) {
8034 if (!is_array($adddateof)) {
8035 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
8036 } else {
8037 $arrayofdateof = $adddateof;
8038 }
8039 foreach ($arrayofdateof as $valuedateof) {
8040 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
8041 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
8042 $tmparray = dol_getdate($tmpadddateof);
8043 if (empty($tmplabeladddateof)) {
8044 $tmplabeladddateof = $langs->trans("DateInvoice");
8045 }
8046 $reset_scripts = 'console.log(\'Click on now link\'); ';
8047 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
8048 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
8049 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
8050 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
8051 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
8052 }
8053 }
8054
8055 return $retstring;
8056 }
8057
8066 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
8067 {
8068 global $langs;
8069
8070 $TDurationTypes = array(
8071 'y' => $langs->trans('Years'),
8072 'm' => $langs->trans('Month'),
8073 'w' => $langs->trans('Weeks'),
8074 'd' => $langs->trans('Days'),
8075 'h' => $langs->trans('Hours'),
8076 'i' => $langs->trans('Minutes')
8077 );
8078
8079 // Removed undesired duration types
8080 foreach ($excludetypes as $value) {
8081 unset($TDurationTypes[$value]);
8082 }
8083
8084 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
8085 foreach ($TDurationTypes as $key => $typeduration) {
8086 $retstring .= '<option value="' . $key . '"';
8087 if ($key == $selected) {
8088 $retstring .= " selected";
8089 }
8090 $retstring .= ">" . $typeduration . "</option>";
8091 }
8092 $retstring .= "</select>";
8093
8094 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
8095
8096 return $retstring;
8097 }
8098
8099 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8100
8114 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
8115 {
8116 // phpcs:enable
8117 global $langs;
8118
8119 $retstring = '<span class="nowraponall">';
8120
8121 $hourSelected = '';
8122 $minSelected = '';
8123
8124 // Hours
8125 if ($iSecond != '') {
8126 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
8127
8128 $hourSelected = convertSecondToTime($iSecond, 'allhour');
8129 $minSelected = convertSecondToTime($iSecond, 'min');
8130 }
8131
8132 if ($typehour == 'select') {
8133 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
8134 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
8135 $retstring .= '<option value="' . $hour . '"';
8136 if (is_numeric($hourSelected) && $hourSelected == $hour) {
8137 $retstring .= " selected";
8138 }
8139 $retstring .= ">" . $hour . "</option>";
8140 }
8141 $retstring .= "</select>";
8142 } elseif ($typehour == 'text' || $typehour == 'textselect') {
8143 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
8144 } else {
8145 return 'BadValueForParameterTypeHour';
8146 }
8147
8148 if ($typehour != 'text') {
8149 $retstring .= ' ' . $langs->trans('HourShort');
8150 } else {
8151 $retstring .= '<span class="">:</span>';
8152 }
8153
8154 // Minutes
8155 if ($minunderhours) {
8156 $retstring .= '<br>';
8157 } else {
8158 if ($typehour != 'text') {
8159 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
8160 }
8161 }
8162
8163 if ($typehour == 'select' || $typehour == 'textselect') {
8164 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
8165 for ($min = 0; $min <= 55; $min += 5) {
8166 $retstring .= '<option value="' . $min . '"';
8167 if (is_numeric($minSelected) && $minSelected == $min) {
8168 $retstring .= ' selected';
8169 }
8170 $retstring .= '>' . $min . '</option>';
8171 }
8172 $retstring .= "</select>";
8173 } elseif ($typehour == 'text') {
8174 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
8175 }
8176
8177 if ($typehour != 'text') {
8178 $retstring .= ' ' . $langs->trans('MinuteShort');
8179 }
8180
8181 $retstring .= "</span>";
8182
8183 if (!empty($nooutput)) {
8184 return $retstring;
8185 }
8186
8187 print $retstring;
8188
8189 return '';
8190 }
8191
8211 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)
8212 {
8213 global $langs, $conf;
8214
8215 $out = '';
8216
8217 // check parameters
8218 if (is_null($ajaxoptions)) {
8219 $ajaxoptions = array();
8220 }
8221
8222 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8223 $placeholder = '';
8224
8225 if ($selected && empty($selected_input_value)) {
8226 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
8227 $tickettmpselect = new Ticket($this->db);
8228 $tickettmpselect->fetch((int) $selected);
8229 $selected_input_value = $tickettmpselect->ref;
8230 unset($tickettmpselect);
8231 }
8232
8233 $urloption = '';
8234 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8235
8236 if (empty($hidelabel)) {
8237 $out .= $langs->trans("RefOrLabel") . ' : ';
8238 } elseif ($hidelabel > 1) {
8239 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8240 if ($hidelabel == 2) {
8241 $out .= img_picto($langs->trans("Search"), 'search');
8242 }
8243 }
8244 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8245 if ($hidelabel == 3) {
8246 $out .= img_picto($langs->trans("Search"), 'search');
8247 }
8248 } else {
8249 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8250 }
8251
8252 if (empty($nooutput)) {
8253 print $out;
8254 } else {
8255 return $out;
8256 }
8257 return '';
8258 }
8259
8260
8277 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8278 {
8279 global $langs, $conf;
8280
8281 $out = '';
8282 $outarray = array();
8283
8284 $selectFields = " p.rowid, p.ref, p.message";
8285
8286 $sql = "SELECT ";
8287 $sql .= $selectFields;
8288 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
8289 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
8290
8291 // Add criteria on ref/label
8292 if ($filterkey != '') {
8293 $sql .= ' AND (';
8294 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8295 // For natural search
8296 $search_crit = explode(' ', $filterkey);
8297 $i = 0;
8298 if (count($search_crit) > 1) {
8299 $sql .= "(";
8300 }
8301 foreach ($search_crit as $crit) {
8302 if ($i > 0) {
8303 $sql .= " AND ";
8304 }
8305 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8306 $sql .= ")";
8307 $i++;
8308 }
8309 if (count($search_crit) > 1) {
8310 $sql .= ")";
8311 }
8312 $sql .= ')';
8313 }
8314
8315 $sql .= $this->db->plimit($limit, 0);
8316
8317 // Build output string
8318 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
8319 $result = $this->db->query($sql);
8320 if ($result) {
8321 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
8322 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
8323
8324 $num = $this->db->num_rows($result);
8325
8326 $events = array();
8327
8328 if (!$forcecombo) {
8329 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8330 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('TICKET_USE_SEARCH_TO_SELECT'));
8331 }
8332
8333 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8334
8335 $textifempty = '';
8336 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8337 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8338 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8339 if ($showempty && !is_numeric($showempty)) {
8340 $textifempty = $langs->trans($showempty);
8341 } else {
8342 $textifempty .= $langs->trans("All");
8343 }
8344 } else {
8345 if ($showempty && !is_numeric($showempty)) {
8346 $textifempty = $langs->trans($showempty);
8347 }
8348 }
8349 if ($showempty) {
8350 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8351 }
8352
8353 $i = 0;
8354 while ($num && $i < $num) {
8355 $opt = '';
8356 $optJson = array();
8357 $objp = $this->db->fetch_object($result);
8358
8359 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
8360 '@phan-var-force array{key:string,value:mixed,type:int} $optJson';
8361 // Add new entry
8362 // "key" value of json key array is used by jQuery automatically as selected value
8363 // "label" value of json key array is used by jQuery automatically as text for combo box
8364 $out .= $opt;
8365 array_push($outarray, $optJson);
8366
8367 $i++;
8368 }
8369
8370 $out .= '</select>';
8371
8372 $this->db->free($result);
8373
8374 if (empty($outputmode)) {
8375 return $out;
8376 }
8377 return $outarray;
8378 } else {
8379 dol_print_error($this->db);
8380 }
8381
8382 return array();
8383 }
8384
8396 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8397 {
8398 $outkey = '';
8399 $outref = '';
8400 $outtype = '';
8401
8402 $outkey = $objp->rowid;
8403 $outref = $objp->ref;
8404
8405 $opt = '<option value="' . $objp->rowid . '"';
8406 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8407 $opt .= '>';
8408 $opt .= $objp->ref;
8409 $objRef = $objp->ref;
8410 if (!empty($filterkey) && $filterkey != '') {
8411 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8412 }
8413
8414 $opt .= "</option>\n";
8415 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8416 }
8417
8437 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)
8438 {
8439 global $langs, $conf;
8440
8441 $out = '';
8442
8443 // check parameters
8444 if (is_null($ajaxoptions)) {
8445 $ajaxoptions = array();
8446 }
8447
8448 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8449 $placeholder = '';
8450
8451 if ($selected && empty($selected_input_value)) {
8452 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8453 $projecttmpselect = new Project($this->db);
8454 $projecttmpselect->fetch((int) $selected);
8455 $selected_input_value = $projecttmpselect->ref;
8456 unset($projecttmpselect);
8457 }
8458
8459 $urloption = '';
8460 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8461
8462 if (empty($hidelabel)) {
8463 $out .= $langs->trans("RefOrLabel") . ' : ';
8464 } elseif ($hidelabel > 1) {
8465 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8466 if ($hidelabel == 2) {
8467 $out .= img_picto($langs->trans("Search"), 'search');
8468 }
8469 }
8470 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8471 if ($hidelabel == 3) {
8472 $out .= img_picto($langs->trans("Search"), 'search');
8473 }
8474 } else {
8475 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8476 }
8477
8478 if (empty($nooutput)) {
8479 print $out;
8480 } else {
8481 return $out;
8482 }
8483 return '';
8484 }
8485
8502 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8503 {
8504 global $langs, $conf;
8505
8506 $out = '';
8507 $outarray = array();
8508
8509 $selectFields = " p.rowid, p.ref";
8510
8511 $sql = "SELECT ";
8512 $sql .= $selectFields;
8513 $sql .= " FROM " . $this->db->prefix() . "projet as p";
8514 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
8515
8516 // Add criteria on ref/label
8517 if ($filterkey != '') {
8518 $sql .= ' AND (';
8519 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8520 // For natural search
8521 $search_crit = explode(' ', $filterkey);
8522 $i = 0;
8523 if (count($search_crit) > 1) {
8524 $sql .= "(";
8525 }
8526 foreach ($search_crit as $crit) {
8527 if ($i > 0) {
8528 $sql .= " AND ";
8529 }
8530 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8531 $sql .= "";
8532 $i++;
8533 }
8534 if (count($search_crit) > 1) {
8535 $sql .= ")";
8536 }
8537 $sql .= ')';
8538 }
8539
8540 $sql .= $this->db->plimit($limit, 0);
8541
8542 // Build output string
8543 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
8544 $result = $this->db->query($sql);
8545 if ($result) {
8546 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8547 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
8548
8549 $num = $this->db->num_rows($result);
8550
8551 $events = array();
8552
8553 if (!$forcecombo) {
8554 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8555 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8556 }
8557
8558 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8559
8560 $textifempty = '';
8561 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8562 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8563 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8564 if ($showempty && !is_numeric($showempty)) {
8565 $textifempty = $langs->trans($showempty);
8566 } else {
8567 $textifempty .= $langs->trans("All");
8568 }
8569 } else {
8570 if ($showempty && !is_numeric($showempty)) {
8571 $textifempty = $langs->trans($showempty);
8572 }
8573 }
8574 if ($showempty) {
8575 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8576 }
8577
8578 $i = 0;
8579 while ($num && $i < $num) {
8580 $opt = '';
8581 $optJson = array();
8582 $objp = $this->db->fetch_object($result);
8583
8584 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
8585 // Add new entry
8586 // "key" value of json key array is used by jQuery automatically as selected value
8587 // "label" value of json key array is used by jQuery automatically as text for combo box
8588 $out .= $opt;
8589 array_push($outarray, $optJson);
8590
8591 $i++;
8592 }
8593
8594 $out .= '</select>';
8595
8596 $this->db->free($result);
8597
8598 if (empty($outputmode)) {
8599 return $out;
8600 }
8601 return $outarray;
8602 } else {
8603 dol_print_error($this->db);
8604 }
8605
8606 return array();
8607 }
8608
8622 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8623 {
8624 $outkey = '';
8625 $outref = '';
8626 $outtype = '';
8627
8628 $label = $objp->label;
8629
8630 $outkey = $objp->rowid;
8631 $outref = $objp->ref;
8632 $outlabel = $objp->label;
8633 $outtype = $objp->fk_product_type;
8634
8635 $opt = '<option value="' . $objp->rowid . '"';
8636 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8637 $opt .= '>';
8638 $opt .= $objp->ref;
8639 $objRef = $objp->ref;
8640 if (!empty($filterkey) && $filterkey != '') {
8641 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8642 }
8643
8644 $opt .= "</option>\n";
8645 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8646 }
8647
8648
8668 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)
8669 {
8670 global $langs, $conf;
8671
8672 $out = '';
8673
8674 // check parameters
8675 if (is_null($ajaxoptions)) {
8676 $ajaxoptions = array();
8677 }
8678
8679 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8680 $placeholder = '';
8681
8682 if ($selected && empty($selected_input_value)) {
8683 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8684 $adherenttmpselect = new Adherent($this->db);
8685 $adherenttmpselect->fetch((int) $selected);
8686 $selected_input_value = $adherenttmpselect->ref;
8687 unset($adherenttmpselect);
8688 }
8689
8690 $urloption = '';
8691
8692 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8693
8694 if (empty($hidelabel)) {
8695 $out .= $langs->trans("RefOrLabel") . ' : ';
8696 } elseif ($hidelabel > 1) {
8697 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8698 if ($hidelabel == 2) {
8699 $out .= img_picto($langs->trans("Search"), 'search');
8700 }
8701 }
8702 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8703 if ($hidelabel == 3) {
8704 $out .= img_picto($langs->trans("Search"), 'search');
8705 }
8706 } else {
8707 $filterkey = '';
8708
8709 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8710 }
8711
8712 if (empty($nooutput)) {
8713 print $out;
8714 } else {
8715 return $out;
8716 }
8717 return '';
8718 }
8719
8736 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8737 {
8738 global $langs, $conf;
8739
8740 $out = '';
8741 $outarray = array();
8742
8743 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8744
8745 $sql = "SELECT ";
8746 $sql .= $selectFields;
8747 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8748 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8749
8750 // Add criteria on ref/label
8751 if ($filterkey != '') {
8752 $sql .= ' AND (';
8753 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8754 // For natural search
8755 $search_crit = explode(' ', $filterkey);
8756 $i = 0;
8757 if (count($search_crit) > 1) {
8758 $sql .= "(";
8759 }
8760 foreach ($search_crit as $crit) {
8761 if ($i > 0) {
8762 $sql .= " AND ";
8763 }
8764 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8765 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8766 $i++;
8767 }
8768 if (count($search_crit) > 1) {
8769 $sql .= ")";
8770 }
8771 $sql .= ')';
8772 }
8773 if ($status != -1) {
8774 $sql .= ' AND statut = ' . ((int) $status);
8775 }
8776 $sql .= $this->db->plimit($limit, 0);
8777
8778 // Build output string
8779 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8780 $result = $this->db->query($sql);
8781 if ($result) {
8782 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8783 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8784
8785 $num = $this->db->num_rows($result);
8786
8787 $events = array();
8788
8789 if (!$forcecombo) {
8790 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8791 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8792 }
8793
8794 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8795
8796 $textifempty = '';
8797 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8798 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8799 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8800 if ($showempty && !is_numeric($showempty)) {
8801 $textifempty = $langs->trans($showempty);
8802 } else {
8803 $textifempty .= $langs->trans("All");
8804 }
8805 } else {
8806 if ($showempty && !is_numeric($showempty)) {
8807 $textifempty = $langs->trans($showempty);
8808 }
8809 }
8810 if ($showempty) {
8811 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8812 }
8813
8814 $i = 0;
8815 while ($num && $i < $num) {
8816 $opt = '';
8817 $optJson = array();
8818 $objp = $this->db->fetch_object($result);
8819
8820 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8821
8822 // Add new entry
8823 // "key" value of json key array is used by jQuery automatically as selected value
8824 // "label" value of json key array is used by jQuery automatically as text for combo box
8825 $out .= $opt;
8826 array_push($outarray, $optJson);
8827
8828 $i++;
8829 }
8830
8831 $out .= '</select>';
8832
8833 $this->db->free($result);
8834
8835 if (empty($outputmode)) {
8836 return $out;
8837 }
8838 return $outarray;
8839 } else {
8840 dol_print_error($this->db);
8841 }
8842
8843 return array();
8844 }
8845
8857 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8858 {
8859 $outkey = '';
8860 $outlabel = '';
8861 $outtype = '';
8862
8863 $outkey = $objp->rowid;
8864 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8865 $outtype = $objp->fk_adherent_type;
8866
8867 $opt = '<option value="' . $objp->rowid . '"';
8868 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8869 $opt .= '>';
8870 if (!empty($filterkey) && $filterkey != '') {
8871 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8872 }
8873 $opt .= $outlabel;
8874 $opt .= "</option>\n";
8875
8876 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8877 }
8878
8899 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8900 {
8901 global $conf, $extrafields, $user;
8902
8903 // Example of common usage for a link to a thirdparty
8904
8905 // We got this in a modulebuilder form of "MyObject" of module "mymodule".
8906 // When ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...), we have
8907 // $objectdesc = 'Societe'
8908 // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc']) or it can be an array that is directly
8909 // array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8910
8911 // We got this when showing an extrafields on resource that is a link to societe
8912 // When extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)', we have
8913 // $objectdesc = 'Societe'
8914 // $objectfield = 'resource:options_link_to_societe' or it can be an array that is directly
8915 // array("type"=>'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8916
8917 // With old usage:
8918 // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))'
8919 // $objectfield = ''
8920
8921 //var_dump($objectdesc.' '.$objectfield);
8922 //debug_print_backtrace();
8923
8924 $objectdescorig = $objectdesc;
8925 $objecttmp = null;
8926 $InfoFieldList = array();
8927 $classname = '';
8928 $filter = ''; // Ensure filter has value (for static analysis)
8929 $sortfield = ''; // Ensure filter has value (for static analysis)
8930
8931 if (is_array($objectfield)) { // objectfield is an array
8932 $objectdesc = $objectfield['type'];
8933 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8934 } elseif ($objectfield) { // objectfield is a string. We must retrieve the objectdesc from the field or extrafield. Deprecated, it is better to provide the array record directly.
8935 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8936 $tmparray = explode(':', $objectfield);
8937
8938 // Get instance of object from $element
8939 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8940
8941 if (is_object($objectforfieldstmp)) {
8942 $objectdesc = '';
8943
8944 $reg = array();
8945 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8946 // For a property in extrafields
8947 $key = $reg[1];
8948 // fetch optionals attributes and labels
8949 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8950
8951 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8952 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8953 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8954 $objectdesc = $tmpextrafields[0];
8955 }
8956 }
8957 } else {
8958 // For a property in ->fields
8959 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8960 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8961 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8962 }
8963 }
8964 }
8965 }
8966
8967 if ($objectdesc) {
8968 // Example of value for $objectdesc:
8969 // Bom:bom/class/bom.class.php:0:t.status=1
8970 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8971 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8972 $InfoFieldList = explode(":", $objectdesc, 4);
8973 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8974 $reg = array();
8975 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8976 $InfoFieldList[4] = $reg[1]; // take the sort field
8977 }
8978 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8979
8980 $classname = $InfoFieldList[0];
8981 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8982 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8983 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8984 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8985
8986 // Load object according to $id and $element
8987 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8988
8989 // Fallback to another solution to get $objecttmp
8990 if (empty($objecttmp) && !empty($classpath)) {
8991 dol_include_once($classpath);
8992
8993 if ($classname && class_exists($classname)) {
8994 $objecttmp = new $classname($this->db);
8995 }
8996 }
8997 }
8998
8999 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
9000 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
9001 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
9002 $filter = str_replace(
9003 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
9004 array($conf->entity, $sharedentities, $user->id),
9005 $filter
9006 );
9007
9008 if (!is_object($objecttmp)) {
9009 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.(is_array($objectfield) ? 'array' : $objectfield).', objectdesc='.$objectdesc, LOG_WARNING);
9010 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.(is_array($objectfield) ? 'array' : $objectfield).', objectdesc='.$objectdesc;
9011 }
9012 '@phan-var-force CommonObject $objecttmp';
9014 //var_dump($filter);
9015 $prefixforautocompletemode = $objecttmp->element;
9016 if ($prefixforautocompletemode == 'societe') {
9017 $prefixforautocompletemode = 'company';
9018 }
9019 if ($prefixforautocompletemode == 'product') {
9020 $prefixforautocompletemode = 'produit';
9021 }
9022
9023 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
9024
9025 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
9026
9027 // Generate the combo HTML component
9028 $out = '';
9029 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
9030 // No immediate load of all database
9031 $placeholder = '';
9032
9033 if ($preSelectedValue && empty($selected_input_value)) {
9034 $objecttmp->fetch($preSelectedValue);
9035 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
9036
9037 $oldValueForShowOnCombobox = 0;
9038 foreach ($objecttmp->fields as $fieldK => $fielV) {
9039 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
9040 continue;
9041 }
9042
9043 if (!$oldValueForShowOnCombobox) {
9044 $selected_input_value = '';
9045 }
9046
9047 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
9048 $selected_input_value .= $objecttmp->$fieldK;
9049 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
9050 }
9051 }
9052
9053 // Set url and param to call to get json of the search results
9054 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
9055 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . (is_scalar($objectfield) ? '&objectfield='.urlencode($objectfield) : '') . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
9056
9057 // Activate the auto complete using ajax call.
9058 $out .= ajax_autocompleter((string) $preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalInt($confkeyforautocompletemode), 0);
9059 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
9060 $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) . '"' : '') . ' />';
9061 } else {
9062 // Immediate load of table record.
9063 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
9064 }
9065
9066 return $out;
9067 }
9068
9069
9090 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
9091 {
9092 global $langs, $user, $hookmanager;
9093
9094 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
9095
9096 $prefixforautocompletemode = $objecttmp->element;
9097 if ($prefixforautocompletemode == 'societe') {
9098 $prefixforautocompletemode = 'company';
9099 }
9100 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
9101
9102 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
9103 $tmpfieldstoshow = '';
9104 foreach ($objecttmp->fields as $key => $val) {
9105 if (! (int) dol_eval((string) $val['enabled'], 1, 1, '1')) {
9106 continue;
9107 }
9108 if (!empty($val['showoncombobox'])) {
9109 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
9110 }
9111 }
9112 if ($tmpfieldstoshow) {
9113 $fieldstoshow = $tmpfieldstoshow;
9114 }
9115 } elseif ($objecttmp->element === 'category') {
9116 $fieldstoshow = 't.label';
9117 } else {
9118 // For backward compatibility
9119 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
9120 }
9121
9122 if (empty($fieldstoshow)) {
9123 if (!empty($objecttmp->parent_element)) {
9124 $fieldstoshow = 'o.ref';
9125 if (empty($sortfield)) {
9126 $sortfield = 'o.ref';
9127 }
9128 if (in_array($objecttmp->element, ['commandedet', 'propaldet', 'facturedet', 'expeditiondet'])) {
9129 $fieldstoshow .= ',p.ref AS p_ref,p.label,t.description';
9130 $sortfield .= ', p.ref';
9131 }
9132 } elseif (isset($objecttmp->fields['ref'])) {
9133 $fieldstoshow = 't.ref';
9134 } else {
9135 $langs->load("errors");
9136 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
9137 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
9138 }
9139 }
9140
9141 $out = '';
9142 $outarray = array();
9143 $tmparray = array();
9144
9145 $num = 0;
9146
9147 // Search data
9148 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . " as t";
9149 if (!empty($objecttmp->isextrafieldmanaged)) {
9150 $extrafieldTable = $objecttmp->table_element;
9151 if ($extrafieldTable == 'categorie') {
9152 $extrafieldTable = 'categories'; // For compatibility
9153 }
9154 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($extrafieldTable) . "_extrafields as e ON t.rowid = e.fk_object";
9155 }
9156 if (!empty($objecttmp->parent_element)) { // If parent_element is defined
9157 $parent_properties = getElementProperties($objecttmp->parent_element);
9158 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($parent_properties['table_element']) . " as o ON o.rowid = t.".$objecttmp->fk_parent_attribute;
9159 }
9160 if (isset($objecttmp->parent_element) && in_array($objecttmp->parent_element, ['commande', 'propal', 'facture', 'expedition'])) {
9161 $sql .= " LEFT JOIN " . $this->db->prefix() . "product as p ON p.rowid = t.fk_product";
9162 }
9163 if (!empty($objecttmp->ismultientitymanaged)) {
9164 if ($objecttmp->ismultientitymanaged == 1) { // @phan-suppress-current-line PhanPluginEmptyStatementIf
9165 // No need to join/link another table
9166 }
9167 if (!is_numeric($objecttmp->ismultientitymanaged)) {
9168 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
9169 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($tmparray[1]) . " as parenttable ON parenttable.rowid = t." . $this->db->sanitize($tmparray[0]);
9170 }
9171 }
9172
9173 // Add where from hooks
9174 $parameters = array(
9175 'object' => $objecttmp,
9176 'htmlname' => $htmlname,
9177 'filter' => $filter,
9178 'searchkey' => $searchkey
9179 );
9180
9181 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
9182 if (!empty($hookmanager->resPrint)) {
9183 $sql .= $hookmanager->resPrint;
9184 } else {
9185 $sql .= " WHERE 1=1";
9186
9187 // If table need a multientity restriction
9188 if (!empty($objecttmp->ismultientitymanaged)) {
9189 if ($objecttmp->ismultientitymanaged == 1) {
9190 $sql .= " AND t.entity IN (" . getEntity($objecttmp->element) . ")";
9191 }
9192 if (!is_numeric($objecttmp->ismultientitymanaged)) {
9193 $sql .= " AND parenttable.entity = t." . $this->db->sanitize($tmparray[0]);
9194 }
9195 // If the parent table is llx_societe and user is not an external user (a more robust test done later for external users),
9196 // then we must also check that user has permissions
9197 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
9198 if (!$user->hasRight('societe', 'client', 'voir') && empty($user->socid)) {
9199 $sql .= " AND EXISTS (SELECT sc.rowid FROM ".$this->db->prefix() . "societe_commerciaux as sc";
9200 $sql .= " WHERE sc.fk_soc = t.fk_soc AND sc.fk_user = ".((int) $user->id).")";
9201 }
9202 }
9203 }
9204
9205 // If user is external user, we must also make a test on llx_societe_commerciaux
9206 if (!empty($user->socid)) {
9207 if ($objecttmp->element == 'societe') {
9208 $sql .= " AND t.rowid = " . ((int) $user->socid);
9209 } elseif (!empty($objecttmp->fields['fk_soc']) || !empty($objecttmp->fields['t.fk_soc']) || property_exists($objecttmp, 'fk_soc') || property_exists($objecttmp, 'socid')) {
9210 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
9211 }
9212 }
9213
9214 $splittedfieldstoshow = explode(',', $fieldstoshow);
9215 foreach ($splittedfieldstoshow as &$field2) {
9216 if (is_numeric($pos = strpos($field2, ' '))) {
9217 $field2 = substr($field2, 0, $pos);
9218 }
9219 }
9220 if ($searchkey != '') {
9221 $sql .= natural_search($splittedfieldstoshow, $searchkey);
9222 }
9223
9224 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
9225 $errormessage = '';
9226 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
9227 if ($errormessage) {
9228 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
9229 }
9230 }
9231 }
9232 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
9233 //$sql.=$this->db->plimit($limit, 0);
9234 //print $sql;
9235
9236 // Build output string
9237 $resql = $this->db->query($sql);
9238 if ($resql) {
9239 // Construct $out and $outarray
9240 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
9241
9242 // 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
9243 $textifempty = '&nbsp;';
9244
9245 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
9246 if (getDolGlobalInt($confkeyforautocompletemode)) {
9247 if ($showempty && !is_numeric($showempty)) {
9248 $textifempty = $langs->trans($showempty);
9249 } else {
9250 $textifempty .= $langs->trans("All");
9251 }
9252 }
9253 if ($showempty) {
9254 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
9255 }
9256
9257 $num = $this->db->num_rows($resql);
9258 $i = 0;
9259 if ($num) {
9260 while ($i < $num) {
9261 $obj = $this->db->fetch_object($resql);
9262 $label = '';
9263 $labelhtml = '';
9264 $tmparray = explode(',', $fieldstoshow);
9265 $oldvalueforshowoncombobox = 0;
9266 foreach ($tmparray as $key => $val) {
9267 $val = preg_replace('/(t|p|o)\./', '', $val);
9268 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
9269 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
9270 $label .= $obj->$val;
9271 $labelhtml .= $obj->$val;
9272
9273 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
9274 }
9275 if (empty($outputmode)) {
9276 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
9277 $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>';
9278 } else {
9279 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
9280 }
9281 } else {
9282 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
9283 }
9284
9285 $i++;
9286 if (($i % 10) == 0) {
9287 $out .= "\n";
9288 }
9289 }
9290 }
9291
9292 $out .= '</select>' . "\n";
9293
9294 if (!$forcecombo) {
9295 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9296 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
9297 }
9298 } else {
9299 dol_print_error($this->db);
9300 }
9301
9302 $this->result = array('nbofelement' => $num);
9303
9304 if ($outputmode) {
9305 return $outarray;
9306 }
9307 return $out;
9308 }
9309
9310
9334 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)
9335 {
9336 global $conf, $langs;
9337
9338 // Do we want a multiselect ?
9339 //$jsbeautify = 0;
9340 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
9341 $jsbeautify = 1;
9342
9343 if ($value_as_key) {
9344 $array = array_combine($array, $array);
9345 }
9346
9347 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
9348
9349 $out = '';
9350
9351 if ($addjscombo < 0) {
9352 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9353 $addjscombo = 1;
9354 } else {
9355 $addjscombo = 0;
9356 }
9357 }
9358 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
9359 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
9360 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
9361 $out .= '>'."\n";
9362
9363 if ($show_empty) {
9364 $textforempty = ' ';
9365 if (!empty($conf->use_javascript_ajax)) {
9366 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
9367 }
9368 if (!is_numeric($show_empty)) {
9369 $textforempty = $show_empty;
9370 }
9371 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
9372 }
9373 if (is_array($array)) {
9374 // Translate
9375 if ($translate) {
9376 foreach ($array as $key => $value) {
9377 if (!is_array($value)) {
9378 $array[$key] = $langs->trans($value);
9379 } else {
9380 $array[$key]['label'] = $langs->trans($value['label']);
9381 }
9382 }
9383 }
9384 // Sort
9385 if ($sort == 'ASC') {
9386 asort($array);
9387 } elseif ($sort == 'DESC') {
9388 arsort($array);
9389 }
9390
9391 foreach ($array as $key => $tmpvalue) {
9392 if (is_array($tmpvalue)) {
9393 $value = $tmpvalue['label'];
9394 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
9395 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
9396 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
9397 } else {
9398 $value = $tmpvalue;
9399 //$valuehtml = $tmpvalue;
9400 $disabled = '';
9401 $style = '';
9402 }
9403 if (!empty($disablebademail)) {
9404 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
9405 || ($disablebademail == 2 && preg_match('/---/', $value))) {
9406 $disabled = ' disabled';
9407 $style = ' class="warning"';
9408 }
9409 }
9410 if ($key_in_label) {
9411 if (empty($nohtmlescape)) {
9412 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
9413 } else {
9414 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
9415 }
9416 } else {
9417 if (empty($nohtmlescape)) {
9418 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
9419 } else {
9420 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
9421 }
9422 if ($value == '' || $value == '-') {
9423 $selectOptionValue = '&nbsp;';
9424 }
9425 }
9426 $out .= '<option value="' . $key . '"';
9427 $out .= $style . $disabled;
9428 if (is_array($id)) {
9429 if (in_array($key, $id) && !$disabled) {
9430 $out .= ' selected'; // To preselect a value
9431 }
9432 } else {
9433 $id = (string) $id; // if $id = 0, then $id = '0'
9434 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
9435 $out .= ' selected'; // To preselect a value
9436 }
9437 }
9438 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
9439 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
9440 }
9441
9442 if (is_array($tmpvalue)) {
9443 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
9444 if ($keyforvalue == 'labelhtml') {
9445 $keyforvalue = 'data-html';
9446 }
9447 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
9448 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
9449 }
9450 }
9451 }
9452 $out .= '>';
9453 $out .= $selectOptionValue;
9454 $out .= "</option>\n";
9455 }
9456 }
9457 $out .= "</select>";
9458
9459 // Add code for jquery to use multiselect
9460 if ($addjscombo && $jsbeautify) {
9461 // Enhance with select2
9462 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9463 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
9464 }
9465
9466 return $out;
9467 }
9468
9487 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
9488 {
9489 global $conf;
9490 global $delayedhtmlcontent; // Will be used later outside of this function
9491
9492 // TODO Use an internal dolibarr component instead of select2
9493 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9494 return '';
9495 }
9496
9497 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
9498
9499 $outdelayed = '';
9500 if (!empty($conf->use_javascript_ajax)) {
9501 $tmpplugin = 'select2';
9502 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9503 <script nonce="' . getNonce() . '">
9504 $(document).ready(function () {
9505
9506 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
9507
9508 $(".' . $htmlname . '").select2({
9509 ajax: {
9510 dir: "ltr",
9511 url: "' . $url . '",
9512 dataType: \'json\',
9513 delay: 250,
9514 data: function (params) {
9515 return {
9516 q: params.term, // search term
9517 page: params.page
9518 }
9519 },
9520 processResults: function (data) {
9521 // parse the results into the format expected by Select2.
9522 // since we are using custom formatting functions we do not need to alter the remote JSON data
9523 //console.log(data);
9524 saveRemoteData = data;
9525 /* format json result for select2 */
9526 result = []
9527 $.each( data, function( key, value ) {
9528 result.push({id: key, text: value.text});
9529 });
9530 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
9531 //console.log(result);
9532 return {results: result, more: false}
9533 },
9534 cache: true
9535 },
9536 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9537 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9538 placeholder: \'' . dol_escape_js($placeholder) . '\',
9539 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9540 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9541 formatResult: function (result, container, query, escapeMarkup) {
9542 return escapeMarkup(result.text);
9543 },
9544 });
9545
9546 ' . ($callurlonselect ? '
9547 /* Code to execute a GET when we select a value */
9548 $(".' . $htmlname . '").change(function() {
9549 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9550 console.log("We select in selectArrayAjax the entry "+selected)
9551 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9552 $.each( saveRemoteData, function( key, value ) {
9553 if (key == selected)
9554 {
9555 console.log("selectArrayAjax - Do a redirect to "+value.url)
9556 location.assign(value.url);
9557 }
9558 });
9559 });' : '') . '
9560
9561 });
9562 </script>';
9563 }
9564
9565 if ($acceptdelayedhtml) {
9566 $delayedhtmlcontent .= $outdelayed;
9567 } else {
9568 $out .= $outdelayed;
9569 }
9570 return $out;
9571 }
9572
9592 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
9593 {
9594 global $conf;
9595 global $delayedhtmlcontent; // Will be used later outside of this function
9596
9597 // TODO Use an internal dolibarr component instead of select2
9598 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9599 return '';
9600 }
9601
9602 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
9603
9604 $formattedarrayresult = array();
9605
9606 foreach ($array as $key => $value) {
9607 $o = new stdClass();
9608 $o->id = $key;
9609 $o->text = $value['text'];
9610 $o->url = $value['url'];
9611 $formattedarrayresult[] = $o;
9612 }
9613
9614 $outdelayed = '';
9615 if (!empty($conf->use_javascript_ajax)) {
9616 $tmpplugin = 'select2';
9617 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9618 <script nonce="' . getNonce() . '">
9619 $(document).ready(function () {
9620 var data = ' . json_encode($formattedarrayresult) . ';
9621
9622 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
9623
9624 $(\'.' . dol_escape_js($htmlname) . '\').select2({
9625 data: data,
9626 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9627 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9628 placeholder: \'' . dol_escape_js($placeholder) . '\',
9629 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9630 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9631 formatResult: function (result, container, query, escapeMarkup) {
9632 return escapeMarkup(result.text);
9633 },
9634 matcher: function (params, data) {
9635
9636 if(! data.id) return null;';
9637
9638 if ($callurlonselect) {
9639 // We forge the url with 'sall='
9640 $outdelayed .= '
9641
9642 var urlBase = data.url;
9643 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
9644 /* console.log("params.term="+params.term); */
9645 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
9646 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
9647 }
9648
9649 if (!$disableFiltering) {
9650 $outdelayed .= '
9651
9652 if(data.text.match(new RegExp(params.term))) {
9653 return data;
9654 }
9655
9656 return null;';
9657 } else {
9658 $outdelayed .= '
9659
9660 return data;';
9661 }
9662
9663 $outdelayed .= '
9664 }
9665 });
9666
9667 ' . ($callurlonselect ? '
9668 /* Code to execute a GET when we select a value */
9669 $(\'.' . dol_escape_js($htmlname) . '\').change(function() {
9670 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9671 console.log("We select "+selected)
9672
9673 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9674 $.each( saveRemoteData, function( key, value ) {
9675 if (key == selected)
9676 {
9677 console.log("selectArrayFilter - Do a redirect to "+value.url)
9678 location.assign(value.url);
9679 }
9680 });
9681 });' : '') . '
9682
9683 });
9684 </script>';
9685 }
9686
9687 if ($acceptdelayedhtml) {
9688 $delayedhtmlcontent .= $outdelayed;
9689 } else {
9690 $out .= $outdelayed;
9691 }
9692 return $out;
9693 }
9694
9713 public static function multiselectarray($htmlname, $array, $selected = array(), $key_in_label = 0, $value_as_key = 0, $morecss = '', $translate = 0, $width = 0, $moreattrib = '', $nu = '', $placeholder = '', $addjscombo = -1)
9714 {
9715 global $conf, $langs;
9716 $out = '';
9717
9718 if ($addjscombo < 0) {
9719 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9720 $addjscombo = 1;
9721 } else {
9722 $addjscombo = 0;
9723 }
9724 }
9725
9726 $useenhancedmultiselect = 0;
9727 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9728 if ($addjscombo) {
9729 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9730 }
9731 }
9732
9733 $out .= '<span class="multiselectarray'.$htmlname.'">';
9734
9735 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9736 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9737 // submitted to nothing.
9738 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9739 // Output select component
9740 $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";
9741 if (is_array($array) && !empty($array)) {
9742 if ($value_as_key) {
9743 $array = array_combine($array, $array);
9744 }
9745
9746 if (!empty($array)) {
9747 foreach ($array as $key => $value) {
9748 $tmpkey = $key;
9749 $tmpvalue = $value;
9750 $tmpcolor = '';
9751 $tmppicto = '';
9752 $tmplabelhtml = '';
9753 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9754 $tmpkey = $value['id'];
9755 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9756 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9757 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9758 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']) : $value['labelhtml'];
9759 }
9760 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9761 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9762
9763 $out .= '<option value="' . $tmpkey . '"';
9764 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9765 $out .= ' selected';
9766 }
9767 if (!empty($tmplabelhtml)) {
9768 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9769 } else {
9770 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9771 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9772 }
9773 $out .= '>';
9774 $out .= dol_htmlentitiesbr($newval);
9775 $out .= '</option>' . "\n";
9776 }
9777 }
9778 }
9779 $out .= '</select>' . "\n";
9780
9781 $out .= '</span>';
9782
9783 // Add code for jquery to use multiselect
9784 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9785 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9786 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9787 if ($addjscombo == 1) {
9788 $tmpplugin = getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT', (defined('REQUIRE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : 'select2'));
9789
9790 // If property data-html set, we decode html entities and use this.
9791 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9792 // TODO Move this into common js ?
9793 $out .= 'function formatResult(record, container) {' . "\n";
9794 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9795 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9796 $out .= ' }'."\n";
9797 $out .= ' return record.text;';
9798 $out .= '}' . "\n";
9799
9800 $out .= 'function formatSelection(record) {' . "\n";
9801 $out .= ' return record.text;';
9802 $out .= '}' . "\n";
9803
9804 // Load the select2 enhancer
9805 //$out .= 'console.log(\'addjscombo=1 for htmlname=' . dol_escape_js($htmlname) . '\');';
9806 $out .= '$(document).ready(function () {
9807 $(\'#' . dol_escape_js($htmlname) . '\').' . $tmpplugin . '({';
9808 if ($placeholder) {
9809 $out .= '
9810 placeholder: {
9811 id: \'-1\',
9812 text: \''.dol_escape_js($placeholder).'\'
9813 },';
9814 }
9815 $out .= ' dir: \'ltr\',
9816 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9817 dropdownCssClass: \'' . dol_escape_js($morecss) . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
9818 // Specify format function for dropdown item
9819 formatResult: formatResult,
9820 templateResult: formatResult, /* For 4.0 */
9821 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9822 // Specify format function for selected item
9823 formatSelection: formatSelection,
9824 templateSelection: formatSelection, /* For 4.0 */
9825 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage
9826 });
9827
9828 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are shown dynamically after load, because select2 set
9829 the size only if component is not hidden by default on load */
9830 $(\'#' . dol_escape_js($htmlname) . ' + .select2\').addClass(\'' . dol_escape_js($morecss) . '\');
9831 });' . "\n";
9832 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9833 // Add other js lib
9834 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9835 // ...
9836 $out .= 'console.log(\'addjscombo=2 for htmlname=' . dol_escape_js($htmlname) . '\');';
9837 $out .= '$(document).ready(function () {
9838 $(\'#' . dol_escape_js($htmlname) . '\').multiSelect({
9839 containerHTML: \'<div class="multi-select-container">\',
9840 menuHTML: \'<div class="multi-select-menu">\',
9841 buttonHTML: \'<span class="multi-select-button ' . dol_escape_js($morecss) . '">\',
9842 menuItemHTML: \'<label class="multi-select-menuitem">\',
9843 activeClass: \'multi-select-container--open\',
9844 noneText: \'' . dol_escape_js($placeholder) . '\'
9845 });
9846 })';
9847 }
9848 $out .= '</script>';
9849 }
9850
9851 return $out;
9852 }
9853
9854
9866 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9867 {
9868 global $conf, $langs, $user;
9869
9870 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9871 return '';
9872 }
9873 if (empty($array)) {
9874 return '';
9875 }
9876
9877 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9878
9879 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9880 $tmparray = explode(',', $user->conf->$tmpvar);
9881 foreach ($array as $key => $val) {
9882 //var_dump($key);
9883 //var_dump($tmparray);
9884 if (in_array($key, $tmparray)) {
9885 $array[$key]['checked'] = 1;
9886 } else {
9887 $array[$key]['checked'] = 0;
9888 }
9889 }
9890 } else { // There is no list of fields already customized for user
9891 foreach ($array as $key => $val) {
9892 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9893 $array[$key]['checked'] = 0;
9894 }
9895 }
9896 }
9897
9898 $listoffieldsforselection = '';
9899 $listcheckedstring = '';
9900
9901 foreach ($array as $key => $val) {
9902 // var_dump($val);
9903 // var_dump(array_key_exists('enabled', $val));
9904 // var_dump(!$val['enabled']);
9905 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9906 unset($array[$key]); // We don't want this field
9907 continue;
9908 }
9909 if (!empty($val['type']) && $val['type'] == 'separate') {
9910 // Field remains in array but we don't add it into $listoffieldsforselection
9911 //$listoffieldsforselection .= '<li>-----</li>';
9912 continue;
9913 }
9914 if (!empty($val['label']) && $val['label']) {
9915 if (!empty($val['langfile']) && is_object($langs)) {
9916 $langs->load($val['langfile']);
9917 }
9918
9919 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9920 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((!array_key_exists('checked', $val) || empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . ' data-position="'.(empty($val['position']) ? '' : $val['position']).'" />';
9921 $listoffieldsforselection .= '<label for="checkbox' . $key . '" class="paddingleft">';
9922 $listoffieldsforselection .= dolPrintHTML(dol_string_nohtmltag($langs->trans($val['label'])));
9923 $listoffieldsforselection .= '</label></li>';
9924 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9925 }
9926 }
9927
9928 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9929
9930 <dl class="dropdown">
9931 <dt>
9932 <a href="#' . $htmlname . '">
9933 ' . img_picto('', 'list') . '
9934 </a>
9935 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9936 </dt>
9937 <dd class="dropdowndd">
9938 <div class="multiselectcheckbox'.$htmlname.'">
9939 <ul class="'.$htmlname.(((string) $pos == '1' || (string) $pos == 'left') ? 'left' : '').'">
9940 <li class="liinputsearch">
9941 <input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'">
9942 </li>
9943 '.$listoffieldsforselection.'
9944 </ul>
9945 </div>
9946 </dd>
9947 </dl>
9948
9949 <script nonce="' . getNonce() . '" type="text/javascript">
9950 jQuery(document).ready(function () {
9951 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on("click", function () {
9952 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9953
9954 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9955
9956 var title = $(this).val() + ",";
9957 if ($(this).is(\':checked\')) {
9958 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9959 }
9960 else {
9961 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9962 }
9963 // Now, we submit page
9964 //$(this).parents(\'form:first\').submit();
9965 });
9966
9967 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9968 console.log("keyup on inputsearch_dropdownselectedfields");
9969 var value = $(this).val().toLowerCase();
9970 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9971 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9972 });
9973 });
9974 ';
9975 if (empty($conf->browser->layout) || $conf->browser->layout != 'phone') {
9976 $out .= '
9977 $(".dropdown dt a").on("click", function () {
9978 console.log("Click on dropdown, we set focus to search field");
9979 setTimeout(() => { $(\'.inputsearch_dropdownselectedfields\').focus(); }, 200);
9980 });';
9981 }
9982 $out .= '
9983 });
9984 </script>
9985
9986 ';
9987 return $out;
9988 }
9989
9999 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
10000 {
10001 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
10002
10003 $cat = new Categorie($this->db);
10004 $categories = $cat->containing($id, $type);
10005
10006 if ($rendermode == 1) {
10007 $toprint = array();
10008 foreach ($categories as $c) {
10009 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
10010 foreach ($ways as $way) {
10011 $color = $c->color;
10012 $sfortag = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($color ? ' style="background: #' . $color . ';"' : ' style="background: #bbb"') . '>';
10013 $sfortag .= $way;
10014 $sfortag .= '</li>';
10015 $toprint[] = $sfortag;
10016 }
10017 }
10018 if (empty($toprint)) {
10019 return '';
10020 } else {
10021 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
10022 }
10023 }
10024
10025 if ($rendermode == 0) {
10026 $arrayselected = array();
10027 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
10028 foreach ($categories as $c) {
10029 $arrayselected[(string) $c->id] = (string) $c->id;
10030 }
10031
10032 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
10033 }
10034
10035 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
10036 }
10037
10047 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
10048 {
10049 global $conf, $langs, $hookmanager;
10050 global $action;
10051
10052 $object->fetchObjectLinked();
10053
10054 // Bypass the default method
10055 $hookmanager->initHooks(array('commonobject'));
10056 $parameters = array(
10057 'morehtmlright' => $morehtmlright,
10058 'compatibleImportElementsList' => &$compatibleImportElementsList,
10059 );
10060 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
10061
10062 $nbofdifferenttypes = count($object->linkedObjects);
10063
10064 if (empty($reshook)) {
10065 print '<!-- showLinkedObjectBlock -->';
10066 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, '', 'showlinkedobjectblock');
10067
10068
10069 print '<div class="div-table-responsive-no-min">';
10070 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
10071
10072 print '<tr class="liste_titre">';
10073 print '<td>' . $langs->trans("Type") . '</td>';
10074 print '<td>' . $langs->trans("Ref") . '</td>';
10075 print '<td class="center"></td>';
10076 print '<td class="center">' . $langs->trans("Date") . '</td>';
10077 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
10078 print '<td class="right">' . $langs->trans("Status") . '</td>';
10079 print '<td></td>';
10080 print '</tr>';
10081
10082 $nboftypesoutput = 0;
10083
10084 foreach ($object->linkedObjects as $objecttype => $objects) {
10085 $tplpath = $element = $subelement = $objecttype;
10086
10087 // to display import button on tpl
10088 $showImportButton = false;
10089 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
10090 $showImportButton = true;
10091 }
10092
10093 $regs = array();
10094
10095 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
10096 $element = $regs[1];
10097 $subelement = $regs[2];
10098 $tplpath = $element . '/' . $subelement;
10099 }
10100 $tplname = 'linkedobjectblock';
10101
10102 // If we ask a resource form external module (instead of default path)
10103 if (preg_match('/^([^@]+)@([^@]+)$/i', $objecttype, $regs)) { // 'myobject@mymodule'
10104 $element = $regs[1];
10105 $module = $regs[2];
10106 $tplpath = $module. '/' . $element;
10107 $tplname = $tplname.'_'.$element;
10108 }
10109
10110 // To work with non standard path
10111 if ($objecttype == 'facture') {
10112 $tplpath = 'compta/' . $element;
10113 if (!isModEnabled('invoice')) {
10114 continue; // Do not show if module disabled
10115 }
10116 } elseif ($objecttype == 'facturerec') {
10117 $tplpath = 'compta/facture';
10118 $tplname = 'linkedobjectblockForRec';
10119 if (!isModEnabled('invoice')) {
10120 continue; // Do not show if module disabled
10121 }
10122 } elseif ($objecttype == 'propal') {
10123 $tplpath = 'comm/' . $element;
10124 if (!isModEnabled('propal')) {
10125 continue; // Do not show if module disabled
10126 }
10127 } elseif ($objecttype == 'supplier_proposal') {
10128 if (!isModEnabled('supplier_proposal')) {
10129 continue; // Do not show if module disabled
10130 }
10131 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
10132 $tplpath = 'expedition';
10133 if (!isModEnabled('shipping')) {
10134 continue; // Do not show if module disabled
10135 }
10136 } elseif ($objecttype == 'reception') {
10137 $tplpath = 'reception';
10138 if (!isModEnabled('reception')) {
10139 continue; // Do not show if module disabled
10140 }
10141 } elseif ($objecttype == 'delivery') {
10142 $tplpath = 'delivery';
10143 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
10144 continue; // Do not show if sub module disabled
10145 }
10146 } elseif ($objecttype == 'ficheinter') {
10147 $tplpath = 'fichinter';
10148 if (!isModEnabled('intervention')) {
10149 continue; // Do not show if module disabled
10150 }
10151 } elseif ($objecttype == 'invoice_supplier') {
10152 $tplpath = 'fourn/facture';
10153 } elseif ($objecttype == 'order_supplier') {
10154 $tplpath = 'fourn/commande';
10155 } elseif ($objecttype == 'expensereport') {
10156 $tplpath = 'expensereport';
10157 } elseif ($objecttype == 'subscription') {
10158 $tplpath = 'adherents';
10159 } elseif ($objecttype == 'conferenceorbooth') {
10160 $tplpath = 'eventorganization';
10161 } elseif ($objecttype == 'conferenceorboothattendee') {
10162 $tplpath = 'eventorganization';
10163 } elseif ($objecttype == 'mo') {
10164 $tplpath = 'mrp';
10165 if (!isModEnabled('mrp')) {
10166 continue; // Do not show if module disabled
10167 }
10168 } elseif ($objecttype == 'project_task') {
10169 $tplpath = 'projet/tasks';
10170 }
10171
10172 global $linkedObjectBlock;
10173 $linkedObjectBlock = $objects;
10174
10175 // Output template part (modules that overwrite templates must declare this into descriptor)
10176 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
10177
10178 foreach ($dirtpls as $reldir) {
10179 $reldir = rtrim($reldir, '/');
10180 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
10181 global $noMoreLinkedObjectBlockAfter;
10182 $noMoreLinkedObjectBlockAfter = 1;
10183 }
10184
10185 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
10186 if ($res) {
10187 $nboftypesoutput++;
10188 break;
10189 }
10190 }
10191 }
10192
10193 if (!$nboftypesoutput) {
10194 print '<tr><td colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
10195 }
10196
10197 print '</table>';
10198
10199 if (!empty($compatibleImportElementsList)) {
10200 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
10201 }
10202
10203 print '</div>';
10204 }
10205
10206 return $nbofdifferenttypes;
10207 }
10208
10218 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array(), $nooutput = 0)
10219 {
10220 global $conf, $langs, $hookmanager, $form;
10221 global $action;
10222
10223 if (empty($form)) {
10224 $form = new Form($this->db);
10225 }
10226
10227 $linktoelem = '';
10228 $linktoelemlist = '';
10229 $listofidcompanytoscan = '';
10230
10231 if (!is_object($object->thirdparty)) {
10232 $object->fetch_thirdparty();
10233 }
10234
10235 $possiblelinks = array();
10236
10237 $dontIncludeCompletedItems = getDolGlobalString('DONT_INCLUDE_COMPLETED_ELEMENTS_LINKS');
10238
10239 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
10240 $listofidcompanytoscan = (int) $object->thirdparty->id;
10241 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
10242 $listofidcompanytoscan .= ',' . (int) $object->thirdparty->parent;
10243 }
10244 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
10245 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10246 $tmpproject = new Project($this->db);
10247 $tmpproject->fetch($object->fk_project);
10248 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
10249 $listofidcompanytoscan .= ',' . (int) $tmpproject->socid;
10250 }
10251 unset($tmpproject);
10252 }
10253
10254 $possiblelinks = array(
10255 'propal' => array(
10256 'enabled' => isModEnabled('propal'),
10257 'perms' => 1,
10258 'label' => 'LinkToProposal',
10259 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('propal') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 4' : ''),
10260 ),
10261 'shipping' => array(
10262 'enabled' => isModEnabled('shipping'),
10263 'perms' => 1,
10264 'label' => 'LinkToExpedition',
10265 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "expedition as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('shipping') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 2' : ''),
10266 ),
10267 'order' => array(
10268 'enabled' => isModEnabled('order'),
10269 'perms' => 1,
10270 'label' => 'LinkToOrder',
10271 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('commande') . ')'.($dontIncludeCompletedItems ? ' AND t.facture < 1' : ''),
10272 'linkname' => 'commande',
10273 'subscription' => array(
10274 'enabled' => isModEnabled('member'),
10275 'perms' => 1,
10276 'label' => 'LinkToMemberSubscription',
10277 'sql' => "SELECT a.fk_soc as socid, CONCAT(a.firstname, ' ', a.lastname) as name, a.entity as client, sub.rowid, sub.note as ref, '' as ref_client, sub.subscription as total_ht FROM " . $this->db->prefix() . "adherent as a, " . $this->db->prefix() . "subscription as sub WHERE sub.fk_adherent = a.rowid AND a.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND a.entity IN (' . getEntity('subscription') . ')',
10278 'linkname' => 'subscription'),
10279 ),
10280 'invoice' => array(
10281 'enabled' => isModEnabled('invoice'),
10282 'perms' => 1,
10283 'label' => 'LinkToInvoice',
10284 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('invoice') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : ''),
10285 'linkname' => 'facture',
10286 ),
10287 'invoice_template' => array(
10288 'enabled' => isModEnabled('invoice'),
10289 'perms' => 1,
10290 'label' => 'LinkToTemplateInvoice',
10291 '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') . ')',
10292 ),
10293 'contrat' => array(
10294 'enabled' => isModEnabled('contract'),
10295 'perms' => 1,
10296 'label' => 'LinkToContract',
10297 '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
10298 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',
10299 ),
10300 'fichinter' => array(
10301 'enabled' => isModEnabled('intervention'),
10302 'perms' => 1,
10303 'label' => 'LinkToIntervention',
10304 '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') . ')',
10305 ),
10306 'supplier_proposal' => array(
10307 'enabled' => isModEnabled('supplier_proposal'),
10308 'perms' => 1,
10309 'label' => 'LinkToSupplierProposal',
10310 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('supplier_proposal') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 4' : ''),
10311 ),
10312 'order_supplier' => array(
10313 'enabled' => isModEnabled("supplier_order"),
10314 'perms' => 1,
10315 'label' => 'LinkToSupplierOrder',
10316 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('commande_fournisseur') . ')'.($dontIncludeCompletedItems ? ' AND t.billed < 1' : ''),
10317 ),
10318 'invoice_supplier' => array(
10319 'enabled' => isModEnabled("supplier_invoice"),
10320 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
10321 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('facture_fourn') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : ''),
10322 ),
10323 'ticket' => array(
10324 'enabled' => isModEnabled('ticket'),
10325 'perms' => 1,
10326 'label' => 'LinkToTicket',
10327 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('ticket') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 8' : ''),
10328 ),
10329 'mo' => array(
10330 'enabled' => isModEnabled('mrp'),
10331 'perms' => 1,
10332 'label' => 'LinkToMo',
10333 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM " . $this->db->prefix() . "societe as s INNER JOIN " . $this->db->prefix() . "mrp_mo as t ON t.fk_soc = s.rowid WHERE t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('mo') . ')'.($dontIncludeCompletedItems ? ' AND t.status < 3' : ''),
10334 ),
10335 );
10336 }
10337
10338 if ($object->table_element == 'commande_fournisseur') {
10339 $possiblelinks['mo']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM ".$this->db->prefix()."societe as s INNER JOIN ".$this->db->prefix().'mrp_mo as t ON t.fk_soc = s.rowid WHERE t.entity IN ('.getEntity('mo').')'.($dontIncludeCompletedItems ? ' AND t.status < 3' : '');
10340 } elseif ($object->table_element == 'mrp_mo') {
10341 $possiblelinks['order_supplier']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix().'commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.entity IN ('.getEntity('commande_fournisseur').')'.($dontIncludeCompletedItems ? ' AND t.billed < 1' : '');
10342 }
10343
10344 $reshook = 0; // Ensure $reshook is defined for static analysis
10345 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
10346 // Can complete the possiblelink array
10347 $hookmanager->initHooks(array('commonobject'));
10348 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
10349 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
10350 }
10351
10352 if (empty($reshook)) {
10353 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
10354 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
10355 }
10356 } elseif ($reshook > 0) {
10357 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
10358 $possiblelinks = $hookmanager->resArray;
10359 }
10360 }
10361
10362 if (!empty($possiblelinks)) {
10363 $object->fetchObjectLinked();
10364 }
10365
10366 // Build the html part with possible suggested links
10367 $htmltoenteralink = '';
10368 foreach ($possiblelinks as $key => $possiblelink) {
10369 $num = 0;
10370 if (empty($possiblelink['enabled'])) {
10371 continue;
10372 }
10373
10374
10375 // If we ask a resource form external module (instead of default path)
10376 $module='';
10377 if (preg_match('/^([^@]+)@([^@]+)$/i', $key, $regs)) { // 'myobject@mymodule'
10378 $key = $regs[1];
10379 $module=$regs[2];
10380 }
10381
10382 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
10383 $htmltoenteralink .= '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
10384
10385 // Section for free ref input
10386 if (!getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10387 $htmltoenteralink .= '<br>'."\n";
10388 $htmltoenteralink .= '<!-- form to add a link from anywhere -->'."\n";
10389 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
10390 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
10391 $htmltoenteralink .= '<input type="hidden" name="action" value="addlinkbyref">';
10392 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
10393 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key .(!empty($module)?'@'.$module:''). '">';
10394 $htmltoenteralink .= '<table class="noborder">';
10395 $htmltoenteralink .= '<tr class="liste_titre">';
10396 //print '<td>' . $langs->trans("Ref") . '</td>';
10397 $htmltoenteralink .= '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
10398 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
10399 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
10400 $htmltoenteralink .= '</tr>';
10401 $htmltoenteralink .= '</table>';
10402 $htmltoenteralink .= '</form>';
10403 }
10404
10405 $sql = $possiblelink['sql'];
10406
10407 $resqllist = $this->db->query($sql);
10408 if ($resqllist) {
10409 $num = $this->db->num_rows($resqllist);
10410 $i = 0;
10411
10412 if ($num > 0) {
10413 // Section for free predefined list
10414 if (getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10415 $htmltoenteralink .= '<br>';
10416 }
10417 $htmltoenteralink .= '<!-- form to add a link from object to same thirdparty -->'."\n";
10418 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
10419 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
10420 $htmltoenteralink .= '<input type="hidden" name="action" value="addlink">';
10421 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
10422 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . (!empty($module)?'@'.$module:''). '">';
10423 $htmltoenteralink .= '<table class="noborder">';
10424 $htmltoenteralink .= '<tr class="liste_titre">';
10425 $htmltoenteralink .= '<td class="nowrap"></td>';
10426 $htmltoenteralink .= '<td>' . $langs->trans("Ref") . '</td>';
10427 $htmltoenteralink .= '<td>' . $langs->trans("RefCustomer") . '</td>';
10428 $htmltoenteralink .= '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
10429 $htmltoenteralink .= '<td>' . $langs->trans("Company") . '</td>';
10430 $htmltoenteralink .= '</tr>';
10431 while ($i < $num) {
10432 $objp = $this->db->fetch_object($resqllist);
10433 $alreadylinked = false;
10434 if (!empty($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key])) {
10435 if (in_array($objp->rowid, array_values($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key]))) {
10436 $alreadylinked = true;
10437 }
10438 }
10439 $htmltoenteralink .= '<tr class="oddeven">';
10440 $htmltoenteralink .= '<td>';
10441 if ($alreadylinked) {
10442 $htmltoenteralink .= img_picto('', 'link');
10443 } else {
10444 $htmltoenteralink .= '<input type="checkbox" name="idtolinkto[' . $key . '_' . $objp->rowid . ']" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
10445 }
10446 $htmltoenteralink .= '</td>';
10447 $htmltoenteralink .= '<td><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
10448 $htmltoenteralink .= '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
10449 $htmltoenteralink .= '<td class="right">';
10450 if ($possiblelink['label'] == 'LinkToContract') {
10451 $htmltoenteralink .= $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
10452 }
10453 $htmltoenteralink .= '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
10454 $htmltoenteralink .= '</td>';
10455 $htmltoenteralink .= '<td>' . $objp->name . '</td>';
10456 $htmltoenteralink .= '</tr>';
10457 $i++;
10458 }
10459 $htmltoenteralink .= '</table>';
10460 $htmltoenteralink .= '<div class="center">';
10461 if ($num) {
10462 $htmltoenteralink .= '<input type="submit" class="button valignmiddle marginleftonly marginrightonly smallpaddingimp" value="' . $langs->trans('ToLink') . '">';
10463 }
10464 if (empty($conf->use_javascript_ajax)) {
10465 $htmltoenteralink .= '<input type="submit" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
10466 } else {
10467 $htmltoenteralink .= '<input type="submit" onclick="jQuery(\'#' . $key . 'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
10468 }
10469 $htmltoenteralink .= '</form>';
10470 }
10471
10472 $this->db->free($resqllist);
10473 } else {
10474 dol_print_error($this->db);
10475 }
10476 $htmltoenteralink .= '</div>';
10477
10478
10479 // Complete the list for the combo box
10480 if ($num > 0 || !getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10481 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
10482 // } else $linktoelem.=$langs->trans($possiblelink['label']);
10483 } else {
10484 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
10485 }
10486 }
10487 }
10488
10489 if ($linktoelemlist) {
10490 $linktoelem = '
10491 <dl class="dropdown" id="linktoobjectname">
10492 ';
10493 if (!empty($conf->use_javascript_ajax)) {
10494 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
10495 }
10496 $linktoelem .= '<dd>
10497 <div class="multiselectlinkto">
10498 <ul class="ulselectedfields">' . $linktoelemlist . '
10499 </ul>
10500 </div>
10501 </dd>
10502 </dl>';
10503 } else {
10504 $linktoelem = '';
10505 }
10506
10507 if (!empty($conf->use_javascript_ajax)) {
10508 print '<!-- Add js to show linkto box -->
10509 <script nonce="' . getNonce() . '">
10510 jQuery(document).ready(function() {
10511 jQuery(".linkto").click(function() {
10512 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
10513 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
10514 });
10515 });
10516 </script>
10517 ';
10518 }
10519
10520 if ($nooutput) {
10521 return array('linktoelem' => $linktoelem, 'htmltoenteralink' => $htmltoenteralink);
10522 } else {
10523 print $htmltoenteralink;
10524 }
10525
10526 return $linktoelem;
10527 }
10528
10543 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'width75', $labelyes = 'Yes', $labelno = 'No')
10544 {
10545 global $langs;
10546
10547 $yes = "yes";
10548 $no = "no";
10549 if ($option) {
10550 $yes = "1";
10551 $no = "0";
10552 }
10553
10554 $disabled = ($disabled ? ' disabled' : '');
10555
10556 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
10557 if ($useempty) {
10558 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10559 }
10560 if (("$value" == 'yes') || ($value == 1)) {
10561 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
10562 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
10563 } else {
10564 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
10565 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
10566 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
10567 }
10568 $resultyesno .= '</select>' . "\n";
10569
10570 if ($addjscombo) {
10571 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
10572 }
10573
10574 return $resultyesno;
10575 }
10576
10577 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10578
10588 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
10589 {
10590 // phpcs:enable
10591 $sql = "SELECT rowid, label";
10592 $sql .= " FROM " . $this->db->prefix() . "export_model";
10593 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
10594 $sql .= " ORDER BY rowid";
10595 $result = $this->db->query($sql);
10596 if ($result) {
10597 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
10598 if ($useempty) {
10599 print '<option value="-1">&nbsp;</option>';
10600 }
10601
10602 $num = $this->db->num_rows($result);
10603 $i = 0;
10604 while ($i < $num) {
10605 $obj = $this->db->fetch_object($result);
10606 if ($selected == $obj->rowid) {
10607 print '<option value="' . $obj->rowid . '" selected>';
10608 } else {
10609 print '<option value="' . $obj->rowid . '">';
10610 }
10611 print $obj->label;
10612 print '</option>';
10613 $i++;
10614 }
10615 print "</select>";
10616 } else {
10617 dol_print_error($this->db);
10618 }
10619 }
10620
10639 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
10640 {
10641 global $conf, $langs, $hookmanager, $extralanguages;
10642
10643 $ret = '';
10644 if (empty($fieldid)) {
10645 $fieldid = 'rowid';
10646 }
10647 if (empty($fieldref)) {
10648 $fieldref = 'ref';
10649 }
10650
10651 // Preparing gender's display if there is one
10652 $addgendertxt = '';
10653 if (property_exists($object, 'gender') && !empty($object->gender)) {
10654 $addgendertxt = ' ';
10655 switch ($object->gender) {
10656 case 'man':
10657 $addgendertxt .= '<i class="fas fa-mars valignmiddle"></i>';
10658 break;
10659 case 'woman':
10660 $addgendertxt .= '<i class="fas fa-venus valignmiddle"></i>';
10661 break;
10662 case 'other':
10663 $addgendertxt .= '<i class="fas fa-transgender valignmiddle"></i>';
10664 break;
10665 }
10666 }
10667
10668 // Add where from hooks
10669 if (is_object($hookmanager)) {
10670 $parameters = array('showrefnav' => true);
10671 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
10672 if (!empty($hookmanager->resPrint)) {
10673 if (empty($object->next_prev_filter) && preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10674 $object->next_prev_filter = preg_replace('/^\s*AND\s*/i', '', $hookmanager->resPrint);
10675 } elseif (!empty($object->next_prev_filter) && !preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10676 $object->next_prev_filter .= ' AND '.$hookmanager->resPrint;
10677 } else {
10678 $object->next_prev_filter .= $hookmanager->resPrint;
10679 }
10680 }
10681 }
10682
10683 $previous_ref = $next_ref = '';
10684 if ($shownav) {
10685 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
10686 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
10687
10688 $navurl = $_SERVER["PHP_SELF"];
10689 // Special case for project/task page
10690 if ($paramid == 'project_ref') {
10691 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
10692 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
10693 $paramid = 'ref';
10694 }
10695 }
10696
10697 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
10698 // accesskey is for Mac: CTRL + key for all browsers
10699 $stringforfirstkey = $langs->trans("KeyboardShortcut");
10700 if ($conf->browser->name == 'chrome') {
10701 $stringforfirstkey .= ' ALT +';
10702 } elseif ($conf->browser->name == 'firefox') {
10703 $stringforfirstkey .= ' ALT + SHIFT +';
10704 } else {
10705 $stringforfirstkey .= ' CTL +';
10706 }
10707
10708 $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>';
10709 $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>';
10710 }
10711
10712 //print "xx".$previous_ref."x".$next_ref;
10713 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
10714
10715 // Right part of banner
10716 if ($morehtmlright) {
10717 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
10718 }
10719
10720 if ($previous_ref || $next_ref || $morehtml) {
10721 $ret .= '<div class="pagination paginationref"><ul class="right">';
10722 }
10723 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
10724 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
10725 }
10726 if ($shownav && ($previous_ref || $next_ref)) {
10727 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
10728 $ret .= '<li class="pagination">' . $next_ref . '</li>';
10729 }
10730 if ($previous_ref || $next_ref || $morehtml) {
10731 $ret .= '</ul></div>';
10732 }
10733
10734 // Status
10735 $parameters = array('morehtmlstatus' => $morehtmlstatus);
10736 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
10737 if (empty($reshook)) {
10738 $morehtmlstatus .= $hookmanager->resPrint;
10739 } else {
10740 $morehtmlstatus = $hookmanager->resPrint;
10741 }
10742 if ($morehtmlstatus) {
10743 $ret .= '<!-- status --><div class="statusref">' . $morehtmlstatus . '</div>';
10744 }
10745
10746 $parameters = array();
10747 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
10748 if (empty($reshook)) {
10749 $morehtmlref .= $hookmanager->resPrint;
10750 } elseif ($reshook > 0) {
10751 $morehtmlref = $hookmanager->resPrint;
10752 }
10753
10754 // Left part of banner
10755 if ($morehtmlleft) {
10756 if ($conf->browser->layout == 'phone') {
10757 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
10758 } else {
10759 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
10760 }
10761 }
10762
10763 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
10764 $ret .= '<!-- Ref or ID --><div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
10765
10766 // For thirdparty, contact, user, member, the ref is the id, so we show something else
10767 if ($object->element == 'societe') {
10768 $ret .= dol_htmlentities((string) $object->name);
10769
10770 // List of extra languages
10771 $arrayoflangcode = array();
10772 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
10773 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
10774 }
10775
10776 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
10777 if (!is_object($extralanguages)) {
10778 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
10779 $extralanguages = new ExtraLanguages($this->db);
10780 }
10781 $extralanguages->fetch_name_extralanguages('societe');
10782
10783 // Guard against PHP 8 'Undefined array key' when MAIN_USE_ALTERNATE_TRANSLATION_FOR
10784 // is not configured and fetch_name_extralanguages() leaves attributes empty (issue #34596).
10785 if (!empty($extralanguages->attributes['societe']) && !empty($extralanguages->attributes['societe']['name'])) {
10786 $object->fetchValuesForExtraLanguages();
10787
10788 $htmltext = '';
10789 // If there is extra languages
10790 foreach ($arrayoflangcode as $extralangcode) {
10791 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
10792 if ($object->array_languages['name'][$extralangcode]) {
10793 $htmltext .= $object->array_languages['name'][$extralangcode];
10794 } else {
10795 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
10796 }
10797 }
10798 $ret .= '<!-- Show translations of name -->' . "\n";
10799 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
10800 }
10801 }
10802 } elseif ($object->element == 'member') {
10803 '@phan-var-force Adherent $object';
10804 $ret .= $object->ref . '<br>';
10805 $fullname = $object->getFullName($langs);
10806 if ($object->morphy == 'mor' && $object->societe) {
10807 $ret .= dol_htmlentities((string) $object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
10808 } else {
10809 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities((string) $object->societe) . ')' : '');
10810 }
10811 } elseif (in_array($object->element, array('contact', 'user'))) {
10812 $ret .= '<span class="valignmiddle">'.dol_htmlentities($object->getFullName($langs)).'</span>'.$addgendertxt;
10813 } elseif ($object->element == 'usergroup') {
10814 $ret .= dol_htmlentities((string) $object->name);
10815 } elseif (in_array($object->element, array('action', 'agenda'))) {
10816 '@phan-var-force ActionComm $object';
10817 $ret .= $object->ref . '<br>' . $object->label;
10818 } elseif (in_array($object->element, array('adherent_type'))) {
10819 $ret .= $object->label;
10820 } elseif ($object->element == 'ecm_directories') {
10821 $ret .= '';
10822 } elseif ($object->element == 'accountingbookkeeping' && !empty($object->context['mode']) && $object->context['mode'] == '_tmp') {
10823 $ret .= $langs->trans("Draft");
10824 } elseif ($fieldref != 'none') {
10825 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
10826 }
10827 if ($morehtmlref) {
10828 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
10829 if (substr($morehtmlref, 0, 4) != '<div') {
10830 $ret .= ' ';
10831 }
10832
10833 $ret .= '<!-- morehtmlref -->'.$morehtmlref;
10834 }
10835
10836 $ret .= '</div>';
10837
10838 $ret .= '</div><!-- End banner content -->';
10839
10840 return $ret;
10841 }
10842
10843
10852 public function showbarcode(&$object, $width = 100, $morecss = '')
10853 {
10854 global $conf;
10855
10856 //Check if barcode is filled in the card
10857 if (empty($object->barcode)) {
10858 return '';
10859 }
10860
10861 // Complete object if not complete
10862 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10863 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10864 $result = $object->fetchBarCode();
10865 //Check if fetchBarCode() failed
10866 if ($result < 1) {
10867 return '<!-- ErrorFetchBarcode -->';
10868 }
10869 }
10870
10871 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10872 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10873 $out = '<!-- url barcode = ' . $url . ' -->';
10874 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10875
10876 return $out;
10877 }
10878
10896 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10897 {
10898 global $conf, $langs;
10899
10900 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10901 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10902
10903 $dir = '';
10904 $file = '';
10905 $originalfile = '';
10906 $altfile = '';
10907 $email = '';
10908 $capture = '';
10909 if ($modulepart == 'societe') {
10910 $dir = $conf->societe->multidir_output[$entity];
10911 if (!empty($object->logo)) {
10912 if (dolIsAllowedForPreview($object->logo)) {
10913 if ((string) $imagesize == 'mini') {
10914 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10915 } elseif ((string) $imagesize == 'small') {
10916 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10917 } else {
10918 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10919 }
10920 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10921 }
10922 }
10923 $email = $object->email;
10924 } elseif ($modulepart == 'contact') {
10925 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10926 if (!empty($object->photo)) {
10927 if (dolIsAllowedForPreview($object->photo)) {
10928 if ((string) $imagesize == 'mini') {
10929 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10930 } elseif ((string) $imagesize == 'small') {
10931 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10932 } else {
10933 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10934 }
10935 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10936 }
10937 }
10938 $email = $object->email;
10939 $capture = 'user';
10940 } elseif ($modulepart == 'userphoto') {
10941 $dir = $conf->user->dir_output;
10942 if (!empty($object->photo)) {
10943 if (dolIsAllowedForPreview($object->photo)) {
10944 if ((string) $imagesize == 'mini') {
10945 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10946 } elseif ((string) $imagesize == 'small') {
10947 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10948 } else {
10949 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10950 }
10951 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10952 }
10953 }
10954 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10955 $altfile = $object->id . ".jpg"; // For backward compatibility
10956 }
10957 $email = $object->email;
10958 $capture = 'user';
10959 } elseif ($modulepart == 'memberphoto') {
10960 $dir = $conf->adherent->dir_output;
10961 if (!empty($object->photo)) {
10962 if (dolIsAllowedForPreview($object->photo)) {
10963 if ((string) $imagesize == 'mini') {
10964 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10965 } elseif ((string) $imagesize == 'small') {
10966 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10967 } else {
10968 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10969 }
10970 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10971 }
10972 }
10973 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10974 $altfile = $object->id . ".jpg"; // For backward compatibility
10975 }
10976 $email = $object->email;
10977 $capture = 'user';
10978 } else {
10979 // Generic case to show photos
10980 // TODO Implement this method in previous objects so we can always use this generic method.
10981 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10982 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10983
10984 $dir = $tmpdata['dir'];
10985 $file = $tmpdata['file'];
10986 $originalfile = $tmpdata['originalfile'];
10987 $altfile = $tmpdata['altfile'];
10988 $email = $tmpdata['email'];
10989 $capture = $tmpdata['capture'];
10990 }
10991 }
10992
10993 if ($forcecapture) {
10994 $capture = $forcecapture;
10995 }
10996
10997 $ret = '';
10998
10999 if ($dir) {
11000 if ($file && file_exists($dir . "/" . $file)) {
11001 if ($addlinktofullsize) {
11002 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
11003 if ($urladvanced) {
11004 $ret .= '<a href="' . $urladvanced . '">';
11005 } else {
11006 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
11007 }
11008 }
11009 $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 . '">';
11010 if ($addlinktofullsize) {
11011 $ret .= '</a>';
11012 }
11013 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
11014 if ($addlinktofullsize) {
11015 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
11016 if ($urladvanced) {
11017 $ret .= '<a href="' . $urladvanced . '">';
11018 } else {
11019 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
11020 }
11021 }
11022 $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 . '">';
11023 if ($addlinktofullsize) {
11024 $ret .= '</a>';
11025 }
11026 } else {
11027 $nophoto = '/public/theme/common/nophoto.png';
11028 $defaultimg = 'identicon'; // For gravatar
11029 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
11030 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
11031 $nophoto = 'company';
11032 } else {
11033 $nophoto = '/public/theme/common/user_anonymous.png';
11034 if (!empty($object->gender) && $object->gender == 'man') {
11035 $nophoto = '/public/theme/common/user_man.png';
11036 }
11037 if (!empty($object->gender) && $object->gender == 'woman') {
11038 $nophoto = '/public/theme/common/user_woman.png';
11039 }
11040 }
11041 }
11042
11043 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
11044 // see https://gravatar.com/site/implement/images/php/
11045 $ret .= '<!-- Put link to gravatar -->';
11046 $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
11047 } else {
11048 if ($nophoto == 'company') {
11049 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
11050 //$ret .= '<div class="difforspanimgright"></div>';
11051 } else {
11052 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
11053 }
11054 }
11055 }
11056
11057 if ($caneditfield) {
11058 if ($object->photo) {
11059 $ret .= "<br>\n";
11060 }
11061 $ret .= '<table class="nobordernopadding centpercent">';
11062 if ($object->photo) {
11063 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
11064 }
11065 $ret .= '<tr><td class="tdoverflow">';
11066 $maxfilesizearray = getMaxFileSizeArray();
11067 $maxmin = $maxfilesizearray['maxmin'];
11068 if ($maxmin > 0) {
11069 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
11070 }
11071 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . dolPrintHTMLForAttribute($capture) . '"' : '') . '>';
11072 $ret .= '</td></tr>';
11073 $ret .= '</table>';
11074 }
11075 }
11076
11077 return $ret;
11078 }
11079
11080 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11081
11098 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
11099 {
11100 // phpcs:enable
11101 global $conf, $user, $langs;
11102
11103 // Allow excluding groups
11104 $excludeGroups = null;
11105 if (is_array($exclude)) {
11106 $excludeGroups = implode(",", $exclude);
11107 }
11108 // Allow including groups
11109 $includeGroups = null;
11110 if (is_array($include)) {
11111 $includeGroups = implode(",", $include);
11112 }
11113
11114 if (!is_array($selected)) {
11115 $selected = array($selected);
11116 }
11117
11118 $out = '';
11119
11120 // Build sql to search groups
11121 $sql = "SELECT ug.rowid, ug.nom as name";
11122 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
11123 $sql .= ", e.label";
11124 }
11125 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
11126 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
11127 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
11128 if ($force_entity) {
11129 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
11130 } else {
11131 $sql .= " WHERE ug.entity IS NOT NULL";
11132 }
11133 } else {
11134 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
11135 }
11136 if (is_array($exclude) && $excludeGroups) {
11137 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
11138 }
11139 if (is_array($include) && $includeGroups) {
11140 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
11141 }
11142 $sql .= " ORDER BY ug.nom ASC";
11143
11144 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
11145 $resql = $this->db->query($sql);
11146 if ($resql) {
11147 // Enhance with select2
11148 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11149
11150 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
11151
11152 $num = $this->db->num_rows($resql);
11153 $i = 0;
11154 if ($num) {
11155 if ($show_empty && !$multiple) {
11156 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
11157 }
11158
11159 while ($i < $num) {
11160 $obj = $this->db->fetch_object($resql);
11161 $disableline = 0;
11162 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
11163 $disableline = 1;
11164 }
11165
11166 $label = $obj->name;
11167 $labelhtml = $obj->name;
11168 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
11169 $label .= " (" . $obj->label . ")";
11170 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
11171 }
11172
11173 $out .= '<option value="' . $obj->rowid . '"';
11174 if ($disableline) {
11175 $out .= ' disabled';
11176 }
11177 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
11178 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
11179 $out .= ' selected';
11180 }
11181 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
11182 $out .= '>';
11183 $out .= $label;
11184 $out .= '</option>';
11185 $i++;
11186 }
11187 } else {
11188 if ($show_empty) {
11189 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
11190 }
11191 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
11192 }
11193 $out .= '</select>';
11194
11195 $out .= ajax_combobox($htmlname);
11196 } else {
11197 dol_print_error($this->db);
11198 }
11199
11200 return $out;
11201 }
11202
11203
11210 public function showFilterButtons($pos = '')
11211 {
11212 $out = '<div class="nowraponall">';
11213 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
11214 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
11215 $out .= '</div>';
11216
11217 return $out;
11218 }
11219
11228 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
11229 {
11230 global $conf;
11231
11232 $out = '';
11233
11234 if (!empty($conf->use_javascript_ajax)) {
11235 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
11236 }
11237 $out .= '<script nonce="' . getNonce() . '">
11238 $(document).ready(function() {
11239 $("#' . $cssclass . 's").click(function() {
11240 if($(this).is(\':checked\')){
11241 console.log("We check all ' . $cssclass . ' and trigger the change method");
11242 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
11243 }
11244 else
11245 {
11246 console.log("We uncheck all");
11247 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
11248 }' . "\n";
11249 if ($calljsfunction) {
11250 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
11251 }
11252 $out .= ' });
11253 $(".' . $cssclass . '").change(function() {
11254 console.log("We check and change the tr class highlight after a change on .'.$cssclass.'");
11255 var $row = $(this).closest("tr");
11256 if ($row.length) {
11257 var anyChecked = $row.find(\'input[type="checkbox"].checkforselect:checked\').length > 0;
11258 console.log(anyChecked);
11259 if (!anyChecked) {
11260 $row.removeClass("highlight");
11261 } else {
11262 $row.addClass("highlight");
11263 }
11264 }
11265 });
11266 });
11267 </script>';
11268
11269 return $out;
11270 }
11271
11281 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
11282 {
11283 $out = $this->showFilterButtons();
11284 if ($addcheckuncheckall) {
11285 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
11286 }
11287 return $out;
11288 }
11289
11303 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
11304 {
11305 global $langs, $user;
11306
11307 $out = '';
11308 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
11309 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
11310 if (!empty($excludeid)) {
11311 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
11312 }
11313 $sql .= " ORDER BY label";
11314
11315 $resql = $this->db->query($sql);
11316 if ($resql) {
11317 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
11318 if ($useempty) {
11319 $out .= '<option value="0">&nbsp;</option>';
11320 }
11321
11322 while ($obj = $this->db->fetch_object($resql)) {
11323 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
11324 }
11325 $out .= '</select>';
11326 $out .= ajax_combobox('select_' . $htmlname);
11327
11328 if (!empty($htmlname) && $user->admin && $info_admin) {
11329 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11330 }
11331
11332 if (!empty($target)) {
11333 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
11334 $resql = $this->db->query($sql);
11335 if ($resql) {
11336 if ($this->db->num_rows($resql) > 0) {
11337 $obj = $this->db->fetch_object($resql);
11338 $out .= '<script nonce="' . getNonce() . '">
11339 $(function() {
11340 $("select[name=' . $target . ']").on("change", function() {
11341 var current_val = $(this).val();
11342 if (current_val == ' . $obj->id . ') {';
11343 if (!empty($default_selected) || !empty($selected)) {
11344 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
11345 }
11346
11347 $out .= '
11348 $("select[name=' . $htmlname . ']").change();
11349 }
11350 });
11351
11352 $("select[name=' . $htmlname . ']").change(function() {
11353
11354 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
11355 // get price of kilometer to fill the unit price
11356 $.ajax({
11357 method: "POST",
11358 dataType: "json",
11359 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
11360 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
11361 }).done(function( data, textStatus, jqXHR ) {
11362 console.log(data);
11363 if (typeof data.up != "undefined") {
11364 $("input[name=value_unit]").val(data.up);
11365 $("select[name=' . $htmlname . ']").attr("title", data.title);
11366 } else {
11367 $("input[name=value_unit]").val("");
11368 $("select[name=' . $htmlname . ']").attr("title", "");
11369 }
11370 });
11371 }
11372 });
11373 });
11374 </script>';
11375 }
11376 }
11377 }
11378 } else {
11379 dol_print_error($this->db);
11380 }
11381
11382 return $out;
11383 }
11384
11393 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
11394 {
11395 global $conf, $langs;
11396
11397 $out = '';
11398 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
11399 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
11400
11401 $resql = $this->db->query($sql);
11402 if ($resql) {
11403 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
11404 if ($useempty) {
11405 $out .= '<option value="0"></option>';
11406 }
11407
11408 while ($obj = $this->db->fetch_object($resql)) {
11409 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
11410 }
11411 $out .= '</select>';
11412 } else {
11413 dol_print_error($this->db);
11414 }
11415
11416 return $out;
11417 }
11418
11429 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
11430 {
11431 global $langs;
11432
11433 $out = '';
11434 $sql = "SELECT id, code, label";
11435 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
11436 $sql .= " WHERE active = 1";
11437
11438 $resql = $this->db->query($sql);
11439 if ($resql) {
11440 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
11441 if ($useempty) {
11442 $out .= '<option value="0"></option>';
11443 }
11444 if ($allchoice) {
11445 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
11446 }
11447
11448 $field = 'code';
11449 if ($useid) {
11450 $field = 'id';
11451 }
11452
11453 while ($obj = $this->db->fetch_object($resql)) {
11454 $key = $langs->trans($obj->code);
11455 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
11456 }
11457 $out .= '</select>';
11458
11459 $out .= ajax_combobox('select_'.$htmlname);
11460 } else {
11461 dol_print_error($this->db);
11462 }
11463
11464 return $out;
11465 }
11466
11485 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)
11486 {
11487 global $user, $conf, $langs;
11488
11489 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
11490
11491 if (is_null($usertofilter)) {
11492 $usertofilter = $user;
11493 }
11494
11495 $out = '';
11496
11497 $hideunselectables = false;
11498 if (getDolGlobalString('INVOICE_HIDE_UNSELECTABLES')) {
11499 $hideunselectables = true;
11500 }
11501
11502 if (empty($projectsListId)) {
11503 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
11504 $projectstatic = new Project($this->db);
11505 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
11506 }
11507 }
11508
11509 // Search all projects
11510 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
11511 p.title, p.fk_soc, p.fk_statut, p.public,";
11512 $sql .= ' s.nom as name';
11513 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
11514 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
11515 $sql .= ' ' . $this->db->prefix() . 'facture as f';
11516 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
11517 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
11518 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
11519 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
11520 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
11521 $sql .= " ORDER BY p.ref, f.ref ASC";
11522
11523 $resql = $this->db->query($sql);
11524 if ($resql) {
11525 // Use select2 selector
11526 if (!empty($conf->use_javascript_ajax)) {
11527 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11528 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11529 $out .= $comboenhancement;
11530 $morecss = 'minwidth200imp maxwidth500';
11531 }
11532
11533 if (empty($option_only)) {
11534 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11535 }
11536 if (!empty($show_empty)) {
11537 $out .= '<option value="0" class="optiongrey">';
11538 if (!is_numeric($show_empty)) {
11539 $out .= $show_empty;
11540 } else {
11541 $out .= '&nbsp;';
11542 }
11543 $out .= '</option>';
11544 }
11545 $num = $this->db->num_rows($resql);
11546 $i = 0;
11547 if ($num) {
11548 while ($i < $num) {
11549 $obj = $this->db->fetch_object($resql);
11550 // 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.
11551 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
11552 // Do nothing
11553 } else {
11554 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11555 $i++;
11556 continue;
11557 }
11558
11559 $labeltoshow = '';
11560
11561 if ($showproject == 'all') {
11562 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
11563 if ($obj->name) {
11564 $labeltoshow .= ' - ' . $obj->name; // Soc name
11565 }
11566
11567 $disabled = 0;
11568 if ($obj->fk_statut == Project::STATUS_DRAFT) {
11569 $disabled = 1;
11570 $labeltoshow .= ' - ' . $langs->trans("Draft");
11571 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
11572 if ($discard_closed == 2) {
11573 $disabled = 1;
11574 }
11575 $labeltoshow .= ' - ' . $langs->trans("Closed");
11576 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
11577 $disabled = 1;
11578 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
11579 }
11580 }
11581
11582 if (!empty($selected) && $selected == $obj->rowid) {
11583 $out .= '<option value="' . $obj->rowid . '" selected';
11584 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11585 $out .= '>' . $labeltoshow . '</option>';
11586 } else {
11587 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11588 $resultat = '';
11589 } else {
11590 $resultat = '<option value="' . $obj->rowid . '"';
11591 if ($disabled) {
11592 $resultat .= ' disabled';
11593 }
11594 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11595 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11596 $resultat .= '>';
11597 $resultat .= $labeltoshow;
11598 $resultat .= '</option>';
11599 }
11600 $out .= $resultat;
11601 }
11602 }
11603 $i++;
11604 }
11605 }
11606 if (empty($option_only)) {
11607 $out .= '</select>';
11608 }
11609
11610 $this->db->free($resql);
11611
11612 return $out;
11613 } else {
11614 dol_print_error($this->db);
11615 return '';
11616 }
11617 }
11618
11632 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11633 {
11634 global $conf, $langs;
11635
11636 $out = '';
11637
11638 dol_syslog('FactureRec::fetch', LOG_DEBUG);
11639
11640 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
11641 //$sql.= ', el.fk_source';
11642 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
11643 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
11644 $sql .= " ORDER BY f.titre ASC";
11645
11646 $resql = $this->db->query($sql);
11647 if ($resql) {
11648 // Use select2 selector
11649 if (!empty($conf->use_javascript_ajax)) {
11650 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11651 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11652 $out .= $comboenhancement;
11653 $morecss = 'minwidth200imp maxwidth500';
11654 }
11655
11656 if (empty($option_only)) {
11657 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11658 }
11659 if (!empty($show_empty)) {
11660 $out .= '<option value="0" class="optiongrey">';
11661 if (!is_numeric($show_empty)) {
11662 $out .= $show_empty;
11663 } else {
11664 $out .= '&nbsp;';
11665 }
11666 $out .= '</option>';
11667 }
11668 $num = $this->db->num_rows($resql);
11669 if ($num) {
11670 while ($obj = $this->db->fetch_object($resql)) {
11671 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
11672
11673 $disabled = 0;
11674 if (!empty($obj->suspended)) {
11675 $disabled = 1;
11676 $labeltoshow .= ' - ' . $langs->trans("Closed");
11677 }
11678
11679
11680 if (!empty($selected) && $selected == $obj->rowid) {
11681 $out .= '<option value="' . $obj->rowid . '" selected';
11682 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11683 $out .= '>' . $labeltoshow . '</option>';
11684 } else {
11685 if ($disabled && ($selected != $obj->rowid)) {
11686 $resultat = '';
11687 } else {
11688 $resultat = '<option value="' . $obj->rowid . '"';
11689 if ($disabled) {
11690 $resultat .= ' disabled';
11691 }
11692 $resultat .= '>';
11693 $resultat .= $labeltoshow;
11694 $resultat .= '</option>';
11695 }
11696 $out .= $resultat;
11697 }
11698 }
11699 }
11700 if (empty($option_only)) {
11701 $out .= '</select>';
11702 }
11703
11704 print $out;
11705
11706 $this->db->free($resql);
11707 return $num;
11708 } else {
11709 $this->errors[] = $this->db->lasterror;
11710 return -1;
11711 }
11712 }
11713
11714
11730 public function selectOrder($selected = '', $htmlname = 'orderid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11731 {
11732 global $user, $conf, $langs;
11733
11734 $out = '';
11735
11736 $hideunselectables = false;
11737 if (getDolGlobalString('ORDER_HIDE_UNSELECTABLES')) {
11738 $hideunselectables = true;
11739 }
11740
11741 // Search all orders
11742 $sql = "SELECT c.rowid, c.ref";
11743 $sql .= ' FROM '.$this->db->prefix().'commande as c';
11744 $sql .= " ORDER BY c.ref ASC";
11745
11746 $resql = $this->db->query($sql);
11747 if ($resql) {
11748 // Use select2 selector
11749 if (!empty($conf->use_javascript_ajax)) {
11750 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
11751 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11752 $out .= $comboenhancement;
11753 $morecss = 'minwidth200imp maxwidth500';
11754 }
11755
11756 if (empty($option_only)) {
11757 $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
11758 }
11759 if (!empty($show_empty)) {
11760 $out .= '<option value="0" class="optiongrey">';
11761 if (!is_numeric($show_empty)) {
11762 $out .= $show_empty;
11763 } else {
11764 $out .= '&nbsp;';
11765 }
11766 $out .= '</option>';
11767 }
11768 $num = $this->db->num_rows($resql);
11769 $i = 0;
11770 if ($num) {
11771 while ($i < $num) {
11772 $obj = $this->db->fetch_object($resql);
11773
11774 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11775 $i++;
11776 continue;
11777 }
11778
11779 $labeltoshow = dol_trunc($obj->ref, 18); // Order ref
11780
11781 if (!empty($selected) && $selected == $obj->rowid) {
11782 $out .= '<option value="'.$obj->rowid.'" selected';
11783 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11784 $out .= '>'.$labeltoshow.'</option>';
11785 } else {
11786 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11787 $resultat = '';
11788 } else {
11789 $resultat = '<option value="'.$obj->rowid.'"';
11790 if ($disabled) {
11791 $resultat .= ' disabled';
11792 }
11793 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11794 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11795 $resultat .= '>';
11796 $resultat .= $labeltoshow;
11797 $resultat .= '</option>';
11798 }
11799 $out .= $resultat;
11800 }
11801 $i++;
11802 }
11803 }
11804 if (empty($option_only)) {
11805 $out .= '</select>';
11806 }
11807
11808 print $out;
11809
11810 $this->db->free($resql);
11811 return $num;
11812 } else {
11813 dol_print_error($this->db);
11814 return -1;
11815 }
11816 }
11817
11833 public function selectSupplierOrder($selected = '', $htmlname = 'supplierorderid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11834 {
11835 global $user, $conf, $langs;
11836
11837 $out = '';
11838
11839 $hideunselectables = false;
11840 if (getDolGlobalString('SUPPLIER_ORDER_HIDE_UNSELECTABLES')) {
11841 $hideunselectables = true;
11842 }
11843
11844 // Search all supplier orders
11845 $sql = "SELECT cf.rowid, cf.ref";
11846 $sql .= ' FROM '.$this->db->prefix().'commande_fournisseur as cf';
11847 $sql .= " ORDER BY cf.ref ASC";
11848
11849 $resql = $this->db->query($sql);
11850 if ($resql) {
11851 // Use select2 selector
11852 if (!empty($conf->use_javascript_ajax)) {
11853 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
11854 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11855 $out .= $comboenhancement;
11856 $morecss = 'minwidth200imp maxwidth500';
11857 }
11858
11859 if (empty($option_only)) {
11860 $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
11861 }
11862 if (!empty($show_empty)) {
11863 $out .= '<option value="0" class="optiongrey">';
11864 if (!is_numeric($show_empty)) {
11865 $out .= $show_empty;
11866 } else {
11867 $out .= '&nbsp;';
11868 }
11869 $out .= '</option>';
11870 }
11871 $num = $this->db->num_rows($resql);
11872 $i = 0;
11873 if ($num) {
11874 while ($i < $num) {
11875 $obj = $this->db->fetch_object($resql);
11876
11877 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11878 $i++;
11879 continue;
11880 }
11881
11882 $labeltoshow = dol_trunc($obj->ref, 18); // Supplier order ref
11883
11884 if (!empty($selected) && $selected == $obj->rowid) {
11885 $out .= '<option value="'.$obj->rowid.'" selected';
11886 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11887 $out .= '>'.$labeltoshow.'</option>';
11888 } else {
11889 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11890 $resultat = '';
11891 } else {
11892 $resultat = '<option value="'.$obj->rowid.'"';
11893 if ($disabled) {
11894 $resultat .= ' disabled';
11895 }
11896 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11897 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11898 $resultat .= '>';
11899 $resultat .= $labeltoshow;
11900 $resultat .= '</option>';
11901 }
11902 $out .= $resultat;
11903 }
11904 $i++;
11905 }
11906 }
11907 if (empty($option_only)) {
11908 $out .= '</select>';
11909 }
11910
11911 print $out;
11912
11913 $this->db->free($resql);
11914 return $num;
11915 } else {
11916 dol_print_error($this->db);
11917 return -1;
11918 }
11919 }
11920
11936 public function selectSupplierInvoice($selected = '', $htmlname = 'supplierinvoiceid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11937 {
11938 global $user, $conf, $langs;
11939
11940 $out = '';
11941
11942 $hideunselectables = false;
11943 if (getDolGlobalString('SUPPLIER_INVOICE_HIDE_UNSELECTABLES')) {
11944 $hideunselectables = true;
11945 }
11946
11947 // Search all supplier orders
11948 $sql = "SELECT ff.rowid, ff.ref";
11949 $sql .= ' FROM '.$this->db->prefix().'facture_fourn as ff';
11950 $sql .= " ORDER BY ff.ref ASC";
11951
11952 $resql = $this->db->query($sql);
11953 if ($resql) {
11954 // Use select2 selector
11955 if (!empty($conf->use_javascript_ajax)) {
11956 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
11957 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11958 $out .= $comboenhancement;
11959 $morecss = 'minwidth200imp maxwidth500';
11960 }
11961
11962 if (empty($option_only)) {
11963 $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
11964 }
11965 if (!empty($show_empty)) {
11966 $out .= '<option value="0" class="optiongrey">';
11967 if (!is_numeric($show_empty)) {
11968 $out .= $show_empty;
11969 } else {
11970 $out .= '&nbsp;';
11971 }
11972 $out .= '</option>';
11973 }
11974 $num = $this->db->num_rows($resql);
11975 $i = 0;
11976 if ($num) {
11977 while ($i < $num) {
11978 $obj = $this->db->fetch_object($resql);
11979
11980 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11981 $i++;
11982 continue;
11983 }
11984
11985 $labeltoshow = dol_trunc($obj->ref, 18); // Supplier order ref
11986
11987 if (!empty($selected) && $selected == $obj->rowid) {
11988 $out .= '<option value="'.$obj->rowid.'" selected';
11989 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11990 $out .= '>'.$labeltoshow.'</option>';
11991 } else {
11992 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11993 $resultat = '';
11994 } else {
11995 $resultat = '<option value="'.$obj->rowid.'"';
11996 if ($disabled) {
11997 $resultat .= ' disabled';
11998 }
11999 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
12000 //else $labeltoshow.=' ('.$langs->trans("Private").')';
12001 $resultat .= '>';
12002 $resultat .= $labeltoshow;
12003 $resultat .= '</option>';
12004 }
12005 $out .= $resultat;
12006 }
12007 $i++;
12008 }
12009 }
12010 if (empty($option_only)) {
12011 $out .= '</select>';
12012 }
12013
12014 print $out;
12015
12016 $this->db->free($resql);
12017 return $num;
12018 } else {
12019 dol_print_error($this->db);
12020 return -1;
12021 }
12022 }
12023
12034 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '', $arrayoffiltercriterias = array())
12035 {
12036 // TODO: Use $arrayoffiltercriterias param instead of $arrayofcriterias to include linked object fields in search
12037 global $langs, $form;
12038
12039 //require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
12040 //$formother = new FormOther($this->db);
12041
12042 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
12043 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
12044 }
12045
12046 $ret = '<!-- searchComponent -->';
12047
12048 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
12049 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
12050 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
12051 $ret .= '</a>';
12052
12053 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
12054
12055 // Show select fields as tags.
12056 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
12057
12058 if ($search_component_params_hidden) {
12059 // Split the criteria on each AND
12060 //var_dump($search_component_params_hidden);
12061
12062 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
12063
12064 // $arrayofandtags is now array( '...' , '...', ...)
12065 // Show each AND part
12066 foreach ($arrayofandtags as $tmpkey => $tmpval) {
12067 $errormessage = '';
12068 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
12069 if ($errormessage) {
12070 $this->error = 'ERROR in parsing search string: '.$errormessage;
12071 }
12072 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
12073 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
12074 $searchtags = removeGlobalParenthesis($searchtags);
12075
12076 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
12077 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
12078 $ret .= dol_escape_htmltag($searchtags);
12079 $ret .= '</span>';
12080 }
12081 }
12082
12083 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
12084
12085 //$ret .= search_component_params
12086 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
12087 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
12088
12089 $show_search_component_params_hidden = 1;
12090 if ($show_search_component_params_hidden) {
12091 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
12092 }
12093 $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%')) -->";
12094 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
12095 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
12096
12097 // TODO : Use $arrayoffiltercriterias instead of $arrayofcriterias
12098 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
12099 foreach ($arrayofcriterias as $criteria) {
12100 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
12101 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
12102 continue;
12103 }
12104 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
12105 continue;
12106 }
12107 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
12108 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
12109 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
12110 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
12111 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
12112 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
12113 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
12114 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
12115 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
12116 } else {
12117 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
12118 }
12119 }
12120 }
12121
12122 $ret .= '</div>';
12123
12124 $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";
12125 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
12126
12127 $ret .= '</div>';
12128 $ret .= '</div>';
12129
12130 $ret .= '<script>
12131 jQuery(".tagsearchdelete").click(function(e) {
12132 var filterid = $(this).parents().attr("data-ufilterid");
12133 console.log("We click to delete the criteria nb "+filterid);
12134
12135 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
12136 var newparamstring = \'\';
12137 $(\'.tagsearch\').each(function(index, element) {
12138 tmpfilterid = $(this).attr("data-ufilterid");
12139 if (tmpfilterid != filterid) {
12140 // We keep this criteria
12141 if (newparamstring == \'\') {
12142 newparamstring = $(this).attr("data-ufilter");
12143 } else {
12144 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
12145 }
12146 }
12147 });
12148 console.log("newparamstring = "+newparamstring);
12149
12150 jQuery("#search_component_params_hidden").val(newparamstring);
12151
12152 // We repost the form
12153 $(this).closest(\'form\').submit();
12154 });
12155
12156 jQuery("#search_component_params_input").keydown(function(e) {
12157 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
12158 console.log(e.which);
12159 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
12160 /* We click on back when the input field is already empty */
12161 event.preventDefault();
12162 jQuery("#divsearch_component_params .tagsearch").last().remove();
12163 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
12164 var s = "";
12165 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
12166 if (s != "") {
12167 s = s + " AND ";
12168 }
12169 s = s + $(this).attr("data-ufilter");
12170 });
12171 console.log("New value for search_component_params_hidden = "+s);
12172 jQuery("#search_component_params_hidden").val(s);
12173 }
12174 });
12175
12176 </script>
12177 ';
12178
12179 // Convert $arrayoffiltercriterias into a json object that can be used in jquery to build the search component dynamically
12180 $arrayoffiltercriterias_json = json_encode($arrayoffiltercriterias);
12181 $ret .= '<script>
12182 var arrayoffiltercriterias = ' . $arrayoffiltercriterias_json . ';
12183 </script>';
12184
12185
12186 $arrayoffilterfieldslabel = array();
12187 foreach ($arrayoffiltercriterias as $key => $val) {
12188 $arrayoffilterfieldslabel[$key]['label'] = $val['label'];
12189 $arrayoffilterfieldslabel[$key]['data-type'] = $val['type'];
12190 }
12191
12192 // Adding the div for search assistance
12193 $ret .= '<div class="search-component-assistance">';
12194 $ret .= '<div>';
12195
12196 $ret .= '<p class="assistance-title">' . img_picto('', 'filter') . ' ' . $langs->trans('FilterAssistance') . ' </p>';
12197
12198 $ret .= '<p class="assistance-errors error" style="display:none">' . $langs->trans('AllFieldsRequired') . ' </p>';
12199
12200 $ret .= '<div class="operand">';
12201 $ret .= $form->selectarray('search_filter_field', $arrayoffilterfieldslabel, '', $langs->trans("Fields"), 0, 0, '', 0, 0, 0, '', 'width200 combolargeelem', 1);
12202 $ret .= '</div>';
12203
12204 $ret .= '<span class="separator"></span>';
12205
12206 // Operator selector (will be populated dynamically)
12207 $ret .= '<div class="operator">';
12208 $ret .= '<select class="operator-selector width150" id="operator-selector"">';
12209 $ret .= '</select>';
12210 $ret .= '<script>$(document).ready(function() {';
12211 $ret .= ' $(".operator-selector").select2({';
12212 $ret .= ' placeholder: \'' . dol_escape_js($langs->transnoentitiesnoconv('Operator')) . '\'';
12213 $ret .= ' });';
12214 $ret .= '});</script>';
12215 $ret .= '</div>';
12216
12217 $ret .= '<span class="separator"></span>';
12218
12219 $ret .= '<div class="value">';
12220 // Input field for entering values
12221 $ret .= '<input type="text" class="flat width100 value-input" placeholder="' . dolPrintHTML($langs->trans('Value')) . '">';
12222
12223 // Date selector
12224 $dateOne = '';
12225 $ret .= '<span class="date-one" style="display:none">';
12226 $ret .= $form->selectDate(($dateOne ? $dateOne : -1), 'dateone', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '');
12227 $ret .= '</span>';
12228
12229 // Value selector (will be populated dynamically) based on search_filter_field value if a selected value has an array of values
12230 $ret .= '<select class="value-selector width150" id="value-selector" style="display:none">';
12231 $ret .= '</select>';
12232 $ret .= '<script>
12233 $(document).ready(function() {
12234 $("#value-selector").select2({
12235 placeholder: "' . dol_escape_js($langs->trans('Value')) . '"
12236 });
12237 $("#value-selector").hide();
12238 $("#value-selector").next(".select2-container").hide();
12239 });
12240 </script>';
12241
12242 $ret .= '</div>';
12243
12244 $ret .= '<div class="btn-div">';
12245 $ret .= '<button class="button buttongen button-save add-filter-btn" type="button">' . $langs->trans("addToFilter") . '</button>';
12246 $ret .= '</div>';
12247
12248 $ret .= '</div>';
12249 //$ret .= '</tbody></table>';
12250
12251 // End of the assistance div
12252 $ret .= '</div>';
12253
12254 // Script jQuery to show/hide the floating assistance
12255 $ret .= '<script>
12256 $(document).ready(function() {
12257 $("#search_component_params_input").on("click", function() {
12258 const inputPosition = $(this).offset();
12259 const inputHeight = $(this).outerHeight();
12260 $(".search-component-assistance").css({
12261 top: inputPosition.top + inputHeight + 5 + "px",
12262 left: $("#divsearch_component_params").position().left
12263 }).slideToggle(200);
12264 });
12265 $(document).on("click", function(e) {
12266 if (!$(e.target).closest("#search_component_params_input, .search-component-assistance, #ui-datepicker-div").length) {
12267 $(".search-component-assistance").hide();
12268 }
12269 });
12270 });
12271 </script>';
12272
12273 $ret .= '<script>
12274 $(document).ready(function() {
12275 $(".search_filter_field").on("change", function() {
12276 console.log("We change search_filter_field");
12277
12278 let maybenull = 0;
12279 const selectedField = $(this).find(":selected");
12280 let fieldType = selectedField.data("type");
12281 const selectedFieldValue = selectedField.val();
12282
12283 // If the selected field has an array of values then ask toshow the value selector instead of the value input
12284 if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
12285 fieldType = "select";
12286 }
12287
12288 // If the selected field may be null then ask to append the "IsDefined" and "IsNotDefined" operators
12289 if (arrayoffiltercriterias[selectedFieldValue]["maybenull"] !== undefined) {
12290 maybenull = 1;
12291 }
12292 const operators = getOperatorsForFieldType(fieldType, maybenull);
12293 const operatorSelector = $(".operator-selector");
12294
12295 // Clear existing options
12296 operatorSelector.empty();
12297
12298 // Populate operators
12299 Object.entries(operators).forEach(function([operator, label]) {
12300 operatorSelector.append("<option value=\'" + operator + "\'>" + label + "</option>");
12301 });
12302
12303 operatorSelector.trigger("change.select2");
12304
12305 // Clear and hide all input elements initially
12306 $(".value-input, .dateone, .datemonth, .dateyear").val("").hide();
12307 $("#datemonth, #dateyear").val(null).trigger("change.select2");
12308 $("#dateone").datepicker("setDate", null);
12309 $(".date-one, .date-month, .date-year").hide();
12310 $("#value-selector").val("").hide();
12311 $("#value-selector").next(".select2-container").hide();
12312 $("#value-selector").val(null).trigger("change.select2");
12313
12314 if (fieldType === "date" || fieldType === "datetime" || fieldType === "timestamp") {
12315 $(".date-one").show();
12316 } else if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
12317 var arrayofkeyval = arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"];
12318 var valueSelector = $("#value-selector");
12319 valueSelector.empty();
12320 Object.entries(arrayofkeyval).forEach(function([key, val]) {
12321 valueSelector.append("<option value=\'" + key + "\'>" + val + "</option>");
12322 });
12323 valueSelector.trigger("change.select2");
12324
12325 $("#value-selector").show();
12326 $("#value-selector").next(".select2-container").show();
12327 } else {
12328 $(".value-input").show();
12329 }
12330 });
12331
12332 $("#operator-selector").on("change", function() {
12333 console.log("We change operator-selector");
12334
12335 const selectedOperator = $(this).find(":selected").val();
12336 if (selectedOperator === "IsDefined" || selectedOperator === "IsNotDefined") {
12337 // Disable all value input elements
12338 $(".value-input, .dateone, .datemonth, .dateyear").val("").prop("disabled", true);
12339 $("#datemonth, #dateyear").val(null).trigger("change.select2");
12340 $("#dateone").datepicker("setDate", null).datepicker("option", "disabled", true);
12341 $(".date-one, .date-month, .date-year").prop("disabled", true);
12342 $("#value-selector").val("").prop("disabled", true);
12343 $("#value-selector").val(null).trigger("change.select2");
12344 } else {
12345 // Enable all value input elements
12346 $(".value-input, .dateone, .datemonth, .dateyear").prop("disabled", false);
12347 $(".date-one, .date-month, .date-year").prop("disabled", false);
12348 $("#dateone").datepicker("option", "disabled", false);
12349 $("#value-selector").prop("disabled", false);
12350 }
12351 });
12352
12353 $(".add-filter-btn").on("click", function(event) {
12354 console.log("We click on add-filter-btn");
12355
12356 event.preventDefault();
12357
12358 const field = $(".search_filter_field").val();
12359 const operator = $(".operator-selector").val();
12360 let value = $(".value-input").val();
12361 const fieldType = $(".search_filter_field").find(":selected").data("type");
12362
12363 if (["date", "datetime", "timestamp"].includes(fieldType)) {
12364 const year = $("#dateoneyear").val().toString().padStart(4, "0");;
12365 const month = $("#dateonemonth").val().toString().padStart(2, "0");
12366 const day = $("#dateoneday").val().toString().padStart(2, "0");
12367 value = `${year}-${month}-${day}`;
12368 console.log("value="+value);
12369 }
12370
12371 // If the selected field has an array of values then take the selected value
12372 if (arrayoffiltercriterias[field]["arrayofkeyval"] !== undefined) {
12373 value = $("#value-selector").val();
12374 }
12375
12376 // If the operator is "IsDefined" or "IsNotDefined" then set the value to 1 (it will not be used)
12377 if (operator === "IsDefined" || operator === "IsNotDefined") {
12378 value = "1";
12379 }
12380
12381 const filterString = generateFilterString(field, operator, value, fieldType);
12382
12383 // Submit the form
12384 if (filterString !== "" && field !== "" && operator !== "" && value !== "") {
12385 $("#search_component_params_input").val($("#search_component_params_input").val() + " " + filterString);
12386 $("#search_component_params_input").closest("form").submit();
12387 } else {
12388 $(".assistance-errors").show();
12389 }
12390 });
12391 });
12392 </script>';
12393
12394 return $ret;
12395 }
12396
12407 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0, $selected = 0)
12408 {
12409 global $langs, $user;
12410
12411 $retstring = '';
12412
12413 $TModels = array();
12414
12415 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
12416 $formmail = new FormMail($this->db);
12417 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
12418
12419 if ($default) {
12420 $TModels[0] = $langs->trans('DefaultMailModel');
12421 }
12422 if ($result > 0) {
12423 foreach ($formmail->lines_model as $model) {
12424 $TModels[(int) $model->id] = $model->label;
12425 }
12426 }
12427
12428 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
12429
12430 foreach ($TModels as $id_model => $label_model) {
12431 $retstring .= '<option value="' . $id_model . '"';
12432 if (!empty($selected) && ((int) $selected) == $id_model) {
12433 $retstring .= "selected";
12434 }
12435 $retstring .= ">" . $label_model . "</option>";
12436 }
12437
12438 $retstring .= "</select>";
12439
12440 if ($addjscombo) {
12441 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
12442 }
12443
12444 return $retstring;
12445 }
12446
12458 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
12459 {
12460 global $langs;
12461
12462 $buttons = array();
12463
12464 $save = array(
12465 'name' => 'save',
12466 'label_key' => $save_label,
12467 );
12468
12469 if ($save_label == 'Create' || $save_label == 'Add') {
12470 $save['name'] = 'add';
12471 } elseif ($save_label == 'Modify') {
12472 $save['name'] = 'edit';
12473 }
12474
12475 $cancel = array(
12476 'name' => 'cancel',
12477 'label_key' => 'Cancel',
12478 );
12479
12480 // If MAIN_BUTTON_POSITION_FIRST_OR_LEFT not set, default is to have main action first, then complementary, then cancel at end
12481 if (!getDolGlobalInt('MAIN_BUTTON_POSITION_FIRST_OR_LEFT')) {
12482 !empty($save_label) ? $buttons[] = $save : '';
12483 if (!empty($morebuttons)) {
12484 $buttons[] = $morebuttons;
12485 }
12486 !empty($cancel_label) ? $buttons[] = $cancel : '';
12487 } else {
12488 if (!empty($morebuttons)) {
12489 $buttons[] = $morebuttons;
12490 }
12491 !empty($cancel_label) ? $buttons[] = $cancel : '';
12492 !empty($save_label) ? $buttons[] = $save : '';
12493 }
12494
12495 $retstring = $withoutdiv ? '' : '<div class="center">';
12496
12497 foreach ($buttons as $button) {
12498 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
12499 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->transnoentities($button['label_key'])) . '">';
12500 }
12501 $retstring .= $withoutdiv ? '' : '</div>';
12502
12503 if ($dol_openinpopup) {
12504 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
12505 $retstring .= '<script nonce="' . getNonce() . '">';
12506 $retstring .= 'jQuery(".button-cancel").click(function(e) {
12507 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
12508 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
12509 });';
12510 $retstring .= '</script>';
12511 }
12512
12513 return $retstring;
12514 }
12515
12516
12517 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
12518
12525 {
12526 // phpcs:enable
12527 global $langs;
12528
12529 $num = count($this->cache_invoice_subtype);
12530 if ($num > 0) {
12531 return 0; // Cache already loaded
12532 }
12533
12534 dol_syslog(__METHOD__, LOG_DEBUG);
12535
12536 $sql = "SELECT rowid, code, label as label";
12537 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
12538 $sql .= " WHERE active = 1";
12539
12540 $resql = $this->db->query($sql);
12541 if ($resql) {
12542 $num = $this->db->num_rows($resql);
12543 $i = 0;
12544 while ($i < $num) {
12545 $obj = $this->db->fetch_object($resql);
12546
12547 // If translation exists, we use it, otherwise we take the default wording
12548 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
12549 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
12550 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
12551 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
12552 $i++;
12553 }
12554
12555 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
12556
12557 return $num;
12558 } else {
12559 dol_print_error($this->db);
12560 return -1;
12561 }
12562 }
12563
12564
12575 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
12576 {
12577 global $langs, $user;
12578
12579 $out = '';
12580 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
12581
12582 $this->load_cache_invoice_subtype();
12583
12584 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
12585 if ($addempty) {
12586 $out .= '<option value="0">&nbsp;</option>';
12587 }
12588
12589 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
12590 $label = $subtype['label'];
12591 $out .= '<option value="' . $subtype['rowid'] . '"';
12592 if ($selected == $subtype['rowid']) {
12593 $out .= ' selected="selected"';
12594 }
12595 $out .= '>';
12596 $out .= $label;
12597 $out .= '</option>';
12598 }
12599
12600 $out .= '</select>';
12601 if ($user->admin && empty($noinfoadmin)) {
12602 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
12603 }
12604 $out .= ajax_combobox($htmlname);
12605
12606 return $out;
12607 }
12608
12618 public function getSearchFilterToolInput($dataTarget, $htmlName = 'search-tools-input', $value = '', $params = [])
12619 {
12620 global $langs;
12621
12622 $attr = array(
12623 'type' => 'search',
12624 'name' => $htmlName,
12625 'value' => $value,
12626 'class' => "search-tool-input",
12627 'placeholder' => $langs->trans('Search'),
12628 'autocomplete' => 'off'
12629 );
12630
12631 // Optional data attr
12632 // 'autofocus' : will set auto focus on field ,
12633 // data-counter-target : will get count results
12634 // data-no-item-target : will be display if count results is 0
12635
12636 if ($dataTarget !== false) {
12637 $attr['data-search-tool-target'] = $dataTarget;
12638 }
12639
12640 // Override attr
12641 if (!empty($params['attr']) && is_array($params['attr'])) {
12642 foreach ($params['attr'] as $key => $value) {
12643 if ($key == 'class') {
12644 $attr['class'] .= ' '.$value;
12645 } elseif ($key == 'classOverride') {
12646 $attr['class'] = $value;
12647 } else {
12648 $attr[$key] = $value;
12649 }
12650 }
12651 }
12652
12653 // automatic add tooltip when title is detected
12654 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
12655 $attr['class'] .= ' classfortooltip';
12656 }
12657
12658 $TCompiledAttr = [];
12659 foreach ($attr as $key => $value) {
12660 if (in_array($key, ['data-target'])
12661 || (!empty($params['use_unsecured_unescapedattr']) && is_array($params['use_unsecured_unescapedattr']) && in_array($key, $params['use_unsecured_unescapedattr']))) { // Not recommended
12662 $value = dol_htmlentities($value, ENT_QUOTES | ENT_SUBSTITUTE);
12663 } else {
12664 $value = dolPrintHTMLForAttribute($value);
12665 }
12666
12667 $TCompiledAttr[] = $key . '="' . $value . '"'; // $value has been escaped by the dolPrintHTMLForAttribute... just before
12668 }
12669
12670 $compiledAttributes = implode(' ', $TCompiledAttr);
12671
12672
12673 return '<div class="search-tool-container"><input '.$compiledAttributes.'></div>';
12674 }
12675}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to transform a common input text or select field into ...
Definition ajax.lib.php:49
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:475
ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
Generic function that return javascript to add to a page to transform a common input text field into ...
Definition ajax.lib.php:324
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:578
$c
Definition line.php:331
$object ref
Definition info.php:90
Class to manage bank accounts.
Class to manage categories.
Class to manage bank accounts description of third parties.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
DAO Resource object.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage invoice templates.
Class to manage generation of HTML components Only common components must be here.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array(), $nooutput=0)
Show block with links "to link to" other objects.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='maxwidth200 widthcentpercentminusx')
Return array of currencies in user language.
showFilterButtons($pos='')
Return HTML to show the search and clear search button.
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array(), $canremoveowner=1)
Return select list of users.
load_cache_vatrates($country_code)
Load into the cache ->cache_vatrates, all the vat rates of a country.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0, $selected=0)
selectModelMail
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=array(), $title='RelatedObjects')
Show linked object block.
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
getSelectRuleForLinesDates($selected='', $htmlname='rule_for_lines_dates', $addempty=0)
Returns select with rule for lines dates.
select_dolresources_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofresourceid=array())
Return select list of resources.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
Show a confirmation HTML form or AJAX popup.
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
formRib($page, $selected='', $htmlname='ribcompanyid', $filtre='', $addempty=0, $showibanbic=0)
Display form to select bank customer account.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party This call select_thirdparty_list() or ajax depending on setu...
select_produits($selected=0, $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1, $warehouseId=0)
Return list of products for customer.
select_dolgroups($selected=0, $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly=array(), $force_entity='0', $multiple=false, $morecss='minwidth200')
Return select list of user groups.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
selectSupplierOrder($selected='', $htmlname='supplierorderid', $maxlength=24, $option_only=0, $show_empty='1', $discard_closed=0, $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with supplier orders qualified for a third party.
select_contact($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $nokeyifsocid=true, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $selected_input_value='', $filter='')
Output html form to select a contact This call select_contacts() or ajax depending on setup.
selectSupplierInvoice($selected='', $htmlname='supplierinvoiceid', $maxlength=24, $option_only=0, $show_empty='1', $discard_closed=0, $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with supplier invoices qualified for a third party.
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="", $useajaxcombo=1)
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
selectRib($selected='', $htmlname='ribcompanyid', $filtre='', $useempty=0, $moreattrib='', $showibanbic=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts customer.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $nu='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
getSelectInvoiceSubtype($selected=0, $htmlname='subtypeid', $addempty=0, $noinfoadmin=0, $morecss='')
Return list of invoice subtypes.
select_produits_list($selected=0, $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='maxwidth500', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1, $warehouseId=0)
Return list of products for a customer.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse=null, $societe_acheteuse=null, $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0, $type_vat=0)
Output an HTML select vat rate.
form_multicurrency_rate($page, $rate=0.0, $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
load_cache_availability()
Load int a cache property the list of possible delivery delays.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='', $maxlength=0, $showstatus=0, $morefilter='', $showalso=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
form_rule_for_lines_dates($page, $selected='', $htmlname='rule_for_lines_dates', $addempty=0, $nooutput=0)
Form select for rule for lines dates.
selectcontacts($socid, $selected=array(), $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=0, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0, $filter='')
Return HTML code of the SELECT of list of all contacts (for a third party or all).
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=false, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0, $forcecombo=0)
Return combo list of activated countries, into language of user.
selectOrder($selected='', $htmlname='orderid', $maxlength=24, $option_only=0, $show_empty='1', $discard_closed=0, $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with orders qualified for a third party.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
getSearchFilterToolInput($dataTarget, $htmlName='search-tools-input', $value='', $params=[])
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1, $noprint=0)
print list of payment modes.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
load_cache_rule_for_lines_dates()
Loads into a cache property the list of possible rules for line dates.
form_confirm($page, $title, $question, $action, $formquestion=array(), $selectedchoice="", $useajax=0, $height=170, $width=500)
load_cache_conditions_paiements()
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier=0)
Return list of suppliers prices for a product.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='width75', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly=array(), $force_entity='0')
Return the HTML select list of users.
selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='', $openinghours='', $stepminutes=1, $labeladddateof='', $placeholder='', $gm='auto', $calendarpicto='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
static selectArrayFilter($htmlname, $array, $id='', $moreparam='', $disableFiltering=0, $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0, $textfortitle='')
Return a HTML select string, built from an array of key+value, but content returned into select is de...
textwithpicto($text, $htmltooltip, $direction=1, $type='help', $extracss='valignmiddle', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday=0, $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
load_cache_invoice_subtype()
Load into cache list of invoice subtypes.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
selectCategories($categtype, $htmlname, $object=null)
Return HTML compopent to select a category.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
load_cache_types_paiements()
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Return the list of type of delay available.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='', $nooutput=0)
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='', $arrayoffiltercriterias=array())
Output the component to make advanced search criteries.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage hooks.
Class for MyObject.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
const STATUS_CLOSED
Closed status.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
Class toolbox to validate values.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
currency_name($code_iso, $withcode=0, $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $jsonclose='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
currentToken()
Return the value of token currently saved into session with name 'token'.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0, $morecss='paddingrightonly')
Show EMail link formatted for HTML output.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external links.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0, $allowscript=0, $allowstyle=0, $allowphp=0)
Clean a string to keep only desirable HTML tags.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
a disabled
treeview li table
No Email.
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:158
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:161
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.
getMaxFileSizeArray()
Return the max allowed for file upload.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition waf.inc.php:103