dolibarr  9.0.0
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 <http://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  var $cache_warehouses=array();
44  var $cache_lot=array();
45 
46 
52  function __construct($db)
53  {
54  $this->db = $db;
55  }
56 
57 
72  function loadWarehouses($fk_product=0, $batch = '', $status='', $sumStock = true, $exclude='')
73  {
74  global $conf, $langs;
75 
76  if (empty($fk_product) && count($this->cache_warehouses)) return 0; // Cache already loaded and we do not want a list with information specific to a product
77 
78  if (is_array($exclude)) $excludeGroups = implode("','",$exclude);
79 
80  $warehouseStatus = array();
81 
82  if (preg_match('/warehouseclosed/', $status))
83  {
84  $warehouseStatus[] = Entrepot::STATUS_CLOSED;
85  }
86  if (preg_match('/warehouseopen/', $status))
87  {
88  $warehouseStatus[] = Entrepot::STATUS_OPEN_ALL;
89  }
90  if (preg_match('/warehouseinternal/', $status))
91  {
92  $warehouseStatus[] = Entrepot::STATUS_OPEN_INTERNAL;
93  }
94 
95  $sql = "SELECT e.rowid, e.ref as label, e.description, e.fk_parent";
96  if (!empty($fk_product))
97  {
98  if (!empty($batch))
99  {
100  $sql.= ", pb.qty as stock";
101  }
102  else
103  {
104  $sql.= ", ps.reel as stock";
105  }
106  }
107  else if ($sumStock)
108  {
109  $sql.= ", sum(ps.reel) as stock";
110  }
111  $sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e";
112  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_entrepot = e.rowid";
113  if (!empty($fk_product))
114  {
115  $sql.= " AND ps.fk_product = '".$fk_product."'";
116  if (!empty($batch))
117  {
118  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_batch as pb on pb.fk_product_stock = ps.rowid AND pb.batch = '".$batch."'";
119  }
120  }
121  $sql.= " WHERE e.entity IN (".getEntity('stock').")";
122  if (count($warehouseStatus))
123  {
124  $sql.= " AND e.statut IN (".$this->db->escape(implode(',',$warehouseStatus)).")";
125  }
126  else
127  {
128  $sql.= " AND e.statut = 1";
129  }
130 
131  if(!empty($exclude)) $sql.= ' AND e.rowid NOT IN('.$this->db->escape(implode(',', $exclude)).')';
132 
133  if ($sumStock && empty($fk_product)) $sql.= " GROUP BY e.rowid, e.ref, e.description, e.fk_parent";
134  $sql.= " ORDER BY e.ref";
135 
136  dol_syslog(get_class($this).'::loadWarehouses', LOG_DEBUG);
137  $resql = $this->db->query($sql);
138  if ($resql)
139  {
140  $num = $this->db->num_rows($resql);
141  $i = 0;
142  while ($i < $num)
143  {
144  $obj = $this->db->fetch_object($resql);
145  if ($sumStock) $obj->stock = price2num($obj->stock,5);
146  $this->cache_warehouses[$obj->rowid]['id'] =$obj->rowid;
147  $this->cache_warehouses[$obj->rowid]['label']=$obj->label;
148  $this->cache_warehouses[$obj->rowid]['parent_id']=$obj->fk_parent;
149  $this->cache_warehouses[$obj->rowid]['description'] = $obj->description;
150  $this->cache_warehouses[$obj->rowid]['stock'] = $obj->stock;
151  $i++;
152  }
153 
154  // Full label init
155  foreach($this->cache_warehouses as $obj_rowid=>$tab) {
156  $this->cache_warehouses[$obj_rowid]['full_label'] = $this->get_parent_path($tab);
157  }
158 
159  return $num;
160  }
161  else
162  {
163  dol_print_error($this->db);
164  return -1;
165  }
166  }
167 
168  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
176  private function get_parent_path($tab, $final_label='')
177  {
178  //phpcs:enable
179  if(empty($final_label)) $final_label = $tab['label'];
180 
181  if(empty($tab['parent_id'])) return $final_label;
182  else {
183  if(!empty($this->cache_warehouses[$tab['parent_id']])) {
184  $final_label = $this->cache_warehouses[$tab['parent_id']]['label'].' >> '.$final_label;
185  return $this->get_parent_path($this->cache_warehouses[$tab['parent_id']], $final_label);
186  }
187  }
188 
189  return $final_label;
190  }
191 
213  function selectWarehouses($selected='',$htmlname='idwarehouse',$filterstatus='',$empty=0,$disabled=0,$fk_product=0,$empty_label='', $showstock=0, $forcecombo=0, $events=array(), $morecss='minwidth200', $exclude='', $showfullpath=1)
214  {
215  global $conf,$langs,$user;
216 
217  dol_syslog(get_class($this)."::selectWarehouses $selected, $htmlname, $filterstatus, $empty, $disabled, $fk_product, $empty_label, $showstock, $forcecombo, $morecss",LOG_DEBUG);
218 
219  $out='';
220  if (empty($conf->global->ENTREPOT_EXTRA_STATUS)) $filterstatus = '';
221  $this->loadWarehouses($fk_product, '', $filterstatus, true, $exclude);
222  $nbofwarehouses=count($this->cache_warehouses);
223 
224  if ($conf->use_javascript_ajax && ! $forcecombo)
225  {
226  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
227  $comboenhancement = ajax_combobox($htmlname, $events);
228  $out.= $comboenhancement;
229  }
230 
231  $out.='<select class="flat'.($morecss?' '.$morecss:'').'"'.($disabled?' disabled':'').' id="'.$htmlname.'" name="'.($htmlname.($disabled?'_disabled':'')).'">';
232  if ($empty) $out.='<option value="-1">'.($empty_label?$empty_label:'&nbsp;').'</option>';
233  foreach($this->cache_warehouses as $id => $arraytypes)
234  {
235  $out.='<option value="'.$id.'"';
236  if ($selected == $id || ($selected == 'ifone' && $nbofwarehouses == 1)) $out.=' selected';
237  $out.='>';
238  if ($showfullpath) $out.=$arraytypes['full_label'];
239  else $out.=$arraytypes['label'];
240  if (($fk_product || ($showstock > 0)) && ($arraytypes['stock'] != 0 || ($showstock > 0))) $out.=' ('.$langs->trans("Stock").':'.$arraytypes['stock'].')';
241  $out.='</option>';
242  }
243  $out.='</select>';
244  if ($disabled) $out.='<input type="hidden" name="'.$htmlname.'" value="'.(($selected>0)?$selected:'').'">';
245 
246  return $out;
247  }
248 
258  function formSelectWarehouses($page, $selected='', $htmlname='warehouse_id', $addempty=0)
259  {
260  global $langs;
261  if ($htmlname != "none") {
262  print '<form method="POST" action="'.$page.'">';
263  print '<input type="hidden" name="action" value="setwarehouse">';
264  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
265  print '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
266  print '<tr><td>';
267  print $this->selectWarehouses($selected, $htmlname, '', $addempty);
268  print '</td>';
269  print '<td align="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
270  print '</tr></table></form>';
271  } else {
272  if ($selected) {
273  require_once DOL_DOCUMENT_ROOT .'/product/stock/class/entrepot.class.php';
274  $warehousestatic=new Entrepot($this->db);
275  $warehousestatic->fetch($selected);
276  print $warehousestatic->getNomUrl();
277  } else {
278  print "&nbsp;";
279  }
280  }
281  }
282 
283  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
294  function select_measuring_units($name='measuring_units', $measuring_style='', $default='0', $adddefault=0)
295  {
296  //phpcs:enable
297  print $this->load_measuring_units($name, $measuring_style, $default, $adddefault);
298  }
299 
300  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
311  function load_measuring_units($name='measuring_units', $measuring_style='', $default='0', $adddefault=0)
312  {
313  //phpcs:enable
314  global $langs,$conf,$mysoc;
315  $langs->load("other");
316 
317  $return='';
318 
319  $measuring_units=array();
320  if ($measuring_style == 'weight') $measuring_units=array(-6=>1,-3=>1,0=>1,3=>1,98=>1,99=>1);
321  else if ($measuring_style == 'size') $measuring_units=array(-3=>1,-2=>1,-1=>1,0=>1,98=>1,99=>1);
322  else if ($measuring_style == 'surface') $measuring_units=array(-6=>1,-4=>1,-2=>1,0=>1,98=>1,99=>1);
323  else if ($measuring_style == 'volume') $measuring_units=array(-9=>1,-6=>1,-3=>1,0=>1,88=>1,89=>1,97=>1,99=>1,/* 98=>1 */); // Liter is not used as already available with dm3
324 
325  $return.= '<select class="flat" name="'.$name.'">';
326  if ($adddefault) $return.= '<option value="0">'.$langs->trans("Default").'</option>';
327 
328  foreach ($measuring_units as $key => $value)
329  {
330  $return.= '<option value="'.$key.'"';
331  if ($key == $default)
332  {
333  $return.= ' selected';
334  }
335  //$return.= '>'.$value.'</option>';
336  $return.= '>'.measuring_units_string($key,$measuring_style).'</option>';
337  }
338  $return.= '</select>';
339 
340  return $return;
341  }
342 
361  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')
362  {
363  global $langs;
364 
365  dol_syslog(get_class($this)."::selectLot $selected, $htmlname, $filterstatus, $empty, $disabled, $fk_product, $fk_entrepot, $empty_label, $showstock, $forcecombo, $morecss",LOG_DEBUG);
366 
367  $out='';
368  $productIdArray = array();
369  if (! is_array($objectLines) || ! count($objectLines))
370  {
371  if (! empty($fk_product)) $productIdArray[] = $fk_product;
372  }
373  else
374  {
375  foreach ($objectLines as $line) {
376  if ($line->fk_product) $productIdArray[] = $line->fk_product;
377  }
378  }
379 
380  $nboflot = $this->loadLotStock($productIdArray);
381 
382  if ($conf->use_javascript_ajax && ! $forcecombo)
383  {
384  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
385  $comboenhancement = ajax_combobox($htmlname, $events);
386  $out.= $comboenhancement;
387  }
388 
389  $out.='<select class="flat'.($morecss?' '.$morecss:'').'"'.($disabled?' disabled':'').' id="'.$htmlname.'" name="'.($htmlname.($disabled?'_disabled':'')).'">';
390  if ($empty) $out.='<option value="-1">'.($empty_label?$empty_label:'&nbsp;').'</option>';
391  if (! empty($fk_product))
392  {
393  $productIdArray = array($fk_product); // only show lot stock for product
394  }
395  else
396  {
397  foreach($this->cache_lot as $key => $value)
398  {
399  $productIdArray[] = $key;
400  }
401  }
402 
403  foreach($productIdArray as $productId)
404  {
405  foreach($this->cache_lot[$productId] as $id => $arraytypes)
406  {
407  if (empty($fk_entrepot) || $fk_entrepot == $arraytypes['entrepot_id'])
408  {
409  $out.='<option value="'.$id.'"';
410  if ($selected == $id || ($selected == 'ifone' && $nboflot == 1)) $out.=' selected';
411  $out.='>';
412  $out.=$arraytypes['entrepot_label'].' - ';
413  $out.=$arraytypes['batch'];
414  $out.=' ('.$langs->trans("Stock").':'.$arraytypes['qty'].')';
415  $out.='</option>';
416  }
417  }
418  }
419  $out.='</select>';
420  if ($disabled) $out.='<input type="hidden" name="'.$htmlname.'" value="'.(($selected>0)?$selected:'').'">';
421 
422  return $out;
423  }
424 
432  private function loadLotStock($productIdArray = array())
433  {
434  global $conf, $langs;
435 
436  $cacheLoaded = false;
437  if (empty($productIdArray))
438  {
439  // only Load lot stock for given products
440  $this->cache_lot = array();
441  return 0;
442  }
443  if (count($productIdArray) && count($this->cache_lot))
444  {
445  // check cache already loaded for product id's
446  foreach ($productIdArray as $productId)
447  {
448  $cacheLoaded = ! empty($this->cache_lot[$productId]) ? true : false;
449  }
450  }
451  if ($cacheLoaded)
452  {
453  return count($this->cache_lot);
454  }
455  else
456  {
457  // clear cache
458  $this->cache_lot = array();
459  $productIdList = implode(',', $productIdArray);
460  $sql = "SELECT pb.batch, pb.rowid, ps.fk_entrepot, pb.qty, e.ref as label, ps.fk_product";
461  $sql.= " FROM ".MAIN_DB_PREFIX."product_batch as pb";
462  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.rowid = pb.fk_product_stock";
463  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on e.rowid = ps.fk_entrepot AND e.entity IN (".getEntity('stock').")";
464  if (!empty($productIdList))
465  {
466  $sql.= " WHERE ps.fk_product IN (".$productIdList.")";
467  }
468  $sql.= " ORDER BY e.ref, pb.batch";
469 
470  dol_syslog(get_class($this).'::loadLotStock', LOG_DEBUG);
471  $resql = $this->db->query($sql);
472  if ($resql)
473  {
474  $num = $this->db->num_rows($resql);
475  $i = 0;
476  while ($i < $num)
477  {
478  $obj = $this->db->fetch_object($resql);
479  $this->cache_lot[$obj->fk_product][$obj->rowid]['id'] =$obj->rowid;
480  $this->cache_lot[$obj->fk_product][$obj->rowid]['batch']=$obj->batch;
481  $this->cache_lot[$obj->fk_product][$obj->rowid]['entrepot_id']=$obj->fk_entrepot;
482  $this->cache_lot[$obj->fk_product][$obj->rowid]['entrepot_label']=$obj->label;
483  $this->cache_lot[$obj->fk_product][$obj->rowid]['qty'] = $obj->qty;
484  $i++;
485  }
486 
487  return $num;
488  }
489  else
490  {
491  dol_print_error($this->db);
492  return -1;
493  }
494  }
495  }
496 }
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:374
load_measuring_units($name='measuring_units', $measuring_style='', $default='0', $adddefault=0)
Return a combo box with list of units For the moment, units labels are defined in measuring_units_str...
select_measuring_units($name='measuring_units', $measuring_style='', $default='0', $adddefault=0)
Output a combo box with list of units pour l&#39;instant on ne definit pas les unites dans la base...
print
Draft customers invoices.
Definition: index.php:91
const STATUS_CLOSED
Warehouse closed, inactive.
if(! empty($conf->facture->enabled) && $user->rights->facture->lire) if(! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture->lire) if(! empty($conf->don->enabled) && $user->rights->societe->lire) if(! empty($conf->tax->enabled) && $user->rights->tax->charges->lire) if(! empty($conf->facture->enabled) &&! empty($conf->commande->enabled) && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(! empty($conf->facture->enabled) && $user->rights->facture->lire) if(! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1053
const STATUS_OPEN_ALL
Warehouse open and operations for customer shipping, supplier dispatch, internal stock transfers/corr...
formSelectWarehouses($page, $selected='', $htmlname='warehouse_id', $addempty=0)
Display form to select warehouse.
loadWarehouses($fk_product=0, $batch='', $status='', $sumStock=true, $exclude='')
Load in cache array list of warehouses If fk_product is not 0, we do not use cache.
__construct($db)
Constructor.
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
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...
loadLotStock($productIdArray=array())
Load in cache array list of lot available in stock from a given list of products. ...
selectWarehouses($selected='', $htmlname='idwarehouse', $filterstatus='', $empty=0, $disabled=0, $fk_product=0, $empty_label='', $showstock=0, $forcecombo=0, $events=array(), $morecss='minwidth200', $exclude='', $showfullpath=1)
Return list of warehouses.
Class with static methods for building HTML components related to products Only components common to ...
const STATUS_OPEN_INTERNAL
Warehouse open and operations for stock transfers/corrections allowed (not for customer shipping and ...
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
if(GETPOST('cancel', 'alpha')) if(! GETPOST( 'confirmmassaction', 'alpha') &&$massaction !='presend' &&$massaction !='confirm_presend')
Draft customers invoices.
Definition: list.php:156
price2num($amount, $rounding='', $alreadysqlnb=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
get_parent_path($tab, $final_label='')
Return full path to current warehouse in $tab (recursive function)
Class to manage warehouses.