dolibarr  18.0.6
html.formproduct.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2008-2009 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2015-2017 Francis Appels <francis.appels@yahoo.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
24 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
25 
31 {
35  public $db;
36 
40  public $error = '';
41 
42  // Cache arrays
43  public $cache_warehouses = array();
44  public $cache_lot = array();
45  public $cache_workstations = array();
46 
47 
53  public function __construct($db)
54  {
55  $this->db = $db;
56  }
57 
58 
76  public function loadWarehouses($fk_product = 0, $batch = '', $status = '', $sumStock = true, $exclude = array(), $stockMin = false, $orderBy = 'e.ref')
77  {
78  global $conf, $langs;
79 
80  if (empty($fk_product) && count($this->cache_warehouses)) {
81  return 0; // Cache already loaded and we do not want a list with information specific to a product
82  }
83 
84  $warehouseStatus = array();
85 
86  if (preg_match('/warehouseclosed/', $status)) {
87  $warehouseStatus[] = Entrepot::STATUS_CLOSED;
88  }
89  if (preg_match('/warehouseopen/', $status)) {
90  $warehouseStatus[] = Entrepot::STATUS_OPEN_ALL;
91  }
92  if (preg_match('/warehouseinternal/', $status)) {
93  $warehouseStatus[] = Entrepot::STATUS_OPEN_INTERNAL;
94  }
95 
96  $sql = "SELECT e.rowid, e.ref as label, e.description, e.fk_parent";
97  if (!empty($fk_product) && $fk_product > 0) {
98  if (!empty($batch)) {
99  $sql .= ", pb.qty as stock";
100  } else {
101  $sql .= ", ps.reel as stock";
102  }
103  } elseif ($sumStock) {
104  $sql .= ", sum(ps.reel) as stock";
105  }
106  $sql .= " FROM ".$this->db->prefix()."entrepot as e";
107  $sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.fk_entrepot = e.rowid";
108  if (!empty($fk_product) && $fk_product > 0) {
109  $sql .= " AND ps.fk_product = ".((int) $fk_product);
110  if (!empty($batch)) {
111  $sql .= " LEFT JOIN ".$this->db->prefix()."product_batch as pb on pb.fk_product_stock = ps.rowid AND pb.batch = '".$this->db->escape($batch)."'";
112  }
113  }
114  $sql .= " WHERE e.entity IN (".getEntity('stock').")";
115  if (count($warehouseStatus)) {
116  $sql .= " AND e.statut IN (".$this->db->sanitize(implode(',', $warehouseStatus)).")";
117  } else {
118  $sql .= " AND e.statut = 1";
119  }
120 
121  if (is_array($exclude) && !empty($exclude)) {
122  $sql .= ' AND e.rowid NOT IN('.$this->db->sanitize(implode(',', $exclude)).')';
123  }
124 
125  // minimum stock
126  if ($stockMin !== false) {
127  if (!empty($fk_product) && $fk_product > 0) {
128  if (!empty($batch)) {
129  $sql .= " AND pb.qty > ".((float) $stockMin);
130  } else {
131  $sql .= " AND ps.reel > ".((float) $stockMin);
132  }
133  }
134  }
135 
136  if ($sumStock && empty($fk_product)) {
137  $sql .= " GROUP BY e.rowid, e.ref, e.description, e.fk_parent";
138 
139  // minimum stock
140  if ($stockMin !== false) {
141  $sql .= " HAVING sum(ps.reel) > ".((float) $stockMin);
142  }
143  }
144  $sql .= " ORDER BY ".$orderBy;
145 
146  dol_syslog(get_class($this).'::loadWarehouses', LOG_DEBUG);
147  $resql = $this->db->query($sql);
148  if ($resql) {
149  $num = $this->db->num_rows($resql);
150  $i = 0;
151  while ($i < $num) {
152  $obj = $this->db->fetch_object($resql);
153  if ($sumStock) {
154  $obj->stock = price2num($obj->stock, 5);
155  }
156  $this->cache_warehouses[$obj->rowid]['id'] = $obj->rowid;
157  $this->cache_warehouses[$obj->rowid]['label'] = $obj->label;
158  $this->cache_warehouses[$obj->rowid]['parent_id'] = $obj->fk_parent;
159  $this->cache_warehouses[$obj->rowid]['description'] = $obj->description;
160  $this->cache_warehouses[$obj->rowid]['stock'] = $obj->stock;
161  $i++;
162  }
163 
164  // Full label init
165  foreach ($this->cache_warehouses as $obj_rowid => $tab) {
166  $this->cache_warehouses[$obj_rowid]['full_label'] = $this->get_parent_path($tab);
167  }
168 
169  return $num;
170  } else {
171  dol_print_error($this->db);
172  return -1;
173  }
174  }
175 
186  public function loadWorkstations($fk_product = 0, $exclude = array(), $orderBy = 'w.ref')
187  {
188  global $conf, $langs;
189 
190  if (empty($fk_product) && count($this->cache_workstations)) {
191  return 0; // Cache already loaded and we do not want a list with information specific to a product
192  }
193 
194  $sql = "SELECT w.rowid, w.ref as ref, w.label as label, w.type, w.nb_operators_required,w.thm_operator_estimated,w.thm_machine_estimated";
195  $sql .= " FROM ".$this->db->prefix()."workstation_workstation as w";
196  $sql .= " WHERE 1 = 1";
197  if (!empty($fk_product) && $fk_product > 0) {
198  $sql .= " AND w.fk_product = ".((int) $fk_product);
199  }
200  $sql .= " AND w.entity IN (".getEntity('workstation').")";
201 
202  if (is_array($exclude) && !empty($exclude)) {
203  $sql .= ' AND w.rowid NOT IN('.$this->db->sanitize(implode(',', $exclude)).')';
204  }
205 
206  $sql .= " ORDER BY ".$orderBy;
207 
208  dol_syslog(get_class($this).'::loadWorkstations', LOG_DEBUG);
209  $resql = $this->db->query($sql);
210  if ($resql) {
211  $num = $this->db->num_rows($resql);
212  $i = 0;
213  while ($i < $num) {
214  $obj = $this->db->fetch_object($resql);
215 
216  $this->cache_workstations[$obj->rowid]['id'] = $obj->rowid;
217  $this->cache_workstations[$obj->rowid]['ref'] = $obj->ref;
218  $this->cache_workstations[$obj->rowid]['label'] = $obj->label;
219  $this->cache_workstations[$obj->rowid]['type'] = $obj->type;
220  $this->cache_workstations[$obj->rowid]['nb_operators_required'] = $obj->nb_operators_required;
221  $this->cache_workstations[$obj->rowid]['thm_operator_estimated'] = $obj->thm_operator_estimated;
222  $this->cache_workstations[$obj->rowid]['thm_machine_estimated'] = $obj->thm_machine_estimated;
223  $i++;
224  }
225 
226  return $num;
227  } else {
228  dol_print_error($this->db);
229  return -1;
230  }
231  }
232 
233  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
241  private function get_parent_path($tab, $final_label = '')
242  {
243  //phpcs:enable
244  if (empty($final_label)) {
245  $final_label = $tab['label'];
246  }
247 
248  if (empty($tab['parent_id'])) {
249  return $final_label;
250  } else {
251  if (!empty($this->cache_warehouses[$tab['parent_id']])) {
252  $final_label = $this->cache_warehouses[$tab['parent_id']]['label'].' >> '.$final_label;
253  return $this->get_parent_path($this->cache_warehouses[$tab['parent_id']], $final_label);
254  }
255  }
256 
257  return $final_label;
258  }
259 
286  public function selectWarehouses($selected = '', $htmlname = 'idwarehouse', $filterstatus = '', $empty = 0, $disabled = 0, $fk_product = 0, $empty_label = '', $showstock = 0, $forcecombo = 0, $events = array(), $morecss = 'minwidth200', $exclude = array(), $showfullpath = 1, $stockMin = false, $orderBy = 'e.ref', $multiselect = 0)
287  {
288  global $conf, $langs, $user, $hookmanager;
289 
290  dol_syslog(get_class($this)."::selectWarehouses $selected, $htmlname, $filterstatus, $empty, $disabled, $fk_product, $empty_label, $showstock, $forcecombo, $morecss", LOG_DEBUG);
291 
292  $out = '';
293  if (empty($conf->global->ENTREPOT_EXTRA_STATUS)) {
294  $filterstatus = '';
295  }
296  if (!empty($fk_product) && $fk_product > 0) {
297  $this->cache_warehouses = array();
298  }
299 
300  $this->loadWarehouses($fk_product, '', $filterstatus, true, $exclude, $stockMin, $orderBy);
301  $nbofwarehouses = count($this->cache_warehouses);
302 
303  if ($conf->use_javascript_ajax && !$forcecombo) {
304  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
305  $comboenhancement = ajax_combobox($htmlname, $events);
306  $out .= $comboenhancement;
307  }
308 
309  if (strpos($htmlname, 'search_') !== 0) {
310  if (empty($user->fk_warehouse) || $user->fk_warehouse == -1) {
311  if (is_scalar($selected) && ($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE)) {
312  $selected = $conf->global->MAIN_DEFAULT_WAREHOUSE;
313  }
314  } else {
315  if (is_scalar($selected) && ($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WAREHOUSE_USER)) {
316  $selected = $user->fk_warehouse;
317  }
318  }
319  }
320 
321  $out .= '<select '.($multiselect ? 'multiple ' : '').'class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled' : '');
322  $out .= ' id="'.$htmlname.'" name="'.($htmlname.($multiselect?'[]':'').($disabled ? '_disabled' : '')).'"';
323  //$out .= ' placeholder="todo"'; // placeholder for select2 must be added by setting the id+placeholder js param when calling select2
324  $out .= '>';
325  if ($empty) {
326  $out .= '<option value="-1">'.($empty_label ? $empty_label : '&nbsp;').'</option>';
327  }
328  foreach ($this->cache_warehouses as $id => $arraytypes) {
329  $label = '';
330  if ($showfullpath) {
331  $label .= $arraytypes['full_label'];
332  } else {
333  $label .= $arraytypes['label'];
334  }
335  if (($fk_product || ($showstock > 0)) && ($arraytypes['stock'] != 0 || ($showstock > 0))) {
336  if ($arraytypes['stock'] <= 0) {
337  $label .= ' <span class="text-warning">('.$langs->trans("Stock").':'.$arraytypes['stock'].')</span>';
338  } else {
339  $label .= ' <span class="opacitymedium">('.$langs->trans("Stock").':'.$arraytypes['stock'].')</span>';
340  }
341  }
342 
343  $out .= '<option value="'.$id.'"';
344  if (is_array($selected)) {
345  if (in_array($id, $selected)) {
346  $out .= ' selected';
347  }
348  } else {
349  if ($selected == $id || (preg_match('/^ifone/', $selected) && $nbofwarehouses == 1)) {
350  $out .= ' selected';
351  }
352  }
353  $out .= ' data-html="'.dol_escape_htmltag($label).'"';
354  $out .= '>';
355  $out .= $label;
356  $out .= '</option>';
357  }
358  $out .= '</select>';
359  if ($disabled) {
360  $out .= '<input type="hidden" name="'.$htmlname.'" value="'.(($selected > 0) ? $selected : '').'">';
361  }
362 
363  $parameters = array(
364  'selected' => $selected,
365  'htmlname' => $htmlname,
366  'filterstatus' => $filterstatus,
367  'empty' => $empty,
368  'disabled ' => $disabled,
369  'fk_product' => $fk_product,
370  'empty_label' => $empty_label,
371  'showstock' => $showstock,
372  'forcecombo' => $forcecombo,
373  'events' => $events,
374  'morecss' => $morecss,
375  'exclude' => $exclude,
376  'showfullpath' => $showfullpath,
377  'stockMin' => $stockMin,
378  'orderBy' => $orderBy
379  );
380 
381  $reshook = $hookmanager->executeHooks('selectWarehouses', $parameters, $this);
382  if ($reshook > 0) {
383  $out = $hookmanager->resPrint;
384  } elseif ($reshook == 0) {
385  $out .= $hookmanager->resPrint;
386  }
387 
388  return $out;
389  }
390 
410  public function selectWorkstations($selected = '', $htmlname = 'idworkstations', $empty = 0, $disabled = 0, $fk_product = 0, $empty_label = '', $forcecombo = 0, $events = array(), $morecss = 'minwidth200', $exclude = array(), $showfullpath = 1, $orderBy = 'e.ref')
411  {
412  global $conf, $langs, $user, $hookmanager;
413 
414  dol_syslog(get_class($this)."::selectWorkstations $selected, $htmlname, $empty, $disabled, $fk_product, $empty_label, $forcecombo, $morecss", LOG_DEBUG);
415 
416  $filterstatus='';
417  $out = '';
418  if (!empty($fk_product) && $fk_product > 0) {
419  $this->cache_workstations = array();
420  }
421 
422  $this->loadWorkstations($fk_product);
423  $nbofworkstations = count($this->cache_workstations);
424 
425  if ($conf->use_javascript_ajax && !$forcecombo) {
426  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
427  $comboenhancement = ajax_combobox($htmlname, $events);
428  $out .= $comboenhancement;
429  }
430 
431  if (strpos($htmlname, 'search_') !== 0) {
432  if (empty($user->fk_workstation) || $user->fk_workstation == -1) {
433  if (($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WORKSTATION)) {
434  $selected = $conf->global->MAIN_DEFAULT_WORKSTATION;
435  }
436  } else {
437  if (($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WORKSTATION)) {
438  $selected = $user->fk_workstation;
439  }
440  }
441  }
442 
443  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled' : '').' id="'.$htmlname.'" name="'.($htmlname.($disabled ? '_disabled' : '')).'">';
444  if ($empty) {
445  $out .= '<option value="-1">'.($empty_label ? $empty_label : '&nbsp;').'</option>';
446  }
447  foreach ($this->cache_workstations as $id => $arraytypes) {
448  $label = $arraytypes['label'];
449 
450  $out .= '<option value="'.$id.'"';
451  if ($selected == $id || (preg_match('/^ifone/', $selected) && $nbofworkstations == 1)) {
452  $out .= ' selected';
453  }
454  $out .= ' data-html="'.dol_escape_htmltag($label).'"';
455  $out .= '>';
456  $out .= $label;
457  $out .= '</option>';
458  }
459  $out .= '</select>';
460  if ($disabled) {
461  $out .= '<input type="hidden" name="'.$htmlname.'" value="'.(($selected > 0) ? $selected : '').'">';
462  }
463 
464  $parameters = array(
465  'selected' => $selected,
466  'htmlname' => $htmlname,
467  'filterstatus' => $filterstatus,
468  'empty' => $empty,
469  'disabled ' => $disabled,
470  'fk_product' => $fk_product,
471  'empty_label' => $empty_label,
472  'forcecombo' => $forcecombo,
473  'events' => $events,
474  'morecss' => $morecss,
475  'exclude' => $exclude,
476  'showfullpath' => $showfullpath,
477  'orderBy' => $orderBy
478  );
479 
480  $reshook = $hookmanager->executeHooks('selectWorkstations', $parameters, $this);
481  if ($reshook > 0) {
482  $out = $hookmanager->resPrint;
483  } elseif ($reshook == 0) {
484  $out .= $hookmanager->resPrint;
485  }
486 
487  return $out;
488  }
489 
499  public function formSelectWarehouses($page, $selected = '', $htmlname = 'warehouse_id', $addempty = 0)
500  {
501  global $langs;
502  if ($htmlname != "none") {
503  print '<form method="POST" action="'.$page.'">';
504  print '<input type="hidden" name="action" value="setwarehouse">';
505  print '<input type="hidden" name="token" value="'.newToken().'">';
506  print '<table class="nobordernopadding">';
507  print '<tr><td>';
508  print $this->selectWarehouses($selected, $htmlname, '', $addempty);
509  print '</td>';
510  print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
511  print '</tr></table></form>';
512  } else {
513  if ($selected) {
514  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
515  $warehousestatic = new Entrepot($this->db);
516  $warehousestatic->fetch($selected);
517  print $warehousestatic->getNomUrl();
518  } else {
519  print "&nbsp;";
520  }
521  }
522  }
523 
524  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
537  public function select_measuring_units($name = 'measuring_units', $measuring_style = '', $default = '0', $adddefault = 0, $mode = 0)
538  {
539  //phpcs:enable
540  print $this->selectMeasuringUnits($name, $measuring_style, $default, $adddefault, $mode);
541  }
542 
555  public function selectMeasuringUnits($name = 'measuring_units', $measuring_style = '', $default = '0', $adddefault = 0, $mode = 0, $morecss = 'maxwidth125')
556  {
557  global $langs, $conf, $mysoc, $db;
558 
559  $langs->load("other");
560 
561  $return = '';
562 
563  // TODO Use a cache
564  require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
565  $measuringUnits = new CUnits($db);
566 
567  $filter = array();
568  $filter['t.active'] = 1;
569  if ($measuring_style) {
570  $filter['t.unit_type'] = $measuring_style;
571  }
572 
573  $result = $measuringUnits->fetchAll(
574  '',
575  '',
576  0,
577  0,
578  $filter
579  );
580  if ($result < 0) {
581  dol_print_error($db);
582  return -1;
583  } else {
584  $return .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$name.'" id="'.$name.'">';
585  if ($adddefault || $adddefault === '') {
586  $return .= '<option value="0">'.($adddefault ? $langs->trans("Default") : '').'</option>';
587  }
588 
589  foreach ($measuringUnits->records as $lines) {
590  $return .= '<option value="';
591  if ($mode == 1) {
592  $return .= $lines->short_label;
593  } elseif ($mode == 2) {
594  $return .= $lines->scale;
595  } else {
596  $return .= $lines->id;
597  }
598  $return .= '"';
599  if ($mode == 1 && $lines->short_label == $default) {
600  $return .= ' selected';
601  } elseif ($mode == 2 && $lines->scale == $default) {
602  $return .= ' selected';
603  } elseif ($mode == 0 && $lines->id == $default) {
604  $return .= ' selected';
605  }
606  $return .= '>';
607  if ($measuring_style == 'time') {
608  $return .= $langs->trans(ucfirst($lines->label));
609  } else {
610  $return .= $langs->trans($lines->label);
611  }
612  $return .= '</option>';
613  }
614  $return .= '</select>';
615  }
616 
617  $return .= ajax_combobox($name);
618 
619  return $return;
620  }
621 
632  public function selectProductNature($name = 'finished', $selected = '', $mode = 0, $showempty = 1)
633  {
634  global $langs, $db;
635 
636  $langs->load('products');
637 
638  $return = '';
639 
640  // TODO Use a cache
641  require_once DOL_DOCUMENT_ROOT.'/core/class/cproductnature.class.php';
642  $productNature = new CProductNature($db);
643 
644  $filter = array();
645  $filter['t.active'] = 1;
646 
647  $result = $productNature->fetchAll('', '', 0, 0, $filter);
648 
649  if ($result < 0) {
650  dol_print_error($db);
651  return -1;
652  } else {
653  $return .= '<select class="flat" name="'.$name.'" id="'.$name.'">';
654  if ($showempty || ($selected == '' || $selected == '-1')) {
655  $return .= '<option value="-1"';
656  if ($selected == '' || $selected == '-1') {
657  $return .= ' selected';
658  }
659  $return .= '></option>';
660  }
661  if (!empty($productNature->records) && is_array($productNature->records)) {
662  foreach ($productNature->records as $lines) {
663  $return .= '<option value="';
664  if ($mode == 1) {
665  $return .= $lines->label;
666  } else {
667  $return .= $lines->code;
668  }
669 
670  $return .= '"';
671 
672  if ($mode == 1 && $lines->label == $selected) {
673  $return .= ' selected';
674  } elseif ($lines->code == $selected) {
675  $return .= ' selected';
676  }
677 
678  $return .= '>';
679  $return .= $langs->trans($lines->label);
680  $return .= '</option>';
681  }
682  }
683  $return .= '</select>';
684  }
685 
686  $return .= ajax_combobox($name);
687 
688  return $return;
689  }
690 
709  public function selectLotStock($selected = '', $htmlname = 'batch_id', $filterstatus = '', $empty = 0, $disabled = 0, $fk_product = 0, $fk_entrepot = 0, $objectLines = array(), $empty_label = '', $forcecombo = 0, $events = array(), $morecss = 'minwidth200')
710  {
711  global $conf, $langs;
712 
713  dol_syslog(get_class($this)."::selectLotStock $selected, $htmlname, $filterstatus, $empty, $disabled, $fk_product, $fk_entrepot, $empty_label, $forcecombo, $morecss", LOG_DEBUG);
714 
715  $out = '';
716  $productIdArray = array();
717  if (!is_array($objectLines) || !count($objectLines)) {
718  if (!empty($fk_product) && $fk_product > 0) {
719  $productIdArray[] = (int) $fk_product;
720  }
721  } else {
722  foreach ($objectLines as $line) {
723  if ($line->fk_product) {
724  $productIdArray[] = $line->fk_product;
725  }
726  }
727  }
728 
729  $nboflot = $this->loadLotStock($productIdArray);
730 
731  if ($conf->use_javascript_ajax && !$forcecombo) {
732  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
733  $comboenhancement = ajax_combobox($htmlname, $events);
734  $out .= $comboenhancement;
735  }
736 
737  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled' : '').' id="'.$htmlname.'" name="'.($htmlname.($disabled ? '_disabled' : '')).'">';
738  if ($empty) {
739  $out .= '<option value="-1">'.($empty_label ? $empty_label : '&nbsp;').'</option>';
740  }
741  if (!empty($fk_product) && $fk_product > 0) {
742  $productIdArray = array((int) $fk_product); // only show lot stock for product
743  } else {
744  foreach ($this->cache_lot as $key => $value) {
745  $productIdArray[] = $key;
746  }
747  }
748 
749  foreach ($productIdArray as $productId) {
750  foreach ($this->cache_lot[$productId] as $id => $arraytypes) {
751  if (empty($fk_entrepot) || $fk_entrepot == $arraytypes['entrepot_id']) {
752  $label = $arraytypes['entrepot_label'].' - ';
753  $label .= $arraytypes['batch'];
754  if ($arraytypes['qty'] <= 0) {
755  $label .= ' <span class=\'text-warning\'>('.$langs->trans("Stock").' '.$arraytypes['qty'].')</span>';
756  } else {
757  $label .= ' <span class=\'opacitymedium\'>('.$langs->trans("Stock").' '.$arraytypes['qty'].')</span>';
758  }
759 
760  $out .= '<option value="'.$id.'"';
761 
762  if ($selected == $id || ($selected == 'ifone' && $nboflot == 1)) {
763  $out .= ' selected';
764  }
765  $out .= ' data-html="'.dol_escape_htmltag($label).'"';
766  $out .= '>';
767  $out .= $label;
768  $out .= '</option>';
769  }
770  }
771  }
772  $out .= '</select>';
773  if ($disabled) {
774  $out .= '<input type="hidden" name="'.$htmlname.'" value="'.(($selected > 0) ? $selected : '').'">';
775  }
776 
777  return $out;
778  }
779 
780 
781 
792  public function selectLotDataList($htmlname = 'batch_id', $empty = 0, $fk_product = 0, $fk_entrepot = 0, $objectLines = array())
793  {
794  global $langs;
795 
796  dol_syslog(get_class($this)."::selectLotDataList $htmlname, $empty, $fk_product, $fk_entrepot", LOG_DEBUG);
797 
798  $out = '';
799  $productIdArray = array();
800  if (!is_array($objectLines) || !count($objectLines)) {
801  if (!empty($fk_product) && $fk_product > 0) {
802  $productIdArray[] = (int) $fk_product;
803  }
804  } else {
805  foreach ($objectLines as $line) {
806  if ($line->fk_product) {
807  $productIdArray[] = $line->fk_product;
808  }
809  }
810  }
811 
812  $nboflot = $this->loadLotStock($productIdArray);
813 
814  $out .= '<datalist id="'.$htmlname.'" >';
815 
816  if (!empty($fk_product) && $fk_product > 0) {
817  $productIdArray = array((int) $fk_product); // only show lot stock for product
818  } else {
819  foreach ($this->cache_lot as $key => $value) {
820  $productIdArray[] = $key;
821  }
822  }
823 
824  foreach ($productIdArray as $productId) {
825  if (array_key_exists($productId, $this->cache_lot)) {
826  foreach ($this->cache_lot[$productId] as $id => $arraytypes) {
827  if (empty($fk_entrepot) || $fk_entrepot == $arraytypes['entrepot_id']) {
828  $label = $arraytypes['entrepot_label'] . ' - ';
829  $label .= $arraytypes['batch'];
830  $out .= '<option data-warehouse="'.dol_escape_htmltag($label).'" value="' . $arraytypes['batch'] . '">(' . $langs->trans('Stock Total') . ': ' . $arraytypes['qty'] . ')</option>';
831  }
832  }
833  }
834  }
835  $out .= '</datalist>';
836 
837  return $out;
838  }
839 
840 
848  private function loadLotStock($productIdArray = array())
849  {
850  global $conf, $langs;
851 
852  $cacheLoaded = false;
853  if (empty($productIdArray)) {
854  // only Load lot stock for given products
855  $this->cache_lot = array();
856  return 0;
857  }
858  if (count($productIdArray) && count($this->cache_lot)) {
859  // check cache already loaded for product id's
860  foreach ($productIdArray as $productId) {
861  $cacheLoaded = !empty($this->cache_lot[$productId]) ? true : false;
862  }
863  }
864  if ($cacheLoaded) {
865  return count($this->cache_lot);
866  } else {
867  // clear cache
868  $this->cache_lot = array();
869  $productIdList = implode(',', $productIdArray);
870 
871  $batch_count = 0;
872  global $hookmanager;
873  if (empty($hookmanager)) {
874  include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
875  $hookmanager = new HookManager($this->db);
876  }
877  $hookmanager->initHooks(array('productdao'));
878  $parameters = array('productIdList' => $productIdList);
879  $reshook = $hookmanager->executeHooks('loadLotStock', $parameters, $this);
880  if ($reshook < 0) {
881  $this->error = $hookmanager->error;
882  return -1;
883  }
884  if (!empty($hookmanager->resArray['batch_list']) && is_array($hookmanager->resArray['batch_list'])) {
885  $this->cache_lot = $hookmanager->resArray['batch_list'];
886  $batch_count = (int) $hookmanager->resArray['batch_count'];
887  }
888  if ($reshook > 0) {
889  return $batch_count;
890  }
891 
892  $sql = "SELECT pb.batch, pb.rowid, ps.fk_entrepot, pb.qty, e.ref as label, ps.fk_product";
893  $sql .= " FROM ".$this->db->prefix()."product_batch as pb";
894  $sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.rowid = pb.fk_product_stock";
895  $sql .= " LEFT JOIN ".$this->db->prefix()."entrepot as e on e.rowid = ps.fk_entrepot AND e.entity IN (".getEntity('stock').")";
896  if (!empty($productIdList)) {
897  $sql .= " WHERE ps.fk_product IN (".$this->db->sanitize($productIdList).")";
898  }
899  $sql .= " ORDER BY e.ref, pb.batch";
900 
901  dol_syslog(get_class($this).'::loadLotStock', LOG_DEBUG);
902  $resql = $this->db->query($sql);
903  if ($resql) {
904  $num = $this->db->num_rows($resql);
905  $i = 0;
906  while ($i < $num) {
907  $obj = $this->db->fetch_object($resql);
908  $this->cache_lot[$obj->fk_product][$obj->rowid]['id'] = $obj->rowid;
909  $this->cache_lot[$obj->fk_product][$obj->rowid]['batch'] = $obj->batch;
910  $this->cache_lot[$obj->fk_product][$obj->rowid]['entrepot_id'] = $obj->fk_entrepot;
911  $this->cache_lot[$obj->fk_product][$obj->rowid]['entrepot_label'] = $obj->label;
912  $this->cache_lot[$obj->fk_product][$obj->rowid]['qty'] = $obj->qty;
913  $i++;
914  }
915 
916  return $batch_count + $num;
917  } else {
918  dol_print_error($this->db);
919  return -1;
920  }
921  }
922  }
923 }
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:449
Class of dictionary of nature of product (used by imports)
Class of dictionary type of thirdparty (used by imports)
Class to manage warehouses.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class with static methods for building HTML components related to products Only components common to ...
selectWarehouses($selected='', $htmlname='idwarehouse', $filterstatus='', $empty=0, $disabled=0, $fk_product=0, $empty_label='', $showstock=0, $forcecombo=0, $events=array(), $morecss='minwidth200', $exclude=array(), $showfullpath=1, $stockMin=false, $orderBy='e.ref', $multiselect=0)
Return list of warehouses.
loadWorkstations($fk_product=0, $exclude=array(), $orderBy='w.ref')
Load in cache array list of workstations If fk_product is not 0, we do not use cache.
selectWorkstations($selected='', $htmlname='idworkstations', $empty=0, $disabled=0, $fk_product=0, $empty_label='', $forcecombo=0, $events=array(), $morecss='minwidth200', $exclude=array(), $showfullpath=1, $orderBy='e.ref')
Return list of workstations.
selectLotDataList($htmlname='batch_id', $empty=0, $fk_product=0, $fk_entrepot=0, $objectLines=array())
Return list of lot numbers (stock from product_batch) for product and warehouse.
selectProductNature($name='finished', $selected='', $mode=0, $showempty=1)
Return a combo box with list of units NAture of product labels are defined in llx_c_product_nature.
selectLotStock($selected='', $htmlname='batch_id', $filterstatus='', $empty=0, $disabled=0, $fk_product=0, $fk_entrepot=0, $objectLines=array(), $empty_label='', $forcecombo=0, $events=array(), $morecss='minwidth200')
Return list of lot numbers (stock from product_batch) with stock location and stock qty.
selectMeasuringUnits($name='measuring_units', $measuring_style='', $default='0', $adddefault=0, $mode=0, $morecss='maxwidth125')
Return a combo box with list of units Units labels are defined in llx_c_units.
loadLotStock($productIdArray=array())
Load in cache array list of lot available in stock from a given list of products.
select_measuring_units($name='measuring_units', $measuring_style='', $default='0', $adddefault=0, $mode=0)
Output a combo box with list of units pour l'instant on ne definit pas les unites dans la base.
get_parent_path($tab, $final_label='')
Return full path to current warehouse in $tab (recursive function)
formSelectWarehouses($page, $selected='', $htmlname='warehouse_id', $addempty=0)
Display form to select warehouse.
__construct($db)
Constructor.
loadWarehouses($fk_product=0, $batch='', $status='', $sumStock=true, $exclude=array(), $stockMin=false, $orderBy='e.ref')
Load in cache array list of warehouses If fk_product is not 0, we do not use cache.
Class to manage hooks.
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
if(!defined( 'CSRFCHECK_WITH_TOKEN'))