dolibarr 19.0.3
html.form.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13 * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18 * Copyright (C) 2014-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-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 * Copyright (C) 2023 Nick Fragoulis
26 *
27 * This program is free software; you can redistribute it and/or modify
28 * it under the terms of the GNU General Public License as published by
29 * the Free Software Foundation; either version 3 of the License, or
30 * (at your option) any later version.
31 *
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
36 *
37 * You should have received a copy of the GNU General Public License
38 * along with this program. If not, see <https://www.gnu.org/licenses/>.
39 */
40
54class Form
55{
59 public $db;
60
64 public $error = '';
65
69 public $errors = array();
70
71 // Some properties used to return data by some methods
72 public $result;
73 public $num;
74
75 // Cache arrays
76 public $cache_types_paiements = array();
77 public $cache_conditions_paiements = array();
78 public $cache_transport_mode = array();
79 public $cache_availability = array();
80 public $cache_demand_reason = array();
81 public $cache_types_fees = array();
82 public $cache_vatrates = array();
83 public $cache_invoice_subtype = array();
84
85
91 public function __construct($db)
92 {
93 $this->db = $db;
94 }
95
112 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
113 {
114 global $conf, $langs;
115
116 $ret = '';
117
118 // TODO change for compatibility
119 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
120 if (!empty($perm)) {
121 $tmp = explode(':', $typeofdata);
122 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
123 if ($fieldrequired) {
124 $ret .= '<span class="fieldrequired">';
125 }
126 if ($help) {
127 $ret .= $this->textwithpicto($langs->trans($text), $help);
128 } else {
129 $ret .= $langs->trans($text);
130 }
131 if ($fieldrequired) {
132 $ret .= '</span>';
133 }
134 $ret .= '</div>' . "\n";
135 } else {
136 if ($fieldrequired) {
137 $ret .= '<span class="fieldrequired">';
138 }
139 if ($help) {
140 $ret .= $this->textwithpicto($langs->trans($text), $help);
141 } else {
142 $ret .= $langs->trans($text);
143 }
144 if ($fieldrequired) {
145 $ret .= '</span>';
146 }
147 }
148 } else {
149 if (empty($notabletag) && $perm) {
150 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
151 }
152 if ($fieldrequired) {
153 $ret .= '<span class="fieldrequired">';
154 }
155 if ($help) {
156 $ret .= $this->textwithpicto($langs->trans($text), $help);
157 } else {
158 $ret .= $langs->trans($text);
159 }
160 if ($fieldrequired) {
161 $ret .= '</span>';
162 }
163 if (!empty($notabletag)) {
164 $ret .= ' ';
165 }
166 if (empty($notabletag) && $perm) {
167 $ret .= '</td>';
168 }
169 if (empty($notabletag) && $perm) {
170 $ret .= '<td class="right">';
171 }
172 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
173 $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>';
174 }
175 if (!empty($notabletag) && $notabletag == 1) {
176 if ($text) {
177 $ret .= ' : ';
178 } else {
179 $ret .= ' ';
180 }
181 }
182 if (!empty($notabletag) && $notabletag == 3) {
183 $ret .= ' ';
184 }
185 if (empty($notabletag) && $perm) {
186 $ret .= '</td>';
187 }
188 if (empty($notabletag) && $perm) {
189 $ret .= '</tr></table>';
190 }
191 }
192
193 return $ret;
194 }
195
219 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 = '')
220 {
221 global $conf, $langs;
222
223 $ret = '';
224
225 // Check parameters
226 if (empty($typeofdata)) {
227 return 'ErrorBadParameter typeofdata is empty';
228 }
229 // Clean paramater $typeofdata
230 if ($typeofdata == 'datetime') {
231 $typeofdata = 'dayhour';
232 }
233 $reg = array();
234 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
235 if ($reg[1] == 'varchar') {
236 $typeofdata = 'string';
237 } elseif ($reg[1] == 'int') {
238 $typeofdata = 'numeric';
239 } else {
240 return 'ErrorBadParameter ' . $typeofdata;
241 }
242 }
243
244 // When option to edit inline is activated
245 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
246 $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
247 } else {
248 if ($editaction == '') {
249 $editaction = GETPOST('action', 'aZ09');
250 }
251 $editmode = ($editaction == 'edit' . $htmlname);
252 if ($editmode) { // edit mode
253 $ret .= "\n";
254 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
255 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
256 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
257 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
258 if (empty($notabletag)) {
259 $ret .= '<table class="nobordernopadding centpercent">';
260 }
261 if (empty($notabletag)) {
262 $ret .= '<tr><td>';
263 }
264 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
265 $tmp = explode(':', $typeofdata);
266 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
267 } elseif (preg_match('/^(integer)/', $typeofdata)) {
268 $tmp = explode(':', $typeofdata);
269 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
270 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
271 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
272 $tmp = explode(':', $typeofdata);
273 $valuetoshow = price2num($editvalue ? $editvalue : $value);
274 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
275 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
276 $tmp = explode(':', $typeofdata);
277 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
278 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
279 $tmp = explode(':', $typeofdata);
280 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
281 $morealt = '';
282 if (preg_match('/%/', $cols)) {
283 $morealt = ' style="width: ' . $cols . '"';
284 $cols = '';
285 }
286 $valuetoshow = ($editvalue ? $editvalue : $value);
287 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
288 // textarea convert automatically entities chars into simple chars.
289 // 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.
290 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
291 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
292 $ret .= '</textarea>';
293 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
294 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
295 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
296 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
297 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
298 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
299 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
300 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
301 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
302 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
303 } elseif (preg_match('/^select;/', $typeofdata)) {
304 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
305 $arraylist = array();
306 foreach ($arraydata as $val) {
307 $tmp = explode(':', $val);
308 $tmpkey = str_replace('|', ':', $tmp[0]);
309 $arraylist[$tmpkey] = $tmp[1];
310 }
311 $ret .= $this->selectarray($htmlname, $arraylist, $value);
312 } elseif (preg_match('/^link/', $typeofdata)) {
313 // TODO Not yet implemented. See code for extrafields
314 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
315 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
316 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
317 $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]));
318 $ret .= $doleditor->Create(1);
319 } elseif ($typeofdata == 'asis') {
320 $ret .= ($editvalue ? $editvalue : $value);
321 }
322 if (empty($notabletag)) {
323 $ret .= '</td>';
324 }
325
326 // Button save-cancel
327 if (empty($notabletag)) {
328 $ret .= '<td>';
329 }
330 //else $ret.='<div class="clearboth"></div>';
331 $ret .= '<input type="submit" class="smallpaddingimp button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
332 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
333 $ret .= '<br>' . "\n";
334 }
335 $ret .= '<input type="submit" class="smallpaddingimp button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
336 if (empty($notabletag)) {
337 $ret .= '</td>';
338 }
339
340 if (empty($notabletag)) {
341 $ret .= '</tr></table>' . "\n";
342 }
343 $ret .= '</form>' . "\n";
344 } else { // view mode
345 if (preg_match('/^email/', $typeofdata)) {
346 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
347 } elseif (preg_match('/^phone/', $typeofdata)) {
348 $ret .= dol_print_phone($value, '_blank', 32, 1);
349 } elseif (preg_match('/^url/', $typeofdata)) {
350 $ret .= dol_print_url($value, '_blank', 32, 1);
351 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
352 $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
353 } elseif (preg_match('/^checkbox/', $typeofdata)) {
354 $tmp = explode(':', $typeofdata);
355 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
356 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
358 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
360 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
361 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
362 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
363 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
364 } elseif (preg_match('/^select;/', $typeofdata)) {
365 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
366 $arraylist = array();
367 foreach ($arraydata as $val) {
368 $tmp = explode(':', $val);
369 $arraylist[$tmp[0]] = $tmp[1];
370 }
371 $ret .= $arraylist[$value];
372 if ($htmlname == 'fk_product_type') {
373 if ($value == 0) {
374 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
375 } else {
376 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
377 }
378 }
379 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
380 $tmpcontent = dol_htmlentitiesbr($value);
381 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
382 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
383 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
384 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
385 }
386 // We dont use dol_escape_htmltag to get the html formating active, but this need we must also
387 // clean data from some dangerous html
389 } else {
390 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
391 $ret .= dol_escape_htmltag($value);
392 } else {
393 $ret .= $value; // $value must be already html escaped.
394 }
395 }
396
397 // Custom format if parameter $formatfunc has been provided
398 if ($formatfunc && method_exists($object, $formatfunc)) {
399 $ret = $object->$formatfunc($ret);
400 }
401 }
402 }
403 return $ret;
404 }
405
417 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
418 {
419 global $conf, $langs, $extralanguages;
420
421 $result = '';
422
423 // List of extra languages
424 $arrayoflangcode = array();
425 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
426 $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
427 }
428
429 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
430 if (!is_object($extralanguages)) {
431 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
432 $extralanguages = new ExtraLanguages($this->db);
433 }
434 $extralanguages->fetch_name_extralanguages('societe');
435
436 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
437 return ''; // No extralang field to show
438 }
439
440 $result .= '<!-- Widget for translation -->' . "\n";
441 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
442 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
443 $result .= $s;
444 $result .= '</div>';
445
446 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
447
448 $resultforextrlang = '';
449 foreach ($arrayoflangcode as $langcode) {
450 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
451 if (empty($valuetoshow)) {
452 $object->fetchValuesForExtraLanguages();
453 //var_dump($object->array_languages);
454 $valuetoshow = $object->array_languages[$fieldname][$langcode];
455 }
456
457 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
458 $resultforextrlang .= $s;
459
460 // TODO Use the showInputField() method of ExtraLanguages object
461 if ($typeofdata == 'textarea') {
462 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
463 $resultforextrlang .= $valuetoshow;
464 $resultforextrlang .= '</textarea>';
465 } else {
466 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
467 }
468 }
469 $result .= $resultforextrlang;
470
471 $result .= '</div>';
472 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
473 }
474
475 return $result;
476 }
477
491 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
492 {
493 global $conf;
494
495 $out = '';
496
497 // Check parameters
498 if (preg_match('/^text/', $inputType)) {
499 $value = dol_nl2br($value);
500 } elseif (preg_match('/^numeric/', $inputType)) {
501 $value = price($value);
502 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
503 $value = dol_print_date($value, 'day');
504 }
505
506 if ($condition) {
507 $element = false;
508 $table_element = false;
509 $fk_element = false;
510 $loadmethod = false;
511 $savemethod = false;
512 $ext_element = false;
513 $button_only = false;
514 $inputOption = '';
515 $rows = '';
516 $cols = '';
517
518 if (is_object($object)) {
519 $element = $object->element;
520 $table_element = $object->table_element;
521 $fk_element = $object->id;
522 }
523
524 if (is_object($extObject)) {
525 $ext_element = $extObject->element;
526 }
527
528 if (preg_match('/^(string|email|numeric)/', $inputType)) {
529 $tmp = explode(':', $inputType);
530 $inputType = $tmp[0];
531 if (!empty($tmp[1])) {
532 $inputOption = $tmp[1];
533 }
534 if (!empty($tmp[2])) {
535 $savemethod = $tmp[2];
536 }
537 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
538 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
539 $tmp = explode(':', $inputType);
540 $inputType = $tmp[0];
541 if (!empty($tmp[1])) {
542 $inputOption = $tmp[1];
543 }
544 if (!empty($tmp[2])) {
545 $savemethod = $tmp[2];
546 }
547
548 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
549 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
550 $tmp = explode(':', $inputType);
551 $inputType = $tmp[0];
552 $loadmethod = $tmp[1];
553 if (!empty($tmp[2])) {
554 $savemethod = $tmp[2];
555 }
556 if (!empty($tmp[3])) {
557 $button_only = true;
558 }
559 } elseif (preg_match('/^textarea/', $inputType)) {
560 $tmp = explode(':', $inputType);
561 $inputType = $tmp[0];
562 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
563 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
564 } elseif (preg_match('/^ckeditor/', $inputType)) {
565 $tmp = explode(':', $inputType);
566 $inputType = $tmp[0];
567 $toolbar = $tmp[1];
568 if (!empty($tmp[2])) {
569 $width = $tmp[2];
570 }
571 if (!empty($tmp[3])) {
572 $heigth = $tmp[3];
573 }
574 if (!empty($tmp[4])) {
575 $savemethod = $tmp[4];
576 }
577
578 if (isModEnabled('fckeditor')) {
579 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
580 } else {
581 $inputType = 'textarea';
582 }
583 }
584
585 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
586 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
587 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
588 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
589 if (!empty($savemethod)) {
590 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
591 }
592 if (!empty($ext_element)) {
593 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
594 }
595 if (!empty($custommsg)) {
596 if (is_array($custommsg)) {
597 if (!empty($custommsg['success'])) {
598 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
599 }
600 if (!empty($custommsg['error'])) {
601 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
602 }
603 } else {
604 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
605 }
606 }
607 if ($inputType == 'textarea') {
608 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
609 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
610 }
611 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
612 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
613 } else {
614 $out = $value;
615 }
616
617 return $out;
618 }
619
638 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
639 {
640 if ($incbefore) {
641 $text = $incbefore . $text;
642 }
643 if (!$htmltext) {
644 return $text;
645 }
646 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
647
648 $tag = 'td';
649 if ($notabs == 2) {
650 $tag = 'div';
651 }
652 if ($notabs == 3) {
653 $tag = 'span';
654 }
655 // Sanitize tooltip
656 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
657
658 $extrastyle = '';
659 if ($direction < 0) {
660 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
661 $extrastyle = 'padding: 0px; padding-left: 3px;';
662 }
663 if ($direction > 0) {
664 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
665 $extrastyle = 'padding: 0px; padding-right: 3px;';
666 }
667
668 $classfortooltip = 'classfortooltip';
669
670 $s = '';
671 $textfordialog = '';
672
673 if ($tooltiptrigger == '') {
674 $htmltext = str_replace('"', '&quot;', $htmltext);
675 } else {
676 $classfortooltip = 'classfortooltiponclick';
677 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
678 }
679 if ($tooltipon == 2 || $tooltipon == 3) {
680 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
681 if ($tooltiptrigger == '') {
682 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribut to put on img tag to store tooltip
683 } else {
684 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
685 }
686 } else {
687 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribut to put on td text tag
688 }
689 if ($tooltipon == 1 || $tooltipon == 3) {
690 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
691 if ($tooltiptrigger == '') {
692 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribut to put on td tag to store tooltip
693 } else {
694 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
695 }
696 } else {
697 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribut to put on td text tag
698 }
699 if (empty($notabs)) {
700 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
701 } elseif ($notabs == 2) {
702 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
703 }
704 // Define value if value is before
705 if ($direction < 0) {
706 $s .= '<' . $tag . $paramfortooltipimg;
707 if ($tag == 'td') {
708 $s .= ' class="valigntop" width="14"';
709 }
710 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
711 }
712 // Use another method to help avoid having a space in value in order to use this value with jquery
713 // Define label
714 if ((string) $text != '') {
715 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
716 }
717 // Define value if value is after
718 if ($direction > 0) {
719 $s .= '<' . $tag . $paramfortooltipimg;
720 if ($tag == 'td') {
721 $s .= ' class="valignmiddle" width="14"';
722 }
723 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
724 }
725 if (empty($notabs)) {
726 $s .= '</tr></table>';
727 } elseif ($notabs == 2) {
728 $s .= '</div>';
729 }
730
731 return $s;
732 }
733
748 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
749 {
750 global $conf, $langs;
751
752 //For backwards compatibility
753 if ($type == '0') {
754 $type = 'info';
755 } elseif ($type == '1') {
756 $type = 'help';
757 }
758 // Clean parameters
759 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
760
761 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
762 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
763 }
764 $alt = '';
765 if ($tooltiptrigger) {
766 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
767 }
768
769 // If info or help with no javascript, show only text
770 if (empty($conf->use_javascript_ajax)) {
771 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
772 return $text;
773 } else {
774 $alt = $htmltext;
775 $htmltext = '';
776 }
777 }
778
779 // If info or help with smartphone, show only text (tooltip hover can't works)
780 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
781 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
782 return $text;
783 }
784 }
785 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
786 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
787 //{
788 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
789 //}
790
791 $img = '';
792 if ($type == 'info') {
793 $img = img_help(0, $alt);
794 } elseif ($type == 'help') {
795 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
796 } elseif ($type == 'helpclickable') {
797 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
798 } elseif ($type == 'superadmin') {
799 $img = img_picto($alt, 'redstar');
800 } elseif ($type == 'admin') {
801 $img = img_picto($alt, 'star');
802 } elseif ($type == 'warning') {
803 $img = img_warning($alt);
804 } elseif ($type != 'none') {
805 $img = img_picto($alt, $type); // $type can be an image path
806 }
807
808 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
809 }
810
821 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
822 {
823 global $conf, $langs, $hookmanager;
824
825 $disabled = 0;
826 $ret = '<div class="centpercent center">';
827 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
828
829 // 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.
830 $parameters = array();
831 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
832 // check if there is a mass action
833
834 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
835 return;
836 }
837 if (empty($reshook)) {
838 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
839 if (is_array($arrayofaction)) {
840 foreach ($arrayofaction as $code => $label) {
841 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
842 }
843 }
844 }
845 $ret .= $hookmanager->resPrint;
846
847 $ret .= '</select>';
848
849 if (empty($conf->dol_optimize_smallscreen)) {
850 $ret .= ajax_combobox('.' . $name . 'select');
851 }
852
853 // 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
854 $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.
855 $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")) . '">';
856 $ret .= '</div>';
857
858 if (!empty($conf->use_javascript_ajax)) {
859 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
860 <script nonce="' . getNonce() . '">
861 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 */
862 {
863 atleastoneselected=0;
864 jQuery("."+cssclass).each(function( index ) {
865 /* console.log( index + ": " + $( this ).text() ); */
866 if ($(this).is(\':checked\')) atleastoneselected++;
867 });
868
869 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
870
871 if (atleastoneselected || ' . $alwaysvisible . ')
872 {
873 jQuery("."+name).show();
874 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
875 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
876 }
877 else
878 {
879 jQuery("."+name).hide();
880 jQuery("."+name+"other").hide();
881 }
882 }
883
884 jQuery(document).ready(function () {
885 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
886 jQuery(".' . $cssclass . '").click(function() {
887 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
888 });
889 jQuery(".' . $name . 'select").change(function() {
890 var massaction = $( this ).val();
891 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
892 if (massaction == "builddoc")
893 {
894 urlform = urlform + "#show_files";
895 }
896 $( this ).closest("form").attr("action", urlform);
897 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
898 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
899 if ($(this).val() != \'0\')
900 {
901 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
902 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
903 jQuery(".' . $name . '"+massaction).show();
904 }
905 else
906 {
907 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
908 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
909 }
910 });
911 });
912 </script>
913 ';
914 }
915
916 return $ret;
917 }
918
919 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
920
937 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)
938 {
939 // phpcs:enable
940 global $conf, $langs, $mysoc;
941
942 $langs->load("dict");
943
944 $out = '';
945 $countryArray = array();
946 $favorite = array();
947 $label = array();
948 $atleastonefavorite = 0;
949
950 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
951 $sql .= " FROM " . $this->db->prefix() . "c_country";
952 $sql .= " WHERE active > 0";
953 //$sql.= " ORDER BY code ASC";
954
955 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
956 $resql = $this->db->query($sql);
957 if ($resql) {
958 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
959 $num = $this->db->num_rows($resql);
960 $i = 0;
961 if ($num) {
962 while ($i < $num) {
963 $obj = $this->db->fetch_object($resql);
964
965 $countryArray[$i]['rowid'] = $obj->rowid;
966 $countryArray[$i]['code_iso'] = $obj->code_iso;
967 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
968 $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 : ''));
969 $countryArray[$i]['favorite'] = $obj->favorite;
970 $countryArray[$i]['eec'] = $obj->eec;
971 $favorite[$i] = $obj->favorite;
972 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
973 $i++;
974 }
975
976 if (empty($disablefavorites)) {
977 $array1_sort_order = SORT_DESC;
978 $array2_sort_order = SORT_ASC;
979 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
980 } else {
981 $countryArray = dol_sort_array($countryArray, 'label');
982 }
983
984 if ($showempty) {
985 if (is_numeric($showempty)) {
986 $out .= '<option value="">&nbsp;</option>' . "\n";
987 } else {
988 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
989 }
990 }
991
992 if ($addspecialentries) { // Add dedicated entries for groups of countries
993 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
994 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
995 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
996 if ($mysoc->isInEEC()) {
997 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
998 }
999 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1000 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1001 }
1002
1003 foreach ($countryArray as $row) {
1004 //if (empty($showempty) && empty($row['rowid'])) continue;
1005 if (empty($row['rowid'])) {
1006 continue;
1007 }
1008 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1009 continue; // exclude some countries
1010 }
1011
1012 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1013 $atleastonefavorite++;
1014 }
1015 if (empty($row['favorite']) && $atleastonefavorite) {
1016 $atleastonefavorite = 0;
1017 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1018 }
1019
1020 $labeltoshow = '';
1021 if ($row['label']) {
1022 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1023 } else {
1024 $labeltoshow .= '&nbsp;';
1025 }
1026 if ($row['code_iso']) {
1027 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1028 if (empty($hideflags)) {
1029 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1030 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1031 }
1032 }
1033
1034 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1035 $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']) . '">';
1036 } else {
1037 $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']) . '">';
1038 }
1039 $out .= $labeltoshow;
1040 $out .= '</option>' . "\n";
1041 }
1042 }
1043 $out .= '</select>';
1044 } else {
1045 dol_print_error($this->db);
1046 }
1047
1048 // Make select dynamic
1049 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1050 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1051
1052 return $out;
1053 }
1054
1055 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1056
1070 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1071 {
1072 // phpcs:enable
1073 global $conf, $langs;
1074
1075 $langs->load("dict");
1076
1077 $out = '';
1078 $moreattrib = '';
1079 $incotermArray = array();
1080
1081 $sql = "SELECT rowid, code";
1082 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1083 $sql .= " WHERE active > 0";
1084 $sql .= " ORDER BY code ASC";
1085
1086 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1087 $resql = $this->db->query($sql);
1088 if ($resql) {
1089 if ($conf->use_javascript_ajax && !$forcecombo) {
1090 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1091 $out .= ajax_combobox($htmlname, $events);
1092 }
1093
1094 if (!empty($page)) {
1095 $out .= '<form method="post" action="' . $page . '">';
1096 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1097 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1098 }
1099
1100 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1101 $out .= '<option value="0">&nbsp;</option>';
1102 $num = $this->db->num_rows($resql);
1103 $i = 0;
1104 if ($num) {
1105 while ($i < $num) {
1106 $obj = $this->db->fetch_object($resql);
1107 $incotermArray[$i]['rowid'] = $obj->rowid;
1108 $incotermArray[$i]['code'] = $obj->code;
1109 $i++;
1110 }
1111
1112 foreach ($incotermArray as $row) {
1113 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1114 $out .= '<option value="' . $row['rowid'] . '" selected>';
1115 } else {
1116 $out .= '<option value="' . $row['rowid'] . '">';
1117 }
1118
1119 if ($row['code']) {
1120 $out .= $row['code'];
1121 }
1122
1123 $out .= '</option>';
1124 }
1125 }
1126 $out .= '</select>';
1127
1128 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1129 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1130 $moreattrib .= ' autocomplete="off"';
1131 }
1132 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1133
1134 if (!empty($page)) {
1135 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1136 }
1137 } else {
1138 dol_print_error($this->db);
1139 }
1140
1141 return $out;
1142 }
1143
1144 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1145
1157 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
1158 {
1159 // phpcs:enable
1160 global $langs;
1161
1162 // If product & services are enabled or both disabled.
1163 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1164 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1165 if (empty($hidetext)) {
1166 print $langs->trans("Type") . ': ';
1167 }
1168 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1169 if ($showempty) {
1170 print '<option value="-1"';
1171 if ($selected == -1) {
1172 print ' selected';
1173 }
1174 print '>&nbsp;</option>';
1175 }
1176
1177 print '<option value="0"';
1178 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1179 print ' selected';
1180 }
1181 print '>' . $langs->trans("Product");
1182
1183 print '<option value="1"';
1184 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1185 print ' selected';
1186 }
1187 print '>' . $langs->trans("Service");
1188
1189 print '</select>';
1190 print ajax_combobox('select_' . $htmlname);
1191 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1192 }
1193 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1194 print $langs->trans("Service");
1195 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1196 }
1197 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1198 print $langs->trans("Product");
1199 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1200 }
1201 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1202 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
1203 }
1204 }
1205
1206 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1207
1213 public function load_cache_types_fees()
1214 {
1215 // phpcs:enable
1216 global $langs;
1217
1218 $num = count($this->cache_types_fees);
1219 if ($num > 0) {
1220 return 0; // Cache already loaded
1221 }
1222
1223 dol_syslog(__METHOD__, LOG_DEBUG);
1224
1225 $langs->load("trips");
1226
1227 $sql = "SELECT c.code, c.label";
1228 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1229 $sql .= " WHERE active > 0";
1230
1231 $resql = $this->db->query($sql);
1232 if ($resql) {
1233 $num = $this->db->num_rows($resql);
1234 $i = 0;
1235
1236 while ($i < $num) {
1237 $obj = $this->db->fetch_object($resql);
1238
1239 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1240 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1241 $this->cache_types_fees[$obj->code] = $label;
1242 $i++;
1243 }
1244
1245 asort($this->cache_types_fees);
1246
1247 return $num;
1248 } else {
1249 dol_print_error($this->db);
1250 return -1;
1251 }
1252 }
1253
1254 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1255
1264 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1265 {
1266 // phpcs:enable
1267 global $user, $langs;
1268
1269 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1270
1271 $this->load_cache_types_fees();
1272
1273 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1274 if ($showempty) {
1275 print '<option value="-1"';
1276 if ($selected == -1) {
1277 print ' selected';
1278 }
1279 print '>&nbsp;</option>';
1280 }
1281
1282 foreach ($this->cache_types_fees as $key => $value) {
1283 print '<option value="' . $key . '"';
1284 if ($key == $selected) {
1285 print ' selected';
1286 }
1287 print '>';
1288 print $value;
1289 print '</option>';
1290 }
1291
1292 print '</select>';
1293 if ($user->admin) {
1294 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1295 }
1296 }
1297
1298
1299 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1300
1322 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)
1323 {
1324 // phpcs:enable
1325 global $conf, $user, $langs;
1326
1327 $out = '';
1328
1329 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1330 if (is_null($ajaxoptions)) {
1331 $ajaxoptions = array();
1332 }
1333
1334 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1335
1336 // No immediate load of all database
1337 $placeholder = '';
1338 if ($selected && empty($selected_input_value)) {
1339 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1340 $societetmp = new Societe($this->db);
1341 $societetmp->fetch($selected);
1342 $selected_input_value = $societetmp->name;
1343 unset($societetmp);
1344 }
1345
1346 // mode 1
1347 $urloption = 'htmlname=' . urlencode(str_replace('.', '_', $htmlname)) . '&outjson=1&filter=' . urlencode($filter) . (empty($excludeids) ? '' : '&excludeids=' . join(',', $excludeids)) . ($showtype ? '&showtype=' . urlencode($showtype) : '') . ($showcode ? '&showcode=' . urlencode($showcode) : '');
1348
1349 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1350 if (empty($hidelabel)) {
1351 print $langs->trans("RefOrLabel") . ' : ';
1352 } elseif ($hidelabel > 1) {
1353 $placeholder = $langs->trans("RefOrLabel");
1354 if ($hidelabel == 2) {
1355 $out .= img_picto($langs->trans("Search"), 'search');
1356 }
1357 }
1358 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('THIRDPARTY_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1359 if ($hidelabel == 3) {
1360 $out .= img_picto($langs->trans("Search"), 'search');
1361 }
1362
1363 $out .= ajax_event($htmlname, $events);
1364
1365 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1366 } else {
1367 // Immediate load of all database
1368 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1369 }
1370
1371 return $out;
1372 }
1373
1374 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1375
1399 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)
1400 {
1401 // phpcs:enable
1402 global $conf, $user, $langs;
1403 global $hookmanager;
1404
1405 $out = '';
1406 $num = 0;
1407 $outarray = array();
1408
1409 if ($selected === '') {
1410 $selected = array();
1411 } elseif (!is_array($selected)) {
1412 $selected = array($selected);
1413 }
1414
1415 // Clean $filter that may contains sql conditions so sql code
1416 if (function_exists('testSqlAndScriptInject')) {
1417 if (testSqlAndScriptInject($filter, 3) > 0) {
1418 $filter = '';
1419 return 'SQLInjectionTryDetected';
1420 }
1421 }
1422
1423 if ($filter != '') { // If a filter was provided
1424 if (preg_match('/[\‍(\‍)]/', $filter)) {
1425 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1426 $errormsg = '';
1427 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1428
1429 // Redo clean $filter that may contains sql conditions so sql code
1430 if (function_exists('testSqlAndScriptInject')) {
1431 if (testSqlAndScriptInject($filter, 3) > 0) {
1432 $filter = '';
1433 return 'SQLInjectionTryDetected';
1434 }
1435 }
1436 } else {
1437 // If not, we do nothing. We already know that there is no parenthesis
1438 // TODO Disallow this case in a future.
1439 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1440 }
1441 }
1442
1443 // We search companies
1444 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1445 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1446 $sql .= ", s.address, s.zip, s.town";
1447 $sql .= ", dictp.code as country_code";
1448 }
1449 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1450 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1451 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1452 }
1453 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
1454 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1455 }
1456 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1457 if (!empty($user->socid)) {
1458 $sql .= " AND s.rowid = " . ((int) $user->socid);
1459 }
1460 if ($filter) {
1461 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1462 // if not, by testSqlAndScriptInject() only.
1463 $sql .= " AND (" . $filter . ")";
1464 }
1465 if (!$user->hasRight('societe', 'client', 'voir') && !$user->socid) {
1466 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1467 }
1468 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1469 $sql .= " AND s.status <> 0";
1470 }
1471 if (!empty($excludeids)) {
1472 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(join(',', $excludeids)) . ")";
1473 }
1474 // Add where from hooks
1475 $parameters = array();
1476 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1477 $sql .= $hookmanager->resPrint;
1478 // Add criteria
1479 if ($filterkey && $filterkey != '') {
1480 $sql .= " AND (";
1481 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1482 // For natural search
1483 $scrit = explode(' ', $filterkey);
1484 $i = 0;
1485 if (count($scrit) > 1) {
1486 $sql .= "(";
1487 }
1488 foreach ($scrit as $crit) {
1489 if ($i > 0) {
1490 $sql .= " AND ";
1491 }
1492 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1493 $i++;
1494 }
1495 if (count($scrit) > 1) {
1496 $sql .= ")";
1497 }
1498 if (isModEnabled('barcode')) {
1499 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1500 }
1501 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1502 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1503 $sql .= ")";
1504 }
1505 $sql .= $this->db->order("nom", "ASC");
1506 $sql .= $this->db->plimit($limit, 0);
1507
1508 // Build output string
1509 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1510 $resql = $this->db->query($sql);
1511 if ($resql) {
1512 if (!$forcecombo) {
1513 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1514 $out .= ajax_combobox($htmlname, $events, getDolGlobalString("COMPANY_USE_SEARCH_TO_SELECT"));
1515 }
1516
1517 // Construct $out and $outarray
1518 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1519
1520 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1521 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1522 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1523 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1524 if ($showempty && !is_numeric($showempty)) {
1525 $textifempty = $langs->trans($showempty);
1526 } else {
1527 $textifempty .= $langs->trans("All");
1528 }
1529 }
1530 if ($showempty) {
1531 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1532 }
1533
1534 $companytemp = new Societe($this->db);
1535
1536 $num = $this->db->num_rows($resql);
1537 $i = 0;
1538 if ($num) {
1539 while ($i < $num) {
1540 $obj = $this->db->fetch_object($resql);
1541 $label = '';
1542 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1543 if (($obj->client) && (!empty($obj->code_client))) {
1544 $label = $obj->code_client . ' - ';
1545 }
1546 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1547 $label .= $obj->code_fournisseur . ' - ';
1548 }
1549 $label .= ' ' . $obj->name;
1550 } else {
1551 $label = $obj->name;
1552 }
1553
1554 if (!empty($obj->name_alias)) {
1555 $label .= ' (' . $obj->name_alias . ')';
1556 }
1557
1558 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1559 $label .= ' - '.$obj->tva_intra;
1560 }
1561
1562 $labelhtml = $label;
1563
1564 if ($showtype) {
1565 $companytemp->id = $obj->rowid;
1566 $companytemp->client = $obj->client;
1567 $companytemp->fournisseur = $obj->fournisseur;
1568 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1569 if ($tmptype) {
1570 $labelhtml .= ' ' . $tmptype;
1571 }
1572
1573 if ($obj->client || $obj->fournisseur) {
1574 $label .= ' (';
1575 }
1576 if ($obj->client == 1 || $obj->client == 3) {
1577 $label .= $langs->trans("Customer");
1578 }
1579 if ($obj->client == 2 || $obj->client == 3) {
1580 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1581 }
1582 if ($obj->fournisseur) {
1583 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1584 }
1585 if ($obj->client || $obj->fournisseur) {
1586 $label .= ')';
1587 }
1588 }
1589
1590 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1591 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1592 if (!empty($obj->country_code)) {
1593 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1594 }
1595 $label .= $s;
1596 $labelhtml .= $s;
1597 }
1598
1599 if (empty($outputmode)) {
1600 if (in_array($obj->rowid, $selected)) {
1601 $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>';
1602 } else {
1603 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1604 }
1605 } else {
1606 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1607 }
1608
1609 $i++;
1610 if (($i % 10) == 0) {
1611 $out .= "\n";
1612 }
1613 }
1614 }
1615 $out .= '</select>' . "\n";
1616 } else {
1617 dol_print_error($this->db);
1618 }
1619
1620 $this->result = array('nbofthirdparties' => $num);
1621
1622 if ($outputmode) {
1623 return $outarray;
1624 }
1625 return $out;
1626 }
1627
1628
1629 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1630
1641 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1642 {
1643 // phpcs:enable
1644 global $langs, $conf;
1645
1646 // On recherche les remises
1647 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1648 $sql .= " re.description, re.fk_facture_source";
1649 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
1650 $sql .= " WHERE re.fk_soc = " . (int) $socid;
1651 $sql .= " AND re.entity = " . $conf->entity;
1652 if ($filter) {
1653 $sql .= " AND " . $filter;
1654 }
1655 $sql .= " ORDER BY re.description ASC";
1656
1657 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
1658 $resql = $this->db->query($sql);
1659 if ($resql) {
1660 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
1661 $num = $this->db->num_rows($resql);
1662
1663 $qualifiedlines = $num;
1664
1665 $i = 0;
1666 if ($num) {
1667 print '<option value="0">&nbsp;</option>';
1668 while ($i < $num) {
1669 $obj = $this->db->fetch_object($resql);
1670 $desc = dol_trunc($obj->description, 40);
1671 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
1672 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
1673 }
1674 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
1675 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
1676 }
1677 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
1678 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
1679 }
1680 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
1681 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
1682 }
1683
1684 $selectstring = '';
1685 if ($selected > 0 && $selected == $obj->rowid) {
1686 $selectstring = ' selected';
1687 }
1688
1689 $disabled = '';
1690 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
1691 $qualifiedlines--;
1692 $disabled = ' disabled';
1693 }
1694
1695 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
1696 $tmpfac = new Facture($this->db);
1697 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
1698 $desc = $desc . ' - ' . $tmpfac->ref;
1699 }
1700 }
1701
1702 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
1703 $i++;
1704 }
1705 }
1706 print '</select>';
1707 print ajax_combobox('select_' . $htmlname);
1708
1709 return $qualifiedlines;
1710 } else {
1711 dol_print_error($this->db);
1712 return -1;
1713 }
1714 }
1715
1716 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1717
1738 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 = '')
1739 {
1740 // phpcs:enable
1741 print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1742 return $this->num;
1743 }
1744
1769 public function selectcontacts($socid, $selected = array(), $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0)
1770 {
1771 global $conf, $langs, $hookmanager, $action;
1772
1773 $langs->load('companies');
1774
1775 if (empty($htmlid)) {
1776 $htmlid = $htmlname;
1777 }
1778 $num = 0;
1779
1780 if ($selected === '') {
1781 $selected = array();
1782 } elseif (!is_array($selected)) {
1783 $selected = array($selected);
1784 }
1785 $out = '';
1786
1787 if (!is_object($hookmanager)) {
1788 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1789 $hookmanager = new HookManager($this->db);
1790 }
1791
1792 // We search third parties
1793 $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";
1794 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1795 $sql .= ", s.nom as company, s.town AS company_town";
1796 }
1797 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1798 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1799 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1800 }
1801 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1802 if ($socid > 0 || $socid == -1) {
1803 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1804 }
1805 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1806 $sql .= " AND sp.statut <> 0";
1807 }
1808 // Add where from hooks
1809 $parameters = array();
1810 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1811 $sql .= $hookmanager->resPrint;
1812 $sql .= " ORDER BY sp.lastname ASC";
1813
1814 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1815 $resql = $this->db->query($sql);
1816 if ($resql) {
1817 $num = $this->db->num_rows($resql);
1818
1819 if ($htmlname != 'none' && !$options_only) {
1820 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1821 }
1822
1823 if ($showempty && !is_numeric($showempty)) {
1824 $textforempty = $showempty;
1825 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1826 } else {
1827 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1828 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1829 }
1830 if ($showempty == 2) {
1831 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1832 }
1833 }
1834
1835 $i = 0;
1836 if ($num) {
1837 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1838 $contactstatic = new Contact($this->db);
1839
1840 while ($i < $num) {
1841 $obj = $this->db->fetch_object($resql);
1842
1843 // Set email (or phones) and town extended infos
1844 $extendedInfos = '';
1845 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1846 $extendedInfos = array();
1847 $email = trim($obj->email);
1848 if (!empty($email)) {
1849 $extendedInfos[] = $email;
1850 } else {
1851 $phone = trim($obj->phone);
1852 $phone_perso = trim($obj->phone_perso);
1853 $phone_mobile = trim($obj->phone_mobile);
1854 if (!empty($phone)) {
1855 $extendedInfos[] = $phone;
1856 }
1857 if (!empty($phone_perso)) {
1858 $extendedInfos[] = $phone_perso;
1859 }
1860 if (!empty($phone_mobile)) {
1861 $extendedInfos[] = $phone_mobile;
1862 }
1863 }
1864 $contact_town = trim($obj->contact_town);
1865 $company_town = trim($obj->company_town);
1866 if (!empty($contact_town)) {
1867 $extendedInfos[] = $contact_town;
1868 } elseif (!empty($company_town)) {
1869 $extendedInfos[] = $company_town;
1870 }
1871 $extendedInfos = implode(' - ', $extendedInfos);
1872 if (!empty($extendedInfos)) {
1873 $extendedInfos = ' - ' . $extendedInfos;
1874 }
1875 }
1876
1877 $contactstatic->id = $obj->rowid;
1878 $contactstatic->lastname = $obj->lastname;
1879 $contactstatic->firstname = $obj->firstname;
1880 if ($obj->statut == 1) {
1881 if ($htmlname != 'none') {
1882 $disabled = 0;
1883 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1884 $disabled = 1;
1885 }
1886 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1887 $disabled = 1;
1888 }
1889 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1890 $out .= '<option value="' . $obj->rowid . '"';
1891 if ($disabled) {
1892 $out .= ' disabled';
1893 }
1894 $out .= ' selected>';
1895 $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1896 if ($showfunction && $obj->poste) {
1897 $out .= ' (' . $obj->poste . ')';
1898 }
1899 if (($showsoc > 0) && $obj->company) {
1900 $out .= ' - (' . $obj->company . ')';
1901 }
1902 $out .= '</option>';
1903 } else {
1904 $out .= '<option value="' . $obj->rowid . '"';
1905 if ($disabled) {
1906 $out .= ' disabled';
1907 }
1908 $out .= '>';
1909 $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1910 if ($showfunction && $obj->poste) {
1911 $out .= ' (' . $obj->poste . ')';
1912 }
1913 if (($showsoc > 0) && $obj->company) {
1914 $out .= ' - (' . $obj->company . ')';
1915 }
1916 $out .= '</option>';
1917 }
1918 } else {
1919 if (in_array($obj->rowid, $selected)) {
1920 $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1921 if ($showfunction && $obj->poste) {
1922 $out .= ' (' . $obj->poste . ')';
1923 }
1924 if (($showsoc > 0) && $obj->company) {
1925 $out .= ' - (' . $obj->company . ')';
1926 }
1927 }
1928 }
1929 }
1930 $i++;
1931 }
1932 } else {
1933 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1934 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1935 $out .= $labeltoshow;
1936 $out .= '</option>';
1937 }
1938
1939 $parameters = array(
1940 'socid' => $socid,
1941 'htmlname' => $htmlname,
1942 'resql' => $resql,
1943 'out' => &$out,
1944 'showfunction' => $showfunction,
1945 'showsoc' => $showsoc,
1946 );
1947
1948 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1949
1950 if ($htmlname != 'none' && !$options_only) {
1951 $out .= '</select>';
1952 }
1953
1954 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1955 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1956 $out .= ajax_combobox($htmlid, $events, getDolGlobalString("CONTACT_USE_SEARCH_TO_SELECT"));
1957 }
1958
1959 $this->num = $num;
1960 return $out;
1961 } else {
1962 dol_print_error($this->db);
1963 return -1;
1964 }
1965 }
1966
1967 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1968
1984 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
1985 {
1986 // phpcs:enable
1987 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1988 }
1989
1990 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1991
2016 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2017 {
2018 // phpcs:enable
2019 global $conf, $user, $langs, $hookmanager;
2020 global $action;
2021
2022 // If no preselected user defined, we take current user
2023 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2024 $selected = $user->id;
2025 }
2026
2027 if ($selected === '') {
2028 $selected = array();
2029 } elseif (!is_array($selected)) {
2030 $selected = array($selected);
2031 }
2032
2033 $excludeUsers = null;
2034 $includeUsers = null;
2035
2036 // Exclude some users
2037 if (is_array($exclude)) {
2038 $excludeUsers = implode(",", $exclude);
2039 }
2040 // Include some uses
2041 if (is_array($include)) {
2042 $includeUsers = implode(",", $include);
2043 } elseif ($include == 'hierarchy') {
2044 // Build list includeUsers to have only hierarchy
2045 $includeUsers = implode(",", $user->getAllChildIds(0));
2046 } elseif ($include == 'hierarchyme') {
2047 // Build list includeUsers to have only hierarchy and current user
2048 $includeUsers = implode(",", $user->getAllChildIds(1));
2049 }
2050
2051 $out = '';
2052 $outarray = array();
2053 $outarray2 = array();
2054
2055 // Forge request to select users
2056 $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
2057 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
2058 $sql .= ", e.label";
2059 }
2060 $sql .= " FROM " . $this->db->prefix() . "user as u";
2061 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
2062 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2063 if (!empty($force_entity)) {
2064 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2065 } else {
2066 $sql .= " WHERE u.entity IS NOT NULL";
2067 }
2068 } else {
2069 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2070 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2071 } else {
2072 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2073 }
2074 }
2075 if (!empty($user->socid)) {
2076 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2077 }
2078 if (is_array($exclude) && $excludeUsers) {
2079 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2080 }
2081 if ($includeUsers) {
2082 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2083 }
2084 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2085 $sql .= " AND u.statut <> 0";
2086 }
2087 if (!empty($morefilter)) {
2088 $sql .= " " . $morefilter;
2089 }
2090
2091 //Add hook to filter on user (for exemple on usergroup define in custom modules)
2092 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2093 if (!empty($reshook)) {
2094 $sql .= $hookmanager->resPrint;
2095 }
2096
2097 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2098 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2099 } else {
2100 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2101 }
2102
2103 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2104
2105 $resql = $this->db->query($sql);
2106 if ($resql) {
2107 $num = $this->db->num_rows($resql);
2108 $i = 0;
2109 if ($num) {
2110 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2111 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2112 if ($show_empty && !$multiple) {
2113 $textforempty = ' ';
2114 if (!empty($conf->use_javascript_ajax)) {
2115 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2116 }
2117 if (!is_numeric($show_empty)) {
2118 $textforempty = $show_empty;
2119 }
2120 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2121 }
2122 if ($show_every) {
2123 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2124 }
2125
2126 $userstatic = new User($this->db);
2127
2128 while ($i < $num) {
2129 $obj = $this->db->fetch_object($resql);
2130
2131 $userstatic->id = $obj->rowid;
2132 $userstatic->lastname = $obj->lastname;
2133 $userstatic->firstname = $obj->firstname;
2134 $userstatic->photo = $obj->photo;
2135 $userstatic->statut = $obj->status;
2136 $userstatic->entity = $obj->entity;
2137 $userstatic->admin = $obj->admin;
2138
2139 $disableline = '';
2140 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2141 $disableline = ($enableonlytext ? $enableonlytext : '1');
2142 }
2143
2144 $labeltoshow = '';
2145 $labeltoshowhtml = '';
2146
2147 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2148 $fullNameMode = 0;
2149 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2150 $fullNameMode = 1; //Firstname+lastname
2151 }
2152 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2153 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2154 if (empty($obj->firstname) && empty($obj->lastname)) {
2155 $labeltoshow .= $obj->login;
2156 $labeltoshowhtml .= $obj->login;
2157 }
2158
2159 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2160 $moreinfo = '';
2161 $moreinfohtml = '';
2162 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2163 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2164 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2165 $moreinfo .= $obj->login;
2166 $moreinfohtml .= $obj->login;
2167 }
2168 if ($showstatus >= 0) {
2169 if ($obj->status == 1 && $showstatus == 1) {
2170 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2171 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2172 }
2173 if ($obj->status == 0 && $showstatus == 1) {
2174 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2175 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2176 }
2177 }
2178 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity)) {
2179 if (empty($obj->entity)) {
2180 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2181 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2182 } else {
2183 if ($obj->entity != $conf->entity) {
2184 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2185 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2186 }
2187 }
2188 }
2189 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2190 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2191 if (!empty($disableline) && $disableline != '1') {
2192 // Add text from $enableonlytext parameter
2193 $moreinfo .= ' - ' . $disableline;
2194 $moreinfohtml .= ' - ' . $disableline;
2195 }
2196 $labeltoshow .= $moreinfo;
2197 $labeltoshowhtml .= $moreinfohtml;
2198
2199 $out .= '<option value="' . $obj->rowid . '"';
2200 if (!empty($disableline)) {
2201 $out .= ' disabled';
2202 }
2203 if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
2204 $out .= ' selected';
2205 }
2206 $out .= ' data-html="';
2207 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2208 if ($showstatus >= 0 && $obj->status == 0) {
2209 $outhtml .= '<strike class="opacitymediumxxx">';
2210 }
2211 $outhtml .= $labeltoshowhtml;
2212 if ($showstatus >= 0 && $obj->status == 0) {
2213 $outhtml .= '</strike>';
2214 }
2215 $out .= dol_escape_htmltag($outhtml);
2216 $out .= '">';
2217 $out .= $labeltoshow;
2218 $out .= '</option>';
2219
2220 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2221 $outarray2[$userstatic->id] = array(
2222 'id'=>$userstatic->id,
2223 'label'=>$labeltoshow,
2224 'labelhtml'=>$labeltoshowhtml,
2225 'color'=>'',
2226 'picto'=>''
2227 );
2228
2229 $i++;
2230 }
2231 } else {
2232 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2233 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2234 }
2235 $out .= '</select>';
2236
2237 if ($num && !$forcecombo) {
2238 // Enhance with select2
2239 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2240 $out .= ajax_combobox($htmlname);
2241 }
2242 } else {
2243 dol_print_error($this->db);
2244 }
2245
2246 if ($outputmode == 2) {
2247 return $outarray2;
2248 } elseif ($outputmode) {
2249 return $outarray;
2250 }
2251
2252 return $out;
2253 }
2254
2255
2256 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2279 public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array())
2280 {
2281 // phpcs:enable
2282 global $langs;
2283
2284 $userstatic = new User($this->db);
2285 $out = '';
2286
2287 $assignedtouser = array();
2288 if (!empty($_SESSION['assignedtouser'])) {
2289 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2290 }
2291 $nbassignetouser = count($assignedtouser);
2292
2293 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2294 if ($nbassignetouser) {
2295 $out .= '<ul class="attendees">';
2296 }
2297 $i = 0;
2298 $ownerid = 0;
2299 foreach ($assignedtouser as $key => $value) {
2300 if ($value['id'] == $ownerid) {
2301 continue;
2302 }
2303
2304 $out .= '<li>';
2305 $userstatic->fetch($value['id']);
2306 $out .= $userstatic->getNomUrl(-1);
2307 if ($i == 0) {
2308 $ownerid = $value['id'];
2309 $out .= ' (' . $langs->trans("Owner") . ')';
2310 }
2311 if ($nbassignetouser > 1 && $action != 'view') {
2312 $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 . '">';
2313 }
2314 // Show my availability
2315 if ($showproperties) {
2316 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2317 $out .= '<div class="myavailability inline-block">';
2318 $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>';
2319 $out .= '</div>';
2320 }
2321 }
2322 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2323 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2324
2325 $out .= '</li>';
2326 $i++;
2327 }
2328 if ($nbassignetouser) {
2329 $out .= '</ul>';
2330 }
2331
2332 // Method with no ajax
2333 if ($action != 'view') {
2334 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2335 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2336 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2337 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2338 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2339 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2340 $out .= '});';
2341 $out .= '})</script>';
2342 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2343 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2344 $out .= '<br>';
2345 }
2346
2347 return $out;
2348 }
2349
2350 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2370 public function select_dolresources_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofresourceid = array())
2371 {
2372 // phpcs:enable
2373 global $langs;
2374
2375 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2376 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2377 $formresources = new FormResource($this->db);
2378 $resourcestatic = new Dolresource($this->db);
2379
2380 $out = '';
2381 $assignedtoresource = array();
2382 if (!empty($_SESSION['assignedtoresource'])) {
2383 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2384 }
2385 $nbassignetoresource = count($assignedtoresource);
2386
2387 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2388 if ($nbassignetoresource) {
2389 $out .= '<ul class="attendees">';
2390 }
2391 $i = 0;
2392
2393 foreach ($assignedtoresource as $key => $value) {
2394 $out .= '<li>';
2395 $resourcestatic->fetch($value['id']);
2396 $out .= $resourcestatic->getNomUrl(-1);
2397 if ($nbassignetoresource > 1 && $action != 'view') {
2398 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassigned reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2399 }
2400 // Show my availability
2401 if ($showproperties) {
2402 if (is_array($listofresourceid) && count($listofresourceid)) {
2403 $out .= '<div class="myavailability inline-block">';
2404 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparencyresource" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2405 $out .= '</div>';
2406 }
2407 }
2408 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2409 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2410
2411 $out .= '</li>';
2412 $i++;
2413 }
2414 if ($nbassignetoresource) {
2415 $out .= '</ul>';
2416 }
2417
2418 // Method with no ajax
2419 if ($action != 'view') {
2420 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassignedresource" value="">';
2421 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2422 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2423 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2424 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2425 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2426 $out .= '});';
2427 $out .= '})</script>';
2428
2429 $events = array();
2430 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2431 $out .= $formresources->select_resource_list('', $htmlname, '', 1, 1, 0, $events, '', 2, null);
2432 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2433 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2434 $out .= '<br>';
2435 }
2436
2437 return $out;
2438 }
2439
2440 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2441
2469 public function select_produits($selected = 0, $htmlname = 'productid', $filtertype = '', $limit = 0, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = null, $nooutput = 0, $status_purchase = -1)
2470 {
2471 // phpcs:enable
2472 global $langs, $conf;
2473
2474 $out = '';
2475
2476 // check parameters
2477 $price_level = (!empty($price_level) ? $price_level : 0);
2478 if (is_null($ajaxoptions)) {
2479 $ajaxoptions = array();
2480 }
2481
2482 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2483 if (isModEnabled("product") && !isModEnabled('service')) {
2484 $filtertype = '0';
2485 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2486 $filtertype = '1';
2487 }
2488 }
2489
2490 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2491 $placeholder = '';
2492
2493 if ($selected && empty($selected_input_value)) {
2494 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2495 $producttmpselect = new Product($this->db);
2496 $producttmpselect->fetch($selected);
2497 $selected_input_value = $producttmpselect->ref;
2498 unset($producttmpselect);
2499 }
2500 // handle case where product or service module is disabled + no filter specified
2501 if ($filtertype == '') {
2502 if (!isModEnabled('product')) { // when product module is disabled, show services only
2503 $filtertype = 1;
2504 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2505 $filtertype = 0;
2506 }
2507 }
2508 // mode=1 means customers products
2509 $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;
2510 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2511
2512 if (isModEnabled('variants') && is_array($selected_combinations)) {
2513 // Code to automatically insert with javascript the select of attributes under the select of product
2514 // when a parent of variant has been selected.
2515 $out .= '
2516 <!-- script to auto show attributes select tags if a variant was selected -->
2517 <script nonce="' . getNonce() . '">
2518 // auto show attributes fields
2519 selected = ' . json_encode($selected_combinations) . ';
2520 combvalues = {};
2521
2522 jQuery(document).ready(function () {
2523
2524 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2525 if (jQuery(this).val() == \'free\') {
2526 jQuery(\'div#attributes_box\').empty();
2527 }
2528 });
2529
2530 jQuery("input#' . $htmlname . '").change(function () {
2531
2532 if (!jQuery(this).val()) {
2533 jQuery(\'div#attributes_box\').empty();
2534 return;
2535 }
2536
2537 console.log("A change has started. We get variants fields to inject html select");
2538
2539 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2540 id: jQuery(this).val()
2541 }, function (data) {
2542 jQuery(\'div#attributes_box\').empty();
2543
2544 jQuery.each(data, function (key, val) {
2545
2546 combvalues[val.id] = val.values;
2547
2548 var span = jQuery(document.createElement(\'div\')).css({
2549 \'display\': \'table-row\'
2550 });
2551
2552 span.append(
2553 jQuery(document.createElement(\'div\')).text(val.label).css({
2554 \'font-weight\': \'bold\',
2555 \'display\': \'table-cell\'
2556 })
2557 );
2558
2559 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2560 \'margin-left\': \'15px\',
2561 \'white-space\': \'pre\'
2562 }).append(
2563 jQuery(document.createElement(\'option\')).val(\'\')
2564 );
2565
2566 jQuery.each(combvalues[val.id], function (key, val) {
2567 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2568
2569 if (selected[val.fk_product_attribute] == val.id) {
2570 tag.attr(\'selected\', \'selected\');
2571 }
2572
2573 html.append(tag);
2574 });
2575
2576 span.append(html);
2577 jQuery(\'div#attributes_box\').append(span);
2578 });
2579 })
2580 });
2581
2582 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2583 });
2584 </script>
2585 ';
2586 }
2587
2588 if (empty($hidelabel)) {
2589 $out .= $langs->trans("RefOrLabel") . ' : ';
2590 } elseif ($hidelabel > 1) {
2591 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
2592 if ($hidelabel == 2) {
2593 $out .= img_picto($langs->trans("Search"), 'search');
2594 }
2595 }
2596 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2597 if ($hidelabel == 3) {
2598 $out .= img_picto($langs->trans("Search"), 'search');
2599 }
2600 } else {
2601 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2602 }
2603
2604 if (empty($nooutput)) {
2605 print $out;
2606 } else {
2607 return $out;
2608 }
2609 }
2610
2611 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2612
2628 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2629 {
2630 // phpcs:enable
2631 global $conf, $user, $langs, $db;
2632
2633 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2634
2635 $error = 0;
2636 $out = '';
2637
2638 if (!$forcecombo) {
2639 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2640 $events = array();
2641 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2642 }
2643
2644 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2645
2646 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2647 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2648 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2649 if (!empty($status)) {
2650 $sql .= ' AND status = ' . (int) $status;
2651 }
2652 if (!empty($type)) {
2653 $sql .= ' AND bomtype = ' . (int) $type;
2654 }
2655 if (!empty($TProducts)) {
2656 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2657 }
2658 if (!empty($limit)) {
2659 $sql .= ' LIMIT ' . (int) $limit;
2660 }
2661 $resql = $db->query($sql);
2662 if ($resql) {
2663 if ($showempty) {
2664 $out .= '<option value="-1"';
2665 if (empty($selected)) {
2666 $out .= ' selected';
2667 }
2668 $out .= '>&nbsp;</option>';
2669 }
2670 while ($obj = $db->fetch_object($resql)) {
2671 $product = new Product($db);
2672 $res = $product->fetch($obj->fk_product);
2673 $out .= '<option value="' . $obj->rowid . '"';
2674 if ($obj->rowid == $selected) {
2675 $out .= 'selected';
2676 }
2677 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2678 }
2679 } else {
2680 $error++;
2681 dol_print_error($db);
2682 }
2683 $out .= '</select>';
2684 if (empty($nooutput)) {
2685 print $out;
2686 } else {
2687 return $out;
2688 }
2689 }
2690
2691 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2692
2718 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)
2719 {
2720 // phpcs:enable
2721 global $langs, $conf;
2722 global $hookmanager;
2723
2724 $out = '';
2725 $outarray = array();
2726
2727 // Units
2728 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2729 $langs->load('other');
2730 }
2731
2732 $warehouseStatusArray = array();
2733 if (!empty($warehouseStatus)) {
2734 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2735 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2736 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2737 }
2738 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2739 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2740 }
2741 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2742 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2743 }
2744 }
2745
2746 $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";
2747 if (count($warehouseStatusArray)) {
2748 $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
2749 } else {
2750 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2751 }
2752
2753 $sql = "SELECT ";
2754
2755 // Add select from hooks
2756 $parameters = array();
2757 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2758 if (empty($reshook)) {
2759 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2760 } else {
2761 $sql .= $hookmanager->resPrint;
2762 }
2763
2764 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2765 //Product category
2766 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2767 FROM " . $this->db->prefix() . "categorie_product
2768 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2769 LIMIT 1
2770 ) AS categorie_product_id ";
2771 }
2772
2773 //Price by customer
2774 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2775 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2776 $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';
2777 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2778 }
2779 // Units
2780 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2781 $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";
2782 $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';
2783 }
2784
2785 // Multilang : we add translation
2786 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2787 $sql .= ", pl.label as label_translated";
2788 $sql .= ", pl.description as description_translated";
2789 $selectFields .= ", label_translated";
2790 $selectFields .= ", description_translated";
2791 }
2792 // Price by quantity
2793 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2794 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2795 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2796 $sql .= " AND price_level = " . ((int) $price_level);
2797 }
2798 $sql .= " ORDER BY date_price";
2799 $sql .= " DESC LIMIT 1) as price_rowid";
2800 $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
2801 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2802 $sql .= " AND price_level = " . ((int) $price_level);
2803 }
2804 $sql .= " ORDER BY date_price";
2805 $sql .= " DESC LIMIT 1) as price_by_qty";
2806 $selectFields .= ", price_rowid, price_by_qty";
2807 }
2808
2809 $sql .= " FROM ".$this->db->prefix()."product as p";
2810 // Add from (left join) from hooks
2811 $parameters = array();
2812 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
2813 $sql .= $hookmanager->resPrint;
2814
2815 if (count($warehouseStatusArray)) {
2816 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
2817 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
2818 $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.
2819 }
2820
2821 // include search in supplier ref
2822 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
2823 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2824 }
2825
2826 //Price by customer
2827 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2828 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
2829 }
2830 // Units
2831 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2832 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
2833 }
2834 // Multilang : we add translation
2835 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2836 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
2837 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
2838 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
2839 $soc = new Societe($this->db);
2840 $result = $soc->fetch($socid);
2841 if ($result > 0 && !empty($soc->default_lang)) {
2842 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
2843 } else {
2844 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
2845 }
2846 } else {
2847 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
2848 }
2849 }
2850
2851 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
2852 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2853 }
2854
2855 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
2856
2857 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
2858 $sql .= " AND pac.rowid IS NULL";
2859 }
2860
2861 if ($finished == 0) {
2862 $sql .= " AND p.finished = " . ((int) $finished);
2863 } elseif ($finished == 1) {
2864 $sql .= " AND p.finished = ".((int) $finished);
2865 }
2866 if ($status >= 0) {
2867 $sql .= " AND p.tosell = ".((int) $status);
2868 }
2869 if ($status_purchase >= 0) {
2870 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
2871 }
2872 // Filter by product type
2873 if (strval($filtertype) != '') {
2874 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
2875 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
2876 $sql .= " AND p.fk_product_type = 1";
2877 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2878 $sql .= " AND p.fk_product_type = 0";
2879 }
2880 // Add where from hooks
2881 $parameters = array();
2882 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
2883 $sql .= $hookmanager->resPrint;
2884 // Add criteria on ref/label
2885 if ($filterkey != '') {
2886 $sql .= ' AND (';
2887 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2888 // For natural search
2889 $scrit = explode(' ', $filterkey);
2890 $i = 0;
2891 if (count($scrit) > 1) {
2892 $sql .= "(";
2893 }
2894 foreach ($scrit as $crit) {
2895 if ($i > 0) {
2896 $sql .= " AND ";
2897 }
2898 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2899 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2900 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2901 }
2902 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2903 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2904 }
2905 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
2906 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2907 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2908 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2909 }
2910 }
2911 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
2912 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2913 }
2914 $sql .= ")";
2915 $i++;
2916 }
2917 if (count($scrit) > 1) {
2918 $sql .= ")";
2919 }
2920 if (isModEnabled('barcode')) {
2921 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
2922 }
2923 $sql .= ')';
2924 }
2925 if (count($warehouseStatusArray)) {
2926 $sql .= " GROUP BY " . $selectFields;
2927 }
2928
2929 //Sort by category
2930 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2931 $sql .= " ORDER BY categorie_product_id ";
2932 //ASC OR DESC order
2933 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
2934 } else {
2935 $sql .= $this->db->order("p.ref");
2936 }
2937
2938 $sql .= $this->db->plimit($limit, 0);
2939
2940 // Build output string
2941 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
2942 $result = $this->db->query($sql);
2943 if ($result) {
2944 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2945 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
2946 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
2947
2948 $num = $this->db->num_rows($result);
2949
2950 $events = null;
2951
2952 if (!$forcecombo) {
2953 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2954 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2955 }
2956
2957 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2958
2959 $textifempty = '';
2960 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2961 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2962 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2963 if ($showempty && !is_numeric($showempty)) {
2964 $textifempty = $langs->trans($showempty);
2965 } else {
2966 $textifempty .= $langs->trans("All");
2967 }
2968 } else {
2969 if ($showempty && !is_numeric($showempty)) {
2970 $textifempty = $langs->trans($showempty);
2971 }
2972 }
2973 if ($showempty) {
2974 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
2975 }
2976
2977 $i = 0;
2978 while ($num && $i < $num) {
2979 $opt = '';
2980 $optJson = array();
2981 $objp = $this->db->fetch_object($result);
2982
2983 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) && !empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product
2984 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2985 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
2986 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
2987 $sql .= " ORDER BY quantity ASC";
2988
2989 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
2990 $result2 = $this->db->query($sql);
2991 if ($result2) {
2992 $nb_prices = $this->db->num_rows($result2);
2993 $j = 0;
2994 while ($nb_prices && $j < $nb_prices) {
2995 $objp2 = $this->db->fetch_object($result2);
2996
2997 $objp->price_by_qty_rowid = $objp2->rowid;
2998 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
2999 $objp->price_by_qty_quantity = $objp2->quantity;
3000 $objp->price_by_qty_unitprice = $objp2->unitprice;
3001 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3002 // For backward compatibility
3003 $objp->quantity = $objp2->quantity;
3004 $objp->price = $objp2->price;
3005 $objp->unitprice = $objp2->unitprice;
3006 $objp->remise_percent = $objp2->remise_percent;
3007
3008 //$objp->tva_tx is not overwritten by $objp2 value
3009 //$objp->default_vat_code is not overwritten by $objp2 value
3010
3011 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3012
3013 $j++;
3014
3015 // Add new entry
3016 // "key" value of json key array is used by jQuery automatically as selected value
3017 // "label" value of json key array is used by jQuery automatically as text for combo box
3018 $out .= $opt;
3019 array_push($outarray, $optJson);
3020 }
3021 }
3022 } else {
3023 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3024 $price_product = new Product($this->db);
3025 $price_product->fetch($objp->rowid, '', '', 1);
3026
3027 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3028 $priceparser = new PriceParser($this->db);
3029 $price_result = $priceparser->parseProduct($price_product);
3030 if ($price_result >= 0) {
3031 $objp->price = $price_result;
3032 $objp->unitprice = $price_result;
3033 //Calculate the VAT
3034 $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3035 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3036 }
3037 }
3038
3039 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3040 // Add new entry
3041 // "key" value of json key array is used by jQuery automatically as selected value
3042 // "label" value of json key array is used by jQuery automatically as text for combo box
3043 $out .= $opt;
3044 array_push($outarray, $optJson);
3045 }
3046
3047 $i++;
3048 }
3049
3050 $out .= '</select>';
3051
3052 $this->db->free($result);
3053
3054 if (empty($outputmode)) {
3055 return $out;
3056 }
3057
3058 return $outarray;
3059 } else {
3060 dol_print_error($this->db);
3061 }
3062
3063 return '';
3064 }
3065
3081 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3082 {
3083 global $langs, $conf, $user;
3084 global $hookmanager;
3085
3086 $outkey = '';
3087 $outval = '';
3088 $outref = '';
3089 $outlabel = '';
3090 $outlabel_translated = '';
3091 $outdesc = '';
3092 $outdesc_translated = '';
3093 $outbarcode = '';
3094 $outorigin = '';
3095 $outtype = '';
3096 $outprice_ht = '';
3097 $outprice_ttc = '';
3098 $outpricebasetype = '';
3099 $outtva_tx = '';
3100 $outdefault_vat_code = '';
3101 $outqty = 1;
3102 $outdiscount = 0;
3103
3104 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3105
3106 $label = $objp->label;
3107 if (!empty($objp->label_translated)) {
3108 $label = $objp->label_translated;
3109 }
3110 if (!empty($filterkey) && $filterkey != '') {
3111 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3112 }
3113
3114 $outkey = $objp->rowid;
3115 $outref = $objp->ref;
3116 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3117 $outlabel = $objp->label;
3118 $outdesc = $objp->description;
3119 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3120 $outlabel_translated = $objp->label_translated;
3121 $outdesc_translated = $objp->description_translated;
3122 }
3123 $outbarcode = $objp->barcode;
3124 $outorigin = $objp->fk_country;
3125 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3126
3127 $outtype = $objp->fk_product_type;
3128 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3129 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3130
3131 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3132 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3133 }
3134
3135 // Units
3136 $outvalUnits = '';
3137 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3138 if (!empty($objp->unit_short)) {
3139 $outvalUnits .= ' - ' . $objp->unit_short;
3140 }
3141 }
3142 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3143 if (!empty($objp->weight) && $objp->weight_units !== null) {
3144 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3145 $outvalUnits .= ' - ' . $unitToShow;
3146 }
3147 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3148 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3149 $outvalUnits .= ' - ' . $unitToShow;
3150 }
3151 if (!empty($objp->surface) && $objp->surface_units !== null) {
3152 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3153 $outvalUnits .= ' - ' . $unitToShow;
3154 }
3155 if (!empty($objp->volume) && $objp->volume_units !== null) {
3156 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3157 $outvalUnits .= ' - ' . $unitToShow;
3158 }
3159 }
3160 if ($outdurationvalue && $outdurationunit) {
3161 $da = array(
3162 'h' => $langs->trans('Hour'),
3163 'd' => $langs->trans('Day'),
3164 'w' => $langs->trans('Week'),
3165 'm' => $langs->trans('Month'),
3166 'y' => $langs->trans('Year')
3167 );
3168 if (isset($da[$outdurationunit])) {
3169 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3170 }
3171 }
3172
3173 $opt = '<option value="' . $objp->rowid . '"';
3174 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3175 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3176 $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 . '"';
3177 }
3178 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3179 if ($user->hasRight('stock', 'lire')) {
3180 if ($objp->stock > 0) {
3181 $opt .= ' class="product_line_stock_ok"';
3182 } elseif ($objp->stock <= 0) {
3183 $opt .= ' class="product_line_stock_too_low"';
3184 }
3185 }
3186 }
3187 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3188 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3189 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3190 }
3191 $opt .= '>';
3192 $opt .= $objp->ref;
3193 if (!empty($objp->custref)) {
3194 $opt .= ' (' . $objp->custref . ')';
3195 }
3196 if ($outbarcode) {
3197 $opt .= ' (' . $outbarcode . ')';
3198 }
3199 $opt .= ' - ' . dol_trunc($label, $maxlengtharticle);
3200 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3201 $opt .= ' (' . getCountry($outorigin, 1) . ')';
3202 }
3203
3204 $objRef = $objp->ref;
3205 if (!empty($objp->custref)) {
3206 $objRef .= ' (' . $objp->custref . ')';
3207 }
3208 if (!empty($filterkey) && $filterkey != '') {
3209 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3210 }
3211 $outval .= $objRef;
3212 if ($outbarcode) {
3213 $outval .= ' (' . $outbarcode . ')';
3214 }
3215 $outval .= ' - ' . dol_trunc($label, $maxlengtharticle);
3216 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3217 $outval .= ' (' . getCountry($outorigin, 1) . ')';
3218 }
3219
3220 // Units
3221 $opt .= $outvalUnits;
3222 $outval .= $outvalUnits;
3223
3224 $found = 0;
3225
3226 // Multiprice
3227 // If we need a particular price level (from 1 to n)
3228 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3229 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3230 $sql .= " FROM " . $this->db->prefix() . "product_price";
3231 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3232 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3233 $sql .= " AND price_level = " . ((int) $price_level);
3234 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3235 $sql .= " LIMIT 1";
3236
3237 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3238 $result2 = $this->db->query($sql);
3239 if ($result2) {
3240 $objp2 = $this->db->fetch_object($result2);
3241 if ($objp2) {
3242 $found = 1;
3243 if ($objp2->price_base_type == 'HT') {
3244 $opt .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3245 $outval .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3246 } else {
3247 $opt .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3248 $outval .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3249 }
3250 $outprice_ht = price($objp2->price);
3251 $outprice_ttc = price($objp2->price_ttc);
3252 $outpricebasetype = $objp2->price_base_type;
3253 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3254 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3255 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3256 } else {
3257 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3258 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3259 }
3260 }
3261 } else {
3262 dol_print_error($this->db);
3263 }
3264 }
3265
3266 // Price by quantity
3267 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3268 $found = 1;
3269 $outqty = $objp->quantity;
3270 $outdiscount = $objp->remise_percent;
3271 if ($objp->quantity == 1) {
3272 $opt .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3273 $outval .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3274 $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3275 $outval .= $langs->transnoentities("Unit");
3276 } else {
3277 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3278 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3279 $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3280 $outval .= $langs->transnoentities("Units");
3281 }
3282
3283 $outprice_ht = price($objp->unitprice);
3284 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3285 $outpricebasetype = $objp->price_base_type;
3286 $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
3287 $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
3288 }
3289 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3290 $opt .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3291 $outval .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3292 }
3293 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3294 $opt .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3295 $outval .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3296 }
3297
3298 // Price by customer
3299 if (empty($hidepriceinlabel) && getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
3300 if (!empty($objp->idprodcustprice)) {
3301 $found = 1;
3302
3303 if ($objp->custprice_base_type == 'HT') {
3304 $opt .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3305 $outval .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3306 } else {
3307 $opt .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3308 $outval .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3309 }
3310
3311 $outprice_ht = price($objp->custprice);
3312 $outprice_ttc = price($objp->custprice_ttc);
3313 $outpricebasetype = $objp->custprice_base_type;
3314 $outtva_tx = $objp->custtva_tx;
3315 $outdefault_vat_code = $objp->custdefault_vat_code;
3316 }
3317 }
3318
3319 // If level no defined or multiprice not found, we used the default price
3320 if (empty($hidepriceinlabel) && !$found) {
3321 if ($objp->price_base_type == 'HT') {
3322 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3323 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3324 } else {
3325 $opt .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3326 $outval .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3327 }
3328 $outprice_ht = price($objp->price);
3329 $outprice_ttc = price($objp->price_ttc);
3330 $outpricebasetype = $objp->price_base_type;
3331 $outtva_tx = $objp->tva_tx;
3332 $outdefault_vat_code = $objp->default_vat_code;
3333 }
3334
3335 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3336 if ($user->hasRight('stock', 'lire')) {
3337 $opt .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3338
3339 if ($objp->stock > 0) {
3340 $outval .= ' - <span class="product_line_stock_ok">';
3341 } elseif ($objp->stock <= 0) {
3342 $outval .= ' - <span class="product_line_stock_too_low">';
3343 }
3344 $outval .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3345 $outval .= '</span>';
3346 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3347 $langs->load("stocks");
3348
3349 $tmpproduct = new Product($this->db);
3350 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3351 $tmpproduct->load_virtual_stock();
3352 $virtualstock = $tmpproduct->stock_theorique;
3353
3354 $opt .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3355
3356 $outval .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3357 if ($virtualstock > 0) {
3358 $outval .= '<span class="product_line_stock_ok">';
3359 } elseif ($virtualstock <= 0) {
3360 $outval .= '<span class="product_line_stock_too_low">';
3361 }
3362 $outval .= $virtualstock;
3363 $outval .= '</span>';
3364
3365 unset($tmpproduct);
3366 }
3367 }
3368 }
3369
3370 $parameters = array('objp'=>$objp);
3371 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3372 if (empty($reshook)) {
3373 $opt .= $hookmanager->resPrint;
3374 } else {
3375 $opt = $hookmanager->resPrint;
3376 }
3377
3378 $opt .= "</option>\n";
3379 $optJson = array(
3380 'key' => $outkey,
3381 'value' => $outref,
3382 'label' => $outval,
3383 'label2' => $outlabel,
3384 'desc' => $outdesc,
3385 'type' => $outtype,
3386 'price_ht' => price2num($outprice_ht),
3387 'price_ttc' => price2num($outprice_ttc),
3388 'price_ht_locale' => price(price2num($outprice_ht)),
3389 'price_ttc_locale' => price(price2num($outprice_ttc)),
3390 'pricebasetype' => $outpricebasetype,
3391 'tva_tx' => $outtva_tx,
3392 'default_vat_code' => $outdefault_vat_code,
3393 'qty' => $outqty,
3394 'discount' => $outdiscount,
3395 'duration_value' => $outdurationvalue,
3396 'duration_unit' => $outdurationunit,
3397 'pbq' => $outpbq,
3398 'labeltrans' => $outlabel_translated,
3399 'desctrans' => $outdesc_translated,
3400 'ref_customer' => $outrefcust
3401 );
3402 }
3403
3404 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3405
3421 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3422 {
3423 // phpcs:enable
3424 global $langs, $conf;
3425 global $price_level, $status, $finished;
3426
3427 if (!isset($status)) {
3428 $status = 1;
3429 }
3430
3431 $selected_input_value = '';
3432 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3433 if ($selected > 0) {
3434 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3435 $producttmpselect = new Product($this->db);
3436 $producttmpselect->fetch($selected);
3437 $selected_input_value = $producttmpselect->ref;
3438 unset($producttmpselect);
3439 }
3440
3441 // mode=2 means suppliers products
3442 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3443 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
3444
3445 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="minwidth300" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3446 } else {
3447 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3448 }
3449 }
3450
3451 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3452
3471 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 = '')
3472 {
3473 // phpcs:enable
3474 global $langs, $conf, $user;
3475 global $hookmanager;
3476
3477 $out = '';
3478 $outarray = array();
3479
3480 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3481
3482 $langs->load('stocks');
3483 // Units
3484 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3485 $langs->load('other');
3486 }
3487
3488 $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,";
3489 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
3490 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name,";
3491 $sql .= " pfp.supplier_reputation";
3492 // if we use supplier description of the products
3493 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3494 $sql .= ", pfp.desc_fourn as description";
3495 } else {
3496 $sql .= ", p.description";
3497 }
3498 // Units
3499 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3500 $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";
3501 }
3502 if (isModEnabled('barcode')) {
3503 $sql .= ", pfp.barcode";
3504 }
3505 $sql .= " FROM " . $this->db->prefix() . "product as p";
3506 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3507 if ($socid > 0) {
3508 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3509 }
3510 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3511 // Units
3512 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3513 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3514 }
3515 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3516 if ($statut != -1) {
3517 $sql .= " AND p.tobuy = " . ((int) $statut);
3518 }
3519 if (strval($filtertype) != '') {
3520 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3521 }
3522 if (!empty($filtre)) {
3523 $sql .= " " . $filtre;
3524 }
3525 // Add where from hooks
3526 $parameters = array();
3527 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3528 $sql .= $hookmanager->resPrint;
3529 // Add criteria on ref/label
3530 if ($filterkey != '') {
3531 $sql .= ' AND (';
3532 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3533 // For natural search
3534 $scrit = explode(' ', $filterkey);
3535 $i = 0;
3536 if (count($scrit) > 1) {
3537 $sql .= "(";
3538 }
3539 foreach ($scrit as $crit) {
3540 if ($i > 0) {
3541 $sql .= " AND ";
3542 }
3543 $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) . "%'";
3544 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3545 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3546 }
3547 $sql .= ")";
3548 $i++;
3549 }
3550 if (count($scrit) > 1) {
3551 $sql .= ")";
3552 }
3553 if (isModEnabled('barcode')) {
3554 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3555 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3556 }
3557 $sql .= ')';
3558 }
3559 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3560 $sql .= $this->db->plimit($limit, 0);
3561
3562 // Build output string
3563
3564 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3565 $result = $this->db->query($sql);
3566 if ($result) {
3567 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3568 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3569
3570 $num = $this->db->num_rows($result);
3571
3572 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3573 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3574 if (!$selected) {
3575 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3576 } else {
3577 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3578 }
3579
3580 $i = 0;
3581 while ($i < $num) {
3582 $objp = $this->db->fetch_object($result);
3583
3584 if (is_null($objp->idprodfournprice)) {
3585 // There is no supplier price found, we will use the vat rate for sale
3586 $objp->tva_tx = $objp->tva_tx_sale;
3587 $objp->default_vat_code = $objp->default_vat_code_sale;
3588 }
3589
3590 $outkey = $objp->idprodfournprice; // id in table of price
3591 if (!$outkey && $alsoproductwithnosupplierprice) {
3592 $outkey = 'idprod_' . $objp->rowid; // id of product
3593 }
3594
3595 $outref = $objp->ref;
3596 $outbarcode = $objp->barcode;
3597 $outqty = 1;
3598 $outdiscount = 0;
3599 $outtype = $objp->fk_product_type;
3600 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3601 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3602
3603 // Units
3604 $outvalUnits = '';
3605 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3606 if (!empty($objp->unit_short)) {
3607 $outvalUnits .= ' - ' . $objp->unit_short;
3608 }
3609 if (!empty($objp->weight) && $objp->weight_units !== null) {
3610 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3611 $outvalUnits .= ' - ' . $unitToShow;
3612 }
3613 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3614 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3615 $outvalUnits .= ' - ' . $unitToShow;
3616 }
3617 if (!empty($objp->surface) && $objp->surface_units !== null) {
3618 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3619 $outvalUnits .= ' - ' . $unitToShow;
3620 }
3621 if (!empty($objp->volume) && $objp->volume_units !== null) {
3622 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3623 $outvalUnits .= ' - ' . $unitToShow;
3624 }
3625 if ($outdurationvalue && $outdurationunit) {
3626 $da = array(
3627 'h' => $langs->trans('Hour'),
3628 'd' => $langs->trans('Day'),
3629 'w' => $langs->trans('Week'),
3630 'm' => $langs->trans('Month'),
3631 'y' => $langs->trans('Year')
3632 );
3633 if (isset($da[$outdurationunit])) {
3634 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3635 }
3636 }
3637 }
3638
3639 $objRef = $objp->ref;
3640 if ($filterkey && $filterkey != '') {
3641 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3642 }
3643 $objRefFourn = $objp->ref_fourn;
3644 if ($filterkey && $filterkey != '') {
3645 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3646 }
3647 $label = $objp->label;
3648 if ($filterkey && $filterkey != '') {
3649 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3650 }
3651
3652 switch ($objp->fk_product_type) {
3654 $picto = 'product';
3655 break;
3657 $picto = 'service';
3658 break;
3659 default:
3660 $picto = '';
3661 break;
3662 }
3663
3664 if (empty($picto)) {
3665 $optlabel = '';
3666 } else {
3667 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3668 }
3669
3670 $optlabel .= $objp->ref;
3671 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3672 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3673 }
3674 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3675 $optlabel .= ' (' . $outbarcode . ')';
3676 }
3677 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3678
3679 $outvallabel = $objRef;
3680 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3681 $outvallabel .= ' (' . $objRefFourn . ')';
3682 }
3683 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3684 $outvallabel .= ' (' . $outbarcode . ')';
3685 }
3686 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3687
3688 // Units
3689 $optlabel .= $outvalUnits;
3690 $outvallabel .= $outvalUnits;
3691
3692 if (!empty($objp->idprodfournprice)) {
3693 $outqty = $objp->quantity;
3694 $outdiscount = $objp->remise_percent;
3695 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3696 $prod_supplier = new ProductFournisseur($this->db);
3697 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3698 $prod_supplier->id = $objp->fk_product;
3699 $prod_supplier->fourn_qty = $objp->quantity;
3700 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3701 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3702
3703 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3704 $priceparser = new PriceParser($this->db);
3705 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3706 if ($price_result >= 0) {
3707 $objp->fprice = $price_result;
3708 if ($objp->quantity >= 1) {
3709 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3710 }
3711 }
3712 }
3713 if ($objp->quantity == 1) {
3714 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3715 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3716 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3717 $outvallabel .= $langs->transnoentities("Unit");
3718 } else {
3719 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3720 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3721 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3722 $outvallabel .= ' ' . $langs->transnoentities("Units");
3723 }
3724
3725 if ($objp->quantity > 1) {
3726 $optlabel .= " (" . price($objp->unitprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3727 $outvallabel .= " (" . price($objp->unitprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3728 }
3729 if ($objp->remise_percent >= 1) {
3730 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3731 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3732 }
3733 if ($objp->duration) {
3734 $optlabel .= " - " . $objp->duration;
3735 $outvallabel .= " - " . $objp->duration;
3736 }
3737 if (!$socid) {
3738 $optlabel .= " - " . dol_trunc($objp->name, 8);
3739 $outvallabel .= " - " . dol_trunc($objp->name, 8);
3740 }
3741 if ($objp->supplier_reputation) {
3742 //TODO dictionary
3743 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3744
3745 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3746 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3747 }
3748 } else {
3749 if (empty($alsoproductwithnosupplierprice)) { // No supplier price defined for couple product/supplier
3750 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3751 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3752 } else { // No supplier price defined for product, even on other suppliers
3753 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3754 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3755 }
3756 }
3757
3758 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3759 $novirtualstock = ($showstockinlist == 2);
3760
3761 if ($user->hasRight('stock', 'lire')) {
3762 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3763
3764 if ($objp->stock > 0) {
3765 $optlabel .= ' - <span class="product_line_stock_ok">';
3766 } elseif ($objp->stock <= 0) {
3767 $optlabel .= ' - <span class="product_line_stock_too_low">';
3768 }
3769 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3770 $optlabel .= '</span>';
3771 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3772 $langs->load("stocks");
3773
3774 $tmpproduct = new Product($this->db);
3775 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3776 $tmpproduct->load_virtual_stock();
3777 $virtualstock = $tmpproduct->stock_theorique;
3778
3779 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3780
3781 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3782 if ($virtualstock > 0) {
3783 $optlabel .= '<span class="product_line_stock_ok">';
3784 } elseif ($virtualstock <= 0) {
3785 $optlabel .= '<span class="product_line_stock_too_low">';
3786 }
3787 $optlabel .= $virtualstock;
3788 $optlabel .= '</span>';
3789
3790 unset($tmpproduct);
3791 }
3792 }
3793 }
3794
3795 $optstart = '<option value="' . $outkey . '"';
3796 if ($selected && $selected == $objp->idprodfournprice) {
3797 $optstart .= ' selected';
3798 }
3799 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3800 $optstart .= ' disabled';
3801 }
3802
3803 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3804 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
3805 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
3806 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
3807 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
3808 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
3809 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
3810 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
3811 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
3812 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
3813 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
3814 }
3815 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
3816
3817 $outarrayentry = array(
3818 'key' => $outkey,
3819 'value' => $outref,
3820 'label' => $outvallabel,
3821 'qty' => $outqty,
3822 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3823 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3824 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3825 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
3826 'tva_tx' => price2num($objp->tva_tx),
3827 'default_vat_code' => $objp->default_vat_code,
3828 'discount' => $outdiscount,
3829 'type' => $outtype,
3830 'duration_value' => $outdurationvalue,
3831 'duration_unit' => $outdurationunit,
3832 'disabled' => (empty($objp->idprodfournprice) ? true : false),
3833 'description' => $objp->description
3834 );
3835
3836 $parameters = array(
3837 'objp' => &$objp,
3838 'optstart' => &$optstart,
3839 'optlabel' => &$optlabel,
3840 'outvallabel' => &$outvallabel,
3841 'outarrayentry' => &$outarrayentry
3842 );
3843 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
3844
3845
3846 // Add new entry
3847 // "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
3848 // "label" value of json key array is used by jQuery automatically as text for combo box
3849 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
3850 array_push(
3851 $outarray,
3852 array('key' => $outkey,
3853 'value' => $outref,
3854 'label' => $outvallabel,
3855 'qty' => $outqty,
3856 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3857 'price_qty_ht_locale' => price($objp->fprice),
3858 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3859 'price_unit_ht_locale' => price($objp->unitprice),
3860 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3861 'tva_tx_formated' => price($objp->tva_tx),
3862 'tva_tx' => price2num($objp->tva_tx),
3863 'default_vat_code' => $objp->default_vat_code,
3864 'discount' => $outdiscount,
3865 'type' => $outtype,
3866 'duration_value' => $outdurationvalue,
3867 'duration_unit' => $outdurationunit,
3868 'disabled' => (empty($objp->idprodfournprice) ? true : false),
3869 'description' => $objp->description
3870 )
3871 );
3872 // Exemple of var_dump $outarray
3873 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
3874 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
3875 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
3876 //}
3877 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3878 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
3879 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3880
3881 $i++;
3882 }
3883 $out .= '</select>';
3884
3885 $this->db->free($result);
3886
3887 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3888 $out .= ajax_combobox($htmlname);
3889 } else {
3890 dol_print_error($this->db);
3891 }
3892
3893 if (empty($outputmode)) {
3894 return $out;
3895 }
3896 return $outarray;
3897 }
3898
3899 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3900
3909 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
3910 {
3911 // phpcs:enable
3912 global $langs, $conf;
3913
3914 $langs->load('stocks');
3915
3916 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3917 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3918 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3919 $sql .= " FROM " . $this->db->prefix() . "product as p";
3920 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3921 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3922 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
3923 $sql .= " AND p.tobuy = 1";
3924 $sql .= " AND s.fournisseur = 1";
3925 $sql .= " AND p.rowid = " . ((int) $productid);
3926 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
3927 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3928 } else {
3929 $sql .= " ORDER BY pfp.unitprice ASC";
3930 }
3931
3932 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
3933 $result = $this->db->query($sql);
3934
3935 if ($result) {
3936 $num = $this->db->num_rows($result);
3937
3938 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
3939
3940 if (!$num) {
3941 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
3942 } else {
3943 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3944 $form .= '<option value="0">&nbsp;</option>';
3945
3946 $i = 0;
3947 while ($i < $num) {
3948 $objp = $this->db->fetch_object($result);
3949
3950 $opt = '<option value="' . $objp->idprodfournprice . '"';
3951 //if there is only one supplier, preselect it
3952 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
3953 $opt .= ' selected';
3954 }
3955 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
3956
3957 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3958 $prod_supplier = new ProductFournisseur($this->db);
3959 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3960 $prod_supplier->id = $productid;
3961 $prod_supplier->fourn_qty = $objp->quantity;
3962 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3963 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3964
3965 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3966 $priceparser = new PriceParser($this->db);
3967 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3968 if ($price_result >= 0) {
3969 $objp->fprice = $price_result;
3970 if ($objp->quantity >= 1) {
3971 $objp->unitprice = $objp->fprice / $objp->quantity;
3972 }
3973 }
3974 }
3975 if ($objp->quantity == 1) {
3976 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3977 }
3978
3979 $opt .= $objp->quantity . ' ';
3980
3981 if ($objp->quantity == 1) {
3982 $opt .= $langs->trans("Unit");
3983 } else {
3984 $opt .= $langs->trans("Units");
3985 }
3986 if ($objp->quantity > 1) {
3987 $opt .= " - ";
3988 $opt .= price($objp->unitprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit");
3989 }
3990 if ($objp->duration) {
3991 $opt .= " - " . $objp->duration;
3992 }
3993 $opt .= "</option>\n";
3994
3995 $form .= $opt;
3996 $i++;
3997 }
3998 }
3999
4000 $form .= '</select>';
4001 $this->db->free($result);
4002 return $form;
4003 } else {
4004 dol_print_error($this->db);
4005 return '';
4006 }
4007 }
4008
4009
4010 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4017 {
4018 // phpcs:enable
4019 global $langs;
4020
4021 $num = count($this->cache_conditions_paiements);
4022 if ($num > 0) {
4023 return 0; // Cache already loaded
4024 }
4025
4026 dol_syslog(__METHOD__, LOG_DEBUG);
4027
4028 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4029 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4030 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4031 $sql .= " AND active > 0";
4032 $sql .= " ORDER BY sortorder";
4033
4034 $resql = $this->db->query($sql);
4035 if ($resql) {
4036 $num = $this->db->num_rows($resql);
4037 $i = 0;
4038 while ($i < $num) {
4039 $obj = $this->db->fetch_object($resql);
4040
4041 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4042 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4043 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4044 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4045 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4046 $i++;
4047 }
4048
4049 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4050
4051 return $num;
4052 } else {
4053 dol_print_error($this->db);
4054 return -1;
4055 }
4056 }
4057
4058 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4059
4065 public function load_cache_availability()
4066 {
4067 // phpcs:enable
4068 global $langs;
4069
4070 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4071 if ($num > 0) {
4072 return 0; // Cache already loaded
4073 }
4074
4075 dol_syslog(__METHOD__, LOG_DEBUG);
4076
4077 $langs->load('propal');
4078
4079 $sql = "SELECT rowid, code, label, position";
4080 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4081 $sql .= " WHERE active > 0";
4082
4083 $resql = $this->db->query($sql);
4084 if ($resql) {
4085 $num = $this->db->num_rows($resql);
4086 $i = 0;
4087 while ($i < $num) {
4088 $obj = $this->db->fetch_object($resql);
4089
4090 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4091 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4092 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4093 $this->cache_availability[$obj->rowid]['label'] = $label;
4094 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4095 $i++;
4096 }
4097
4098 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4099
4100 return $num;
4101 } else {
4102 dol_print_error($this->db);
4103 return -1;
4104 }
4105 }
4106
4117 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4118 {
4119 global $langs, $user;
4120
4121 $this->load_cache_availability();
4122
4123 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4124
4125 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4126 if ($addempty) {
4127 print '<option value="0">&nbsp;</option>';
4128 }
4129 foreach ($this->cache_availability as $id => $arrayavailability) {
4130 if ($selected == $id) {
4131 print '<option value="' . $id . '" selected>';
4132 } else {
4133 print '<option value="' . $id . '">';
4134 }
4135 print dol_escape_htmltag($arrayavailability['label']);
4136 print '</option>';
4137 }
4138 print '</select>';
4139 if ($user->admin) {
4140 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4141 }
4142 print ajax_combobox($htmlname);
4143 }
4144
4150 public function loadCacheInputReason()
4151 {
4152 global $langs;
4153
4154 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4155 if ($num > 0) {
4156 return 0; // Cache already loaded
4157 }
4158
4159 $sql = "SELECT rowid, code, label";
4160 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4161 $sql .= " WHERE active > 0";
4162
4163 $resql = $this->db->query($sql);
4164 if ($resql) {
4165 $num = $this->db->num_rows($resql);
4166 $i = 0;
4167 $tmparray = array();
4168 while ($i < $num) {
4169 $obj = $this->db->fetch_object($resql);
4170
4171 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4172 $label = ($obj->label != '-' ? $obj->label : '');
4173 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4174 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4175 }
4176 if ($langs->trans($obj->code) != $obj->code) {
4177 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4178 }
4179
4180 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4181 $tmparray[$obj->rowid]['code'] = $obj->code;
4182 $tmparray[$obj->rowid]['label'] = $label;
4183 $i++;
4184 }
4185
4186 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4187
4188 unset($tmparray);
4189 return $num;
4190 } else {
4191 dol_print_error($this->db);
4192 return -1;
4193 }
4194 }
4195
4208 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4209 {
4210 global $langs, $user;
4211
4212 $this->loadCacheInputReason();
4213
4214 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4215 if ($addempty) {
4216 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4217 }
4218 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4219 if ($arraydemandreason['code'] == $exclude) {
4220 continue;
4221 }
4222
4223 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4224 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4225 } else {
4226 print '<option value="' . $arraydemandreason['id'] . '">';
4227 }
4228 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4229 print $langs->trans($label);
4230 print '</option>';
4231 }
4232 print '</select>';
4233 if ($user->admin && empty($notooltip)) {
4234 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4235 }
4236 print ajax_combobox('select_' . $htmlname);
4237 }
4238
4239 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4240
4247 {
4248 // phpcs:enable
4249 global $langs;
4250
4251 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4252 if ($num > 0) {
4253 return $num; // Cache already loaded
4254 }
4255
4256 dol_syslog(__METHOD__, LOG_DEBUG);
4257
4258 $this->cache_types_paiements = array();
4259
4260 $sql = "SELECT id, code, libelle as label, type, active";
4261 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4262 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4263
4264 $resql = $this->db->query($sql);
4265 if ($resql) {
4266 $num = $this->db->num_rows($resql);
4267 $i = 0;
4268 while ($i < $num) {
4269 $obj = $this->db->fetch_object($resql);
4270
4271 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4272 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4273 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4274 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4275 $this->cache_types_paiements[$obj->id]['label'] = $label;
4276 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4277 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4278 $i++;
4279 }
4280
4281 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4282
4283 return $num;
4284 } else {
4285 dol_print_error($this->db);
4286 return -1;
4287 }
4288 }
4289
4290
4291 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4292
4310 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4311 {
4312 // phpcs:enable
4313 print $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4314 }
4315
4316
4333 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4334 {
4335 global $langs, $user, $conf;
4336
4337 $out = '';
4338 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4339
4341
4342 // Set default value if not already set by caller
4343 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4344 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4345 $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
4346 }
4347
4348 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4349 if ($addempty) {
4350 $out .= '<option value="0">&nbsp;</option>';
4351 }
4352
4353 $selectedDepositPercent = null;
4354
4355 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4356 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4357 continue;
4358 }
4359
4360 if ($selected == $id) {
4361 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4362 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4363 } else {
4364 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4365 }
4366 $label = $arrayconditions['label'];
4367
4368 if (!empty($arrayconditions['deposit_percent'])) {
4369 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4370 }
4371
4372 $out .= $label;
4373 $out .= '</option>';
4374 }
4375 $out .= '</select>';
4376 if ($user->admin && empty($noinfoadmin)) {
4377 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4378 }
4379 $out .= ajax_combobox($htmlname);
4380
4381 if ($deposit_percent >= 0) {
4382 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4383 $out .= $langs->trans('DepositPercent') . ' : ';
4384 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4385 $out .= '</span>';
4386 $out .= '
4387 <script nonce="' . getNonce() . '">
4388 $(document).ready(function () {
4389 $("#' . $htmlname . '").change(function () {
4390 let $selected = $(this).find("option:selected");
4391 let depositPercent = $selected.attr("data-deposit_percent");
4392
4393 if (depositPercent.length > 0) {
4394 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4395 } else {
4396 $("#' . $htmlname . '_deposit_percent_container").hide();
4397 }
4398
4399 return true;
4400 });
4401 });
4402 </script>';
4403 }
4404
4405 return $out;
4406 }
4407
4408
4409 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4410
4427 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4428 {
4429 // phpcs:enable
4430 global $langs, $user, $conf;
4431
4432 $out = '';
4433
4434 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4435
4436 $filterarray = array();
4437 if ($filtertype == 'CRDT') {
4438 $filterarray = array(0, 2, 3);
4439 } elseif ($filtertype == 'DBIT') {
4440 $filterarray = array(1, 2, 3);
4441 } elseif ($filtertype != '' && $filtertype != '-1') {
4442 $filterarray = explode(',', $filtertype);
4443 }
4444
4446
4447 // Set default value if not already set by caller
4448 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4449 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4450 $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
4451 }
4452
4453 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4454 if ($empty) {
4455 $out .= '<option value="">&nbsp;</option>';
4456 }
4457 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4458 // If not good status
4459 if ($active >= 0 && $arraytypes['active'] != $active) {
4460 continue;
4461 }
4462
4463 // On passe si on a demande de filtrer sur des modes de paiments particuliers
4464 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4465 continue;
4466 }
4467
4468 // We discard empty line if showempty is on because an empty line has already been output.
4469 if ($empty && empty($arraytypes['code'])) {
4470 continue;
4471 }
4472
4473 if ($format == 0) {
4474 $out .= '<option value="' . $id . '"';
4475 } elseif ($format == 1) {
4476 $out .= '<option value="' . $arraytypes['code'] . '"';
4477 } elseif ($format == 2) {
4478 $out .= '<option value="' . $arraytypes['code'] . '"';
4479 } elseif ($format == 3) {
4480 $out .= '<option value="' . $id . '"';
4481 }
4482 // Print attribute selected or not
4483 if ($format == 1 || $format == 2) {
4484 if ($selected == $arraytypes['code']) {
4485 $out .= ' selected';
4486 }
4487 } else {
4488 if ($selected == $id) {
4489 $out .= ' selected';
4490 }
4491 }
4492 $out .= '>';
4493 $value = '';
4494 if ($format == 0) {
4495 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4496 } elseif ($format == 1) {
4497 $value = $arraytypes['code'];
4498 } elseif ($format == 2) {
4499 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4500 } elseif ($format == 3) {
4501 $value = $arraytypes['code'];
4502 }
4503 $out .= $value ? $value : '&nbsp;';
4504 $out .= '</option>';
4505 }
4506 $out .= '</select>';
4507 if ($user->admin && !$noadmininfo) {
4508 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4509 }
4510 $out .= ajax_combobox('select' . $htmlname);
4511
4512 if (empty($nooutput)) {
4513 print $out;
4514 } else {
4515 return $out;
4516 }
4517 }
4518
4519
4528 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4529 {
4530 global $langs;
4531
4532 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4533 $options = array(
4534 'HT' => $langs->trans("HT"),
4535 'TTC' => $langs->trans("TTC")
4536 );
4537 foreach ($options as $id => $value) {
4538 if ($selected == $id) {
4539 $return .= '<option value="' . $id . '" selected>' . $value;
4540 } else {
4541 $return .= '<option value="' . $id . '">' . $value;
4542 }
4543 $return .= '</option>';
4544 }
4545 $return .= '</select>';
4546 if ($addjscombo) {
4547 $return .= ajax_combobox('select_' . $htmlname);
4548 }
4549
4550 return $return;
4551 }
4552
4553 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4554
4561 {
4562 // phpcs:enable
4563 global $langs;
4564
4565 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4566 if ($num > 0) {
4567 return $num; // Cache already loaded
4568 }
4569
4570 dol_syslog(__METHOD__, LOG_DEBUG);
4571
4572 $this->cache_transport_mode = array();
4573
4574 $sql = "SELECT rowid, code, label, active";
4575 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4576 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4577
4578 $resql = $this->db->query($sql);
4579 if ($resql) {
4580 $num = $this->db->num_rows($resql);
4581 $i = 0;
4582 while ($i < $num) {
4583 $obj = $this->db->fetch_object($resql);
4584
4585 // If traduction exist, we use it else we take the default label
4586 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4587 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4588 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4589 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4590 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4591 $i++;
4592 }
4593
4594 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4595
4596 return $num;
4597 } else {
4598 dol_print_error($this->db);
4599 return -1;
4600 }
4601 }
4602
4616 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4617 {
4618 global $langs, $user;
4619
4620 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4621
4623
4624 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4625 if ($empty) {
4626 print '<option value="">&nbsp;</option>';
4627 }
4628 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4629 // If not good status
4630 if ($active >= 0 && $arraytypes['active'] != $active) {
4631 continue;
4632 }
4633
4634 // We discard empty line if showempty is on because an empty line has already been output.
4635 if ($empty && empty($arraytypes['code'])) {
4636 continue;
4637 }
4638
4639 if ($format == 0) {
4640 print '<option value="' . $id . '"';
4641 } elseif ($format == 1) {
4642 print '<option value="' . $arraytypes['code'] . '"';
4643 } elseif ($format == 2) {
4644 print '<option value="' . $arraytypes['code'] . '"';
4645 } elseif ($format == 3) {
4646 print '<option value="' . $id . '"';
4647 }
4648 // If text is selected, we compare with code, else with id
4649 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4650 print ' selected';
4651 } elseif ($selected == $id) {
4652 print ' selected';
4653 }
4654 print '>';
4655 $value = '';
4656 if ($format == 0) {
4657 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4658 } elseif ($format == 1) {
4659 $value = $arraytypes['code'];
4660 } elseif ($format == 2) {
4661 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4662 } elseif ($format == 3) {
4663 $value = $arraytypes['code'];
4664 }
4665 print $value ? $value : '&nbsp;';
4666 print '</option>';
4667 }
4668 print '</select>';
4669 if ($user->admin && !$noadmininfo) {
4670 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4671 }
4672 }
4673
4686 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4687 {
4688 global $langs, $user;
4689
4690 $langs->load("admin");
4691 $langs->load("deliveries");
4692
4693 $sql = "SELECT rowid, code, libelle as label";
4694 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4695 $sql .= " WHERE active > 0";
4696 if ($filtre) {
4697 $sql .= " AND " . $filtre;
4698 }
4699 $sql .= " ORDER BY libelle ASC";
4700
4701 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4702 $result = $this->db->query($sql);
4703 if ($result) {
4704 $num = $this->db->num_rows($result);
4705 $i = 0;
4706 if ($num) {
4707 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4708 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4709 print '<option value="-1">&nbsp;</option>';
4710 }
4711 while ($i < $num) {
4712 $obj = $this->db->fetch_object($result);
4713 if ($selected == $obj->rowid) {
4714 print '<option value="' . $obj->rowid . '" selected>';
4715 } else {
4716 print '<option value="' . $obj->rowid . '">';
4717 }
4718 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
4719 print '</option>';
4720 $i++;
4721 }
4722 print "</select>";
4723 if ($user->admin && empty($noinfoadmin)) {
4724 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4725 }
4726
4727 print ajax_combobox('select' . $htmlname);
4728 } else {
4729 print $langs->trans("NoShippingMethodDefined");
4730 }
4731 } else {
4732 dol_print_error($this->db);
4733 }
4734 }
4735
4745 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4746 {
4747 global $langs;
4748
4749 $langs->load("deliveries");
4750
4751 if ($htmlname != "none") {
4752 print '<form method="POST" action="' . $page . '">';
4753 print '<input type="hidden" name="action" value="setshippingmethod">';
4754 print '<input type="hidden" name="token" value="' . newToken() . '">';
4755 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4756 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
4757 print '</form>';
4758 } else {
4759 if ($selected) {
4760 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4761 print $langs->trans("SendingMethod" . strtoupper($code));
4762 } else {
4763 print "&nbsp;";
4764 }
4765 }
4766 }
4767
4776 public function selectSituationInvoices($selected = '', $socid = 0)
4777 {
4778 global $langs;
4779
4780 $langs->load('bills');
4781
4782 $opt = '<option value="" selected></option>';
4783 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4784 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
4785 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
4786 $sql .= ' AND situation_counter >= 1';
4787 $sql .= ' AND fk_soc = ' . (int) $socid;
4788 $sql .= ' AND type <> 2';
4789 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4790 $resql = $this->db->query($sql);
4791
4792 if ($resql && $this->db->num_rows($resql) > 0) {
4793 // Last seen cycle
4794 $ref = 0;
4795 while ($obj = $this->db->fetch_object($resql)) {
4796 //Same cycle ?
4797 if ($obj->situation_cycle_ref != $ref) {
4798 // Just seen this cycle
4799 $ref = $obj->situation_cycle_ref;
4800 //not final ?
4801 if ($obj->situation_final != 1) {
4802 //Not prov?
4803 if (substr($obj->ref, 1, 4) != 'PROV') {
4804 if ($selected == $obj->rowid) {
4805 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
4806 } else {
4807 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
4808 }
4809 }
4810 }
4811 }
4812 }
4813 } else {
4814 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
4815 }
4816 if ($opt == '<option value ="" selected></option>') {
4817 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
4818 }
4819 return $opt;
4820 }
4821
4831 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
4832 {
4833 global $langs;
4834
4835 $langs->load('products');
4836
4837 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
4838
4839 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
4840 $sql .= ' WHERE active > 0';
4841 if (!empty($unit_type)) {
4842 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
4843 }
4844 $sql .= " ORDER BY sortorder";
4845
4846 $resql = $this->db->query($sql);
4847 if ($resql && $this->db->num_rows($resql) > 0) {
4848 if ($showempty) {
4849 $return .= '<option value="none"></option>';
4850 }
4851
4852 while ($res = $this->db->fetch_object($resql)) {
4853 $unitLabel = $res->label;
4854 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
4855 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
4856 }
4857
4858 if ($selected == $res->rowid) {
4859 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
4860 } else {
4861 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
4862 }
4863 }
4864 $return .= '</select>';
4865 }
4866 return $return;
4867 }
4868
4869 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4870
4885 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
4886 {
4887 // phpcs:enable
4888 global $langs, $conf;
4889
4890 $out = '';
4891
4892 $langs->load("admin");
4893 $num = 0;
4894
4895 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
4896 $sql .= " FROM " . $this->db->prefix() . "bank_account";
4897 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
4898 if ($status != 2) {
4899 $sql .= " AND clos = " . (int) $status;
4900 }
4901 if ($filtre) {
4902 $sql .= " AND " . $filtre;
4903 }
4904 $sql .= " ORDER BY label";
4905
4906 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
4907 $result = $this->db->query($sql);
4908 if ($result) {
4909 $num = $this->db->num_rows($result);
4910 $i = 0;
4911 if ($num) {
4912 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4913 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4914 $out .= '<option value="-1">&nbsp;</option>';
4915 }
4916
4917 while ($i < $num) {
4918 $obj = $this->db->fetch_object($result);
4919 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
4920 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" selected>';
4921 } else {
4922 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '">';
4923 }
4924 $out .= trim($obj->label);
4925 if ($showcurrency) {
4926 $out .= ' (' . $obj->currency_code . ')';
4927 }
4928 if ($status == 2 && $obj->status == 1) {
4929 $out .= ' (' . $langs->trans("Closed") . ')';
4930 }
4931 $out .= '</option>';
4932 $i++;
4933 }
4934 $out .= "</select>";
4935 $out .= ajax_combobox('select' . $htmlname);
4936 } else {
4937 if ($status == 0) {
4938 $out .= '<span class="opacitymedium">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
4939 } else {
4940 $out .= '<span class="opacitymedium">' . $langs->trans("NoBankAccountFound") . '</span>';
4941 }
4942 }
4943 } else {
4944 dol_print_error($this->db);
4945 }
4946
4947 // Output or return
4948 if (empty($nooutput)) {
4949 print $out;
4950 } else {
4951 return $out;
4952 }
4953
4954 return $num;
4955 }
4956
4968 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4969 {
4970 global $langs, $conf;
4971
4972 $langs->load("admin");
4973 $num = 0;
4974
4975 $sql = "SELECT rowid, name, fk_country, status, entity";
4976 $sql .= " FROM " . $this->db->prefix() . "establishment";
4977 $sql .= " WHERE 1=1";
4978 if ($status != 2) {
4979 $sql .= " AND status = " . (int) $status;
4980 }
4981 if ($filtre) {
4982 $sql .= " AND " . $filtre;
4983 }
4984 $sql .= " ORDER BY name";
4985
4986 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
4987 $result = $this->db->query($sql);
4988 if ($result) {
4989 $num = $this->db->num_rows($result);
4990 $i = 0;
4991 if ($num) {
4992 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4993 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4994 print '<option value="-1">&nbsp;</option>';
4995 }
4996
4997 while ($i < $num) {
4998 $obj = $this->db->fetch_object($result);
4999 if ($selected == $obj->rowid) {
5000 print '<option value="' . $obj->rowid . '" selected>';
5001 } else {
5002 print '<option value="' . $obj->rowid . '">';
5003 }
5004 print trim($obj->name);
5005 if ($status == 2 && $obj->status == 1) {
5006 print ' (' . $langs->trans("Closed") . ')';
5007 }
5008 print '</option>';
5009 $i++;
5010 }
5011 print "</select>";
5012 } else {
5013 if ($status == 0) {
5014 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5015 } else {
5016 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5017 }
5018 }
5019
5020 return $num;
5021 } else {
5022 dol_print_error($this->db);
5023 return -1;
5024 }
5025 }
5026
5036 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5037 {
5038 global $langs;
5039 if ($htmlname != "none") {
5040 print '<form method="POST" action="' . $page . '">';
5041 print '<input type="hidden" name="action" value="setbankaccount">';
5042 print '<input type="hidden" name="token" value="' . newToken() . '">';
5043 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5044 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5045 if ($nbaccountfound > 0) {
5046 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5047 }
5048 print '</form>';
5049 } else {
5050 $langs->load('banks');
5051
5052 if ($selected) {
5053 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5054 $bankstatic = new Account($this->db);
5055 $result = $bankstatic->fetch($selected);
5056 if ($result) {
5057 print $bankstatic->getNomUrl(1);
5058 }
5059 } else {
5060 print "&nbsp;";
5061 }
5062 }
5063 }
5064
5065 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5066
5085 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
5086 {
5087 // phpcs:enable
5088 global $conf, $langs;
5089 $langs->load("categories");
5090
5091 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5092
5093 // For backward compatibility
5094 if (is_numeric($type)) {
5095 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5096 }
5097
5098 if ($type === Categorie::TYPE_BANK_LINE) {
5099 // TODO Move this into common category feature
5100 $cate_arbo = array();
5101 $sql = "SELECT c.label, c.rowid";
5102 $sql .= " FROM " . $this->db->prefix() . "bank_categ as c";
5103 $sql .= " WHERE entity = " . $conf->entity;
5104 $sql .= " ORDER BY c.label";
5105 $result = $this->db->query($sql);
5106 if ($result) {
5107 $num = $this->db->num_rows($result);
5108 $i = 0;
5109 while ($i < $num) {
5110 $objp = $this->db->fetch_object($result);
5111 if ($objp) {
5112 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5113 }
5114 $i++;
5115 }
5116 $this->db->free($result);
5117 } else {
5118 dol_print_error($this->db);
5119 }
5120 } else {
5121 $cat = new Categorie($this->db);
5122 $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
5123 }
5124
5125 $outarray = array();
5126 $outarrayrichhtml = array();
5127
5128 $output = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5129 if (is_array($cate_arbo)) {
5130 if (!count($cate_arbo)) {
5131 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5132 } else {
5133 $output .= '<option value="-1">&nbsp;</option>';
5134 foreach ($cate_arbo as $key => $value) {
5135 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5136 $add = 'selected ';
5137 } else {
5138 $add = '';
5139 }
5140
5141 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5142 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5143
5144 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5145
5146 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5147
5148 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5149 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5150 $output .= '>';
5151 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5152 $output .= '</option>';
5153 }
5154 }
5155 }
5156 $output .= '</select>';
5157 $output .= "\n";
5158
5159 if ($outputmode == 2) {
5160 return $cate_arbo;
5161 } elseif ($outputmode == 1) {
5162 return $outarray;
5163 } elseif ($outputmode == 3) {
5164 return $outarrayrichhtml;
5165 }
5166 return $output;
5167 }
5168
5169 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5170
5187 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5188 {
5189 // phpcs:enable
5190 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5191 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5192 }
5193
5221 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5222 {
5223 global $langs, $conf;
5224
5225 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5226 $formconfirm = '';
5227 $inputok = array();
5228 $inputko = array();
5229
5230 // Clean parameters
5231 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5232 if ($conf->browser->layout == 'phone') {
5233 $width = '95%';
5234 }
5235
5236 // Set height automatically if not defined
5237 if (empty($height)) {
5238 $height = 220;
5239 if (is_array($formquestion) && count($formquestion) > 2) {
5240 $height += ((count($formquestion) - 2) * 24);
5241 }
5242 }
5243
5244 if (is_array($formquestion) && !empty($formquestion)) {
5245 // First add hidden fields and value
5246 foreach ($formquestion as $key => $input) {
5247 if (is_array($input) && !empty($input)) {
5248 if ($input['type'] == 'hidden') {
5249 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5250 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5251
5252 $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";
5253 }
5254 }
5255 }
5256
5257 // Now add questions
5258 $moreonecolumn = '';
5259 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5260 foreach ($formquestion as $key => $input) {
5261 if (is_array($input) && !empty($input)) {
5262 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5263 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5264 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5265
5266 if ($input['type'] == 'text') {
5267 $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";
5268 } elseif ($input['type'] == 'password') {
5269 $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";
5270 } elseif ($input['type'] == 'textarea') {
5271 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5272 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5273 $more .= $input['value'];
5274 $more .= '</textarea>';
5275 $more .= '</div></div>'."\n";*/
5276 $moreonecolumn .= '<div class="margintoponly">';
5277 $moreonecolumn .= $input['label'] . '<br>';
5278 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5279 $moreonecolumn .= $input['value'];
5280 $moreonecolumn .= '</textarea>';
5281 $moreonecolumn .= '</div>';
5282 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5283 if (empty($morecss)) {
5284 $morecss = 'minwidth100';
5285 }
5286
5287 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5288 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5289 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5290 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5291 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5292 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5293 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5294
5295 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5296 if (!empty($input['label'])) {
5297 $more .= $input['label'] . '</div><div class="tagtd left">';
5298 }
5299 if ($input['type'] == 'select') {
5300 $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);
5301 } else {
5302 $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);
5303 }
5304 $more .= '</div></div>' . "\n";
5305 } elseif ($input['type'] == 'checkbox') {
5306 $more .= '<div class="tagtr">';
5307 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5308 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5309 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5310 $more .= ' checked';
5311 }
5312 if (is_bool($input['value']) && $input['value']) {
5313 $more .= ' checked';
5314 }
5315 if (isset($input['disabled'])) {
5316 $more .= ' disabled';
5317 }
5318 $more .= ' /></div>';
5319 $more .= '</div>' . "\n";
5320 } elseif ($input['type'] == 'radio') {
5321 $i = 0;
5322 foreach ($input['values'] as $selkey => $selval) {
5323 $more .= '<div class="tagtr">';
5324 if (isset($input['label'])) {
5325 if ($i == 0) {
5326 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5327 } else {
5328 $more .= '<div clas="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5329 }
5330 }
5331 $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;
5332 if (!empty($input['disabled'])) {
5333 $more .= ' disabled';
5334 }
5335 if (isset($input['default']) && $input['default'] === $selkey) {
5336 $more .= ' checked="checked"';
5337 }
5338 $more .= ' /> ';
5339 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5340 $more .= '</div></div>' . "\n";
5341 $i++;
5342 }
5343 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5344 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5345 $more .= '<div class="tagtd">';
5346 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5347 $h = $m = 0;
5348 if ($input['type'] == 'datetime') {
5349 $h = isset($input['hours']) ? $input['hours'] : 1;
5350 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5351 }
5352 $more .= $this->selectDate($input['value'], $input['name'], $h, $m, 0, '', 1, $addnowlink);
5353 $more .= '</div></div>'."\n";
5354 $formquestion[] = array('name'=>$input['name'].'day');
5355 $formquestion[] = array('name'=>$input['name'].'month');
5356 $formquestion[] = array('name'=>$input['name'].'year');
5357 $formquestion[] = array('name'=>$input['name'].'hour');
5358 $formquestion[] = array('name'=>$input['name'].'min');
5359 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5360 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5361 if (!empty($input['label'])) {
5362 $more .= $input['label'] . '</div><div class="tagtd">';
5363 }
5364 $more .= $input['value'];
5365 $more .= '</div></div>' . "\n";
5366 } elseif ($input['type'] == 'onecolumn') {
5367 $moreonecolumn .= '<div class="margintoponly">';
5368 $moreonecolumn .= $input['value'];
5369 $moreonecolumn .= '</div>' . "\n";
5370 } elseif ($input['type'] == 'hidden') {
5371 // Do nothing more, already added by a previous loop
5372 } elseif ($input['type'] == 'separator') {
5373 $more .= '<br>';
5374 } else {
5375 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5376 }
5377 }
5378 }
5379 $more .= '</div>' . "\n";
5380 $more .= $moreonecolumn;
5381 }
5382
5383 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5384 // 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
5385 // See page product/card.php for example
5386 if (!empty($conf->dol_use_jmobile)) {
5387 $useajax = 0;
5388 }
5389 if (empty($conf->use_javascript_ajax)) {
5390 $useajax = 0;
5391 }
5392
5393 if ($useajax) {
5394 $autoOpen = true;
5395 $dialogconfirm = 'dialog-confirm';
5396 $button = '';
5397 if (!is_numeric($useajax)) {
5398 $button = $useajax;
5399 $useajax = 1;
5400 $autoOpen = false;
5401 $dialogconfirm .= '-' . $button;
5402 }
5403 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5404 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5405
5406 // Add input fields into list of fields to read during submit (inputok and inputko)
5407 if (is_array($formquestion)) {
5408 foreach ($formquestion as $key => $input) {
5409 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5410 // Add name of fields to propagate with the GET when submitting the form with button OK.
5411 if (is_array($input) && isset($input['name'])) {
5412 if (strpos($input['name'], ',') > 0) {
5413 $inputok = array_merge($inputok, explode(',', $input['name']));
5414 } else {
5415 array_push($inputok, $input['name']);
5416 }
5417 }
5418 // Add name of fields to propagate with the GET when submitting the form with button KO.
5419 if (isset($input['inputko']) && $input['inputko'] == 1) {
5420 array_push($inputko, $input['name']);
5421 }
5422 }
5423 }
5424
5425 // Show JQuery confirm box.
5426 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5427 if (is_array($formquestion) && !empty($formquestion['text'])) {
5428 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5429 }
5430 if (!empty($more)) {
5431 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5432 }
5433 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help('', '') . ' ' . $question . '</div>' : '');
5434 $formconfirm .= '</div>' . "\n";
5435
5436 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5437 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5438 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5439 $formconfirm .= 'jQuery(document).ready(function() {
5440 $(function() {
5441 $( "#' . $dialogconfirm . '" ).dialog(
5442 {
5443 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5444 if ($newselectedchoice == 'no') {
5445 $formconfirm .= '
5446 open: function() {
5447 $(this).parent().find("button.ui-button:eq(2)").focus();
5448 },';
5449 }
5450
5451 $jsforcursor = '';
5452 if ($useajax == 1) {
5453 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5454 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5455 }
5456
5457 $postconfirmas = 'GET';
5458
5459 $formconfirm .= '
5460 resizable: false,
5461 height: "' . $height . '",
5462 width: "' . $width . '",
5463 modal: true,
5464 closeOnEscape: false,
5465 buttons: {
5466 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5467 var options = "token=' . urlencode(newToken()) . '";
5468 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5469 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5470 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5471
5472 if (inputok.length > 0) {
5473 $.each(inputok, function(i, inputname) {
5474 var more = "";
5475 var inputvalue;
5476 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5477 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5478 } else {
5479 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5480 inputvalue = $("#" + inputname + more).val();
5481 }
5482 if (typeof inputvalue == "undefined") { inputvalue=""; }
5483 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5484 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5485 });
5486 }
5487 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5488 if (pageyes.length > 0) {';
5489 if ($postconfirmas == 'GET') {
5490 $formconfirm .= 'location.href = urljump;';
5491 } else {
5492 $formconfirm .= $jsforcursor;
5493 $formconfirm .= 'var post = $.post(
5494 pageyes,
5495 options,
5496 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5497 );';
5498 }
5499 $formconfirm .= '
5500 console.log("after post ok");
5501 }
5502 $(this).dialog("close");
5503 },
5504 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5505 var options = "token=' . urlencode(newToken()) . '";
5506 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5507 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5508 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5509 if (inputko.length > 0) {
5510 $.each(inputko, function(i, inputname) {
5511 var more = "";
5512 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5513 var inputvalue = $("#" + inputname + more).val();
5514 if (typeof inputvalue == "undefined") { inputvalue=""; }
5515 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5516 });
5517 }
5518 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5519 //alert(urljump);
5520 if (pageno.length > 0) {';
5521 if ($postconfirmas == 'GET') {
5522 $formconfirm .= 'location.href = urljump;';
5523 } else {
5524 $formconfirm .= $jsforcursor;
5525 $formconfirm .= 'var post = $.post(
5526 pageno,
5527 options,
5528 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5529 );';
5530 }
5531 $formconfirm .= '
5532 console.log("after post ko");
5533 }
5534 $(this).dialog("close");
5535 }
5536 }
5537 }
5538 );
5539
5540 var button = "' . $button . '";
5541 if (button.length > 0) {
5542 $( "#" + button ).click(function() {
5543 $("#' . $dialogconfirm . '").dialog("open");
5544 });
5545 }
5546 });
5547 });
5548 </script>';
5549 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5550 } else {
5551 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5552
5553 if (empty($disableformtag)) {
5554 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftroright">' . "\n";
5555 }
5556
5557 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5558 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5559
5560 $formconfirm .= '<table class="valid centpercent">' . "\n";
5561
5562 // Line title
5563 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5564 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5565 $formconfirm .= '</td></tr>' . "\n";
5566
5567 // Line text
5568 if (is_array($formquestion) && !empty($formquestion['text'])) {
5569 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5570 }
5571
5572 // Line form fields
5573 if ($more) {
5574 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5575 $formconfirm .= $more;
5576 $formconfirm .= '</td></tr>' . "\n";
5577 }
5578
5579 // Line with question
5580 $formconfirm .= '<tr class="valid">';
5581 $formconfirm .= '<td class="valid">' . $question . '</td>';
5582 $formconfirm .= '<td class="valid center">';
5583 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5584 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5585 $formconfirm .= '</td>';
5586 $formconfirm .= '</tr>' . "\n";
5587
5588 $formconfirm .= '</table>' . "\n";
5589
5590 if (empty($disableformtag)) {
5591 $formconfirm .= "</form>\n";
5592 }
5593 $formconfirm .= '<br>';
5594
5595 if (!empty($conf->use_javascript_ajax)) {
5596 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5597 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5598 $formconfirm .= '
5599 $(document).ready(function () {
5600 $(".confirmvalidatebutton").on("click", function() {
5601 console.log("We click on button confirmvalidatebutton");
5602 $(this).attr("disabled", "disabled");
5603 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5604 //console.log($(this).closest("form"));
5605 $(this).closest("form").submit();
5606 });
5607 });
5608 ';
5609 $formconfirm .= '</script>' . "\n";
5610 }
5611
5612 $formconfirm .= "<!-- end formconfirm -->\n";
5613 }
5614
5615 return $formconfirm;
5616 }
5617
5618
5619 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5620
5636 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5637 {
5638 // phpcs:enable
5639 global $langs;
5640
5641 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
5642 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
5643
5644 $out = '';
5645
5646 $formproject = new FormProjets($this->db);
5647
5648 $langs->load("project");
5649 if ($htmlname != "none") {
5650 $out .= '<form method="post" action="' . $page . '">';
5651 $out .= '<input type="hidden" name="action" value="classin">';
5652 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5653 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5654 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5655 $out .= '</form>';
5656 } else {
5657 $out .= '<span class="project_head_block">';
5658 if ($selected) {
5659 $projet = new Project($this->db);
5660 $projet->fetch($selected);
5661 $out .= $projet->getNomUrl(0, '', 1);
5662 } else {
5663 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
5664 }
5665 $out .= '</span>';
5666 }
5667
5668 if (empty($nooutput)) {
5669 print $out;
5670 return '';
5671 }
5672 return $out;
5673 }
5674
5675 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5676
5692 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5693 {
5694 // phpcs:enable
5695 global $langs;
5696
5697 $out = '';
5698
5699 if ($htmlname != "none") {
5700 $out .= '<form method="POST" action="' . $page . '">';
5701 $out .= '<input type="hidden" name="action" value="setconditions">';
5702 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5703 if ($type) {
5704 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5705 }
5706 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5707 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5708 $out .= '</form>';
5709 } else {
5710 if ($selected) {
5712 if (isset($this->cache_conditions_paiements[$selected])) {
5713 $label = $this->cache_conditions_paiements[$selected]['label'];
5714
5715 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5716 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5717 }
5718
5719 $out .= $label;
5720 } else {
5721 $langs->load('errors');
5722 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
5723 }
5724 } else {
5725 $out .= '&nbsp;';
5726 }
5727 }
5728
5729 if (empty($nooutput)) {
5730 print $out;
5731 return '';
5732 }
5733 return $out;
5734 }
5735
5736 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5737
5747 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5748 {
5749 // phpcs:enable
5750 global $langs;
5751 if ($htmlname != "none") {
5752 print '<form method="post" action="' . $page . '">';
5753 print '<input type="hidden" name="action" value="setavailability">';
5754 print '<input type="hidden" name="token" value="' . newToken() . '">';
5755 $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5756 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5757 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
5758 print '</form>';
5759 } else {
5760 if ($selected) {
5761 $this->load_cache_availability();
5762 print $this->cache_availability[$selected]['label'];
5763 } else {
5764 print "&nbsp;";
5765 }
5766 }
5767 }
5768
5779 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5780 {
5781 global $langs;
5782 if ($htmlname != "none") {
5783 print '<form method="post" action="' . $page . '">';
5784 print '<input type="hidden" name="action" value="setdemandreason">';
5785 print '<input type="hidden" name="token" value="' . newToken() . '">';
5786 $this->selectInputReason($selected, $htmlname, -1, $addempty);
5787 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5788 print '</form>';
5789 } else {
5790 if ($selected) {
5791 $this->loadCacheInputReason();
5792 foreach ($this->cache_demand_reason as $key => $val) {
5793 if ($val['id'] == $selected) {
5794 print $val['label'];
5795 break;
5796 }
5797 }
5798 } else {
5799 print "&nbsp;";
5800 }
5801 }
5802 }
5803
5804 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5805
5819 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
5820 {
5821 // phpcs:enable
5822 global $langs;
5823
5824 $ret = '';
5825
5826 if ($htmlname != "none") {
5827 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
5828 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
5829 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
5830 if ($type) {
5831 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5832 }
5833 $ret .= '<table class="nobordernopadding">';
5834 $ret .= '<tr><td>';
5835 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
5836 $ret .= '</td>';
5837 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
5838 $ret .= '</tr></table></form>';
5839 } else {
5840 if ($displayhour) {
5841 $ret .= dol_print_date($selected, 'dayhour');
5842 } else {
5843 $ret .= dol_print_date($selected, 'day');
5844 }
5845 }
5846
5847 if (empty($nooutput)) {
5848 print $ret;
5849 }
5850 return $ret;
5851 }
5852
5853
5854 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5855
5866 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
5867 {
5868 // phpcs:enable
5869 global $langs;
5870
5871 if ($htmlname != "none") {
5872 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
5873 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
5874 print '<input type="hidden" name="token" value="' . newToken() . '">';
5875 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
5876 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5877 print '</form>';
5878 } else {
5879 if ($selected) {
5880 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
5881 $theuser = new User($this->db);
5882 $theuser->fetch($selected);
5883 print $theuser->getNomUrl(1);
5884 } else {
5885 print "&nbsp;";
5886 }
5887 }
5888 }
5889
5890
5891 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5892
5906 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
5907 {
5908 // phpcs:enable
5909 global $langs;
5910
5911 $out = '';
5912 if ($htmlname != "none") {
5913 $out .= '<form method="POST" action="' . $page . '">';
5914 $out .= '<input type="hidden" name="action" value="setmode">';
5915 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5916 if ($type) {
5917 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5918 }
5919 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
5920 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5921 $out .= '</form>';
5922 } else {
5923 if ($selected) {
5925 $out .= $this->cache_types_paiements[$selected]['label'];
5926 } else {
5927 $out .= "&nbsp;";
5928 }
5929 }
5930
5931 if ($nooutput) {
5932 return $out;
5933 } else {
5934 print $out;
5935 }
5936 return '';
5937 }
5938
5949 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
5950 {
5951 global $langs;
5952 if ($htmlname != "none") {
5953 print '<form method="POST" action="' . $page . '">';
5954 print '<input type="hidden" name="action" value="settransportmode">';
5955 print '<input type="hidden" name="token" value="' . newToken() . '">';
5956 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
5957 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5958 print '</form>';
5959 } else {
5960 if ($selected) {
5962 print $this->cache_transport_mode[$selected]['label'];
5963 } else {
5964 print "&nbsp;";
5965 }
5966 }
5967 }
5968
5969 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5970
5979 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
5980 {
5981 // phpcs:enable
5982 global $langs;
5983 if ($htmlname != "none") {
5984 print '<form method="POST" action="' . $page . '">';
5985 print '<input type="hidden" name="action" value="setmulticurrencycode">';
5986 print '<input type="hidden" name="token" value="' . newToken() . '">';
5987 print $this->selectMultiCurrency($selected, $htmlname, 0);
5988 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5989 print '</form>';
5990 } else {
5991 dol_include_once('/core/lib/company.lib.php');
5992 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
5993 }
5994 }
5995
5996 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5997
6007 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6008 {
6009 // phpcs:enable
6010 global $langs, $mysoc, $conf;
6011
6012 if ($htmlname != "none") {
6013 print '<form method="POST" action="' . $page . '">';
6014 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6015 print '<input type="hidden" name="token" value="' . newToken() . '">';
6016 print '<input type="text" class="maxwidth100" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6017 print '<select name="calculation_mode">';
6018 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6019 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6020 print '</select> ';
6021 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6022 print '</form>';
6023 } else {
6024 if (!empty($rate)) {
6025 print price($rate, 1, $langs, 0, 0);
6026 if ($currency && $rate != 1) {
6027 print ' &nbsp; (' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')';
6028 }
6029 } else {
6030 print 1;
6031 }
6032 }
6033 }
6034
6035
6036 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6037
6053 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6054 {
6055 // phpcs:enable
6056 global $conf, $langs;
6057 if ($htmlname != "none") {
6058 print '<form method="post" action="' . $page . '">';
6059 print '<input type="hidden" name="action" value="setabsolutediscount">';
6060 print '<input type="hidden" name="token" value="' . newToken() . '">';
6061 print '<div class="inline-block">';
6062 if (!empty($discount_type)) {
6063 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6064 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6065 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
6066 } else {
6067 $translationKey = 'HasCreditNoteFromSupplier';
6068 }
6069 } else {
6070 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6071 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6072 } else {
6073 $translationKey = 'HasCreditNoteFromSupplier';
6074 }
6075 }
6076 } else {
6077 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6078 if (!$filter || $filter == "fk_facture_source IS NULL") {
6079 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
6080 } else {
6081 $translationKey = 'CompanyHasCreditNote';
6082 }
6083 } else {
6084 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6085 $translationKey = 'CompanyHasAbsoluteDiscount';
6086 } else {
6087 $translationKey = 'CompanyHasCreditNote';
6088 }
6089 }
6090 }
6091 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6092 if (empty($hidelist)) {
6093 print ' ';
6094 }
6095 print '</div>';
6096 if (empty($hidelist)) {
6097 print '<div class="inline-block" style="padding-right: 10px">';
6098 $newfilter = 'discount_type=' . intval($discount_type);
6099 if (!empty($discount_type)) {
6100 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6101 } else {
6102 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6103 }
6104 if ($filter) {
6105 $newfilter .= ' AND (' . $filter . ')';
6106 }
6107 // output the combo of discounts
6108 $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
6109 if ($nbqualifiedlines > 0) {
6110 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6111 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6112 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6113 }
6114 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6115 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6116 }
6117
6118 print '>';
6119 }
6120 print '</div>';
6121 }
6122 if ($more) {
6123 print '<div class="inline-block">';
6124 print $more;
6125 print '</div>';
6126 }
6127 print '</form>';
6128 } else {
6129 if ($selected) {
6130 print $selected;
6131 } else {
6132 print "0";
6133 }
6134 }
6135 }
6136
6137
6138 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6139
6149 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6150 {
6151 // phpcs:enable
6152 global $langs, $conf;
6153
6154 if ($htmlname != "none") {
6155 print '<form method="post" action="' . $page . '">';
6156 print '<input type="hidden" name="action" value="set_contact">';
6157 print '<input type="hidden" name="token" value="' . newToken() . '">';
6158 print '<table class="nobordernopadding">';
6159 print '<tr><td>';
6160 print $this->selectcontacts($societe->id, $selected, $htmlname);
6161 $num = $this->num;
6162 if ($num == 0) {
6163 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6164 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&amp;action=create&amp;backtoreferer=1">' . $addcontact . '</a>';
6165 }
6166 print '</td>';
6167 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6168 print '</tr></table></form>';
6169 } else {
6170 if ($selected) {
6171 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6172 $contact = new Contact($this->db);
6173 $contact->fetch($selected);
6174 print $contact->getFullName($langs);
6175 } else {
6176 print "&nbsp;";
6177 }
6178 }
6179 }
6180
6181 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6182
6199 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6200 {
6201 // phpcs:enable
6202 global $langs;
6203
6204 $out = '';
6205 if ($htmlname != "none") {
6206 $out .= '<form method="post" action="' . $page . '">';
6207 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6208 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6209 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6210 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6211 $out .= '</form>';
6212 } else {
6213 if ($selected) {
6214 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6215 $soc = new Societe($this->db);
6216 $soc->fetch($selected);
6217 $out .= $soc->getNomUrl(0, '');
6218 } else {
6219 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6220 }
6221 }
6222
6223 if ($nooutput) {
6224 return $out;
6225 } else {
6226 print $out;
6227 }
6228
6229 return '';
6230 }
6231
6232 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6233
6242 public function select_currency($selected = '', $htmlname = 'currency_id')
6243 {
6244 // phpcs:enable
6245 print $this->selectCurrency($selected, $htmlname);
6246 }
6247
6257 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6258 {
6259 global $conf, $langs, $user;
6260
6261 $langs->loadCacheCurrencies('');
6262
6263 $out = '';
6264
6265 if ($selected == 'euro' || $selected == 'euros') {
6266 $selected = 'EUR'; // Pour compatibilite
6267 }
6268
6269 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6270 if ($useempty) {
6271 $out .= '<option value="-1" selected></option>';
6272 }
6273 foreach ($langs->cache_currencies as $code_iso => $currency) {
6274 $labeltoshow = $currency['label'];
6275 if ($mode == 1) {
6276 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6277 } else {
6278 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6279 }
6280
6281 if ($selected && $selected == $code_iso) {
6282 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6283 } else {
6284 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6285 }
6286 $out .= $labeltoshow;
6287 $out .= '</option>';
6288 }
6289 $out .= '</select>';
6290 if ($user->admin) {
6291 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6292 }
6293
6294 // Make select dynamic
6295 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6296 $out .= ajax_combobox($htmlname);
6297
6298 return $out;
6299 }
6300
6313 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6314 {
6315 global $conf, $langs;
6316
6317 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6318
6319 $TCurrency = array();
6320
6321 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6322 $sql .= " WHERE entity IN ('" . getEntity('mutlicurrency') . "')";
6323 if ($filter) {
6324 $sql .= " AND " . $filter;
6325 }
6326 $resql = $this->db->query($sql);
6327 if ($resql) {
6328 while ($obj = $this->db->fetch_object($resql)) {
6329 $TCurrency[$obj->code] = $obj->code;
6330 }
6331 }
6332
6333 $out = '';
6334 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlnam