dolibarr 20.0.0
html.form.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13 * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18 * Copyright (C) 2014-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 3 of the License, or
31 * (at your option) any later version.
32 *
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program. If not, see <https://www.gnu.org/licenses/>.
40 */
41
55class Form
56{
60 public $db;
61
65 public $error = '';
66
70 public $errors = array();
71
72 // Some properties used to return data by some methods
74 public $result;
76 public $num;
77
78 // Cache arrays
79 public $cache_types_paiements = array();
80 public $cache_conditions_paiements = array();
81 public $cache_transport_mode = array();
82 public $cache_availability = array();
83 public $cache_demand_reason = array();
84 public $cache_types_fees = array();
85 public $cache_vatrates = array();
86 public $cache_invoice_subtype = array();
87
88
94 public function __construct($db)
95 {
96 $this->db = $db;
97 }
98
115 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
116 {
117 global $langs;
118
119 $ret = '';
120
121 // TODO change for compatibility
122 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
123 if (!empty($perm)) {
124 $tmp = explode(':', $typeofdata);
125 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
126 if ($fieldrequired) {
127 $ret .= '<span class="fieldrequired">';
128 }
129 if ($help) {
130 $ret .= $this->textwithpicto($langs->trans($text), $help);
131 } else {
132 $ret .= $langs->trans($text);
133 }
134 if ($fieldrequired) {
135 $ret .= '</span>';
136 }
137 $ret .= '</div>' . "\n";
138 } else {
139 if ($fieldrequired) {
140 $ret .= '<span class="fieldrequired">';
141 }
142 if ($help) {
143 $ret .= $this->textwithpicto($langs->trans($text), $help);
144 } else {
145 $ret .= $langs->trans($text);
146 }
147 if ($fieldrequired) {
148 $ret .= '</span>';
149 }
150 }
151 } else {
152 if (empty($notabletag) && $perm) {
153 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
154 }
155 if ($fieldrequired) {
156 $ret .= '<span class="fieldrequired">';
157 }
158 if ($help) {
159 $ret .= $this->textwithpicto($langs->trans($text), $help);
160 } else {
161 $ret .= $langs->trans($text);
162 }
163 if ($fieldrequired) {
164 $ret .= '</span>';
165 }
166 if (!empty($notabletag)) {
167 $ret .= ' ';
168 }
169 if (empty($notabletag) && $perm) {
170 $ret .= '</td>';
171 }
172 if (empty($notabletag) && $perm) {
173 $ret .= '<td class="right">';
174 }
175 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
176 $ret .= '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=edit' . $htmlname . '&token=' . newToken() . '&' . $paramid . '=' . $object->id . $moreparam . '">' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . '</a>';
177 }
178 if (!empty($notabletag) && $notabletag == 1) {
179 if ($text) {
180 $ret .= ' : ';
181 } else {
182 $ret .= ' ';
183 }
184 }
185 if (!empty($notabletag) && $notabletag == 3) {
186 $ret .= ' ';
187 }
188 if (empty($notabletag) && $perm) {
189 $ret .= '</td>';
190 }
191 if (empty($notabletag) && $perm) {
192 $ret .= '</tr></table>';
193 }
194 }
195
196 return $ret;
197 }
198
222 public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '')
223 {
224 global $conf, $langs;
225
226 $ret = '';
227
228 // Check parameters
229 if (empty($typeofdata)) {
230 return 'ErrorBadParameter typeofdata is empty';
231 }
232 // Clean parameter $typeofdata
233 if ($typeofdata == 'datetime') {
234 $typeofdata = 'dayhour';
235 }
236 $reg = array();
237 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
238 if ($reg[1] == 'varchar') {
239 $typeofdata = 'string';
240 } elseif ($reg[1] == 'int') {
241 $typeofdata = 'numeric';
242 } else {
243 return 'ErrorBadParameter ' . $typeofdata;
244 }
245 }
246
247 // When option to edit inline is activated
248 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
249 $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
250 } else {
251 if ($editaction == '') {
252 $editaction = GETPOST('action', 'aZ09');
253 }
254 $editmode = ($editaction == 'edit' . $htmlname);
255 if ($editmode) { // edit mode
256 $ret .= "\n";
257 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
258 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
259 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
260 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
261 if (empty($notabletag)) {
262 $ret .= '<table class="nobordernopadding centpercent">';
263 }
264 if (empty($notabletag)) {
265 $ret .= '<tr><td>';
266 }
267 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
268 $tmp = explode(':', $typeofdata);
269 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
270 } elseif (preg_match('/^(integer)/', $typeofdata)) {
271 $tmp = explode(':', $typeofdata);
272 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
273 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
274 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
275 $tmp = explode(':', $typeofdata);
276 $valuetoshow = price2num($editvalue ? $editvalue : $value);
277 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
278 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
279 $tmp = explode(':', $typeofdata);
280 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
281 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
282 $tmp = explode(':', $typeofdata);
283 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
284 $morealt = '';
285 if (preg_match('/%/', $cols)) {
286 $morealt = ' style="width: ' . $cols . '"';
287 $cols = '';
288 }
289 $valuetoshow = ($editvalue ? $editvalue : $value);
290 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
291 // textarea convert automatically entities chars into simple chars.
292 // So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwyg is off.
293 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
294 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
295 $ret .= '</textarea>';
296 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
297 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
298 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
299 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
300 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
301 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
302 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
303 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
304 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
305 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
306 } elseif (preg_match('/^select;/', $typeofdata)) {
307 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
308 $arraylist = array();
309 foreach ($arraydata as $val) {
310 $tmp = explode(':', $val);
311 $tmpkey = str_replace('|', ':', $tmp[0]);
312 $arraylist[$tmpkey] = $tmp[1];
313 }
314 $ret .= $this->selectarray($htmlname, $arraylist, $value);
315 } elseif (preg_match('/^link/', $typeofdata)) {
316 // TODO Not yet implemented. See code for extrafields
317 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
318 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
319 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
320 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? '100' : $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? 0 : $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? '20' : $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
321 $ret .= $doleditor->Create(1);
322 } elseif ($typeofdata == 'asis') {
323 $ret .= ($editvalue ? $editvalue : $value);
324 }
325 if (empty($notabletag)) {
326 $ret .= '</td>';
327 }
328
329 // Button save-cancel
330 if (empty($notabletag)) {
331 $ret .= '<td>';
332 }
333 //else $ret.='<div class="clearboth"></div>';
334 $ret .= '<input type="submit" class="smallpaddingimp button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
335 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
336 $ret .= '<br>' . "\n";
337 }
338 $ret .= '<input type="submit" class="smallpaddingimp button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
339 if (empty($notabletag)) {
340 $ret .= '</td>';
341 }
342
343 if (empty($notabletag)) {
344 $ret .= '</tr></table>' . "\n";
345 }
346 $ret .= '</form>' . "\n";
347 } else { // view mode
348 if (preg_match('/^email/', $typeofdata)) {
349 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
350 } elseif (preg_match('/^phone/', $typeofdata)) {
351 $ret .= dol_print_phone($value, '_blank', 32, 1);
352 } elseif (preg_match('/^url/', $typeofdata)) {
353 $ret .= dol_print_url($value, '_blank', 32, 1);
354 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
355 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
356 } elseif (preg_match('/^checkbox/', $typeofdata)) {
357 $tmp = explode(':', $typeofdata);
358 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
359 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
361 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
363 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
364 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
365 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
366 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
367 } elseif (preg_match('/^select;/', $typeofdata)) {
368 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
369 $arraylist = array();
370 foreach ($arraydata as $val) {
371 $tmp = explode(':', $val);
372 $arraylist[$tmp[0]] = $tmp[1];
373 }
374 $ret .= $arraylist[$value];
375 if ($htmlname == 'fk_product_type') {
376 if ($value == 0) {
377 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
378 } else {
379 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
380 }
381 }
382 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
383 $tmpcontent = dol_htmlentitiesbr($value);
384 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
385 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
386 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
387 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
388 }
389 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
390 // clean data from some dangerous html
392 } else {
393 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
394 $ret .= dol_escape_htmltag($value);
395 } else {
396 $ret .= $value; // $value must be already html escaped.
397 }
398 }
399
400 // Custom format if parameter $formatfunc has been provided
401 if ($formatfunc && method_exists($object, $formatfunc)) {
402 $ret = $object->$formatfunc($ret);
403 }
404 }
405 }
406 return $ret;
407 }
408
420 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
421 {
422 global $conf, $langs, $extralanguages;
423
424 $result = '';
425
426 // List of extra languages
427 $arrayoflangcode = array();
428 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
429 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
430 }
431
432 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
433 if (!is_object($extralanguages)) {
434 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
435 $extralanguages = new ExtraLanguages($this->db);
436 }
437 $extralanguages->fetch_name_extralanguages('societe');
438
439 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
440 return ''; // No extralang field to show
441 }
442
443 $result .= '<!-- Widget for translation -->' . "\n";
444 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
445 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
446 $result .= $s;
447 $result .= '</div>';
448
449 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
450
451 $resultforextrlang = '';
452 foreach ($arrayoflangcode as $langcode) {
453 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
454 if (empty($valuetoshow)) {
455 $object->fetchValuesForExtraLanguages();
456 //var_dump($object->array_languages);
457 $valuetoshow = $object->array_languages[$fieldname][$langcode];
458 }
459
460 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
461 $resultforextrlang .= $s;
462
463 // TODO Use the showInputField() method of ExtraLanguages object
464 if ($typeofdata == 'textarea') {
465 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
466 $resultforextrlang .= $valuetoshow;
467 $resultforextrlang .= '</textarea>';
468 } else {
469 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
470 }
471 }
472 $result .= $resultforextrlang;
473
474 $result .= '</div>';
475 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
476 }
477
478 return $result;
479 }
480
494 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
495 {
496 $out = '';
497
498 // Check parameters
499 if (preg_match('/^text/', $inputType)) {
500 $value = dol_nl2br($value);
501 } elseif (preg_match('/^numeric/', $inputType)) {
502 $value = price($value);
503 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
504 $value = dol_print_date($value, 'day');
505 }
506
507 if ($condition) {
508 $element = false;
509 $table_element = false;
510 $fk_element = false;
511 $loadmethod = false;
512 $savemethod = false;
513 $ext_element = false;
514 $button_only = false;
515 $inputOption = '';
516 $rows = '';
517 $cols = '';
518
519 if (is_object($object)) {
520 $element = $object->element;
521 $table_element = $object->table_element;
522 $fk_element = $object->id;
523 }
524
525 if (is_object($extObject)) {
526 $ext_element = $extObject->element;
527 }
528
529 if (preg_match('/^(string|email|numeric)/', $inputType)) {
530 $tmp = explode(':', $inputType);
531 $inputType = $tmp[0];
532 if (!empty($tmp[1])) {
533 $inputOption = $tmp[1];
534 }
535 if (!empty($tmp[2])) {
536 $savemethod = $tmp[2];
537 }
538 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
539 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
540 $tmp = explode(':', $inputType);
541 $inputType = $tmp[0];
542 if (!empty($tmp[1])) {
543 $inputOption = $tmp[1];
544 }
545 if (!empty($tmp[2])) {
546 $savemethod = $tmp[2];
547 }
548
549 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
550 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
551 $tmp = explode(':', $inputType);
552 $inputType = $tmp[0];
553 $loadmethod = $tmp[1];
554 if (!empty($tmp[2])) {
555 $savemethod = $tmp[2];
556 }
557 if (!empty($tmp[3])) {
558 $button_only = true;
559 }
560 } elseif (preg_match('/^textarea/', $inputType)) {
561 $tmp = explode(':', $inputType);
562 $inputType = $tmp[0];
563 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
564 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
565 } elseif (preg_match('/^ckeditor/', $inputType)) {
566 $tmp = explode(':', $inputType);
567 $inputType = $tmp[0];
568 $toolbar = $tmp[1];
569 if (!empty($tmp[2])) {
570 $width = $tmp[2];
571 }
572 if (!empty($tmp[3])) {
573 $height = $tmp[3];
574 }
575 if (!empty($tmp[4])) {
576 $savemethod = $tmp[4];
577 }
578
579 if (isModEnabled('fckeditor')) {
580 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
581 } else {
582 $inputType = 'textarea';
583 }
584 }
585
586 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
587 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
588 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
589 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
590 if (!empty($savemethod)) {
591 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
592 }
593 if (!empty($ext_element)) {
594 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
595 }
596 if (!empty($custommsg)) {
597 if (is_array($custommsg)) {
598 if (!empty($custommsg['success'])) {
599 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
600 }
601 if (!empty($custommsg['error'])) {
602 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
603 }
604 } else {
605 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
606 }
607 }
608 if ($inputType == 'textarea') {
609 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
610 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
611 }
612 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
613 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
614 } else {
615 $out = $value;
616 }
617
618 return $out;
619 }
620
639 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
640 {
641 if ($incbefore) {
642 $text = $incbefore . $text;
643 }
644 if (!$htmltext) {
645 return $text;
646 }
647 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
648
649 $tag = 'td';
650 if ($notabs == 2) {
651 $tag = 'div';
652 }
653 if ($notabs == 3) {
654 $tag = 'span';
655 }
656 // Sanitize tooltip
657 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
658
659 $extrastyle = '';
660 if ($direction < 0) {
661 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
662 $extrastyle = 'padding: 0px; padding-left: 2px;';
663 }
664 if ($direction > 0) {
665 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
666 $extrastyle = 'padding: 0px; padding-right: 2px;';
667 }
668
669 $classfortooltip = 'classfortooltip';
670
671 $s = '';
672 $textfordialog = '';
673
674 if ($tooltiptrigger == '') {
675 $htmltext = str_replace('"', '&quot;', $htmltext);
676 } else {
677 $classfortooltip = 'classfortooltiponclick';
678 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
679 }
680 if ($tooltipon == 2 || $tooltipon == 3) {
681 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
682 if ($tooltiptrigger == '') {
683 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
684 } else {
685 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
686 }
687 } else {
688 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
689 }
690 if ($tooltipon == 1 || $tooltipon == 3) {
691 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
692 if ($tooltiptrigger == '') {
693 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
694 } else {
695 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
696 }
697 } else {
698 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
699 }
700 if (empty($notabs)) {
701 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
702 } elseif ($notabs == 2) {
703 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
704 }
705 // Define value if value is before
706 if ($direction < 0) {
707 $s .= '<' . $tag . $paramfortooltipimg;
708 if ($tag == 'td') {
709 $s .= ' class="valigntop" width="14"';
710 }
711 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
712 }
713 // Use another method to help avoid having a space in value in order to use this value with jquery
714 // Define label
715 if ((string) $text != '') {
716 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
717 }
718 // Define value if value is after
719 if ($direction > 0) {
720 $s .= '<' . $tag . $paramfortooltipimg;
721 if ($tag == 'td') {
722 $s .= ' class="valignmiddle" width="14"';
723 }
724 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
725 }
726 if (empty($notabs)) {
727 $s .= '</tr></table>';
728 } elseif ($notabs == 2) {
729 $s .= '</div>';
730 }
731
732 return $s;
733 }
734
749 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
750 {
751 global $conf, $langs;
752
753 //For backwards compatibility
754 if ($type == '0') {
755 $type = 'info';
756 } elseif ($type == '1') {
757 $type = 'help';
758 }
759 // Clean parameters
760 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
761
762 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
763 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
764 }
765 $alt = '';
766 if ($tooltiptrigger) {
767 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
768 }
769
770 // If info or help with no javascript, show only text
771 if (empty($conf->use_javascript_ajax)) {
772 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
773 return $text;
774 } else {
775 $alt = $htmltext;
776 $htmltext = '';
777 }
778 }
779
780 // If info or help with smartphone, show only text (tooltip hover can't works)
781 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
782 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
783 return $text;
784 }
785 }
786 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
787 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
788 //{
789 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
790 //}
791
792 $img = '';
793 if ($type == 'info') {
794 $img = img_help(0, $alt);
795 } elseif ($type == 'help') {
796 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
797 } elseif ($type == 'helpclickable') {
798 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
799 } elseif ($type == 'superadmin') {
800 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
801 $img = img_picto($alt, 'redstar');
802 } elseif ($type == 'admin') {
803 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
804 $img = img_picto($alt, 'star');
805 } elseif ($type == 'warning') {
806 $img = img_warning($alt);
807 } elseif ($type != 'none') {
808 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
809 $img = img_picto($alt, $type); // $type can be an image path
810 }
811
812 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
813 }
814
825 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
826 {
827 global $conf, $langs, $hookmanager;
828
829 $disabled = 0;
830 $ret = '<div class="centpercent center">';
831 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
832
833 // Complete list with data from external modules. THe module can use $_SERVER['PHP_SELF'] to know on which page we are, or use the $parameters['currentcontext'] completed by executeHooks.
834 $parameters = array();
835 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
836 // check if there is a mass action
837
838 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
839 return;
840 }
841 if (empty($reshook)) {
842 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
843 if (is_array($arrayofaction)) {
844 foreach ($arrayofaction as $code => $label) {
845 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
846 }
847 }
848 }
849 $ret .= $hookmanager->resPrint;
850
851 $ret .= '</select>';
852
853 if (empty($conf->dol_optimize_smallscreen)) {
854 $ret .= ajax_combobox('.' . $name . 'select');
855 }
856
857 // Warning: if you set submit button to disabled, post using 'Enter' will no more work if there is no another input submit. So we add a hidden button
858 $ret .= '<input type="submit" name="confirmmassactioninvisible" style="display: none" tabindex="-1">'; // Hidden button BEFORE so it is the one used when we submit with ENTER.
859 $ret .= '<input type="submit" disabled name="confirmmassaction"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display: none"') . ' class="reposition button smallpaddingimp' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'confirmed" value="' . dol_escape_htmltag($langs->trans("Confirm")) . '">';
860 $ret .= '</div>';
861
862 if (!empty($conf->use_javascript_ajax)) {
863 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
864 <script nonce="' . getNonce() . '">
865 function initCheckForSelect(mode, name, cssclass) /* mode is 0 during init of page or click all, 1 when we click on 1 checkboxi, "name" refers to the class of the massaction button, "cssclass" to the class of the checkfor select boxes */
866 {
867 atleastoneselected=0;
868 jQuery("."+cssclass).each(function( index ) {
869 /* console.log( index + ": " + $( this ).text() ); */
870 if ($(this).is(\':checked\')) atleastoneselected++;
871 });
872
873 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
874
875 if (atleastoneselected || ' . $alwaysvisible . ')
876 {
877 jQuery("."+name).show();
878 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
879 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
880 }
881 else
882 {
883 jQuery("."+name).hide();
884 jQuery("."+name+"other").hide();
885 }
886 }
887
888 jQuery(document).ready(function () {
889 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
890 jQuery(".' . $cssclass . '").click(function() {
891 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
892 });
893 jQuery(".' . $name . 'select").change(function() {
894 var massaction = $( this ).val();
895 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
896 if (massaction == "builddoc")
897 {
898 urlform = urlform + "#show_files";
899 }
900 $( this ).closest("form").attr("action", urlform);
901 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
902 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
903 if ($(this).val() != \'0\')
904 {
905 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
906 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
907 jQuery(".' . $name . '"+massaction).show();
908 }
909 else
910 {
911 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
912 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
913 }
914 });
915 });
916 </script>
917 ';
918 }
919
920 return $ret;
921 }
922
923 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
924
941 public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0)
942 {
943 // phpcs:enable
944 global $conf, $langs, $mysoc;
945
946 $langs->load("dict");
947
948 $out = '';
949 $countryArray = array();
950 $favorite = array();
951 $label = array();
952 $atleastonefavorite = 0;
953
954 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
955 $sql .= " FROM " . $this->db->prefix() . "c_country";
956 $sql .= " WHERE active > 0";
957 //$sql.= " ORDER BY code ASC";
958
959 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
960 $resql = $this->db->query($sql);
961 if ($resql) {
962 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
963 $num = $this->db->num_rows($resql);
964 $i = 0;
965 if ($num) {
966 while ($i < $num) {
967 $obj = $this->db->fetch_object($resql);
968
969 $countryArray[$i]['rowid'] = $obj->rowid;
970 $countryArray[$i]['code_iso'] = $obj->code_iso;
971 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
972 $countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
973 $countryArray[$i]['favorite'] = $obj->favorite;
974 $countryArray[$i]['eec'] = $obj->eec;
975 $favorite[$i] = $obj->favorite;
976 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
977 $i++;
978 }
979
980 if (empty($disablefavorites)) {
981 $array1_sort_order = SORT_DESC;
982 $array2_sort_order = SORT_ASC;
983 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
984 } else {
985 $countryArray = dol_sort_array($countryArray, 'label');
986 }
987
988 if ($showempty) {
989 if (is_numeric($showempty)) {
990 $out .= '<option value="">&nbsp;</option>' . "\n";
991 } else {
992 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
993 }
994 }
995
996 if ($addspecialentries) { // Add dedicated entries for groups of countries
997 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
998 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
999 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
1000 if ($mysoc->isInEEC()) {
1001 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1002 }
1003 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1004 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1005 }
1006
1007 foreach ($countryArray as $row) {
1008 //if (empty($showempty) && empty($row['rowid'])) continue;
1009 if (empty($row['rowid'])) {
1010 continue;
1011 }
1012 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1013 continue; // exclude some countries
1014 }
1015
1016 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1017 $atleastonefavorite++;
1018 }
1019 if (empty($row['favorite']) && $atleastonefavorite) {
1020 $atleastonefavorite = 0;
1021 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1022 }
1023
1024 $labeltoshow = '';
1025 if ($row['label']) {
1026 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1027 } else {
1028 $labeltoshow .= '&nbsp;';
1029 }
1030 if ($row['code_iso']) {
1031 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1032 if (empty($hideflags)) {
1033 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1034 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1035 }
1036 }
1037
1038 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1039 $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1040 } else {
1041 $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1042 }
1043 $out .= $labeltoshow;
1044 $out .= '</option>' . "\n";
1045 }
1046 }
1047 $out .= '</select>';
1048 } else {
1049 dol_print_error($this->db);
1050 }
1051
1052 // Make select dynamic
1053 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1054 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1055
1056 return $out;
1057 }
1058
1059 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1060
1074 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1075 {
1076 // phpcs:enable
1077 global $conf, $langs;
1078
1079 $langs->load("dict");
1080
1081 $out = '';
1082 $moreattrib = '';
1083 $incotermArray = array();
1084
1085 $sql = "SELECT rowid, code";
1086 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1087 $sql .= " WHERE active > 0";
1088 $sql .= " ORDER BY code ASC";
1089
1090 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1091 $resql = $this->db->query($sql);
1092 if ($resql) {
1093 if ($conf->use_javascript_ajax && !$forcecombo) {
1094 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1095 $out .= ajax_combobox($htmlname, $events);
1096 }
1097
1098 if (!empty($page)) {
1099 $out .= '<form method="post" action="' . $page . '">';
1100 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1101 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1102 }
1103
1104 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1105 $out .= '<option value="0">&nbsp;</option>';
1106 $num = $this->db->num_rows($resql);
1107 $i = 0;
1108 if ($num) {
1109 while ($i < $num) {
1110 $obj = $this->db->fetch_object($resql);
1111 $incotermArray[$i]['rowid'] = $obj->rowid;
1112 $incotermArray[$i]['code'] = $obj->code;
1113 $i++;
1114 }
1115
1116 foreach ($incotermArray as $row) {
1117 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1118 $out .= '<option value="' . $row['rowid'] . '" selected>';
1119 } else {
1120 $out .= '<option value="' . $row['rowid'] . '">';
1121 }
1122
1123 if ($row['code']) {
1124 $out .= $row['code'];
1125 }
1126
1127 $out .= '</option>';
1128 }
1129 }
1130 $out .= '</select>';
1131
1132 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1133 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1134 $moreattrib .= ' autocomplete="off"';
1135 }
1136 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1137
1138 if (!empty($page)) {
1139 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1140 }
1141 } else {
1142 dol_print_error($this->db);
1143 }
1144
1145 return $out;
1146 }
1147
1148 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1149
1162 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "")
1163 {
1164 // phpcs:enable
1165 global $langs;
1166
1167 // If product & services are enabled or both disabled.
1168 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1169 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1170 if (empty($hidetext)) {
1171 print $langs->trans("Type") . ': ';
1172 }
1173 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1174 if ($showempty) {
1175 print '<option value="-1"';
1176 if ($selected == -1) {
1177 print ' selected';
1178 }
1179 print '>';
1180 if (is_numeric($showempty)) {
1181 print '&nbsp;';
1182 } else {
1183 print $showempty;
1184 }
1185 print '</option>';
1186 }
1187
1188 print '<option value="0"';
1189 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1190 print ' selected';
1191 }
1192 print '>' . $langs->trans("Product");
1193
1194 print '<option value="1"';
1195 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1196 print ' selected';
1197 }
1198 print '>' . $langs->trans("Service");
1199
1200 print '</select>';
1201 print ajax_combobox('select_' . $htmlname);
1202 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1203 }
1204 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1205 print $langs->trans("Service");
1206 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1207 }
1208 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1209 print $langs->trans("Product");
1210 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1211 }
1212 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1213 print '<input type="hidden" name="' . $htmlname . '" value="1">'; // By default we set on service for contract. If CONTRACT_SUPPORT_PRODUCTS is set, forceall should be 1 not -1
1214 }
1215 }
1216
1217 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1218
1224 public function load_cache_types_fees()
1225 {
1226 // phpcs:enable
1227 global $langs;
1228
1229 $num = count($this->cache_types_fees);
1230 if ($num > 0) {
1231 return 0; // Cache already loaded
1232 }
1233
1234 dol_syslog(__METHOD__, LOG_DEBUG);
1235
1236 $langs->load("trips");
1237
1238 $sql = "SELECT c.code, c.label";
1239 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1240 $sql .= " WHERE active > 0";
1241
1242 $resql = $this->db->query($sql);
1243 if ($resql) {
1244 $num = $this->db->num_rows($resql);
1245 $i = 0;
1246
1247 while ($i < $num) {
1248 $obj = $this->db->fetch_object($resql);
1249
1250 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1251 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1252 $this->cache_types_fees[$obj->code] = $label;
1253 $i++;
1254 }
1255
1256 asort($this->cache_types_fees);
1257
1258 return $num;
1259 } else {
1260 dol_print_error($this->db);
1261 return -1;
1262 }
1263 }
1264
1265 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1266
1275 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1276 {
1277 // phpcs:enable
1278 global $user, $langs;
1279
1280 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1281
1282 $this->load_cache_types_fees();
1283
1284 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1285 if ($showempty) {
1286 print '<option value="-1"';
1287 if ($selected == -1) {
1288 print ' selected';
1289 }
1290 print '>&nbsp;</option>';
1291 }
1292
1293 foreach ($this->cache_types_fees as $key => $value) {
1294 print '<option value="' . $key . '"';
1295 if ($key == $selected) {
1296 print ' selected';
1297 }
1298 print '>';
1299 print $value;
1300 print '</option>';
1301 }
1302
1303 print '</select>';
1304 if ($user->admin) {
1305 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1306 }
1307 }
1308
1309
1310 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1311
1334 public function select_company($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $limit = 0, $morecss = 'minwidth100', $moreparam = '', $selected_input_value = '', $hidelabel = 1, $ajaxoptions = array(), $multiple = false, $excludeids = array(), $showcode = 0)
1335 {
1336 // phpcs:enable
1337 global $conf, $langs;
1338
1339 $out = '';
1340
1341 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1342 if (is_null($ajaxoptions)) {
1343 $ajaxoptions = array();
1344 }
1345
1346 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1347
1348 // No immediate load of all database
1349 $placeholder = '';
1350 if ($selected && empty($selected_input_value)) {
1351 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1352 $societetmp = new Societe($this->db);
1353 $societetmp->fetch($selected);
1354 $selected_input_value = $societetmp->name;
1355 unset($societetmp);
1356 }
1357
1358 // mode 1
1359 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($excludeids) ? '' : '&excludeids=' . implode(',', $excludeids)) . ($showtype ? '&showtype=' . urlencode((string) ($showtype)) : '') . ($showcode ? '&showcode=' . urlencode((string) ($showcode)) : '');
1360
1361 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1362 if (empty($hidelabel)) {
1363 print $langs->trans("RefOrLabel") . ' : ';
1364 } elseif ($hidelabel > 1) {
1365 $placeholder = $langs->trans("RefOrLabel");
1366 if ($hidelabel == 2) {
1367 $out .= img_picto($langs->trans("Search"), 'search');
1368 }
1369 }
1370 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('THIRDPARTY_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1371 if ($hidelabel == 3) {
1372 $out .= img_picto($langs->trans("Search"), 'search');
1373 }
1374
1375 $out .= ajax_event($htmlname, $events);
1376
1377 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1378 } else {
1379 // Immediate load of all database
1380 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1381 }
1382
1383 return $out;
1384 }
1385
1386
1387 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1388
1414 public function select_contact($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $nokeyifsocid = true, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $selected_input_value = '', $filter = '')
1415 {
1416 // phpcs:enable
1417
1418 global $conf, $langs;
1419
1420 $out = '';
1421
1422 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1423 if ($nokeyifsocid && $socid > 0) {
1424 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1425 }
1426
1427 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1428 if (is_null($events)) {
1429 $events = array();
1430 }
1431
1432 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1433
1434 // No immediate load of all database
1435 $placeholder = '';
1436 if ($selected && empty($selected_input_value)) {
1437 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1438 $contacttmp = new Contact($this->db);
1439 $contacttmp->fetch($selected);
1440 $selected_input_value = $contacttmp->getFullName($langs);
1441 unset($contacttmp);
1442 }
1443 if (!is_numeric($showempty)) {
1444 $placeholder = $showempty;
1445 }
1446
1447 // mode 1
1448 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1449
1450 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1451
1452 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('CONTACT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1453
1454 $out .= ajax_event($htmlname, $events);
1455
1456 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1457 } else {
1458 // Immediate load of all database
1459 $multiple = false;
1460 $disableifempty = 0;
1461 $options_only = false;
1462 $limitto = '';
1463
1464 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1465 }
1466
1467 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1468
1469 return $out;
1470 }
1471
1472
1473 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1474
1499 public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false, $excludeids = array(), $showcode = 0)
1500 {
1501 // phpcs:enable
1502 global $user, $langs;
1503 global $hookmanager;
1504
1505 $out = '';
1506 $num = 0;
1507 $outarray = array();
1508
1509 if ($selected === '') {
1510 $selected = array();
1511 } elseif (!is_array($selected)) {
1512 $selected = array($selected);
1513 }
1514
1515 // Clean $filter that may contains sql conditions so sql code
1516 if (function_exists('testSqlAndScriptInject')) {
1517 if (testSqlAndScriptInject($filter, 3) > 0) {
1518 $filter = '';
1519 return 'SQLInjectionTryDetected';
1520 }
1521 }
1522
1523 if ($filter != '') { // If a filter was provided
1524 if (preg_match('/[\‍(\‍)]/', $filter)) {
1525 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1526 $errormsg = '';
1527 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1528
1529 // Redo clean $filter that may contains sql conditions so sql code
1530 if (function_exists('testSqlAndScriptInject')) {
1531 if (testSqlAndScriptInject($filter, 3) > 0) {
1532 $filter = '';
1533 return 'SQLInjectionTryDetected';
1534 }
1535 }
1536 } else {
1537 // If not, we do nothing. We already know that there is no parenthesis
1538 // TODO Disallow this case in a future.
1539 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1540 }
1541 }
1542
1543 // We search companies
1544 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1545 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1546 $sql .= ", s.address, s.zip, s.town";
1547 $sql .= ", dictp.code as country_code";
1548 }
1549 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1550 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1551 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1552 }
1553 if (!$user->hasRight('societe', 'client', 'voir')) {
1554 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1555 }
1556 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1557 if (!empty($user->socid)) {
1558 $sql .= " AND s.rowid = " . ((int) $user->socid);
1559 }
1560 if ($filter) {
1561 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1562 // if not, by testSqlAndScriptInject() only.
1563 $sql .= " AND (" . $filter . ")";
1564 }
1565 if (!$user->hasRight('societe', 'client', 'voir')) {
1566 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1567 }
1568 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1569 $sql .= " AND s.status <> 0";
1570 }
1571 if (!empty($excludeids)) {
1572 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1573 }
1574 // Add where from hooks
1575 $parameters = array();
1576 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1577 $sql .= $hookmanager->resPrint;
1578 // Add criteria
1579 if ($filterkey && $filterkey != '') {
1580 $sql .= " AND (";
1581 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1582 // For natural search
1583 $search_crit = explode(' ', $filterkey);
1584 $i = 0;
1585 if (count($search_crit) > 1) {
1586 $sql .= "(";
1587 }
1588 foreach ($search_crit as $crit) {
1589 if ($i > 0) {
1590 $sql .= " AND ";
1591 }
1592 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1593 $i++;
1594 }
1595 if (count($search_crit) > 1) {
1596 $sql .= ")";
1597 }
1598 if (isModEnabled('barcode')) {
1599 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1600 }
1601 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1602 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1603 $sql .= ")";
1604 }
1605 $sql .= $this->db->order("nom", "ASC");
1606 $sql .= $this->db->plimit($limit, 0);
1607
1608 // Build output string
1609 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1610 $resql = $this->db->query($sql);
1611 if ($resql) {
1612 // Construct $out and $outarray
1613 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1614
1615 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1616 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1617 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1618 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1619 if ($showempty && !is_numeric($showempty)) {
1620 $textifempty = $langs->trans($showempty);
1621 } else {
1622 $textifempty .= $langs->trans("All");
1623 }
1624 }
1625 if ($showempty) {
1626 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1627 }
1628
1629 $companytemp = new Societe($this->db);
1630
1631 $num = $this->db->num_rows($resql);
1632 $i = 0;
1633 if ($num) {
1634 while ($i < $num) {
1635 $obj = $this->db->fetch_object($resql);
1636 $label = '';
1637 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1638 if (($obj->client) && (!empty($obj->code_client))) {
1639 $label = $obj->code_client . ' - ';
1640 }
1641 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1642 $label .= $obj->code_fournisseur . ' - ';
1643 }
1644 $label .= ' ' . $obj->name;
1645 } else {
1646 $label = $obj->name;
1647 }
1648
1649 if (!empty($obj->name_alias)) {
1650 $label .= ' (' . $obj->name_alias . ')';
1651 }
1652
1653 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1654 $label .= ' - '.$obj->tva_intra;
1655 }
1656
1657 $labelhtml = $label;
1658
1659 if ($showtype) {
1660 $companytemp->id = $obj->rowid;
1661 $companytemp->client = $obj->client;
1662 $companytemp->fournisseur = $obj->fournisseur;
1663 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1664 if ($tmptype) {
1665 $labelhtml .= ' ' . $tmptype;
1666 }
1667
1668 if ($obj->client || $obj->fournisseur) {
1669 $label .= ' (';
1670 }
1671 if ($obj->client == 1 || $obj->client == 3) {
1672 $label .= $langs->trans("Customer");
1673 }
1674 if ($obj->client == 2 || $obj->client == 3) {
1675 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1676 }
1677 if ($obj->fournisseur) {
1678 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1679 }
1680 if ($obj->client || $obj->fournisseur) {
1681 $label .= ')';
1682 }
1683 }
1684
1685 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1686 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1687 if (!empty($obj->country_code)) {
1688 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1689 }
1690 $label .= $s;
1691 $labelhtml .= $s;
1692 }
1693
1694 if (empty($outputmode)) {
1695 if (in_array($obj->rowid, $selected)) {
1696 $out .= '<option value="' . $obj->rowid . '" selected data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1697 } else {
1698 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1699 }
1700 } else {
1701 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1702 }
1703
1704 $i++;
1705 if (($i % 10) == 0) {
1706 $out .= "\n";
1707 }
1708 }
1709 }
1710 $out .= '</select>' . "\n";
1711 if (!$forcecombo) {
1712 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1713 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1714 }
1715 } else {
1716 dol_print_error($this->db);
1717 }
1718
1719 $this->result = array('nbofthirdparties' => $num);
1720
1721 if ($outputmode) {
1722 return $outarray;
1723 }
1724 return $out;
1725 }
1726
1727
1753 public function selectcontacts($socid, $selected = array(), $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = 0, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0, $filter = '')
1754 {
1755 global $conf, $langs, $hookmanager, $action;
1756
1757 $langs->load('companies');
1758
1759 if (empty($htmlid)) {
1760 $htmlid = $htmlname;
1761 }
1762 $num = 0;
1763 $out = '';
1764 $outarray = array();
1765
1766 if ($selected === '') {
1767 $selected = array();
1768 } elseif (!is_array($selected)) {
1769 $selected = array((int) $selected);
1770 }
1771
1772 // Clean $filter that may contains sql conditions so sql code
1773 if (function_exists('testSqlAndScriptInject')) {
1774 if (testSqlAndScriptInject($filter, 3) > 0) {
1775 $filter = '';
1776 return 'SQLInjectionTryDetected';
1777 }
1778 }
1779
1780 if ($filter != '') { // If a filter was provided
1781 if (preg_match('/[\‍(\‍)]/', $filter)) {
1782 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1783 $errormsg = '';
1784 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1785
1786 // Redo clean $filter that may contains sql conditions so sql code
1787 if (function_exists('testSqlAndScriptInject')) {
1788 if (testSqlAndScriptInject($filter, 3) > 0) {
1789 $filter = '';
1790 return 'SQLInjectionTryDetected';
1791 }
1792 }
1793 } else {
1794 // If not, we do nothing. We already know that there is no parenthesis
1795 // TODO Disallow this case in a future by returning an error here.
1796 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1797 }
1798 }
1799
1800 if (!is_object($hookmanager)) {
1801 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1802 $hookmanager = new HookManager($this->db);
1803 }
1804
1805 // We search third parties
1806 $sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste, sp.email, sp.phone, sp.phone_perso, sp.phone_mobile, sp.town AS contact_town";
1807 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1808 $sql .= ", s.nom as company, s.town AS company_town";
1809 }
1810 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1811 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1812 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1813 }
1814 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1815 if ($socid > 0 || $socid == -1) {
1816 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1817 }
1818 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1819 $sql .= " AND sp.statut <> 0";
1820 }
1821 if ($filter) {
1822 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1823 // if not, by testSqlAndScriptInject() only.
1824 $sql .= " AND (" . $filter . ")";
1825 }
1826 // Add where from hooks
1827 $parameters = array();
1828 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1829 $sql .= $hookmanager->resPrint;
1830 $sql .= " ORDER BY sp.lastname ASC";
1831
1832 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1833 $resql = $this->db->query($sql);
1834 if ($resql) {
1835 $num = $this->db->num_rows($resql);
1836
1837 if ($htmlname != 'none' && !$options_only) {
1838 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1839 }
1840
1841 if ($showempty && !is_numeric($showempty)) {
1842 $textforempty = $showempty;
1843 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1844 } else {
1845 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1846 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1847 }
1848 if ($showempty == 2) {
1849 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1850 }
1851 }
1852
1853 $i = 0;
1854 if ($num) {
1855 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1856 $contactstatic = new Contact($this->db);
1857
1858 while ($i < $num) {
1859 $obj = $this->db->fetch_object($resql);
1860
1861 // Set email (or phones) and town extended infos
1862 $extendedInfos = '';
1863 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1864 $extendedInfos = array();
1865 $email = trim($obj->email);
1866 if (!empty($email)) {
1867 $extendedInfos[] = $email;
1868 } else {
1869 $phone = trim($obj->phone);
1870 $phone_perso = trim($obj->phone_perso);
1871 $phone_mobile = trim($obj->phone_mobile);
1872 if (!empty($phone)) {
1873 $extendedInfos[] = $phone;
1874 }
1875 if (!empty($phone_perso)) {
1876 $extendedInfos[] = $phone_perso;
1877 }
1878 if (!empty($phone_mobile)) {
1879 $extendedInfos[] = $phone_mobile;
1880 }
1881 }
1882 $contact_town = trim($obj->contact_town);
1883 $company_town = trim($obj->company_town);
1884 if (!empty($contact_town)) {
1885 $extendedInfos[] = $contact_town;
1886 } elseif (!empty($company_town)) {
1887 $extendedInfos[] = $company_town;
1888 }
1889 $extendedInfos = implode(' - ', $extendedInfos);
1890 if (!empty($extendedInfos)) {
1891 $extendedInfos = ' - ' . $extendedInfos;
1892 }
1893 }
1894
1895 $contactstatic->id = $obj->rowid;
1896 $contactstatic->lastname = $obj->lastname;
1897 $contactstatic->firstname = $obj->firstname;
1898 if ($obj->statut == 1) {
1899 $tmplabel = '';
1900 if ($htmlname != 'none') {
1901 $disabled = 0;
1902 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1903 $disabled = 1;
1904 }
1905 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1906 $disabled = 1;
1907 }
1908 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1909 $out .= '<option value="' . $obj->rowid . '"';
1910 if ($disabled) {
1911 $out .= ' disabled';
1912 }
1913 $out .= ' selected>';
1914
1915 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1916 if ($showfunction && $obj->poste) {
1917 $tmplabel .= ' (' . $obj->poste . ')';
1918 }
1919 if (($showsoc > 0) && $obj->company) {
1920 $tmplabel .= ' - (' . $obj->company . ')';
1921 }
1922
1923 $out .= $tmplabel;
1924 $out .= '</option>';
1925 } else {
1926 $out .= '<option value="' . $obj->rowid . '"';
1927 if ($disabled) {
1928 $out .= ' disabled';
1929 }
1930 $out .= '>';
1931
1932 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1933 if ($showfunction && $obj->poste) {
1934 $tmplabel .= ' (' . $obj->poste . ')';
1935 }
1936 if (($showsoc > 0) && $obj->company) {
1937 $tmplabel .= ' - (' . $obj->company . ')';
1938 }
1939
1940 $out .= $tmplabel;
1941 $out .= '</option>';
1942 }
1943 } else {
1944 if (in_array($obj->rowid, $selected)) {
1945 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1946 if ($showfunction && $obj->poste) {
1947 $tmplabel .= ' (' . $obj->poste . ')';
1948 }
1949 if (($showsoc > 0) && $obj->company) {
1950 $tmplabel .= ' - (' . $obj->company . ')';
1951 }
1952
1953 $out .= $tmplabel;
1954 }
1955 }
1956
1957 if ($tmplabel != '') {
1958 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1959 }
1960 }
1961 $i++;
1962 }
1963 } else {
1964 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1965 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1966 $out .= $labeltoshow;
1967 $out .= '</option>';
1968 }
1969
1970 $parameters = array(
1971 'socid' => $socid,
1972 'htmlname' => $htmlname,
1973 'resql' => $resql,
1974 'out' => &$out,
1975 'showfunction' => $showfunction,
1976 'showsoc' => $showsoc,
1977 );
1978
1979 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1980
1981 if ($htmlname != 'none' && !$options_only) {
1982 $out .= '</select>';
1983 }
1984
1985 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1986 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1987 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
1988 }
1989
1990 $this->num = $num;
1991
1992 if ($options_only === 2) {
1993 // Return array of options
1994 return $outarray;
1995 } else {
1996 return $out;
1997 }
1998 } else {
1999 dol_print_error($this->db);
2000 return -1;
2001 }
2002 }
2003
2004
2005 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2006
2017 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2018 {
2019 // phpcs:enable
2020 global $langs, $conf;
2021
2022 // On recherche les remises
2023 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2024 $sql .= " re.description, re.fk_facture_source";
2025 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2026 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2027 $sql .= " AND re.entity = " . $conf->entity;
2028 if ($filter) {
2029 $sql .= " AND " . $filter;
2030 }
2031 $sql .= " ORDER BY re.description ASC";
2032
2033 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2034 $resql = $this->db->query($sql);
2035 if ($resql) {
2036 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2037 $num = $this->db->num_rows($resql);
2038
2039 $qualifiedlines = $num;
2040
2041 $i = 0;
2042 if ($num) {
2043 print '<option value="0">&nbsp;</option>';
2044 while ($i < $num) {
2045 $obj = $this->db->fetch_object($resql);
2046 $desc = dol_trunc($obj->description, 40);
2047 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2048 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2049 }
2050 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2051 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2052 }
2053 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2054 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2055 }
2056 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2057 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2058 }
2059
2060 $selectstring = '';
2061 if ($selected > 0 && $selected == $obj->rowid) {
2062 $selectstring = ' selected';
2063 }
2064
2065 $disabled = '';
2066 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2067 $qualifiedlines--;
2068 $disabled = ' disabled';
2069 }
2070
2071 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2072 $tmpfac = new Facture($this->db);
2073 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2074 $desc = $desc . ' - ' . $tmpfac->ref;
2075 }
2076 }
2077
2078 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2079 $i++;
2080 }
2081 }
2082 print '</select>';
2083 print ajax_combobox('select_' . $htmlname);
2084
2085 return $qualifiedlines;
2086 } else {
2087 dol_print_error($this->db);
2088 return -1;
2089 }
2090 }
2091
2092
2093 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2094
2110 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2111 {
2112 // phpcs:enable
2113 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2114 }
2115
2116 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2117
2142 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2143 {
2144 // phpcs:enable
2145 global $conf, $user, $langs, $hookmanager;
2146 global $action;
2147
2148 // If no preselected user defined, we take current user
2149 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2150 $selected = $user->id;
2151 }
2152
2153 if ($selected === '') {
2154 $selected = array();
2155 } elseif (!is_array($selected)) {
2156 $selected = array($selected);
2157 }
2158
2159 $excludeUsers = null;
2160 $includeUsers = null;
2161
2162 // Exclude some users
2163 if (is_array($exclude)) {
2164 $excludeUsers = implode(",", $exclude);
2165 }
2166 // Include some uses
2167 if (is_array($include)) {
2168 $includeUsers = implode(",", $include);
2169 } elseif ($include == 'hierarchy') {
2170 // Build list includeUsers to have only hierarchy
2171 $includeUsers = implode(",", $user->getAllChildIds(0));
2172 } elseif ($include == 'hierarchyme') {
2173 // Build list includeUsers to have only hierarchy and current user
2174 $includeUsers = implode(",", $user->getAllChildIds(1));
2175 }
2176
2177 $num = 0;
2178
2179 $out = '';
2180 $outarray = array();
2181 $outarray2 = array();
2182
2183 // Do we want to show the label of entity into the combo list ?
2184 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2185 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2186
2187 // Forge request to select users
2188 $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";
2189 if ($showlabelofentity) {
2190 $sql .= ", e.label";
2191 }
2192 $sql .= " FROM " . $this->db->prefix() . "user as u";
2193 if ($showlabelofentity) {
2194 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2195 }
2196 // Condition here should be the same than into societe->getSalesRepresentatives().
2197 if ($userissuperadminentityone && $force_entity != 'default') {
2198 if (!empty($force_entity)) {
2199 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2200 } else {
2201 $sql .= " WHERE u.entity IS NOT NULL";
2202 }
2203 } else {
2204 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2205 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2206 } else {
2207 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2208 }
2209 }
2210
2211 if (!empty($user->socid)) {
2212 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2213 }
2214 if (is_array($exclude) && $excludeUsers) {
2215 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2216 }
2217 if ($includeUsers) {
2218 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2219 }
2220 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2221 $sql .= " AND u.statut <> 0";
2222 }
2223 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2224 $sql .= " AND u.employee <> 0";
2225 }
2226 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2227 $sql .= " AND u.fk_soc IS NULL";
2228 }
2229 if (!empty($morefilter)) {
2230 $sql .= " " . $morefilter;
2231 }
2232
2233 //Add hook to filter on user (for example on usergroup define in custom modules)
2234 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2235 if (!empty($reshook)) {
2236 $sql .= $hookmanager->resPrint;
2237 }
2238
2239 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2240 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2241 } else {
2242 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2243 }
2244
2245 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2246
2247 $resql = $this->db->query($sql);
2248 if ($resql) {
2249 $num = $this->db->num_rows($resql);
2250 $i = 0;
2251 if ($num) {
2252 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2253 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2254 if ($show_empty && !$multiple) {
2255 $textforempty = ' ';
2256 if (!empty($conf->use_javascript_ajax)) {
2257 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2258 }
2259 if (!is_numeric($show_empty)) {
2260 $textforempty = $show_empty;
2261 }
2262 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2263 }
2264 if ($show_every) {
2265 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2266 }
2267
2268 $userstatic = new User($this->db);
2269
2270 while ($i < $num) {
2271 $obj = $this->db->fetch_object($resql);
2272
2273 $userstatic->id = $obj->rowid;
2274 $userstatic->lastname = $obj->lastname;
2275 $userstatic->firstname = $obj->firstname;
2276 $userstatic->photo = $obj->photo;
2277 $userstatic->status = $obj->status;
2278 $userstatic->entity = $obj->entity;
2279 $userstatic->admin = $obj->admin;
2280 $userstatic->gender = $obj->gender;
2281
2282 $disableline = '';
2283 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2284 $disableline = ($enableonlytext ? $enableonlytext : '1');
2285 }
2286
2287 $labeltoshow = '';
2288 $labeltoshowhtml = '';
2289
2290 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2291 $fullNameMode = 0;
2292 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2293 $fullNameMode = 1; //Firstname+lastname
2294 }
2295 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2296 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2297 if (empty($obj->firstname) && empty($obj->lastname)) {
2298 $labeltoshow .= $obj->login;
2299 $labeltoshowhtml .= $obj->login;
2300 }
2301
2302 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2303 $moreinfo = '';
2304 $moreinfohtml = '';
2305 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2306 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2307 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2308 $moreinfo .= $obj->login;
2309 $moreinfohtml .= $obj->login;
2310 }
2311 if ($showstatus >= 0) {
2312 if ($obj->status == 1 && $showstatus == 1) {
2313 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2314 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2315 }
2316 if ($obj->status == 0 && $showstatus == 1) {
2317 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2318 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2319 }
2320 }
2321 if ($showlabelofentity) {
2322 if (empty($obj->entity)) {
2323 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2324 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2325 } else {
2326 if ($obj->entity != $conf->entity) {
2327 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2328 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2329 }
2330 }
2331 }
2332 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2333 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2334 if (!empty($disableline) && $disableline != '1') {
2335 // Add text from $enableonlytext parameter
2336 $moreinfo .= ' - ' . $disableline;
2337 $moreinfohtml .= ' - ' . $disableline;
2338 }
2339 $labeltoshow .= $moreinfo;
2340 $labeltoshowhtml .= $moreinfohtml;
2341
2342 $out .= '<option value="' . $obj->rowid . '"';
2343 if (!empty($disableline)) {
2344 $out .= ' disabled';
2345 }
2346 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2347 $out .= ' selected';
2348 }
2349 $out .= ' data-html="';
2350
2351 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2352 if ($showstatus >= 0 && $obj->status == 0) {
2353 $outhtml .= '<strike class="opacitymediumxxx">';
2354 }
2355 $outhtml .= $labeltoshowhtml;
2356 if ($showstatus >= 0 && $obj->status == 0) {
2357 $outhtml .= '</strike>';
2358 }
2359 $labeltoshowhtml = $outhtml;
2360
2361 $out .= dol_escape_htmltag($outhtml);
2362 $out .= '">';
2363 $out .= $labeltoshow;
2364 $out .= '</option>';
2365
2366 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2367 $outarray2[$userstatic->id] = array(
2368 'id' => $userstatic->id,
2369 'label' => $labeltoshow,
2370 'labelhtml' => $labeltoshowhtml,
2371 'color' => '',
2372 'picto' => ''
2373 );
2374
2375 $i++;
2376 }
2377 } else {
2378 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2379 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2380 }
2381 $out .= '</select>';
2382
2383 if ($num && !$forcecombo) {
2384 // Enhance with select2
2385 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2386 $out .= ajax_combobox($htmlname);
2387 }
2388 } else {
2389 dol_print_error($this->db);
2390 }
2391
2392 $this->num = $num;
2393
2394 if ($outputmode == 2) {
2395 return $outarray2;
2396 } elseif ($outputmode) {
2397 return $outarray;
2398 }
2399
2400 return $out;
2401 }
2402
2403
2404 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2427 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())
2428 {
2429 // phpcs:enable
2430 global $langs;
2431
2432 $userstatic = new User($this->db);
2433 $out = '';
2434
2435 if (!empty($_SESSION['assignedtouser'])) {
2436 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2437 if (!is_array($assignedtouser)) {
2438 $assignedtouser = array();
2439 }
2440 } else {
2441 $assignedtouser = array();
2442 }
2443 $nbassignetouser = count($assignedtouser);
2444
2445 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2446 if ($nbassignetouser) {
2447 $out .= '<ul class="attendees">';
2448 }
2449 $i = 0;
2450 $ownerid = 0;
2451 foreach ($assignedtouser as $key => $value) {
2452 if ($value['id'] == $ownerid) {
2453 continue;
2454 }
2455
2456 $out .= '<li>';
2457 $userstatic->fetch($value['id']);
2458 $out .= $userstatic->getNomUrl(-1);
2459 if ($i == 0) {
2460 $ownerid = $value['id'];
2461 $out .= ' (' . $langs->trans("Owner") . ')';
2462 }
2463 if ($nbassignetouser > 1 && $action != 'view') {
2464 $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 . '">';
2465 }
2466 // Show my availability
2467 if ($showproperties) {
2468 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2469 $out .= '<div class="myavailability inline-block">';
2470 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparency" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofuserid[$ownerid]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2471 $out .= '</div>';
2472 }
2473 }
2474 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2475 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2476
2477 $out .= '</li>';
2478 $i++;
2479 }
2480 if ($nbassignetouser) {
2481 $out .= '</ul>';
2482 }
2483
2484 // Method with no ajax
2485 if ($action != 'view') {
2486 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2487 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2488 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2489 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2490 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2491 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2492 $out .= '});';
2493 $out .= '})</script>';
2494 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2495 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2496 $out .= '<br>';
2497 }
2498
2499 return $out;
2500 }
2501
2502 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2522 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())
2523 {
2524 // phpcs:enable
2525 global $langs;
2526
2527 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2528 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2529 $formresources = new FormResource($this->db);
2530 $resourcestatic = new Dolresource($this->db);
2531
2532 $out = '';
2533 if (!empty($_SESSION['assignedtoresource'])) {
2534 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2535 if (!is_array($assignedtoresource)) {
2536 $assignedtoresource = array();
2537 }
2538 } else {
2539 $assignedtoresource = array();
2540 }
2541 $nbassignetoresource = count($assignedtoresource);
2542
2543 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2544 if ($nbassignetoresource) {
2545 $out .= '<ul class="attendees">';
2546 }
2547 $i = 0;
2548
2549 foreach ($assignedtoresource as $key => $value) {
2550 $out .= '<li>';
2551 $resourcestatic->fetch($value['id']);
2552 $out .= $resourcestatic->getNomUrl(-1);
2553 if ($nbassignetoresource > 1 && $action != 'view') {
2554 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassigned reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2555 }
2556 // Show my availability
2557 if ($showproperties) {
2558 if (is_array($listofresourceid) && count($listofresourceid)) {
2559 $out .= '<div class="myavailability inline-block">';
2560 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparencyresource" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2561 $out .= '</div>';
2562 }
2563 }
2564 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2565 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2566
2567 $out .= '</li>';
2568 $i++;
2569 }
2570 if ($nbassignetoresource) {
2571 $out .= '</ul>';
2572 }
2573
2574 // Method with no ajax
2575 if ($action != 'view') {
2576 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassignedresource" value="">';
2577 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2578 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2579 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2580 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2581 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2582 $out .= '});';
2583 $out .= '})</script>';
2584
2585 $events = array();
2586 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2587 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2588 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2589 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2590 $out .= '<br>';
2591 }
2592
2593 return $out;
2594 }
2595
2596 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2597
2626 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)
2627 {
2628 // phpcs:enable
2629 global $langs, $conf;
2630
2631 $out = '';
2632
2633 // check parameters
2634 $price_level = (!empty($price_level) ? $price_level : 0);
2635 if (is_null($ajaxoptions)) {
2636 $ajaxoptions = array();
2637 }
2638
2639 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2640 if (isModEnabled("product") && !isModEnabled('service')) {
2641 $filtertype = '0';
2642 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2643 $filtertype = '1';
2644 }
2645 }
2646
2647 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2648 $placeholder = '';
2649
2650 if ($selected && empty($selected_input_value)) {
2651 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2652 $producttmpselect = new Product($this->db);
2653 $producttmpselect->fetch($selected);
2654 $selected_input_value = $producttmpselect->ref;
2655 unset($producttmpselect);
2656 }
2657 // handle case where product or service module is disabled + no filter specified
2658 if ($filtertype == '') {
2659 if (!isModEnabled('product')) { // when product module is disabled, show services only
2660 $filtertype = 1;
2661 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2662 $filtertype = 0;
2663 }
2664 }
2665 // mode=1 means customers products
2666 $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;
2667 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2668
2669 if (isModEnabled('variants') && is_array($selected_combinations)) {
2670 // Code to automatically insert with javascript the select of attributes under the select of product
2671 // when a parent of variant has been selected.
2672 $out .= '
2673 <!-- script to auto show attributes select tags if a variant was selected -->
2674 <script nonce="' . getNonce() . '">
2675 // auto show attributes fields
2676 selected = ' . json_encode($selected_combinations) . ';
2677 combvalues = {};
2678
2679 jQuery(document).ready(function () {
2680
2681 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2682 if (jQuery(this).val() == \'free\') {
2683 jQuery(\'div#attributes_box\').empty();
2684 }
2685 });
2686
2687 jQuery("input#' . $htmlname . '").change(function () {
2688
2689 if (!jQuery(this).val()) {
2690 jQuery(\'div#attributes_box\').empty();
2691 return;
2692 }
2693
2694 console.log("A change has started. We get variants fields to inject html select");
2695
2696 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2697 id: jQuery(this).val()
2698 }, function (data) {
2699 jQuery(\'div#attributes_box\').empty();
2700
2701 jQuery.each(data, function (key, val) {
2702
2703 combvalues[val.id] = val.values;
2704
2705 var span = jQuery(document.createElement(\'div\')).css({
2706 \'display\': \'table-row\'
2707 });
2708
2709 span.append(
2710 jQuery(document.createElement(\'div\')).text(val.label).css({
2711 \'font-weight\': \'bold\',
2712 \'display\': \'table-cell\'
2713 })
2714 );
2715
2716 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2717 \'margin-left\': \'15px\',
2718 \'white-space\': \'pre\'
2719 }).append(
2720 jQuery(document.createElement(\'option\')).val(\'\')
2721 );
2722
2723 jQuery.each(combvalues[val.id], function (key, val) {
2724 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2725
2726 if (selected[val.fk_product_attribute] == val.id) {
2727 tag.attr(\'selected\', \'selected\');
2728 }
2729
2730 html.append(tag);
2731 });
2732
2733 span.append(html);
2734 jQuery(\'div#attributes_box\').append(span);
2735 });
2736 })
2737 });
2738
2739 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2740 });
2741 </script>
2742 ';
2743 }
2744
2745 if (empty($hidelabel)) {
2746 $out .= $langs->trans("RefOrLabel") . ' : ';
2747 } elseif ($hidelabel > 1) {
2748 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
2749 if ($hidelabel == 2) {
2750 $out .= img_picto($langs->trans("Search"), 'search');
2751 }
2752 }
2753 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2754 if ($hidelabel == 3) {
2755 $out .= img_picto($langs->trans("Search"), 'search');
2756 }
2757 } else {
2758 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2759 }
2760
2761 if (empty($nooutput)) {
2762 print $out;
2763 } else {
2764 return $out;
2765 }
2766 }
2767
2768 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2769
2785 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2786 {
2787 // phpcs:enable
2788 global $db;
2789
2790 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2791
2792 $error = 0;
2793 $out = '';
2794
2795 if (!$forcecombo) {
2796 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2797 $events = array();
2798 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2799 }
2800
2801 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2802
2803 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2804 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2805 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2806 if (!empty($status)) {
2807 $sql .= ' AND status = ' . (int) $status;
2808 }
2809 if (!empty($type)) {
2810 $sql .= ' AND bomtype = ' . (int) $type;
2811 }
2812 if (!empty($TProducts)) {
2813 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2814 }
2815 if (!empty($limit)) {
2816 $sql .= ' LIMIT ' . (int) $limit;
2817 }
2818 $resql = $db->query($sql);
2819 if ($resql) {
2820 if ($showempty) {
2821 $out .= '<option value="-1"';
2822 if (empty($selected)) {
2823 $out .= ' selected';
2824 }
2825 $out .= '>&nbsp;</option>';
2826 }
2827 while ($obj = $db->fetch_object($resql)) {
2828 $product = new Product($db);
2829 $res = $product->fetch($obj->fk_product);
2830 $out .= '<option value="' . $obj->rowid . '"';
2831 if ($obj->rowid == $selected) {
2832 $out .= 'selected';
2833 }
2834 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2835 }
2836 } else {
2837 $error++;
2838 dol_print_error($db);
2839 }
2840 $out .= '</select>';
2841 if (empty($nooutput)) {
2842 print $out;
2843 } else {
2844 return $out;
2845 }
2846 }
2847
2848 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2849
2875 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)
2876 {
2877 // phpcs:enable
2878 global $langs;
2879 global $hookmanager;
2880
2881 $out = '';
2882 $outarray = array();
2883
2884 // Units
2885 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2886 $langs->load('other');
2887 }
2888
2889 $warehouseStatusArray = array();
2890 if (!empty($warehouseStatus)) {
2891 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2892 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2893 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2894 }
2895 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2896 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2897 }
2898 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2899 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2900 }
2901 }
2902
2903 $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";
2904 if (count($warehouseStatusArray)) {
2905 $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
2906 } else {
2907 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2908 }
2909
2910 $sql = "SELECT ";
2911
2912 // Add select from hooks
2913 $parameters = array();
2914 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2915 if (empty($reshook)) {
2916 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2917 } else {
2918 $sql .= $hookmanager->resPrint;
2919 }
2920
2921 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2922 //Product category
2923 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2924 FROM " . $this->db->prefix() . "categorie_product
2925 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2926 LIMIT 1
2927 ) AS categorie_product_id ";
2928 }
2929
2930 //Price by customer
2931 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2932 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2933 $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';
2934 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2935 }
2936 // Units
2937 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2938 $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";
2939 $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';
2940 }
2941
2942 // Multilang : we add translation
2943 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2944 $sql .= ", pl.label as label_translated";
2945 $sql .= ", pl.description as description_translated";
2946 $selectFields .= ", label_translated";
2947 $selectFields .= ", description_translated";
2948 }
2949 // Price by quantity
2950 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2951 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2952 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2953 $sql .= " AND price_level = " . ((int) $price_level);
2954 }
2955 $sql .= " ORDER BY date_price";
2956 $sql .= " DESC LIMIT 1) as price_rowid";
2957 $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
2958 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2959 $sql .= " AND price_level = " . ((int) $price_level);
2960 }
2961 $sql .= " ORDER BY date_price";
2962 $sql .= " DESC LIMIT 1) as price_by_qty";
2963 $selectFields .= ", price_rowid, price_by_qty";
2964 }
2965
2966 $sql .= " FROM ".$this->db->prefix()."product as p";
2967
2968 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
2969 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
2970 }
2971
2972 // Add from (left join) from hooks
2973 $parameters = array();
2974 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
2975 $sql .= $hookmanager->resPrint;
2976
2977 if (count($warehouseStatusArray)) {
2978 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
2979 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
2980 $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.
2981 }
2982
2983 // include search in supplier ref
2984 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
2985 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2986 }
2987
2988 //Price by customer
2989 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2990 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
2991 }
2992 // Units
2993 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2994 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
2995 }
2996 // Multilang : we add translation
2997 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2998 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
2999 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3000 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3001 $soc = new Societe($this->db);
3002 $result = $soc->fetch($socid);
3003 if ($result > 0 && !empty($soc->default_lang)) {
3004 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3005 } else {
3006 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3007 }
3008 } else {
3009 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3010 }
3011 }
3012
3013 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3014 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3015 }
3016
3017 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3018
3019 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3020 $sql .= " AND pac.rowid IS NULL";
3021 }
3022
3023 if ($finished == 0) {
3024 $sql .= " AND p.finished = " . ((int) $finished);
3025 } elseif ($finished == 1) {
3026 $sql .= " AND p.finished = ".((int) $finished);
3027 }
3028 if ($status >= 0) {
3029 $sql .= " AND p.tosell = ".((int) $status);
3030 }
3031 if ($status_purchase >= 0) {
3032 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3033 }
3034 // Filter by product type
3035 if (strval($filtertype) != '') {
3036 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3037 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3038 $sql .= " AND p.fk_product_type = 1";
3039 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3040 $sql .= " AND p.fk_product_type = 0";
3041 }
3042 // Add where from hooks
3043 $parameters = array();
3044 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3045 $sql .= $hookmanager->resPrint;
3046 // Add criteria on ref/label
3047 if ($filterkey != '') {
3048 $sql .= ' AND (';
3049 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3050 // For natural search
3051 $search_crit = explode(' ', $filterkey);
3052 $i = 0;
3053 if (count($search_crit) > 1) {
3054 $sql .= "(";
3055 }
3056 foreach ($search_crit as $crit) {
3057 if ($i > 0) {
3058 $sql .= " AND ";
3059 }
3060 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3061 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3062 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3063 }
3064 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
3065 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3066 }
3067 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3068 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3069 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3070 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3071 }
3072 }
3073 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3074 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3075 }
3076 $sql .= ")";
3077 $i++;
3078 }
3079 if (count($search_crit) > 1) {
3080 $sql .= ")";
3081 }
3082 if (isModEnabled('barcode')) {
3083 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3084 }
3085 $sql .= ')';
3086 }
3087 if (count($warehouseStatusArray)) {
3088 $sql .= " GROUP BY " . $selectFields;
3089 }
3090
3091 //Sort by category
3092 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3093 $sql .= " ORDER BY categorie_product_id ";
3094 //ASC OR DESC order
3095 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3096 } else {
3097 $sql .= $this->db->order("p.ref");
3098 }
3099
3100 $sql .= $this->db->plimit($limit, 0);
3101
3102 // Build output string
3103 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3104 $result = $this->db->query($sql);
3105 if ($result) {
3106 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3107 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3108 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3109
3110 $num = $this->db->num_rows($result);
3111
3112 $events = array();
3113
3114 if (!$forcecombo) {
3115 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3116 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3117 }
3118
3119 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3120
3121 $textifempty = '';
3122 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3123 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3124 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3125 if ($showempty && !is_numeric($showempty)) {
3126 $textifempty = $langs->trans($showempty);
3127 } else {
3128 $textifempty .= $langs->trans("All");
3129 }
3130 } else {
3131 if ($showempty && !is_numeric($showempty)) {
3132 $textifempty = $langs->trans($showempty);
3133 }
3134 }
3135 if ($showempty) {
3136 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3137 }
3138
3139 $i = 0;
3140 while ($num && $i < $num) {
3141 $opt = '';
3142 $optJson = array();
3143 $objp = $this->db->fetch_object($result);
3144
3145 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
3146 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3147 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3148 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3149 $sql .= " ORDER BY quantity ASC";
3150
3151 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3152 $result2 = $this->db->query($sql);
3153 if ($result2) {
3154 $nb_prices = $this->db->num_rows($result2);
3155 $j = 0;
3156 while ($nb_prices && $j < $nb_prices) {
3157 $objp2 = $this->db->fetch_object($result2);
3158
3159 $objp->price_by_qty_rowid = $objp2->rowid;
3160 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3161 $objp->price_by_qty_quantity = $objp2->quantity;
3162 $objp->price_by_qty_unitprice = $objp2->unitprice;
3163 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3164 // For backward compatibility
3165 $objp->quantity = $objp2->quantity;
3166 $objp->price = $objp2->price;
3167 $objp->unitprice = $objp2->unitprice;
3168 $objp->remise_percent = $objp2->remise_percent;
3169
3170 //$objp->tva_tx is not overwritten by $objp2 value
3171 //$objp->default_vat_code is not overwritten by $objp2 value
3172
3173 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3174
3175 $j++;
3176
3177 // Add new entry
3178 // "key" value of json key array is used by jQuery automatically as selected value
3179 // "label" value of json key array is used by jQuery automatically as text for combo box
3180 $out .= $opt;
3181 array_push($outarray, $optJson);
3182 }
3183 }
3184 } else {
3185 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3186 $price_product = new Product($this->db);
3187 $price_product->fetch($objp->rowid, '', '', 1);
3188
3189 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3190 $priceparser = new PriceParser($this->db);
3191 $price_result = $priceparser->parseProduct($price_product);
3192 if ($price_result >= 0) {
3193 $objp->price = $price_result;
3194 $objp->unitprice = $price_result;
3195 //Calculate the VAT
3196 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3197 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3198 }
3199 }
3200
3201 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3202 // Add new entry
3203 // "key" value of json key array is used by jQuery automatically as selected value
3204 // "label" value of json key array is used by jQuery automatically as text for combo box
3205 $out .= $opt;
3206 array_push($outarray, $optJson);
3207 }
3208
3209 $i++;
3210 }
3211
3212 $out .= '</select>';
3213
3214 $this->db->free($result);
3215
3216 if (empty($outputmode)) {
3217 return $out;
3218 }
3219
3220 return $outarray;
3221 } else {
3222 dol_print_error($this->db);
3223 }
3224
3225 return '';
3226 }
3227
3243 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3244 {
3245 global $langs, $conf, $user;
3246 global $hookmanager;
3247
3248 $outkey = '';
3249 $outval = '';
3250 $outref = '';
3251 $outlabel = '';
3252 $outlabel_translated = '';
3253 $outdesc = '';
3254 $outdesc_translated = '';
3255 $outbarcode = '';
3256 $outorigin = '';
3257 $outtype = '';
3258 $outprice_ht = '';
3259 $outprice_ttc = '';
3260 $outpricebasetype = '';
3261 $outtva_tx = '';
3262 $outdefault_vat_code = '';
3263 $outqty = 1;
3264 $outdiscount = 0;
3265
3266 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3267
3268 $label = $objp->label;
3269 if (!empty($objp->label_translated)) {
3270 $label = $objp->label_translated;
3271 }
3272 if (!empty($filterkey) && $filterkey != '') {
3273 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3274 }
3275
3276 $outkey = $objp->rowid;
3277 $outref = $objp->ref;
3278 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3279 $outlabel = $objp->label;
3280 $outdesc = $objp->description;
3281 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3282 $outlabel_translated = $objp->label_translated;
3283 $outdesc_translated = $objp->description_translated;
3284 }
3285 $outbarcode = $objp->barcode;
3286 $outorigin = $objp->fk_country;
3287 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3288
3289 $outtype = $objp->fk_product_type;
3290 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3291 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3292
3293 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3294 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3295 }
3296
3297 // Units
3298 $outvalUnits = '';
3299 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3300 if (!empty($objp->unit_short)) {
3301 $outvalUnits .= ' - ' . $objp->unit_short;
3302 }
3303 }
3304 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3305 if (!empty($objp->weight) && $objp->weight_units !== null) {
3306 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3307 $outvalUnits .= ' - ' . $unitToShow;
3308 }
3309 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3310 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3311 $outvalUnits .= ' - ' . $unitToShow;
3312 }
3313 if (!empty($objp->surface) && $objp->surface_units !== null) {
3314 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3315 $outvalUnits .= ' - ' . $unitToShow;
3316 }
3317 if (!empty($objp->volume) && $objp->volume_units !== null) {
3318 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3319 $outvalUnits .= ' - ' . $unitToShow;
3320 }
3321 }
3322 if ($outdurationvalue && $outdurationunit) {
3323 $da = array(
3324 'h' => $langs->trans('Hour'),
3325 'd' => $langs->trans('Day'),
3326 'w' => $langs->trans('Week'),
3327 'm' => $langs->trans('Month'),
3328 'y' => $langs->trans('Year')
3329 );
3330 if (isset($da[$outdurationunit])) {
3331 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3332 }
3333 }
3334
3335 $opt = '<option value="' . $objp->rowid . '"';
3336 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3337 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3338 $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 . '"';
3339 }
3340 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3341 if ($user->hasRight('stock', 'lire')) {
3342 if ($objp->stock > 0) {
3343 $opt .= ' class="product_line_stock_ok"';
3344 } elseif ($objp->stock <= 0) {
3345 $opt .= ' class="product_line_stock_too_low"';
3346 }
3347 }
3348 }
3349 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3350 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3351 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3352 }
3353 $opt .= '>';
3354 $opt .= $objp->ref;
3355 if (!empty($objp->custref)) {
3356 $opt .= ' (' . $objp->custref . ')';
3357 }
3358 if ($outbarcode) {
3359 $opt .= ' (' . $outbarcode . ')';
3360 }
3361 $opt .= ' - ' . dol_trunc($label, $maxlengtharticle);
3362 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3363 $opt .= ' (' . getCountry($outorigin, 1) . ')';
3364 }
3365
3366 $objRef = $objp->ref;
3367 if (!empty($objp->custref)) {
3368 $objRef .= ' (' . $objp->custref . ')';
3369 }
3370 if (!empty($filterkey) && $filterkey != '') {
3371 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3372 }
3373 $outval .= $objRef;
3374 if ($outbarcode) {
3375 $outval .= ' (' . $outbarcode . ')';
3376 }
3377 $outval .= ' - ' . dol_trunc($label, $maxlengtharticle);
3378 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3379 $outval .= ' (' . getCountry($outorigin, 1) . ')';
3380 }
3381
3382 // Units
3383 $opt .= $outvalUnits;
3384 $outval .= $outvalUnits;
3385
3386 $found = 0;
3387
3388 // Multiprice
3389 // If we need a particular price level (from 1 to n)
3390 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3391 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3392 $sql .= " FROM " . $this->db->prefix() . "product_price";
3393 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3394 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3395 $sql .= " AND price_level = " . ((int) $price_level);
3396 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3397 $sql .= " LIMIT 1";
3398
3399 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3400 $result2 = $this->db->query($sql);
3401 if ($result2) {
3402 $objp2 = $this->db->fetch_object($result2);
3403 if ($objp2) {
3404 $found = 1;
3405 if ($objp2->price_base_type == 'HT') {
3406 $opt .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3407 $outval .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3408 } else {
3409 $opt .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3410 $outval .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3411 }
3412 $outprice_ht = price($objp2->price);
3413 $outprice_ttc = price($objp2->price_ttc);
3414 $outpricebasetype = $objp2->price_base_type;
3415 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3416 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3417 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3418 } else {
3419 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3420 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3421 }
3422 }
3423 } else {
3424 dol_print_error($this->db);
3425 }
3426 }
3427
3428 // Price by quantity
3429 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3430 $found = 1;
3431 $outqty = $objp->quantity;
3432 $outdiscount = $objp->remise_percent;
3433 if ($objp->quantity == 1) {
3434 $opt .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3435 $outval .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3436 $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3437 $outval .= $langs->transnoentities("Unit");
3438 } else {
3439 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3440 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3441 $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3442 $outval .= $langs->transnoentities("Units");
3443 }
3444
3445 $outprice_ht = price($objp->unitprice);
3446 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3447 $outpricebasetype = $objp->price_base_type;
3448 $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
3449 $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
3450 }
3451 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3452 $opt .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3453 $outval .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3454 }
3455 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3456 $opt .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3457 $outval .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3458 }
3459
3460 // Price by customer
3461 if (empty($hidepriceinlabel) && getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
3462 if (!empty($objp->idprodcustprice)) {
3463 $found = 1;
3464
3465 if ($objp->custprice_base_type == 'HT') {
3466 $opt .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3467 $outval .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3468 } else {
3469 $opt .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3470 $outval .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3471 }
3472
3473 $outprice_ht = price($objp->custprice);
3474 $outprice_ttc = price($objp->custprice_ttc);
3475 $outpricebasetype = $objp->custprice_base_type;
3476 $outtva_tx = $objp->custtva_tx;
3477 $outdefault_vat_code = $objp->custdefault_vat_code;
3478 }
3479 }
3480
3481 // If level no defined or multiprice not found, we used the default price
3482 if (empty($hidepriceinlabel) && !$found) {
3483 if ($objp->price_base_type == 'HT') {
3484 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3485 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3486 } else {
3487 $opt .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3488 $outval .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3489 }
3490 $outprice_ht = price($objp->price);
3491 $outprice_ttc = price($objp->price_ttc);
3492 $outpricebasetype = $objp->price_base_type;
3493 $outtva_tx = $objp->tva_tx;
3494 $outdefault_vat_code = $objp->default_vat_code;
3495 }
3496
3497 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3498 if ($user->hasRight('stock', 'lire')) {
3499 $opt .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3500
3501 if ($objp->stock > 0) {
3502 $outval .= ' - <span class="product_line_stock_ok">';
3503 } elseif ($objp->stock <= 0) {
3504 $outval .= ' - <span class="product_line_stock_too_low">';
3505 }
3506 $outval .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3507 $outval .= '</span>';
3508 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3509 $langs->load("stocks");
3510
3511 $tmpproduct = new Product($this->db);
3512 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3513 $tmpproduct->load_virtual_stock();
3514 $virtualstock = $tmpproduct->stock_theorique;
3515
3516 $opt .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3517
3518 $outval .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3519 if ($virtualstock > 0) {
3520 $outval .= '<span class="product_line_stock_ok">';
3521 } elseif ($virtualstock <= 0) {
3522 $outval .= '<span class="product_line_stock_too_low">';
3523 }
3524 $outval .= $virtualstock;
3525 $outval .= '</span>';
3526
3527 unset($tmpproduct);
3528 }
3529 }
3530 }
3531
3532 $parameters = array('objp' => $objp);
3533 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3534 if (empty($reshook)) {
3535 $opt .= $hookmanager->resPrint;
3536 } else {
3537 $opt = $hookmanager->resPrint;
3538 }
3539
3540 $opt .= "</option>\n";
3541 $optJson = array(
3542 'key' => $outkey,
3543 'value' => $outref,
3544 'label' => $outval,
3545 'label2' => $outlabel,
3546 'desc' => $outdesc,
3547 'type' => $outtype,
3548 'price_ht' => price2num($outprice_ht),
3549 'price_ttc' => price2num($outprice_ttc),
3550 'price_ht_locale' => price(price2num($outprice_ht)),
3551 'price_ttc_locale' => price(price2num($outprice_ttc)),
3552 'pricebasetype' => $outpricebasetype,
3553 'tva_tx' => $outtva_tx,
3554 'default_vat_code' => $outdefault_vat_code,
3555 'qty' => $outqty,
3556 'discount' => $outdiscount,
3557 'duration_value' => $outdurationvalue,
3558 'duration_unit' => $outdurationunit,
3559 'pbq' => $outpbq,
3560 'labeltrans' => $outlabel_translated,
3561 'desctrans' => $outdesc_translated,
3562 'ref_customer' => $outrefcust
3563 );
3564 }
3565
3566 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3567
3583 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3584 {
3585 // phpcs:enable
3586 global $langs, $conf;
3587 global $price_level, $status, $finished;
3588
3589 if (!isset($status)) {
3590 $status = 1;
3591 }
3592
3593 $selected_input_value = '';
3594 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3595 if ($selected > 0) {
3596 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3597 $producttmpselect = new Product($this->db);
3598 $producttmpselect->fetch($selected);
3599 $selected_input_value = $producttmpselect->ref;
3600 unset($producttmpselect);
3601 }
3602
3603 // mode=2 means suppliers products
3604 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3605 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3606
3607 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3608 } else {
3609 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3610 }
3611 }
3612
3613 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3614
3633 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 = '')
3634 {
3635 // phpcs:enable
3636 global $langs, $conf, $user;
3637 global $hookmanager;
3638
3639 $out = '';
3640 $outarray = array();
3641
3642 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3643
3644 $langs->load('stocks');
3645 // Units
3646 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3647 $langs->load('other');
3648 }
3649
3650 $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,";
3651 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3652 if (isModEnabled('multicurrency')) {
3653 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3654 }
3655 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3656 $sql .= ", pfp.supplier_reputation";
3657 // if we use supplier description of the products
3658 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3659 $sql .= ", pfp.desc_fourn as description";
3660 } else {
3661 $sql .= ", p.description";
3662 }
3663 // Units
3664 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3665 $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";
3666 }
3667 $sql .= " FROM " . $this->db->prefix() . "product as p";
3668 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3669 if ($socid > 0) {
3670 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3671 }
3672 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3673 // Units
3674 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3675 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3676 }
3677 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3678 if ($statut != -1) {
3679 $sql .= " AND p.tobuy = " . ((int) $statut);
3680 }
3681 if (strval($filtertype) != '') {
3682 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3683 }
3684 if (!empty($filtre)) {
3685 $sql .= " " . $filtre;
3686 }
3687 // Add where from hooks
3688 $parameters = array();
3689 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3690 $sql .= $hookmanager->resPrint;
3691 // Add criteria on ref/label
3692 if ($filterkey != '') {
3693 $sql .= ' AND (';
3694 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3695 // For natural search
3696 $search_crit = explode(' ', $filterkey);
3697 $i = 0;
3698 if (count($search_crit) > 1) {
3699 $sql .= "(";
3700 }
3701 foreach ($search_crit as $crit) {
3702 if ($i > 0) {
3703 $sql .= " AND ";
3704 }
3705 $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) . "%'";
3706 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3707 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3708 }
3709 $sql .= ")";
3710 $i++;
3711 }
3712 if (count($search_crit) > 1) {
3713 $sql .= ")";
3714 }
3715 if (isModEnabled('barcode')) {
3716 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3717 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3718 }
3719 $sql .= ')';
3720 }
3721 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3722 $sql .= $this->db->plimit($limit, 0);
3723
3724 // Build output string
3725
3726 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3727 $result = $this->db->query($sql);
3728 if ($result) {
3729 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3730 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3731
3732 $num = $this->db->num_rows($result);
3733
3734 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3735 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3736 if (!$selected) {
3737 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3738 } else {
3739 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3740 }
3741
3742 $i = 0;
3743 while ($i < $num) {
3744 $objp = $this->db->fetch_object($result);
3745
3746 if (is_null($objp->idprodfournprice)) {
3747 // There is no supplier price found, we will use the vat rate for sale
3748 $objp->tva_tx = $objp->tva_tx_sale;
3749 $objp->default_vat_code = $objp->default_vat_code_sale;
3750 }
3751
3752 $outkey = $objp->idprodfournprice; // id in table of price
3753 if (!$outkey && $alsoproductwithnosupplierprice) {
3754 $outkey = 'idprod_' . $objp->rowid; // id of product
3755 }
3756
3757 $outref = $objp->ref;
3758 $outbarcode = $objp->barcode;
3759 $outqty = 1;
3760 $outdiscount = 0;
3761 $outtype = $objp->fk_product_type;
3762 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3763 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3764
3765 // Units
3766 $outvalUnits = '';
3767 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3768 if (!empty($objp->unit_short)) {
3769 $outvalUnits .= ' - ' . $objp->unit_short;
3770 }
3771 if (!empty($objp->weight) && $objp->weight_units !== null) {
3772 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3773 $outvalUnits .= ' - ' . $unitToShow;
3774 }
3775 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3776 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3777 $outvalUnits .= ' - ' . $unitToShow;
3778 }
3779 if (!empty($objp->surface) && $objp->surface_units !== null) {
3780 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3781 $outvalUnits .= ' - ' . $unitToShow;
3782 }
3783 if (!empty($objp->volume) && $objp->volume_units !== null) {
3784 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3785 $outvalUnits .= ' - ' . $unitToShow;
3786 }
3787 if ($outdurationvalue && $outdurationunit) {
3788 $da = array(
3789 'h' => $langs->trans('Hour'),
3790 'd' => $langs->trans('Day'),
3791 'w' => $langs->trans('Week'),
3792 'm' => $langs->trans('Month'),
3793 'y' => $langs->trans('Year')
3794 );
3795 if (isset($da[$outdurationunit])) {
3796 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3797 }
3798 }
3799 }
3800
3801 $objRef = $objp->ref;
3802 if ($filterkey && $filterkey != '') {
3803 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3804 }
3805 $objRefFourn = $objp->ref_fourn;
3806 if ($filterkey && $filterkey != '') {
3807 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3808 }
3809 $label = $objp->label;
3810 if ($filterkey && $filterkey != '') {
3811 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3812 }
3813
3814 switch ($objp->fk_product_type) {
3816 $picto = 'product';
3817 break;
3819 $picto = 'service';
3820 break;
3821 default:
3822 $picto = '';
3823 break;
3824 }
3825
3826 if (empty($picto)) {
3827 $optlabel = '';
3828 } else {
3829 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3830 }
3831
3832 $optlabel .= $objp->ref;
3833 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3834 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3835 }
3836 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3837 $optlabel .= ' (' . $outbarcode . ')';
3838 }
3839 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3840
3841 $outvallabel = $objRef;
3842 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3843 $outvallabel .= ' (' . $objRefFourn . ')';
3844 }
3845 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3846 $outvallabel .= ' (' . $outbarcode . ')';
3847 }
3848 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3849
3850 // Units
3851 $optlabel .= $outvalUnits;
3852 $outvallabel .= $outvalUnits;
3853
3854 if (!empty($objp->idprodfournprice)) {
3855 $outqty = $objp->quantity;
3856 $outdiscount = $objp->remise_percent;
3857 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3858 $prod_supplier = new ProductFournisseur($this->db);
3859 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3860 $prod_supplier->id = $objp->fk_product;
3861 $prod_supplier->fourn_qty = $objp->quantity;
3862 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3863 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3864
3865 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3866 $priceparser = new PriceParser($this->db);
3867 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3868 if ($price_result >= 0) {
3869 $objp->fprice = $price_result;
3870 if ($objp->quantity >= 1) {
3871 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3872 }
3873 }
3874 }
3875 if ($objp->quantity == 1) {
3876 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3877 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3878 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3879 $outvallabel .= $langs->transnoentities("Unit");
3880 } else {
3881 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3882 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3883 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3884 $outvallabel .= ' ' . $langs->transnoentities("Units");
3885 }
3886
3887 if ($objp->quantity > 1) {
3888 $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
3889 $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
3890 }
3891 if ($objp->remise_percent >= 1) {
3892 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3893 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3894 }
3895 if ($objp->duration) {
3896 $optlabel .= " - " . $objp->duration;
3897 $outvallabel .= " - " . $objp->duration;
3898 }
3899 if (!$socid) {
3900 $optlabel .= " - " . dol_trunc($objp->name, 8);
3901 $outvallabel .= " - " . dol_trunc($objp->name, 8);
3902 }
3903 if ($objp->supplier_reputation) {
3904 //TODO dictionary
3905 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3906
3907 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3908 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3909 }
3910 } else {
3911 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3912 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3913 }
3914
3915 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3916 $novirtualstock = ($showstockinlist == 2);
3917
3918 if ($user->hasRight('stock', 'lire')) {
3919 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3920
3921 if ($objp->stock > 0) {
3922 $optlabel .= ' - <span class="product_line_stock_ok">';
3923 } elseif ($objp->stock <= 0) {
3924 $optlabel .= ' - <span class="product_line_stock_too_low">';
3925 }
3926 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3927 $optlabel .= '</span>';
3928 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3929 $langs->load("stocks");
3930
3931 $tmpproduct = new Product($this->db);
3932 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3933 $tmpproduct->load_virtual_stock();
3934 $virtualstock = $tmpproduct->stock_theorique;
3935
3936 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3937
3938 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3939 if ($virtualstock > 0) {
3940 $optlabel .= '<span class="product_line_stock_ok">';
3941 } elseif ($virtualstock <= 0) {
3942 $optlabel .= '<span class="product_line_stock_too_low">';
3943 }
3944 $optlabel .= $virtualstock;
3945 $optlabel .= '</span>';
3946
3947 unset($tmpproduct);
3948 }
3949 }
3950 }
3951
3952 $optstart = '<option value="' . $outkey . '"';
3953 if ($selected && $selected == $objp->idprodfournprice) {
3954 $optstart .= ' selected';
3955 }
3956 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3957 $optstart .= ' disabled';
3958 }
3959
3960 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3961 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
3962 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
3963 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
3964 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
3965 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
3966 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
3967 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
3968 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
3969 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
3970 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
3971 if (isModEnabled('multicurrency')) {
3972 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
3973 $optstart .= ' data-multicurrency-up="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
3974 }
3975 }
3976 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
3977
3978 $outarrayentry = array(
3979 'key' => $outkey,
3980 'value' => $outref,
3981 'label' => $outvallabel,
3982 'qty' => $outqty,
3983 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3984 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3985 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3986 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
3987 'tva_tx' => price2num($objp->tva_tx),
3988 'default_vat_code' => $objp->default_vat_code,
3989 'supplier_ref' => $objp->ref_fourn,
3990 'discount' => $outdiscount,
3991 'type' => $outtype,
3992 'duration_value' => $outdurationvalue,
3993 'duration_unit' => $outdurationunit,
3994 'disabled' => empty($objp->idprodfournprice),
3995 'description' => $objp->description
3996 );
3997 if (isModEnabled('multicurrency')) {
3998 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
3999 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4000 }
4001
4002 $parameters = array(
4003 'objp' => &$objp,
4004 'optstart' => &$optstart,
4005 'optlabel' => &$optlabel,
4006 'outvallabel' => &$outvallabel,
4007 'outarrayentry' => &$outarrayentry
4008 );
4009 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4010
4011
4012 // Add new entry
4013 // "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
4014 // "label" value of json key array is used by jQuery automatically as text for combo box
4015 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4016 $outarraypush = array(
4017 'key' => $outkey,
4018 'value' => $outref,
4019 'label' => $outvallabel,
4020 'qty' => $outqty,
4021 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4022 'price_qty_ht_locale' => price($objp->fprice),
4023 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4024 'price_unit_ht_locale' => price($objp->unitprice),
4025 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4026 'tva_tx_formated' => price($objp->tva_tx),
4027 'tva_tx' => price2num($objp->tva_tx),
4028 'default_vat_code' => $objp->default_vat_code,
4029 'supplier_ref' => $objp->ref_fourn,
4030 'discount' => $outdiscount,
4031 'type' => $outtype,
4032 'duration_value' => $outdurationvalue,
4033 'duration_unit' => $outdurationunit,
4034 'disabled' => empty($objp->idprodfournprice),
4035 'description' => $objp->description
4036 );
4037 if (isModEnabled('multicurrency')) {
4038 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4039 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4040 }
4041 array_push($outarray, $outarraypush);
4042
4043 // Example of var_dump $outarray
4044 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4045 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4046 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4047 //}
4048 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4049 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4050 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4051
4052 $i++;
4053 }
4054 $out .= '</select>';
4055
4056 $this->db->free($result);
4057
4058 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4059 $out .= ajax_combobox($htmlname);
4060 } else {
4061 dol_print_error($this->db);
4062 }
4063
4064 if (empty($outputmode)) {
4065 return $out;
4066 }
4067 return $outarray;
4068 }
4069
4070 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4071
4080 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4081 {
4082 // phpcs:enable
4083 global $langs, $conf;
4084
4085 $langs->load('stocks');
4086
4087 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4088 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4089 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4090 $sql .= " FROM " . $this->db->prefix() . "product as p";
4091 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4092 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4093 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4094 $sql .= " AND p.tobuy = 1";
4095 $sql .= " AND s.fournisseur = 1";
4096 $sql .= " AND p.rowid = " . ((int) $productid);
4097 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4098 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4099 } else {
4100 $sql .= " ORDER BY pfp.unitprice ASC";
4101 }
4102
4103 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4104 $result = $this->db->query($sql);
4105
4106 if ($result) {
4107 $num = $this->db->num_rows($result);
4108
4109 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4110
4111 if (!$num) {
4112 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4113 } else {
4114 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4115 $form .= '<option value="0">&nbsp;</option>';
4116
4117 $i = 0;
4118 while ($i < $num) {
4119 $objp = $this->db->fetch_object($result);
4120
4121 $opt = '<option value="' . $objp->idprodfournprice . '"';
4122 //if there is only one supplier, preselect it
4123 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4124 $opt .= ' selected';
4125 }
4126 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4127
4128 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4129 $prod_supplier = new ProductFournisseur($this->db);
4130 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4131 $prod_supplier->id = $productid;
4132 $prod_supplier->fourn_qty = $objp->quantity;
4133 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4134 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4135
4136 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4137 $priceparser = new PriceParser($this->db);
4138 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4139 if ($price_result >= 0) {
4140 $objp->fprice = $price_result;
4141 if ($objp->quantity >= 1) {
4142 $objp->unitprice = $objp->fprice / $objp->quantity;
4143 }
4144 }
4145 }
4146 if ($objp->quantity == 1) {
4147 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4148 }
4149
4150 $opt .= $objp->quantity . ' ';
4151
4152 if ($objp->quantity == 1) {
4153 $opt .= $langs->trans("Unit");
4154 } else {
4155 $opt .= $langs->trans("Units");
4156 }
4157 if ($objp->quantity > 1) {
4158 $opt .= " - ";
4159 $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");
4160 }
4161 if ($objp->duration) {
4162 $opt .= " - " . $objp->duration;
4163 }
4164 $opt .= "</option>\n";
4165
4166 $form .= $opt;
4167 $i++;
4168 }
4169 }
4170
4171 $form .= '</select>';
4172 $this->db->free($result);
4173 return $form;
4174 } else {
4175 dol_print_error($this->db);
4176 return '';
4177 }
4178 }
4179
4180
4181 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4188 {
4189 // phpcs:enable
4190 global $langs;
4191
4192 $num = count($this->cache_conditions_paiements);
4193 if ($num > 0) {
4194 return 0; // Cache already loaded
4195 }
4196
4197 dol_syslog(__METHOD__, LOG_DEBUG);
4198
4199 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4200 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4201 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4202 $sql .= " AND active > 0";
4203 $sql .= " ORDER BY sortorder";
4204
4205 $resql = $this->db->query($sql);
4206 if ($resql) {
4207 $num = $this->db->num_rows($resql);
4208 $i = 0;
4209 while ($i < $num) {
4210 $obj = $this->db->fetch_object($resql);
4211
4212 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4213 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4214 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4215 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4216 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4217 $i++;
4218 }
4219
4220 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4221
4222 return $num;
4223 } else {
4224 dol_print_error($this->db);
4225 return -1;
4226 }
4227 }
4228
4229 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4230
4236 public function load_cache_availability()
4237 {
4238 // phpcs:enable
4239 global $langs;
4240
4241 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4242 if ($num > 0) {
4243 return 0; // Cache already loaded
4244 }
4245
4246 dol_syslog(__METHOD__, LOG_DEBUG);
4247
4248 $langs->load('propal');
4249
4250 $sql = "SELECT rowid, code, label, position";
4251 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4252 $sql .= " WHERE active > 0";
4253
4254 $resql = $this->db->query($sql);
4255 if ($resql) {
4256 $num = $this->db->num_rows($resql);
4257 $i = 0;
4258 while ($i < $num) {
4259 $obj = $this->db->fetch_object($resql);
4260
4261 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4262 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4263 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4264 $this->cache_availability[$obj->rowid]['label'] = $label;
4265 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4266 $i++;
4267 }
4268
4269 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4270
4271 return $num;
4272 } else {
4273 dol_print_error($this->db);
4274 return -1;
4275 }
4276 }
4277
4288 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4289 {
4290 global $langs, $user;
4291
4292 $this->load_cache_availability();
4293
4294 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4295
4296 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4297 if ($addempty) {
4298 print '<option value="0">&nbsp;</option>';
4299 }
4300 foreach ($this->cache_availability as $id => $arrayavailability) {
4301 if ($selected == $id) {
4302 print '<option value="' . $id . '" selected>';
4303 } else {
4304 print '<option value="' . $id . '">';
4305 }
4306 print dol_escape_htmltag($arrayavailability['label']);
4307 print '</option>';
4308 }
4309 print '</select>';
4310 if ($user->admin) {
4311 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4312 }
4313 print ajax_combobox($htmlname);
4314 }
4315
4321 public function loadCacheInputReason()
4322 {
4323 global $langs;
4324
4325 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4326 if ($num > 0) {
4327 return 0; // Cache already loaded
4328 }
4329
4330 $sql = "SELECT rowid, code, label";
4331 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4332 $sql .= " WHERE active > 0";
4333
4334 $resql = $this->db->query($sql);
4335 if ($resql) {
4336 $num = $this->db->num_rows($resql);
4337 $i = 0;
4338 $tmparray = array();
4339 while ($i < $num) {
4340 $obj = $this->db->fetch_object($resql);
4341
4342 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4343 $label = ($obj->label != '-' ? $obj->label : '');
4344 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4345 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4346 }
4347 if ($langs->trans($obj->code) != $obj->code) {
4348 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4349 }
4350
4351 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4352 $tmparray[$obj->rowid]['code'] = $obj->code;
4353 $tmparray[$obj->rowid]['label'] = $label;
4354 $i++;
4355 }
4356
4357 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4358
4359 unset($tmparray);
4360 return $num;
4361 } else {
4362 dol_print_error($this->db);
4363 return -1;
4364 }
4365 }
4366
4379 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4380 {
4381 global $langs, $user;
4382
4383 $this->loadCacheInputReason();
4384
4385 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4386 if ($addempty) {
4387 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4388 }
4389 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4390 if ($arraydemandreason['code'] == $exclude) {
4391 continue;
4392 }
4393
4394 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4395 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4396 } else {
4397 print '<option value="' . $arraydemandreason['id'] . '">';
4398 }
4399 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4400 print $langs->trans($label);
4401 print '</option>';
4402 }
4403 print '</select>';
4404 if ($user->admin && empty($notooltip)) {
4405 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4406 }
4407 print ajax_combobox('select_' . $htmlname);
4408 }
4409
4410 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4411
4418 {
4419 // phpcs:enable
4420 global $langs;
4421
4422 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4423 if ($num > 0) {
4424 return $num; // Cache already loaded
4425 }
4426
4427 dol_syslog(__METHOD__, LOG_DEBUG);
4428
4429 $this->cache_types_paiements = array();
4430
4431 $sql = "SELECT id, code, libelle as label, type, active";
4432 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4433 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4434
4435 $resql = $this->db->query($sql);
4436 if ($resql) {
4437 $num = $this->db->num_rows($resql);
4438 $i = 0;
4439 while ($i < $num) {
4440 $obj = $this->db->fetch_object($resql);
4441
4442 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4443 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4444 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4445 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4446 $this->cache_types_paiements[$obj->id]['label'] = $label;
4447 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4448 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4449 $i++;
4450 }
4451
4452 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4453
4454 return $num;
4455 } else {
4456 dol_print_error($this->db);
4457 return -1;
4458 }
4459 }
4460
4461
4462 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4463
4482 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4483 {
4484 // phpcs:enable
4485 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4486 if (empty($noprint)) {
4487 print $out;
4488 } else {
4489 return $out;
4490 }
4491 }
4492
4493
4510 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4511 {
4512 global $langs, $user, $conf;
4513
4514 $out = '';
4515 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4516
4518
4519 // Set default value if not already set by caller
4520 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4521 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4522 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4523 }
4524
4525 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4526 if ($addempty) {
4527 $out .= '<option value="0">&nbsp;</option>';
4528 }
4529
4530 $selectedDepositPercent = null;
4531
4532 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4533 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4534 continue;
4535 }
4536
4537 if ($selected == $id) {
4538 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4539 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4540 } else {
4541 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4542 }
4543 $label = $arrayconditions['label'];
4544
4545 if (!empty($arrayconditions['deposit_percent'])) {
4546 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4547 }
4548
4549 $out .= $label;
4550 $out .= '</option>';
4551 }
4552 $out .= '</select>';
4553 if ($user->admin && empty($noinfoadmin)) {
4554 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4555 }
4556 $out .= ajax_combobox($htmlname);
4557
4558 if ($deposit_percent >= 0) {
4559 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4560 $out .= $langs->trans('DepositPercent') . ' : ';
4561 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4562 $out .= '</span>';
4563 $out .= '
4564 <script nonce="' . getNonce() . '">
4565 $(document).ready(function () {
4566 $("#' . $htmlname . '").change(function () {
4567 let $selected = $(this).find("option:selected");
4568 let depositPercent = $selected.attr("data-deposit_percent");
4569
4570 if (depositPercent.length > 0) {
4571 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4572 } else {
4573 $("#' . $htmlname . '_deposit_percent_container").hide();
4574 }
4575
4576 return true;
4577 });
4578 });
4579 </script>';
4580 }
4581
4582 return $out;
4583 }
4584
4585
4586 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4587
4604 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4605 {
4606 // phpcs:enable
4607 global $langs, $user, $conf;
4608
4609 $out = '';
4610
4611 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4612
4613 $filterarray = array();
4614 if ($filtertype == 'CRDT') {
4615 $filterarray = array(0, 2, 3);
4616 } elseif ($filtertype == 'DBIT') {
4617 $filterarray = array(1, 2, 3);
4618 } elseif ($filtertype != '' && $filtertype != '-1') {
4619 $filterarray = explode(',', $filtertype);
4620 }
4621
4623
4624 // Set default value if not already set by caller
4625 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4626 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4627 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4628 }
4629
4630 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4631 if ($empty) {
4632 $out .= '<option value="">&nbsp;</option>';
4633 }
4634 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4635 // If not good status
4636 if ($active >= 0 && $arraytypes['active'] != $active) {
4637 continue;
4638 }
4639
4640 // We skip of the user requested to filter on specific payment methods
4641 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4642 continue;
4643 }
4644
4645 // We discard empty lines if showempty is on because an empty line has already been output.
4646 if ($empty && empty($arraytypes['code'])) {
4647 continue;
4648 }
4649
4650 if ($format == 0) {
4651 $out .= '<option value="' . $id . '"';
4652 } elseif ($format == 1) {
4653 $out .= '<option value="' . $arraytypes['code'] . '"';
4654 } elseif ($format == 2) {
4655 $out .= '<option value="' . $arraytypes['code'] . '"';
4656 } elseif ($format == 3) {
4657 $out .= '<option value="' . $id . '"';
4658 }
4659 // Print attribute selected or not
4660 if ($format == 1 || $format == 2) {
4661 if ($selected == $arraytypes['code']) {
4662 $out .= ' selected';
4663 }
4664 } else {
4665 if ($selected == $id) {
4666 $out .= ' selected';
4667 }
4668 }
4669 $out .= '>';
4670 $value = '';
4671 if ($format == 0) {
4672 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4673 } elseif ($format == 1) {
4674 $value = $arraytypes['code'];
4675 } elseif ($format == 2) {
4676 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4677 } elseif ($format == 3) {
4678 $value = $arraytypes['code'];
4679 }
4680 $out .= $value ? $value : '&nbsp;';
4681 $out .= '</option>';
4682 }
4683 $out .= '</select>';
4684 if ($user->admin && !$noadmininfo) {
4685 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4686 }
4687 $out .= ajax_combobox('select' . $htmlname);
4688
4689 if (empty($nooutput)) {
4690 print $out;
4691 } else {
4692 return $out;
4693 }
4694 }
4695
4696
4705 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4706 {
4707 global $langs;
4708
4709 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4710 $options = array(
4711 'HT' => $langs->trans("HT"),
4712 'TTC' => $langs->trans("TTC")
4713 );
4714 foreach ($options as $id => $value) {
4715 if ($selected == $id) {
4716 $return .= '<option value="' . $id . '" selected>' . $value;
4717 } else {
4718 $return .= '<option value="' . $id . '">' . $value;
4719 }
4720 $return .= '</option>';
4721 }
4722 $return .= '</select>';
4723 if ($addjscombo) {
4724 $return .= ajax_combobox('select_' . $htmlname);
4725 }
4726
4727 return $return;
4728 }
4729
4730 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4731
4738 {
4739 // phpcs:enable
4740 global $langs;
4741
4742 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4743 if ($num > 0) {
4744 return $num; // Cache already loaded
4745 }
4746
4747 dol_syslog(__METHOD__, LOG_DEBUG);
4748
4749 $this->cache_transport_mode = array();
4750
4751 $sql = "SELECT rowid, code, label, active";
4752 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4753 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4754
4755 $resql = $this->db->query($sql);
4756 if ($resql) {
4757 $num = $this->db->num_rows($resql);
4758 $i = 0;
4759 while ($i < $num) {
4760 $obj = $this->db->fetch_object($resql);
4761
4762 // If traduction exist, we use it else we take the default label
4763 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4764 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4765 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4766 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4767 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4768 $i++;
4769 }
4770
4771 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4772
4773 return $num;
4774 } else {
4775 dol_print_error($this->db);
4776 return -1;
4777 }
4778 }
4779
4793 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4794 {
4795 global $langs, $user;
4796
4797 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4798
4800
4801 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4802 if ($empty) {
4803 print '<option value="">&nbsp;</option>';
4804 }
4805 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4806 // If not good status
4807 if ($active >= 0 && $arraytypes['active'] != $active) {
4808 continue;
4809 }
4810
4811 // We discard empty line if showempty is on because an empty line has already been output.
4812 if ($empty && empty($arraytypes['code'])) {
4813 continue;
4814 }
4815
4816 if ($format == 0) {
4817 print '<option value="' . $id . '"';
4818 } elseif ($format == 1) {
4819 print '<option value="' . $arraytypes['code'] . '"';
4820 } elseif ($format == 2) {
4821 print '<option value="' . $arraytypes['code'] . '"';
4822 } elseif ($format == 3) {
4823 print '<option value="' . $id . '"';
4824 }
4825 // If text is selected, we compare with code, else with id
4826 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4827 print ' selected';
4828 } elseif ($selected == $id) {
4829 print ' selected';
4830 }
4831 print '>';
4832 $value = '';
4833 if ($format == 0) {
4834 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4835 } elseif ($format == 1) {
4836 $value = $arraytypes['code'];
4837 } elseif ($format == 2) {
4838 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4839 } elseif ($format == 3) {
4840 $value = $arraytypes['code'];
4841 }
4842 print $value ? $value : '&nbsp;';
4843 print '</option>';
4844 }
4845 print '</select>';
4846 if ($user->admin && !$noadmininfo) {
4847 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4848 }
4849 }
4850
4863 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4864 {
4865 global $langs, $user;
4866
4867 $langs->load("admin");
4868 $langs->load("deliveries");
4869
4870 $sql = "SELECT rowid, code, libelle as label";
4871 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4872 $sql .= " WHERE active > 0";
4873 if ($filtre) {
4874 $sql .= " AND " . $filtre;
4875 }
4876 $sql .= " ORDER BY libelle ASC";
4877
4878 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4879 $result = $this->db->query($sql);
4880 if ($result) {
4881 $num = $this->db->num_rows($result);
4882 $i = 0;
4883 if ($num) {
4884 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4885 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4886 print '<option value="-1">&nbsp;</option>';
4887 }
4888 while ($i < $num) {
4889 $obj = $this->db->fetch_object($result);
4890 if ($selected == $obj->rowid) {
4891 print '<option value="' . $obj->rowid . '" selected>';
4892 } else {
4893 print '<option value="' . $obj->rowid . '">';
4894 }
4895 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
4896 print '</option>';
4897 $i++;
4898 }
4899 print "</select>";
4900 if ($user->admin && empty($noinfoadmin)) {
4901 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4902 }
4903
4904 print ajax_combobox('select' . $htmlname);
4905 } else {
4906 print $langs->trans("NoShippingMethodDefined");
4907 }
4908 } else {
4909 dol_print_error($this->db);
4910 }
4911 }
4912
4922 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4923 {
4924 global $langs;
4925
4926 $langs->load("deliveries");
4927
4928 if ($htmlname != "none") {
4929 print '<form method="POST" action="' . $page . '">';
4930 print '<input type="hidden" name="action" value="setshippingmethod">';
4931 print '<input type="hidden" name="token" value="' . newToken() . '">';
4932 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4933 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
4934 print '</form>';
4935 } else {
4936 if ($selected) {
4937 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4938 print $langs->trans("SendingMethod" . strtoupper($code));
4939 } else {
4940 print "&nbsp;";
4941 }
4942 }
4943 }
4944
4953 public function selectSituationInvoices($selected = '', $socid = 0)
4954 {
4955 global $langs;
4956
4957 $langs->load('bills');
4958
4959 $opt = '<option value="" selected></option>';
4960 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4961 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
4962 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
4963 $sql .= ' AND situation_counter >= 1';
4964 $sql .= ' AND fk_soc = ' . (int) $socid;
4965 $sql .= ' AND type <> 2';
4966 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4967 $resql = $this->db->query($sql);
4968
4969 if ($resql && $this->db->num_rows($resql) > 0) {
4970 // Last seen cycle
4971 $ref = 0;
4972 while ($obj = $this->db->fetch_object($resql)) {
4973 //Same cycle ?
4974 if ($obj->situation_cycle_ref != $ref) {
4975 // Just seen this cycle
4976 $ref = $obj->situation_cycle_ref;
4977 //not final ?
4978 if ($obj->situation_final != 1) {
4979 //Not prov?
4980 if (substr($obj->ref, 1, 4) != 'PROV') {
4981 if ($selected == $obj->rowid) {
4982 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
4983 } else {
4984 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
4985 }
4986 }
4987 }
4988 }
4989 }
4990 } else {
4991 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
4992 }
4993 if ($opt == '<option value ="" selected></option>') {
4994 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
4995 }
4996 return $opt;
4997 }
4998
5008 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5009 {
5010 global $langs;
5011
5012 $langs->load('products');
5013
5014 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5015
5016 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5017 $sql .= ' WHERE active > 0';
5018 if (!empty($unit_type)) {
5019 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5020 }
5021 $sql .= " ORDER BY sortorder";
5022
5023 $resql = $this->db->query($sql);
5024 if ($resql && $this->db->num_rows($resql) > 0) {
5025 if ($showempty) {
5026 $return .= '<option value="none"></option>';
5027 }
5028
5029 while ($res = $this->db->fetch_object($resql)) {
5030 $unitLabel = $res->label;
5031 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5032 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5033 }
5034
5035 if ($selected == $res->rowid) {
5036 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5037 } else {
5038 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5039 }
5040 }
5041 $return .= '</select>';
5042 }
5043 return $return;
5044 }
5045
5046 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5047
5062 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5063 {
5064 // phpcs:enable
5065 global $langs;
5066
5067 $out = '';
5068
5069 $langs->load("admin");
5070 $num = 0;
5071
5072 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5073 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5074 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5075 if ($status != 2) {
5076 $sql .= " AND clos = " . (int) $status;
5077 }
5078 if ($filtre) { // TODO Support USF
5079 $sql .= " AND " . $filtre;
5080 }
5081 $sql .= " ORDER BY label";
5082
5083 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5084 $result = $this->db->query($sql);
5085 if ($result) {
5086 $num = $this->db->num_rows($result);
5087 $i = 0;
5088 if ($num) {
5089 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5090
5091 if (!empty($useempty) && !is_numeric($useempty)) {
5092 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5093 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5094 $out .= '<option value="-1">&nbsp;</option>';
5095 }
5096
5097 while ($i < $num) {
5098 $obj = $this->db->fetch_object($result);
5099 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5100 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" selected>';
5101 } else {
5102 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '">';
5103 }
5104 $out .= trim($obj->label);
5105 if ($showcurrency) {
5106 $out .= ' (' . $obj->currency_code . ')';
5107 }
5108 if ($status == 2 && $obj->status == 1) {
5109 $out .= ' (' . $langs->trans("Closed") . ')';
5110 }
5111 $out .= '</option>';
5112 $i++;
5113 }
5114 $out .= "</select>";
5115 $out .= ajax_combobox('select' . $htmlname);
5116 } else {
5117 if ($status == 0) {
5118 $out .= '<span class="opacitymedium">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5119 } else {
5120 $out .= '<span class="opacitymedium">' . $langs->trans("NoBankAccountFound") . '</span>';
5121 }
5122 }
5123 } else {
5124 dol_print_error($this->db);
5125 }
5126
5127 // Output or return
5128 if (empty($nooutput)) {
5129 print $out;
5130 } else {
5131 return $out;
5132 }
5133
5134 return $num;
5135 }
5136
5148 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5149 {
5150 global $langs;
5151
5152 $langs->load("admin");
5153 $num = 0;
5154
5155 $sql = "SELECT rowid, name, fk_country, status, entity";
5156 $sql .= " FROM " . $this->db->prefix() . "establishment";
5157 $sql .= " WHERE 1=1";
5158 if ($status != 2) {
5159 $sql .= " AND status = " . (int) $status;
5160 }
5161 if ($filtre) { // TODO Support USF
5162 $sql .= " AND " . $filtre;
5163 }
5164 $sql .= " ORDER BY name";
5165
5166 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5167 $result = $this->db->query($sql);
5168 if ($result) {
5169 $num = $this->db->num_rows($result);
5170 $i = 0;
5171 if ($num) {
5172 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5173 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5174 print '<option value="-1">&nbsp;</option>';
5175 }
5176
5177 while ($i < $num) {
5178 $obj = $this->db->fetch_object($result);
5179 if ($selected == $obj->rowid) {
5180 print '<option value="' . $obj->rowid . '" selected>';
5181 } else {
5182 print '<option value="' . $obj->rowid . '">';
5183 }
5184 print trim($obj->name);
5185 if ($status == 2 && $obj->status == 1) {
5186 print ' (' . $langs->trans("Closed") . ')';
5187 }
5188 print '</option>';
5189 $i++;
5190 }
5191 print "</select>";
5192 } else {
5193 if ($status == 0) {
5194 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5195 } else {
5196 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5197 }
5198 }
5199
5200 return $num;
5201 } else {
5202 dol_print_error($this->db);
5203 return -1;
5204 }
5205 }
5206
5216 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5217 {
5218 global $langs;
5219 if ($htmlname != "none") {
5220 print '<form method="POST" action="' . $page . '">';
5221 print '<input type="hidden" name="action" value="setbankaccount">';
5222 print '<input type="hidden" name="token" value="' . newToken() . '">';
5223 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5224 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5225 if ($nbaccountfound > 0) {
5226 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5227 }
5228 print '</form>';
5229 } else {
5230 $langs->load('banks');
5231
5232 if ($selected) {
5233 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5234 $bankstatic = new Account($this->db);
5235 $result = $bankstatic->fetch($selected);
5236 if ($result) {
5237 print $bankstatic->getNomUrl(1);
5238 }
5239 } else {
5240 print "&nbsp;";
5241 }
5242 }
5243 }
5244
5245 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5246
5266 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5267 {
5268 // phpcs:enable
5269 global $conf, $langs;
5270 $langs->load("categories");
5271
5272 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5273
5274 // For backward compatibility
5275 if (is_numeric($type)) {
5276 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5277 }
5278
5279 if ($type === Categorie::TYPE_BANK_LINE) {
5280 // TODO Move this into common category feature
5281 $cate_arbo = array();
5282 $sql = "SELECT c.label, c.rowid";
5283 $sql .= " FROM " . $this->db->prefix() . "bank_categ as c";
5284 $sql .= " WHERE entity = " . $conf->entity;
5285 $sql .= " ORDER BY c.label";
5286 $result = $this->db->query($sql);
5287 if ($result) {
5288 $num = $this->db->num_rows($result);
5289 $i = 0;
5290 while ($i < $num) {
5291 $objp = $this->db->fetch_object($result);
5292 if ($objp) {
5293 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5294 }
5295 $i++;
5296 }
5297 $this->db->free($result);
5298 } else {
5299 dol_print_error($this->db);
5300 }
5301 } else {
5302 $cat = new Categorie($this->db);
5303 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5304 }
5305
5306 $outarray = array();
5307 $outarrayrichhtml = array();
5308
5309
5310 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5311 if (is_array($cate_arbo)) {
5312 $num = count($cate_arbo);
5313
5314 if (!$num) {
5315 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5316 } else {
5317 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5318 $output .= '<option value="-1">&nbsp;</option>';
5319 }
5320 foreach ($cate_arbo as $key => $value) {
5321 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5322 $add = 'selected ';
5323 } else {
5324 $add = '';
5325 }
5326
5327 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5328 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5329
5330 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5331
5332 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5333
5334 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5335 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5336 $output .= '>';
5337 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5338 $output .= '</option>';
5339
5340 $cate_arbo[$key]['data-html'] = $labeltoshow;
5341 }
5342 }
5343 }
5344 $output .= '</select>';
5345 $output .= "\n";
5346
5347 if ($outputmode == 2) {
5348 // TODO: handle error when $cate_arbo is not an array
5349 return $cate_arbo;
5350 } elseif ($outputmode == 1) {
5351 return $outarray;
5352 } elseif ($outputmode == 3) {
5353 return $outarrayrichhtml;
5354 }
5355 return $output;
5356 }
5357
5358 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5359
5376 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5377 {
5378 // phpcs:enable
5379 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5380 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5381 }
5382
5410 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5411 {
5412 global $langs, $conf;
5413
5414 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5415 $formconfirm = '';
5416 $inputok = array();
5417 $inputko = array();
5418
5419 // Clean parameters
5420 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5421 if ($conf->browser->layout == 'phone') {
5422 $width = '95%';
5423 }
5424
5425 // Set height automatically if not defined
5426 if (empty($height)) {
5427 $height = 220;
5428 if (is_array($formquestion) && count($formquestion) > 2) {
5429 $height += ((count($formquestion) - 2) * 24);
5430 }
5431 }
5432
5433 if (is_array($formquestion) && !empty($formquestion)) {
5434 // First add hidden fields and value
5435 foreach ($formquestion as $key => $input) {
5436 if (is_array($input) && !empty($input)) {
5437 if ($input['type'] == 'hidden') {
5438 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5439 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5440
5441 $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";
5442 }
5443 }
5444 }
5445
5446 // Now add questions
5447 $moreonecolumn = '';
5448 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5449 foreach ($formquestion as $key => $input) {
5450 if (is_array($input) && !empty($input)) {
5451 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5452 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5453 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5454
5455 if ($input['type'] == 'text') {
5456 $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";
5457 } elseif ($input['type'] == 'password') {
5458 $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";
5459 } elseif ($input['type'] == 'textarea') {
5460 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5461 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5462 $more .= $input['value'];
5463 $more .= '</textarea>';
5464 $more .= '</div></div>'."\n";*/
5465 $moreonecolumn .= '<div class="margintoponly">';
5466 $moreonecolumn .= $input['label'] . '<br>';
5467 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5468 $moreonecolumn .= $input['value'];
5469 $moreonecolumn .= '</textarea>';
5470 $moreonecolumn .= '</div>';
5471 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5472 if (empty($morecss)) {
5473 $morecss = 'minwidth100';
5474 }
5475
5476 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5477 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5478 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5479 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5480 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5481 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5482 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5483
5484 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5485 if (!empty($input['label'])) {
5486 $more .= $input['label'] . '</div><div class="tagtd left">';
5487 }
5488 if ($input['type'] == 'select') {
5489 $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);
5490 } else {
5491 $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);
5492 }
5493 $more .= '</div></div>' . "\n";
5494 } elseif ($input['type'] == 'checkbox') {
5495 $more .= '<div class="tagtr">';
5496 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5497 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5498 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5499 $more .= ' checked';
5500 }
5501 if (is_bool($input['value']) && $input['value']) {
5502 $more .= ' checked';
5503 }
5504 if (isset($input['disabled'])) {
5505 $more .= ' disabled';
5506 }
5507 $more .= ' /></div>';
5508 $more .= '</div>' . "\n";
5509 } elseif ($input['type'] == 'radio') {
5510 $i = 0;
5511 foreach ($input['values'] as $selkey => $selval) {
5512 $more .= '<div class="tagtr">';
5513 if (isset($input['label'])) {
5514 if ($i == 0) {
5515 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5516 } else {
5517 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5518 }
5519 }
5520 $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;
5521 if (!empty($input['disabled'])) {
5522 $more .= ' disabled';
5523 }
5524 if (isset($input['default']) && $input['default'] === $selkey) {
5525 $more .= ' checked="checked"';
5526 }
5527 $more .= ' /> ';
5528 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5529 $more .= '</div></div>' . "\n";
5530 $i++;
5531 }
5532 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5533 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5534 $more .= '<div class="tagtd">';
5535 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5536 $h = $m = 0;
5537 if ($input['type'] == 'datetime') {
5538 $h = isset($input['hours']) ? $input['hours'] : 1;
5539 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5540 }
5541 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5542 $more .= '</div></div>'."\n";
5543 $formquestion[] = array('name' => $input['name'].'day');
5544 $formquestion[] = array('name' => $input['name'].'month');
5545 $formquestion[] = array('name' => $input['name'].'year');
5546 $formquestion[] = array('name' => $input['name'].'hour');
5547 $formquestion[] = array('name' => $input['name'].'min');
5548 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5549 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5550 if (!empty($input['label'])) {
5551 $more .= $input['label'] . '</div><div class="tagtd">';
5552 }
5553 $more .= $input['value'];
5554 $more .= '</div></div>' . "\n";
5555 } elseif ($input['type'] == 'onecolumn') {
5556 $moreonecolumn .= '<div class="margintoponly">';
5557 $moreonecolumn .= $input['value'];
5558 $moreonecolumn .= '</div>' . "\n";
5559 } elseif ($input['type'] == 'hidden') {
5560 // Do nothing more, already added by a previous loop
5561 } elseif ($input['type'] == 'separator') {
5562 $more .= '<br>';
5563 } else {
5564 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5565 }
5566 }
5567 }
5568 $more .= '</div>' . "\n";
5569 $more .= $moreonecolumn;
5570 }
5571
5572 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5573 // 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
5574 // See page product/card.php for example
5575 if (!empty($conf->dol_use_jmobile)) {
5576 $useajax = 0;
5577 }
5578 if (empty($conf->use_javascript_ajax)) {
5579 $useajax = 0;
5580 }
5581
5582 if ($useajax) {
5583 $autoOpen = true;
5584 $dialogconfirm = 'dialog-confirm';
5585 $button = '';
5586 if (!is_numeric($useajax)) {
5587 $button = $useajax;
5588 $useajax = 1;
5589 $autoOpen = false;
5590 $dialogconfirm .= '-' . $button;
5591 }
5592 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5593 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5594
5595 // Add input fields into list of fields to read during submit (inputok and inputko)
5596 if (is_array($formquestion)) {
5597 foreach ($formquestion as $key => $input) {
5598 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5599 // Add name of fields to propagate with the GET when submitting the form with button OK.
5600 if (is_array($input) && isset($input['name'])) {
5601 if (strpos($input['name'], ',') > 0) {
5602 $inputok = array_merge($inputok, explode(',', $input['name']));
5603 } else {
5604 array_push($inputok, $input['name']);
5605 }
5606 }
5607 // Add name of fields to propagate with the GET when submitting the form with button KO.
5608 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5609 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5610 array_push($inputko, $input['name']);
5611 }
5612 }
5613 }
5614
5615 // Show JQuery confirm box.
5616 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5617 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5618 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5619 }
5620 if (!empty($more)) {
5621 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5622 }
5623 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5624 $formconfirm .= '</div>' . "\n";
5625
5626 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5627 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5628 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5629 $formconfirm .= 'jQuery(document).ready(function() {
5630 $(function() {
5631 $( "#' . $dialogconfirm . '" ).dialog(
5632 {
5633 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5634 if ($newselectedchoice == 'no') {
5635 $formconfirm .= '
5636 open: function() {
5637 $(this).parent().find("button.ui-button:eq(2)").focus();
5638 },';
5639 }
5640
5641 $jsforcursor = '';
5642 if ($useajax == 1) {
5643 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5644 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5645 }
5646
5647 $postconfirmas = 'GET';
5648
5649 $formconfirm .= '
5650 resizable: false,
5651 height: "' . $height . '",
5652 width: "' . $width . '",
5653 modal: true,
5654 closeOnEscape: false,
5655 buttons: {
5656 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5657 var options = "token=' . urlencode(newToken()) . '";
5658 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5659 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5660 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5661
5662 if (inputok.length > 0) {
5663 $.each(inputok, function(i, inputname) {
5664 var more = "";
5665 var inputvalue;
5666 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5667 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5668 } else {
5669 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5670 inputvalue = $("#" + inputname + more).val();
5671 }
5672 if (typeof inputvalue == "undefined") { inputvalue=""; }
5673 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5674 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5675 });
5676 }
5677 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5678 if (pageyes.length > 0) {';
5679 if ($postconfirmas == 'GET') {
5680 $formconfirm .= 'location.href = urljump;';
5681 } else {
5682 $formconfirm .= $jsforcursor;
5683 $formconfirm .= 'var post = $.post(
5684 pageyes,
5685 options,
5686 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5687 );';
5688 }
5689 $formconfirm .= '
5690 console.log("after post ok");
5691 }
5692 $(this).dialog("close");
5693 },
5694 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5695 var options = "token=' . urlencode(newToken()) . '";
5696 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5697 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5698 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5699 if (inputko.length > 0) {
5700 $.each(inputko, function(i, inputname) {
5701 var more = "";
5702 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5703 var inputvalue = $("#" + inputname + more).val();
5704 if (typeof inputvalue == "undefined") { inputvalue=""; }
5705 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5706 });
5707 }
5708 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5709 //alert(urljump);
5710 if (pageno.length > 0) {';
5711 if ($postconfirmas == 'GET') {
5712 $formconfirm .= 'location.href = urljump;';
5713 } else {
5714 $formconfirm .= $jsforcursor;
5715 $formconfirm .= 'var post = $.post(
5716 pageno,
5717 options,
5718 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5719 );';
5720 }
5721 $formconfirm .= '
5722 console.log("after post ko");
5723 }
5724 $(this).dialog("close");
5725 }
5726 }
5727 }
5728 );
5729
5730 var button = "' . $button . '";
5731 if (button.length > 0) {
5732 $( "#" + button ).click(function() {
5733 $("#' . $dialogconfirm . '").dialog("open");
5734 });
5735 }
5736 });
5737 });
5738 </script>';
5739 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5740 } else {
5741 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5742
5743 if (empty($disableformtag)) {
5744 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftroright">' . "\n";
5745 }
5746
5747 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5748 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5749
5750 $formconfirm .= '<table class="valid centpercent">' . "\n";
5751
5752 // Line title
5753 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5754 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5755 $formconfirm .= '</td></tr>' . "\n";
5756
5757 // Line text
5758 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5759 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5760 }
5761
5762 // Line form fields
5763 if ($more) {
5764 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5765 $formconfirm .= $more;
5766 $formconfirm .= '</td></tr>' . "\n";
5767 }
5768
5769 // Line with question
5770 $formconfirm .= '<tr class="valid">';
5771 $formconfirm .= '<td class="valid">' . $question . '</td>';
5772 $formconfirm .= '<td class="valid center">';
5773 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5774 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5775 $formconfirm .= '</td>';
5776 $formconfirm .= '</tr>' . "\n";
5777
5778 $formconfirm .= '</table>' . "\n";
5779
5780 if (empty($disableformtag)) {
5781 $formconfirm .= "</form>\n";
5782 }
5783 $formconfirm .= '<br>';
5784
5785 if (!empty($conf->use_javascript_ajax)) {
5786 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5787 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5788 $formconfirm .= '
5789 $(document).ready(function () {
5790 $(".confirmvalidatebutton").on("click", function() {
5791 console.log("We click on button confirmvalidatebutton");
5792 $(this).attr("disabled", "disabled");
5793 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5794 //console.log($(this).closest("form"));
5795 $(this).closest("form").submit();
5796 });
5797 });
5798 ';
5799 $formconfirm .= '</script>' . "\n";
5800 }
5801
5802 $formconfirm .= "<!-- end formconfirm -->\n";
5803 }
5804
5805 return $formconfirm;
5806 }
5807
5808
5809 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5810
5826 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5827 {
5828 // phpcs:enable
5829 global $langs;
5830
5831 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
5832 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
5833
5834 $out = '';
5835
5836 $formproject = new FormProjets($this->db);
5837
5838 $langs->load("project");
5839 if ($htmlname != "none") {
5840 $out .= '<form method="post" action="' . $page . '">';
5841 $out .= '<input type="hidden" name="action" value="classin">';
5842 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5843 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5844 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5845 $out .= '</form>';
5846 } else {
5847 $out .= '<span class="project_head_block">';
5848 if ($selected) {
5849 $projet = new Project($this->db);
5850 $projet->fetch($selected);
5851 $out .= $projet->getNomUrl(0, '', 1);
5852 } else {
5853 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
5854 }
5855 $out .= '</span>';
5856 }
5857
5858 if (empty($nooutput)) {
5859 print $out;
5860 return '';
5861 }
5862 return $out;
5863 }
5864
5865 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5866
5882 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5883 {
5884 // phpcs:enable
5885 global $langs;
5886
5887 $out = '';
5888
5889 if ($htmlname != "none") {
5890 $out .= '<form method="POST" action="' . $page . '">';
5891 $out .= '<input type="hidden" name="action" value="setconditions">';
5892 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5893 if ($type) {
5894 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5895 }
5896 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5897 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5898 $out .= '</form>';
5899 } else {
5900 if ($selected) {
5902 if (isset($this->cache_conditions_paiements[$selected])) {
5903 $label = $this->cache_conditions_paiements[$selected]['label'];
5904
5905 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5906 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5907 }
5908
5909 $out .= $label;
5910 } else {
5911 $langs->load('errors');
5912 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
5913 }
5914 } else {
5915 $out .= '&nbsp;';
5916 }
5917 }
5918
5919 if (empty($nooutput)) {
5920 print $out;
5921 return '';
5922 }
5923 return $out;
5924 }
5925
5926 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5927
5937 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5938 {
5939 // phpcs:enable
5940 global $langs;
5941 if ($htmlname != "none") {
5942 print '<form method="post" action="' . $page . '">';
5943 print '<input type="hidden" name="action" value="setavailability">';
5944 print '<input type="hidden" name="token" value="' . newToken() . '">';
5945 $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5946 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5947 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
5948 print '</form>';
5949 } else {
5950 if ($selected) {
5951 $this->load_cache_availability();
5952 print $this->cache_availability[$selected]['label'];
5953 } else {
5954 print "&nbsp;";
5955 }
5956 }
5957 }
5958
5969 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5970 {
5971 global $langs;
5972 if ($htmlname != "none") {
5973 print '<form method="post" action="' . $page . '">';
5974 print '<input type="hidden" name="action" value="setdemandreason">';
5975 print '<input type="hidden" name="token" value="' . newToken() . '">';
5976 $this->selectInputReason($selected, $htmlname, -1, $addempty);
5977 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5978 print '</form>';
5979 } else {
5980 if ($selected) {
5981 $this->loadCacheInputReason();
5982 foreach ($this->cache_demand_reason as $key => $val) {
5983 if ($val['id'] == $selected) {
5984 print $val['label'];
5985 break;
5986 }
5987 }
5988 } else {
5989 print "&nbsp;";
5990 }
5991 }
5992 }
5993
5994 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5995
6009 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6010 {
6011 // phpcs:enable
6012 global $langs;
6013
6014 $ret = '';
6015
6016 if ($htmlname != "none") {
6017 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6018 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6019 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6020 if ($type) {
6021 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6022 }
6023 $ret .= '<table class="nobordernopadding">';
6024 $ret .= '<tr><td>';
6025 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6026 $ret .= '</td>';
6027 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6028 $ret .= '</tr></table></form>';
6029 } else {
6030 if ($displayhour) {
6031 $ret .= dol_print_date($selected, 'dayhour');
6032 } else {
6033 $ret .= dol_print_date($selected, 'day');
6034 }
6035 }
6036
6037 if (empty($nooutput)) {
6038 print $ret;
6039 }
6040 return $ret;
6041 }
6042
6043
6044 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6045
6056 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6057 {
6058 // phpcs:enable
6059 global $langs;
6060
6061 if ($htmlname != "none") {
6062 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6063 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6064 print '<input type="hidden" name="token" value="' . newToken() . '">';
6065 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6066 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6067 print '</form>';
6068 } else {
6069 if ($selected) {
6070 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6071 $theuser = new User($this->db);
6072 $theuser->fetch($selected);
6073 print $theuser->getNomUrl(1);
6074 } else {
6075 print "&nbsp;";
6076 }
6077 }
6078 }
6079
6080
6081 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6082
6096 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6097 {
6098 // phpcs:enable
6099 global $langs;
6100
6101 $out = '';
6102 if ($htmlname != "none") {
6103 $out .= '<form method="POST" action="' . $page . '">';
6104 $out .= '<input type="hidden" name="action" value="setmode">';
6105 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6106 if ($type) {
6107 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6108 }
6109 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6110 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6111 $out .= '</form>';
6112 } else {
6113 if ($selected) {
6115 $out .= $this->cache_types_paiements[$selected]['label'];
6116 } else {
6117 $out .= "&nbsp;";
6118 }
6119 }
6120
6121 if ($nooutput) {
6122 return $out;
6123 } else {
6124 print $out;
6125 }
6126 return '';
6127 }
6128
6139 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6140 {
6141 global $langs;
6142 if ($htmlname != "none") {
6143 print '<form method="POST" action="' . $page . '">';
6144 print '<input type="hidden" name="action" value="settransportmode">';
6145 print '<input type="hidden" name="token" value="' . newToken() . '">';
6146 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6147 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6148 print '</form>';
6149 } else {
6150 if ($selected) {
6152 print $this->cache_transport_mode[$selected]['label'];
6153 } else {
6154 print "&nbsp;";
6155 }
6156 }
6157 }
6158
6159 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6160
6169 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6170 {
6171 // phpcs:enable
6172 global $langs;
6173 if ($htmlname != "none") {
6174 print '<form method="POST" action="' . $page . '">';
6175 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6176 print '<input type="hidden" name="token" value="' . newToken() . '">';
6177 print $this->selectMultiCurrency($selected, $htmlname, 0);
6178 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6179 print '</form>';
6180 } else {
6181 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6182 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6183 }
6184 }
6185
6186 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6187
6197 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6198 {
6199 // phpcs:enable
6200 global $langs, $mysoc, $conf;
6201
6202 if ($htmlname != "none") {
6203 print '<form method="POST" action="' . $page . '">';
6204 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6205 print '<input type="hidden" name="token" value="' . newToken() . '">';
6206 print '<input type="text" class="maxwidth100" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6207 print '<select name="calculation_mode">';
6208 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6209 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6210 print '</select> ';
6211 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6212 print '</form>';
6213 } else {
6214 if (!empty($rate)) {
6215 print price($rate, 1, $langs, 0, 0);
6216 if ($currency && $rate != 1) {
6217 print ' &nbsp; (' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')';
6218 }
6219 } else {
6220 print 1;
6221 }
6222 }
6223 }
6224
6225
6226 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6227
6243 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6244 {
6245 // phpcs:enable
6246 global $conf, $langs;
6247 if ($htmlname != "none") {
6248 print '<form method="post" action="' . $page . '">';
6249 print '<input type="hidden" name="action" value="setabsolutediscount">';
6250 print '<input type="hidden" name="token" value="' . newToken() . '">';
6251 print '<div class="inline-block">';
6252 if (!empty($discount_type)) {
6253 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6254 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6255 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6256 } else {
6257 $translationKey = 'HasCreditNoteFromSupplier';
6258 }
6259 } else {
6260 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6261 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6262 } else {
6263 $translationKey = 'HasCreditNoteFromSupplier';
6264 }
6265 }
6266 } else {
6267 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6268 if (!$filter || $filter == "fk_facture_source IS NULL") {
6269 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6270 } else {
6271 $translationKey = 'CompanyHasCreditNote';
6272 }
6273 } else {
6274 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6275 $translationKey = 'CompanyHasAbsoluteDiscount';
6276 } else {
6277 $translationKey = 'CompanyHasCreditNote';
6278 }
6279 }
6280 }
6281 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6282 if (empty($hidelist)) {
6283 print ' ';
6284 }
6285 print '</div>';
6286 if (empty($hidelist)) {
6287 print '<div class="inline-block" style="padding-right: 10px">';
6288 $newfilter = 'discount_type=' . intval($discount_type);
6289 if (!empty($discount_type)) {
6290 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6291 } else {
6292 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6293 }
6294 if ($filter) {
6295 $newfilter .= ' AND (' . $filter . ')';
6296 }
6297 // output the combo of discounts
6298 $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
6299 if ($nbqualifiedlines > 0) {
6300 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6301 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6302 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6303 }
6304 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6305 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6306 }
6307
6308 print '>';
6309 }
6310 print '</div>';
6311 }
6312 if ($more) {
6313 print '<div class="inline-block">';
6314 print $more;
6315 print '</div>';
6316 }
6317 print '</form>';
6318 } else {
6319 if ($selected) {
6320 print $selected;
6321 } else {
6322 print "0";
6323 }
6324 }
6325 }
6326
6327
6328 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6329
6339 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6340 {
6341 // phpcs:enable
6342 global $langs;
6343
6344 if ($htmlname != "none") {
6345 print '<form method="post" action="' . $page . '">';
6346 print '<input type="hidden" name="action" value="set_contact">';
6347 print '<input type="hidden" name="token" value="' . newToken() . '">';
6348 print '<table class="nobordernopadding">';
6349 print '<tr><td>';
6350 print $this->selectcontacts($societe->id, $selected, $htmlname);
6351 $num = $this->num;
6352 if ($num == 0) {
6353 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6354 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&amp;action=create&amp;backtoreferer=1">' . $addcontact . '</a>';
6355 }
6356 print '</td>';
6357 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6358 print '</tr></table></form>';
6359 } else {
6360 if ($selected) {
6361 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6362 $contact = new Contact($this->db);
6363 $contact->fetch($selected);
6364 print $contact->getFullName($langs);
6365 } else {
6366 print "&nbsp;";
6367 }
6368 }
6369 }
6370
6371 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6372
6389 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6390 {
6391 // phpcs:enable
6392 global $langs;
6393
6394 $out = '';
6395 if ($htmlname != "none") {
6396 $out .= '<form method="post" action="' . $page . '">';
6397 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6398 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6399 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6400 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6401 $out .= '</form>';
6402 } else {
6403 if ($selected) {
6404 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6405 $soc = new Societe($this->db);
6406 $soc->fetch($selected);
6407 $out .= $soc->getNomUrl(0, '');
6408 } else {
6409 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6410 }
6411 }
6412
6413 if ($nooutput) {
6414 return $out;
6415 } else {
6416 print $out;
6417 }
6418
6419 return '';
6420 }
6421
6422 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6423
6432 public function select_currency($selected = '', $htmlname = 'currency_id')
6433 {
6434 // phpcs:enable
6435 print $this->selectCurrency($selected, $htmlname);
6436 }
6437
6447 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6448 {
6449 global $langs, $user;
6450
6451 $langs->loadCacheCurrencies('');
6452
6453 $out = '';
6454
6455 if ($selected == 'euro' || $selected == 'euros') {
6456 $selected = 'EUR'; // Pour compatibilite
6457 }
6458
6459 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6460 if ($useempty) {
6461 $out .= '<option value="-1" selected></option>';
6462 }
6463 foreach ($langs->cache_currencies as $code_iso => $currency) {
6464 $labeltoshow = $currency['label'];
6465 if ($mode == 1) {
6466 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6467 } else {
6468 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6469 }
6470
6471 if ($selected && $selected == $code_iso) {
6472 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6473 } else {
6474 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6475 }
6476 $out .= $labeltoshow;
6477 $out .= '</option>';
6478 }
6479 $out .= '</select>';
6480 if ($user->admin) {
6481 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6482 }
6483
6484 // Make select dynamic
6485 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6486 $out .= ajax_combobox($htmlname);
6487
6488 return $out;
6489 }
6490
6503 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6504 {
6505 global $conf, $langs;
6506
6507 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6508
6509 $TCurrency = array();
6510
6511 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6512 $sql .= " WHERE entity IN ('" . getEntity('mutlicurrency') . "')";
6513 if ($filter) {
6514 $sql .= " AND " . $filter;
6515 }
6516 $resql = $this->db->query($sql);
6517 if ($resql) {
6518 while ($obj = $this->db->fetch_object($resql)) {
6519 $TCurrency[$obj->code] = $obj->code;
6520 }
6521 }
6522
6523 $out = '';
6524 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6525 if ($useempty) {
6526 $out .= '<option value="">&nbsp;</option>';
6527 }
6528 // If company current currency not in table, we add it into list. Should always be available.
6529 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6530 $TCurrency[$conf->currency] = $conf->currency;
6531 }
6532 if (count($TCurrency) > 0) {
6533 foreach ($langs->cache_currencies as $code_iso => $currency) {
6534 if (isset($TCurrency[$code_iso])) {
6535 if (!empty($selected) && $selected == $code_iso) {
6536 $out .= '<option value="' . $code_iso . '" selected="selected">';
6537 } else {
6538 $out .= '<option value="' . $code_iso . '">';
6539 }
6540
6541 $out .= $currency['label'];
6542 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6543 $out .= '</option>';
6544 }
6545 }
6546 }
6547
6548 $out .= '</select>';
6549
6550 // Make select dynamic
6551 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6552 $out .= ajax_combobox($htmlname);
6553
6554 return $out;
6555 }
6556
6557 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6558
6565 public function load_cache_vatrates($country_code)
6566 {
6567 // phpcs:enable
6568 global $langs, $user;
6569
6570 $num = count($this->cache_vatrates);
6571 if ($num > 0) {
6572 return $num; // Cache already loaded
6573 }
6574
6575 dol_syslog(__METHOD__, LOG_DEBUG);
6576
6577 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6578 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6579 $sql .= " WHERE t.fk_pays = c.rowid";
6580 $sql .= " AND t.active > 0";
6581 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6582 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6583 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6584
6585 $resql = $this->db->query($sql);
6586 if ($resql) {
6587 $num = $this->db->num_rows($resql);
6588 if ($num) {
6589 for ($i = 0; $i < $num; $i++) {
6590 $obj = $this->db->fetch_object($resql);
6591
6592 $tmparray = array();
6593 $tmparray['rowid'] = $obj->rowid;
6594 $tmparray['type_vat'] = $obj->type_vat;
6595 $tmparray['code'] = $obj->code;
6596 $tmparray['txtva'] = $obj->taux;
6597 $tmparray['nprtva'] = $obj->recuperableonly;
6598 $tmparray['localtax1'] = $obj->localtax1;
6599 $tmparray['localtax1_type'] = $obj->localtax1_type;
6600 $tmparray['localtax2'] = $obj->localtax2;
6601 $tmparray['localtax2_type'] = $obj->localtax1_type;
6602 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6603 $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
6604 $positiverates = '';
6605 if ($obj->taux) {
6606 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6607 }
6608 if ($obj->localtax1) {
6609 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6610 }
6611 if ($obj->localtax2) {
6612 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6613 }
6614 if (empty($positiverates)) {
6615 $positiverates = '0';
6616 }
6617 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6618
6619 $this->cache_vatrates[$obj->rowid] = $tmparray;
6620 }
6621
6622 return $num;
6623 } else {
6624 $this->error = '<span class="error">';
6625 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6626 $reg = array();
6627 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6628 $langs->load("errors");
6629 $new_country_code = $reg[1];
6630 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid');
6631 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6632 }
6633 $this->error .= '</span>';
6634 return -1;
6635 }
6636 } else {
6637 $this->error = '<span class="error">' . $this->db->error() . '</span>';
6638 return -2;
6639 }
6640 }
6641
6642 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6643
6666 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)
6667 {
6668 // phpcs:enable
6669 global $langs, $mysoc;
6670
6671 $langs->load('errors');
6672
6673 $return = '';
6674
6675 // Define defaultnpr, defaultttx and defaultcode
6676 $defaultnpr = ($info_bits & 0x01);
6677 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6678 $defaulttx = str_replace('*', '', $selectedrate);
6679 $defaultcode = '';
6680 $reg = array();
6681 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6682 $defaultcode = $reg[1];
6683 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6684 }
6685 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6686
6687 // Check parameters
6688 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6689 if ($societe_vendeuse->id == $mysoc->id) {
6690 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6691 } else {
6692 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6693 }
6694 return $return;
6695 }
6696
6697 //var_dump($societe_acheteuse);
6698 //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";
6699 //exit;
6700
6701 // Define list of countries to use to search VAT rates to show
6702 // First we defined code_country to use to find list
6703 if (is_object($societe_vendeuse)) {
6704 $code_country = "'" . $societe_vendeuse->country_code . "'";
6705 } else {
6706 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6707 }
6708 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
6709 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6710 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
6711 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
6712 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
6713 if (isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
6714 // We also add the buyer country code
6715 if (is_numeric($type)) {
6716 if ($type == 1) { // We know product is a service
6717 switch ($selectVatComboMode) {
6718 case '1':
6719 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6720 break;
6721 case '2':
6722 $code_country = "'" . $societe_acheteuse->country_code . "'";
6723 break;
6724 }
6725 }
6726 } elseif (!$idprod) { // We don't know type of product
6727 switch ($selectVatComboMode) {
6728 case '1':
6729 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6730 break;
6731 case '2':
6732 $code_country = "'" . $societe_acheteuse->country_code . "'";
6733 break;
6734 }
6735 } else {
6736 $prodstatic = new Product($this->db);
6737 $prodstatic->fetch($idprod);
6738 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6739 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6740 }
6741 }
6742 }
6743 }
6744
6745 // Now we load the list of VAT
6746 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6747
6748 // Keep only the VAT qualified for $type_vat
6749 $arrayofvatrates = array();
6750 foreach ($this->cache_vatrates as $cachevalue) {
6751 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] != $type_vat) {
6752 $arrayofvatrates[] = $cachevalue;
6753 }
6754 }
6755
6756 $num = count($arrayofvatrates);
6757
6758 if ($num > 0) {
6759 // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6760 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6761 $tmpthirdparty = new Societe($this->db);
6762
6763 $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6764 $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6765
6766 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6767 $defaultcode = $reg[1];
6768 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6769 }
6770 if (empty($defaulttx)) {
6771 $defaultnpr = 0;
6772 }
6773 }
6774
6775 // If we fails to find a default vat rate, we take the last one in list
6776 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
6777 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6778 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6779 // We take the last one found in list
6780 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
6781 } else {
6782 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
6783 $defaulttx = '';
6784 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6785 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
6786 }
6787 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6788 $defaultcode = $reg[1];
6789 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6790 }
6791 }
6792 }
6793
6794 // Disabled if seller is not subject to VAT
6795 $disabled = false;
6796 $title = '';
6797 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6798 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6799 // of using supplier invoices (this is a very bad idea !)
6800 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
6801 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
6802 $disabled = true;
6803 }
6804 }
6805
6806 if (!$options_only) {
6807 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
6808 }
6809
6810 $selectedfound = false;
6811 foreach ($arrayofvatrates as $rate) {
6812 // Keep only 0 if seller is not subject to VAT
6813 if ($disabled && $rate['txtva'] != 0) {
6814 continue;
6815 }
6816
6817 // Define key to use into select list
6818 $key = $rate['txtva'];
6819 $key .= $rate['nprtva'] ? '*' : '';
6820 if ($mode > 0 && $rate['code']) {
6821 $key .= ' (' . $rate['code'] . ')';
6822 }
6823 if ($mode < 0) {
6824 $key = $rate['rowid'];
6825 }
6826
6827 $return .= '<option value="' . $key . '"';
6828 if (!$selectedfound) {
6829 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6830 if ($defaultcode == $rate['code']) {
6831 $return .= ' selected';
6832 $selectedfound = true;
6833 }
6834 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6835 $return .= ' selected';
6836 $selectedfound = true;
6837 }
6838 }
6839 $return .= '>';
6840
6841 // Show label of VAT
6842 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
6843 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
6844 $return .= $rate['labelpositiverates'];
6845 } else {
6846 // Simple label
6847 $return .= vatrate($rate['label']);
6848 }
6849
6850 //$return.=($rate['code']?' '.$rate['code']:'');
6851 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
6852
6853 $return .= '</option>';
6854 }
6855
6856 if (!$options_only) {
6857 $return .= '</select>';
6858 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
6859 }
6860 } else {
6861 $return .= $this->error;
6862 }
6863
6864 $this->num = $num;
6865 return $return;
6866 }
6867
6868
6869 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6870
6895 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 = '')
6896 {
6897 // phpcs:enable
6898 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
6899 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
6900 if (!empty($nooutput)) {
6901 return $retstring;
6902 }
6903 print $retstring;
6904
6905 return '';
6906 }
6907
6923 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
6924 {
6925 global $langs;
6926
6927 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6928 if ($forcenewline) {
6929 $ret .= '<br>';
6930 }
6931 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6932 return $ret;
6933 }
6934
6962 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')
6963 {
6964 global $conf, $langs;
6965
6966 if ($gm === 'auto') {
6967 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
6968 }
6969
6970 $retstring = '';
6971
6972 if ($prefix == '') {
6973 $prefix = 're';
6974 }
6975 if ($h == '') {
6976 $h = 0;
6977 }
6978 if ($m == '') {
6979 $m = 0;
6980 }
6981 $emptydate = 0;
6982 $emptyhours = 0;
6983 if ($stepminutes <= 0 || $stepminutes > 30) {
6984 $stepminutes = 1;
6985 }
6986 if ($empty == 1) {
6987 $emptydate = 1;
6988 $emptyhours = 1;
6989 }
6990 if ($empty == 2) {
6991 $emptydate = 0;
6992 $emptyhours = 1;
6993 }
6994 $orig_set_time = $set_time;
6995
6996 if ($set_time === '' && $emptydate == 0) {
6997 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
6998 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
6999 $set_time = dol_now($gm);
7000 } else {
7001 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7002 }
7003 }
7004
7005 // Analysis of the pre-selection date
7006 $reg = array();
7007 $shour = '';
7008 $smin = '';
7009 $ssec = '';
7010 if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
7011 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7012 $syear = (!empty($reg[1]) ? $reg[1] : '');
7013 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7014 $sday = (!empty($reg[3]) ? $reg[3] : '');
7015 $shour = (!empty($reg[4]) ? $reg[4] : '');
7016 $smin = (!empty($reg[5]) ? $reg[5] : '');
7017 } elseif (strval($set_time) != '' && $set_time != -1) {
7018 // set_time est un timestamps (0 possible)
7019 $syear = dol_print_date($set_time, "%Y", $gm);
7020 $smonth = dol_print_date($set_time, "%m", $gm);
7021 $sday = dol_print_date($set_time, "%d", $gm);
7022 if ($orig_set_time != '') {
7023 $shour = dol_print_date($set_time, "%H", $gm);
7024 $smin = dol_print_date($set_time, "%M", $gm);
7025 $ssec = dol_print_date($set_time, "%S", $gm);
7026 }
7027 } else {
7028 // Date est '' ou vaut -1
7029 $syear = '';
7030 $smonth = '';
7031 $sday = '';
7032 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7033 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7034 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7035 }
7036 if ($h == 3 || $h == 4) {
7037 $shour = '';
7038 }
7039 if ($m == 3) {
7040 $smin = '';
7041 }
7042
7043 $nowgmt = dol_now('gmt');
7044 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7045
7046 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7047 $usecalendar = 'combo';
7048 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7049 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
7050 }
7051 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7052 // If we use a text browser or screen reader, we use the 'combo' date selector
7053 $usecalendar = 'html';
7054 }
7055
7056 if ($d) {
7057 // Show date with popup
7058 if ($usecalendar != 'combo') {
7059 $formated_date = '';
7060 //print "e".$set_time." t ".$conf->format_date_short;
7061 if (strval($set_time) != '' && $set_time != -1) {
7062 //$formated_date=dol_print_date($set_time,$conf->format_date_short);
7063 $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7064 }
7065
7066 // Calendrier popup version eldy
7067 if ($usecalendar == "eldy") {
7068 // Input area to enter date manually
7069 $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formated_date . '"';
7070 $retstring .= ($disabled ? ' disabled' : '');
7071 $retstring .= ' onChange="dpChangeDay(\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7072 $retstring .= ' autocomplete="off">';
7073
7074 // Icon calendar
7075 $retstringbuttom = '';
7076 if (!$disabled) {
7077 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7078 $base = DOL_URL_ROOT . '/core/';
7079 $retstringbuttom .= ' onClick="showDP(\'' . $base . '\',\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\',\'' . $langs->defaultlang . '\');"';
7080 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
7081 } else {
7082 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7083 }
7084 $retstring = $retstringbuttom . $retstring;
7085
7086 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7087 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7088 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7089 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7090 if (!$disabled && $usecalendar != 'html') {
7091 // Output javascript for datepicker
7092 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7093 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7094
7095 $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
7096 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7097 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7098 autoclose: true,
7099 todayHighlight: true,
7100 yearRange: '" . $minYear . ":" . $maxYear . "',";
7101 if (!empty($conf->dol_use_jmobile)) {
7102 $retstring .= "
7103 beforeShow: function (input, datePicker) {
7104 input.disabled = true;
7105 },
7106 onClose: function (dateText, datePicker) {
7107 this.disabled = false;
7108 },
7109 ";
7110 }
7111 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7112 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7113 $retstring .= "
7114 showOn: 'button', /* both has problem with autocompletion */
7115 buttonImage: '" . DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png',
7116 buttonImageOnly: true";
7117 }
7118 $retstring .= "
7119 }) });";
7120 $retstring .= "</script>";
7121 }
7122
7123 // Input area to enter date manually
7124 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7125 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate center" maxlength="11" value="'.$formated_date.'"';
7126 $retstring .= ($disabled ? ' disabled' : '');
7127 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7128 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7129 $retstring .= ' autocomplete="off">';
7130
7131 // Icone calendrier
7132 if ($disabled) {
7133 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7134 $retstring = $retstringbutton . $retstring;
7135 }
7136
7137 $retstring .= '</div>';
7138 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7139 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7140 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7141 } else {
7142 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7143 }
7144 } else {
7145 // Show date with combo selects
7146 // Day
7147 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7148
7149 if ($emptydate || $set_time == -1) {
7150 $retstring .= '<option value="0" selected>&nbsp;</option>';
7151 }
7152
7153 for ($day = 1; $day <= 31; $day++) {
7154 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7155 }
7156
7157 $retstring .= "</select>";
7158
7159 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7160 if ($emptydate || $set_time == -1) {
7161 $retstring .= '<option value="0" selected>&nbsp;</option>';
7162 }
7163
7164 // Month
7165 for ($month = 1; $month <= 12; $month++) {
7166 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7167 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7168 $retstring .= "</option>";
7169 }
7170 $retstring .= "</select>";
7171
7172 // Year
7173 if ($emptydate || $set_time == -1) {
7174 $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 . '">';
7175 } else {
7176 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7177
7178 $syear = (int) $syear;
7179 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7180 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7181 }
7182 $retstring .= "</select>\n";
7183 }
7184 }
7185 }
7186
7187 if ($d && $h) {
7188 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7189 $retstring .= '<span class="nowraponall">';
7190 }
7191
7192 if ($h) {
7193 $hourstart = 0;
7194 $hourend = 24;
7195 if ($openinghours != '') {
7196 $openinghours = explode(',', $openinghours);
7197 $hourstart = $openinghours[0];
7198 $hourend = $openinghours[1];
7199 if ($hourend < $hourstart) {
7200 $hourend = $hourstart;
7201 }
7202 }
7203 // Show hour
7204 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7205 if ($emptyhours) {
7206 $retstring .= '<option value="-1">&nbsp;</option>';
7207 }
7208 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7209 if (strlen($hour) < 2) {
7210 $hour = "0" . $hour;
7211 }
7212 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7213 //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
7214 $retstring .= '</option>';
7215 }
7216 $retstring .= '</select>';
7217 //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
7218 if ($m) {
7219 $retstring .= ":";
7220 }
7221 }
7222
7223 if ($m) {
7224 // Show minutes
7225 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7226 if ($emptyhours) {
7227 $retstring .= '<option value="-1">&nbsp;</option>';
7228 }
7229 for ($min = 0; $min < 60; $min += $stepminutes) {
7230 $min_str = sprintf("%02d", $min);
7231 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7232 }
7233 $retstring .= '</select>';
7234
7235 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7236 }
7237
7238 if ($d && $h) {
7239 $retstring .= '</span>';
7240 }
7241
7242 // Add a "Now" link
7243 if (!empty($conf->use_javascript_ajax) && $addnowlink) {
7244 // Script which will be inserted in the onClick of the "Now" link
7245 $reset_scripts = "";
7246 if ($addnowlink == 2) { // local computer time
7247 // pad add leading 0 on numbers
7248 $reset_scripts .= "Number.prototype.pad = function(size) {
7249 var s = String(this);
7250 while (s.length < (size || 2)) {s = '0' + s;}
7251 return s;
7252 };
7253 var d = new Date();";
7254 }
7255
7256 // Generate the date part, depending on the use or not of the javascript calendar
7257 if ($addnowlink == 1) { // server time expressed in user time setup
7258 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7259 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7260 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7261 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7262 } elseif ($addnowlink == 2) {
7263 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7264 * This break application for foreign languages.
7265 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7266 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7267 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7268 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7269 */
7270 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7271 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7272 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7273 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7274 }
7275 /*if ($usecalendar == "eldy")
7276 {
7277 $base=DOL_URL_ROOT.'/core/';
7278 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7279 }
7280 else
7281 {
7282 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7283 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7284 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7285 }*/
7286 // Update the hour part
7287 if ($h) {
7288 if ($fullday) {
7289 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7290 }
7291 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7292 if ($addnowlink == 1) {
7293 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7294 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7295 } elseif ($addnowlink == 2) {
7296 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7297 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7298 }
7299
7300 if ($fullday) {
7301 $reset_scripts .= ' } ';
7302 }
7303 }
7304 // Update the minute part
7305 if ($m) {
7306 if ($fullday) {
7307 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7308 }
7309 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7310 if ($addnowlink == 1) {
7311 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7312 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7313 } elseif ($addnowlink == 2) {
7314 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7315 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7316 }
7317 if ($fullday) {
7318 $reset_scripts .= ' } ';
7319 }
7320 }
7321 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7322 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7323 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7324 $retstring .= $langs->trans("Now");
7325 $retstring .= '</button> ';
7326 }
7327 }
7328
7329 // Add a "Plus one hour" link
7330 if ($conf->use_javascript_ajax && $addplusone) {
7331 // Script which will be inserted in the onClick of the "Add plusone" link
7332 $reset_scripts = "";
7333
7334 // Generate the date part, depending on the use or not of the javascript calendar
7335 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7336 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7337 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7338 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7339 // Update the hour part
7340 if ($h) {
7341 if ($fullday) {
7342 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7343 }
7344 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7345 if ($fullday) {
7346 $reset_scripts .= ' } ';
7347 }
7348 }
7349 // Update the minute part
7350 if ($m) {
7351 if ($fullday) {
7352 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7353 }
7354 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7355 if ($fullday) {
7356 $reset_scripts .= ' } ';
7357 }
7358 }
7359 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7360 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7361 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7362 $retstring .= $langs->trans("DateStartPlusOne");
7363 $retstring .= '</button> ';
7364 }
7365 }
7366
7367 // Add a link to set data
7368 if ($conf->use_javascript_ajax && !empty($adddateof)) {
7369 if (!is_array($adddateof)) {
7370 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
7371 } else {
7372 $arrayofdateof = $adddateof;
7373 }
7374 foreach ($arrayofdateof as $valuedateof) {
7375 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
7376 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
7377 $tmparray = dol_getdate($tmpadddateof);
7378 if (empty($tmplabeladddateof)) {
7379 $tmplabeladddateof = $langs->trans("DateInvoice");
7380 }
7381 $reset_scripts = 'console.log(\'Click on now link\'); ';
7382 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7383 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7384 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7385 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7386 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7387 }
7388 }
7389
7390 return $retstring;
7391 }
7392
7401 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7402 {
7403 global $langs;
7404
7405 $TDurationTypes = array(
7406 'y' => $langs->trans('Years'),
7407 'm' => $langs->trans('Month'),
7408 'w' => $langs->trans('Weeks'),
7409 'd' => $langs->trans('Days'),
7410 'h' => $langs->trans('Hours'),
7411 'i' => $langs->trans('Minutes')
7412 );
7413
7414 // Removed undesired duration types
7415 foreach ($excludetypes as $value) {
7416 unset($TDurationTypes[$value]);
7417 }
7418
7419 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7420 foreach ($TDurationTypes as $key => $typeduration) {
7421 $retstring .= '<option value="' . $key . '"';
7422 if ($key == $selected) {
7423 $retstring .= " selected";
7424 }
7425 $retstring .= ">" . $typeduration . "</option>";
7426 }
7427 $retstring .= "</select>";
7428
7429 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7430
7431 return $retstring;
7432 }
7433
7434 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7435
7449 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7450 {
7451 // phpcs:enable
7452 global $langs;
7453
7454 $retstring = '<span class="nowraponall">';
7455
7456 $hourSelected = '';
7457 $minSelected = '';
7458
7459 // Hours
7460 if ($iSecond != '') {
7461 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7462
7463 $hourSelected = convertSecondToTime($iSecond, 'allhour');
7464 $minSelected = convertSecondToTime($iSecond, 'min');
7465 }
7466
7467 if ($typehour == 'select') {
7468 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7469 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7470 $retstring .= '<option value="' . $hour . '"';
7471 if (is_numeric($hourSelected) && $hourSelected == $hour) {
7472 $retstring .= " selected";
7473 }
7474 $retstring .= ">" . $hour . "</option>";
7475 }
7476 $retstring .= "</select>";
7477 } elseif ($typehour == 'text' || $typehour == 'textselect') {
7478 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7479 } else {
7480 return 'BadValueForParameterTypeHour';
7481 }
7482
7483 if ($typehour != 'text') {
7484 $retstring .= ' ' . $langs->trans('HourShort');
7485 } else {
7486 $retstring .= '<span class="">:</span>';
7487 }
7488
7489 // Minutes
7490 if ($minunderhours) {
7491 $retstring .= '<br>';
7492 } else {
7493 if ($typehour != 'text') {
7494 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7495 }
7496 }
7497
7498 if ($typehour == 'select' || $typehour == 'textselect') {
7499 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7500 for ($min = 0; $min <= 55; $min += 5) {
7501 $retstring .= '<option value="' . $min . '"';
7502 if (is_numeric($minSelected) && $minSelected == $min) {
7503 $retstring .= ' selected';
7504 }
7505 $retstring .= '>' . $min . '</option>';
7506 }
7507 $retstring .= "</select>";
7508 } elseif ($typehour == 'text') {
7509 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7510 }
7511
7512 if ($typehour != 'text') {
7513 $retstring .= ' ' . $langs->trans('MinuteShort');
7514 }
7515
7516 $retstring .= "</span>";
7517
7518 if (!empty($nooutput)) {
7519 return $retstring;
7520 }
7521
7522 print $retstring;
7523
7524 return '';
7525 }
7526
7546 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)
7547 {
7548 global $langs, $conf;
7549
7550 $out = '';
7551
7552 // check parameters
7553 if (is_null($ajaxoptions)) {
7554 $ajaxoptions = array();
7555 }
7556
7557 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7558 $placeholder = '';
7559
7560 if ($selected && empty($selected_input_value)) {
7561 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7562 $tickettmpselect = new Ticket($this->db);
7563 $tickettmpselect->fetch($selected);
7564 $selected_input_value = $tickettmpselect->ref;
7565 unset($tickettmpselect);
7566 }
7567
7568 $urloption = '';
7569 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7570
7571 if (empty($hidelabel)) {
7572 $out .= $langs->trans("RefOrLabel") . ' : ';
7573 } elseif ($hidelabel > 1) {
7574 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7575 if ($hidelabel == 2) {
7576 $out .= img_picto($langs->trans("Search"), 'search');
7577 }
7578 }
7579 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7580 if ($hidelabel == 3) {
7581 $out .= img_picto($langs->trans("Search"), 'search');
7582 }
7583 } else {
7584 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7585 }
7586
7587 if (empty($nooutput)) {
7588 print $out;
7589 } else {
7590 return $out;
7591 }
7592 return '';
7593 }
7594
7595
7612 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7613 {
7614 global $langs, $conf;
7615
7616 $out = '';
7617 $outarray = array();
7618
7619 $selectFields = " p.rowid, p.ref, p.message";
7620
7621 $sql = "SELECT ";
7622 $sql .= $selectFields;
7623 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7624 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7625
7626 // Add criteria on ref/label
7627 if ($filterkey != '') {
7628 $sql .= ' AND (';
7629 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7630 // For natural search
7631 $search_crit = explode(' ', $filterkey);
7632 $i = 0;
7633 if (count($search_crit) > 1) {
7634 $sql .= "(";
7635 }
7636 foreach ($search_crit as $crit) {
7637 if ($i > 0) {
7638 $sql .= " AND ";
7639 }
7640 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7641 $sql .= ")";
7642 $i++;
7643 }
7644 if (count($search_crit) > 1) {
7645 $sql .= ")";
7646 }
7647 $sql .= ')';
7648 }
7649
7650 $sql .= $this->db->plimit($limit, 0);
7651
7652 // Build output string
7653 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7654 $result = $this->db->query($sql);
7655 if ($result) {
7656 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7657 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7658
7659 $num = $this->db->num_rows($result);
7660
7661 $events = array();
7662
7663 if (!$forcecombo) {
7664 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7665 $out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
7666 }
7667
7668 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7669
7670 $textifempty = '';
7671 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7672 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7673 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7674 if ($showempty && !is_numeric($showempty)) {
7675 $textifempty = $langs->trans($showempty);
7676 } else {
7677 $textifempty .= $langs->trans("All");
7678 }
7679 } else {
7680 if ($showempty && !is_numeric($showempty)) {
7681 $textifempty = $langs->trans($showempty);
7682 }
7683 }
7684 if ($showempty) {
7685 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7686 }
7687
7688 $i = 0;
7689 while ($num && $i < $num) {
7690 $opt = '';
7691 $optJson = array();
7692 $objp = $this->db->fetch_object($result);
7693
7694 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7695 // Add new entry
7696 // "key" value of json key array is used by jQuery automatically as selected value
7697 // "label" value of json key array is used by jQuery automatically as text for combo box
7698 $out .= $opt;
7699 array_push($outarray, $optJson);
7700
7701 $i++;
7702 }
7703
7704 $out .= '</select>';
7705
7706 $this->db->free($result);
7707
7708 if (empty($outputmode)) {
7709 return $out;
7710 }
7711 return $outarray;
7712 } else {
7713 dol_print_error($this->db);
7714 }
7715
7716 return array();
7717 }
7718
7730 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7731 {
7732 $outkey = '';
7733 $outref = '';
7734 $outtype = '';
7735
7736 $outkey = $objp->rowid;
7737 $outref = $objp->ref;
7738 $outtype = $objp->fk_product_type;
7739
7740 $opt = '<option value="' . $objp->rowid . '"';
7741 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7742 $opt .= '>';
7743 $opt .= $objp->ref;
7744 $objRef = $objp->ref;
7745 if (!empty($filterkey) && $filterkey != '') {
7746 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7747 }
7748
7749 $opt .= "</option>\n";
7750 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7751 }
7752
7772 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)
7773 {
7774 global $langs, $conf;
7775
7776 $out = '';
7777
7778 // check parameters
7779 if (is_null($ajaxoptions)) {
7780 $ajaxoptions = array();
7781 }
7782
7783 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7784 $placeholder = '';
7785
7786 if ($selected && empty($selected_input_value)) {
7787 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7788 $projecttmpselect = new Project($this->db);
7789 $projecttmpselect->fetch($selected);
7790 $selected_input_value = $projecttmpselect->ref;
7791 unset($projecttmpselect);
7792 }
7793
7794 $urloption = '';
7795 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7796
7797 if (empty($hidelabel)) {
7798 $out .= $langs->trans("RefOrLabel") . ' : ';
7799 } elseif ($hidelabel > 1) {
7800 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7801 if ($hidelabel == 2) {
7802 $out .= img_picto($langs->trans("Search"), 'search');
7803 }
7804 }
7805 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7806 if ($hidelabel == 3) {
7807 $out .= img_picto($langs->trans("Search"), 'search');
7808 }
7809 } else {
7810 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7811 }
7812
7813 if (empty($nooutput)) {
7814 print $out;
7815 } else {
7816 return $out;
7817 }
7818 return '';
7819 }
7820
7837 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7838 {
7839 global $langs, $conf;
7840
7841 $out = '';
7842 $outarray = array();
7843
7844 $selectFields = " p.rowid, p.ref";
7845
7846 $sql = "SELECT ";
7847 $sql .= $selectFields;
7848 $sql .= " FROM " . $this->db->prefix() . "projet as p";
7849 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
7850
7851 // Add criteria on ref/label
7852 if ($filterkey != '') {
7853 $sql .= ' AND (';
7854 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7855 // For natural search
7856 $search_crit = explode(' ', $filterkey);
7857 $i = 0;
7858 if (count($search_crit) > 1) {
7859 $sql .= "(";
7860 }
7861 foreach ($search_crit as $crit) {
7862 if ($i > 0) {
7863 $sql .= " AND ";
7864 }
7865 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7866 $sql .= "";
7867 $i++;
7868 }
7869 if (count($search_crit) > 1) {
7870 $sql .= ")";
7871 }
7872 $sql .= ')';
7873 }
7874
7875 $sql .= $this->db->plimit($limit, 0);
7876
7877 // Build output string
7878 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
7879 $result = $this->db->query($sql);
7880 if ($result) {
7881 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7882 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
7883
7884 $num = $this->db->num_rows($result);
7885
7886 $events = array();
7887
7888 if (!$forcecombo) {
7889 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7890 $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7891 }
7892
7893 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7894
7895 $textifempty = '';
7896 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7897 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7898 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
7899 if ($showempty && !is_numeric($showempty)) {
7900 $textifempty = $langs->trans($showempty);
7901 } else {
7902 $textifempty .= $langs->trans("All");
7903 }
7904 } else {
7905 if ($showempty && !is_numeric($showempty)) {
7906 $textifempty = $langs->trans($showempty);
7907 }
7908 }
7909 if ($showempty) {
7910 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7911 }
7912
7913 $i = 0;
7914 while ($num && $i < $num) {
7915 $opt = '';
7916 $optJson = array();
7917 $objp = $this->db->fetch_object($result);
7918
7919 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
7920 // Add new entry
7921 // "key" value of json key array is used by jQuery automatically as selected value
7922 // "label" value of json key array is used by jQuery automatically as text for combo box
7923 $out .= $opt;
7924 array_push($outarray, $optJson);
7925
7926 $i++;
7927 }
7928
7929 $out .= '</select>';
7930
7931 $this->db->free($result);
7932
7933 if (empty($outputmode)) {
7934 return $out;
7935 }
7936 return $outarray;
7937 } else {
7938 dol_print_error($this->db);
7939 }
7940
7941 return array();
7942 }
7943
7955 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7956 {
7957 $outkey = '';
7958 $outref = '';
7959 $outtype = '';
7960
7961 $label = $objp->label;
7962
7963 $outkey = $objp->rowid;
7964 $outref = $objp->ref;
7965 $outlabel = $objp->label;
7966 $outtype = $objp->fk_product_type;
7967
7968 $opt = '<option value="' . $objp->rowid . '"';
7969 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7970 $opt .= '>';
7971 $opt .= $objp->ref;
7972 $objRef = $objp->ref;
7973 if (!empty($filterkey) && $filterkey != '') {
7974 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7975 }
7976
7977 $opt .= "</option>\n";
7978 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7979 }
7980
7981
8001 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)
8002 {
8003 global $langs, $conf;
8004
8005 $out = '';
8006
8007 // check parameters
8008 if (is_null($ajaxoptions)) {
8009 $ajaxoptions = array();
8010 }
8011
8012 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8013 $placeholder = '';
8014
8015 if ($selected && empty($selected_input_value)) {
8016 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8017 $adherenttmpselect = new Adherent($this->db);
8018 $adherenttmpselect->fetch($selected);
8019 $selected_input_value = $adherenttmpselect->ref;
8020 unset($adherenttmpselect);
8021 }
8022
8023 $urloption = '';
8024
8025 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8026
8027 if (empty($hidelabel)) {
8028 $out .= $langs->trans("RefOrLabel") . ' : ';
8029 } elseif ($hidelabel > 1) {
8030 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8031 if ($hidelabel == 2) {
8032 $out .= img_picto($langs->trans("Search"), 'search');
8033 }
8034 }
8035 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8036 if ($hidelabel == 3) {
8037 $out .= img_picto($langs->trans("Search"), 'search');
8038 }
8039 } else {
8040 $filterkey = '';
8041
8042 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8043 }
8044
8045 if (empty($nooutput)) {
8046 print $out;
8047 } else {
8048 return $out;
8049 }
8050 return '';
8051 }
8052
8069 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8070 {
8071 global $langs, $conf;
8072
8073 $out = '';
8074 $outarray = array();
8075
8076 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8077
8078 $sql = "SELECT ";
8079 $sql .= $selectFields;
8080 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8081 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8082
8083 // Add criteria on ref/label
8084 if ($filterkey != '') {
8085 $sql .= ' AND (';
8086 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8087 // For natural search
8088 $search_crit = explode(' ', $filterkey);
8089 $i = 0;
8090 if (count($search_crit) > 1) {
8091 $sql .= "(";
8092 }
8093 foreach ($search_crit as $crit) {
8094 if ($i > 0) {
8095 $sql .= " AND ";
8096 }
8097 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8098 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8099 $i++;
8100 }
8101 if (count($search_crit) > 1) {
8102 $sql .= ")";
8103 }
8104 $sql .= ')';
8105 }
8106 if ($status != -1) {
8107 $sql .= ' AND statut = ' . ((int) $status);
8108 }
8109 $sql .= $this->db->plimit($limit, 0);
8110
8111 // Build output string
8112 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8113 $result = $this->db->query($sql);
8114 if ($result) {
8115 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8116 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8117
8118 $num = $this->db->num_rows($result);
8119
8120 $events = array();
8121
8122 if (!$forcecombo) {
8123 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8124 $out .= ajax_combobox($htmlname, $events, getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT') ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
8125 }
8126
8127 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8128
8129 $textifempty = '';
8130 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8131 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8132 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8133 if ($showempty && !is_numeric($showempty)) {
8134 $textifempty = $langs->trans($showempty);
8135 } else {
8136 $textifempty .= $langs->trans("All");
8137 }
8138 } else {
8139 if ($showempty && !is_numeric($showempty)) {
8140 $textifempty = $langs->trans($showempty);
8141 }
8142 }
8143 if ($showempty) {
8144 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8145 }
8146
8147 $i = 0;
8148 while ($num && $i < $num) {
8149 $opt = '';
8150 $optJson = array();
8151 $objp = $this->db->fetch_object($result);
8152
8153 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8154
8155 // Add new entry
8156 // "key" value of json key array is used by jQuery automatically as selected value
8157 // "label" value of json key array is used by jQuery automatically as text for combo box
8158 $out .= $opt;
8159 array_push($outarray, $optJson);
8160
8161 $i++;
8162 }
8163
8164 $out .= '</select>';
8165
8166 $this->db->free($result);
8167
8168 if (empty($outputmode)) {
8169 return $out;
8170 }
8171 return $outarray;
8172 } else {
8173 dol_print_error($this->db);
8174 }
8175
8176 return array();
8177 }
8178
8190 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8191 {
8192 $outkey = '';
8193 $outlabel = '';
8194 $outtype = '';
8195
8196 $outkey = $objp->rowid;
8197 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8198 $outtype = $objp->fk_adherent_type;
8199
8200 $opt = '<option value="' . $objp->rowid . '"';
8201 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8202 $opt .= '>';
8203 if (!empty($filterkey) && $filterkey != '') {
8204 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8205 }
8206 $opt .= $outlabel;
8207 $opt .= "</option>\n";
8208
8209 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8210 }
8211
8232 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8233 {
8234 global $conf, $extrafields, $user;
8235
8236 //var_dump($objectdesc); debug_print_backtrace();
8237
8238 $objectdescorig = $objectdesc;
8239 $objecttmp = null;
8240 $InfoFieldList = array();
8241 $classname = '';
8242 $filter = ''; // Ensure filter has value (for static analysis)
8243 $sortfield = ''; // Ensure filter has value (for static analysis)
8244
8245 if ($objectfield) { // We must retrieve the objectdesc from the field or extrafield
8246 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8247 $tmparray = explode(':', $objectfield);
8248
8249 // Get instance of object from $element
8250 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8251
8252 if (is_object($objectforfieldstmp)) {
8253 $objectdesc = '';
8254
8255 $reg = array();
8256 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8257 // For a property in extrafields
8258 $key = $reg[1];
8259 // fetch optionals attributes and labels
8260 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8261
8262 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8263 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8264 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8265 $objectdesc = $tmpextrafields[0];
8266 }
8267 }
8268 } else {
8269 // For a property in ->fields
8270 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8271 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8272 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8273 }
8274 }
8275 }
8276 }
8277
8278 if ($objectdesc) {
8279 // Example of value for $objectdesc:
8280 // Bom:bom/class/bom.class.php:0:t.status=1
8281 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8282 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8283 $InfoFieldList = explode(":", $objectdesc, 4);
8284 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8285 $reg = array();
8286 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8287 $InfoFieldList[4] = $reg[1]; // take the sort field
8288 }
8289 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8290
8291 $classname = $InfoFieldList[0];
8292 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8293 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8294 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8295 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8296
8297 // Load object according to $id and $element
8298 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8299
8300 // Fallback to another solution to get $objecttmp
8301 if (empty($objecttmp) && !empty($classpath)) {
8302 dol_include_once($classpath);
8303
8304 if ($classname && class_exists($classname)) {
8305 $objecttmp = new $classname($this->db);
8306 }
8307 }
8308 }
8309
8310 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
8311 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
8312 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
8313 $filter = str_replace(
8314 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
8315 array($conf->entity, $sharedentities, $user->id),
8316 $filter
8317 );
8318
8319 if (!is_object($objecttmp)) {
8320 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc, LOG_WARNING);
8321 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc;
8322 }
8323 '@phan-var-force CommonObject $objecttmp';
8324
8325 //var_dump($filter);
8326 $prefixforautocompletemode = $objecttmp->element;
8327 if ($prefixforautocompletemode == 'societe') {
8328 $prefixforautocompletemode = 'company';
8329 }
8330 if ($prefixforautocompletemode == 'product') {
8331 $prefixforautocompletemode = 'produit';
8332 }
8333 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8334
8335 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
8336
8337 // Generate the combo HTML component
8338 $out = '';
8339 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
8340 // No immediate load of all database
8341 $placeholder = '';
8342
8343 if ($preSelectedValue && empty($selected_input_value)) {
8344 $objecttmp->fetch($preSelectedValue);
8345 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
8346
8347 $oldValueForShowOnCombobox = 0;
8348 foreach ($objecttmp->fields as $fieldK => $fielV) {
8349 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
8350 continue;
8351 }
8352
8353 if (!$oldValueForShowOnCombobox) {
8354 $selected_input_value = '';
8355 }
8356
8357 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
8358 $selected_input_value .= $objecttmp->$fieldK;
8359 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
8360 }
8361 }
8362
8363 // Set url and param to call to get json of the search results
8364 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
8365 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . '&objectfield='.urlencode($objectfield) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
8366
8367 // Activate the auto complete using ajax call.
8368 $out .= ajax_autocompleter($preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalString($confkeyforautocompletemode), 0);
8369 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
8370 $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) . '"' : '') . ' />';
8371 } else {
8372 // Immediate load of table record.
8373 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
8374 }
8375
8376 return $out;
8377 }
8378
8379
8400 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
8401 {
8402 global $langs, $user, $hookmanager;
8403
8404 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
8405
8406 $prefixforautocompletemode = $objecttmp->element;
8407 if ($prefixforautocompletemode == 'societe') {
8408 $prefixforautocompletemode = 'company';
8409 }
8410 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8411
8412 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
8413 $tmpfieldstoshow = '';
8414 foreach ($objecttmp->fields as $key => $val) {
8415 if (! (int) dol_eval($val['enabled'], 1, 1, '1')) {
8416 continue;
8417 }
8418 if (!empty($val['showoncombobox'])) {
8419 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8420 }
8421 }
8422 if ($tmpfieldstoshow) {
8423 $fieldstoshow = $tmpfieldstoshow;
8424 }
8425 } else {
8426 // For backward compatibility
8427 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8428 }
8429
8430 if (empty($fieldstoshow)) {
8431 if (isset($objecttmp->fields['ref'])) {
8432 $fieldstoshow = 't.ref';
8433 } else {
8434 $langs->load("errors");
8435 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8436 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8437 }
8438 }
8439
8440 $out = '';
8441 $outarray = array();
8442 $tmparray = array();
8443
8444 $num = 0;
8445
8446 // Search data
8447 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $objecttmp->table_element . " as t";
8448 if (!empty($objecttmp->isextrafieldmanaged)) {
8449 $sql .= " LEFT JOIN " . $this->db->prefix() . $objecttmp->table_element . "_extrafields as e ON t.rowid=e.fk_object";
8450 }
8451 if (isset($objecttmp->ismultientitymanaged)) {
8452 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8453 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8454 $sql .= " INNER JOIN " . $this->db->prefix() . $tmparray[1] . " as parenttable ON parenttable.rowid = t." . $tmparray[0];
8455 }
8456 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8457 if (!$user->hasRight('societe', 'client', 'voir')) {
8458 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8459 }
8460 }
8461 }
8462
8463 // Add where from hooks
8464 $parameters = array(
8465 'object' => $objecttmp,
8466 'htmlname' => $htmlname,
8467 'filter' => $filter,
8468 'searchkey' => $searchkey
8469 );
8470
8471 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8472 if (!empty($hookmanager->resPrint)) {
8473 $sql .= $hookmanager->resPrint;
8474 } else {
8475 $sql .= " WHERE 1=1";
8476 if (isset($objecttmp->ismultientitymanaged)) {
8477 if ($objecttmp->ismultientitymanaged == 1) {
8478 $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8479 }
8480 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8481 $sql .= " AND parenttable.entity = t." . $tmparray[0];
8482 }
8483 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8484 if ($objecttmp->element == 'societe') {
8485 $sql .= " AND t.rowid = " . ((int) $user->socid);
8486 } else {
8487 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8488 }
8489 }
8490 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8491 if (!$user->hasRight('societe', 'client', 'voir')) {
8492 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8493 }
8494 }
8495 }
8496 if ($searchkey != '') {
8497 $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
8498 }
8499
8500 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8501 $errormessage = '';
8502 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8503 if ($errormessage) {
8504 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8505 }
8506 }
8507 }
8508 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8509 //$sql.=$this->db->plimit($limit, 0);
8510 //print $sql;
8511
8512 // Build output string
8513 $resql = $this->db->query($sql);
8514 if ($resql) {
8515 // Construct $out and $outarray
8516 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8517
8518 // 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
8519 $textifempty = '&nbsp;';
8520
8521 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8522 if (getDolGlobalInt($confkeyforautocompletemode)) {
8523 if ($showempty && !is_numeric($showempty)) {
8524 $textifempty = $langs->trans($showempty);
8525 } else {
8526 $textifempty .= $langs->trans("All");
8527 }
8528 }
8529 if ($showempty) {
8530 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8531 }
8532
8533 $num = $this->db->num_rows($resql);
8534 $i = 0;
8535 if ($num) {
8536 while ($i < $num) {
8537 $obj = $this->db->fetch_object($resql);
8538 $label = '';
8539 $labelhtml = '';
8540 $tmparray = explode(',', $fieldstoshow);
8541 $oldvalueforshowoncombobox = 0;
8542 foreach ($tmparray as $key => $val) {
8543 $val = preg_replace('/t\./', '', $val);
8544 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8545 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8546 $label .= $obj->$val;
8547 $labelhtml .= $obj->$val;
8548
8549 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8550 }
8551 if (empty($outputmode)) {
8552 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8553 $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>';
8554 } else {
8555 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8556 }
8557 } else {
8558 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8559 }
8560
8561 $i++;
8562 if (($i % 10) == 0) {
8563 $out .= "\n";
8564 }
8565 }
8566 }
8567
8568 $out .= '</select>' . "\n";
8569
8570 if (!$forcecombo) {
8571 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8572 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
8573 }
8574 } else {
8575 dol_print_error($this->db);
8576 }
8577
8578 $this->result = array('nbofelement' => $num);
8579
8580 if ($outputmode) {
8581 return $outarray;
8582 }
8583 return $out;
8584 }
8585
8586
8610 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)
8611 {
8612 global $conf, $langs;
8613
8614 // Do we want a multiselect ?
8615 //$jsbeautify = 0;
8616 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8617 $jsbeautify = 1;
8618
8619 if ($value_as_key) {
8620 $array = array_combine($array, $array);
8621 }
8622
8623 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
8624
8625 $out = '';
8626
8627 if ($addjscombo < 0) {
8628 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8629 $addjscombo = 1;
8630 } else {
8631 $addjscombo = 0;
8632 }
8633 }
8634 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8635 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8636 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8637 $out .= '>'."\n";
8638
8639 if ($show_empty) {
8640 $textforempty = ' ';
8641 if (!empty($conf->use_javascript_ajax)) {
8642 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8643 }
8644 if (!is_numeric($show_empty)) {
8645 $textforempty = $show_empty;
8646 }
8647 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8648 }
8649 if (is_array($array)) {
8650 // Translate
8651 if ($translate) {
8652 foreach ($array as $key => $value) {
8653 if (!is_array($value)) {
8654 $array[$key] = $langs->trans($value);
8655 } else {
8656 $array[$key]['label'] = $langs->trans($value['label']);
8657 }
8658 }
8659 }
8660 // Sort
8661 if ($sort == 'ASC') {
8662 asort($array);
8663 } elseif ($sort == 'DESC') {
8664 arsort($array);
8665 }
8666
8667 foreach ($array as $key => $tmpvalue) {
8668 if (is_array($tmpvalue)) {
8669 $value = $tmpvalue['label'];
8670 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
8671 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8672 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8673 } else {
8674 $value = $tmpvalue;
8675 //$valuehtml = $tmpvalue;
8676 $disabled = '';
8677 $style = '';
8678 }
8679 if (!empty($disablebademail)) {
8680 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8681 || ($disablebademail == 2 && preg_match('/---/', $value))) {
8682 $disabled = ' disabled';
8683 $style = ' class="warning"';
8684 }
8685 }
8686 if ($key_in_label) {
8687 if (empty($nohtmlescape)) {
8688 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8689 } else {
8690 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8691 }
8692 } else {
8693 if (empty($nohtmlescape)) {
8694 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
8695 } else {
8696 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8697 }
8698 if ($value == '' || $value == '-') {
8699 $selectOptionValue = '&nbsp;';
8700 }
8701 }
8702 $out .= '<option value="' . $key . '"';
8703 $out .= $style . $disabled;
8704 if (is_array($id)) {
8705 if (in_array($key, $id) && !$disabled) {
8706 $out .= ' selected'; // To preselect a value
8707 }
8708 } else {
8709 $id = (string) $id; // if $id = 0, then $id = '0'
8710 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8711 $out .= ' selected'; // To preselect a value
8712 }
8713 }
8714 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
8715 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
8716 }
8717
8718 if (is_array($tmpvalue)) {
8719 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
8720 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
8721 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
8722 }
8723 }
8724 }
8725 $out .= '>';
8726 $out .= $selectOptionValue;
8727 $out .= "</option>\n";
8728 }
8729 }
8730 $out .= "</select>";
8731
8732 // Add code for jquery to use multiselect
8733 if ($addjscombo && $jsbeautify) {
8734 // Enhance with select2
8735 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8736 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
8737 }
8738
8739 return $out;
8740 }
8741
8760 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8761 {
8762 global $conf, $langs;
8763 global $delayedhtmlcontent; // Will be used later outside of this function
8764
8765 // TODO Use an internal dolibarr component instead of select2
8766 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8767 return '';
8768 }
8769
8770 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
8771
8772 $outdelayed = '';
8773 if (!empty($conf->use_javascript_ajax)) {
8774 $tmpplugin = 'select2';
8775 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8776 <script nonce="' . getNonce() . '">
8777 $(document).ready(function () {
8778
8779 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
8780
8781 $(".' . $htmlname . '").select2({
8782 ajax: {
8783 dir: "ltr",
8784 url: "' . $url . '",
8785 dataType: \'json\',
8786 delay: 250,
8787 data: function (params) {
8788 return {
8789 q: params.term, // search term
8790 page: params.page
8791 }
8792 },
8793 processResults: function (data) {
8794 // parse the results into the format expected by Select2.
8795 // since we are using custom formatting functions we do not need to alter the remote JSON data
8796 //console.log(data);
8797 saveRemoteData = data;
8798 /* format json result for select2 */
8799 result = []
8800 $.each( data, function( key, value ) {
8801 result.push({id: key, text: value.text});
8802 });
8803 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
8804 //console.log(result);
8805 return {results: result, more: false}
8806 },
8807 cache: true
8808 },
8809 language: select2arrayoflanguage,
8810 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8811 placeholder: "' . dol_escape_js($placeholder) . '",
8812 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8813 minimumInputLength: ' . ((int) $minimumInputLength) . ',
8814 formatResult: function (result, container, query, escapeMarkup) {
8815 return escapeMarkup(result.text);
8816 },
8817 });
8818
8819 ' . ($callurlonselect ? '
8820 /* Code to execute a GET when we select a value */
8821 $(".' . $htmlname . '").change(function() {
8822 var selected = $(".' . $htmlname . '").val();
8823 console.log("We select in selectArrayAjax the entry "+selected)
8824 $(".' . $htmlname . '").val(""); /* reset visible combo value */
8825 $.each( saveRemoteData, function( key, value ) {
8826 if (key == selected)
8827 {
8828 console.log("selectArrayAjax - Do a redirect to "+value.url)
8829 location.assign(value.url);
8830 }
8831 });
8832 });' : '') . '
8833
8834 });
8835 </script>';
8836 }
8837
8838 if ($acceptdelayedhtml) {
8839 $delayedhtmlcontent .= $outdelayed;
8840 } else {
8841 $out .= $outdelayed;
8842 }
8843 return $out;
8844 }
8845
8865 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
8866 {
8867 global $conf, $langs;
8868 global $delayedhtmlcontent; // Will be used later outside of this function
8869
8870 // TODO Use an internal dolibarr component instead of select2
8871 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8872 return '';
8873 }
8874
8875 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
8876
8877 $formattedarrayresult = array();
8878
8879 foreach ($array as $key => $value) {
8880 $o = new stdClass();
8881 $o->id = $key;
8882 $o->text = $value['text'];
8883 $o->url = $value['url'];
8884 $formattedarrayresult[] = $o;
8885 }
8886
8887 $outdelayed = '';
8888 if (!empty($conf->use_javascript_ajax)) {
8889 $tmpplugin = 'select2';
8890 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8891 <script nonce="' . getNonce() . '">
8892 $(document).ready(function () {
8893 var data = ' . json_encode($formattedarrayresult) . ';
8894
8895 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
8896
8897 $(".' . $htmlname . '").select2({
8898 data: data,
8899 language: select2arrayoflanguage,
8900 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8901 placeholder: "' . dol_escape_js($placeholder) . '",
8902 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8903 minimumInputLength: ' . $minimumInputLength . ',
8904 formatResult: function (result, container, query, escapeMarkup) {
8905 return escapeMarkup(result.text);
8906 },
8907 matcher: function (params, data) {
8908
8909 if(! data.id) return null;';
8910
8911 if ($callurlonselect) {
8912 // We forge the url with 'sall='
8913 $outdelayed .= '
8914
8915 var urlBase = data.url;
8916 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
8917 /* console.log("params.term="+params.term); */
8918 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
8919 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
8920 }
8921
8922 if (!$disableFiltering) {
8923 $outdelayed .= '
8924
8925 if(data.text.match(new RegExp(params.term))) {
8926 return data;
8927 }
8928
8929 return null;';
8930 } else {
8931 $outdelayed .= '
8932
8933 return data;';
8934 }
8935
8936 $outdelayed .= '
8937 }
8938 });
8939
8940 ' . ($callurlonselect ? '
8941 /* Code to execute a GET when we select a value */
8942 $(".' . $htmlname . '").change(function() {
8943 var selected = $(".' . $htmlname . '").val();
8944 console.log("We select "+selected)
8945
8946 $(".' . $htmlname . '").val(""); /* reset visible combo value */
8947 $.each( saveRemoteData, function( key, value ) {
8948 if (key == selected)
8949 {
8950 console.log("selectArrayFilter - Do a redirect to "+value.url)
8951 location.assign(value.url);
8952 }
8953 });
8954 });' : '') . '
8955
8956 });
8957 </script>';
8958 }
8959
8960 if ($acceptdelayedhtml) {
8961 $delayedhtmlcontent .= $outdelayed;
8962 } else {
8963 $out .= $outdelayed;
8964 }
8965 return $out;
8966 }
8967
8986 public static function multiselectarray($htmlname, $array, $selected = array(), $key_in_label = 0, $value_as_key = 0, $morecss = '', $translate = 0, $width = 0, $moreattrib = '', $elemtype = '', $placeholder = '', $addjscombo = -1)
8987 {
8988 global $conf, $langs;
8989
8990 $out = '';
8991
8992 if ($addjscombo < 0) {
8993 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8994 $addjscombo = 1;
8995 } else {
8996 $addjscombo = 0;
8997 }
8998 }
8999
9000 $useenhancedmultiselect = 0;
9001 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9002 if ($addjscombo) {
9003 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9004 }
9005 }
9006
9007 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9008 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9009 // submitted to nothing.
9010 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9011 // Output select component
9012 $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";
9013 if (is_array($array) && !empty($array)) {
9014 if ($value_as_key) {
9015 $array = array_combine($array, $array);
9016 }
9017
9018 if (!empty($array)) {
9019 foreach ($array as $key => $value) {
9020 $tmpkey = $key;
9021 $tmpvalue = $value;
9022 $tmpcolor = '';
9023 $tmppicto = '';
9024 $tmplabelhtml = '';
9025 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9026 $tmpkey = $value['id'];
9027 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9028 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9029 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9030 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']): $value['labelhtml'];
9031 }
9032 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9033 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9034
9035 $out .= '<option value="' . $tmpkey . '"';
9036 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9037 $out .= ' selected';
9038 }
9039 if (!empty($tmplabelhtml)) {
9040 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9041 } else {
9042 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9043 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9044 }
9045 $out .= '>';
9046 $out .= dol_htmlentitiesbr($newval);
9047 $out .= '</option>' . "\n";
9048 }
9049 }
9050 }
9051 $out .= '</select>' . "\n";
9052
9053 // Add code for jquery to use multiselect
9054 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9055 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9056 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9057 if ($addjscombo == 1) {
9058 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
9059 $out .= 'function formatResult(record, container) {' . "\n";
9060 // If property data-html set, we decode html entities and use this.
9061 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9062 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9063 //$out .= ' console.log("aaa");';
9064 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9065 $out .= ' }'."\n";
9066 $out .= ' return record.text;';
9067 $out .= '}' . "\n";
9068 $out .= 'function formatSelection(record) {' . "\n";
9069 if ($elemtype == 'category') {
9070 $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
9071 } else {
9072 $out .= 'return record.text;';
9073 }
9074 $out .= '}' . "\n";
9075 $out .= '$(document).ready(function () {
9076 $(\'#' . $htmlname . '\').' . $tmpplugin . '({';
9077 if ($placeholder) {
9078 $out .= '
9079 placeholder: {
9080 id: \'-1\',
9081 text: \'' . dol_escape_js($placeholder) . '\'
9082 },';
9083 }
9084 $out .= ' dir: \'ltr\',
9085 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9086 dropdownCssClass: \'' . $morecss . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
9087 // Specify format function for dropdown item
9088 formatResult: formatResult,
9089 templateResult: formatResult, /* For 4.0 */
9090 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9091 // Specify format function for selected item
9092 formatSelection: formatSelection,
9093 templateSelection: formatSelection /* For 4.0 */
9094 });
9095
9096 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
9097 the size only if component is not hidden by default on load */
9098 $(\'#' . $htmlname . ' + .select2\').addClass(\'' . $morecss . '\');
9099 });' . "\n";
9100 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9101 // Add other js lib
9102 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9103 // ...
9104 $out .= 'console.log(\'addjscombo=2 for htmlname=' . $htmlname . '\');';
9105 $out .= '$(document).ready(function () {
9106 $(\'#' . $htmlname . '\').multiSelect({
9107 containerHTML: \'<div class="multi-select-container">\',
9108 menuHTML: \'<div class="multi-select-menu">\',
9109 buttonHTML: \'<span class="multi-select-button ' . $morecss . '">\',
9110 menuItemHTML: \'<label class="multi-select-menuitem">\',
9111 activeClass: \'multi-select-container--open\',
9112 noneText: \'' . $placeholder . '\'
9113 });
9114 })';
9115 }
9116 $out .= '</script>';
9117 }
9118
9119 return $out;
9120 }
9121
9122
9134 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9135 {
9136 global $langs, $user;
9137
9138 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9139 return '';
9140 }
9141 if (empty($array)) {
9142 return '';
9143 }
9144
9145 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9146
9147 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9148 $tmparray = explode(',', $user->conf->$tmpvar);
9149 foreach ($array as $key => $val) {
9150 //var_dump($key);
9151 //var_dump($tmparray);
9152 if (in_array($key, $tmparray)) {
9153 $array[$key]['checked'] = 1;
9154 } else {
9155 $array[$key]['checked'] = 0;
9156 }
9157 }
9158 } else { // There is no list of fields already customized for user
9159 foreach ($array as $key => $val) {
9160 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9161 $array[$key]['checked'] = 0;
9162 }
9163 }
9164 }
9165
9166 $listoffieldsforselection = '';
9167 $listcheckedstring = '';
9168
9169 foreach ($array as $key => $val) {
9170 // var_dump($val);
9171 // var_dump(array_key_exists('enabled', $val));
9172 // var_dump(!$val['enabled']);
9173 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9174 unset($array[$key]); // We don't want this field
9175 continue;
9176 }
9177 if (!empty($val['type']) && $val['type'] == 'separate') {
9178 // Field remains in array but we don't add it into $listoffieldsforselection
9179 //$listoffieldsforselection .= '<li>-----</li>';
9180 continue;
9181 }
9182 if (!empty($val['label']) && $val['label']) {
9183 if (!empty($val['langfile']) && is_object($langs)) {
9184 $langs->load($val['langfile']);
9185 }
9186
9187 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9188 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((!array_key_exists('checked', $val) || empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . '/><label for="checkbox' . $key . '">' . dol_escape_htmltag($langs->trans($val['label'])) . '</label></li>';
9189 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9190 }
9191 }
9192
9193 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9194
9195 <dl class="dropdown">
9196 <dt>
9197 <a href="#' . $htmlname . '">
9198 ' . img_picto('', 'list') . '
9199 </a>
9200 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9201 </dt>
9202 <dd class="dropdowndd">
9203 <div class="multiselectcheckbox'.$htmlname.'">
9204 <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
9205 <li><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
9206 '.$listoffieldsforselection.'
9207 </ul>
9208 </div>
9209 </dd>
9210 </dl>
9211
9212 <script nonce="' . getNonce() . '" type="text/javascript">
9213 jQuery(document).ready(function () {
9214 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
9215 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9216
9217 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9218
9219 var title = $(this).val() + ",";
9220 if ($(this).is(\':checked\')) {
9221 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9222 }
9223 else {
9224 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9225 }
9226 // Now, we submit page
9227 //$(this).parents(\'form:first\').submit();
9228 });
9229 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9230 var value = $(this).val().toLowerCase();
9231 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9232 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9233 });
9234 });
9235
9236
9237 });
9238 </script>
9239
9240 ';
9241 return $out;
9242 }
9243
9253 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
9254 {
9255 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
9256
9257 $cat = new Categorie($this->db);
9258 $categories = $cat->containing($id, $type);
9259
9260 if ($rendermode == 1) {
9261 $toprint = array();
9262 foreach ($categories as $c) {
9263 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
9264 foreach ($ways as $way) {
9265 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
9266 }
9267 }
9268 if (empty($toprint)) {
9269 return '';
9270 } else {
9271 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
9272 }
9273 }
9274
9275 if ($rendermode == 0) {
9276 $arrayselected = array();
9277 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
9278 foreach ($categories as $c) {
9279 $arrayselected[] = $c->id;
9280 }
9281
9282 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
9283 }
9284
9285 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
9286 }
9287
9297 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
9298 {
9299 global $conf, $langs, $hookmanager;
9300 global $bc, $action;
9301
9302 $object->fetchObjectLinked();
9303
9304 // Bypass the default method
9305 $hookmanager->initHooks(array('commonobject'));
9306 $parameters = array(
9307 'morehtmlright' => $morehtmlright,
9308 'compatibleImportElementsList' => &$compatibleImportElementsList,
9309 );
9310 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9311
9312 $nbofdifferenttypes = count($object->linkedObjects);
9313
9314 if (empty($reshook)) {
9315 print '<!-- showLinkedObjectBlock -->';
9316 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
9317
9318
9319 print '<div class="div-table-responsive-no-min">';
9320 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
9321
9322 print '<tr class="liste_titre">';
9323 print '<td>' . $langs->trans("Type") . '</td>';
9324 print '<td>' . $langs->trans("Ref") . '</td>';
9325 print '<td class="center"></td>';
9326 print '<td class="center">' . $langs->trans("Date") . '</td>';
9327 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9328 print '<td class="right">' . $langs->trans("Status") . '</td>';
9329 print '<td></td>';
9330 print '</tr>';
9331
9332 $nboftypesoutput = 0;
9333
9334 foreach ($object->linkedObjects as $objecttype => $objects) {
9335 $tplpath = $element = $subelement = $objecttype;
9336
9337 // to display import button on tpl
9338 $showImportButton = false;
9339 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
9340 $showImportButton = true;
9341 }
9342
9343 $regs = array();
9344 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
9345 $element = $regs[1];
9346 $subelement = $regs[2];
9347 $tplpath = $element . '/' . $subelement;
9348 }
9349 $tplname = 'linkedobjectblock';
9350
9351 // To work with non standard path
9352 if ($objecttype == 'facture') {
9353 $tplpath = 'compta/' . $element;
9354 if (!isModEnabled('invoice')) {
9355 continue; // Do not show if module disabled
9356 }
9357 } elseif ($objecttype == 'facturerec') {
9358 $tplpath = 'compta/facture';
9359 $tplname = 'linkedobjectblockForRec';
9360 if (!isModEnabled('invoice')) {
9361 continue; // Do not show if module disabled
9362 }
9363 } elseif ($objecttype == 'propal') {
9364 $tplpath = 'comm/' . $element;
9365 if (!isModEnabled('propal')) {
9366 continue; // Do not show if module disabled
9367 }
9368 } elseif ($objecttype == 'supplier_proposal') {
9369 if (!isModEnabled('supplier_proposal')) {
9370 continue; // Do not show if module disabled
9371 }
9372 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
9373 $tplpath = 'expedition';
9374 if (!isModEnabled('shipping')) {
9375 continue; // Do not show if module disabled
9376 }
9377 } elseif ($objecttype == 'reception') {
9378 $tplpath = 'reception';
9379 if (!isModEnabled('reception')) {
9380 continue; // Do not show if module disabled
9381 }
9382 } elseif ($objecttype == 'delivery') {
9383 $tplpath = 'delivery';
9384 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
9385 continue; // Do not show if sub module disabled
9386 }
9387 } elseif ($objecttype == 'ficheinter') {
9388 $tplpath = 'fichinter';
9389 if (!isModEnabled('intervention')) {
9390 continue; // Do not show if module disabled
9391 }
9392 } elseif ($objecttype == 'invoice_supplier') {
9393 $tplpath = 'fourn/facture';
9394 } elseif ($objecttype == 'order_supplier') {
9395 $tplpath = 'fourn/commande';
9396 } elseif ($objecttype == 'expensereport') {
9397 $tplpath = 'expensereport';
9398 } elseif ($objecttype == 'subscription') {
9399 $tplpath = 'adherents';
9400 } elseif ($objecttype == 'conferenceorbooth') {
9401 $tplpath = 'eventorganization';
9402 } elseif ($objecttype == 'conferenceorboothattendee') {
9403 $tplpath = 'eventorganization';
9404 } elseif ($objecttype == 'mo') {
9405 $tplpath = 'mrp';
9406 if (!isModEnabled('mrp')) {
9407 continue; // Do not show if module disabled
9408 }
9409 }
9410
9411 global $linkedObjectBlock;
9412 $linkedObjectBlock = $objects;
9413
9414 // Output template part (modules that overwrite templates must declare this into descriptor)
9415 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
9416 foreach ($dirtpls as $reldir) {
9417 $reldir = rtrim($reldir, '/');
9418 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
9419 global $noMoreLinkedObjectBlockAfter;
9420 $noMoreLinkedObjectBlockAfter = 1;
9421 }
9422
9423 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
9424 if ($res) {
9425 $nboftypesoutput++;
9426 break;
9427 }
9428 }
9429 }
9430
9431 if (!$nboftypesoutput) {
9432 print '<tr><td class="impair" colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9433 }
9434
9435 print '</table>';
9436
9437 if (!empty($compatibleImportElementsList)) {
9438 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9439 }
9440
9441 print '</div>';
9442 }
9443
9444 return $nbofdifferenttypes;
9445 }
9446
9455 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
9456 {
9457 global $conf, $langs, $hookmanager;
9458 global $action;
9459
9460 $linktoelem = '';
9461 $linktoelemlist = '';
9462 $listofidcompanytoscan = '';
9463
9464 if (!is_object($object->thirdparty)) {
9465 $object->fetch_thirdparty();
9466 }
9467
9468 $possiblelinks = array();
9469 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9470 $listofidcompanytoscan = $object->thirdparty->id;
9471 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
9472 $listofidcompanytoscan .= ',' . $object->thirdparty->parent;
9473 }
9474 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
9475 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9476 $tmpproject = new Project($this->db);
9477 $tmpproject->fetch($object->fk_project);
9478 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9479 $listofidcompanytoscan .= ',' . $tmpproject->socid;
9480 }
9481 unset($tmpproject);
9482 }
9483
9484 $possiblelinks = array(
9485 'propal' => array(
9486 'enabled' => isModEnabled('propal'),
9487 'perms' => 1,
9488 'label' => 'LinkToProposal',
9489 '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') . ')'),
9490 'shipping' => array(
9491 'enabled' => isModEnabled('shipping'),
9492 'perms' => 1,
9493 'label' => 'LinkToExpedition',
9494 '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') . ')'),
9495 'order' => array(
9496 'enabled' => isModEnabled('order'),
9497 'perms' => 1,
9498 'label' => 'LinkToOrder',
9499 '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') . ')'),
9500 'invoice' => array(
9501 'enabled' => isModEnabled('invoice'),
9502 'perms' => 1,
9503 'label' => 'LinkToInvoice',
9504 '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') . ')'),
9505 'invoice_template' => array(
9506 'enabled' => isModEnabled('invoice'),
9507 'perms' => 1,
9508 'label' => 'LinkToTemplateInvoice',
9509 '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') . ')'),
9510 'contrat' => array(
9511 'enabled' => isModEnabled('contract'),
9512 'perms' => 1,
9513 'label' => 'LinkToContract',
9514 '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
9515 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'
9516 ),
9517 'fichinter' => array(
9518 'enabled' => isModEnabled('intervention'),
9519 'perms' => 1,
9520 'label' => 'LinkToIntervention',
9521 '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') . ')'),
9522 'supplier_proposal' => array(
9523 'enabled' => isModEnabled('supplier_proposal'),
9524 'perms' => 1,
9525 'label' => 'LinkToSupplierProposal',
9526 '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') . ')'),
9527 'order_supplier' => array(
9528 'enabled' => isModEnabled("supplier_order"),
9529 'perms' => 1,
9530 'label' => 'LinkToSupplierOrder',
9531 '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') . ')'),
9532 'invoice_supplier' => array(
9533 'enabled' => isModEnabled("supplier_invoice"),
9534 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9535 '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') . ')'),
9536 'ticket' => array(
9537 'enabled' => isModEnabled('ticket'),
9538 'perms' => 1,
9539 'label' => 'LinkToTicket',
9540 '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') . ')'),
9541 'mo' => array(
9542 'enabled' => isModEnabled('mrp'),
9543 'perms' => 1,
9544 'label' => 'LinkToMo',
9545 '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') . ')')
9546 );
9547 }
9548
9549 if ($object->table_element == 'commande_fournisseur') {
9550 $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').')';
9551 } elseif ($object->table_element == 'mrp_mo') {
9552 $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').')';
9553 }
9554
9555 $reshook = 0; // Ensure $reshook is defined for static analysis
9556 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9557 // Can complete the possiblelink array
9558 $hookmanager->initHooks(array('commonobject'));
9559 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9560 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9561 }
9562
9563 if (empty($reshook)) {
9564 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9565 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9566 }
9567 } elseif ($reshook > 0) {
9568 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9569 $possiblelinks = $hookmanager->resArray;
9570 }
9571 }
9572
9573 foreach ($possiblelinks as $key => $possiblelink) {
9574 $num = 0;
9575
9576 if (empty($possiblelink['enabled'])) {
9577 continue;
9578 }
9579
9580 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9581 print '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9582
9583 if (getDolGlobalString('MAIN_LINK_BY_REF_IN_LINKTO')) {
9584 print '<br>'."\n";
9585 print '<!-- form to add a link from anywhere -->'."\n";
9586 print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9587 print '<input type="hidden" name="id" value="' . $object->id . '">';
9588 print '<input type="hidden" name="action" value="addlinkbyref">';
9589 print '<input type="hidden" name="token" value="' . newToken() . '">';
9590 print '<input type="hidden" name="addlink" value="' . $key . '">';
9591 print '<table class="noborder">';
9592 print '<tr>';
9593 //print '<td>' . $langs->trans("Ref") . '</td>';
9594 print '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9595 print '<input type="submit" class="button small valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9596 print '<input type="submit" class="button small" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9597 print '</tr>';
9598 print '</table>';
9599 print '</form>';
9600 }
9601
9602 $sql = $possiblelink['sql'];
9603
9604 $resqllist = $this->db->query($sql);
9605 if ($resqllist) {
9606 $num = $this->db->num_rows($resqllist);
9607 $i = 0;
9608
9609 print '<br>';
9610 print '<!-- form to add a link from object to same thirdparty -->'."\n";
9611 print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9612 print '<input type="hidden" name="action" value="addlink">';
9613 print '<input type="hidden" name="token" value="' . newToken() . '">';
9614 print '<input type="hidden" name="id" value="' . $object->id . '">';
9615 print '<input type="hidden" name="addlink" value="' . $key . '">';
9616 print '<table class="noborder">';
9617 print '<tr class="liste_titre">';
9618 print '<td class="nowrap"></td>';
9619 print '<td class="center">' . $langs->trans("Ref") . '</td>';
9620 print '<td class="left">' . $langs->trans("RefCustomer") . '</td>';
9621 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9622 print '<td class="left">' . $langs->trans("Company") . '</td>';
9623 print '</tr>';
9624 while ($i < $num) {
9625 $objp = $this->db->fetch_object($resqllist);
9626
9627 print '<tr class="oddeven">';
9628 print '<td class="left">';
9629 print '<input type="radio" name="idtolinkto" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9630 print '</td>';
9631 print '<td class="center"><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9632 print '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9633 print '<td class="right">';
9634 if ($possiblelink['label'] == 'LinkToContract') {
9635 $form = new Form($this->db);
9636 print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9637 }
9638 print '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9639 print '</td>';
9640 print '<td>' . $objp->name . '</td>';
9641 print '</tr>';
9642 $i++;
9643 }
9644 print '</table>';
9645 print '<div class="center">';
9646 if ($num) {
9647 print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly small" value="' . $langs->trans('ToLink') . '">';
9648 }
9649 if (empty($conf->use_javascript_ajax)) {
9650 print '<input type="submit" class="button button-cancel marginleftonly marginrightonly small" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9651 } else {
9652 print '<input type="submit" onclick="jQuery(\'#' . $key . 'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly small" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9653 }
9654 print '</form>';
9655 $this->db->free($resqllist);
9656 } else {
9657 dol_print_error($this->db);
9658 }
9659 print '</div>';
9660
9661 //$linktoelem.=($linktoelem?' &nbsp; ':'');
9662 if ($num > 0 || getDolGlobalString('MAIN_LINK_BY_REF_IN_LINKTO')) {
9663 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
9664 // } else $linktoelem.=$langs->trans($possiblelink['label']);
9665 } else {
9666 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
9667 }
9668 }
9669 }
9670
9671 if ($linktoelemlist) {
9672 $linktoelem = '
9673 <dl class="dropdown" id="linktoobjectname">
9674 ';
9675 if (!empty($conf->use_javascript_ajax)) {
9676 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
9677 }
9678 $linktoelem .= '<dd>
9679 <div class="multiselectlinkto">
9680 <ul class="ulselectedfields">' . $linktoelemlist . '
9681 </ul>
9682 </div>
9683 </dd>
9684 </dl>';
9685 } else {
9686 $linktoelem = '';
9687 }
9688
9689 if (!empty($conf->use_javascript_ajax)) {
9690 print '<!-- Add js to show linkto box -->
9691 <script nonce="' . getNonce() . '">
9692 jQuery(document).ready(function() {
9693 jQuery(".linkto").click(function() {
9694 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
9695 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
9696 });
9697 });
9698 </script>
9699 ';
9700 }
9701
9702 return $linktoelem;
9703 }
9704
9719 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '', $labelyes = 'Yes', $labelno = 'No')
9720 {
9721 global $langs;
9722
9723 $yes = "yes";
9724 $no = "no";
9725 if ($option) {
9726 $yes = "1";
9727 $no = "0";
9728 }
9729
9730 $disabled = ($disabled ? ' disabled' : '');
9731
9732 $resultyesno = '<select class="flat width75' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
9733 if ($useempty) {
9734 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
9735 }
9736 if (("$value" == 'yes') || ($value == 1)) {
9737 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
9738 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
9739 } else {
9740 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
9741 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
9742 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
9743 }
9744 $resultyesno .= '</select>' . "\n";
9745
9746 if ($addjscombo) {
9747 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
9748 }
9749
9750 return $resultyesno;
9751 }
9752
9753 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9754
9764 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
9765 {
9766 // phpcs:enable
9767 $sql = "SELECT rowid, label";
9768 $sql .= " FROM " . $this->db->prefix() . "export_model";
9769 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
9770 $sql .= " ORDER BY rowid";
9771 $result = $this->db->query($sql);
9772 if ($result) {
9773 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
9774 if ($useempty) {
9775 print '<option value="-1">&nbsp;</option>';
9776 }
9777
9778 $num = $this->db->num_rows($result);
9779 $i = 0;
9780 while ($i < $num) {
9781 $obj = $this->db->fetch_object($result);
9782 if ($selected == $obj->rowid) {
9783 print '<option value="' . $obj->rowid . '" selected>';
9784 } else {
9785 print '<option value="' . $obj->rowid . '">';
9786 }
9787 print $obj->label;
9788 print '</option>';
9789 $i++;
9790 }
9791 print "</select>";
9792 } else {
9793 dol_print_error($this->db);
9794 }
9795 }
9796
9815 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
9816 {
9817 global $conf, $langs, $hookmanager, $extralanguages;
9818
9819 $ret = '';
9820 if (empty($fieldid)) {
9821 $fieldid = 'rowid';
9822 }
9823 if (empty($fieldref)) {
9824 $fieldref = 'ref';
9825 }
9826
9827 // Preparing gender's display if there is one
9828 $addgendertxt = '';
9829 if (property_exists($object, 'gender') && !empty($object->gender)) {
9830 $addgendertxt = ' ';
9831 switch ($object->gender) {
9832 case 'man':
9833 $addgendertxt .= '<i class="fas fa-mars"></i>';
9834 break;
9835 case 'woman':
9836 $addgendertxt .= '<i class="fas fa-venus"></i>';
9837 break;
9838 case 'other':
9839 $addgendertxt .= '<i class="fas fa-transgender"></i>';
9840 break;
9841 }
9842 }
9843
9844 // Add where from hooks
9845 if (is_object($hookmanager)) {
9846 $parameters = array('showrefnav' => true);
9847 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
9848 $object->next_prev_filter .= $hookmanager->resPrint;
9849 }
9850
9851 $previous_ref = $next_ref = '';
9852 if ($shownav) {
9853 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
9854 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
9855
9856 $navurl = $_SERVER["PHP_SELF"];
9857 // Special case for project/task page
9858 if ($paramid == 'project_ref') {
9859 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
9860 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
9861 $paramid = 'ref';
9862 }
9863 }
9864
9865 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
9866 // accesskey is for Mac: CTRL + key for all browsers
9867 $stringforfirstkey = $langs->trans("KeyboardShortcut");
9868 if ($conf->browser->name == 'chrome') {
9869 $stringforfirstkey .= ' ALT +';
9870 } elseif ($conf->browser->name == 'firefox') {
9871 $stringforfirstkey .= ' ALT + SHIFT +';
9872 } else {
9873 $stringforfirstkey .= ' CTL +';
9874 }
9875
9876 $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>';
9877 $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>';
9878 }
9879
9880 //print "xx".$previous_ref."x".$next_ref;
9881 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
9882
9883 // Right part of banner
9884 if ($morehtmlright) {
9885 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
9886 }
9887
9888 if ($previous_ref || $next_ref || $morehtml) {
9889 $ret .= '<div class="pagination paginationref"><ul class="right">';
9890 }
9891 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
9892 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
9893 }
9894 if ($shownav && ($previous_ref || $next_ref)) {
9895 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
9896 $ret .= '<li class="pagination">' . $next_ref . '</li>';
9897 }
9898 if ($previous_ref || $next_ref || $morehtml) {
9899 $ret .= '</ul></div>';
9900 }
9901
9902 // Status
9903 $parameters = array('morehtmlstatus' => $morehtmlstatus);
9904 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
9905 if (empty($reshook)) {
9906 $morehtmlstatus .= $hookmanager->resPrint;
9907 } else {
9908 $morehtmlstatus = $hookmanager->resPrint;
9909 }
9910 if ($morehtmlstatus) {
9911 $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
9912 }
9913
9914 $parameters = array();
9915 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
9916 if (empty($reshook)) {
9917 $morehtmlref .= $hookmanager->resPrint;
9918 } elseif ($reshook > 0) {
9919 $morehtmlref = $hookmanager->resPrint;
9920 }
9921
9922 // Left part of banner
9923 if ($morehtmlleft) {
9924 if ($conf->browser->layout == 'phone') {
9925 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
9926 } else {
9927 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
9928 }
9929 }
9930
9931 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
9932 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
9933
9934 // For thirdparty, contact, user, member, the ref is the id, so we show something else
9935 if ($object->element == 'societe') {
9936 $ret .= dol_htmlentities($object->name);
9937
9938 // List of extra languages
9939 $arrayoflangcode = array();
9940 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
9941 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
9942 }
9943
9944 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
9945 if (!is_object($extralanguages)) {
9946 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
9947 $extralanguages = new ExtraLanguages($this->db);
9948 }
9949 $extralanguages->fetch_name_extralanguages('societe');
9950
9951 if (!empty($extralanguages->attributes['societe']['name'])) {
9952 $object->fetchValuesForExtraLanguages();
9953
9954 $htmltext = '';
9955 // If there is extra languages
9956 foreach ($arrayoflangcode as $extralangcode) {
9957 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
9958 if ($object->array_languages['name'][$extralangcode]) {
9959 $htmltext .= $object->array_languages['name'][$extralangcode];
9960 } else {
9961 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
9962 }
9963 }
9964 $ret .= '<!-- Show translations of name -->' . "\n";
9965 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
9966 }
9967 }
9968 } elseif ($object->element == 'member') {
9969 '@phan-var-force Adherent $object';
9970 $ret .= $object->ref . '<br>';
9971 $fullname = $object->getFullName($langs);
9972 if ($object->morphy == 'mor' && $object->societe) {
9973 $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
9974 } else {
9975 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
9976 }
9977 } elseif (in_array($object->element, array('contact', 'user'))) {
9978 $ret .= dol_htmlentities($object->getFullName($langs)) . $addgendertxt;
9979 } elseif ($object->element == 'usergroup') {
9980 $ret .= dol_htmlentities($object->name);
9981 } elseif (in_array($object->element, array('action', 'agenda'))) {
9982 '@phan-var-force ActionComm $object';
9983 $ret .= $object->ref . '<br>' . $object->label;
9984 } elseif (in_array($object->element, array('adherent_type'))) {
9985 $ret .= $object->label;
9986 } elseif ($object->element == 'ecm_directories') {
9987 $ret .= '';
9988 } elseif ($fieldref != 'none') {
9989 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
9990 }
9991 if ($morehtmlref) {
9992 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
9993 if (substr($morehtmlref, 0, 4) != '<div') {
9994 $ret .= ' ';
9995 }
9996
9997 $ret .= $morehtmlref;
9998 }
9999
10000 $ret .= '</div>';
10001
10002 $ret .= '</div><!-- End banner content -->';
10003
10004 return $ret;
10005 }
10006
10007
10016 public function showbarcode(&$object, $width = 100, $morecss = '')
10017 {
10018 global $conf;
10019
10020 //Check if barcode is filled in the card
10021 if (empty($object->barcode)) {
10022 return '';
10023 }
10024
10025 // Complete object if not complete
10026 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10027 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10028 $result = $object->fetch_barcode();
10029 //Check if fetch_barcode() failed
10030 if ($result < 1) {
10031 return '<!-- ErrorFetchBarcode -->';
10032 }
10033 }
10034
10035 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10036 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10037 $out = '<!-- url barcode = ' . $url . ' -->';
10038 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10039
10040 return $out;
10041 }
10042
10060 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10061 {
10062 global $conf, $langs;
10063
10064 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10065 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10066
10067 $dir = '';
10068 $file = '';
10069 $originalfile = '';
10070 $altfile = '';
10071 $email = '';
10072 $capture = '';
10073 if ($modulepart == 'societe') {
10074 $dir = $conf->societe->multidir_output[$entity];
10075 if (!empty($object->logo)) {
10076 if (dolIsAllowedForPreview($object->logo)) {
10077 if ((string) $imagesize == 'mini') {
10078 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10079 } elseif ((string) $imagesize == 'small') {
10080 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10081 } else {
10082 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10083 }
10084 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10085 }
10086 }
10087 $email = $object->email;
10088 } elseif ($modulepart == 'contact') {
10089 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10090 if (!empty($object->photo)) {
10091 if (dolIsAllowedForPreview($object->photo)) {
10092 if ((string) $imagesize == 'mini') {
10093 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10094 } elseif ((string) $imagesize == 'small') {
10095 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10096 } else {
10097 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10098 }
10099 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10100 }
10101 }
10102 $email = $object->email;
10103 $capture = 'user';
10104 } elseif ($modulepart == 'userphoto') {
10105 $dir = $conf->user->dir_output;
10106 if (!empty($object->photo)) {
10107 if (dolIsAllowedForPreview($object->photo)) {
10108 if ((string) $imagesize == 'mini') {
10109 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10110 } elseif ((string) $imagesize == 'small') {
10111 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10112 } else {
10113 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10114 }
10115 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10116 }
10117 }
10118 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10119 $altfile = $object->id . ".jpg"; // For backward compatibility
10120 }
10121 $email = $object->email;
10122 $capture = 'user';
10123 } elseif ($modulepart == 'memberphoto') {
10124 $dir = $conf->adherent->dir_output;
10125 if (!empty($object->photo)) {
10126 if (dolIsAllowedForPreview($object->photo)) {
10127 if ((string) $imagesize == 'mini') {
10128 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10129 } elseif ((string) $imagesize == 'small') {
10130 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10131 } else {
10132 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10133 }
10134 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10135 }
10136 }
10137 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10138 $altfile = $object->id . ".jpg"; // For backward compatibility
10139 }
10140 $email = $object->email;
10141 $capture = 'user';
10142 } else {
10143 // Generic case to show photos
10144 // TODO Implement this method in previous objects so we can always use this generic method.
10145 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10146 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10147
10148 $dir = $tmpdata['dir'];
10149 $file = $tmpdata['file'];
10150 $originalfile = $tmpdata['originalfile'];
10151 $altfile = $tmpdata['altfile'];
10152 $email = $tmpdata['email'];
10153 $capture = $tmpdata['capture'];
10154 }
10155 }
10156
10157 if ($forcecapture) {
10158 $capture = $forcecapture;
10159 }
10160
10161 $ret = '';
10162
10163 if ($dir) {
10164 if ($file && file_exists($dir . "/" . $file)) {
10165 if ($addlinktofullsize) {
10166 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10167 if ($urladvanced) {
10168 $ret .= '<a href="' . $urladvanced . '">';
10169 } else {
10170 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10171 }
10172 }
10173 $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 . '">';
10174 if ($addlinktofullsize) {
10175 $ret .= '</a>';
10176 }
10177 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
10178 if ($addlinktofullsize) {
10179 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10180 if ($urladvanced) {
10181 $ret .= '<a href="' . $urladvanced . '">';
10182 } else {
10183 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10184 }
10185 }
10186 $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 . '">';
10187 if ($addlinktofullsize) {
10188 $ret .= '</a>';
10189 }
10190 } else {
10191 $nophoto = '/public/theme/common/nophoto.png';
10192 $defaultimg = 'identicon'; // For gravatar
10193 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
10194 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
10195 $nophoto = 'company';
10196 } else {
10197 $nophoto = '/public/theme/common/user_anonymous.png';
10198 if (!empty($object->gender) && $object->gender == 'man') {
10199 $nophoto = '/public/theme/common/user_man.png';
10200 }
10201 if (!empty($object->gender) && $object->gender == 'woman') {
10202 $nophoto = '/public/theme/common/user_woman.png';
10203 }
10204 }
10205 }
10206
10207 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
10208 // see https://gravatar.com/site/implement/images/php/
10209 $ret .= '<!-- Put link to gravatar -->';
10210 $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
10211 } else {
10212 if ($nophoto == 'company') {
10213 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
10214 //$ret .= '<div class="difforspanimgright"></div>';
10215 } else {
10216 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
10217 }
10218 }
10219 }
10220
10221 if ($caneditfield) {
10222 if ($object->photo) {
10223 $ret .= "<br>\n";
10224 }
10225 $ret .= '<table class="nobordernopadding centpercent">';
10226 if ($object->photo) {
10227 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
10228 }
10229 $ret .= '<tr><td class="tdoverflow">';
10230 $maxfilesizearray = getMaxFileSizeArray();
10231 $maxmin = $maxfilesizearray['maxmin'];
10232 if ($maxmin > 0) {
10233 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
10234 }
10235 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
10236 $ret .= '</td></tr>';
10237 $ret .= '</table>';
10238 }
10239 }
10240
10241 return $ret;
10242 }
10243
10244 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10245
10262 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
10263 {
10264 // phpcs:enable
10265 global $conf, $user, $langs;
10266
10267 // Allow excluding groups
10268 $excludeGroups = null;
10269 if (is_array($exclude)) {
10270 $excludeGroups = implode(",", $exclude);
10271 }
10272 // Allow including groups
10273 $includeGroups = null;
10274 if (is_array($include)) {
10275 $includeGroups = implode(",", $include);
10276 }
10277
10278 if (!is_array($selected)) {
10279 $selected = array($selected);
10280 }
10281
10282 $out = '';
10283
10284 // Build sql to search groups
10285 $sql = "SELECT ug.rowid, ug.nom as name";
10286 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10287 $sql .= ", e.label";
10288 }
10289 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
10290 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10291 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
10292 if ($force_entity) {
10293 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
10294 } else {
10295 $sql .= " WHERE ug.entity IS NOT NULL";
10296 }
10297 } else {
10298 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
10299 }
10300 if (is_array($exclude) && $excludeGroups) {
10301 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
10302 }
10303 if (is_array($include) && $includeGroups) {
10304 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
10305 }
10306 $sql .= " ORDER BY ug.nom ASC";
10307
10308 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
10309 $resql = $this->db->query($sql);
10310 if ($resql) {
10311 // Enhance with select2
10312 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10313
10314 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
10315
10316 $num = $this->db->num_rows($resql);
10317 $i = 0;
10318 if ($num) {
10319 if ($show_empty && !$multiple) {
10320 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10321 }
10322
10323 while ($i < $num) {
10324 $obj = $this->db->fetch_object($resql);
10325 $disableline = 0;
10326 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
10327 $disableline = 1;
10328 }
10329
10330 $label = $obj->name;
10331 $labelhtml = $obj->name;
10332 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
10333 $label .= " (" . $obj->label . ")";
10334 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
10335 }
10336
10337 $out .= '<option value="' . $obj->rowid . '"';
10338 if ($disableline) {
10339 $out .= ' disabled';
10340 }
10341 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
10342 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
10343 $out .= ' selected';
10344 }
10345 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
10346 $out .= '>';
10347 $out .= $label;
10348 $out .= '</option>';
10349 $i++;
10350 }
10351 } else {
10352 if ($show_empty) {
10353 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
10354 }
10355 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
10356 }
10357 $out .= '</select>';
10358
10359 $out .= ajax_combobox($htmlname);
10360 } else {
10361 dol_print_error($this->db);
10362 }
10363
10364 return $out;
10365 }
10366
10367
10374 public function showFilterButtons($pos = '')
10375 {
10376 $out = '<div class="nowraponall">';
10377 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
10378 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
10379 $out .= '</div>';
10380
10381 return $out;
10382 }
10383
10392 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10393 {
10394 global $conf;
10395
10396 $out = '';
10397
10398 if (!empty($conf->use_javascript_ajax)) {
10399 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
10400 }
10401 $out .= '<script nonce="' . getNonce() . '">
10402 $(document).ready(function() {
10403 $("#' . $cssclass . 's").click(function() {
10404 if($(this).is(\':checked\')){
10405 console.log("We check all ' . $cssclass . ' and trigger the change method");
10406 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
10407 }
10408 else
10409 {
10410 console.log("We uncheck all");
10411 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
10412 }' . "\n";
10413 if ($calljsfunction) {
10414 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
10415 }
10416 $out .= ' });
10417 $(".' . $cssclass . '").change(function() {
10418 $(this).closest("tr").toggleClass("highlight", this.checked);
10419 });
10420 });
10421 </script>';
10422
10423 return $out;
10424 }
10425
10435 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10436 {
10437 $out = $this->showFilterButtons();
10438 if ($addcheckuncheckall) {
10439 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10440 }
10441 return $out;
10442 }
10443
10457 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10458 {
10459 global $langs, $user;
10460
10461 $out = '';
10462 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10463 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10464 if (!empty($excludeid)) {
10465 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10466 }
10467 $sql .= " ORDER BY label";
10468
10469 $resql = $this->db->query($sql);
10470 if ($resql) {
10471 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10472 if ($useempty) {
10473 $out .= '<option value="0">&nbsp;</option>';
10474 }
10475
10476 while ($obj = $this->db->fetch_object($resql)) {
10477 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10478 }
10479 $out .= '</select>';
10480 $out .= ajax_combobox('select_' . $htmlname);
10481
10482 if (!empty($htmlname) && $user->admin && $info_admin) {
10483 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10484 }
10485
10486 if (!empty($target)) {
10487 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10488 $resql = $this->db->query($sql);
10489 if ($resql) {
10490 if ($this->db->num_rows($resql) > 0) {
10491 $obj = $this->db->fetch_object($resql);
10492 $out .= '<script nonce="' . getNonce() . '">
10493 $(function() {
10494 $("select[name=' . $target . ']").on("change", function() {
10495 var current_val = $(this).val();
10496 if (current_val == ' . $obj->id . ') {';
10497 if (!empty($default_selected) || !empty($selected)) {
10498 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10499 }
10500
10501 $out .= '
10502 $("select[name=' . $htmlname . ']").change();
10503 }
10504 });
10505
10506 $("select[name=' . $htmlname . ']").change(function() {
10507
10508 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10509 // get price of kilometer to fill the unit price
10510 $.ajax({
10511 method: "POST",
10512 dataType: "json",
10513 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10514 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
10515 }).done(function( data, textStatus, jqXHR ) {
10516 console.log(data);
10517 if (typeof data.up != "undefined") {
10518 $("input[name=value_unit]").val(data.up);
10519 $("select[name=' . $htmlname . ']").attr("title", data.title);
10520 } else {
10521 $("input[name=value_unit]").val("");
10522 $("select[name=' . $htmlname . ']").attr("title", "");
10523 }
10524 });
10525 }
10526 });
10527 });
10528 </script>';
10529 }
10530 }
10531 }
10532 } else {
10533 dol_print_error($this->db);
10534 }
10535
10536 return $out;
10537 }
10538
10547 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10548 {
10549 global $conf, $langs;
10550
10551 $out = '';
10552 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10553 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10554
10555 $resql = $this->db->query($sql);
10556 if ($resql) {
10557 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10558 if ($useempty) {
10559 $out .= '<option value="0"></option>';
10560 }
10561
10562 while ($obj = $this->db->fetch_object($resql)) {
10563 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10564 }
10565 $out .= '</select>';
10566 } else {
10567 dol_print_error($this->db);
10568 }
10569
10570 return $out;
10571 }
10572
10583 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10584 {
10585 global $langs;
10586
10587 $out = '';
10588 $sql = "SELECT id, code, label";
10589 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
10590 $sql .= " WHERE active = 1";
10591
10592 $resql = $this->db->query($sql);
10593 if ($resql) {
10594 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10595 if ($useempty) {
10596 $out .= '<option value="0"></option>';
10597 }
10598 if ($allchoice) {
10599 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10600 }
10601
10602 $field = 'code';
10603 if ($useid) {
10604 $field = 'id';
10605 }
10606
10607 while ($obj = $this->db->fetch_object($resql)) {
10608 $key = $langs->trans($obj->code);
10609 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10610 }
10611 $out .= '</select>';
10612
10613 $out .= ajax_combobox('select_'.$htmlname);
10614 } else {
10615 dol_print_error($this->db);
10616 }
10617
10618 return $out;
10619 }
10620
10639 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)
10640 {
10641 global $user, $conf, $langs;
10642
10643 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10644
10645 if (is_null($usertofilter)) {
10646 $usertofilter = $user;
10647 }
10648
10649 $out = '';
10650
10651 $hideunselectables = false;
10652 if (getDolGlobalString('PROJECT_HIDE_UNSELECTABLES')) {
10653 $hideunselectables = true;
10654 }
10655
10656 if (empty($projectsListId)) {
10657 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
10658 $projectstatic = new Project($this->db);
10659 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10660 }
10661 }
10662
10663 // Search all projects
10664 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10665 p.title, p.fk_soc, p.fk_statut, p.public,";
10666 $sql .= ' s.nom as name';
10667 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
10668 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
10669 $sql .= ' ' . $this->db->prefix() . 'facture as f';
10670 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
10671 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
10672 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
10673 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
10674 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
10675 $sql .= " ORDER BY p.ref, f.ref ASC";
10676
10677 $resql = $this->db->query($sql);
10678 if ($resql) {
10679 // Use select2 selector
10680 if (!empty($conf->use_javascript_ajax)) {
10681 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10682 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
10683 $out .= $comboenhancement;
10684 $morecss = 'minwidth200imp maxwidth500';
10685 }
10686
10687 if (empty($option_only)) {
10688 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10689 }
10690 if (!empty($show_empty)) {
10691 $out .= '<option value="0" class="optiongrey">';
10692 if (!is_numeric($show_empty)) {
10693 $out .= $show_empty;
10694 } else {
10695 $out .= '&nbsp;';
10696 }
10697 $out .= '</option>';
10698 }
10699 $num = $this->db->num_rows($resql);
10700 $i = 0;
10701 if ($num) {
10702 while ($i < $num) {
10703 $obj = $this->db->fetch_object($resql);
10704 // 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.
10705 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
10706 // Do nothing
10707 } else {
10708 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
10709 $i++;
10710 continue;
10711 }
10712
10713 $labeltoshow = '';
10714
10715 if ($showproject == 'all') {
10716 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
10717 if ($obj->name) {
10718 $labeltoshow .= ' - ' . $obj->name; // Soc name
10719 }
10720
10721 $disabled = 0;
10722 if ($obj->fk_statut == Project::STATUS_DRAFT) {
10723 $disabled = 1;
10724 $labeltoshow .= ' - ' . $langs->trans("Draft");
10725 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
10726 if ($discard_closed == 2) {
10727 $disabled = 1;
10728 }
10729 $labeltoshow .= ' - ' . $langs->trans("Closed");
10730 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
10731 $disabled = 1;
10732 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
10733 }
10734 }
10735
10736 if (!empty($selected) && $selected == $obj->rowid) {
10737 $out .= '<option value="' . $obj->rowid . '" selected';
10738 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10739 $out .= '>' . $labeltoshow . '</option>';
10740 } else {
10741 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
10742 $resultat = '';
10743 } else {
10744 $resultat = '<option value="' . $obj->rowid . '"';
10745 if ($disabled) {
10746 $resultat .= ' disabled';
10747 }
10748 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
10749 //else $labeltoshow.=' ('.$langs->trans("Private").')';
10750 $resultat .= '>';
10751 $resultat .= $labeltoshow;
10752 $resultat .= '</option>';
10753 }
10754 $out .= $resultat;
10755 }
10756 }
10757 $i++;
10758 }
10759 }
10760 if (empty($option_only)) {
10761 $out .= '</select>';
10762 }
10763
10764 $this->db->free($resql);
10765
10766 return $out;
10767 } else {
10768 dol_print_error($this->db);
10769 return '';
10770 }
10771 }
10772
10786 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
10787 {
10788 global $conf, $langs;
10789
10790 $out = '';
10791
10792 dol_syslog('FactureRec::fetch', LOG_DEBUG);
10793
10794 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
10795 //$sql.= ', el.fk_source';
10796 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
10797 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
10798 $sql .= " ORDER BY f.titre ASC";
10799
10800 $resql = $this->db->query($sql);
10801 if ($resql) {
10802 // Use select2 selector
10803 if (!empty($conf->use_javascript_ajax)) {
10804 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10805 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
10806 $out .= $comboenhancement;
10807 $morecss = 'minwidth200imp maxwidth500';
10808 }
10809
10810 if (empty($option_only)) {
10811 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10812 }
10813 if (!empty($show_empty)) {
10814 $out .= '<option value="0" class="optiongrey">';
10815 if (!is_numeric($show_empty)) {
10816 $out .= $show_empty;
10817 } else {
10818 $out .= '&nbsp;';
10819 }
10820 $out .= '</option>';
10821 }
10822 $num = $this->db->num_rows($resql);
10823 if ($num) {
10824 while ($obj = $this->db->fetch_object($resql)) {
10825 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
10826
10827 $disabled = 0;
10828 if (!empty($obj->suspended)) {
10829 $disabled = 1;
10830 $labeltoshow .= ' - ' . $langs->trans("Closed");
10831 }
10832
10833
10834 if (!empty($selected) && $selected == $obj->rowid) {
10835 $out .= '<option value="' . $obj->rowid . '" selected';
10836 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10837 $out .= '>' . $labeltoshow . '</option>';
10838 } else {
10839 if ($disabled && ($selected != $obj->rowid)) {
10840 $resultat = '';
10841 } else {
10842 $resultat = '<option value="' . $obj->rowid . '"';
10843 if ($disabled) {
10844 $resultat .= ' disabled';
10845 }
10846 $resultat .= '>';
10847 $resultat .= $labeltoshow;
10848 $resultat .= '</option>';
10849 }
10850 $out .= $resultat;
10851 }
10852 }
10853 }
10854 if (empty($option_only)) {
10855 $out .= '</select>';
10856 }
10857
10858 print $out;
10859
10860 $this->db->free($resql);
10861 return $num;
10862 } else {
10863 $this->errors[] = $this->db->lasterror;
10864 return -1;
10865 }
10866 }
10867
10877 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '')
10878 {
10879 global $langs;
10880
10881 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
10882 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
10883 }
10884
10885 $ret = '';
10886
10887 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
10888 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
10889 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
10890 $ret .= '</a>';
10891
10892 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
10893
10894 // Show select fields as tags.
10895 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
10896
10897 if ($search_component_params_hidden) {
10898 // Split the criteria on each AND
10899 //var_dump($search_component_params_hidden);
10900
10901 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
10902
10903 // $arrayofandtags is now array( '...' , '...', ...)
10904 // Show each AND part
10905 foreach ($arrayofandtags as $tmpkey => $tmpval) {
10906 $errormessage = '';
10907 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
10908 if ($errormessage) {
10909 $this->error = 'ERROR in parsing search string: '.$errormessage;
10910 }
10911 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
10912 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
10913 $searchtags = removeGlobalParenthesis($searchtags);
10914
10915 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
10916 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
10917 $ret .= dol_escape_htmltag($searchtags);
10918 $ret .= '</span>';
10919 }
10920 }
10921
10922 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
10923
10924 //$ret .= search_component_params
10925 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
10926 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
10927
10928 $show_search_component_params_hidden = 1;
10929 if ($show_search_component_params_hidden) {
10930 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
10931 }
10932 $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%')) -->";
10933 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
10934 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
10935
10936 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
10937 foreach ($arrayofcriterias as $criteria) {
10938 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
10939 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
10940 continue;
10941 }
10942 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
10943 continue;
10944 }
10945 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
10946 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
10947 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
10948 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
10949 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
10950 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
10951 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
10952 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
10953 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
10954 } else {
10955 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
10956 }
10957 }
10958 }
10959
10960 $ret .= '</div>';
10961
10962 $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";
10963 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
10964
10965 $ret .= '</div>';
10966 $ret .= '</div>';
10967
10968 $ret .= '<script>
10969 jQuery(".tagsearchdelete").click(function(e) {
10970 var filterid = $(this).parents().attr("data-ufilterid");
10971 console.log("We click to delete the criteria nb "+filterid);
10972
10973 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
10974 var newparamstring = \'\';
10975 $(\'.tagsearch\').each(function(index, element) {
10976 tmpfilterid = $(this).attr("data-ufilterid");
10977 if (tmpfilterid != filterid) {
10978 // We keep this criteria
10979 if (newparamstring == \'\') {
10980 newparamstring = $(this).attr("data-ufilter");
10981 } else {
10982 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
10983 }
10984 }
10985 });
10986 console.log("newparamstring = "+newparamstring);
10987
10988 jQuery("#search_component_params_hidden").val(newparamstring);
10989
10990 // We repost the form
10991 $(this).closest(\'form\').submit();
10992 });
10993
10994 jQuery("#search_component_params_input").keydown(function(e) {
10995 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
10996 console.log(e.which);
10997 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
10998 /* We click on back when the input field is already empty */
10999 event.preventDefault();
11000 jQuery("#divsearch_component_params .tagsearch").last().remove();
11001 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
11002 var s = "";
11003 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
11004 if (s != "") {
11005 s = s + " AND ";
11006 }
11007 s = s + $(this).attr("data-ufilter");
11008 });
11009 console.log("New value for search_component_params_hidden = "+s);
11010 jQuery("#search_component_params_hidden").val(s);
11011 }
11012 });
11013
11014 </script>
11015 ';
11016
11017 return $ret;
11018 }
11019
11029 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
11030 {
11031 global $langs, $user;
11032
11033 $retstring = '';
11034
11035 $TModels = array();
11036
11037 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
11038 $formmail = new FormMail($this->db);
11039 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
11040
11041 if ($default) {
11042 $TModels[0] = $langs->trans('DefaultMailModel');
11043 }
11044 if ($result > 0) {
11045 foreach ($formmail->lines_model as $model) {
11046 $TModels[$model->id] = $model->label;
11047 }
11048 }
11049
11050 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
11051
11052 foreach ($TModels as $id_model => $label_model) {
11053 $retstring .= '<option value="' . $id_model . '"';
11054 $retstring .= ">" . $label_model . "</option>";
11055 }
11056
11057 $retstring .= "</select>";
11058
11059 if ($addjscombo) {
11060 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
11061 }
11062
11063 return $retstring;
11064 }
11065
11077 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
11078 {
11079 global $langs;
11080
11081 $buttons = array();
11082
11083 $save = array(
11084 'name' => 'save',
11085 'label_key' => $save_label,
11086 );
11087
11088 if ($save_label == 'Create' || $save_label == 'Add') {
11089 $save['name'] = 'add';
11090 } elseif ($save_label == 'Modify') {
11091 $save['name'] = 'edit';
11092 }
11093
11094 $cancel = array(
11095 'name' => 'cancel',
11096 'label_key' => 'Cancel',
11097 );
11098
11099 !empty($save_label) ? $buttons[] = $save : '';
11100
11101 if (!empty($morebuttons)) {
11102 $buttons[] = $morebuttons;
11103 }
11104
11105 !empty($cancel_label) ? $buttons[] = $cancel : '';
11106
11107 $retstring = $withoutdiv ? '' : '<div class="center">';
11108
11109 foreach ($buttons as $button) {
11110 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
11111 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
11112 }
11113 $retstring .= $withoutdiv ? '' : '</div>';
11114
11115 if ($dol_openinpopup) {
11116 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
11117 $retstring .= '<script nonce="' . getNonce() . '">';
11118 $retstring .= 'jQuery(".button-cancel").click(function(e) {
11119 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
11120 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
11121 });';
11122 $retstring .= '</script>';
11123 }
11124
11125 return $retstring;
11126 }
11127
11128
11129 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11130
11137 {
11138 // phpcs:enable
11139 global $langs;
11140
11141 $num = count($this->cache_invoice_subtype);
11142 if ($num > 0) {
11143 return 0; // Cache already loaded
11144 }
11145
11146 dol_syslog(__METHOD__, LOG_DEBUG);
11147
11148 $sql = "SELECT rowid, code, label as label";
11149 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
11150 $sql .= " WHERE active = 1";
11151
11152 $resql = $this->db->query($sql);
11153 if ($resql) {
11154 $num = $this->db->num_rows($resql);
11155 $i = 0;
11156 while ($i < $num) {
11157 $obj = $this->db->fetch_object($resql);
11158
11159 // If translation exists, we use it, otherwise we take the default wording
11160 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
11161 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
11162 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
11163 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
11164 $i++;
11165 }
11166
11167 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
11168
11169 return $num;
11170 } else {
11171 dol_print_error($this->db);
11172 return -1;
11173 }
11174 }
11175
11176
11187 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
11188 {
11189 global $langs, $user;
11190
11191 $out = '';
11192 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
11193
11194 $this->load_cache_invoice_subtype();
11195
11196 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
11197 if ($addempty) {
11198 $out .= '<option value="0">&nbsp;</option>';
11199 }
11200
11201 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
11202 $label = $subtype['label'];
11203 $out .= '<option value="' . $subtype['rowid'] . '"';
11204 if ($selected == $subtype['rowid']) {
11205 $out .= ' selected="selected"';
11206 }
11207 $out .= '>';
11208 $out .= $label;
11209 $out .= '</option>';
11210 }
11211
11212 $out .= '</select>';
11213 if ($user->admin && empty($noinfoadmin)) {
11214 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11215 }
11216 $out .= ajax_combobox($htmlname);
11217
11218 return $out;
11219 }
11220}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to transform a common input text or select field into ...
Definition ajax.lib.php:48
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:456
ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
Generic function that return javascript to add to a page to transform a common input text field into ...
Definition ajax.lib.php:305
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:559
$object ref
Definition info.php:79
Class to manage bank accounts.
Class to manage categories.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
DAO Resource object.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0)
selectModelMail
showFilterButtons($pos='')
Return HTML to show the search and clear search button.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
load_cache_vatrates($country_code)
Load into the cache ->cache_vatrates, all the vat rates of a country.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=array(), $title='RelatedObjects')
Show linked object block.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
select_dolresources_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofresourceid=array())
Return select list of resources.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
select_produits($selected=0, $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1)
Return list of products for customer.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party This call select_thirdparty_list() or ajax depending on setu...
textwithpicto($text, $htmltext, $direction=1, $type='help', $extracss='', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
select_dolgroups($selected=0, $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly=array(), $force_entity='0', $multiple=false, $morecss='minwidth200')
Return select list of groups.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
select_produits_list($selected=0, $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='maxwidth500', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1)
Return list of products for a customer.
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array())
Return select list of users.
select_contact($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $nokeyifsocid=true, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $selected_input_value='', $filter='')
Output html form to select a contact This call select_contacts() or ajax depending on setup.
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='', $openinghours='', $stepminutes=1, $labeladddateof='', $placeholder='', $gm='auto')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
getSelectInvoiceSubtype($selected=0, $htmlname='subtypeid', $addempty=0, $noinfoadmin=0, $morecss='')
Return list of invoice subtypes.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse=null, $societe_acheteuse=null, $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0, $type_vat=0)
Output an HTML select vat rate.
form_multicurrency_rate($page, $rate=0.0, $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
load_cache_availability()
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
selectcontacts($socid, $selected=array(), $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=0, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0, $filter='')
Return HTML code of the SELECT of list of all contacts (for a third party or all).
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
selectMembersList($selected='', $htmlname='adherentid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of adherents.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
selectTicketsList($selected='', $htmlname='ticketid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of tickets.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array())
Show block with links to link to other objects.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=false, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
selectProjectsList($selected='', $htmlname='projectid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of projects.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1, $noprint=0)
print list of payment modes.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
form_confirm($page, $title, $question, $action, $formquestion=array(), $selectedchoice="", $useajax=0, $height=170, $width=500)
load_cache_conditions_paiements()
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier=0)
Return list of suppliers prices for a product.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0)
Return combo list of activated countries, into language of user.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="")
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly=array(), $force_entity='0')
Return the HTML select list of users.
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday=0, $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
load_cache_invoice_subtype()
Load into cache list of invoice subtypes.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='')
Output the component to make advanced search criteries.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $elemtype='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
load_cache_types_paiements()
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Return the list of type of delay available.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage hooks.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
currency_name($code_iso, $withcode=0, $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:85
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='')
Format phone numbers according to country.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
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.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
a disabled
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition main.inc.php:123
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:139
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:142
getMaxFileSizeArray()
Return the max allowed for file upload.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e rowid
Definition invoice.php:1991