dolibarr 18.0.6
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-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.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 *
26 * This program is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published by
28 * the Free Software Foundation; either version 3 of the License, or
29 * (at your option) any later version.
30 *
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
35 *
36 * You should have received a copy of the GNU General Public License
37 * along with this program. If not, see <https://www.gnu.org/licenses/>.
38 */
39
53class Form
54{
58 public $db;
59
63 public $error = '';
64
68 public $errors = array();
69
70 // Some properties used to return data by some methods
71 public $result;
72 public $num;
73
74 // Cache arrays
75 public $cache_types_paiements = array();
76 public $cache_conditions_paiements = array();
77 public $cache_transport_mode = array();
78 public $cache_availability = array();
79 public $cache_demand_reason = array();
80 public $cache_types_fees = array();
81 public $cache_vatrates = array();
82
83
89 public function __construct($db)
90 {
91 $this->db = $db;
92 }
93
110 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
111 {
112 global $conf, $langs;
113
114 $ret = '';
115
116 // TODO change for compatibility
117 if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata)) {
118 if (!empty($perm)) {
119 $tmp = explode(':', $typeofdata);
120 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
121 if ($fieldrequired) {
122 $ret .= '<span class="fieldrequired">';
123 }
124 if ($help) {
125 $ret .= $this->textwithpicto($langs->trans($text), $help);
126 } else {
127 $ret .= $langs->trans($text);
128 }
129 if ($fieldrequired) {
130 $ret .= '</span>';
131 }
132 $ret .= '</div>' . "\n";
133 } else {
134 if ($fieldrequired) {
135 $ret .= '<span class="fieldrequired">';
136 }
137 if ($help) {
138 $ret .= $this->textwithpicto($langs->trans($text), $help);
139 } else {
140 $ret .= $langs->trans($text);
141 }
142 if ($fieldrequired) {
143 $ret .= '</span>';
144 }
145 }
146 } else {
147 if (empty($notabletag) && $perm) {
148 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
149 }
150 if ($fieldrequired) {
151 $ret .= '<span class="fieldrequired">';
152 }
153 if ($help) {
154 $ret .= $this->textwithpicto($langs->trans($text), $help);
155 } else {
156 $ret .= $langs->trans($text);
157 }
158 if ($fieldrequired) {
159 $ret .= '</span>';
160 }
161 if (!empty($notabletag)) {
162 $ret .= ' ';
163 }
164 if (empty($notabletag) && $perm) {
165 $ret .= '</td>';
166 }
167 if (empty($notabletag) && $perm) {
168 $ret .= '<td class="right">';
169 }
170 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
171 $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>';
172 }
173 if (!empty($notabletag) && $notabletag == 1) {
174 if ($text) {
175 $ret .= ' : ';
176 } else {
177 $ret .= ' ';
178 }
179 }
180 if (!empty($notabletag) && $notabletag == 3) {
181 $ret .= ' ';
182 }
183 if (empty($notabletag) && $perm) {
184 $ret .= '</td>';
185 }
186 if (empty($notabletag) && $perm) {
187 $ret .= '</tr></table>';
188 }
189 }
190
191 return $ret;
192 }
193
217 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 = '')
218 {
219 global $conf, $langs;
220
221 $ret = '';
222
223 // Check parameters
224 if (empty($typeofdata)) {
225 return 'ErrorBadParameter typeofdata is empty';
226 }
227 // Clean paramater $typeofdata
228 if ($typeofdata == 'datetime') {
229 $typeofdata = 'dayhour';
230 }
231 $reg = array();
232 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
233 if ($reg[1] == 'varchar') {
234 $typeofdata = 'string';
235 } elseif ($reg[1] == 'int') {
236 $typeofdata = 'numeric';
237 } else {
238 return 'ErrorBadParameter ' . $typeofdata;
239 }
240 }
241
242 // When option to edit inline is activated
243 if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
244 $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
245 } else {
246 if ($editaction == '') {
247 $editaction = GETPOST('action', 'aZ09');
248 }
249 $editmode = ($editaction == 'edit' . $htmlname);
250 if ($editmode) { // edit mode
251 $ret .= "\n";
252 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
253 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
254 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
255 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
256 if (empty($notabletag)) {
257 $ret .= '<table class="nobordernopadding centpercent">';
258 }
259 if (empty($notabletag)) {
260 $ret .= '<tr><td>';
261 }
262 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
263 $tmp = explode(':', $typeofdata);
264 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
265 } elseif (preg_match('/^(integer)/', $typeofdata)) {
266 $tmp = explode(':', $typeofdata);
267 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
268 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
269 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
270 $tmp = explode(':', $typeofdata);
271 $valuetoshow = price2num($editvalue ? $editvalue : $value);
272 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
273 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
274 $tmp = explode(':', $typeofdata);
275 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
276 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
277 $tmp = explode(':', $typeofdata);
278 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
279 $morealt = '';
280 if (preg_match('/%/', $cols)) {
281 $morealt = ' style="width: ' . $cols . '"';
282 $cols = '';
283 }
284 $valuetoshow = ($editvalue ? $editvalue : $value);
285 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
286 // textarea convert automatically entities chars into simple chars.
287 // 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 wysiwig is off.
288 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
289 $ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
290 $ret .= '</textarea>';
291 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
292 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
293 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
294 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
295 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
296 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
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, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
301 } elseif (preg_match('/^select;/', $typeofdata)) {
302 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
303 $arraylist = array();
304 foreach ($arraydata as $val) {
305 $tmp = explode(':', $val);
306 $tmpkey = str_replace('|', ':', $tmp[0]);
307 $arraylist[$tmpkey] = $tmp[1];
308 }
309 $ret .= $this->selectarray($htmlname, $arraylist, $value);
310 } elseif (preg_match('/^link/', $typeofdata)) {
311 // TODO Not yet implemented. See code for extrafields
312 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
313 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
314 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
315 $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]));
316 $ret .= $doleditor->Create(1);
317 } elseif ($typeofdata == 'asis') {
318 $ret .= ($editvalue ? $editvalue : $value);
319 }
320 if (empty($notabletag)) {
321 $ret .= '</td>';
322 }
323
324 // Button save-cancel
325 if (empty($notabletag)) {
326 $ret .= '<td>';
327 }
328 //else $ret.='<div class="clearboth"></div>';
329 $ret .= '<input type="submit" class="smallpaddingimp button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
330 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
331 $ret .= '<br>' . "\n";
332 }
333 $ret .= '<input type="submit" class="smallpaddingimp button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
334 if (empty($notabletag)) {
335 $ret .= '</td>';
336 }
337
338 if (empty($notabletag)) {
339 $ret .= '</tr></table>' . "\n";
340 }
341 $ret .= '</form>' . "\n";
342 } else { // view mode
343 if (preg_match('/^email/', $typeofdata)) {
344 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
345 } elseif (preg_match('/^phone/', $typeofdata)) {
346 $ret .= dol_print_phone($value, '_blank', 32, 1);
347 } elseif (preg_match('/^url/', $typeofdata)) {
348 $ret .= dol_print_url($value, '_blank', 32, 1);
349 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
350 $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
351 } elseif (preg_match('/^checkbox/', $typeofdata)) {
352 $tmp = explode(':', $typeofdata);
353 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
354 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
355 $ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($value), 1, 1, 1);
356 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
357 $ret .= dol_string_onlythesehtmltags($value);
358 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
359 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
360 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
361 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
362 } elseif (preg_match('/^select;/', $typeofdata)) {
363 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
364 $arraylist = array();
365 foreach ($arraydata as $val) {
366 $tmp = explode(':', $val);
367 $arraylist[$tmp[0]] = $tmp[1];
368 }
369 $ret .= $arraylist[$value];
370 if ($htmlname == 'fk_product_type') {
371 if ($value == 0) {
372 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
373 } else {
374 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
375 }
376 }
377 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
378 $tmpcontent = dol_htmlentitiesbr($value);
379 if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
380 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
381 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
382 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
383 }
384 // We dont use dol_escape_htmltag to get the html formating active, but this need we must also
385 // clean data from some dangerous html
387 } else {
388 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
389 $ret .= dol_escape_htmltag($value);
390 } else {
391 $ret .= $value; // $value must be already html escaped.
392 }
393 }
394
395 // Custom format if parameter $formatfunc has been provided
396 if ($formatfunc && method_exists($object, $formatfunc)) {
397 $ret = $object->$formatfunc($ret);
398 }
399 }
400 }
401 return $ret;
402 }
403
415 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
416 {
417 global $conf, $langs, $extralanguages;
418
419 $result = '';
420
421 // List of extra languages
422 $arrayoflangcode = array();
423 if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
424 $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
425 }
426
427 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
428 if (!is_object($extralanguages)) {
429 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
430 $extralanguages = new ExtraLanguages($this->db);
431 }
432 $extralanguages->fetch_name_extralanguages('societe');
433
434 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
435 return ''; // No extralang field to show
436 }
437
438 $result .= '<!-- Widget for translation -->' . "\n";
439 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
440 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
441 $result .= $s;
442 $result .= '</div>';
443
444 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
445
446 $resultforextrlang = '';
447 foreach ($arrayoflangcode as $langcode) {
448 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
449 if (empty($valuetoshow)) {
450 $object->fetchValuesForExtraLanguages();
451 //var_dump($object->array_languages);
452 $valuetoshow = $object->array_languages[$fieldname][$langcode];
453 }
454
455 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
456 $resultforextrlang .= $s;
457
458 // TODO Use the showInputField() method of ExtraLanguages object
459 if ($typeofdata == 'textarea') {
460 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
461 $resultforextrlang .= $valuetoshow;
462 $resultforextrlang .= '</textarea>';
463 } else {
464 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
465 }
466 }
467 $result .= $resultforextrlang;
468
469 $result .= '</div>';
470 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
471 }
472
473 return $result;
474 }
475
489 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
490 {
491 global $conf;
492
493 $out = '';
494
495 // Check parameters
496 if (preg_match('/^text/', $inputType)) {
497 $value = dol_nl2br($value);
498 } elseif (preg_match('/^numeric/', $inputType)) {
499 $value = price($value);
500 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
501 $value = dol_print_date($value, 'day');
502 }
503
504 if ($condition) {
505 $element = false;
506 $table_element = false;
507 $fk_element = false;
508 $loadmethod = false;
509 $savemethod = false;
510 $ext_element = false;
511 $button_only = false;
512 $inputOption = '';
513 $rows = '';
514 $cols = '';
515
516 if (is_object($object)) {
517 $element = $object->element;
518 $table_element = $object->table_element;
519 $fk_element = $object->id;
520 }
521
522 if (is_object($extObject)) {
523 $ext_element = $extObject->element;
524 }
525
526 if (preg_match('/^(string|email|numeric)/', $inputType)) {
527 $tmp = explode(':', $inputType);
528 $inputType = $tmp[0];
529 if (!empty($tmp[1])) {
530 $inputOption = $tmp[1];
531 }
532 if (!empty($tmp[2])) {
533 $savemethod = $tmp[2];
534 }
535 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
536 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
537 $tmp = explode(':', $inputType);
538 $inputType = $tmp[0];
539 if (!empty($tmp[1])) {
540 $inputOption = $tmp[1];
541 }
542 if (!empty($tmp[2])) {
543 $savemethod = $tmp[2];
544 }
545
546 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
547 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
548 $tmp = explode(':', $inputType);
549 $inputType = $tmp[0];
550 $loadmethod = $tmp[1];
551 if (!empty($tmp[2])) {
552 $savemethod = $tmp[2];
553 }
554 if (!empty($tmp[3])) {
555 $button_only = true;
556 }
557 } elseif (preg_match('/^textarea/', $inputType)) {
558 $tmp = explode(':', $inputType);
559 $inputType = $tmp[0];
560 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
561 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
562 } elseif (preg_match('/^ckeditor/', $inputType)) {
563 $tmp = explode(':', $inputType);
564 $inputType = $tmp[0];
565 $toolbar = $tmp[1];
566 if (!empty($tmp[2])) {
567 $width = $tmp[2];
568 }
569 if (!empty($tmp[3])) {
570 $heigth = $tmp[3];
571 }
572 if (!empty($tmp[4])) {
573 $savemethod = $tmp[4];
574 }
575
576 if (isModEnabled('fckeditor')) {
577 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
578 } else {
579 $inputType = 'textarea';
580 }
581 }
582
583 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
584 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
585 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
586 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
587 if (!empty($savemethod)) {
588 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
589 }
590 if (!empty($ext_element)) {
591 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
592 }
593 if (!empty($custommsg)) {
594 if (is_array($custommsg)) {
595 if (!empty($custommsg['success'])) {
596 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
597 }
598 if (!empty($custommsg['error'])) {
599 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
600 }
601 } else {
602 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
603 }
604 }
605 if ($inputType == 'textarea') {
606 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
607 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
608 }
609 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
610 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
611 } else {
612 $out = $value;
613 }
614
615 return $out;
616 }
617
636 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
637 {
638 if ($incbefore) {
639 $text = $incbefore . $text;
640 }
641 if (!$htmltext) {
642 return $text;
643 }
644 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
645
646 $tag = 'td';
647 if ($notabs == 2) {
648 $tag = 'div';
649 }
650 if ($notabs == 3) {
651 $tag = 'span';
652 }
653 // Sanitize tooltip
654 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
655
656 $extrastyle = '';
657 if ($direction < 0) {
658 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
659 $extrastyle = 'padding: 0px; padding-left: 3px;';
660 }
661 if ($direction > 0) {
662 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
663 $extrastyle = 'padding: 0px; padding-right: 3px;';
664 }
665
666 $classfortooltip = 'classfortooltip';
667
668 $s = '';
669 $textfordialog = '';
670
671 if ($tooltiptrigger == '') {
672 $htmltext = str_replace('"', '&quot;', $htmltext);
673 } else {
674 $classfortooltip = 'classfortooltiponclick';
675 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
676 }
677 if ($tooltipon == 2 || $tooltipon == 3) {
678 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
679 if ($tooltiptrigger == '') {
680 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribut to put on img tag to store tooltip
681 } else {
682 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
683 }
684 } else {
685 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribut to put on td text tag
686 }
687 if ($tooltipon == 1 || $tooltipon == 3) {
688 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
689 if ($tooltiptrigger == '') {
690 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribut to put on td tag to store tooltip
691 } else {
692 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
693 }
694 } else {
695 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribut to put on td text tag
696 }
697 if (empty($notabs)) {
698 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
699 } elseif ($notabs == 2) {
700 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
701 }
702 // Define value if value is before
703 if ($direction < 0) {
704 $s .= '<' . $tag . $paramfortooltipimg;
705 if ($tag == 'td') {
706 $s .= ' class="valigntop" width="14"';
707 }
708 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
709 }
710 // Use another method to help avoid having a space in value in order to use this value with jquery
711 // Define label
712 if ((string) $text != '') {
713 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
714 }
715 // Define value if value is after
716 if ($direction > 0) {
717 $s .= '<' . $tag . $paramfortooltipimg;
718 if ($tag == 'td') {
719 $s .= ' class="valignmiddle" width="14"';
720 }
721 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
722 }
723 if (empty($notabs)) {
724 $s .= '</tr></table>';
725 } elseif ($notabs == 2) {
726 $s .= '</div>';
727 }
728
729 return $s;
730 }
731
746 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
747 {
748 global $conf, $langs;
749
750 //For backwards compatibility
751 if ($type == '0') {
752 $type = 'info';
753 } elseif ($type == '1') {
754 $type = 'help';
755 }
756
757 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
758 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
759 }
760
761 $alt = '';
762 if ($tooltiptrigger) {
763 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
764 }
765
766 // If info or help with no javascript, show only text
767 if (empty($conf->use_javascript_ajax)) {
768 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
769 return $text;
770 } else {
771 $alt = $htmltext;
772 $htmltext = '';
773 }
774 }
775
776 // If info or help with smartphone, show only text (tooltip hover can't works)
777 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
778 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
779 return $text;
780 }
781 }
782 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
783 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
784 //{
785 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
786 //}
787
788 $img = '';
789 if ($type == 'info') {
790 $img = img_help(0, $alt);
791 } elseif ($type == 'help') {
792 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
793 } elseif ($type == 'helpclickable') {
794 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
795 } elseif ($type == 'superadmin') {
796 $img = img_picto($alt, 'redstar');
797 } elseif ($type == 'admin') {
798 $img = img_picto($alt, 'star');
799 } elseif ($type == 'warning') {
800 $img = img_warning($alt);
801 } elseif ($type != 'none') {
802 $img = img_picto($alt, $type); // $type can be an image path
803 }
804
805 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
806 }
807
818 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
819 {
820 global $conf, $langs, $hookmanager;
821
822 $disabled = 0;
823 $ret = '<div class="centpercent center">';
824 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
825
826 // 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.
827 $parameters = array();
828 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
829 // check if there is a mass action
830 if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
831 return;
832 }
833 if (empty($reshook)) {
834 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
835 foreach ($arrayofaction as $code => $label) {
836 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
837 }
838 }
839 $ret .= $hookmanager->resPrint;
840
841 $ret .= '</select>';
842
843 if (empty($conf->dol_optimize_smallscreen)) {
844 $ret .= ajax_combobox('.' . $name . 'select');
845 }
846
847 // 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
848 $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.
849 $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")) . '">';
850 $ret .= '</div>';
851
852 if (!empty($conf->use_javascript_ajax)) {
853 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
854 <script nonce="' . getNonce() . '">
855 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 */
856 {
857 atleastoneselected=0;
858 jQuery("."+cssclass).each(function( index ) {
859 /* console.log( index + ": " + $( this ).text() ); */
860 if ($(this).is(\':checked\')) atleastoneselected++;
861 });
862
863 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
864
865 if (atleastoneselected || ' . $alwaysvisible . ')
866 {
867 jQuery("."+name).show();
868 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
869 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
870 }
871 else
872 {
873 jQuery("."+name).hide();
874 jQuery("."+name+"other").hide();
875 }
876 }
877
878 jQuery(document).ready(function () {
879 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
880 jQuery(".' . $cssclass . '").click(function() {
881 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
882 });
883 jQuery(".' . $name . 'select").change(function() {
884 var massaction = $( this ).val();
885 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
886 if (massaction == "builddoc")
887 {
888 urlform = urlform + "#show_files";
889 }
890 $( this ).closest("form").attr("action", urlform);
891 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
892 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
893 if ($(this).val() != \'0\')
894 {
895 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
896 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
897 jQuery(".' . $name . '"+massaction).show();
898 }
899 else
900 {
901 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
902 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
903 }
904 });
905 });
906 </script>
907 ';
908 }
909
910 return $ret;
911 }
912
913 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
914
931 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)
932 {
933 // phpcs:enable
934 global $conf, $langs, $mysoc;
935
936 $langs->load("dict");
937
938 $out = '';
939 $countryArray = array();
940 $favorite = array();
941 $label = array();
942 $atleastonefavorite = 0;
943
944 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
945 $sql .= " FROM " . $this->db->prefix() . "c_country";
946 $sql .= " WHERE active > 0";
947 //$sql.= " ORDER BY code ASC";
948
949 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
950 $resql = $this->db->query($sql);
951 if ($resql) {
952 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
953 $num = $this->db->num_rows($resql);
954 $i = 0;
955 if ($num) {
956 while ($i < $num) {
957 $obj = $this->db->fetch_object($resql);
958
959 $countryArray[$i]['rowid'] = $obj->rowid;
960 $countryArray[$i]['code_iso'] = $obj->code_iso;
961 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
962 $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 : ''));
963 $countryArray[$i]['favorite'] = $obj->favorite;
964 $countryArray[$i]['eec'] = $obj->eec;
965 $favorite[$i] = $obj->favorite;
966 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
967 $i++;
968 }
969
970 if (empty($disablefavorites)) {
971 $array1_sort_order = SORT_DESC;
972 $array2_sort_order = SORT_ASC;
973 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
974 } else {
975 $countryArray = dol_sort_array($countryArray, 'label');
976 }
977
978 if ($showempty) {
979 if (is_numeric($showempty)) {
980 $out .= '<option value="">&nbsp;</option>' . "\n";
981 } else {
982 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
983 }
984 }
985
986 if ($addspecialentries) { // Add dedicated entries for groups of countries
987 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
988 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
989 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
990 if ($mysoc->isInEEC()) {
991 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
992 }
993 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
994 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
995 }
996
997 foreach ($countryArray as $row) {
998 //if (empty($showempty) && empty($row['rowid'])) continue;
999 if (empty($row['rowid'])) {
1000 continue;
1001 }
1002 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1003 continue; // exclude some countries
1004 }
1005
1006 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1007 $atleastonefavorite++;
1008 }
1009 if (empty($row['favorite']) && $atleastonefavorite) {
1010 $atleastonefavorite = 0;
1011 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1012 }
1013
1014 $labeltoshow = '';
1015 if ($row['label']) {
1016 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1017 } else {
1018 $labeltoshow .= '&nbsp;';
1019 }
1020 if ($row['code_iso']) {
1021 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1022 if (empty($hideflags)) {
1023 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1024 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1025 }
1026 }
1027
1028 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1029 $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']) . '">';
1030 } else {
1031 $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']) . '">';
1032 }
1033 $out .= $labeltoshow;
1034 $out .= '</option>' . "\n";
1035 }
1036 }
1037 $out .= '</select>';
1038 } else {
1039 dol_print_error($this->db);
1040 }
1041
1042 // Make select dynamic
1043 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1044 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1045
1046 return $out;
1047 }
1048
1049 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1050
1064 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1065 {
1066 // phpcs:enable
1067 global $conf, $langs;
1068
1069 $langs->load("dict");
1070
1071 $out = '';
1072 $moreattrib = '';
1073 $incotermArray = array();
1074
1075 $sql = "SELECT rowid, code";
1076 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1077 $sql .= " WHERE active > 0";
1078 $sql .= " ORDER BY code ASC";
1079
1080 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1081 $resql = $this->db->query($sql);
1082 if ($resql) {
1083 if ($conf->use_javascript_ajax && !$forcecombo) {
1084 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1085 $out .= ajax_combobox($htmlname, $events);
1086 }
1087
1088 if (!empty($page)) {
1089 $out .= '<form method="post" action="' . $page . '">';
1090 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1091 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1092 }
1093
1094 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1095 $out .= '<option value="0">&nbsp;</option>';
1096 $num = $this->db->num_rows($resql);
1097 $i = 0;
1098 if ($num) {
1099 while ($i < $num) {
1100 $obj = $this->db->fetch_object($resql);
1101 $incotermArray[$i]['rowid'] = $obj->rowid;
1102 $incotermArray[$i]['code'] = $obj->code;
1103 $i++;
1104 }
1105
1106 foreach ($incotermArray as $row) {
1107 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1108 $out .= '<option value="' . $row['rowid'] . '" selected>';
1109 } else {
1110 $out .= '<option value="' . $row['rowid'] . '">';
1111 }
1112
1113 if ($row['code']) {
1114 $out .= $row['code'];
1115 }
1116
1117 $out .= '</option>';
1118 }
1119 }
1120 $out .= '</select>';
1121
1122 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1123 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1124 $moreattrib .= ' autocomplete="off"';
1125 }
1126 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1127
1128 if (!empty($page)) {
1129 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1130 }
1131 } else {
1132 dol_print_error($this->db);
1133 }
1134
1135 return $out;
1136 }
1137
1138 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1139
1151 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
1152 {
1153 // phpcs:enable
1154 global $langs, $conf;
1155
1156 // If product & services are enabled or both disabled.
1157 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1158 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1159 if (empty($hidetext)) {
1160 print $langs->trans("Type") . ': ';
1161 }
1162 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1163 if ($showempty) {
1164 print '<option value="-1"';
1165 if ($selected == -1) {
1166 print ' selected';
1167 }
1168 print '>&nbsp;</option>';
1169 }
1170
1171 print '<option value="0"';
1172 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1173 print ' selected';
1174 }
1175 print '>' . $langs->trans("Product");
1176
1177 print '<option value="1"';
1178 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1179 print ' selected';
1180 }
1181 print '>' . $langs->trans("Service");
1182
1183 print '</select>';
1184 print ajax_combobox('select_' . $htmlname);
1185 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1186 }
1187 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1188 print $langs->trans("Service");
1189 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1190 }
1191 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1192 print $langs->trans("Product");
1193 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1194 }
1195 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1196 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
1197 }
1198 }
1199
1200 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1201
1207 public function load_cache_types_fees()
1208 {
1209 // phpcs:enable
1210 global $langs;
1211
1212 $num = count($this->cache_types_fees);
1213 if ($num > 0) {
1214 return 0; // Cache already loaded
1215 }
1216
1217 dol_syslog(__METHOD__, LOG_DEBUG);
1218
1219 $langs->load("trips");
1220
1221 $sql = "SELECT c.code, c.label";
1222 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1223 $sql .= " WHERE active > 0";
1224
1225 $resql = $this->db->query($sql);
1226 if ($resql) {
1227 $num = $this->db->num_rows($resql);
1228 $i = 0;
1229
1230 while ($i < $num) {
1231 $obj = $this->db->fetch_object($resql);
1232
1233 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1234 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1235 $this->cache_types_fees[$obj->code] = $label;
1236 $i++;
1237 }
1238
1239 asort($this->cache_types_fees);
1240
1241 return $num;
1242 } else {
1243 dol_print_error($this->db);
1244 return -1;
1245 }
1246 }
1247
1248 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1249
1258 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1259 {
1260 // phpcs:enable
1261 global $user, $langs;
1262
1263 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1264
1265 $this->load_cache_types_fees();
1266
1267 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1268 if ($showempty) {
1269 print '<option value="-1"';
1270 if ($selected == -1) {
1271 print ' selected';
1272 }
1273 print '>&nbsp;</option>';
1274 }
1275
1276 foreach ($this->cache_types_fees as $key => $value) {
1277 print '<option value="' . $key . '"';
1278 if ($key == $selected) {
1279 print ' selected';
1280 }
1281 print '>';
1282 print $value;
1283 print '</option>';
1284 }
1285
1286 print '</select>';
1287 if ($user->admin) {
1288 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1289 }
1290 }
1291
1292
1293 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1294
1316 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)
1317 {
1318 // phpcs:enable
1319 global $conf, $user, $langs;
1320
1321 $out = '';
1322
1323 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo) {
1324 if (is_null($ajaxoptions)) {
1325 $ajaxoptions = array();
1326 }
1327
1328 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1329
1330 // No immediate load of all database
1331 $placeholder = '';
1332 if ($selected && empty($selected_input_value)) {
1333 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1334 $societetmp = new Societe($this->db);
1335 $societetmp->fetch($selected);
1336 $selected_input_value = $societetmp->name;
1337 unset($societetmp);
1338 }
1339
1340 // mode 1
1341 $urloption = 'htmlname=' . urlencode(str_replace('.', '_', $htmlname)) . '&outjson=1&filter=' . urlencode($filter) . (empty($excludeids) ? '' : '&excludeids=' . join(',', $excludeids)) . ($showtype ? '&showtype=' . urlencode($showtype) : '') . ($showcode ? '&showcode=' . urlencode($showcode) : '');
1342
1343 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1344 if (empty($hidelabel)) {
1345 print $langs->trans("RefOrLabel") . ' : ';
1346 } elseif ($hidelabel > 1) {
1347 $placeholder = $langs->trans("RefOrLabel");
1348 if ($hidelabel == 2) {
1349 $out .= img_picto($langs->trans("Search"), 'search');
1350 }
1351 }
1352 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
1353 if ($hidelabel == 3) {
1354 $out .= img_picto($langs->trans("Search"), 'search');
1355 }
1356
1357 $out .= ajax_event($htmlname, $events);
1358
1359 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1360 } else {
1361 // Immediate load of all database
1362 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1363 }
1364
1365 return $out;
1366 }
1367
1368 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1369
1393 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)
1394 {
1395 // phpcs:enable
1396 global $conf, $user, $langs;
1397 global $hookmanager;
1398
1399 $out = '';
1400 $num = 0;
1401 $outarray = array();
1402
1403 if ($selected === '') {
1404 $selected = array();
1405 } elseif (!is_array($selected)) {
1406 $selected = array($selected);
1407 }
1408
1409 // Clean $filter that may contains sql conditions so sql code
1410 if (function_exists('testSqlAndScriptInject')) {
1411 if (testSqlAndScriptInject($filter, 3) > 0) {
1412 $filter = '';
1413 return 'SQLInjectionTryDetected';
1414 }
1415 }
1416
1417 if (preg_match('/[\‍(\‍)]/', $filter)) {
1418 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1419 $errormsg = '';
1420 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1421
1422 // Redo clean $filter that may contains sql conditions so sql code
1423 if (function_exists('testSqlAndScriptInject')) {
1424 if (testSqlAndScriptInject($filter, 3) > 0) {
1425 $filter = '';
1426 return 'SQLInjectionTryDetected';
1427 }
1428 }
1429 } else {
1430 // If not, we do nothing. We already no that there is no parenthesis
1431 // TODO Disallow this case in a future.
1432 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1433 }
1434
1435 // We search companies
1436 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1437 if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1438 $sql .= ", s.address, s.zip, s.town";
1439 $sql .= ", dictp.code as country_code";
1440 }
1441 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1442 if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1443 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1444 }
1445 if (empty($user->rights->societe->client->voir) && !$user->socid) {
1446 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1447 }
1448 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1449 if (!empty($user->socid)) {
1450 $sql .= " AND s.rowid = " . ((int) $user->socid);
1451 }
1452 if ($filter) {
1453 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1454 // if not, by testSqlAndScriptInject() only.
1455 $sql .= " AND (" . $filter . ")";
1456 }
1457 if (empty($user->rights->societe->client->voir) && !$user->socid) {
1458 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1459 }
1460 if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) {
1461 $sql .= " AND s.status <> 0";
1462 }
1463 if (!empty($excludeids)) {
1464 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(join(',', $excludeids)) . ")";
1465 }
1466 // Add where from hooks
1467 $parameters = array();
1468 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1469 $sql .= $hookmanager->resPrint;
1470 // Add criteria
1471 if ($filterkey && $filterkey != '') {
1472 $sql .= " AND (";
1473 $prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1474 // For natural search
1475 $scrit = explode(' ', $filterkey);
1476 $i = 0;
1477 if (count($scrit) > 1) {
1478 $sql .= "(";
1479 }
1480 foreach ($scrit as $crit) {
1481 if ($i > 0) {
1482 $sql .= " AND ";
1483 }
1484 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1485 $i++;
1486 }
1487 if (count($scrit) > 1) {
1488 $sql .= ")";
1489 }
1490 if (isModEnabled('barcode')) {
1491 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1492 }
1493 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1494 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1495 $sql .= ")";
1496 }
1497 $sql .= $this->db->order("nom", "ASC");
1498 $sql .= $this->db->plimit($limit, 0);
1499
1500 // Build output string
1501 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1502 $resql = $this->db->query($sql);
1503 if ($resql) {
1504 if (!$forcecombo) {
1505 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1506 $out .= ajax_combobox($htmlname, $events, getDolGlobalString("COMPANY_USE_SEARCH_TO_SELECT"));
1507 }
1508
1509 // Construct $out and $outarray
1510 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1511
1512 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1513 if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) {
1514 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1515 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1516 if ($showempty && !is_numeric($showempty)) {
1517 $textifempty = $langs->trans($showempty);
1518 } else {
1519 $textifempty .= $langs->trans("All");
1520 }
1521 }
1522 if ($showempty) {
1523 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1524 }
1525
1526 $companytemp = new Societe($this->db);
1527
1528 $num = $this->db->num_rows($resql);
1529 $i = 0;
1530 if ($num) {
1531 while ($i < $num) {
1532 $obj = $this->db->fetch_object($resql);
1533 $label = '';
1534 if ($showcode || !empty($conf->global->SOCIETE_ADD_REF_IN_LIST)) {
1535 if (($obj->client) && (!empty($obj->code_client))) {
1536 $label = $obj->code_client . ' - ';
1537 }
1538 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1539 $label .= $obj->code_fournisseur . ' - ';
1540 }
1541 $label .= ' ' . $obj->name;
1542 } else {
1543 $label = $obj->name;
1544 }
1545
1546 if (!empty($obj->name_alias)) {
1547 $label .= ' (' . $obj->name_alias . ')';
1548 }
1549
1550 if (!empty($conf->global->SOCIETE_SHOW_VAT_IN_LIST) && !empty($obj->tva_intra)) {
1551 $label .= ' - '.$obj->tva_intra;
1552 }
1553
1554 $labelhtml = $label;
1555
1556 if ($showtype) {
1557 $companytemp->id = $obj->rowid;
1558 $companytemp->client = $obj->client;
1559 $companytemp->fournisseur = $obj->fournisseur;
1560 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1561 if ($tmptype) {
1562 $labelhtml .= ' ' . $tmptype;
1563 }
1564
1565 if ($obj->client || $obj->fournisseur) {
1566 $label .= ' (';
1567 }
1568 if ($obj->client == 1 || $obj->client == 3) {
1569 $label .= $langs->trans("Customer");
1570 }
1571 if ($obj->client == 2 || $obj->client == 3) {
1572 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1573 }
1574 if ($obj->fournisseur) {
1575 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1576 }
1577 if ($obj->client || $obj->fournisseur) {
1578 $label .= ')';
1579 }
1580 }
1581
1582 if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1583 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1584 if (!empty($obj->country_code)) {
1585 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1586 }
1587 $label .= $s;
1588 $labelhtml .= $s;
1589 }
1590
1591 if (empty($outputmode)) {
1592 if (in_array($obj->rowid, $selected)) {
1593 $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>';
1594 } else {
1595 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1596 }
1597 } else {
1598 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1599 }
1600
1601 $i++;
1602 if (($i % 10) == 0) {
1603 $out .= "\n";
1604 }
1605 }
1606 }
1607 $out .= '</select>' . "\n";
1608 } else {
1609 dol_print_error($this->db);
1610 }
1611
1612 $this->result = array('nbofthirdparties' => $num);
1613
1614 if ($outputmode) {
1615 return $outarray;
1616 }
1617 return $out;
1618 }
1619
1620
1621 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1622
1633 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1634 {
1635 // phpcs:enable
1636 global $langs, $conf;
1637
1638 // On recherche les remises
1639 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1640 $sql .= " re.description, re.fk_facture_source";
1641 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
1642 $sql .= " WHERE re.fk_soc = " . (int) $socid;
1643 $sql .= " AND re.entity = " . $conf->entity;
1644 if ($filter) {
1645 $sql .= " AND " . $filter;
1646 }
1647 $sql .= " ORDER BY re.description ASC";
1648
1649 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
1650 $resql = $this->db->query($sql);
1651 if ($resql) {
1652 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
1653 $num = $this->db->num_rows($resql);
1654
1655 $qualifiedlines = $num;
1656
1657 $i = 0;
1658 if ($num) {
1659 print '<option value="0">&nbsp;</option>';
1660 while ($i < $num) {
1661 $obj = $this->db->fetch_object($resql);
1662 $desc = dol_trunc($obj->description, 40);
1663 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
1664 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
1665 }
1666 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
1667 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
1668 }
1669 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
1670 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
1671 }
1672 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
1673 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
1674 }
1675
1676 $selectstring = '';
1677 if ($selected > 0 && $selected == $obj->rowid) {
1678 $selectstring = ' selected';
1679 }
1680
1681 $disabled = '';
1682 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
1683 $qualifiedlines--;
1684 $disabled = ' disabled';
1685 }
1686
1687 if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source)) {
1688 $tmpfac = new Facture($this->db);
1689 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
1690 $desc = $desc . ' - ' . $tmpfac->ref;
1691 }
1692 }
1693
1694 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
1695 $i++;
1696 }
1697 }
1698 print '</select>';
1699 print ajax_combobox('select_' . $htmlname);
1700
1701 return $qualifiedlines;
1702 } else {
1703 dol_print_error($this->db);
1704 return -1;
1705 }
1706 }
1707
1708 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1709
1730 public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '')
1731 {
1732 // phpcs:enable
1733 print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1734 return $this->num;
1735 }
1736
1761 public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0)
1762 {
1763 global $conf, $langs, $hookmanager, $action;
1764
1765 $langs->load('companies');
1766
1767 if (empty($htmlid)) {
1768 $htmlid = $htmlname;
1769 }
1770 $num = 0;
1771
1772 if ($selected === '') {
1773 $selected = array();
1774 } elseif (!is_array($selected)) {
1775 $selected = array($selected);
1776 }
1777 $out = '';
1778
1779 if (!is_object($hookmanager)) {
1780 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1781 $hookmanager = new HookManager($this->db);
1782 }
1783
1784 // We search third parties
1785 $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";
1786 if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1787 $sql .= ", s.nom as company, s.town AS company_town";
1788 }
1789 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1790 if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1791 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1792 }
1793 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1794 if ($socid > 0 || $socid == -1) {
1795 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1796 }
1797 if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) {
1798 $sql .= " AND sp.statut <> 0";
1799 }
1800 // Add where from hooks
1801 $parameters = array();
1802 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1803 $sql .= $hookmanager->resPrint;
1804 $sql .= " ORDER BY sp.lastname ASC";
1805
1806 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1807 $resql = $this->db->query($sql);
1808 if ($resql) {
1809 $num = $this->db->num_rows($resql);
1810
1811 if ($htmlname != 'none' && !$options_only) {
1812 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1813 }
1814
1815 if ($showempty && !is_numeric($showempty)) {
1816 $textforempty = $showempty;
1817 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1818 } else {
1819 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1820 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1821 }
1822 if ($showempty == 2) {
1823 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1824 }
1825 }
1826
1827 $i = 0;
1828 if ($num) {
1829 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1830 $contactstatic = new Contact($this->db);
1831
1832 while ($i < $num) {
1833 $obj = $this->db->fetch_object($resql);
1834
1835 // Set email (or phones) and town extended infos
1836 $extendedInfos = '';
1837 if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1838 $extendedInfos = array();
1839 $email = trim($obj->email);
1840 if (!empty($email)) {
1841 $extendedInfos[] = $email;
1842 } else {
1843 $phone = trim($obj->phone);
1844 $phone_perso = trim($obj->phone_perso);
1845 $phone_mobile = trim($obj->phone_mobile);
1846 if (!empty($phone)) {
1847 $extendedInfos[] = $phone;
1848 }
1849 if (!empty($phone_perso)) {
1850 $extendedInfos[] = $phone_perso;
1851 }
1852 if (!empty($phone_mobile)) {
1853 $extendedInfos[] = $phone_mobile;
1854 }
1855 }
1856 $contact_town = trim($obj->contact_town);
1857 $company_town = trim($obj->company_town);
1858 if (!empty($contact_town)) {
1859 $extendedInfos[] = $contact_town;
1860 } elseif (!empty($company_town)) {
1861 $extendedInfos[] = $company_town;
1862 }
1863 $extendedInfos = implode(' - ', $extendedInfos);
1864 if (!empty($extendedInfos)) {
1865 $extendedInfos = ' - ' . $extendedInfos;
1866 }
1867 }
1868
1869 $contactstatic->id = $obj->rowid;
1870 $contactstatic->lastname = $obj->lastname;
1871 $contactstatic->firstname = $obj->firstname;
1872 if ($obj->statut == 1) {
1873 if ($htmlname != 'none') {
1874 $disabled = 0;
1875 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1876 $disabled = 1;
1877 }
1878 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1879 $disabled = 1;
1880 }
1881 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1882 $out .= '<option value="' . $obj->rowid . '"';
1883 if ($disabled) {
1884 $out .= ' disabled';
1885 }
1886 $out .= ' selected>';
1887 $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1888 if ($showfunction && $obj->poste) {
1889 $out .= ' (' . $obj->poste . ')';
1890 }
1891 if (($showsoc > 0) && $obj->company) {
1892 $out .= ' - (' . $obj->company . ')';
1893 }
1894 $out .= '</option>';
1895 } else {
1896 $out .= '<option value="' . $obj->rowid . '"';
1897 if ($disabled) {
1898 $out .= ' disabled';
1899 }
1900 $out .= '>';
1901 $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1902 if ($showfunction && $obj->poste) {
1903 $out .= ' (' . $obj->poste . ')';
1904 }
1905 if (($showsoc > 0) && $obj->company) {
1906 $out .= ' - (' . $obj->company . ')';
1907 }
1908 $out .= '</option>';
1909 }
1910 } else {
1911 if (in_array($obj->rowid, $selected)) {
1912 $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1913 if ($showfunction && $obj->poste) {
1914 $out .= ' (' . $obj->poste . ')';
1915 }
1916 if (($showsoc > 0) && $obj->company) {
1917 $out .= ' - (' . $obj->company . ')';
1918 }
1919 }
1920 }
1921 }
1922 $i++;
1923 }
1924 } else {
1925 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1926 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1927 $out .= $labeltoshow;
1928 $out .= '</option>';
1929 }
1930
1931 $parameters = array(
1932 'socid' => $socid,
1933 'htmlname' => $htmlname,
1934 'resql' => $resql,
1935 'out' => &$out,
1936 'showfunction' => $showfunction,
1937 'showsoc' => $showsoc,
1938 );
1939
1940 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1941
1942 if ($htmlname != 'none' && !$options_only) {
1943 $out .= '</select>';
1944 }
1945
1946 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1947 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1948 $out .= ajax_combobox($htmlid, $events, getDolGlobalString("CONTACT_USE_SEARCH_TO_SELECT"));
1949 }
1950
1951 $this->num = $num;
1952 return $out;
1953 } else {
1954 dol_print_error($this->db);
1955 return -1;
1956 }
1957 }
1958
1959 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1960
1976 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1977 {
1978 // phpcs:enable
1979 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1980 }
1981
1982 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1983
2008 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2009 {
2010 // phpcs:enable
2011 global $conf, $user, $langs, $hookmanager;
2012 global $action;
2013
2014 // If no preselected user defined, we take current user
2015 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) {
2016 $selected = $user->id;
2017 }
2018
2019 if ($selected === '') {
2020 $selected = array();
2021 } elseif (!is_array($selected)) {
2022 $selected = array($selected);
2023 }
2024
2025 $excludeUsers = null;
2026 $includeUsers = null;
2027
2028 // Exclude some users
2029 if (is_array($exclude)) {
2030 $excludeUsers = implode(",", $exclude);
2031 }
2032 // Include some uses
2033 if (is_array($include)) {
2034 $includeUsers = implode(",", $include);
2035 } elseif ($include == 'hierarchy') {
2036 // Build list includeUsers to have only hierarchy
2037 $includeUsers = implode(",", $user->getAllChildIds(0));
2038 } elseif ($include == 'hierarchyme') {
2039 // Build list includeUsers to have only hierarchy and current user
2040 $includeUsers = implode(",", $user->getAllChildIds(1));
2041 }
2042
2043 $out = '';
2044 $outarray = array();
2045 $outarray2 = array();
2046
2047 // Forge request to select users
2048 $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
2049 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
2050 $sql .= ", e.label";
2051 }
2052 $sql .= " FROM " . $this->db->prefix() . "user as u";
2053 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
2054 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2055 if ($force_entity) {
2056 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2057 } else {
2058 $sql .= " WHERE u.entity IS NOT NULL";
2059 }
2060 } else {
2061 if (isModEnabled('multicompany') && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2062 $sql .= " LEFT JOIN " . $this->db->prefix() . "usergroup_user as ug";
2063 $sql .= " ON ug.fk_user = u.rowid";
2064 $sql .= " WHERE ug.entity = " . (int) $conf->entity;
2065 } else {
2066 $sql .= " WHERE u.entity IN (0, " . ((int) $conf->entity) . ")";
2067 }
2068 }
2069 if (!empty($user->socid)) {
2070 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2071 }
2072 if (is_array($exclude) && $excludeUsers) {
2073 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2074 }
2075 if ($includeUsers) {
2076 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2077 }
2078 if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $notdisabled) {
2079 $sql .= " AND u.statut <> 0";
2080 }
2081 if (!empty($morefilter)) {
2082 $sql .= " " . $morefilter;
2083 }
2084
2085 //Add hook to filter on user (for exemple on usergroup define in custom modules)
2086 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2087 if (!empty($reshook)) {
2088 $sql .= $hookmanager->resPrint;
2089 }
2090
2091 if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2092 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2093 } else {
2094 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2095 }
2096
2097 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2098
2099 $resql = $this->db->query($sql);
2100 if ($resql) {
2101 $num = $this->db->num_rows($resql);
2102 $i = 0;
2103 if ($num) {
2104 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2105 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2106 if ($show_empty && !$multiple) {
2107 $textforempty = ' ';
2108 if (!empty($conf->use_javascript_ajax)) {
2109 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2110 }
2111 if (!is_numeric($show_empty)) {
2112 $textforempty = $show_empty;
2113 }
2114 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2115 }
2116 if ($show_every) {
2117 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2118 }
2119
2120 $userstatic = new User($this->db);
2121
2122 while ($i < $num) {
2123 $obj = $this->db->fetch_object($resql);
2124
2125 $userstatic->id = $obj->rowid;
2126 $userstatic->lastname = $obj->lastname;
2127 $userstatic->firstname = $obj->firstname;
2128 $userstatic->photo = $obj->photo;
2129 $userstatic->statut = $obj->status;
2130 $userstatic->entity = $obj->entity;
2131 $userstatic->admin = $obj->admin;
2132
2133 $disableline = '';
2134 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2135 $disableline = ($enableonlytext ? $enableonlytext : '1');
2136 }
2137
2138 $labeltoshow = '';
2139 $labeltoshowhtml = '';
2140
2141 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2142 $fullNameMode = 0;
2143 if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {
2144 $fullNameMode = 1; //Firstname+lastname
2145 }
2146 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2147 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2148 if (empty($obj->firstname) && empty($obj->lastname)) {
2149 $labeltoshow .= $obj->login;
2150 $labeltoshowhtml .= $obj->login;
2151 }
2152
2153 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2154 $moreinfo = '';
2155 $moreinfohtml = '';
2156 if (!empty($conf->global->MAIN_SHOW_LOGIN)) {
2157 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2158 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2159 $moreinfo .= $obj->login;
2160 $moreinfohtml .= $obj->login;
2161 }
2162 if ($showstatus >= 0) {
2163 if ($obj->status == 1 && $showstatus == 1) {
2164 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2165 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2166 }
2167 if ($obj->status == 0 && $showstatus == 1) {
2168 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2169 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2170 }
2171 }
2172 if (isModEnabled('multicompany') && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity) {
2173 if (!$obj->entity) {
2174 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2175 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2176 } else {
2177 if ($obj->entity != $conf->entity) {
2178 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2179 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2180 }
2181 }
2182 }
2183 $moreinfo .= ($moreinfo ? ')' : '');
2184 $moreinfohtml .= ($moreinfohtml ? ')</span>' : '');
2185 if ($disableline && $disableline != '1') {
2186 // Add text from $enableonlytext parameter
2187 $moreinfo .= ' - ' . $disableline;
2188 $moreinfohtml .= ' - ' . $disableline;
2189 }
2190 $labeltoshow .= $moreinfo;
2191 $labeltoshowhtml .= $moreinfohtml;
2192
2193 $out .= '<option value="' . $obj->rowid . '"';
2194 if ($disableline) {
2195 $out .= ' disabled';
2196 }
2197 if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
2198 $out .= ' selected';
2199 }
2200 $out .= ' data-html="';
2201 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2202 if ($showstatus >= 0 && $obj->status == 0) {
2203 $outhtml .= '<strike class="opacitymediumxxx">';
2204 }
2205 $outhtml .= $labeltoshowhtml;
2206 if ($showstatus >= 0 && $obj->status == 0) {
2207 $outhtml .= '</strike>';
2208 }
2209 $out .= dol_escape_htmltag($outhtml);
2210 $out .= '">';
2211 $out .= $labeltoshow;
2212 $out .= '</option>';
2213
2214 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2215 $outarray2[$userstatic->id] = array(
2216 'id'=>$userstatic->id,
2217 'label'=>$labeltoshow,
2218 'labelhtml'=>$labeltoshowhtml,
2219 'color'=>'',
2220 'picto'=>''
2221 );
2222
2223 $i++;
2224 }
2225 } else {
2226 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2227 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2228 }
2229 $out .= '</select>';
2230
2231 if ($num && !$forcecombo) {
2232 // Enhance with select2
2233 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2234 $out .= ajax_combobox($htmlname);
2235 }
2236 } else {
2237 dol_print_error($this->db);
2238 }
2239
2240 if ($outputmode == 2) {
2241 return $outarray2;
2242 } elseif ($outputmode) {
2243 return $outarray;
2244 }
2245
2246 return $out;
2247 }
2248
2249
2250 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2251
2274 public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array())
2275 {
2276 // phpcs:enable
2277 global $conf, $user, $langs;
2278
2279 $userstatic = new User($this->db);
2280 $out = '';
2281
2282
2283 $assignedtouser = array();
2284 if (!empty($_SESSION['assignedtouser'])) {
2285 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2286 }
2287 $nbassignetouser = count($assignedtouser);
2288
2289 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2290 if ($nbassignetouser) {
2291 $out .= '<ul class="attendees">';
2292 }
2293 $i = 0;
2294 $ownerid = 0;
2295 foreach ($assignedtouser as $key => $value) {
2296 if ($value['id'] == $ownerid) {
2297 continue;
2298 }
2299
2300 $out .= '<li>';
2301 $userstatic->fetch($value['id']);
2302 $out .= $userstatic->getNomUrl(-1);
2303 if ($i == 0) {
2304 $ownerid = $value['id'];
2305 $out .= ' (' . $langs->trans("Owner") . ')';
2306 }
2307 if ($nbassignetouser > 1 && $action != 'view') {
2308 $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 . '">';
2309 }
2310 // Show my availability
2311 if ($showproperties) {
2312 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2313 $out .= '<div class="myavailability inline-block">';
2314 $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>';
2315 $out .= '</div>';
2316 }
2317 }
2318 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2319 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2320
2321 $out .= '</li>';
2322 $i++;
2323 }
2324 if ($nbassignetouser) {
2325 $out .= '</ul>';
2326 }
2327
2328 // Method with no ajax
2329 if ($action != 'view') {
2330 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2331 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2332 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2333 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2334 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2335 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2336 $out .= '});';
2337 $out .= '})</script>';
2338 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2339 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2340 $out .= '<br>';
2341 }
2342
2343 return $out;
2344 }
2345
2346
2347 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2348
2376 public function select_produits($selected = '', $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)
2377 {
2378 // phpcs:enable
2379 global $langs, $conf;
2380
2381 $out = '';
2382
2383 // check parameters
2384 $price_level = (!empty($price_level) ? $price_level : 0);
2385 if (is_null($ajaxoptions)) {
2386 $ajaxoptions = array();
2387 }
2388
2389 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2390 if (isModEnabled("product") && !isModEnabled('service')) {
2391 $filtertype = '0';
2392 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2393 $filtertype = '1';
2394 }
2395 }
2396
2397 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2398 $placeholder = '';
2399
2400 if ($selected && empty($selected_input_value)) {
2401 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2402 $producttmpselect = new Product($this->db);
2403 $producttmpselect->fetch($selected);
2404 $selected_input_value = $producttmpselect->ref;
2405 unset($producttmpselect);
2406 }
2407 // handle case where product or service module is disabled + no filter specified
2408 if ($filtertype == '') {
2409 if (!isModEnabled('product')) { // when product module is disabled, show services only
2410 $filtertype = 1;
2411 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2412 $filtertype = 0;
2413 }
2414 }
2415 // mode=1 means customers products
2416 $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;
2417 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2418
2419 if (isModEnabled('variants') && is_array($selected_combinations)) {
2420 // Code to automatically insert with javascript the select of attributes under the select of product
2421 // when a parent of variant has been selected.
2422 $out .= '
2423 <!-- script to auto show attributes select tags if a variant was selected -->
2424 <script nonce="' . getNonce() . '">
2425 // auto show attributes fields
2426 selected = ' . json_encode($selected_combinations) . ';
2427 combvalues = {};
2428
2429 jQuery(document).ready(function () {
2430
2431 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2432 if (jQuery(this).val() == \'free\') {
2433 jQuery(\'div#attributes_box\').empty();
2434 }
2435 });
2436
2437 jQuery("input#' . $htmlname . '").change(function () {
2438
2439 if (!jQuery(this).val()) {
2440 jQuery(\'div#attributes_box\').empty();
2441 return;
2442 }
2443
2444 console.log("A change has started. We get variants fields to inject html select");
2445
2446 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2447 id: jQuery(this).val()
2448 }, function (data) {
2449 jQuery(\'div#attributes_box\').empty();
2450
2451 jQuery.each(data, function (key, val) {
2452
2453 combvalues[val.id] = val.values;
2454
2455 var span = jQuery(document.createElement(\'div\')).css({
2456 \'display\': \'table-row\'
2457 });
2458
2459 span.append(
2460 jQuery(document.createElement(\'div\')).text(val.label).css({
2461 \'font-weight\': \'bold\',
2462 \'display\': \'table-cell\'
2463 })
2464 );
2465
2466 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2467 \'margin-left\': \'15px\',
2468 \'white-space\': \'pre\'
2469 }).append(
2470 jQuery(document.createElement(\'option\')).val(\'\')
2471 );
2472
2473 jQuery.each(combvalues[val.id], function (key, val) {
2474 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2475
2476 if (selected[val.fk_product_attribute] == val.id) {
2477 tag.attr(\'selected\', \'selected\');
2478 }
2479
2480 html.append(tag);
2481 });
2482
2483 span.append(html);
2484 jQuery(\'div#attributes_box\').append(span);
2485 });
2486 })
2487 });
2488
2489 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2490 });
2491 </script>
2492 ';
2493 }
2494
2495 if (empty($hidelabel)) {
2496 $out .= $langs->trans("RefOrLabel") . ' : ';
2497 } elseif ($hidelabel > 1) {
2498 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
2499 if ($hidelabel == 2) {
2500 $out .= img_picto($langs->trans("Search"), 'search');
2501 }
2502 }
2503 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
2504 if ($hidelabel == 3) {
2505 $out .= img_picto($langs->trans("Search"), 'search');
2506 }
2507 } else {
2508 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2509 }
2510
2511 if (empty($nooutput)) {
2512 print $out;
2513 } else {
2514 return $out;
2515 }
2516 }
2517
2518 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2519
2535 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2536 {
2537 // phpcs:enable
2538 global $conf, $user, $langs, $db;
2539
2540 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2541
2542 $error = 0;
2543 $out = '';
2544
2545 if (!$forcecombo) {
2546 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2547 $events = array();
2548 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2549 }
2550
2551 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2552
2553 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2554 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2555 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2556 if (!empty($status)) $sql .= ' AND status = ' . (int) $status;
2557 if (!empty($type)) $sql .= ' AND bomtype = ' . (int) $type;
2558 if (!empty($TProducts)) $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2559 if (!empty($limit)) $sql .= ' LIMIT ' . (int) $limit;
2560 $resql = $db->query($sql);
2561 if ($resql) {
2562 if ($showempty) {
2563 $out .= '<option value="-1"';
2564 if (empty($selected)) $out .= ' selected';
2565 $out .= '>&nbsp;</option>';
2566 }
2567 while ($obj = $db->fetch_object($resql)) {
2568 $product = new Product($db);
2569 $res = $product->fetch($obj->fk_product);
2570 $out .= '<option value="' . $obj->rowid . '"';
2571 if ($obj->rowid == $selected) $out .= 'selected';
2572 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2573 }
2574 } else {
2575 $error++;
2576 dol_print_error($db);
2577 }
2578 $out .= '</select>';
2579 if (empty($nooutput)) {
2580 print $out;
2581 } else {
2582 return $out;
2583 }
2584 }
2585
2586 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2587
2613 public function select_produits_list($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $status_purchase = -1)
2614 {
2615 // phpcs:enable
2616 global $langs, $conf;
2617 global $hookmanager;
2618
2619 $out = '';
2620 $outarray = array();
2621
2622 // Units
2623 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2624 $langs->load('other');
2625 }
2626
2627 $warehouseStatusArray = array();
2628 if (!empty($warehouseStatus)) {
2629 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2630 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2631 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2632 }
2633 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2634 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2635 }
2636 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2637 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2638 }
2639 }
2640
2641 $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";
2642 if (count($warehouseStatusArray)) {
2643 $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
2644 } else {
2645 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2646 }
2647
2648 $sql = "SELECT ";
2649
2650 // Add select from hooks
2651 $parameters = array();
2652 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2653 if (empty($reshook)) {
2654 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2655 } else {
2656 $sql .= $hookmanager->resPrint;
2657 }
2658
2659 if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2660 //Product category
2661 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2662 FROM " . $this->db->prefix() . "categorie_product
2663 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2664 LIMIT 1
2665 ) AS categorie_product_id ";
2666 }
2667
2668 //Price by customer
2669 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2670 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2671 $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';
2672 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2673 }
2674 // Units
2675 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2676 $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";
2677 $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';
2678 }
2679
2680 // Multilang : we add translation
2681 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2682 $sql .= ", pl.label as label_translated";
2683 $sql .= ", pl.description as description_translated";
2684 $selectFields .= ", label_translated";
2685 $selectFields .= ", description_translated";
2686 }
2687 // Price by quantity
2688 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2689 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2690 if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2691 $sql .= " AND price_level = " . ((int) $price_level);
2692 }
2693 $sql .= " ORDER BY date_price";
2694 $sql .= " DESC LIMIT 1) as price_rowid";
2695 $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
2696 if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2697 $sql .= " AND price_level = " . ((int) $price_level);
2698 }
2699 $sql .= " ORDER BY date_price";
2700 $sql .= " DESC LIMIT 1) as price_by_qty";
2701 $selectFields .= ", price_rowid, price_by_qty";
2702 }
2703
2704 $sql .= " FROM ".$this->db->prefix()."product as p";
2705 // Add from (left join) from hooks
2706 $parameters = array();
2707 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
2708 $sql .= $hookmanager->resPrint;
2709
2710 if (count($warehouseStatusArray)) {
2711 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
2712 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
2713 $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.
2714 }
2715
2716 // include search in supplier ref
2717 if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2718 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2719 }
2720
2721 //Price by customer
2722 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2723 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
2724 }
2725 // Units
2726 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2727 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
2728 }
2729 // Multilang : we add translation
2730 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2731 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
2732 if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) {
2733 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
2734 $soc = new Societe($this->db);
2735 $result = $soc->fetch($socid);
2736 if ($result > 0 && !empty($soc->default_lang)) {
2737 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
2738 } else {
2739 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
2740 }
2741 } else {
2742 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
2743 }
2744 }
2745
2746 if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2747 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2748 }
2749
2750 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
2751
2752 if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2753 $sql .= " AND pac.rowid IS NULL";
2754 }
2755
2756 if ($finished == 0) {
2757 $sql .= " AND p.finished = " . ((int) $finished);
2758 } elseif ($finished == 1) {
2759 $sql .= " AND p.finished = ".((int) $finished);
2760 }
2761 if ($status >= 0) {
2762 $sql .= " AND p.tosell = ".((int) $status);
2763 }
2764 if ($status_purchase >= 0) {
2765 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
2766 }
2767 // Filter by product type
2768 if (strval($filtertype) != '') {
2769 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
2770 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
2771 $sql .= " AND p.fk_product_type = 1";
2772 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2773 $sql .= " AND p.fk_product_type = 0";
2774 }
2775 // Add where from hooks
2776 $parameters = array();
2777 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
2778 $sql .= $hookmanager->resPrint;
2779 // Add criteria on ref/label
2780 if ($filterkey != '') {
2781 $sql .= ' AND (';
2782 $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2783 // For natural search
2784 $scrit = explode(' ', $filterkey);
2785 $i = 0;
2786 if (count($scrit) > 1) {
2787 $sql .= "(";
2788 }
2789 foreach ($scrit as $crit) {
2790 if ($i > 0) {
2791 $sql .= " AND ";
2792 }
2793 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2794 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2795 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2796 }
2797 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2798 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2799 }
2800 if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) {
2801 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2802 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2803 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2804 }
2805 }
2806 if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2807 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2808 }
2809 $sql .= ")";
2810 $i++;
2811 }
2812 if (count($scrit) > 1) {
2813 $sql .= ")";
2814 }
2815 if (isModEnabled('barcode')) {
2816 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
2817 }
2818 $sql .= ')';
2819 }
2820 if (count($warehouseStatusArray)) {
2821 $sql .= " GROUP BY " . $selectFields;
2822 }
2823
2824 //Sort by category
2825 if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2826 $sql .= " ORDER BY categorie_product_id ";
2827 //ASC OR DESC order
2828 ($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2829 } else {
2830 $sql .= $this->db->order("p.ref");
2831 }
2832
2833 $sql .= $this->db->plimit($limit, 0);
2834
2835 // Build output string
2836 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
2837 $result = $this->db->query($sql);
2838 if ($result) {
2839 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2840 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
2841 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
2842
2843 $num = $this->db->num_rows($result);
2844
2845 $events = null;
2846
2847 if (!$forcecombo) {
2848 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2849 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2850 }
2851
2852 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2853
2854 $textifempty = '';
2855 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2856 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2857 if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2858 if ($showempty && !is_numeric($showempty)) {
2859 $textifempty = $langs->trans($showempty);
2860 } else {
2861 $textifempty .= $langs->trans("All");
2862 }
2863 } else {
2864 if ($showempty && !is_numeric($showempty)) {
2865 $textifempty = $langs->trans($showempty);
2866 }
2867 }
2868 if ($showempty) {
2869 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
2870 }
2871
2872 $i = 0;
2873 while ($num && $i < $num) {
2874 $opt = '';
2875 $optJson = array();
2876 $objp = $this->db->fetch_object($result);
2877
2878 if ((!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->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
2879 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2880 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
2881 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
2882 $sql .= " ORDER BY quantity ASC";
2883
2884 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
2885 $result2 = $this->db->query($sql);
2886 if ($result2) {
2887 $nb_prices = $this->db->num_rows($result2);
2888 $j = 0;
2889 while ($nb_prices && $j < $nb_prices) {
2890 $objp2 = $this->db->fetch_object($result2);
2891
2892 $objp->price_by_qty_rowid = $objp2->rowid;
2893 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
2894 $objp->price_by_qty_quantity = $objp2->quantity;
2895 $objp->price_by_qty_unitprice = $objp2->unitprice;
2896 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
2897 // For backward compatibility
2898 $objp->quantity = $objp2->quantity;
2899 $objp->price = $objp2->price;
2900 $objp->unitprice = $objp2->unitprice;
2901 $objp->remise_percent = $objp2->remise_percent;
2902
2903 //$objp->tva_tx is not overwritten by $objp2 value
2904 //$objp->default_vat_code is not overwritten by $objp2 value
2905
2906 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2907
2908 $j++;
2909
2910 // Add new entry
2911 // "key" value of json key array is used by jQuery automatically as selected value
2912 // "label" value of json key array is used by jQuery automatically as text for combo box
2913 $out .= $opt;
2914 array_push($outarray, $optJson);
2915 }
2916 }
2917 } else {
2918 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
2919 $price_product = new Product($this->db);
2920 $price_product->fetch($objp->rowid, '', '', 1);
2921
2922 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
2923 $priceparser = new PriceParser($this->db);
2924 $price_result = $priceparser->parseProduct($price_product);
2925 if ($price_result >= 0) {
2926 $objp->price = $price_result;
2927 $objp->unitprice = $price_result;
2928 //Calculate the VAT
2929 $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2930 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
2931 }
2932 }
2933
2934 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2935 // Add new entry
2936 // "key" value of json key array is used by jQuery automatically as selected value
2937 // "label" value of json key array is used by jQuery automatically as text for combo box
2938 $out .= $opt;
2939 array_push($outarray, $optJson);
2940 }
2941
2942 $i++;
2943 }
2944
2945 $out .= '</select>';
2946
2947 $this->db->free($result);
2948
2949 if (empty($outputmode)) {
2950 return $out;
2951 }
2952
2953 return $outarray;
2954 } else {
2955 dol_print_error($this->db);
2956 }
2957
2958 return '';
2959 }
2960
2976 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
2977 {
2978 global $langs, $conf, $user;
2979 global $hookmanager;
2980
2981 $outkey = '';
2982 $outval = '';
2983 $outref = '';
2984 $outlabel = '';
2985 $outlabel_translated = '';
2986 $outdesc = '';
2987 $outdesc_translated = '';
2988 $outbarcode = '';
2989 $outorigin = '';
2990 $outtype = '';
2991 $outprice_ht = '';
2992 $outprice_ttc = '';
2993 $outpricebasetype = '';
2994 $outtva_tx = '';
2995 $outdefault_vat_code = '';
2996 $outqty = 1;
2997 $outdiscount = 0;
2998
2999 $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3000
3001 $label = $objp->label;
3002 if (!empty($objp->label_translated)) {
3003 $label = $objp->label_translated;
3004 }
3005 if (!empty($filterkey) && $filterkey != '') {
3006 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3007 }
3008
3009 $outkey = $objp->rowid;
3010 $outref = $objp->ref;
3011 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3012 $outlabel = $objp->label;
3013 $outdesc = $objp->description;
3014 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3015 $outlabel_translated = $objp->label_translated;
3016 $outdesc_translated = $objp->description_translated;
3017 }
3018 $outbarcode = $objp->barcode;
3019 $outorigin = $objp->fk_country;
3020 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3021
3022 $outtype = $objp->fk_product_type;
3023 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3024 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3025
3026 if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
3027 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3028 }
3029
3030 // Units
3031 $outvalUnits = '';
3032 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3033 if (!empty($objp->unit_short)) {
3034 $outvalUnits .= ' - ' . $objp->unit_short;
3035 }
3036 }
3037 if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
3038 if (!empty($objp->weight) && $objp->weight_units !== null) {
3039 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3040 $outvalUnits .= ' - ' . $unitToShow;
3041 }
3042 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3043 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3044 $outvalUnits .= ' - ' . $unitToShow;
3045 }
3046 if (!empty($objp->surface) && $objp->surface_units !== null) {
3047 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3048 $outvalUnits .= ' - ' . $unitToShow;
3049 }
3050 if (!empty($objp->volume) && $objp->volume_units !== null) {
3051 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3052 $outvalUnits .= ' - ' . $unitToShow;
3053 }
3054 }
3055 if ($outdurationvalue && $outdurationunit) {
3056 $da = array(
3057 'h' => $langs->trans('Hour'),
3058 'd' => $langs->trans('Day'),
3059 'w' => $langs->trans('Week'),
3060 'm' => $langs->trans('Month'),
3061 'y' => $langs->trans('Year')
3062 );
3063 if (isset($da[$outdurationunit])) {
3064 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3065 }
3066 }
3067
3068 $opt = '<option value="' . $objp->rowid . '"';
3069 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3070 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3071 $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 . '"';
3072 }
3073 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3074 if (!empty($user->rights->stock->lire)) {
3075 if ($objp->stock > 0) {
3076 $opt .= ' class="product_line_stock_ok"';
3077 } elseif ($objp->stock <= 0) {
3078 $opt .= ' class="product_line_stock_too_low"';
3079 }
3080 }
3081 }
3082 if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
3083 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3084 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3085 }
3086 $opt .= '>';
3087 $opt .= $objp->ref;
3088 if (!empty($objp->custref)) {
3089 $opt .= ' (' . $objp->custref . ')';
3090 }
3091 if ($outbarcode) {
3092 $opt .= ' (' . $outbarcode . ')';
3093 }
3094 $opt .= ' - ' . dol_trunc($label, $maxlengtharticle);
3095 if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
3096 $opt .= ' (' . getCountry($outorigin, 1) . ')';
3097 }
3098
3099 $objRef = $objp->ref;
3100 if (!empty($objp->custref)) {
3101 $objRef .= ' (' . $objp->custref . ')';
3102 }
3103 if (!empty($filterkey) && $filterkey != '') {
3104 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3105 }
3106 $outval .= $objRef;
3107 if ($outbarcode) {
3108 $outval .= ' (' . $outbarcode . ')';
3109 }
3110 $outval .= ' - ' . dol_trunc($label, $maxlengtharticle);
3111 if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
3112 $outval .= ' (' . getCountry($outorigin, 1) . ')';
3113 }
3114
3115 // Units
3116 $opt .= $outvalUnits;
3117 $outval .= $outvalUnits;
3118
3119 $found = 0;
3120
3121 // Multiprice
3122 // If we need a particular price level (from 1 to n)
3123 if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
3124 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3125 $sql .= " FROM " . $this->db->prefix() . "product_price";
3126 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3127 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3128 $sql .= " AND price_level = " . ((int) $price_level);
3129 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3130 $sql .= " LIMIT 1";
3131
3132 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3133 $result2 = $this->db->query($sql);
3134 if ($result2) {
3135 $objp2 = $this->db->fetch_object($result2);
3136 if ($objp2) {
3137 $found = 1;
3138 if ($objp2->price_base_type == 'HT') {
3139 $opt .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3140 $outval .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3141 } else {
3142 $opt .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3143 $outval .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3144 }
3145 $outprice_ht = price($objp2->price);
3146 $outprice_ttc = price($objp2->price_ttc);
3147 $outpricebasetype = $objp2->price_base_type;
3148 if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility
3149 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3150 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3151 } else {
3152 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3153 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3154 }
3155 }
3156 } else {
3157 dol_print_error($this->db);
3158 }
3159 }
3160
3161 // Price by quantity
3162 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
3163 $found = 1;
3164 $outqty = $objp->quantity;
3165 $outdiscount = $objp->remise_percent;
3166 if ($objp->quantity == 1) {
3167 $opt .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3168 $outval .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3169 $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3170 $outval .= $langs->transnoentities("Unit");
3171 } else {
3172 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3173 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3174 $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3175 $outval .= $langs->transnoentities("Units");
3176 }
3177
3178 $outprice_ht = price($objp->unitprice);
3179 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3180 $outpricebasetype = $objp->price_base_type;
3181 $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
3182 $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
3183 }
3184 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3185 $opt .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3186 $outval .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3187 }
3188 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3189 $opt .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3190 $outval .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3191 }
3192
3193 // Price by customer
3194 if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
3195 if (!empty($objp->idprodcustprice)) {
3196 $found = 1;
3197
3198 if ($objp->custprice_base_type == 'HT') {
3199 $opt .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3200 $outval .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3201 } else {
3202 $opt .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3203 $outval .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3204 }
3205
3206 $outprice_ht = price($objp->custprice);
3207 $outprice_ttc = price($objp->custprice_ttc);
3208 $outpricebasetype = $objp->custprice_base_type;
3209 $outtva_tx = $objp->custtva_tx;
3210 $outdefault_vat_code = $objp->custdefault_vat_code;
3211 }
3212 }
3213
3214 // If level no defined or multiprice not found, we used the default price
3215 if (empty($hidepriceinlabel) && !$found) {
3216 if ($objp->price_base_type == 'HT') {
3217 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3218 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3219 } else {
3220 $opt .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3221 $outval .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3222 }
3223 $outprice_ht = price($objp->price);
3224 $outprice_ttc = price($objp->price_ttc);
3225 $outpricebasetype = $objp->price_base_type;
3226 $outtva_tx = $objp->tva_tx;
3227 $outdefault_vat_code = $objp->default_vat_code;
3228 }
3229
3230 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3231 if (!empty($user->rights->stock->lire)) {
3232 $opt .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3233
3234 if ($objp->stock > 0) {
3235 $outval .= ' - <span class="product_line_stock_ok">';
3236 } elseif ($objp->stock <= 0) {
3237 $outval .= ' - <span class="product_line_stock_too_low">';
3238 }
3239 $outval .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3240 $outval .= '</span>';
3241 if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation
3242 $langs->load("stocks");
3243
3244 $tmpproduct = new Product($this->db);
3245 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3246 $tmpproduct->load_virtual_stock();
3247 $virtualstock = $tmpproduct->stock_theorique;
3248
3249 $opt .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3250
3251 $outval .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3252 if ($virtualstock > 0) {
3253 $outval .= '<span class="product_line_stock_ok">';
3254 } elseif ($virtualstock <= 0) {
3255 $outval .= '<span class="product_line_stock_too_low">';
3256 }
3257 $outval .= $virtualstock;
3258 $outval .= '</span>';
3259
3260 unset($tmpproduct);
3261 }
3262 }
3263 }
3264
3265 $parameters = array('objp'=>$objp);
3266 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3267 if (empty($reshook)) {
3268 $opt .= $hookmanager->resPrint;
3269 } else {
3270 $opt = $hookmanager->resPrint;
3271 }
3272
3273 $opt .= "</option>\n";
3274 $optJson = array(
3275 'key' => $outkey,
3276 'value' => $outref,
3277 'label' => $outval,
3278 'label2' => $outlabel,
3279 'desc' => $outdesc,
3280 'type' => $outtype,
3281 'price_ht' => price2num($outprice_ht),
3282 'price_ttc' => price2num($outprice_ttc),
3283 'price_ht_locale' => price(price2num($outprice_ht)),
3284 'price_ttc_locale' => price(price2num($outprice_ttc)),
3285 'pricebasetype' => $outpricebasetype,
3286 'tva_tx' => $outtva_tx,
3287 'default_vat_code' => $outdefault_vat_code,
3288 'qty' => $outqty,
3289 'discount' => $outdiscount,
3290 'duration_value' => $outdurationvalue,
3291 'duration_unit' => $outdurationunit,
3292 'pbq' => $outpbq,
3293 'labeltrans' => $outlabel_translated,
3294 'desctrans' => $outdesc_translated,
3295 'ref_customer' => $outrefcust
3296 );
3297 }
3298
3299 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3300
3316 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3317 {
3318 // phpcs:enable
3319 global $langs, $conf;
3320 global $price_level, $status, $finished;
3321
3322 if (!isset($status)) {
3323 $status = 1;
3324 }
3325
3326 $selected_input_value = '';
3327 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
3328 if ($selected > 0) {
3329 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3330 $producttmpselect = new Product($this->db);
3331 $producttmpselect->fetch($selected);
3332 $selected_input_value = $producttmpselect->ref;
3333 unset($producttmpselect);
3334 }
3335
3336 // mode=2 means suppliers products
3337 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3338 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
3339
3340 print ($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="minwidth300" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3341 } else {
3342 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3343 }
3344 }
3345
3346 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3347
3366 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 = '')
3367 {
3368 // phpcs:enable
3369 global $langs, $conf, $user;
3370 global $hookmanager;
3371
3372 $out = '';
3373 $outarray = array();
3374
3375 $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3376
3377 $langs->load('stocks');
3378 // Units
3379 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3380 $langs->load('other');
3381 }
3382
3383 $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,";
3384 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice";
3385 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3386 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3387 $sql .= ", pfp.supplier_reputation";
3388 // if we use supplier description of the products
3389 if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3390 $sql .= ", pfp.desc_fourn as description";
3391 } else {
3392 $sql .= ", p.description";
3393 }
3394 // Units
3395 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3396 $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";
3397 }
3398 if (isModEnabled('barcode')) {
3399 $sql .= ", pfp.barcode";
3400 }
3401 $sql .= " FROM " . $this->db->prefix() . "product as p";
3402 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3403 if ($socid > 0) {
3404 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3405 }
3406 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3407 // Units
3408 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3409 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3410 }
3411 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3412 if ($statut != -1) {
3413 $sql .= " AND p.tobuy = " . ((int) $statut);
3414 }
3415 if (strval($filtertype) != '') {
3416 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3417 }
3418 if (!empty($filtre)) {
3419 $sql .= " " . $filtre;
3420 }
3421 // Add where from hooks
3422 $parameters = array();
3423 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3424 $sql .= $hookmanager->resPrint;
3425 // Add criteria on ref/label
3426 if ($filterkey != '') {
3427 $sql .= ' AND (';
3428 $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3429 // For natural search
3430 $scrit = explode(' ', $filterkey);
3431 $i = 0;
3432 if (count($scrit) > 1) {
3433 $sql .= "(";
3434 }
3435 foreach ($scrit as $crit) {
3436 if ($i > 0) {
3437 $sql .= " AND ";
3438 }
3439 $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) . "%'";
3440 if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3441 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3442 }
3443 $sql .= ")";
3444 $i++;
3445 }
3446 if (count($scrit) > 1) {
3447 $sql .= ")";
3448 }
3449 if (isModEnabled('barcode')) {
3450 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3451 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3452 }
3453 $sql .= ')';
3454 }
3455 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3456 $sql .= $this->db->plimit($limit, 0);
3457
3458 // Build output string
3459
3460 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3461 $result = $this->db->query($sql);
3462 if ($result) {
3463 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3464 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3465
3466 $num = $this->db->num_rows($result);
3467
3468 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3469 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3470 if (!$selected) {
3471 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3472 } else {
3473 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3474 }
3475
3476 $i = 0;
3477 while ($i < $num) {
3478 $objp = $this->db->fetch_object($result);
3479
3480 if (is_null($objp->idprodfournprice)) {
3481 // There is no supplier price found, we will use the vat rate for sale
3482 $objp->tva_tx = $objp->tva_tx_sale;
3483 $objp->default_vat_code = $objp->default_vat_code_sale;
3484 }
3485
3486 $outkey = $objp->idprodfournprice; // id in table of price
3487 if (!$outkey && $alsoproductwithnosupplierprice) {
3488 $outkey = 'idprod_' . $objp->rowid; // id of product
3489 }
3490
3491 $outref = $objp->ref;
3492 $outbarcode = $objp->barcode;
3493 $outqty = 1;
3494 $outdiscount = 0;
3495 $outtype = $objp->fk_product_type;
3496 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3497 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3498
3499 // Units
3500 $outvalUnits = '';
3501 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3502 if (!empty($objp->unit_short)) {
3503 $outvalUnits .= ' - ' . $objp->unit_short;
3504 }
3505 if (!empty($objp->weight) && $objp->weight_units !== null) {
3506 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3507 $outvalUnits .= ' - ' . $unitToShow;
3508 }
3509 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3510 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3511 $outvalUnits .= ' - ' . $unitToShow;
3512 }
3513 if (!empty($objp->surface) && $objp->surface_units !== null) {
3514 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3515 $outvalUnits .= ' - ' . $unitToShow;
3516 }
3517 if (!empty($objp->volume) && $objp->volume_units !== null) {
3518 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3519 $outvalUnits .= ' - ' . $unitToShow;
3520 }
3521 if ($outdurationvalue && $outdurationunit) {
3522 $da = array(
3523 'h' => $langs->trans('Hour'),
3524 'd' => $langs->trans('Day'),
3525 'w' => $langs->trans('Week'),
3526 'm' => $langs->trans('Month'),
3527 'y' => $langs->trans('Year')
3528 );
3529 if (isset($da[$outdurationunit])) {
3530 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3531 }
3532 }
3533 }
3534
3535 $objRef = $objp->ref;
3536 if ($filterkey && $filterkey != '') {
3537 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3538 }
3539 $objRefFourn = $objp->ref_fourn;
3540 if ($filterkey && $filterkey != '') {
3541 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3542 }
3543 $label = $objp->label;
3544 if ($filterkey && $filterkey != '') {
3545 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3546 }
3547
3548 $optlabel = $objp->ref;
3549 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3550 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3551 }
3552 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3553 $optlabel .= ' (' . $outbarcode . ')';
3554 }
3555 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3556
3557 $outvallabel = $objRef;
3558 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3559 $outvallabel .= ' (' . $objRefFourn . ')';
3560 }
3561 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3562 $outvallabel .= ' (' . $outbarcode . ')';
3563 }
3564 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3565
3566 // Units
3567 $optlabel .= $outvalUnits;
3568 $outvallabel .= $outvalUnits;
3569
3570 if (!empty($objp->idprodfournprice)) {
3571 $outqty = $objp->quantity;
3572 $outdiscount = $objp->remise_percent;
3573 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3574 $prod_supplier = new ProductFournisseur($this->db);
3575 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3576 $prod_supplier->id = $objp->fk_product;
3577 $prod_supplier->fourn_qty = $objp->quantity;
3578 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3579 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3580
3581 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3582 $priceparser = new PriceParser($this->db);
3583 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3584 if ($price_result >= 0) {
3585 $objp->fprice = $price_result;
3586 if ($objp->quantity >= 1) {
3587 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3588 }
3589 }
3590 }
3591 if ($objp->quantity == 1) {
3592 $optlabel .= ' - ' . price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3593 $outvallabel .= ' - ' . price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3594 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3595 $outvallabel .= $langs->transnoentities("Unit");
3596 } else {
3597 $optlabel .= ' - ' . price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3598 $outvallabel .= ' - ' . price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3599 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3600 $outvallabel .= ' ' . $langs->transnoentities("Units");
3601 }
3602
3603 if ($objp->quantity > 1) {
3604 $optlabel .= " (" . price($objp->unitprice * (!empty($conf->global->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
3605 $outvallabel .= " (" . price($objp->unitprice * (!empty($conf->global->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
3606 }
3607 if ($objp->remise_percent >= 1) {
3608 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3609 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3610 }
3611 if ($objp->duration) {
3612 $optlabel .= " - " . $objp->duration;
3613 $outvallabel .= " - " . $objp->duration;
3614 }
3615 if (!$socid) {
3616 $optlabel .= " - " . dol_trunc($objp->name, 8);
3617 $outvallabel .= " - " . dol_trunc($objp->name, 8);
3618 }
3619 if ($objp->supplier_reputation) {
3620 //TODO dictionary
3621 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3622
3623 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3624 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3625 }
3626 } else {
3627 if (empty($alsoproductwithnosupplierprice)) { // No supplier price defined for couple product/supplier
3628 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3629 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3630 } else // No supplier price defined for product, even on other suppliers
3631 {
3632 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3633 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3634 }
3635 }
3636
3637 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3638 $novirtualstock = ($showstockinlist == 2);
3639
3640 if (!empty($user->rights->stock->lire)) {
3641 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3642
3643 if ($objp->stock > 0) {
3644 $optlabel .= ' - <span class="product_line_stock_ok">';
3645 } elseif ($objp->stock <= 0) {
3646 $optlabel .= ' - <span class="product_line_stock_too_low">';
3647 }
3648 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3649 $optlabel .= '</span>';
3650 if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation
3651 $langs->load("stocks");
3652
3653 $tmpproduct = new Product($this->db);
3654 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3655 $tmpproduct->load_virtual_stock();
3656 $virtualstock = $tmpproduct->stock_theorique;
3657
3658 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3659
3660 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3661 if ($virtualstock > 0) {
3662 $optlabel .= '<span class="product_line_stock_ok">';
3663 } elseif ($virtualstock <= 0) {
3664 $optlabel .= '<span class="product_line_stock_too_low">';
3665 }
3666 $optlabel .= $virtualstock;
3667 $optlabel .= '</span>';
3668
3669 unset($tmpproduct);
3670 }
3671 }
3672 }
3673
3674 $optstart = '<option value="' . $outkey . '"';
3675 if ($selected && $selected == $objp->idprodfournprice) {
3676 $optstart .= ' selected';
3677 }
3678 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3679 $optstart .= ' disabled';
3680 }
3681
3682 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3683 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
3684 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
3685 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
3686 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
3687 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
3688 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
3689 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
3690 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
3691 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
3692 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
3693 if (isModEnabled('multicurrency')) {
3694 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
3695 $optstart .= ' data-multicurrency-up="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
3696 }
3697 }
3698 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
3699
3700 $outarrayentry = array(
3701 'key' => $outkey,
3702 'value' => $outref,
3703 'label' => $outvallabel,
3704 'qty' => $outqty,
3705 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3706 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3707 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3708 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
3709 'tva_tx' => price2num($objp->tva_tx),
3710 'default_vat_code' => $objp->default_vat_code,
3711 'discount' => $outdiscount,
3712 'type' => $outtype,
3713 'duration_value' => $outdurationvalue,
3714 'duration_unit' => $outdurationunit,
3715 'disabled' => (empty($objp->idprodfournprice) ? true : false),
3716 'description' => $objp->description
3717 );
3718 if (isModEnabled('multicurrency')) {
3719 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
3720 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
3721 }
3722
3723 $parameters = array(
3724 'objp' => &$objp,
3725 'optstart' => &$optstart,
3726 'optlabel' => &$optlabel,
3727 'outvallabel' => &$outvallabel,
3728 'outarrayentry' => &$outarrayentry
3729 );
3730 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
3731
3732
3733 // Add new entry
3734 // "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
3735 // "label" value of json key array is used by jQuery automatically as text for combo box
3736 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
3737 $outarraypush = array(
3738 'key' => $outkey,
3739 'value' => $outref,
3740 'label' => $outvallabel,
3741 'qty' => $outqty,
3742 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3743 'price_qty_ht_locale' => price($objp->fprice),
3744 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3745 'price_unit_ht_locale' => price($objp->unitprice),
3746 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3747 'tva_tx_formated' => price($objp->tva_tx),
3748 'tva_tx' => price2num($objp->tva_tx),
3749 'default_vat_code' => $objp->default_vat_code,
3750 'discount' => $outdiscount,
3751 'type' => $outtype,
3752 'duration_value' => $outdurationvalue,
3753 'duration_unit' => $outdurationunit,
3754 'disabled' => (empty($objp->idprodfournprice) ? true : false),
3755 'description' => $objp->description
3756 );
3757 if (isModEnabled('multicurrency')) {
3758 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
3759 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
3760 }
3761 array_push($outarray, $outarraypush);
3762
3763 // Example of var_dump $outarray
3764 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
3765 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
3766 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
3767 //}
3768 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3769 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
3770 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3771
3772 $i++;
3773 }
3774 $out .= '</select>';
3775
3776 $this->db->free($result);
3777
3778 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3779 $out .= ajax_combobox($htmlname);
3780 } else {
3781 dol_print_error($this->db);
3782 }
3783
3784 if (empty($outputmode)) {
3785 return $out;
3786 }
3787 return $outarray;
3788 }
3789
3790 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3791
3800 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
3801 {
3802 // phpcs:enable
3803 global $langs, $conf;
3804
3805 $langs->load('stocks');
3806
3807 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3808 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3809 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3810 $sql .= " FROM " . $this->db->prefix() . "product as p";
3811 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3812 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3813 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
3814 $sql .= " AND p.tobuy = 1";
3815 $sql .= " AND s.fournisseur = 1";
3816 $sql .= " AND p.rowid = " . ((int) $productid);
3817 if (empty($conf->global->PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED)) {
3818 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3819 } else {
3820 $sql .= " ORDER BY pfp.unitprice ASC";
3821 }
3822
3823 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
3824 $result = $this->db->query($sql);
3825
3826 if ($result) {
3827 $num = $this->db->num_rows($result);
3828
3829 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
3830
3831 if (!$num) {
3832 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
3833 } else {
3834 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3835 $form .= '<option value="0">&nbsp;</option>';
3836
3837 $i = 0;
3838 while ($i < $num) {
3839 $objp = $this->db->fetch_object($result);
3840
3841 $opt = '<option value="' . $objp->idprodfournprice . '"';
3842 //if there is only one supplier, preselect it
3843 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && !empty($conf->global->PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED))) {
3844 $opt .= ' selected';
3845 }
3846 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
3847
3848 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3849 $prod_supplier = new ProductFournisseur($this->db);
3850 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3851 $prod_supplier->id = $productid;
3852 $prod_supplier->fourn_qty = $objp->quantity;
3853 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3854 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3855
3856 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3857 $priceparser = new PriceParser($this->db);
3858 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3859 if ($price_result >= 0) {
3860 $objp->fprice = $price_result;
3861 if ($objp->quantity >= 1) {
3862 $objp->unitprice = $objp->fprice / $objp->quantity;
3863 }
3864 }
3865 }
3866 if ($objp->quantity == 1) {
3867 $opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3868 }
3869
3870 $opt .= $objp->quantity . ' ';
3871
3872 if ($objp->quantity == 1) {
3873 $opt .= $langs->trans("Unit");
3874 } else {
3875 $opt .= $langs->trans("Units");
3876 }
3877 if ($objp->quantity > 1) {
3878 $opt .= " - ";
3879 $opt .= price($objp->unitprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit");
3880 }
3881 if ($objp->duration) {
3882 $opt .= " - " . $objp->duration;
3883 }
3884 $opt .= "</option>\n";
3885
3886 $form .= $opt;
3887 $i++;
3888 }
3889 }
3890
3891 $form .= '</select>';
3892 $this->db->free($result);
3893 return $form;
3894 } else {
3895 dol_print_error($this->db);
3896 return '';
3897 }
3898 }
3899
3900 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3901
3911 public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3912 {
3913 // phpcs:enable
3914 // looking for users
3915 $sql = "SELECT a.rowid, a.label";
3916 $sql .= " FROM " . $this->db->prefix() . "societe_address as a";
3917 $sql .= " WHERE a.fk_soc = " . ((int) $socid);
3918 $sql .= " ORDER BY a.label ASC";
3919
3920 dol_syslog(get_class($this) . "::select_address", LOG_DEBUG);
3921 $resql = $this->db->query($sql);
3922 if ($resql) {
3923 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
3924 if ($showempty) {
3925 print '<option value="0">&nbsp;</option>';
3926 }
3927 $num = $this->db->num_rows($resql);
3928 $i = 0;
3929 if ($num) {
3930 while ($i < $num) {
3931 $obj = $this->db->fetch_object($resql);
3932
3933 if ($selected && $selected == $obj->rowid) {
3934 print '<option value="' . $obj->rowid . '" selected>' . $obj->label . '</option>';
3935 } else {
3936 print '<option value="' . $obj->rowid . '">' . $obj->label . '</option>';
3937 }
3938 $i++;
3939 }
3940 }
3941 print '</select>';
3942 return $num;
3943 } else {
3944 dol_print_error($this->db);
3945 return -1;
3946 }
3947 }
3948
3949 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3950
3957 {
3958 // phpcs:enable
3959 global $langs;
3960
3961 $num = count($this->cache_conditions_paiements);
3962 if ($num > 0) {
3963 return 0; // Cache already loaded
3964 }
3965
3966 dol_syslog(__METHOD__, LOG_DEBUG);
3967
3968 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
3969 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
3970 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
3971 $sql .= " AND active > 0";
3972 $sql .= " ORDER BY sortorder";
3973
3974 $resql = $this->db->query($sql);
3975 if ($resql) {
3976 $num = $this->db->num_rows($resql);
3977 $i = 0;
3978 while ($i < $num) {
3979 $obj = $this->db->fetch_object($resql);
3980
3981 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3982 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != ("PaymentConditionShort" . $obj->code) ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
3983 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3984 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3985 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
3986 $i++;
3987 }
3988
3989 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
3990
3991 return $num;
3992 } else {
3993 dol_print_error($this->db);
3994 return -1;
3995 }
3996 }
3997
3998 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3999
4005 public function load_cache_availability()
4006 {
4007 // phpcs:enable
4008 global $langs;
4009
4010 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4011 if ($num > 0) {
4012 return 0; // Cache already loaded
4013 }
4014
4015 dol_syslog(__METHOD__, LOG_DEBUG);
4016
4017 $langs->load('propal');
4018
4019 $sql = "SELECT rowid, code, label, position";
4020 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4021 $sql .= " WHERE active > 0";
4022
4023 $resql = $this->db->query($sql);
4024 if ($resql) {
4025 $num = $this->db->num_rows($resql);
4026 $i = 0;
4027 while ($i < $num) {
4028 $obj = $this->db->fetch_object($resql);
4029
4030 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4031 $label = ($langs->trans("AvailabilityType" . $obj->code) != ("AvailabilityType" . $obj->code) ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4032 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4033 $this->cache_availability[$obj->rowid]['label'] = $label;
4034 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4035 $i++;
4036 }
4037
4038 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4039
4040 return $num;
4041 } else {
4042 dol_print_error($this->db);
4043 return -1;
4044 }
4045 }
4046
4057 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4058 {
4059 global $langs, $user;
4060
4061 $this->load_cache_availability();
4062
4063 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4064
4065 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4066 if ($addempty) {
4067 print '<option value="0">&nbsp;</option>';
4068 }
4069 foreach ($this->cache_availability as $id => $arrayavailability) {
4070 if ($selected == $id) {
4071 print '<option value="' . $id . '" selected>';
4072 } else {
4073 print '<option value="' . $id . '">';
4074 }
4075 print dol_escape_htmltag($arrayavailability['label']);
4076 print '</option>';
4077 }
4078 print '</select>';
4079 if ($user->admin) {
4080 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4081 }
4082 print ajax_combobox($htmlname);
4083 }
4084
4090 public function loadCacheInputReason()
4091 {
4092 global $langs;
4093
4094 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4095 if ($num > 0) {
4096 return 0; // Cache already loaded
4097 }
4098
4099 $sql = "SELECT rowid, code, label";
4100 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4101 $sql .= " WHERE active > 0";
4102
4103 $resql = $this->db->query($sql);
4104 if ($resql) {
4105 $num = $this->db->num_rows($resql);
4106 $i = 0;
4107 $tmparray = array();
4108 while ($i < $num) {
4109 $obj = $this->db->fetch_object($resql);
4110
4111 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4112 $label = ($obj->label != '-' ? $obj->label : '');
4113 if ($langs->trans("DemandReasonType" . $obj->code) != ("DemandReasonType" . $obj->code)) {
4114 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4115 }
4116 if ($langs->trans($obj->code) != $obj->code) {
4117 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4118 }
4119
4120 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4121 $tmparray[$obj->rowid]['code'] = $obj->code;
4122 $tmparray[$obj->rowid]['label'] = $label;
4123 $i++;
4124 }
4125
4126 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4127
4128 unset($tmparray);
4129 return $num;
4130 } else {
4131 dol_print_error($this->db);
4132 return -1;
4133 }
4134 }
4135
4148 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4149 {
4150 global $langs, $user;
4151
4152 $this->loadCacheInputReason();
4153
4154 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4155 if ($addempty) {
4156 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4157 }
4158 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4159 if ($arraydemandreason['code'] == $exclude) {
4160 continue;
4161 }
4162
4163 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4164 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4165 } else {
4166 print '<option value="' . $arraydemandreason['id'] . '">';
4167 }
4168 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4169 print $langs->trans($label);
4170 print '</option>';
4171 }
4172 print '</select>';
4173 if ($user->admin && empty($notooltip)) {
4174 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4175 }
4176 print ajax_combobox('select_' . $htmlname);
4177 }
4178
4179 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4180
4187 {
4188 // phpcs:enable
4189 global $langs;
4190
4191 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4192 if ($num > 0) {
4193 return $num; // Cache already loaded
4194 }
4195
4196 dol_syslog(__METHOD__, LOG_DEBUG);
4197
4198 $this->cache_types_paiements = array();
4199
4200 $sql = "SELECT id, code, libelle as label, type, active";
4201 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4202 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4203
4204 $resql = $this->db->query($sql);
4205 if ($resql) {
4206 $num = $this->db->num_rows($resql);
4207 $i = 0;
4208 while ($i < $num) {
4209 $obj = $this->db->fetch_object($resql);
4210
4211 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4212 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != ("PaymentTypeShort" . $obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4213 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4214 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4215 $this->cache_types_paiements[$obj->id]['label'] = $label;
4216 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4217 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4218 $i++;
4219 }
4220
4221 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4222
4223 return $num;
4224 } else {
4225 dol_print_error($this->db);
4226 return -1;
4227 }
4228 }
4229
4230
4231 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4232
4250 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4251 {
4252 // phpcs:enable
4253 print $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4254 }
4255
4256
4273 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4274 {
4275 global $langs, $user, $conf;
4276
4277 $out = '';
4278 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4279
4281
4282 // Set default value if not already set by caller
4283 if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) {
4284 $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
4285 }
4286
4287 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4288 if ($addempty) {
4289 $out .= '<option value="0">&nbsp;</option>';
4290 }
4291
4292 $selectedDepositPercent = null;
4293
4294 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4295 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4296 continue;
4297 }
4298
4299 if ($selected == $id) {
4300 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4301 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4302 } else {
4303 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4304 }
4305 $label = $arrayconditions['label'];
4306
4307 if (!empty($arrayconditions['deposit_percent'])) {
4308 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4309 }
4310
4311 $out .= $label;
4312 $out .= '</option>';
4313 }
4314 $out .= '</select>';
4315 if ($user->admin && empty($noinfoadmin)) {
4316 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4317 }
4318 $out .= ajax_combobox($htmlname);
4319
4320 if ($deposit_percent >= 0) {
4321 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4322 $out .= $langs->trans('DepositPercent') . ' : ';
4323 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4324 $out .= '</span>';
4325 $out .= '
4326 <script nonce="' . getNonce() . '">
4327 $(document).ready(function () {
4328 $("#' . $htmlname . '").change(function () {
4329 let $selected = $(this).find("option:selected");
4330 let depositPercent = $selected.attr("data-deposit_percent");
4331
4332 if (depositPercent.length > 0) {
4333 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4334 } else {
4335 $("#' . $htmlname . '_deposit_percent_container").hide();
4336 }
4337
4338 return true;
4339 });
4340 });
4341 </script>';
4342 }
4343
4344 return $out;
4345 }
4346
4347
4348 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4349
4366 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4367 {
4368 // phpcs:enable
4369 global $langs, $user, $conf;
4370
4371 $out = '';
4372
4373 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4374
4375 $filterarray = array();
4376 if ($filtertype == 'CRDT') {
4377 $filterarray = array(0, 2, 3);
4378 } elseif ($filtertype == 'DBIT') {
4379 $filterarray = array(1, 2, 3);
4380 } elseif ($filtertype != '' && $filtertype != '-1') {
4381 $filterarray = explode(',', $filtertype);
4382 }
4383
4385
4386 // Set default value if not already set by caller
4387 if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) {
4388 $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
4389 }
4390
4391 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4392 if ($empty) {
4393 $out .= '<option value="">&nbsp;</option>';
4394 }
4395 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4396 // If not good status
4397 if ($active >= 0 && $arraytypes['active'] != $active) {
4398 continue;
4399 }
4400
4401 // On passe si on a demande de filtrer sur des modes de paiments particuliers
4402 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4403 continue;
4404 }
4405
4406 // We discard empty line if showempty is on because an empty line has already been output.
4407 if ($empty && empty($arraytypes['code'])) {
4408 continue;
4409 }
4410
4411 if ($format == 0) {
4412 $out .= '<option value="' . $id . '"';
4413 } elseif ($format == 1) {
4414 $out .= '<option value="' . $arraytypes['code'] . '"';
4415 } elseif ($format == 2) {
4416 $out .= '<option value="' . $arraytypes['code'] . '"';
4417 } elseif ($format == 3) {
4418 $out .= '<option value="' . $id . '"';
4419 }
4420 // Print attribute selected or not
4421 if ($format == 1 || $format == 2) {
4422 if ($selected == $arraytypes['code']) {
4423 $out .= ' selected';
4424 }
4425 } else {
4426 if ($selected == $id) {
4427 $out .= ' selected';
4428 }
4429 }
4430 $out .= '>';
4431 $value = '';
4432 if ($format == 0) {
4433 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4434 } elseif ($format == 1) {
4435 $value = $arraytypes['code'];
4436 } elseif ($format == 2) {
4437 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4438 } elseif ($format == 3) {
4439 $value = $arraytypes['code'];
4440 }
4441 $out .= $value ? $value : '&nbsp;';
4442 $out .= '</option>';
4443 }
4444 $out .= '</select>';
4445 if ($user->admin && !$noadmininfo) {
4446 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4447 }
4448 $out .= ajax_combobox('select' . $htmlname);
4449
4450 if (empty($nooutput)) {
4451 print $out;
4452 } else {
4453 return $out;
4454 }
4455 }
4456
4457
4466 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4467 {
4468 global $langs;
4469
4470 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4471 $options = array(
4472 'HT' => $langs->trans("HT"),
4473 'TTC' => $langs->trans("TTC")
4474 );
4475 foreach ($options as $id => $value) {
4476 if ($selected == $id) {
4477 $return .= '<option value="' . $id . '" selected>' . $value;
4478 } else {
4479 $return .= '<option value="' . $id . '">' . $value;
4480 }
4481 $return .= '</option>';
4482 }
4483 $return .= '</select>';
4484 if ($addjscombo) {
4485 $return .= ajax_combobox('select_' . $htmlname);
4486 }
4487
4488 return $return;
4489 }
4490
4491 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4492
4499 {
4500 // phpcs:enable
4501 global $langs;
4502
4503 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4504 if ($num > 0) {
4505 return $num; // Cache already loaded
4506 }
4507
4508 dol_syslog(__METHOD__, LOG_DEBUG);
4509
4510 $this->cache_transport_mode = array();
4511
4512 $sql = "SELECT rowid, code, label, active";
4513 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4514 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4515
4516 $resql = $this->db->query($sql);
4517 if ($resql) {
4518 $num = $this->db->num_rows($resql);
4519 $i = 0;
4520 while ($i < $num) {
4521 $obj = $this->db->fetch_object($resql);
4522
4523 // If traduction exist, we use it else we take the default label
4524 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != ("PaymentTypeShort" . $obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4525 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4526 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4527 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4528 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4529 $i++;
4530 }
4531
4532 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4533
4534 return $num;
4535 } else {
4536 dol_print_error($this->db);
4537 return -1;
4538 }
4539 }
4540
4554 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4555 {
4556 global $langs, $user;
4557
4558 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4559
4561
4562 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4563 if ($empty) {
4564 print '<option value="">&nbsp;</option>';
4565 }
4566 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4567 // If not good status
4568 if ($active >= 0 && $arraytypes['active'] != $active) {
4569 continue;
4570 }
4571
4572 // We discard empty line if showempty is on because an empty line has already been output.
4573 if ($empty && empty($arraytypes['code'])) {
4574 continue;
4575 }
4576
4577 if ($format == 0) {
4578 print '<option value="' . $id . '"';
4579 } elseif ($format == 1) {
4580 print '<option value="' . $arraytypes['code'] . '"';
4581 } elseif ($format == 2) {
4582 print '<option value="' . $arraytypes['code'] . '"';
4583 } elseif ($format == 3) {
4584 print '<option value="' . $id . '"';
4585 }
4586 // If text is selected, we compare with code, else with id
4587 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4588 print ' selected';
4589 } elseif ($selected == $id) {
4590 print ' selected';
4591 }
4592 print '>';
4593 $value = '';
4594 if ($format == 0) {
4595 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4596 } elseif ($format == 1) {
4597 $value = $arraytypes['code'];
4598 } elseif ($format == 2) {
4599 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4600 } elseif ($format == 3) {
4601 $value = $arraytypes['code'];
4602 }
4603 print $value ? $value : '&nbsp;';
4604 print '</option>';
4605 }
4606 print '</select>';
4607 if ($user->admin && !$noadmininfo) {
4608 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4609 }
4610 }
4611
4624 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4625 {
4626 global $langs, $conf, $user;
4627
4628 $langs->load("admin");
4629 $langs->load("deliveries");
4630
4631 $sql = "SELECT rowid, code, libelle as label";
4632 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4633 $sql .= " WHERE active > 0";
4634 if ($filtre) {
4635 $sql .= " AND " . $filtre;
4636 }
4637 $sql .= " ORDER BY libelle ASC";
4638
4639 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4640 $result = $this->db->query($sql);
4641 if ($result) {
4642 $num = $this->db->num_rows($result);
4643 $i = 0;
4644 if ($num) {
4645 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4646 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4647 print '<option value="-1">&nbsp;</option>';
4648 }
4649 while ($i < $num) {
4650 $obj = $this->db->fetch_object($result);
4651 if ($selected == $obj->rowid) {
4652 print '<option value="' . $obj->rowid . '" selected>';
4653 } else {
4654 print '<option value="' . $obj->rowid . '">';
4655 }
4656 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
4657 print '</option>';
4658 $i++;
4659 }
4660 print "</select>";
4661 if ($user->admin && empty($noinfoadmin)) {
4662 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4663 }
4664
4665 print ajax_combobox('select' . $htmlname);
4666 } else {
4667 print $langs->trans("NoShippingMethodDefined");
4668 }
4669 } else {
4670 dol_print_error($this->db);
4671 }
4672 }
4673
4683 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4684 {
4685 global $langs;
4686
4687 $langs->load("deliveries");
4688
4689 if ($htmlname != "none") {
4690 print '<form method="POST" action="' . $page . '">';
4691 print '<input type="hidden" name="action" value="setshippingmethod">';
4692 print '<input type="hidden" name="token" value="' . newToken() . '">';
4693 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4694 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
4695 print '</form>';
4696 } else {
4697 if ($selected) {
4698 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4699 print $langs->trans("SendingMethod" . strtoupper($code));
4700 } else {
4701 print "&nbsp;";
4702 }
4703 }
4704 }
4705
4714 public function selectSituationInvoices($selected = '', $socid = 0)
4715 {
4716 global $langs;
4717
4718 $langs->load('bills');
4719
4720 $opt = '<option value="" selected></option>';
4721 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4722 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
4723 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
4724 $sql .= ' AND situation_counter >= 1';
4725 $sql .= ' AND fk_soc = ' . (int) $socid;
4726 $sql .= ' AND type <> 2';
4727 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4728 $resql = $this->db->query($sql);
4729
4730 if ($resql && $this->db->num_rows($resql) > 0) {
4731 // Last seen cycle
4732 $ref = 0;
4733 while ($obj = $this->db->fetch_object($resql)) {
4734 //Same cycle ?
4735 if ($obj->situation_cycle_ref != $ref) {
4736 // Just seen this cycle
4737 $ref = $obj->situation_cycle_ref;
4738 //not final ?
4739 if ($obj->situation_final != 1) {
4740 //Not prov?
4741 if (substr($obj->ref, 1, 4) != 'PROV') {
4742 if ($selected == $obj->rowid) {
4743 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
4744 } else {
4745 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
4746 }
4747 }
4748 }
4749 }
4750 }
4751 } else {
4752 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
4753 }
4754 if ($opt == '<option value ="" selected></option>') {
4755 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
4756 }
4757 return $opt;
4758 }
4759
4769 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
4770 {
4771 global $langs;
4772
4773 $langs->load('products');
4774
4775 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
4776
4777 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
4778 $sql .= ' WHERE active > 0';
4779 if (!empty($unit_type)) {
4780 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
4781 }
4782 $sql .= " ORDER BY sortorder";
4783
4784 $resql = $this->db->query($sql);
4785 if ($resql && $this->db->num_rows($resql) > 0) {
4786 if ($showempty) {
4787 $return .= '<option value="none"></option>';
4788 }
4789
4790 while ($res = $this->db->fetch_object($resql)) {
4791 $unitLabel = $res->label;
4792 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
4793 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
4794 }
4795
4796 if ($selected == $res->rowid) {
4797 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
4798 } else {
4799 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
4800 }
4801 }
4802 $return .= '</select>';
4803 }
4804 return $return;
4805 }
4806
4807 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4808
4823 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
4824 {
4825 // phpcs:enable
4826 global $langs, $conf;
4827
4828 $out = '';
4829
4830 $langs->load("admin");
4831 $num = 0;
4832
4833 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
4834 $sql .= " FROM " . $this->db->prefix() . "bank_account";
4835 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
4836 if ($status != 2) {
4837 $sql .= " AND clos = " . (int) $status;
4838 }
4839 if ($filtre) {
4840 $sql .= " AND " . $filtre;
4841 }
4842 $sql .= " ORDER BY label";
4843
4844 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
4845 $result = $this->db->query($sql);
4846 if ($result) {
4847 $num = $this->db->num_rows($result);
4848 $i = 0;
4849 if ($num) {
4850 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4851 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4852 $out .= '<option value="-1">&nbsp;</option>';
4853 }
4854
4855 while ($i < $num) {
4856 $obj = $this->db->fetch_object($result);
4857 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
4858 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" selected>';
4859 } else {
4860 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '">';
4861 }
4862 $out .= trim($obj->label);
4863 if ($showcurrency) {
4864 $out .= ' (' . $obj->currency_code . ')';
4865 }
4866 if ($status == 2 && $obj->status == 1) {
4867 $out .= ' (' . $langs->trans("Closed") . ')';
4868 }
4869 $out .= '</option>';
4870 $i++;
4871 }
4872 $out .= "</select>";
4873 $out .= ajax_combobox('select' . $htmlname);
4874 } else {
4875 if ($status == 0) {
4876 $out .= '<span class="opacitymedium">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
4877 } else {
4878 $out .= '<span class="opacitymedium">' . $langs->trans("NoBankAccountFound") . '</span>';
4879 }
4880 }
4881 } else {
4882 dol_print_error($this->db);
4883 }
4884
4885 // Output or return
4886 if (empty($nooutput)) {
4887 print $out;
4888 } else {
4889 return $out;
4890 }
4891
4892 return $num;
4893 }
4894
4906 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4907 {
4908 global $langs, $conf;
4909
4910 $langs->load("admin");
4911 $num = 0;
4912
4913 $sql = "SELECT rowid, name, fk_country, status, entity";
4914 $sql .= " FROM " . $this->db->prefix() . "establishment";
4915 $sql .= " WHERE 1=1";
4916 if ($status != 2) {
4917 $sql .= " AND status = " . (int) $status;
4918 }
4919 if ($filtre) {
4920 $sql .= " AND " . $filtre;
4921 }
4922 $sql .= " ORDER BY name";
4923
4924 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
4925 $result = $this->db->query($sql);
4926 if ($result) {
4927 $num = $this->db->num_rows($result);
4928 $i = 0;
4929 if ($num) {
4930 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4931 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4932 print '<option value="-1">&nbsp;</option>';
4933 }
4934
4935 while ($i < $num) {
4936 $obj = $this->db->fetch_object($result);
4937 if ($selected == $obj->rowid) {
4938 print '<option value="' . $obj->rowid . '" selected>';
4939 } else {
4940 print '<option value="' . $obj->rowid . '">';
4941 }
4942 print trim($obj->name);
4943 if ($status == 2 && $obj->status == 1) {
4944 print ' (' . $langs->trans("Closed") . ')';
4945 }
4946 print '</option>';
4947 $i++;
4948 }
4949 print "</select>";
4950 } else {
4951 if ($status == 0) {
4952 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
4953 } else {
4954 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
4955 }
4956 }
4957
4958 return $num;
4959 } else {
4960 dol_print_error($this->db);
4961 return -1;
4962 }
4963 }
4964
4974 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
4975 {
4976 global $langs;
4977 if ($htmlname != "none") {
4978 print '<form method="POST" action="' . $page . '">';
4979 print '<input type="hidden" name="action" value="setbankaccount">';
4980 print '<input type="hidden" name="token" value="' . newToken() . '">';
4981 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
4982 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
4983 if ($nbaccountfound > 0) {
4984 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
4985 }
4986 print '</form>';
4987 } else {
4988 $langs->load('banks');
4989
4990 if ($selected) {
4991 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
4992 $bankstatic = new Account($this->db);
4993 $result = $bankstatic->fetch($selected);
4994 if ($result) {
4995 print $bankstatic->getNomUrl(1);
4996 }
4997 } else {
4998 print "&nbsp;";
4999 }
5000 }
5001 }
5002
5003 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5004
5023 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
5024 {
5025 // phpcs:enable
5026 global $conf, $langs;
5027 $langs->load("categories");
5028
5029 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5030
5031 // For backward compatibility
5032 if (is_numeric($type)) {
5033 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5034 }
5035
5036 if ($type === Categorie::TYPE_BANK_LINE) {
5037 // TODO Move this into common category feature
5038 $cate_arbo = array();
5039 $sql = "SELECT c.label, c.rowid";
5040 $sql .= " FROM " . $this->db->prefix() . "bank_categ as c";
5041 $sql .= " WHERE entity = " . $conf->entity;
5042 $sql .= " ORDER BY c.label";
5043 $result = $this->db->query($sql);
5044 if ($result) {
5045 $num = $this->db->num_rows($result);
5046 $i = 0;
5047 while ($i < $num) {
5048 $objp = $this->db->fetch_object($result);
5049 if ($objp) {
5050 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5051 }
5052 $i++;
5053 }
5054 $this->db->free($result);
5055 } else {
5056 dol_print_error($this->db);
5057 }
5058 } else {
5059 $cat = new Categorie($this->db);
5060 $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
5061 }
5062
5063 $outarray = array();
5064
5065 $output = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5066 if (is_array($cate_arbo)) {
5067 if (!count($cate_arbo)) {
5068 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5069 } else {
5070 $output .= '<option value="-1">&nbsp;</option>';
5071 foreach ($cate_arbo as $key => $value) {
5072 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5073 $add = 'selected ';
5074 } else {
5075 $add = '';
5076 }
5077 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5078 $output .= ' data-html="' . dol_escape_htmltag(img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"') . dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle')) . '"';
5079 $output .= '>';
5080 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5081 $output .= '</option>';
5082
5083 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5084 }
5085 }
5086 }
5087 $output .= '</select>';
5088 $output .= "\n";
5089
5090 if ($outputmode == 2) {
5091 return $cate_arbo;
5092 } elseif ($outputmode) {
5093 return $outarray;
5094 }
5095 return $output;
5096 }
5097
5098 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5099
5116 public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5117 {
5118 // phpcs:enable
5119 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5120 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5121 }
5122
5150 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5151 {
5152 global $langs, $conf;
5153
5154 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5155 $formconfirm = '';
5156 $inputok = array();
5157 $inputko = array();
5158
5159 // Clean parameters
5160 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5161 if ($conf->browser->layout == 'phone') {
5162 $width = '95%';
5163 }
5164
5165 // Set height automatically if not defined
5166 if (empty($height)) {
5167 $height = 220;
5168 if (is_array($formquestion) && count($formquestion) > 2) {
5169 $height += ((count($formquestion) - 2) * 24);
5170 }
5171 }
5172
5173 if (is_array($formquestion) && !empty($formquestion)) {
5174 // First add hidden fields and value
5175 foreach ($formquestion as $key => $input) {
5176 if (is_array($input) && !empty($input)) {
5177 if ($input['type'] == 'hidden') {
5178 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5179 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5180
5181 $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";
5182 }
5183 }
5184 }
5185
5186 // Now add questions
5187 $moreonecolumn = '';
5188 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5189 foreach ($formquestion as $key => $input) {
5190 if (is_array($input) && !empty($input)) {
5191 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5192 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5193 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5194
5195 if ($input['type'] == 'text') {
5196 $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";
5197 } elseif ($input['type'] == 'password') {
5198 $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";
5199 } elseif ($input['type'] == 'textarea') {
5200 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5201 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5202 $more .= $input['value'];
5203 $more .= '</textarea>';
5204 $more .= '</div></div>'."\n";*/
5205 $moreonecolumn .= '<div class="margintoponly">';
5206 $moreonecolumn .= $input['label'] . '<br>';
5207 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5208 $moreonecolumn .= $input['value'];
5209 $moreonecolumn .= '</textarea>';
5210 $moreonecolumn .= '</div>';
5211 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5212 if (empty($morecss)) {
5213 $morecss = 'minwidth100';
5214 }
5215
5216 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5217 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5218 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5219 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5220 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5221 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5222 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5223
5224 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5225 if (!empty($input['label'])) {
5226 $more .= $input['label'] . '</div><div class="tagtd left">';
5227 }
5228 if ($input['type'] == 'select') {
5229 $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);
5230 } else {
5231 $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);
5232 }
5233 $more .= '</div></div>' . "\n";
5234 } elseif ($input['type'] == 'checkbox') {
5235 $more .= '<div class="tagtr">';
5236 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5237 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5238 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5239 $more .= ' checked';
5240 }
5241 if (is_bool($input['value']) && $input['value']) {
5242 $more .= ' checked';
5243 }
5244 if (isset($input['disabled'])) {
5245 $more .= ' disabled';
5246 }
5247 $more .= ' /></div>';
5248 $more .= '</div>' . "\n";
5249 } elseif ($input['type'] == 'radio') {
5250 $i = 0;
5251 foreach ($input['values'] as $selkey => $selval) {
5252 $more .= '<div class="tagtr">';
5253 if (isset($input['label'])) {
5254 if ($i == 0) {
5255 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5256 } else {
5257 $more .= '<div clas="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5258 }
5259 }
5260 $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;
5261 if (!empty($input['disabled'])) {
5262 $more .= ' disabled';
5263 }
5264 if (isset($input['default']) && $input['default'] === $selkey) {
5265 $more .= ' checked="checked"';
5266 }
5267 $more .= ' /> ';
5268 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5269 $more .= '</div></div>' . "\n";
5270 $i++;
5271 }
5272 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5273 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5274 $more .= '<div class="tagtd">';
5275 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5276 $h = $m = 0;
5277 if ($input['type'] == 'datetime') {
5278 $h = isset($input['hours']) ? $input['hours'] : 1;
5279 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5280 }
5281 $more .= $this->selectDate($input['value'], $input['name'], $h, $m, 0, '', 1, $addnowlink);
5282 $more .= '</div></div>'."\n";
5283 $formquestion[] = array('name'=>$input['name'].'day');
5284 $formquestion[] = array('name'=>$input['name'].'month');
5285 $formquestion[] = array('name'=>$input['name'].'year');
5286 $formquestion[] = array('name'=>$input['name'].'hour');
5287 $formquestion[] = array('name'=>$input['name'].'min');
5288 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5289 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5290 if (!empty($input['label'])) {
5291 $more .= $input['label'] . '</div><div class="tagtd">';
5292 }
5293 $more .= $input['value'];
5294 $more .= '</div></div>' . "\n";
5295 } elseif ($input['type'] == 'onecolumn') {
5296 $moreonecolumn .= '<div class="margintoponly">';
5297 $moreonecolumn .= $input['value'];
5298 $moreonecolumn .= '</div>' . "\n";
5299 } elseif ($input['type'] == 'hidden') {
5300 // Do nothing more, already added by a previous loop
5301 } elseif ($input['type'] == 'separator') {
5302 $more .= '<br>';
5303 } else {
5304 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5305 }
5306 }
5307 }
5308 $more .= '</div>' . "\n";
5309 $more .= $moreonecolumn;
5310 }
5311
5312 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5313 // 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
5314 // See page product/card.php for example
5315 if (!empty($conf->dol_use_jmobile)) {
5316 $useajax = 0;
5317 }
5318 if (empty($conf->use_javascript_ajax)) {
5319 $useajax = 0;
5320 }
5321
5322 if ($useajax) {
5323 $autoOpen = true;
5324 $dialogconfirm = 'dialog-confirm';
5325 $button = '';
5326 if (!is_numeric($useajax)) {
5327 $button = $useajax;
5328 $useajax = 1;
5329 $autoOpen = false;
5330 $dialogconfirm .= '-' . $button;
5331 }
5332 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5333 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5334
5335 // Add input fields into list of fields to read during submit (inputok and inputko)
5336 if (is_array($formquestion)) {
5337 foreach ($formquestion as $key => $input) {
5338 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5339 // Add name of fields to propagate with the GET when submitting the form with button OK.
5340 if (is_array($input) && isset($input['name'])) {
5341 if (strpos($input['name'], ',') > 0) {
5342 $inputok = array_merge($inputok, explode(',', $input['name']));
5343 } else {
5344 array_push($inputok, $input['name']);
5345 }
5346 }
5347 // Add name of fields to propagate with the GET when submitting the form with button KO.
5348 if (isset($input['inputko']) && $input['inputko'] == 1) {
5349 array_push($inputko, $input['name']);
5350 }
5351 }
5352 }
5353
5354 // Show JQuery confirm box.
5355 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5356 if (is_array($formquestion) && !empty($formquestion['text'])) {
5357 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5358 }
5359 if (!empty($more)) {
5360 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5361 }
5362 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help('', '') . ' ' . $question . '</div>' : '');
5363 $formconfirm .= '</div>' . "\n";
5364
5365 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5366 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5367 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5368 $formconfirm .= 'jQuery(document).ready(function() {
5369 $(function() {
5370 $( "#' . $dialogconfirm . '" ).dialog(
5371 {
5372 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5373 if ($newselectedchoice == 'no') {
5374 $formconfirm .= '
5375 open: function() {
5376 $(this).parent().find("button.ui-button:eq(2)").focus();
5377 },';
5378 }
5379
5380 $jsforcursor = '';
5381 if ($useajax == 1) {
5382 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5383 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5384 }
5385
5386 $postconfirmas = 'GET';
5387
5388 $formconfirm .= '
5389 resizable: false,
5390 height: "' . $height . '",
5391 width: "' . $width . '",
5392 modal: true,
5393 closeOnEscape: false,
5394 buttons: {
5395 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5396 var options = "token=' . urlencode(newToken()) . '";
5397 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5398 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5399 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5400
5401 if (inputok.length > 0) {
5402 $.each(inputok, function(i, inputname) {
5403 var more = "";
5404 var inputvalue;
5405 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5406 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5407 } else {
5408 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5409 inputvalue = $("#" + inputname + more).val();
5410 }
5411 if (typeof inputvalue == "undefined") { inputvalue=""; }
5412 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5413 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5414 });
5415 }
5416 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5417 if (pageyes.length > 0) {';
5418 if ($postconfirmas == 'GET') {
5419 $formconfirm .= 'location.href = urljump;';
5420 } else {
5421 $formconfirm .= $jsforcursor;
5422 $formconfirm .= 'var post = $.post(
5423 pageyes,
5424 options,
5425 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5426 );';
5427 }
5428 $formconfirm .= '
5429 console.log("after post ok");
5430 }
5431 $(this).dialog("close");
5432 },
5433 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5434 var options = "token=' . urlencode(newToken()) . '";
5435 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5436 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5437 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5438 if (inputko.length > 0) {
5439 $.each(inputko, function(i, inputname) {
5440 var more = "";
5441 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5442 var inputvalue = $("#" + inputname + more).val();
5443 if (typeof inputvalue == "undefined") { inputvalue=""; }
5444 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5445 });
5446 }
5447 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5448 //alert(urljump);
5449 if (pageno.length > 0) {';
5450 if ($postconfirmas == 'GET') {
5451 $formconfirm .= 'location.href = urljump;';
5452 } else {
5453 $formconfirm .= $jsforcursor;
5454 $formconfirm .= 'var post = $.post(
5455 pageno,
5456 options,
5457 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5458 );';
5459 }
5460 $formconfirm .= '
5461 console.log("after post ko");
5462 }
5463 $(this).dialog("close");
5464 }
5465 }
5466 }
5467 );
5468
5469 var button = "' . $button . '";
5470 if (button.length > 0) {
5471 $( "#" + button ).click(function() {
5472 $("#' . $dialogconfirm . '").dialog("open");
5473 });
5474 }
5475 });
5476 });
5477 </script>';
5478 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5479 } else {
5480 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5481
5482 if (empty($disableformtag)) {
5483 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftroright">' . "\n";
5484 }
5485
5486 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5487 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5488
5489 $formconfirm .= '<table class="valid centpercent">' . "\n";
5490
5491 // Line title
5492 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5493 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5494 $formconfirm .= '</td></tr>' . "\n";
5495
5496 // Line text
5497 if (is_array($formquestion) && !empty($formquestion['text'])) {
5498 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5499 }
5500
5501 // Line form fields
5502 if ($more) {
5503 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5504 $formconfirm .= $more;
5505 $formconfirm .= '</td></tr>' . "\n";
5506 }
5507
5508 // Line with question
5509 $formconfirm .= '<tr class="valid">';
5510 $formconfirm .= '<td class="valid">' . $question . '</td>';
5511 $formconfirm .= '<td class="valid center">';
5512 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5513 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5514 $formconfirm .= '</td>';
5515 $formconfirm .= '</tr>' . "\n";
5516
5517 $formconfirm .= '</table>' . "\n";
5518
5519 if (empty($disableformtag)) {
5520 $formconfirm .= "</form>\n";
5521 }
5522 $formconfirm .= '<br>';
5523
5524 if (!empty($conf->use_javascript_ajax)) {
5525 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5526 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5527 $formconfirm .= '
5528 $(document).ready(function () {
5529 $(".confirmvalidatebutton").on("click", function() {
5530 console.log("We click on button");
5531 $(this).attr("disabled", "disabled");
5532 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5533 //console.log($(this).closest("form"));
5534 $(this).closest("form").submit();
5535 });
5536 });
5537 ';
5538 $formconfirm .= '</script>' . "\n";
5539 }
5540
5541 $formconfirm .= "<!-- end formconfirm -->\n";
5542 }
5543
5544 return $formconfirm;
5545 }
5546
5547
5548 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5549
5565 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5566 {
5567 // phpcs:enable
5568 global $langs;
5569
5570 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
5571 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
5572
5573 $out = '';
5574
5575 $formproject = new FormProjets($this->db);
5576
5577 $langs->load("project");
5578 if ($htmlname != "none") {
5579 $out .= '<form method="post" action="' . $page . '">';
5580 $out .= '<input type="hidden" name="action" value="classin">';
5581 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5582 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5583 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5584 $out .= '</form>';
5585 } else {
5586 $out .= '<span class="project_head_block">';
5587 if ($selected) {
5588 $projet = new Project($this->db);
5589 $projet->fetch($selected);
5590 $out .= $projet->getNomUrl(0, '', 1);
5591 } else {
5592 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
5593 }
5594 $out .= '</span>';
5595 }
5596
5597 if (empty($nooutput)) {
5598 print $out;
5599 return '';
5600 }
5601 return $out;
5602 }
5603
5604 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5605
5621 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5622 {
5623 // phpcs:enable
5624 global $langs;
5625
5626 $out = '';
5627
5628 if ($htmlname != "none") {
5629 $out .= '<form method="POST" action="' . $page . '">';
5630 $out .= '<input type="hidden" name="action" value="setconditions">';
5631 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5632 if ($type) {
5633 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5634 }
5635 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5636 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5637 $out .= '</form>';
5638 } else {
5639 if ($selected) {
5641 if (isset($this->cache_conditions_paiements[$selected])) {
5642 $label = $this->cache_conditions_paiements[$selected]['label'];
5643
5644 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5645 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5646 }
5647
5648 $out .= $label;
5649 } else {
5650 $langs->load('errors');
5651 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
5652 }
5653 } else {
5654 $out .= '&nbsp;';
5655 }
5656 }
5657
5658 if (empty($nooutput)) {
5659 print $out;
5660 return '';
5661 }
5662 return $out;
5663 }
5664
5665 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5666
5676 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5677 {
5678 // phpcs:enable
5679 global $langs;
5680 if ($htmlname != "none") {
5681 print '<form method="post" action="' . $page . '">';
5682 print '<input type="hidden" name="action" value="setavailability">';
5683 print '<input type="hidden" name="token" value="' . newToken() . '">';
5684 $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5685 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5686 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
5687 print '</form>';
5688 } else {
5689 if ($selected) {
5690 $this->load_cache_availability();
5691 print $this->cache_availability[$selected]['label'];
5692 } else {
5693 print "&nbsp;";
5694 }
5695 }
5696 }
5697
5708 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5709 {
5710 global $langs;
5711 if ($htmlname != "none") {
5712 print '<form method="post" action="' . $page . '">';
5713 print '<input type="hidden" name="action" value="setdemandreason">';
5714 print '<input type="hidden" name="token" value="' . newToken() . '">';
5715 $this->selectInputReason($selected, $htmlname, -1, $addempty);
5716 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5717 print '</form>';
5718 } else {
5719 if ($selected) {
5720 $this->loadCacheInputReason();
5721 foreach ($this->cache_demand_reason as $key => $val) {
5722 if ($val['id'] == $selected) {
5723 print $val['label'];
5724 break;
5725 }
5726 }
5727 } else {
5728 print "&nbsp;";
5729 }
5730 }
5731 }
5732
5733 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5734
5748 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
5749 {
5750 // phpcs:enable
5751 global $langs;
5752
5753 $ret = '';
5754
5755 if ($htmlname != "none") {
5756 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
5757 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
5758 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
5759 if ($type) {
5760 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5761 }
5762 $ret .= '<table class="nobordernopadding">';
5763 $ret .= '<tr><td>';
5764 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
5765 $ret .= '</td>';
5766 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
5767 $ret .= '</tr></table></form>';
5768 } else {
5769 if ($displayhour) {
5770 $ret .= dol_print_date($selected, 'dayhour');
5771 } else {
5772 $ret .= dol_print_date($selected, 'day');
5773 }
5774 }
5775
5776 if (empty($nooutput)) {
5777 print $ret;
5778 }
5779 return $ret;
5780 }
5781
5782
5783 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5784
5795 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
5796 {
5797 // phpcs:enable
5798 global $langs;
5799
5800 if ($htmlname != "none") {
5801 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
5802 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
5803 print '<input type="hidden" name="token" value="' . newToken() . '">';
5804 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
5805 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5806 print '</form>';
5807 } else {
5808 if ($selected) {
5809 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
5810 $theuser = new User($this->db);
5811 $theuser->fetch($selected);
5812 print $theuser->getNomUrl(1);
5813 } else {
5814 print "&nbsp;";
5815 }
5816 }
5817 }
5818
5819
5820 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5821
5835 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
5836 {
5837 // phpcs:enable
5838 global $langs;
5839
5840 $out = '';
5841 if ($htmlname != "none") {
5842 $out .= '<form method="POST" action="' . $page . '">';
5843 $out .= '<input type="hidden" name="action" value="setmode">';
5844 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5845 if ($type) {
5846 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5847 }
5848 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
5849 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5850 $out .= '</form>';
5851 } else {
5852 if ($selected) {
5854 $out .= $this->cache_types_paiements[$selected]['label'];
5855 } else {
5856 $out .= "&nbsp;";
5857 }
5858 }
5859
5860 if ($nooutput) {
5861 return $out;
5862 } else {
5863 print $out;
5864 }
5865 return '';
5866 }
5867
5878 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
5879 {
5880 global $langs;
5881 if ($htmlname != "none") {
5882 print '<form method="POST" action="' . $page . '">';
5883 print '<input type="hidden" name="action" value="settransportmode">';
5884 print '<input type="hidden" name="token" value="' . newToken() . '">';
5885 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
5886 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5887 print '</form>';
5888 } else {
5889 if ($selected) {
5891 print $this->cache_transport_mode[$selected]['label'];
5892 } else {
5893 print "&nbsp;";
5894 }
5895 }
5896 }
5897
5898 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5899
5908 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
5909 {
5910 // phpcs:enable
5911 global $langs;
5912 if ($htmlname != "none") {
5913 print '<form method="POST" action="' . $page . '">';
5914 print '<input type="hidden" name="action" value="setmulticurrencycode">';
5915 print '<input type="hidden" name="token" value="' . newToken() . '">';
5916 print $this->selectMultiCurrency($selected, $htmlname, 0);
5917 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5918 print '</form>';
5919 } else {
5920 dol_include_once('/core/lib/company.lib.php');
5921 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
5922 }
5923 }
5924
5925 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5926
5936 public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
5937 {
5938 // phpcs:enable
5939 global $langs, $mysoc, $conf;
5940
5941 if ($htmlname != "none") {
5942 print '<form method="POST" action="' . $page . '">';
5943 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
5944 print '<input type="hidden" name="token" value="' . newToken() . '">';
5945 print '<input type="text" class="maxwidth100" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
5946 print '<select name="calculation_mode">';
5947 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
5948 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
5949 print '</select> ';
5950 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5951 print '</form>';
5952 } else {
5953 if (!empty($rate)) {
5954 print price($rate, 1, $langs, 0, 0);
5955 if ($currency && $rate != 1) {
5956 print ' &nbsp; (' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')';
5957 }
5958 } else {
5959 print 1;
5960 }
5961 }
5962 }
5963
5964
5965 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5966
5982 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
5983 {
5984 // phpcs:enable
5985 global $conf, $langs;
5986 if ($htmlname != "none") {
5987 print '<form method="post" action="' . $page . '">';
5988 print '<input type="hidden" name="action" value="setabsolutediscount">';
5989 print '<input type="hidden" name="token" value="' . newToken() . '">';
5990 print '<div class="inline-block">';
5991 if (!empty($discount_type)) {
5992 if (!empty($conf->global->FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS)) {
5993 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
5994 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
5995 } else {
5996 $translationKey = 'HasCreditNoteFromSupplier';
5997 }
5998 } else {
5999 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6000 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6001 } else {
6002 $translationKey = 'HasCreditNoteFromSupplier';
6003 }
6004 }
6005 } else {
6006 if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
6007 if (!$filter || $filter == "fk_facture_source IS NULL") {
6008 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
6009 } else {
6010 $translationKey = 'CompanyHasCreditNote';
6011 }
6012 } else {
6013 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6014 $translationKey = 'CompanyHasAbsoluteDiscount';
6015 } else {
6016 $translationKey = 'CompanyHasCreditNote';
6017 }
6018 }
6019 }
6020 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6021 if (empty($hidelist)) {
6022 print ' ';
6023 }
6024 print '</div>';
6025 if (empty($hidelist)) {
6026 print '<div class="inline-block" style="padding-right: 10px">';
6027 $newfilter = 'discount_type=' . intval($discount_type);
6028 if (!empty($discount_type)) {
6029 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6030 } else {
6031 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6032 }
6033 if ($filter) {
6034 $newfilter .= ' AND (' . $filter . ')';
6035 }
6036 // output the combo of discounts
6037 $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
6038 if ($nbqualifiedlines > 0) {
6039 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6040 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6041 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6042 }
6043 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6044 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6045 }
6046
6047 print '>';
6048 }
6049 print '</div>';
6050 }
6051 if ($more) {
6052 print '<div class="inline-block">';
6053 print $more;
6054 print '</div>';
6055 }
6056 print '</form>';
6057 } else {
6058 if ($selected) {
6059 print $selected;
6060 } else {
6061 print "0";
6062 }
6063 }
6064 }
6065
6066
6067 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6068
6078 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6079 {
6080 // phpcs:enable
6081 global $langs, $conf;
6082
6083 if ($htmlname != "none") {
6084 print '<form method="post" action="' . $page . '">';
6085 print '<input type="hidden" name="action" value="set_contact">';
6086 print '<input type="hidden" name="token" value="' . newToken() . '">';
6087 print '<table class="nobordernopadding">';
6088 print '<tr><td>';
6089 print $this->selectcontacts($societe->id, $selected, $htmlname);
6090 $num = $this->num;
6091 if ($num == 0) {
6092 $addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6093 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&amp;action=create&amp;backtoreferer=1">' . $addcontact . '</a>';
6094 }
6095 print '</td>';
6096 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6097 print '</tr></table></form>';
6098 } else {
6099 if ($selected) {
6100 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6101 $contact = new Contact($this->db);
6102 $contact->fetch($selected);
6103 print $contact->getFullName($langs);
6104 } else {
6105 print "&nbsp;";
6106 }
6107 }
6108 }
6109
6110 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6111
6128 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6129 {
6130 // phpcs:enable
6131 global $langs;
6132
6133 $out = '';
6134 if ($htmlname != "none") {
6135 $out .= '<form method="post" action="' . $page . '">';
6136 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6137 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6138 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6139 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6140 $out .= '</form>';
6141 } else {
6142 if ($selected) {
6143 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6144 $soc = new Societe($this->db);
6145 $soc->fetch($selected);
6146 $out .= $soc->getNomUrl(0, '');
6147 } else {
6148 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6149 }
6150 }
6151
6152 if ($nooutput) {
6153 return $out;
6154 } else {
6155 print $out;
6156 }
6157
6158 return '';
6159 }
6160
6161 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6162
6171 public function select_currency($selected = '', $htmlname = 'currency_id')
6172 {
6173 // phpcs:enable
6174 print $this->selectCurrency($selected, $htmlname);
6175 }
6176
6186 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6187 {
6188 global $conf, $langs, $user;
6189
6190 $langs->loadCacheCurrencies('');
6191
6192 $out = '';
6193
6194 if ($selected == 'euro' || $selected == 'euros') {
6195 $selected = 'EUR'; // Pour compatibilite
6196 }
6197
6198 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6199 if ($useempty) {
6200 $out .= '<option value="-1" selected></option>';
6201 }
6202 foreach ($langs->cache_currencies as $code_iso => $currency) {
6203 $labeltoshow = $currency['label'];
6204 if ($mode == 1) {
6205 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6206 } else {
6207 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6208 }
6209
6210 if ($selected && $selected == $code_iso) {
6211 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6212 } else {
6213 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6214 }
6215 $out .= $labeltoshow;
6216 $out .= '</option>';
6217 }
6218 $out .= '</select>';
6219 if ($user->admin) {
6220 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6221 }
6222
6223 // Make select dynamic
6224 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6225 $out .= ajax_combobox($htmlname);
6226
6227 return $out;
6228 }
6229
6242 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6243 {
6244 global $conf, $langs;
6245
6246 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6247
6248 $TCurrency = array();
6249
6250 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6251 $sql .= " WHERE entity IN ('" . getEntity('mutlicurrency') . "')";
6252 if ($filter) {
6253 $sql .= " AND " . $filter;
6254 }
6255 $resql = $this->db->query($sql);
6256 if ($resql) {
6257 while ($obj = $this->db->fetch_object($resql)) {
6258 $TCurrency[$obj->code] = $obj->code;
6259 }
6260 }
6261
6262 $out = '';
6263 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6264 if ($useempty) {
6265 $out .= '<option value="">&nbsp;</option>';
6266 }
6267 // If company current currency not in table, we add it into list. Should always be available.
6268 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6269 $TCurrency[$conf->currency] = $conf->currency;
6270 }
6271 if (count($TCurrency) > 0) {
6272 foreach ($langs->cache_currencies as $code_iso => $currency) {
6273 if (isset($TCurrency[$code_iso])) {
6274 if (!empty($selected) && $selected == $code_iso) {
6275 $out .= '<option value="' . $code_iso . '" selected="selected">';
6276 } else {
6277 $out .= '<option value="' . $code_iso . '">';
6278 }
6279
6280 $out .= $currency['label'];
6281 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6282 $out .= '</option>';
6283 }
6284 }
6285 }
6286
6287 $out .= '</select>';
6288
6289 // Make select dynamic
6290 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6291 $out .= ajax_combobox($htmlname);
6292
6293 return $out;
6294 }
6295
6296 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6297
6304 public function load_cache_vatrates($country_code)
6305 {
6306 // phpcs:enable
6307 global $langs, $user;
6308
6309 $num = count($this->cache_vatrates);
6310 if ($num > 0) {
6311 return $num; // Cache already loaded
6312 }
6313
6314 dol_syslog(__METHOD__, LOG_DEBUG);
6315
6316 $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6317 $sql .= " FROM " . $this->db->prefix() . "c_tva as t, " . $this->db->prefix() . "c_country as c";
6318 $sql .= " WHERE t.fk_pays = c.rowid";
6319 $sql .= " AND t.active > 0";
6320 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6321 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6322
6323 $resql = $this->db->query($sql);
6324 if ($resql) {
6325 $num = $this->db->num_rows($resql);
6326 if ($num) {
6327 for ($i = 0; $i < $num; $i++) {
6328 $obj = $this->db->fetch_object($resql);
6329 $this->cache_vatrates[$i]['rowid'] = $obj->rowid;
6330 $this->cache_vatrates[$i]['code'] = $obj->code;
6331 $this->cache_vatrates[$i]['txtva'] = $obj->taux;
6332 $this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
6333 $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1;
6334 $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type;
6335 $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2;
6336 $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type;
6337
6338 $this->cache_vatrates[$i]['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6339 $this->cache_vatrates[$i]['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
6340 $positiverates = '';
6341 if ($obj->taux) {
6342 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6343 }
6344 if ($obj->localtax1) {
6345 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6346 }
6347 if ($obj->localtax2) {
6348 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6349 }
6350 if (empty($positiverates)) {
6351 $positiverates = '0';
6352 }
6353 $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6354 }
6355
6356 return $num;
6357 } else {
6358 $this->error = '<span class="error">';
6359 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6360 $reg = array();
6361 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6362 $langs->load("errors");
6363 $new_country_code = $reg[1];
6364 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid');
6365 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6366 }
6367 $this->error .= '</span>';
6368 return -1;
6369 }
6370 } else {
6371 $this->error = '<span class="error">' . $this->db->error() . '</span>';
6372 return -2;
6373 }
6374 }
6375
6376 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6377
6399 public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
6400 {
6401 // phpcs:enable
6402 global $langs, $conf, $mysoc;
6403
6404 $langs->load('errors');
6405
6406 $return = '';
6407
6408 // Define defaultnpr, defaultttx and defaultcode
6409 $defaultnpr = ($info_bits & 0x01);
6410 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6411 $defaulttx = str_replace('*', '', $selectedrate);
6412 $defaultcode = '';
6413 $reg = array();
6414 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6415 $defaultcode = $reg[1];
6416 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6417 }
6418 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6419
6420 // Check parameters
6421 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6422 if ($societe_vendeuse->id == $mysoc->id) {
6423 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6424 } else {
6425 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6426 }
6427 return $return;
6428 }
6429
6430 //var_dump($societe_acheteuse);
6431 //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";
6432 //exit;
6433
6434 // Define list of countries to use to search VAT rates to show
6435 // First we defined code_country to use to find list
6436 if (is_object($societe_vendeuse)) {
6437 $code_country = "'" . $societe_vendeuse->country_code . "'";
6438 } else {
6439 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6440 }
6441 if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) { // If option to have vat for end customer for services is on
6442 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6443 if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()))) {
6444 // We also add the buyer country code
6445 if (is_numeric($type)) {
6446 if ($type == 1) { // We know product is a service
6447 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6448 }
6449 } elseif (!$idprod) { // We don't know type of product
6450 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6451 } else {
6452 $prodstatic = new Product($this->db);
6453 $prodstatic->fetch($idprod);
6454 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6455 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6456 }
6457 }
6458 }
6459 }
6460
6461 // Now we get list
6462 $num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6463
6464 if ($num > 0) {
6465 // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6466 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6467 $tmpthirdparty = new Societe($this->db);
6468
6469 $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6470 $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6471
6472 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6473 $defaultcode = $reg[1];
6474 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6475 }
6476 if (empty($defaulttx)) {
6477 $defaultnpr = 0;
6478 }
6479 }
6480
6481 // If we fails to find a default vat rate, we take the last one in list
6482 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
6483 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6484 if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6485 // We take the last one found in list
6486 $defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
6487 } else {
6488 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
6489 $defaulttx = '';
6490 if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') {
6491 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6492 }
6493 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6494 $defaultcode = $reg[1];
6495 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6496 }
6497 }
6498 }
6499
6500 // Disabled if seller is not subject to VAT
6501 $disabled = false;
6502 $title = '';
6503 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6504 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6505 // of using supplier invoices (this is a very bad idea !)
6506 if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT)) {
6507 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
6508 $disabled = true;
6509 }
6510 }
6511
6512 if (!$options_only) {
6513 $return .= '<select class="flat minwidth50imp maxwidth100" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
6514 }
6515
6516 $selectedfound = false;
6517 foreach ($this->cache_vatrates as $rate) {
6518 // Keep only 0 if seller is not subject to VAT
6519 if ($disabled && $rate['txtva'] != 0) {
6520 continue;
6521 }
6522
6523 // Define key to use into select list
6524 $key = $rate['txtva'];
6525 $key .= $rate['nprtva'] ? '*' : '';
6526 if ($mode > 0 && $rate['code']) {
6527 $key .= ' (' . $rate['code'] . ')';
6528 }
6529 if ($mode < 0) {
6530 $key = $rate['rowid'];
6531 }
6532
6533 $return .= '<option value="' . $key . '"';
6534 if (!$selectedfound) {
6535 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6536 if ($defaultcode == $rate['code']) {
6537 $return .= ' selected';
6538 $selectedfound = true;
6539 }
6540 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6541 $return .= ' selected';
6542 $selectedfound = true;
6543 }
6544 }
6545 $return .= '>';
6546
6547 // Show label of VAT
6548 if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES)) {
6549 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
6550 $return .= $rate['labelpositiverates'];
6551 } else {
6552 // Simple label
6553 $return .= vatrate($rate['label']);
6554 }
6555
6556 //$return.=($rate['code']?' '.$rate['code']:'');
6557 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
6558
6559 $return .= '</option>';
6560 }
6561
6562 if (!$options_only) {
6563 $return .= '</select>';
6564 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
6565 }
6566 } else {
6567 $return .= $this->error;
6568 }
6569
6570 $this->num = $num;
6571 return $return;
6572 }
6573
6574
6575 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6576
6601 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 = '', $addplusone = '', $adddateof = '')
6602 {
6603 // phpcs:enable
6604 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
6605 if (!empty($nooutput)) {
6606 return $retstring;
6607 }
6608 print $retstring;
6609
6610 return '';
6611 }
6612
6628 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
6629 {
6630 global $langs;
6631
6632 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6633 if ($forcenewline) {
6634 $ret .= '<br>';
6635 }
6636 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6637 return $ret;
6638 }
6639
6667 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')
6668 {
6669 global $conf, $langs;
6670
6671 if ($gm === 'auto') {
6672 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
6673 }
6674
6675 $retstring = '';
6676
6677 if ($prefix == '') {
6678 $prefix = 're';
6679 }
6680 if ($h == '') {
6681 $h = 0;
6682 }
6683 if ($m == '') {
6684 $m = 0;
6685 }
6686 $emptydate = 0;
6687 $emptyhours = 0;
6688 if ($stepminutes <= 0 || $stepminutes > 30) {
6689 $stepminutes = 1;
6690 }
6691 if ($empty == 1) {
6692 $emptydate = 1;
6693 $emptyhours = 1;
6694 }
6695 if ($empty == 2) {
6696 $emptydate = 0;
6697 $emptyhours = 1;
6698 }
6699 $orig_set_time = $set_time;
6700
6701 if ($set_time === '' && $emptydate == 0) {
6702 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
6703 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
6704 $set_time = dol_now($gm);
6705 } else {
6706 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
6707 }
6708 }
6709
6710 // Analysis of the pre-selection date
6711 $reg = array();
6712 $shour = '';
6713 $smin = '';
6714 $ssec = '';
6715 if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
6716 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
6717 $syear = (!empty($reg[1]) ? $reg[1] : '');
6718 $smonth = (!empty($reg[2]) ? $reg[2] : '');
6719 $sday = (!empty($reg[3]) ? $reg[3] : '');
6720 $shour = (!empty($reg[4]) ? $reg[4] : '');
6721 $smin = (!empty($reg[5]) ? $reg[5] : '');
6722 } elseif (strval($set_time) != '' && $set_time != -1) {
6723 // set_time est un timestamps (0 possible)
6724 $syear = dol_print_date($set_time, "%Y", $gm);
6725 $smonth = dol_print_date($set_time, "%m", $gm);
6726 $sday = dol_print_date($set_time, "%d", $gm);
6727 if ($orig_set_time != '') {
6728 $shour = dol_print_date($set_time, "%H", $gm);
6729 $smin = dol_print_date($set_time, "%M", $gm);
6730 $ssec = dol_print_date($set_time, "%S", $gm);
6731 }
6732 } else {
6733 // Date est '' ou vaut -1
6734 $syear = '';
6735 $smonth = '';
6736 $sday = '';
6737 $shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
6738 $smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
6739 $ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
6740 }
6741 if ($h == 3) {
6742 $shour = '';
6743 }
6744 if ($m == 3) {
6745 $smin = '';
6746 }
6747
6748 $nowgmt = dol_now('gmt');
6749 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
6750
6751 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
6752 $usecalendar = 'combo';
6753 if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
6754 $usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
6755 }
6756
6757 if ($d) {
6758 // Show date with popup
6759 if ($usecalendar != 'combo') {
6760 $formated_date = '';
6761 //print "e".$set_time." t ".$conf->format_date_short;
6762 if (strval($set_time) != '' && $set_time != -1) {
6763 //$formated_date=dol_print_date($set_time,$conf->format_date_short);
6764 $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6765 }
6766
6767 // Calendrier popup version eldy
6768 if ($usecalendar == "eldy") {
6769 // Input area to enter date manually
6770 $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate" maxlength="11" value="' . $formated_date . '"';
6771 $retstring .= ($disabled ? ' disabled' : '');
6772 $retstring .= ' onChange="dpChangeDay(\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6773 $retstring .= '>';
6774
6775 // Icon calendar
6776 $retstringbuttom = '';
6777 if (!$disabled) {
6778 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
6779 $base = DOL_URL_ROOT . '/core/';
6780 $retstringbuttom .= ' onClick="showDP(\'' . $base . '\',\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\',\'' . $langs->defaultlang . '\');"';
6781 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
6782 } else {
6783 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
6784 }
6785 $retstring = $retstringbuttom . $retstring;
6786
6787 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
6788 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
6789 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
6790 } elseif ($usecalendar == 'jquery') {
6791 if (!$disabled) {
6792 // Output javascript for datepicker
6793 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (date('Y') - 100));
6794 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (date('Y') + 100));
6795
6796 $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
6797 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
6798 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
6799 autoclose: true,
6800 todayHighlight: true,
6801 yearRange: '" . $minYear . ":" . $maxYear . "',";
6802 if (!empty($conf->dol_use_jmobile)) {
6803 $retstring .= "
6804 beforeShow: function (input, datePicker) {
6805 input.disabled = true;
6806 },
6807 onClose: function (dateText, datePicker) {
6808 this.disabled = false;
6809 },
6810 ";
6811 }
6812 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
6813 if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS)) {
6814 $retstring .= "
6815 showOn: 'button', /* both has problem with autocompletion */
6816 buttonImage: '" . DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png',
6817 buttonImageOnly: true";
6818 }
6819 $retstring .= "
6820 }) });";
6821 $retstring .= "</script>";
6822 }
6823
6824 // Zone de saisie manuelle de la date
6825 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
6826 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6827 $retstring .= ($disabled ? ' disabled' : '');
6828 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
6829 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6830 $retstring .= '>';
6831
6832 // Icone calendrier
6833 if (!$disabled) {
6834 /* Not required. Managed by option buttonImage of jquery
6835 $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
6836 $retstring.='<script nonce="'.getNonce().'" type="text/javascript">';
6837 $retstring.="jQuery(document).ready(function() {";
6838 $retstring.=' jQuery("#'.$prefix.'id").click(function() {';
6839 $retstring.=" jQuery('#".$prefix."').focus();";
6840 $retstring.=' });';
6841 $retstring.='});';
6842 $retstring.="</script>";*/
6843 } else {
6844 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
6845 $retsring = $retstringbutton . $retstring;
6846 }
6847
6848 $retstring .= '</div>';
6849 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
6850 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
6851 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
6852 } else {
6853 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
6854 }
6855 } else {
6856 // Show date with combo selects
6857 // Day
6858 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
6859
6860 if ($emptydate || $set_time == -1) {
6861 $retstring .= '<option value="0" selected>&nbsp;</option>';
6862 }
6863
6864 for ($day = 1; $day <= 31; $day++) {
6865 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
6866 }
6867
6868 $retstring .= "</select>";
6869
6870 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
6871 if ($emptydate || $set_time == -1) {
6872 $retstring .= '<option value="0" selected>&nbsp;</option>';
6873 }
6874
6875 // Month
6876 for ($month = 1; $month <= 12; $month++) {
6877 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
6878 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
6879 $retstring .= "</option>";
6880 }
6881 $retstring .= "</select>";
6882
6883 // Year
6884 if ($emptydate || $set_time == -1) {
6885 $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 . '">';
6886 } else {
6887 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
6888
6889 for ($year = $syear - 10; $year < $syear + 10; $year++) {
6890 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
6891 }
6892 $retstring .= "</select>\n";
6893 }
6894 }
6895 }
6896
6897 if ($d && $h) {
6898 $retstring .= ($h == 2 ? '<br>' : ' ');
6899 $retstring .= '<span class="nowraponall">';
6900 }
6901
6902 if ($h) {
6903 $hourstart = 0;
6904 $hourend = 24;
6905 if ($openinghours != '') {
6906 $openinghours = explode(',', $openinghours);
6907 $hourstart = $openinghours[0];
6908 $hourend = $openinghours[1];
6909 if ($hourend < $hourstart) {
6910 $hourend = $hourstart;
6911 }
6912 }
6913 // Show hour
6914 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
6915 if ($emptyhours) {
6916 $retstring .= '<option value="-1">&nbsp;</option>';
6917 }
6918 for ($hour = $hourstart; $hour < $hourend; $hour++) {
6919 if (strlen($hour) < 2) {
6920 $hour = "0" . $hour;
6921 }
6922 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
6923 //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
6924 $retstring .= '</option>';
6925 }
6926 $retstring .= '</select>';
6927 //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
6928 if ($m) {
6929 $retstring .= ":";
6930 }
6931 }
6932
6933 if ($m) {
6934 // Show minutes
6935 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
6936 if ($emptyhours) {
6937 $retstring .= '<option value="-1">&nbsp;</option>';
6938 }
6939 for ($min = 0; $min < 60; $min += $stepminutes) {
6940 if (strlen($min) < 2) {
6941 $min = "0" . $min;
6942 }
6943 $retstring .= '<option value="' . $min . '"' . (($min == $smin) ? ' selected' : '') . '>' . $min . (empty($conf->dol_optimize_smallscreen) ? '' : '') . '</option>';
6944 }
6945 $retstring .= '</select>';
6946
6947 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
6948 }
6949
6950 if ($d && $h) {
6951 $retstring .= '</span>';
6952 }
6953
6954 // Add a "Now" link
6955 if (!empty($conf->use_javascript_ajax) && $addnowlink) {
6956 // Script which will be inserted in the onClick of the "Now" link
6957 $reset_scripts = "";
6958 if ($addnowlink == 2) { // local computer time
6959 // pad add leading 0 on numbers
6960 $reset_scripts .= "Number.prototype.pad = function(size) {
6961 var s = String(this);
6962 while (s.length < (size || 2)) {s = '0' + s;}
6963 return s;
6964 };
6965 var d = new Date();";
6966 }
6967
6968 // Generate the date part, depending on the use or not of the javascript calendar
6969 if ($addnowlink == 1) { // server time expressed in user time setup
6970 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
6971 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
6972 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
6973 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
6974 } elseif ($addnowlink == 2) {
6975 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
6976 * This break application for foreign languages.
6977 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
6978 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
6979 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
6980 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
6981 */
6982 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
6983 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
6984 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
6985 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
6986 }
6987 /*if ($usecalendar == "eldy")
6988 {
6989 $base=DOL_URL_ROOT.'/core/';
6990 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
6991 }
6992 else
6993 {
6994 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
6995 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
6996 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
6997 }*/
6998 // Update the hour part
6999 if ($h) {
7000 if ($fullday) {
7001 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7002 }
7003 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7004 if ($addnowlink == 1) {
7005 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7006 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7007 } elseif ($addnowlink == 2) {
7008 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7009 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7010 }
7011
7012 if ($fullday) {
7013 $reset_scripts .= ' } ';
7014 }
7015 }
7016 // Update the minute part
7017 if ($m) {
7018 if ($fullday) {
7019 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7020 }
7021 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7022 if ($addnowlink == 1) {
7023 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7024 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7025 } elseif ($addnowlink == 2) {
7026 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7027 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7028 }
7029 if ($fullday) {
7030 $reset_scripts .= ' } ';
7031 }
7032 }
7033 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7034 if ($reset_scripts && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
7035 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7036 $retstring .= $langs->trans("Now");
7037 $retstring .= '</button> ';
7038 }
7039 }
7040
7041 // Add a "Plus one hour" link
7042 if ($conf->use_javascript_ajax && $addplusone) {
7043 // Script which will be inserted in the onClick of the "Add plusone" link
7044 $reset_scripts = "";
7045
7046 // Generate the date part, depending on the use or not of the javascript calendar
7047 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7048 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7049 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7050 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7051 // Update the hour part
7052 if ($h) {
7053 if ($fullday) {
7054 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7055 }
7056 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7057 if ($fullday) {
7058 $reset_scripts .= ' } ';
7059 }
7060 }
7061 // Update the minute part
7062 if ($m) {
7063 if ($fullday) {
7064 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7065 }
7066 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7067 if ($fullday) {
7068 $reset_scripts .= ' } ';
7069 }
7070 }
7071 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7072 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7073 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7074 $retstring .= $langs->trans("DateStartPlusOne");
7075 $retstring .= '</button> ';
7076 }
7077 }
7078
7079 // Add a link to set data
7080 if ($conf->use_javascript_ajax && !empty($adddateof)) {
7081 if (!is_array($adddateof)) {
7082 $arrayofdateof = array(array('adddateof'=>$adddateof, 'labeladddateof'=>$labeladddateof));
7083 } else {
7084 $arrayofdateof = $adddateof;
7085 }
7086 foreach ($arrayofdateof as $valuedateof) {
7087 $tmpadddateof = $valuedateof['adddateof'] != '' ? $valuedateof['adddateof'] : 0;
7088 $tmplabeladddateof = $valuedateof['labeladddateof'];
7089 $tmparray = dol_getdate($tmpadddateof);
7090 if (empty($tmplabeladddateof)) {
7091 $tmplabeladddateof = $langs->trans("DateInvoice");
7092 }
7093 $reset_scripts = 'console.log(\'Click on now link\'); ';
7094 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7095 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7096 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7097 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7098 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7099 }
7100 }
7101
7102 return $retstring;
7103 }
7104
7113 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7114 {
7115 global $langs;
7116
7117 $TDurationTypes = array(
7118 'y' => $langs->trans('Years'),
7119 'm' => $langs->trans('Month'),
7120 'w' => $langs->trans('Weeks'),
7121 'd' => $langs->trans('Days'),
7122 'h' => $langs->trans('Hours'),
7123 'i' => $langs->trans('Minutes')
7124 );
7125
7126 // Removed undesired duration types
7127 foreach ($excludetypes as $value) {
7128 unset($TDurationTypes[$value]);
7129 }
7130
7131 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7132 foreach ($TDurationTypes as $key => $typeduration) {
7133 $retstring .= '<option value="' . $key . '"';
7134 if ($key == $selected) {
7135 $retstring .= " selected";
7136 }
7137 $retstring .= ">" . $typeduration . "</option>";
7138 }
7139 $retstring .= "</select>";
7140
7141 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7142
7143 return $retstring;
7144 }
7145
7146 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7147
7161 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7162 {
7163 // phpcs:enable
7164 global $langs;
7165
7166 $retstring = '<span class="nowraponall">';
7167
7168 $hourSelected = '';
7169 $minSelected = '';
7170
7171 // Hours
7172 if ($iSecond != '') {
7173 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7174
7175 $hourSelected = convertSecondToTime($iSecond, 'allhour');
7176 $minSelected = convertSecondToTime($iSecond, 'min');
7177 }
7178
7179 if ($typehour == 'select') {
7180 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7181 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7182 $retstring .= '<option value="' . $hour . '"';
7183 if (is_numeric($hourSelected) && $hourSelected == $hour) {
7184 $retstring .= " selected";
7185 }
7186 $retstring .= ">" . $hour . "</option>";
7187 }
7188 $retstring .= "</select>";
7189 } elseif ($typehour == 'text' || $typehour == 'textselect') {
7190 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7191 } else {
7192 return 'BadValueForParameterTypeHour';
7193 }
7194
7195 if ($typehour != 'text') {
7196 $retstring .= ' ' . $langs->trans('HourShort');
7197 } else {
7198 $retstring .= '<span class="">:</span>';
7199 }
7200
7201 // Minutes
7202 if ($minunderhours) {
7203 $retstring .= '<br>';
7204 } else {
7205 if ($typehour != 'text') {
7206 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7207 }
7208 }
7209
7210 if ($typehour == 'select' || $typehour == 'textselect') {
7211 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7212 for ($min = 0; $min <= 55; $min = $min + 5) {
7213 $retstring .= '<option value="' . $min . '"';
7214 if (is_numeric($minSelected) && $minSelected == $min) {
7215 $retstring .= ' selected';
7216 }
7217 $retstring .= '>' . $min . '</option>';
7218 }
7219 $retstring .= "</select>";
7220 } elseif ($typehour == 'text') {
7221 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7222 }
7223
7224 if ($typehour != 'text') {
7225 $retstring .= ' ' . $langs->trans('MinuteShort');
7226 }
7227
7228 $retstring .= "</span>";
7229
7230 if (!empty($nooutput)) {
7231 return $retstring;
7232 }
7233
7234 print $retstring;
7235
7236 return '';
7237 }
7238
7258 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)
7259 {
7260 global $langs, $conf;
7261
7262 $out = '';
7263
7264 // check parameters
7265 if (is_null($ajaxoptions)) $ajaxoptions = array();
7266
7267 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7268 $placeholder = '';
7269
7270 if ($selected && empty($selected_input_value)) {
7271 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7272 $tickettmpselect = new Ticket($this->db);
7273 $tickettmpselect->fetch($selected);
7274 $selected_input_value = $tickettmpselect->ref;
7275 unset($tickettmpselect);
7276 }
7277
7278 $urloption = '';
7279 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7280
7281 if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel") . ' : ';
7282 elseif ($hidelabel > 1) {
7283 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7284 if ($hidelabel == 2) {
7285 $out .= img_picto($langs->trans("Search"), 'search');
7286 }
7287 }
7288 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
7289 if ($hidelabel == 3) {
7290 $out .= img_picto($langs->trans("Search"), 'search');
7291 }
7292 } else {
7293 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7294 }
7295
7296 if (empty($nooutput)) {
7297 print $out;
7298 } else {
7299 return $out;
7300 }
7301 return '';
7302 }
7303
7304
7321 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7322 {
7323 global $langs, $conf;
7324
7325 $out = '';
7326 $outarray = array();
7327
7328 $selectFields = " p.rowid, p.ref, p.message";
7329
7330 $sql = "SELECT ";
7331 $sql .= $selectFields;
7332 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7333 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7334
7335 // Add criteria on ref/label
7336 if ($filterkey != '') {
7337 $sql .= ' AND (';
7338 $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7339 // For natural search
7340 $scrit = explode(' ', $filterkey);
7341 $i = 0;
7342 if (count($scrit) > 1) $sql .= "(";
7343 foreach ($scrit as $crit) {
7344 if ($i > 0) $sql .= " AND ";
7345 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7346 $sql .= ")";
7347 $i++;
7348 }
7349 if (count($scrit) > 1) $sql .= ")";
7350 $sql .= ')';
7351 }
7352
7353 $sql .= $this->db->plimit($limit, 0);
7354
7355 // Build output string
7356 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7357 $result = $this->db->query($sql);
7358 if ($result) {
7359 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7360 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7361
7362 $num = $this->db->num_rows($result);
7363
7364 $events = null;
7365
7366 if (!$forcecombo) {
7367 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7368 $out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
7369 }
7370
7371 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7372
7373 $textifempty = '';
7374 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7375 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7376 if (!empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7377 if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7378 else $textifempty .= $langs->trans("All");
7379 } else {
7380 if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7381 }
7382 if ($showempty) $out .= '<option value="0" selected>' . $textifempty . '</option>';
7383
7384 $i = 0;
7385 while ($num && $i < $num) {
7386 $opt = '';
7387 $optJson = array();
7388 $objp = $this->db->fetch_object($result);
7389
7390 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7391 // Add new entry
7392 // "key" value of json key array is used by jQuery automatically as selected value
7393 // "label" value of json key array is used by jQuery automatically as text for combo box
7394 $out .= $opt;
7395 array_push($outarray, $optJson);
7396
7397 $i++;
7398 }
7399
7400 $out .= '</select>';
7401
7402 $this->db->free($result);
7403
7404 if (empty($outputmode)) {
7405 return $out;
7406 }
7407 return $outarray;
7408 } else {
7409 dol_print_error($this->db);
7410 }
7411
7412 return array();
7413 }
7414
7426 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7427 {
7428 $outkey = '';
7429 $outref = '';
7430 $outtype = '';
7431
7432 $outkey = $objp->rowid;
7433 $outref = $objp->ref;
7434 $outtype = $objp->fk_product_type;
7435
7436 $opt = '<option value="' . $objp->rowid . '"';
7437 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7438 $opt .= '>';
7439 $opt .= $objp->ref;
7440 $objRef = $objp->ref;
7441 if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7442
7443 $opt .= "</option>\n";
7444 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7445 }
7446
7466 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)
7467 {
7468 global $langs, $conf;
7469
7470 $out = '';
7471
7472 // check parameters
7473 if (is_null($ajaxoptions)) $ajaxoptions = array();
7474
7475 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7476 $placeholder = '';
7477
7478 if ($selected && empty($selected_input_value)) {
7479 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7480 $projecttmpselect = new Project($this->db);
7481 $projecttmpselect->fetch($selected);
7482 $selected_input_value = $projecttmpselect->ref;
7483 unset($projecttmpselect);
7484 }
7485
7486 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7487
7488 if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel") . ' : ';
7489 elseif ($hidelabel > 1) {
7490 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7491 if ($hidelabel == 2) {
7492 $out .= img_picto($langs->trans("Search"), 'search');
7493 }
7494 }
7495 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
7496 if ($hidelabel == 3) {
7497 $out .= img_picto($langs->trans("Search"), 'search');
7498 }
7499 } else {
7500 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7501 }
7502
7503 if (empty($nooutput)) {
7504 print $out;
7505 } else {
7506 return $out;
7507 }
7508 return '';
7509 }
7510
7527 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7528 {
7529 global $langs, $conf;
7530
7531 $out = '';
7532 $outarray = array();
7533
7534 $selectFields = " p.rowid, p.ref";
7535
7536 $sql = "SELECT ";
7537 $sql .= $selectFields;
7538 $sql .= " FROM " . $this->db->prefix() . "projet as p";
7539 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
7540
7541 // Add criteria on ref/label
7542 if ($filterkey != '') {
7543 $sql .= ' AND (';
7544 $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7545 // For natural search
7546 $scrit = explode(' ', $filterkey);
7547 $i = 0;
7548 if (count($scrit) > 1) $sql .= "(";
7549 foreach ($scrit as $crit) {
7550 if ($i > 0) $sql .= " AND ";
7551 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7552 $sql .= "";
7553 $i++;
7554 }
7555 if (count($scrit) > 1) $sql .= ")";
7556 $sql .= ')';
7557 }
7558
7559 $sql .= $this->db->plimit($limit, 0);
7560
7561 // Build output string
7562 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
7563 $result = $this->db->query($sql);
7564 if ($result) {
7565 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7566 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
7567
7568 $num = $this->db->num_rows($result);
7569
7570 $events = null;
7571
7572 if (!$forcecombo) {
7573 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7574 $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7575 }
7576
7577 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7578
7579 $textifempty = '';
7580 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7581 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7582 if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7583 if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7584 else $textifempty .= $langs->trans("All");
7585 } else {
7586 if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7587 }
7588 if ($showempty) $out .= '<option value="0" selected>' . $textifempty . '</option>';
7589
7590 $i = 0;
7591 while ($num && $i < $num) {
7592 $opt = '';
7593 $optJson = array();
7594 $objp = $this->db->fetch_object($result);
7595
7596 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
7597 // Add new entry
7598 // "key" value of json key array is used by jQuery automatically as selected value
7599 // "label" value of json key array is used by jQuery automatically as text for combo box
7600 $out .= $opt;
7601 array_push($outarray, $optJson);
7602
7603 $i++;
7604 }
7605
7606 $out .= '</select>';
7607
7608 $this->db->free($result);
7609
7610 if (empty($outputmode)) {
7611 return $out;
7612 }
7613 return $outarray;
7614 } else {
7615 dol_print_error($this->db);
7616 }
7617
7618 return array();
7619 }
7620
7632 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7633 {
7634 $outkey = '';
7635 $outref = '';
7636 $outtype = '';
7637
7638 $label = $objp->label;
7639
7640 $outkey = $objp->rowid;
7641 $outref = $objp->ref;
7642 $outlabel = $objp->label;
7643 $outtype = $objp->fk_product_type;
7644
7645 $opt = '<option value="' . $objp->rowid . '"';
7646 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7647 $opt .= '>';
7648 $opt .= $objp->ref;
7649 $objRef = $objp->ref;
7650 if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7651
7652 $opt .= "</option>\n";
7653 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7654 }
7655
7656
7676 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)
7677 {
7678 global $langs, $conf;
7679
7680 $out = '';
7681
7682 // check parameters
7683 if (is_null($ajaxoptions)) $ajaxoptions = array();
7684
7685 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7686 $placeholder = '';
7687 $urloption = '';
7688
7689 if ($selected && empty($selected_input_value)) {
7690 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
7691 $adherenttmpselect = new Adherent($this->db);
7692 $adherenttmpselect->fetch($selected);
7693 $selected_input_value = $adherenttmpselect->ref;
7694 unset($adherenttmpselect);
7695 }
7696
7697 $urloption = '';
7698
7699 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7700
7701 if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel") . ' : ';
7702 elseif ($hidelabel > 1) {
7703 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7704 if ($hidelabel == 2) {
7705 $out .= img_picto($langs->trans("Search"), 'search');
7706 }
7707 }
7708 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
7709 if ($hidelabel == 3) {
7710 $out .= img_picto($langs->trans("Search"), 'search');
7711 }
7712 } else {
7713 $filterkey = '';
7714
7715 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
7716 }
7717
7718 if (empty($nooutput)) {
7719 print $out;
7720 } else {
7721 return $out;
7722 }
7723 return '';
7724 }
7725
7742 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7743 {
7744 global $langs, $conf;
7745
7746 $out = '';
7747 $outarray = array();
7748
7749 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
7750
7751 $sql = "SELECT ";
7752 $sql .= $selectFields;
7753 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
7754 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
7755
7756 // Add criteria on ref/label
7757 if ($filterkey != '') {
7758 $sql .= ' AND (';
7759 $prefix = empty($conf->global->MEMBER_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7760 // For natural search
7761 $scrit = explode(' ', $filterkey);
7762 $i = 0;
7763 if (count($scrit) > 1) $sql .= "(";
7764 foreach ($scrit as $crit) {
7765 if ($i > 0) $sql .= " AND ";
7766 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7767 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
7768 $i++;
7769 }
7770 if (count($scrit) > 1) $sql .= ")";
7771 $sql .= ')';
7772 }
7773 if ($status != -1) {
7774 $sql .= ' AND statut = ' . ((int) $status);
7775 }
7776 $sql .= $this->db->plimit($limit, 0);
7777
7778 // Build output string
7779 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
7780 $result = $this->db->query($sql);
7781 if ($result) {
7782 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
7783 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
7784
7785 $num = $this->db->num_rows($result);
7786
7787 $events = null;
7788
7789 if (!$forcecombo) {
7790 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7791 $out .= ajax_combobox($htmlname, $events, !empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT) ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
7792 }
7793
7794 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7795
7796 $textifempty = '';
7797 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7798 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7799 if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7800 if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7801 else $textifempty .= $langs->trans("All");
7802 } else {
7803 if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7804 }
7805 if ($showempty) {
7806 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
7807 }
7808
7809 $i = 0;
7810 while ($num && $i < $num) {
7811 $opt = '';
7812 $optJson = array();
7813 $objp = $this->db->fetch_object($result);
7814
7815 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
7816
7817 // Add new entry
7818 // "key" value of json key array is used by jQuery automatically as selected value
7819 // "label" value of json key array is used by jQuery automatically as text for combo box
7820 $out .= $opt;
7821 array_push($outarray, $optJson);
7822
7823 $i++;
7824 }
7825
7826 $out .= '</select>';
7827
7828 $this->db->free($result);
7829
7830 if (empty($outputmode)) {
7831 return $out;
7832 }
7833 return $outarray;
7834 } else {
7835 dol_print_error($this->db);
7836 }
7837
7838 return array();
7839 }
7840
7852 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7853 {
7854 $outkey = '';
7855 $outlabel = '';
7856 $outtype = '';
7857
7858 $outkey = $objp->rowid;
7859 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
7860 $outtype = $objp->fk_adherent_type;
7861
7862 $opt = '<option value="' . $objp->rowid . '"';
7863 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7864 $opt .= '>';
7865 if (!empty($filterkey) && $filterkey != '') {
7866 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
7867 }
7868 $opt .= $outlabel;
7869 $opt .= "</option>\n";
7870
7871 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
7872 }
7873
7893 public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
7894 {
7895 global $conf, $user;
7896
7897 $objecttmp = null;
7898
7899 // Example of value for $objectdec:
7900 // Bom:bom/class/bom.class.php:0:t.status=1
7901 // Bom:bom/class/bom.class.php:0:t.status=1:ref
7902 // Bom:bom/class/bom.class.php:0:(t.status:=:1):ref
7903 $InfoFieldList = explode(":", $objectdesc, 4);
7904 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
7905 $reg = array();
7906 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
7907 $InfoFieldList[4] = $reg[1]; // take the sort field
7908 }
7909 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
7910
7911 $classname = $InfoFieldList[0];
7912 $classpath = $InfoFieldList[1];
7913 $addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
7914 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
7915 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
7916
7917 if (!empty($classpath)) {
7918 dol_include_once($classpath);
7919
7920 if ($classname && class_exists($classname)) {
7921 $objecttmp = new $classname($this->db);
7922
7923 // Make some replacement
7924 $sharedentities = getEntity(strtolower($classname));
7925 $filter = str_replace(
7926 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
7927 array($conf->entity, $sharedentities, $user->id),
7928 $filter
7929 );
7930 }
7931 }
7932 if (!is_object($objecttmp)) {
7933 dol_syslog('Error bad setup of type for field ' . join(',', $InfoFieldList), LOG_WARNING);
7934 return 'Error bad setup of type for field ' . join(',', $InfoFieldList);
7935 }
7936
7937 //var_dump($filter);
7938 $prefixforautocompletemode = $objecttmp->element;
7939 if ($prefixforautocompletemode == 'societe') {
7940 $prefixforautocompletemode = 'company';
7941 }
7942 if ($prefixforautocompletemode == 'product') {
7943 $prefixforautocompletemode = 'produit';
7944 }
7945 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7946
7947 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
7948 $out = '';
7949 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
7950 // No immediate load of all database
7951 $placeholder = '';
7952 if ($preselectedvalue && empty($selected_input_value)) {
7953 $objecttmp->fetch($preselectedvalue);
7954 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
7955 //unset($objecttmp);
7956 }
7957
7958 $objectdesc = $classname . ':' . $classpath . ':' . $addcreatebuttonornot . ':' . $filter;
7959 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
7960
7961 // No immediate load of all database
7962 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdesc) . '&filter=' . urlencode($filter) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
7963 // Activate the auto complete using ajax call.
7964 $out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
7965 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
7966 $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) . '"' : '') . ' />';
7967 } else {
7968 // Immediate load of table record.
7969 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
7970 }
7971
7972 return $out;
7973 }
7974
7975
7996 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
7997 {
7998 global $conf, $langs, $user, $hookmanager;
7999
8000 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
8001
8002 $prefixforautocompletemode = $objecttmp->element;
8003 if ($prefixforautocompletemode == 'societe') {
8004 $prefixforautocompletemode = 'company';
8005 }
8006 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8007
8008 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
8009 $tmpfieldstoshow = '';
8010 foreach ($objecttmp->fields as $key => $val) {
8011 if (!dol_eval($val['enabled'], 1, 1, '1')) {
8012 continue;
8013 }
8014 if (!empty($val['showoncombobox'])) {
8015 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8016 }
8017 }
8018 if ($tmpfieldstoshow) {
8019 $fieldstoshow = $tmpfieldstoshow;
8020 }
8021 } else {
8022 // For backward compatibility
8023 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8024 }
8025
8026 if (empty($fieldstoshow)) {
8027 if (isset($objecttmp->fields['ref'])) {
8028 $fieldstoshow = 't.ref';
8029 } else {
8030 $langs->load("errors");
8031 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8032 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8033 }
8034 }
8035
8036 $out = '';
8037 $outarray = array();
8038 $tmparray = array();
8039
8040 $num = 0;
8041
8042 // Search data
8043 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $objecttmp->table_element . " as t";
8044 if (isset($objecttmp->ismultientitymanaged)) {
8045 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8046 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8047 $sql .= " INNER JOIN " . $this->db->prefix() . $tmparray[1] . " as parenttable ON parenttable.rowid = t." . $tmparray[0];
8048 }
8049 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8050 if (empty($user->rights->societe->client->voir) && !$user->socid) {
8051 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8052 }
8053 }
8054 }
8055
8056 // Add where from hooks
8057 $parameters = array(
8058 'object' => $objecttmp,
8059 'htmlname' => $htmlname,
8060 'filter' => $filter,
8061 'searchkey' => $searchkey
8062 );
8063
8064 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8065 if (!empty($hookmanager->resPrint)) {
8066 $sql .= $hookmanager->resPrint;
8067 } else {
8068 $sql .= " WHERE 1=1";
8069 if (isset($objecttmp->ismultientitymanaged)) {
8070 if ($objecttmp->ismultientitymanaged == 1) {
8071 $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8072 }
8073 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8074 $sql .= " AND parenttable.entity = t." . $tmparray[0];
8075 }
8076 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8077 if ($objecttmp->element == 'societe') {
8078 $sql .= " AND t.rowid = " . ((int) $user->socid);
8079 } else {
8080 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8081 }
8082 }
8083 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8084 if (empty($user->rights->societe->client->voir) && !$user->socid) {
8085 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8086 }
8087 }
8088 }
8089 if ($searchkey != '') {
8090 $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
8091 }
8092
8093 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8094 $errormessage = '';
8095 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8096 if ($errormessage) {
8097 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8098 }
8099 }
8100 }
8101 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8102 //$sql.=$this->db->plimit($limit, 0);
8103 //print $sql;
8104
8105 // Build output string
8106 $resql = $this->db->query($sql);
8107 if ($resql) {
8108 // Construct $out and $outarray
8109 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8110
8111 // 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
8112 $textifempty = '&nbsp;';
8113
8114 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8115 if (!empty($conf->global->$confkeyforautocompletemode)) {
8116 if ($showempty && !is_numeric($showempty)) {
8117 $textifempty = $langs->trans($showempty);
8118 } else {
8119 $textifempty .= $langs->trans("All");
8120 }
8121 }
8122 if ($showempty) {
8123 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8124 }
8125
8126 $num = $this->db->num_rows($resql);
8127 $i = 0;
8128 if ($num) {
8129 while ($i < $num) {
8130 $obj = $this->db->fetch_object($resql);
8131 $label = '';
8132 $labelhtml = '';
8133 $tmparray = explode(',', $fieldstoshow);
8134 $oldvalueforshowoncombobox = 0;
8135 foreach ($tmparray as $key => $val) {
8136 $val = preg_replace('/t\./', '', $val);
8137 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8138 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8139 $label .= $obj->$val;
8140 $labelhtml .= $obj->$val;
8141
8142 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8143 }
8144 if (empty($outputmode)) {
8145 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8146 $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>';
8147 } else {
8148 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8149 }
8150 } else {
8151 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8152 }
8153
8154 $i++;
8155 if (($i % 10) == 0) {
8156 $out .= "\n";
8157 }
8158 }
8159 }
8160
8161 $out .= '</select>' . "\n";
8162
8163 if (!$forcecombo) {
8164 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8165 $out .= ajax_combobox($htmlname, null, (!empty($conf->global->$confkeyforautocompletemode) ? $conf->global->$confkeyforautocompletemode : 0));
8166 }
8167 } else {
8168 dol_print_error($this->db);
8169 }
8170
8171 $this->result = array('nbofelement' => $num);
8172
8173 if ($outputmode) {
8174 return $outarray;
8175 }
8176 return $out;
8177 }
8178
8179
8203 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)
8204 {
8205 global $conf, $langs;
8206
8207 // Do we want a multiselect ?
8208 //$jsbeautify = 0;
8209 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8210 $jsbeautify = 1;
8211
8212 if ($value_as_key) {
8213 $array = array_combine($array, $array);
8214 }
8215
8216 $out = '';
8217
8218 if ($addjscombo < 0) {
8219 if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8220 $addjscombo = 1;
8221 } else {
8222 $addjscombo = 0;
8223 }
8224 }
8225
8226 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8227 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8228 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8229 $out .= '>';
8230
8231 if ($show_empty) {
8232 $textforempty = ' ';
8233 if (!empty($conf->use_javascript_ajax)) {
8234 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8235 }
8236 if (!is_numeric($show_empty)) {
8237 $textforempty = $show_empty;
8238 }
8239 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8240 }
8241
8242 if (is_array($array)) {
8243 // Translate
8244 if ($translate) {
8245 foreach ($array as $key => $value) {
8246 if (!is_array($value)) {
8247 $array[$key] = $langs->trans($value);
8248 } else {
8249 $array[$key]['label'] = $langs->trans($value['label']);
8250 }
8251 }
8252 }
8253
8254 // Sort
8255 if ($sort == 'ASC') {
8256 asort($array);
8257 } elseif ($sort == 'DESC') {
8258 arsort($array);
8259 }
8260
8261 foreach ($array as $key => $tmpvalue) {
8262 if (is_array($tmpvalue)) {
8263 $value = $tmpvalue['label'];
8264 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8265 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8266 } else {
8267 $value = $tmpvalue;
8268 $disabled = '';
8269 $style = '';
8270 }
8271 if (!empty($disablebademail)) {
8272 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8273 || ($disablebademail == 2 && preg_match('/---/', $value))) {
8274 $disabled = ' disabled';
8275 $style = ' class="warning"';
8276 }
8277 }
8278
8279 if ($key_in_label) {
8280 if (empty($nohtmlescape)) {
8281 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8282 } else {
8283 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8284 }
8285 } else {
8286 if (empty($nohtmlescape)) {
8287 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
8288 } else {
8289 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8290 }
8291 if ($value == '' || $value == '-') {
8292 $selectOptionValue = '&nbsp;';
8293 }
8294 }
8295
8296 $out .= '<option value="' . $key . '"';
8297 $out .= $style . $disabled;
8298 if (is_array($id)) {
8299 if (in_array($key, $id) && !$disabled) {
8300 $out .= ' selected'; // To preselect a value
8301 }
8302 } else {
8303 $id = (string) $id; // if $id = 0, then $id = '0'
8304 if ($id != '' && ($id == $key || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8305 $out .= ' selected'; // To preselect a value
8306 }
8307 }
8308 if ($nohtmlescape) {
8309 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
8310 }
8311 if (is_array($tmpvalue)) {
8312 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
8313 if (preg_match('/^data-/', $keyforvalue)) {
8314 $out .= ' '.$keyforvalue.'="'.dol_escape_htmltag($valueforvalue).'"';
8315 }
8316 }
8317 }
8318 $out .= '>';
8319 //var_dump($selectOptionValue);
8320 $out .= $selectOptionValue;
8321 $out .= "</option>\n";
8322 }
8323 }
8324
8325 $out .= "</select>";
8326
8327 // Add code for jquery to use multiselect
8328 if ($addjscombo && $jsbeautify) {
8329 // Enhance with select2
8330 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8331 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
8332 }
8333
8334 return $out;
8335 }
8336
8337
8356 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8357 {
8358 global $conf, $langs;
8359 global $delayedhtmlcontent; // Will be used later outside of this function
8360
8361 // TODO Use an internal dolibarr component instead of select2
8362 if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8363 return '';
8364 }
8365
8366 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
8367
8368 $outdelayed = '';
8369 if (!empty($conf->use_javascript_ajax)) {
8370 $tmpplugin = 'select2';
8371 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8372 <script nonce="' . getNonce() . '">
8373 $(document).ready(function () {
8374
8375 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
8376
8377 $(".' . $htmlname . '").select2({
8378 ajax: {
8379 dir: "ltr",
8380 url: "' . $url . '",
8381 dataType: \'json\',
8382 delay: 250,
8383 data: function (params) {
8384 return {
8385 q: params.term, // search term
8386 page: params.page
8387 }
8388 },
8389 processResults: function (data) {
8390 // parse the results into the format expected by Select2.
8391 // since we are using custom formatting functions we do not need to alter the remote JSON data
8392 //console.log(data);
8393 saveRemoteData = data;
8394 /* format json result for select2 */
8395 result = []
8396 $.each( data, function( key, value ) {
8397 result.push({id: key, text: value.text});
8398 });
8399 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
8400 //console.log(result);
8401 return {results: result, more: false}
8402 },
8403 cache: true
8404 },
8405 language: select2arrayoflanguage,
8406 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8407 placeholder: "' . dol_escape_js($placeholder) . '",
8408 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8409 minimumInputLength: ' . ((int) $minimumInputLength) . ',
8410 formatResult: function (result, container, query, escapeMarkup) {
8411 return escapeMarkup(result.text);
8412 },
8413 });
8414
8415 ' . ($callurlonselect ? '
8416 /* Code to execute a GET when we select a value */
8417 $(".' . $htmlname . '").change(function() {
8418 var selected = $(".' . $htmlname . '").val();
8419 console.log("We select in selectArrayAjax the entry "+selected)
8420 $(".' . $htmlname . '").val(""); /* reset visible combo value */
8421 $.each( saveRemoteData, function( key, value ) {
8422 if (key == selected)
8423 {
8424 console.log("selectArrayAjax - Do a redirect to "+value.url)
8425 location.assign(value.url);
8426 }
8427 });
8428 });' : '') . '
8429
8430 });
8431 </script>';
8432 }
8433
8434 if ($acceptdelayedhtml) {
8435 $delayedhtmlcontent .= $outdelayed;
8436 } else {
8437 $out .= $outdelayed;
8438 }
8439 return $out;
8440 }
8441
8461 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
8462 {
8463 global $conf, $langs;
8464 global $delayedhtmlcontent; // Will be used later outside of this function
8465
8466 // TODO Use an internal dolibarr component instead of select2
8467 if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8468 return '';
8469 }
8470
8471 $out = '<select type="text"'.($textfortitle? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
8472
8473 $formattedarrayresult = array();
8474
8475 foreach ($array as $key => $value) {
8476 $o = new stdClass();
8477 $o->id = $key;
8478 $o->text = $value['text'];
8479 $o->url = $value['url'];
8480 $formattedarrayresult[] = $o;
8481 }
8482
8483 $outdelayed = '';
8484 if (!empty($conf->use_javascript_ajax)) {
8485 $tmpplugin = 'select2';
8486 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8487 <script nonce="' . getNonce() . '">
8488 $(document).ready(function () {
8489 var data = ' . json_encode($formattedarrayresult) . ';
8490
8491 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
8492
8493 $(".' . $htmlname . '").select2({
8494 data: data,
8495 language: select2arrayoflanguage,
8496 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8497 placeholder: "' . dol_escape_js($placeholder) . '",
8498 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8499 minimumInputLength: ' . $minimumInputLength . ',
8500 formatResult: function (result, container, query, escapeMarkup) {
8501 return escapeMarkup(result.text);
8502 },
8503 matcher: function (params, data) {
8504
8505 if(! data.id) return null;';
8506
8507 if ($callurlonselect) {
8508 // We forge the url with 'sall='
8509 $outdelayed .= '
8510
8511 var urlBase = data.url;
8512 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
8513 /* console.log("params.term="+params.term); */
8514 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
8515 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
8516 }
8517
8518 if (!$disableFiltering) {
8519 $outdelayed .= '
8520
8521 if(data.text.match(new RegExp(params.term))) {
8522 return data;
8523 }
8524
8525 return null;';
8526 } else {
8527 $outdelayed .= '
8528
8529 return data;';
8530 }
8531
8532 $outdelayed .= '
8533 }
8534 });
8535
8536 ' . ($callurlonselect ? '
8537 /* Code to execute a GET when we select a value */
8538 $(".' . $htmlname . '").change(function() {
8539 var selected = $(".' . $htmlname . '").val();
8540 console.log("We select "+selected)
8541
8542 $(".' . $htmlname . '").val(""); /* reset visible combo value */
8543 $.each( saveRemoteData, function( key, value ) {
8544 if (key == selected)
8545 {
8546 console.log("selectArrayFilter - Do a redirect to "+value.url)
8547 location.assign(value.url);
8548 }
8549 });
8550 });' : '') . '
8551
8552 });
8553 </script>';
8554 }
8555
8556 if ($acceptdelayedhtml) {
8557 $delayedhtmlcontent .= $outdelayed;
8558 } else {
8559 $out .= $outdelayed;
8560 }
8561 return $out;
8562 }
8563
8582 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)
8583 {
8584 global $conf, $langs;
8585
8586 $out = '';
8587
8588 if ($addjscombo < 0) {
8589 if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8590 $addjscombo = 1;
8591 } else {
8592 $addjscombo = 0;
8593 }
8594 }
8595
8596 $useenhancedmultiselect = 0;
8597 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8598 $useenhancedmultiselect = 1;
8599 }
8600
8601 // Output select component
8602 $out .= '<select id="' . $htmlname . '" class="multiselect' . ($useenhancedmultiselect ? ' multiselectononeline' : '') . ($morecss ? ' ' . $morecss : '') . '" multiple name="' . $htmlname . '[]"' . ($moreattrib ? ' ' . $moreattrib : '') . ($width ? ' style="width: ' . (preg_match('/%/', $width) ? $width : $width . 'px') . '"' : '') . '>' . "\n";
8603 if (is_array($array) && !empty($array)) {
8604 if ($value_as_key) {
8605 $array = array_combine($array, $array);
8606 }
8607
8608 if (!empty($array)) {
8609 foreach ($array as $key => $value) {
8610 $tmpkey = $key;
8611 $tmpvalue = $value;
8612 $tmpcolor = '';
8613 $tmppicto = '';
8614 $tmplabelhtml = '';
8615 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
8616 $tmpkey = $value['id'];
8617 $tmpvalue = $value['label'];
8618 $tmpcolor = $value['color'];
8619 $tmppicto = $value['picto'];
8620 $tmplabelhtml = !empty($value['labelhtml']) ? $value['labelhtml'] : '';
8621 }
8622 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
8623 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
8624
8625 $out .= '<option value="' . $tmpkey . '"';
8626 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
8627 $out .= ' selected';
8628 }
8629 if (!empty($tmplabelhtml)) {
8630 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
8631 } else {
8632 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
8633 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
8634 }
8635 $out .= '>';
8636 $out .= dol_htmlentitiesbr($newval);
8637 $out .= '</option>' . "\n";
8638 }
8639 }
8640 }
8641 $out .= '</select>' . "\n";
8642
8643 // Add code for jquery to use multiselect
8644 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8645 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
8646 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
8647 if ($addjscombo == 1) {
8648 $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
8649 $out .= 'function formatResult(record, container) {' . "\n";
8650 // If property html set, we decode html entities and use this.
8651 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
8652 $out .= ' if ($(record.element).attr("data-html") != undefined) { return htmlEntityDecodeJs($(record.element).attr("data-html")); }'."\n";
8653 $out .= ' return record.text;';
8654 $out .= '}' . "\n";
8655 $out .= 'function formatSelection(record) {' . "\n";
8656 if ($elemtype == 'category') {
8657 $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
8658 } else {
8659 $out .= 'return record.text;';
8660 }
8661 $out .= '}' . "\n";
8662 $out .= '$(document).ready(function () {
8663 $(\'#' . $htmlname . '\').' . $tmpplugin . '({';
8664 if ($placeholder) {
8665 $out .= '
8666 placeholder: {
8667 id: \'-1\',
8668 text: \'' . dol_escape_js($placeholder) . '\'
8669 },';
8670 }
8671 $out .= ' dir: \'ltr\',
8672 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
8673 dropdownCssClass: \'' . $morecss . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect) */
8674 // Specify format function for dropdown item
8675 formatResult: formatResult,
8676 templateResult: formatResult, /* For 4.0 */
8677 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8678 // Specify format function for selected item
8679 formatSelection: formatSelection,
8680 templateSelection: formatSelection /* For 4.0 */
8681 });
8682
8683 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
8684 the size only if component is not hidden by default on load */
8685 $(\'#' . $htmlname . ' + .select2\').addClass(\'' . $morecss . '\');
8686 });' . "\n";
8687 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
8688 // Add other js lib
8689 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
8690 // ...
8691 $out .= 'console.log(\'addjscombo=2 for htmlname=' . $htmlname . '\');';
8692 $out .= '$(document).ready(function () {
8693 $(\'#' . $htmlname . '\').multiSelect({
8694 containerHTML: \'<div class="multi-select-container">\',
8695 menuHTML: \'<div class="multi-select-menu">\',
8696 buttonHTML: \'<span class="multi-select-button ' . $morecss . '">\',
8697 menuItemHTML: \'<label class="multi-select-menuitem">\',
8698 activeClass: \'multi-select-container--open\',
8699 noneText: \'' . $placeholder . '\'
8700 });
8701 })';
8702 }
8703 $out .= '</script>';
8704 }
8705
8706 return $out;
8707 }
8708
8709
8720 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
8721 {
8722 global $conf, $langs, $user, $extrafields;
8723
8724 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8725 return '';
8726 }
8727 if (empty($array)) {
8728 return '';
8729 }
8730
8731 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
8732
8733 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
8734 $tmparray = explode(',', $user->conf->$tmpvar);
8735 foreach ($array as $key => $val) {
8736 //var_dump($key);
8737 //var_dump($tmparray);
8738 if (in_array($key, $tmparray)) {
8739 $array[$key]['checked'] = 1;
8740 } else {
8741 $array[$key]['checked'] = 0;
8742 }
8743 }
8744 } else { // There is no list of fields already customized for user
8745 foreach ($array as $key => $val) {
8746 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
8747 $array[$key]['checked'] = 0;
8748 }
8749 }
8750 }
8751
8752 $listoffieldsforselection = '';
8753 $listcheckedstring = '';
8754
8755 foreach ($array as $key => $val) {
8756 // var_dump($val);
8757 // var_dump(array_key_exists('enabled', $val));
8758 // var_dump(!$val['enabled']);
8759 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
8760 unset($array[$key]); // We don't want this field
8761 continue;
8762 }
8763 if (!empty($val['type']) && $val['type'] == 'separate') {
8764 // Field remains in array but we don't add it into $listoffieldsforselection
8765 //$listoffieldsforselection .= '<li>-----</li>';
8766 continue;
8767 }
8768 if ($val['label']) {
8769 if (!empty($val['langfile']) && is_object($langs)) {
8770 $langs->load($val['langfile']);
8771 }
8772
8773 // Note: $val['checked'] <> 0 means we must show the field into the combo list
8774 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . '/><label for="checkbox' . $key . '">' . dol_escape_htmltag($langs->trans($val['label'])) . '</label></li>';
8775 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
8776 }
8777 }
8778
8779 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
8780
8781 <dl class="dropdown">
8782 <dt>
8783 <a href="#' . $htmlname . '">
8784 ' . img_picto('', 'list') . '
8785 </a>
8786 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
8787 </dt>
8788 <dd class="dropdowndd">
8789 <div class="multiselectcheckbox'.$htmlname.'">
8790 <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
8791 <li><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
8792 '.$listoffieldsforselection.'
8793 </ul>
8794 </div>
8795 </dd>
8796 </dl>
8797
8798 <script nonce="' . getNonce() . '" type="text/javascript">
8799 jQuery(document).ready(function () {
8800 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
8801 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
8802
8803 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
8804
8805 var title = $(this).val() + ",";
8806 if ($(this).is(\':checked\')) {
8807 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
8808 }
8809 else {
8810 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
8811 }
8812 // Now, we submit page
8813 //$(this).parents(\'form:first\').submit();
8814 });
8815 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
8816 var value = $(this).val().toLowerCase();
8817 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
8818 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
8819 });
8820 });
8821
8822
8823 });
8824 </script>
8825
8826 ';
8827 return $out;
8828 }
8829
8839 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
8840 {
8841 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
8842
8843 $cat = new Categorie($this->db);
8844 $categories = $cat->containing($id, $type);
8845
8846 if ($rendermode == 1) {
8847 $toprint = array();
8848 foreach ($categories as $c) {
8849 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
8850 foreach ($ways as $way) {
8851 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
8852 }
8853 }
8854 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
8855 }
8856
8857 if ($rendermode == 0) {
8858 $arrayselected = array();
8859 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
8860 foreach ($categories as $c) {
8861 $arrayselected[] = $c->id;
8862 }
8863
8864 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
8865 }
8866
8867 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
8868 }
8869
8879 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false, $title = 'RelatedObjects')
8880 {
8881 global $conf, $langs, $hookmanager;
8882 global $bc, $action;
8883
8884 $object->fetchObjectLinked();
8885
8886 // Bypass the default method
8887 $hookmanager->initHooks(array('commonobject'));
8888 $parameters = array(
8889 'morehtmlright' => $morehtmlright,
8890 'compatibleImportElementsList' => &$compatibleImportElementsList,
8891 );
8892 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8893
8894 $nbofdifferenttypes = count($object->linkedObjects);
8895
8896 if (empty($reshook)) {
8897 print '<!-- showLinkedObjectBlock -->';
8898 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
8899
8900
8901 print '<div class="div-table-responsive-no-min">';
8902 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
8903
8904 print '<tr class="liste_titre">';
8905 print '<td>' . $langs->trans("Type") . '</td>';
8906 print '<td>' . $langs->trans("Ref") . '</td>';
8907 print '<td class="center"></td>';
8908 print '<td class="center">' . $langs->trans("Date") . '</td>';
8909 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
8910 print '<td class="right">' . $langs->trans("Status") . '</td>';
8911 print '<td></td>';
8912 print '</tr>';
8913
8914 $nboftypesoutput = 0;
8915
8916 foreach ($object->linkedObjects as $objecttype => $objects) {
8917 $tplpath = $element = $subelement = $objecttype;
8918
8919 // to display inport button on tpl
8920 $showImportButton = false;
8921 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
8922 $showImportButton = true;
8923 }
8924
8925 $regs = array();
8926 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
8927 $element = $regs[1];
8928 $subelement = $regs[2];
8929 $tplpath = $element . '/' . $subelement;
8930 }
8931 $tplname = 'linkedobjectblock';
8932
8933 // To work with non standard path
8934 if ($objecttype == 'facture') {
8935 $tplpath = 'compta/' . $element;
8936 if (!isModEnabled('facture')) {
8937 continue; // Do not show if module disabled
8938 }
8939 } elseif ($objecttype == 'facturerec') {
8940 $tplpath = 'compta/facture';
8941 $tplname = 'linkedobjectblockForRec';
8942 if (!isModEnabled('facture')) {
8943 continue; // Do not show if module disabled
8944 }
8945 } elseif ($objecttype == 'propal') {
8946 $tplpath = 'comm/' . $element;
8947 if (!isModEnabled('propal')) {
8948 continue; // Do not show if module disabled
8949 }
8950 } elseif ($objecttype == 'supplier_proposal') {
8951 if (!isModEnabled('supplier_proposal')) {
8952 continue; // Do not show if module disabled
8953 }
8954 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
8955 $tplpath = 'expedition';
8956 if (!isModEnabled('expedition')) {
8957 continue; // Do not show if module disabled
8958 }
8959 } elseif ($objecttype == 'reception') {
8960 $tplpath = 'reception';
8961 if (!isModEnabled('reception')) {
8962 continue; // Do not show if module disabled
8963 }
8964 } elseif ($objecttype == 'delivery') {
8965 $tplpath = 'delivery';
8966 if (!isModEnabled('expedition')) {
8967 continue; // Do not show if module disabled
8968 }
8969 } elseif ($objecttype == 'ficheinter') {
8970 $tplpath = 'fichinter';
8971 if (!isModEnabled('ficheinter')) {
8972 continue; // Do not show if module disabled
8973 }
8974 } elseif ($objecttype == 'invoice_supplier') {
8975 $tplpath = 'fourn/facture';
8976 } elseif ($objecttype == 'order_supplier') {
8977 $tplpath = 'fourn/commande';
8978 } elseif ($objecttype == 'expensereport') {
8979 $tplpath = 'expensereport';
8980 } elseif ($objecttype == 'subscription') {
8981 $tplpath = 'adherents';
8982 } elseif ($objecttype == 'conferenceorbooth') {
8983 $tplpath = 'eventorganization';
8984 } elseif ($objecttype == 'conferenceorboothattendee') {
8985 $tplpath = 'eventorganization';
8986 } elseif ($objecttype == 'mo') {
8987 $tplpath = 'mrp';
8988 if (!isModEnabled('mrp')) {
8989 continue; // Do not show if module disabled
8990 }
8991 }
8992
8993 global $linkedObjectBlock;
8994 $linkedObjectBlock = $objects;
8995
8996 // Output template part (modules that overwrite templates must declare this into descriptor)
8997 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
8998 foreach ($dirtpls as $reldir) {
8999 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
9000 global $noMoreLinkedObjectBlockAfter;
9001 $noMoreLinkedObjectBlockAfter = 1;
9002 }
9003
9004 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
9005 if ($res) {
9006 $nboftypesoutput++;
9007 break;
9008 }
9009 }
9010 }
9011
9012 if (!$nboftypesoutput) {
9013 print '<tr><td class="impair" colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9014 }
9015
9016 print '</table>';
9017
9018 if (!empty($compatibleImportElementsList)) {
9019 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9020 }
9021
9022 print '</div>';
9023 }
9024
9025 return $nbofdifferenttypes;
9026 }
9027
9036 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
9037 {
9038 global $conf, $langs, $hookmanager;
9039 global $action;
9040
9041 $linktoelem = '';
9042 $linktoelemlist = '';
9043 $listofidcompanytoscan = '';
9044
9045 if (!is_object($object->thirdparty)) {
9046 $object->fetch_thirdparty();
9047 }
9048
9049 $possiblelinks = array();
9050 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9051 $listofidcompanytoscan = $object->thirdparty->id;
9052 if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) {
9053 $listofidcompanytoscan .= ',' . $object->thirdparty->parent;
9054 }
9055 if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO)) {
9056 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9057 $tmpproject = new Project($this->db);
9058 $tmpproject->fetch($object->fk_project);
9059 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9060 $listofidcompanytoscan .= ',' . $tmpproject->socid;
9061 }
9062 unset($tmpproject);
9063 }
9064
9065 $possiblelinks = array(
9066 'propal' => array(
9067 'enabled' => isModEnabled('propal'),
9068 'perms' => 1,
9069 'label' => 'LinkToProposal',
9070 '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') . ')'),
9071 'shipping' => array(
9072 'enabled' => isModEnabled('expedition'),
9073 'perms' => 1,
9074 'label' => 'LinkToExpedition',
9075 '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') . ')'),
9076 'order' => array(
9077 'enabled' => isModEnabled('commande'),
9078 'perms' => 1,
9079 'label' => 'LinkToOrder',
9080 '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') . ')'),
9081 'invoice' => array(
9082 'enabled' => isModEnabled('facture'),
9083 'perms' => 1,
9084 'label' => 'LinkToInvoice',
9085 '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') . ')'),
9086 'invoice_template' => array(
9087 'enabled' => isModEnabled('facture'),
9088 'perms' => 1,
9089 'label' => 'LinkToTemplateInvoice',
9090 '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') . ')'),
9091 'contrat' => array(
9092 'enabled' => isModEnabled('contrat'),
9093 'perms' => 1,
9094 'label' => 'LinkToContract',
9095 '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
9096 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'
9097 ),
9098 'fichinter' => array(
9099 'enabled' => isModEnabled('ficheinter'),
9100 'perms' => 1,
9101 'label' => 'LinkToIntervention',
9102 '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') . ')'),
9103 'supplier_proposal' => array(
9104 'enabled' => (isModEnabled('supplier_proposal') ? $conf->supplier_proposal->enabled : 0),
9105 'perms' => 1,
9106 'label' => 'LinkToSupplierProposal',
9107 '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') . ')'),
9108 'order_supplier' => array(
9109 'enabled' => (isModEnabled("supplier_order") ? $conf->supplier_order->enabled : 0),
9110 'perms' => 1,
9111 'label' => 'LinkToSupplierOrder',
9112 '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') . ')'),
9113 'invoice_supplier' => array(
9114 'enabled' => (isModEnabled("supplier_invoice") ? $conf->supplier_invoice->enabled : 0),
9115 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9116 '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') . ')'),
9117 'ticket' => array(
9118 'enabled' => isModEnabled('ticket'),
9119 'perms' => 1,
9120 'label' => 'LinkToTicket',
9121 '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') . ')'),
9122 'mo' => array(
9123 'enabled' => isModEnabled('mrp'),
9124 'perms' => 1,
9125 'label' => 'LinkToMo',
9126 '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') . ')')
9127 );
9128 }
9129
9130 if ($object->table_element == 'commande_fournisseur') {
9131 $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').')';
9132 } elseif ($object->table_element == 'mrp_mo') {
9133 $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').')';
9134 }
9135
9136 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9137 // Can complete the possiblelink array
9138 $hookmanager->initHooks(array('commonobject'));
9139 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9140 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9141 }
9142
9143 if (empty($reshook)) {
9144 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9145 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9146 }
9147 } elseif ($reshook > 0) {
9148 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9149 $possiblelinks = $hookmanager->resArray;
9150 }
9151 }
9152
9153 foreach ($possiblelinks as $key => $possiblelink) {
9154 $num = 0;
9155
9156 if (empty($possiblelink['enabled'])) {
9157 continue;
9158 }
9159
9160 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9161 print '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9162
9163 if (!empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
9164 print '<br>'."\n";
9165 print '<!-- form to add a link from anywhere -->'."\n";
9166 print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9167 print '<input type="hidden" name="id" value="' . $object->id . '">';
9168 print '<input type="hidden" name="action" value="addlinkbyref">';
9169 print '<input type="hidden" name="token" value="' . newToken() . '">';
9170 print '<input type="hidden" name="addlink" value="' . $key . '">';
9171 print '<table class="noborder">';
9172 print '<tr>';
9173 //print '<td>' . $langs->trans("Ref") . '</td>';
9174 print '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9175 print '<input type="submit" class="button small valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9176 print '<input type="submit" class="button small" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9177 print '</tr>';
9178 print '</table>';
9179 print '</form>';
9180 }
9181
9182 $sql = $possiblelink['sql'];
9183
9184 $resqllist = $this->db->query($sql);
9185 if ($resqllist) {
9186 $num = $this->db->num_rows($resqllist);
9187 $i = 0;
9188
9189 print '<br>';
9190 print '<!-- form to add a link from object to same thirdparty -->'."\n";
9191 print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9192 print '<input type="hidden" name="action" value="addlink">';
9193 print '<input type="hidden" name="token" value="' . newToken() . '">';
9194 print '<input type="hidden" name="id" value="' . $object->id . '">';
9195 print '<input type="hidden" name="addlink" value="' . $key . '">';
9196 print '<table class="noborder">';
9197 print '<tr class="liste_titre">';
9198 print '<td class="nowrap"></td>';
9199 print '<td class="center">' . $langs->trans("Ref") . '</td>';
9200 print '<td class="left">' . $langs->trans("RefCustomer") . '</td>';
9201 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9202 print '<td class="left">' . $langs->trans("Company") . '</td>';
9203 print '</tr>';
9204 while ($i < $num) {
9205 $objp = $this->db->fetch_object($resqllist);
9206
9207 print '<tr class="oddeven">';
9208 print '<td class="left">';
9209 print '<input type="radio" name="idtolinkto" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9210 print '</td>';
9211 print '<td class="center"><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9212 print '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9213 print '<td class="right">';
9214 if ($possiblelink['label'] == 'LinkToContract') {
9215 $form = new Form($this->db);
9216 print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9217 }
9218 print '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9219 print '</td>';
9220 print '<td>' . $objp->name . '</td>';
9221 print '</tr>';
9222 $i++;
9223 }
9224 print '</table>';
9225 print '<div class="center">';
9226 if ($num) {
9227 print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly small" value="' . $langs->trans('ToLink') . '">';
9228 }
9229 if (empty($conf->use_javascript_ajax)) {
9230 print '<input type="submit" class="button button-cancel marginleftonly marginrightonly small" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9231 } else {
9232 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>';
9233 }
9234 print '</form>';
9235 $this->db->free($resqllist);
9236 } else {
9237 dol_print_error($this->db);
9238 }
9239 print '</div>';
9240
9241 //$linktoelem.=($linktoelem?' &nbsp; ':'');
9242 if ($num > 0 || !empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
9243 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
9244 // } else $linktoelem.=$langs->trans($possiblelink['label']);
9245 } else {
9246 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
9247 }
9248 }
9249 }
9250
9251 if ($linktoelemlist) {
9252 $linktoelem = '
9253 <dl class="dropdown" id="linktoobjectname">
9254 ';
9255 if (!empty($conf->use_javascript_ajax)) {
9256 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
9257 }
9258 $linktoelem .= '<dd>
9259 <div class="multiselectlinkto">
9260 <ul class="ulselectedfields">' . $linktoelemlist . '
9261 </ul>
9262 </div>
9263 </dd>
9264 </dl>';
9265 } else {
9266 $linktoelem = '';
9267 }
9268
9269 if (!empty($conf->use_javascript_ajax)) {
9270 print '<!-- Add js to show linkto box -->
9271 <script nonce="' . getNonce() . '">
9272 jQuery(document).ready(function() {
9273 jQuery(".linkto").click(function() {
9274 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
9275 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
9276 });
9277 });
9278 </script>
9279 ';
9280 }
9281
9282 return $linktoelem;
9283 }
9284
9299 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '', $labelyes = 'Yes', $labelno = 'No')
9300 {
9301 global $langs;
9302
9303 $yes = "yes";
9304 $no = "no";
9305 if ($option) {
9306 $yes = "1";
9307 $no = "0";
9308 }
9309
9310 $disabled = ($disabled ? ' disabled' : '');
9311
9312 $resultyesno = '<select class="flat width75' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
9313 if ($useempty) {
9314 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
9315 }
9316 if (("$value" == 'yes') || ($value == 1)) {
9317 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
9318 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
9319 } else {
9320 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
9321 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
9322 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
9323 }
9324 $resultyesno .= '</select>' . "\n";
9325
9326 if ($addjscombo) {
9327 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
9328 }
9329
9330 return $resultyesno;
9331 }
9332
9333 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9334
9344 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
9345 {
9346 // phpcs:enable
9347 $sql = "SELECT rowid, label";
9348 $sql .= " FROM " . $this->db->prefix() . "export_model";
9349 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
9350 $sql .= " ORDER BY rowid";
9351 $result = $this->db->query($sql);
9352 if ($result) {
9353 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
9354 if ($useempty) {
9355 print '<option value="-1">&nbsp;</option>';
9356 }
9357
9358 $num = $this->db->num_rows($result);
9359 $i = 0;
9360 while ($i < $num) {
9361 $obj = $this->db->fetch_object($result);
9362 if ($selected == $obj->rowid) {
9363 print '<option value="' . $obj->rowid . '" selected>';
9364 } else {
9365 print '<option value="' . $obj->rowid . '">';
9366 }
9367 print $obj->label;
9368 print '</option>';
9369 $i++;
9370 }
9371 print "</select>";
9372 } else {
9373 dol_print_error($this->db);
9374 }
9375 }
9376
9395 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
9396 {
9397 global $conf, $langs, $hookmanager, $extralanguages;
9398
9399 $ret = '';
9400 if (empty($fieldid)) {
9401 $fieldid = 'rowid';
9402 }
9403 if (empty($fieldref)) {
9404 $fieldref = 'ref';
9405 }
9406
9407 // Preparing gender's display if there is one
9408 $addgendertxt = '';
9409 if (property_exists($object, 'gender') && !empty($object->gender)) {
9410 $addgendertxt = ' ';
9411 switch ($object->gender) {
9412 case 'man':
9413 $addgendertxt .= '<i class="fas fa-mars"></i>';
9414 break;
9415 case 'woman':
9416 $addgendertxt .= '<i class="fas fa-venus"></i>';
9417 break;
9418 case 'other':
9419 $addgendertxt .= '<i class="fas fa-transgender"></i>';
9420 break;
9421 }
9422 }
9423
9424 // Add where from hooks
9425 if (is_object($hookmanager)) {
9426 $parameters = array('showrefnav' => true);
9427 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
9428 $object->next_prev_filter .= $hookmanager->resPrint;
9429 }
9430 $previous_ref = $next_ref = '';
9431 if ($shownav) {
9432 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
9433 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
9434
9435 $navurl = $_SERVER["PHP_SELF"];
9436 // Special case for project/task page
9437 if ($paramid == 'project_ref') {
9438 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
9439 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
9440 $paramid = 'ref';
9441 }
9442 }
9443
9444 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
9445 // accesskey is for Mac: CTRL + key for all browsers
9446 $stringforfirstkey = $langs->trans("KeyboardShortcut");
9447 if ($conf->browser->name == 'chrome') {
9448 $stringforfirstkey .= ' ALT +';
9449 } elseif ($conf->browser->name == 'firefox') {
9450 $stringforfirstkey .= ' ALT + SHIFT +';
9451 } else {
9452 $stringforfirstkey .= ' CTL +';
9453 }
9454
9455 $previous_ref = $object->ref_previous ? '<a accesskey="p" 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>';
9456 $next_ref = $object->ref_next ? '<a accesskey="n" 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>';
9457 }
9458
9459 //print "xx".$previous_ref."x".$next_ref;
9460 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
9461
9462 // Right part of banner
9463 if ($morehtmlright) {
9464 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
9465 }
9466
9467 if ($previous_ref || $next_ref || $morehtml) {
9468 $ret .= '<div class="pagination paginationref"><ul class="right">';
9469 }
9470 if ($morehtml) {
9471 $ret .= '<li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
9472 }
9473 if ($shownav && ($previous_ref || $next_ref)) {
9474 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
9475 $ret .= '<li class="pagination">' . $next_ref . '</li>';
9476 }
9477 if ($previous_ref || $next_ref || $morehtml) {
9478 $ret .= '</ul></div>';
9479 }
9480
9481 // Status
9482 $parameters = array();
9483 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
9484 if (empty($reshook)) {
9485 $morehtmlstatus .= $hookmanager->resPrint;
9486 } else {
9487 $morehtmlstatus = $hookmanager->resPrint;
9488 }
9489 if ($morehtmlstatus) {
9490 $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
9491 }
9492
9493 $parameters = array();
9494 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
9495 if (empty($reshook)) {
9496 $morehtmlref .= $hookmanager->resPrint;
9497 } elseif ($reshook > 0) {
9498 $morehtmlref = $hookmanager->resPrint;
9499 }
9500
9501 // Left part of banner
9502 if ($morehtmlleft) {
9503 if ($conf->browser->layout == 'phone') {
9504 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
9505 } else {
9506 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
9507 }
9508 }
9509
9510 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
9511 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
9512
9513 // For thirdparty, contact, user, member, the ref is the id, so we show something else
9514 if ($object->element == 'societe') {
9515 $ret .= dol_htmlentities($object->name);
9516
9517 // List of extra languages
9518 $arrayoflangcode = array();
9519 if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
9520 $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
9521 }
9522
9523 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
9524 if (!is_object($extralanguages)) {
9525 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
9526 $extralanguages = new ExtraLanguages($this->db);
9527 }
9528 $extralanguages->fetch_name_extralanguages('societe');
9529
9530 if (!empty($extralanguages->attributes['societe']['name'])) {
9531 $object->fetchValuesForExtraLanguages();
9532
9533 $htmltext = '';
9534 // If there is extra languages
9535 foreach ($arrayoflangcode as $extralangcode) {
9536 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
9537 if ($object->array_languages['name'][$extralangcode]) {
9538 $htmltext .= $object->array_languages['name'][$extralangcode];
9539 } else {
9540 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
9541 }
9542 }
9543 $ret .= '<!-- Show translations of name -->' . "\n";
9544 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
9545 }
9546 }
9547 } elseif ($object->element == 'member') {
9548 $ret .= $object->ref . '<br>';
9549 $fullname = $object->getFullName($langs);
9550 if ($object->morphy == 'mor' && $object->societe) {
9551 $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
9552 } else {
9553 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
9554 }
9555 } elseif (in_array($object->element, array('contact', 'user'))) {
9556 $ret .= dol_htmlentities($object->getFullName($langs)) . $addgendertxt;
9557 } elseif ($object->element == 'usergroup') {
9558 $ret .= dol_htmlentities($object->name);
9559 } elseif (in_array($object->element, array('action', 'agenda'))) {
9560 $ret .= $object->ref . '<br>' . $object->label;
9561 } elseif (in_array($object->element, array('adherent_type'))) {
9562 $ret .= $object->label;
9563 } elseif ($object->element == 'ecm_directories') {
9564 $ret .= '';
9565 } elseif ($fieldref != 'none') {
9566 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
9567 }
9568 if ($morehtmlref) {
9569 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
9570 if (substr($morehtmlref, 0, 4) != '<div') {
9571 $ret .= ' ';
9572 }
9573
9574 $ret .= $morehtmlref;
9575 }
9576
9577 $ret .= '</div>';
9578
9579 $ret .= '</div><!-- End banner content -->';
9580
9581 return $ret;
9582 }
9583
9584
9593 public function showbarcode(&$object, $width = 100, $morecss = '')
9594 {
9595 global $conf;
9596
9597 //Check if barcode is filled in the card
9598 if (empty($object->barcode)) {
9599 return '';
9600 }
9601
9602 // Complete object if not complete
9603 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
9604 $result = $object->fetch_barcode();
9605 //Check if fetch_barcode() failed
9606 if ($result < 1) {
9607 return '<!-- ErrorFetchBarcode -->';
9608 }
9609 }
9610
9611 // Barcode image
9612 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
9613 $out = '<!-- url barcode = ' . $url . ' -->';
9614 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
9615
9616 return $out;
9617 }
9618
9635 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
9636 {
9637 global $conf, $langs;
9638
9639 $entity = (!empty($object->entity) ? $object->entity : $conf->entity);
9640 $id = (!empty($object->id) ? $object->id : $object->rowid);
9641
9642 $ret = '';
9643 $dir = '';
9644 $file = '';
9645 $originalfile = '';
9646 $altfile = '';
9647 $email = '';
9648 $capture = '';
9649 if ($modulepart == 'societe') {
9650 $dir = $conf->societe->multidir_output[$entity];
9651 if (!empty($object->logo)) {
9652 if (dolIsAllowedForPreview($object->logo)) {
9653 if ((string) $imagesize == 'mini') {
9654 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
9655 } elseif ((string) $imagesize == 'small') {
9656 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
9657 } else {
9658 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
9659 }
9660 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
9661 }
9662 }
9663 $email = $object->email;
9664 } elseif ($modulepart == 'contact') {
9665 $dir = $conf->societe->multidir_output[$entity] . '/contact';
9666 if (!empty($object->photo)) {
9667 if (dolIsAllowedForPreview($object->photo)) {
9668 if ((string) $imagesize == 'mini') {
9669 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
9670 } elseif ((string) $imagesize == 'small') {
9671 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
9672 } else {
9673 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
9674 }
9675 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
9676 }
9677 }
9678 $email = $object->email;
9679 $capture = 'user';
9680 } elseif ($modulepart == 'userphoto') {
9681 $dir = $conf->user->dir_output;
9682 if (!empty($object->photo)) {
9683 if (dolIsAllowedForPreview($object->photo)) {
9684 if ((string) $imagesize == 'mini') {
9685 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
9686 } elseif ((string) $imagesize == 'small') {
9687 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
9688 } else {
9689 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
9690 }
9691 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
9692 }
9693 }
9694 if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9695 $altfile = $object->id . ".jpg"; // For backward compatibility
9696 }
9697 $email = $object->email;
9698 $capture = 'user';
9699 } elseif ($modulepart == 'memberphoto') {
9700 $dir = $conf->adherent->dir_output;
9701 if (!empty($object->photo)) {
9702 if (dolIsAllowedForPreview($object->photo)) {
9703 if ((string) $imagesize == 'mini') {
9704 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
9705 } elseif ((string) $imagesize == 'small') {
9706 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
9707 } else {
9708 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
9709 }
9710 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
9711 }
9712 }
9713 if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9714 $altfile = $object->id . ".jpg"; // For backward compatibility
9715 }
9716 $email = $object->email;
9717 $capture = 'user';
9718 } else {
9719 // Generic case to show photos
9720 $dir = $conf->$modulepart->dir_output;
9721 if (!empty($object->photo)) {
9722 if (dolIsAllowedForPreview($object->photo)) {
9723 if ((string) $imagesize == 'mini') {
9724 $file = get_exdir($id, 2, 0, 0, $object, $modulepart) . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
9725 } elseif ((string) $imagesize == 'small') {
9726 $file = get_exdir($id, 2, 0, 0, $object, $modulepart) . 'photos/' . getImageFileNameForSize($object->photo, '_small');
9727 } else {
9728 $file = get_exdir($id, 2, 0, 0, $object, $modulepart) . 'photos/' . $object->photo;
9729 }
9730 $originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart) . 'photos/' . $object->photo;
9731 }
9732 }
9733 if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9734 $altfile = $object->id . ".jpg"; // For backward compatibility
9735 }
9736 $email = $object->email;
9737 }
9738
9739 if ($forcecapture) {
9740 $capture = $forcecapture;
9741 }
9742
9743 if ($dir) {
9744 if ($file && file_exists($dir . "/" . $file)) {
9745 if ($addlinktofullsize) {
9746 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
9747 if ($urladvanced) {
9748 $ret .= '<a href="' . $urladvanced . '">';
9749 } else {
9750 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
9751 }
9752 }
9753 $ret .= '<img alt="Photo" 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 . '">';
9754 if ($addlinktofullsize) {
9755 $ret .= '</a>';
9756 }
9757 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
9758 if ($addlinktofullsize) {
9759 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
9760 if ($urladvanced) {
9761 $ret .= '<a href="' . $urladvanced . '">';
9762 } else {
9763 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
9764 }
9765 }
9766 $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 . '">';
9767 if ($addlinktofullsize) {
9768 $ret .= '</a>';
9769 }
9770 } else {
9771 $nophoto = '/public/theme/common/nophoto.png';
9772 $defaultimg = 'identicon'; // For gravatar
9773 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
9774 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor')) !== false) {
9775 $nophoto = 'company';
9776 } else {
9777 $nophoto = '/public/theme/common/user_anonymous.png';
9778 if (!empty($object->gender) && $object->gender == 'man') {
9779 $nophoto = '/public/theme/common/user_man.png';
9780 }
9781 if (!empty($object->gender) && $object->gender == 'woman') {
9782 $nophoto = '/public/theme/common/user_woman.png';
9783 }
9784 }
9785 }
9786
9787 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
9788 // see https://gravatar.com/site/implement/images/php/
9789 $ret .= '<!-- Put link to gravatar -->';
9790 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" title="' . $email . ' Gravatar avatar" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="https://www.gravatar.com/avatar/' . md5(strtolower(trim($email))) . '?s=' . $width . '&d=' . $defaultimg . '">'; // gravatar need md5 hash
9791 } else {
9792 if ($nophoto == 'company') {
9793 $ret .= '<div class="divforspanimg photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
9794 $ret .= '<div class="difforspanimgright"></div>';
9795 } else {
9796 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
9797 }
9798 }
9799 }
9800
9801 if ($caneditfield) {
9802 if ($object->photo) {
9803 $ret .= "<br>\n";
9804 }
9805 $ret .= '<table class="nobordernopadding centpercent">';
9806 if ($object->photo) {
9807 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
9808 }
9809 $ret .= '<tr><td class="tdoverflow">';
9810 $maxfilesizearray = getMaxFileSizeArray();
9811 $maxmin = $maxfilesizearray['maxmin'];
9812 if ($maxmin > 0) {
9813 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
9814 }
9815 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
9816 $ret .= '</td></tr>';
9817 $ret .= '</table>';
9818 }
9819 }
9820
9821 return $ret;
9822 }
9823
9824 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9825
9842 public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
9843 {
9844 // phpcs:enable
9845 global $conf, $user, $langs;
9846
9847 // Permettre l'exclusion de groupes
9848 $excludeGroups = null;
9849 if (is_array($exclude)) {
9850 $excludeGroups = implode(",", $exclude);
9851 }
9852 // Permettre l'inclusion de groupes
9853 $includeGroups = null;
9854 if (is_array($include)) {
9855 $includeGroups = implode(",", $include);
9856 }
9857
9858 if (!is_array($selected)) {
9859 $selected = array($selected);
9860 }
9861
9862 $out = '';
9863
9864 // On recherche les groupes
9865 $sql = "SELECT ug.rowid, ug.nom as name";
9866 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
9867 $sql .= ", e.label";
9868 }
9869 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
9870 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
9871 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
9872 if ($force_entity) {
9873 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
9874 } else {
9875 $sql .= " WHERE ug.entity IS NOT NULL";
9876 }
9877 } else {
9878 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
9879 }
9880 if (is_array($exclude) && $excludeGroups) {
9881 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
9882 }
9883 if (is_array($include) && $includeGroups) {
9884 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
9885 }
9886 $sql .= " ORDER BY ug.nom ASC";
9887
9888 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
9889 $resql = $this->db->query($sql);
9890 if ($resql) {
9891 // Enhance with select2
9892 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9893
9894 $out .= '<select class="flat minwidth200' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
9895
9896 $num = $this->db->num_rows($resql);
9897 $i = 0;
9898 if ($num) {
9899 if ($show_empty && !$multiple) {
9900 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
9901 }
9902
9903 while ($i < $num) {
9904 $obj = $this->db->fetch_object($resql);
9905 $disableline = 0;
9906 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
9907 $disableline = 1;
9908 }
9909
9910 $label = $obj->name;
9911 $labelhtml = $obj->name;
9912 if (isModEnabled('multicompany') && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1) {
9913 $label .= " (" . $obj->label . ")";
9914 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
9915 }
9916
9917 $out .= '<option value="' . $obj->rowid . '"';
9918 if ($disableline) {
9919 $out .= ' disabled';
9920 }
9921 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid) || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
9922 $out .= ' selected';
9923 }
9924 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
9925 $out .= '>';
9926
9927 $out .= $label;
9928
9929 $out .= '</option>';
9930 $i++;
9931 }
9932 } else {
9933 if ($show_empty) {
9934 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
9935 }
9936 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
9937 }
9938 $out .= '</select>';
9939
9940 $out .= ajax_combobox($htmlname);
9941 } else {
9942 dol_print_error($this->db);
9943 }
9944
9945 return $out;
9946 }
9947
9948
9955 public function showFilterButtons($pos = '')
9956 {
9957 $out = '<div class="nowraponall">';
9958 if ($pos == 'left') {
9959 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9960 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9961 } else {
9962 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9963 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9964 }
9965 $out .= '</div>';
9966
9967 return $out;
9968 }
9969
9978 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9979 {
9980 global $conf, $langs;
9981
9982 $out = '';
9983
9984 if (!empty($conf->use_javascript_ajax)) {
9985 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
9986 }
9987 $out .= '<script nonce="' . getNonce() . '">
9988 $(document).ready(function() {
9989 $("#' . $cssclass . 's").click(function() {
9990 if($(this).is(\':checked\')){
9991 console.log("We check all ' . $cssclass . ' and trigger the change method");
9992 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
9993 }
9994 else
9995 {
9996 console.log("We uncheck all");
9997 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
9998 }' . "\n";
9999 if ($calljsfunction) {
10000 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
10001 }
10002 $out .= ' });
10003 $(".' . $cssclass . '").change(function() {
10004 $(this).closest("tr").toggleClass("highlight", this.checked);
10005 });
10006 });
10007 </script>';
10008
10009 return $out;
10010 }
10011
10021 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10022 {
10023 $out = $this->showFilterButtons();
10024 if ($addcheckuncheckall) {
10025 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10026 }
10027 return $out;
10028 }
10029
10043 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10044 {
10045 global $langs, $user;
10046
10047 $out = '';
10048 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10049 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10050 if (!empty($excludeid)) {
10051 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10052 }
10053 $sql .= " ORDER BY label";
10054
10055 $resql = $this->db->query($sql);
10056 if ($resql) {
10057 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10058 if ($useempty) {
10059 $out .= '<option value="0">&nbsp;</option>';
10060 }
10061
10062 while ($obj = $this->db->fetch_object($resql)) {
10063 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10064 }
10065 $out .= '</select>';
10066 $out .= ajax_combobox('select_' . $htmlname);
10067
10068 if (!empty($htmlname) && $user->admin && $info_admin) {
10069 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10070 }
10071
10072 if (!empty($target)) {
10073 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10074 $resql = $this->db->query($sql);
10075 if ($resql) {
10076 if ($this->db->num_rows($resql) > 0) {
10077 $obj = $this->db->fetch_object($resql);
10078 $out .= '<script nonce="' . getNonce() . '">
10079 $(function() {
10080 $("select[name=' . $target . ']").on("change", function() {
10081 var current_val = $(this).val();
10082 if (current_val == ' . $obj->id . ') {';
10083 if (!empty($default_selected) || !empty($selected)) {
10084 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10085 }
10086
10087 $out .= '
10088 $("select[name=' . $htmlname . ']").change();
10089 }
10090 });
10091
10092 $("select[name=' . $htmlname . ']").change(function() {
10093
10094 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10095 // get price of kilometer to fill the unit price
10096 $.ajax({
10097 method: "POST",
10098 dataType: "json",
10099 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10100 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . join('&', $params)) . '",
10101 }).done(function( data, textStatus, jqXHR ) {
10102 console.log(data);
10103 if (typeof data.up != "undefined") {
10104 $("input[name=value_unit]").val(data.up);
10105 $("select[name=' . $htmlname . ']").attr("title", data.title);
10106 } else {
10107 $("input[name=value_unit]").val("");
10108 $("select[name=' . $htmlname . ']").attr("title", "");
10109 }
10110 });
10111 }
10112 });
10113 });
10114 </script>';
10115 }
10116 }
10117 }
10118 } else {
10119 dol_print_error($this->db);
10120 }
10121
10122 return $out;
10123 }
10124
10133 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10134 {
10135 global $conf, $langs;
10136
10137 $out = '';
10138 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10139 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10140
10141 $resql = $this->db->query($sql);
10142 if ($resql) {
10143 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10144 if ($useempty) {
10145 $out .= '<option value="0"></option>';
10146 }
10147
10148 while ($obj = $this->db->fetch_object($resql)) {
10149 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10150 }
10151 $out .= '</select>';
10152 } else {
10153 dol_print_error($this->db);
10154 }
10155
10156 return $out;
10157 }
10158
10169 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10170 {
10171 global $langs;
10172
10173 $out = '';
10174 $sql = "SELECT id, code, label FROM " . $this->db->prefix() . "c_type_fees";
10175 $sql .= " WHERE active = 1";
10176
10177 $resql = $this->db->query($sql);
10178 if ($resql) {
10179 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10180 if ($useempty) {
10181 $out .= '<option value="0"></option>';
10182 }
10183 if ($allchoice) {
10184 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10185 }
10186
10187 $field = 'code';
10188 if ($useid) {
10189 $field = 'id';
10190 }
10191
10192 while ($obj = $this->db->fetch_object($resql)) {
10193 $key = $langs->trans($obj->code);
10194 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10195 }
10196 $out .= '</select>';
10197 } else {
10198 dol_print_error($this->db);
10199 }
10200
10201 return $out;
10202 }
10203
10222 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)
10223 {
10224 global $user, $conf, $langs;
10225
10226 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10227
10228 if (is_null($usertofilter)) {
10229 $usertofilter = $user;
10230 }
10231
10232 $out = '';
10233
10234 $hideunselectables = false;
10235 if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) {
10236 $hideunselectables = true;
10237 }
10238
10239 if (empty($projectsListId)) {
10240 if (empty($usertofilter->rights->projet->all->lire)) {
10241 $projectstatic = new Project($this->db);
10242 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10243 }
10244 }
10245
10246 // Search all projects
10247 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10248 p.title, p.fk_soc, p.fk_statut, p.public,";
10249 $sql .= ' s.nom as name';
10250 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
10251 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
10252 $sql .= ' ' . $this->db->prefix() . 'facture as f';
10253 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
10254 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
10255 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
10256 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
10257 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
10258 $sql .= " ORDER BY p.ref, f.ref ASC";
10259
10260 $resql = $this->db->query($sql);
10261 if ($resql) {
10262 // Use select2 selector
10263 if (!empty($conf->use_javascript_ajax)) {
10264 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10265 $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10266 $out .= $comboenhancement;
10267 $morecss = 'minwidth200imp maxwidth500';
10268 }
10269
10270 if (empty($option_only)) {
10271 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10272 }
10273 if (!empty($show_empty)) {
10274 $out .= '<option value="0" class="optiongrey">';
10275 if (!is_numeric($show_empty)) {
10276 $out .= $show_empty;
10277 } else {
10278 $out .= '&nbsp;';
10279 }
10280 $out .= '</option>';
10281 }
10282 $num = $this->db->num_rows($resql);
10283 $i = 0;
10284 if ($num) {
10285 while ($i < $num) {
10286 $obj = $this->db->fetch_object($resql);
10287 // 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.
10288 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire)) {
10289 // Do nothing
10290 } else {
10291 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
10292 $i++;
10293 continue;
10294 }
10295
10296 $labeltoshow = '';
10297
10298 if ($showproject == 'all') {
10299 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
10300 if ($obj->name) {
10301 $labeltoshow .= ' - ' . $obj->name; // Soc name
10302 }
10303
10304 $disabled = 0;
10305 if ($obj->fk_statut == Project::STATUS_DRAFT) {
10306 $disabled = 1;
10307 $labeltoshow .= ' - ' . $langs->trans("Draft");
10308 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
10309 if ($discard_closed == 2) {
10310 $disabled = 1;
10311 }
10312 $labeltoshow .= ' - ' . $langs->trans("Closed");
10313 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
10314 $disabled = 1;
10315 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
10316 }
10317 }
10318
10319 if (!empty($selected) && $selected == $obj->rowid) {
10320 $out .= '<option value="' . $obj->rowid . '" selected';
10321 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10322 $out .= '>' . $labeltoshow . '</option>';
10323 } else {
10324 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
10325 $resultat = '';
10326 } else {
10327 $resultat = '<option value="' . $obj->rowid . '"';
10328 if ($disabled) {
10329 $resultat .= ' disabled';
10330 }
10331 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
10332 //else $labeltoshow.=' ('.$langs->trans("Private").')';
10333 $resultat .= '>';
10334 $resultat .= $labeltoshow;
10335 $resultat .= '</option>';
10336 }
10337 $out .= $resultat;
10338 }
10339 }
10340 $i++;
10341 }
10342 }
10343 if (empty($option_only)) {
10344 $out .= '</select>';
10345 }
10346
10347 $this->db->free($resql);
10348
10349 return $out;
10350 } else {
10351 dol_print_error($this->db);
10352 return '';
10353 }
10354 }
10355
10369 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
10370 {
10371 global $user, $conf, $langs;
10372
10373 $out = '';
10374
10375 dol_syslog('FactureRec::fetch', LOG_DEBUG);
10376
10377 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
10378 //$sql.= ', el.fk_source';
10379 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
10380 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
10381 $sql .= " ORDER BY f.titre ASC";
10382
10383 $resql = $this->db->query($sql);
10384 if ($resql) {
10385 // Use select2 selector
10386 if (!empty($conf->use_javascript_ajax)) {
10387 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10388 $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10389 $out .= $comboenhancement;
10390 $morecss = 'minwidth200imp maxwidth500';
10391 }
10392
10393 if (empty($option_only)) {
10394 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10395 }
10396 if (!empty($show_empty)) {
10397 $out .= '<option value="0" class="optiongrey">';
10398 if (!is_numeric($show_empty)) {
10399 $out .= $show_empty;
10400 } else {
10401 $out .= '&nbsp;';
10402 }
10403 $out .= '</option>';
10404 }
10405 $num = $this->db->num_rows($resql);
10406 if ($num) {
10407 while ($obj = $this->db->fetch_object($resql)) {
10408 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
10409
10410 $disabled = 0;
10411 if (!empty($obj->suspended)) {
10412 $disabled = 1;
10413 $labeltoshow .= ' - ' . $langs->trans("Closed");
10414 }
10415
10416
10417 if (!empty($selected) && $selected == $obj->rowid) {
10418 $out .= '<option value="' . $obj->rowid . '" selected';
10419 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10420 $out .= '>' . $labeltoshow . '</option>';
10421 } else {
10422 if ($disabled && ($selected != $obj->rowid)) {
10423 $resultat = '';
10424 } else {
10425 $resultat = '<option value="' . $obj->rowid . '"';
10426 if ($disabled) {
10427 $resultat .= ' disabled';
10428 }
10429 $resultat .= '>';
10430 $resultat .= $labeltoshow;
10431 $resultat .= '</option>';
10432 }
10433 $out .= $resultat;
10434 }
10435 }
10436 }
10437 if (empty($option_only)) {
10438 $out .= '</select>';
10439 }
10440
10441 print $out;
10442
10443 $this->db->free($resql);
10444 return $num;
10445 } else {
10446 $this->errors[] = $this->db->lasterror;
10447 return -1;
10448 }
10449 }
10450
10460 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '')
10461 {
10462 global $langs;
10463
10464 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
10465 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
10466 }
10467
10468 $ret = '';
10469
10470 $ret .= '<div class="divadvancedsearchfieldcomp inline-block">';
10471 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
10472 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
10473 $ret .= '</a>';
10474
10475 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
10476
10477 // Show select fields as tags.
10478 $ret .= '<div name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
10479
10480 if ($search_component_params_hidden) {
10481 // Split the criteria on each AND
10482 //var_dump($search_component_params_hidden);
10483
10484 $nbofchars = dol_strlen($search_component_params_hidden);
10485 $arrayofandtags = array();
10486 $i = 0; $s = '';
10487 $countparenthesis = 0;
10488 while ($i < $nbofchars) {
10489 $char = dol_substr($search_component_params_hidden, $i, 1);
10490
10491 if ($char == '(') {
10492 $countparenthesis++;
10493 } elseif ($char == ')') {
10494 $countparenthesis--;
10495 }
10496
10497 if ($countparenthesis == 0) {
10498 $char2 = dol_substr($search_component_params_hidden, $i+1, 1);
10499 $char3 = dol_substr($search_component_params_hidden, $i+2, 1);
10500 if ($char == 'A' && $char2 == 'N' && $char3 == 'D') {
10501 // We found a AND
10502 $arrayofandtags[] = trim($s);
10503 $s = '';
10504 $i+=2;
10505 } else {
10506 $s .= $char;
10507 }
10508 } else {
10509 $s .= $char;
10510 }
10511 $i++;
10512 }
10513 if ($s) {
10514 $arrayofandtags[] = trim($s);
10515 }
10516
10517 // Show each AND part
10518 foreach ($arrayofandtags as $tmpkey => $tmpval) {
10519 $errormessage = '';
10520 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
10521 if ($errormessage) {
10522 $this->error = 'ERROR in parsing search string: '.$errormessage;
10523 }
10524 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
10525 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
10526 $searchtags = removeGlobalParenthesis($searchtags);
10527
10528 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey+1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
10529 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey+1).'">x</span> ';
10530 $ret .= dol_escape_htmltag($searchtags);
10531 $ret .= '</span>';
10532 }
10533 }
10534
10535 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
10536
10537 //$ret .= search_component_params
10538 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
10539 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
10540
10541 $show_search_component_params_hidden = 1;
10542 if ($show_search_component_params_hidden) {
10543 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
10544 }
10545 $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%')) -->";
10546 $ret .= '<input type="hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
10547 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
10548
10549 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
10550 foreach ($arrayofcriterias as $criterias) {
10551 foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
10552 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
10553 continue;
10554 }
10555 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
10556 continue;
10557 }
10558 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
10559 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
10560 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
10561 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
10562 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
10563 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
10564 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
10565 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
10566 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
10567 } else {
10568 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
10569 }
10570 }
10571 }
10572
10573 $ret .= '</div>';
10574
10575 $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";
10576 $ret .= '<input type="text" placeholder="' . $langs->trans("Search") . '" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
10577
10578 $ret .= '</div>';
10579 $ret .= '</div>';
10580
10581 $ret .= '<script>
10582 jQuery(".tagsearchdelete").click(function() {
10583 var filterid = $(this).parents().data("ufilterid");
10584 console.log("We click to delete a criteria nb "+filterid);
10585 // TODO Update the search_component_params_hidden with all data-ufilter except the one delete and post page
10586
10587 });
10588 </script>
10589 ';
10590
10591
10592 return $ret;
10593 }
10594
10604 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
10605 {
10606 global $langs, $user;
10607
10608 $retstring = '';
10609
10610 $TModels = array();
10611
10612 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
10613 $formmail = new FormMail($this->db);
10614 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
10615
10616 if ($default) {
10617 $TModels[0] = $langs->trans('DefaultMailModel');
10618 }
10619 if ($result > 0) {
10620 foreach ($formmail->lines_model as $model) {
10621 $TModels[$model->id] = $model->label;
10622 }
10623 }
10624
10625 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
10626
10627 foreach ($TModels as $id_model => $label_model) {
10628 $retstring .= '<option value="' . $id_model . '"';
10629 $retstring .= ">" . $label_model . "</option>";
10630 }
10631
10632 $retstring .= "</select>";
10633
10634 if ($addjscombo) {
10635 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
10636 }
10637
10638 return $retstring;
10639 }
10640
10652 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = 0, $morecss = '', $dol_openinpopup = '')
10653 {
10654 global $langs;
10655
10656 $buttons = array();
10657
10658 $save = array(
10659 'name' => 'save',
10660 'label_key' => $save_label,
10661 );
10662
10663 if ($save_label == 'Create' || $save_label == 'Add') {
10664 $save['name'] = 'add';
10665 } elseif ($save_label == 'Modify') {
10666 $save['name'] = 'edit';
10667 }
10668
10669 $cancel = array(
10670 'name' => 'cancel',
10671 'label_key' => 'Cancel',
10672 );
10673
10674 !empty($save_label) ? $buttons[] = $save : '';
10675
10676 if (!empty($morebuttons)) {
10677 $buttons[] = $morebuttons;
10678 }
10679
10680 !empty($cancel_label) ? $buttons[] = $cancel : '';
10681
10682 $retstring = $withoutdiv ? '' : '<div class="center">';
10683
10684 foreach ($buttons as $button) {
10685 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
10686 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
10687 }
10688 $retstring .= $withoutdiv ? '' : '</div>';
10689
10690 if ($dol_openinpopup) {
10691 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . $dol_openinpopup . ' context, so we enable the close of dialog on cancel -->' . "\n";
10692 $retstring .= '<script nonce="' . getNonce() . '">';
10693 $retstring .= 'jQuery(".button-cancel").click(function(e) {
10694 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . $dol_openinpopup . '\');
10695 window.parent.jQuery(\'#idfordialog' . $dol_openinpopup . '\').dialog(\'close\');
10696 });';
10697 $retstring .= '</script>';
10698 }
10699
10700 return $retstring;
10701 }
10702}
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to a page to transform a common input field into an au...
Definition ajax.lib.php:47
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:464
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 field into an au...
Definition ajax.lib.php:312
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:565
$object ref
Definition info.php:78
Class to manage bank accounts.
Class to manage categories.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
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 seach 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 vat rates of a country.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0)
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
select_address($selected, $socid, $htmlname='address_id', $showempty=0)
Return list of delivery address.
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.
select_contacts($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $showsoc=0, $forcecombo=0, $events=array(), $options_only=false, $moreparam='', $htmlid='')
Return list of all contacts (for a third party or all)
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
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.
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.
selectcontacts($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=false, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0)
Return HTML code of the SELECT of list of all contacts (for a third party or all).
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear seach 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.
form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
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_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0')
Return the HTML select list of users.
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_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
select_dolgroups($selected='', $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly='', $force_entity='0', $multiple=false, $morecss='')
Return select list of groups.
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 optionaly hours and minute...
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.
form_users($page, $selected='', $htmlname='userid', $exclude='', $include='')
Show a select form to choose a user.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=0, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
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.
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='')
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.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=false, $title='RelatedObjects')
Show linked object block.
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.
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
print list of payment modes.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier='')
Return list of suppliers prices for a product.
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.
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $markafterid=0, $outputmode=0, $include=0, $morecss='')
Return list of categories having choosed type.
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)
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()
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
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.
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array())
Return select list of users.
form_confirm($page, $title, $question, $action, $formquestion='', $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_produits_list($selected='', $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1)
Return list of products for a customer.
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.
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_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 optionaly hours and minute...
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.
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.
select_produits($selected='', $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 in Ajax if Ajax activated or go to select_produits_list.
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.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse='', $societe_acheteuse='', $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0)
Output an HTML select vat rate.
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.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
load_cache_types_paiements()
selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty='', $searchkey='', $placeholder='', $morecss='', $moreparams='', $forcecombo=0, $disabled=0, $selected_input_value='')
Generic method to select a component from a combo list.
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday='', $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
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...
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Class to manage building of HTML components.
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.
currency_name($code_iso, $withcode='', $outputlangs=null)
Return label of currency or code+label.
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or 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:84
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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_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.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
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_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
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.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='float')
Show Url link.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
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...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier 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...
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1632
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition main.inc.php:89
ui dialog ui datepicker calendar ui widget content ui state ui datepicker calendar ui widget header ui state ui datepicker calendar ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
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:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:123
getMaxFileSizeArray()
Return the max allowed for file upload.