dolibarr  19.0.0-dev
reassortlot.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005-2018 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
6  * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
7  * Copyright (C) 2016 Ferran Marcet <fmarcet@2byte.es>
8  * Copyright (C) 2019 Juanjo Menent <jmenent@2byte.es>
9  * Copyright (C) 2021 Noé Cendrier <noe.cendrier@altairis.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <https://www.gnu.org/licenses/>.
23  */
24 
31 // Load Dolibarr environment
32 require '../main.inc.php';
33 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
38 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
39 
40 // Load translation files required by the page
41 $langs->loadLangs(array('products', 'stocks', 'productbatch', 'categories'));
42 
43 $action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ...
44 $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists)
45 $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'myobjectlist'; // To manage different context of search
46 $backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
47 $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
48 $mode = GETPOST('mode', 'aZ');
49 
50 $sref = GETPOST("sref", 'alpha');
51 $snom = GETPOST("snom", 'alpha');
52 $search_all = trim((GETPOST('search_all', 'alphanohtml') != '') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'));
53 $type = GETPOSTISSET('type') ? GETPOST('type', 'int') : Product::TYPE_PRODUCT;
54 $search_barcode = GETPOST("search_barcode", 'alpha');
55 $search_warehouse = GETPOST('search_warehouse', 'alpha');
56 $search_batch = GETPOST('search_batch', 'alpha');
57 $search_toolowstock = GETPOST('search_toolowstock');
58 $search_subjecttolotserial = GETPOST('search_subjecttolotserial');
59 $tosell = GETPOST("tosell");
60 $tobuy = GETPOST("tobuy");
61 $fourn_id = GETPOST("fourn_id", 'int');
62 $sbarcode = GETPOST("sbarcode", 'int');
63 $search_stock_physique = GETPOST('search_stock_physique', 'alpha');
64 
65 // Load variable for pagination
66 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
67 $sortfield = GETPOST('sortfield', 'aZ09comma');
68 $sortorder = GETPOST('sortorder', 'aZ09comma');
69 $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
70 if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) {
71  // If $page is not defined, or '' or -1 or if we click on clear filters
72  $page = 0;
73 }
74 $offset = $limit * $page;
75 $pageprev = $page - 1;
76 $pagenext = $page + 1;
77 
78 // Initialize array of search criterias
79 $object = new Product($db);
80 $search_sale = GETPOST("search_sale");
81 if (GETPOSTISSET('catid')) {
82  $search_categ = GETPOST('catid', 'int');
83 } else {
84  $search_categ = GETPOST('search_categ', 'int');
85 }
86 $search_warehouse_categ = GETPOST('search_warehouse_categ', 'int');
87 
88 // Fetch optionals attributes and labels
89 $extrafields->fetch_name_optionals_label($object->table_element);
90 //$extrafields->fetch_name_optionals_label($object->table_element_line);
91 
92 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
93 
94 // Default sort order (if not yet defined by previous GETPOST)
95 if (!$sortfield) {
96  reset($object->fields); // Reset is required to avoid key() to return null.
97  $sortfield = "p.".key($object->fields); // Set here default search field. By default 1st field in definition.
98 }
99 if (!$sortorder) {
100  $sortorder = "ASC";
101 }
102 
103 
104 // Initialize array of search criterias
105 $search = array();
106 foreach ($object->fields as $key => $val) {
107  if (GETPOST('search_'.$key, 'alpha') !== '') {
108  $search[$key] = GETPOST('search_'.$key, 'alpha');
109  }
110  if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) {
111  $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int'));
112  $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int'));
113  }
114 }
115 $key = 'sellby';
116 $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int'));
117 $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int'));
118 $key = 'eatby';
119 $search[$key.'_dtstart'] = dol_mktime(0, 0, 0, GETPOST('search_'.$key.'_dtstartmonth', 'int'), GETPOST('search_'.$key.'_dtstartday', 'int'), GETPOST('search_'.$key.'_dtstartyear', 'int'));
120 $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int'));
121 
122 // Get object canvas (By default, this is not defined, so standard usage of dolibarr)
123 $canvas = GETPOST("canvas");
124 $objcanvas = null;
125 if (!empty($canvas)) {
126  require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
127  $objcanvas = new Canvas($db, $action);
128  $objcanvas->getCanvas('product', 'list', $canvas);
129 }
130 
131 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
132 $hookmanager->initHooks(array('reassortlotlist'));
133 
134 // Security check
135 if ($user->socid) {
136  $socid = $user->socid;
137 }
138 $result = restrictedArea($user, 'produit|service', 0, 'product&product');
139 
140 // Definition of array of fields for columns
141 $arrayfields = array(
142  array('type'=>'varchar', 'label'=>'Ref', 'checked'=>1, 'enabled'=>1, 'position'=>1),
143  array('type'=>'varchar', 'label'=>'Label', 'checked'=>1, 'enabled'=>1, 'position'=>1),
144  array('type'=>'int', 'label'=>'Warehouse', 'checked'=>1, 'enabled'=>1, 'position'=>1),
145  array('type'=>'varchar', 'label'=>'Lot', 'checked'=>1, 'enabled'=>1, 'position'=>1),
146  array('type'=>'varchar', 'label'=>'DLC', 'checked'=>1, 'enabled'=>1, 'position'=>1),
147  array('type'=>'varchar', 'label'=>'DLUO', 'checked'=>1, 'enabled'=>1, 'position'=>1),
148  array('type'=>'int', 'label'=>'Stock', 'checked'=>1, 'enabled'=>1, 'position'=>1),
149  array('type'=>'int', 'label'=>'StatusSell', 'checked'=>1, 'enabled'=>1, 'position'=>1),
150  array('type'=>'int', 'label'=>'StatusBuy', 'checked'=>1, 'enabled'=>1, 'position'=>1),
151 );
152 
153 //$arrayfields['anotherfield'] = array('type'=>'integer', 'label'=>'AnotherField', 'checked'=>1, 'enabled'=>1, 'position'=>90, 'csslist'=>'right');
154 $arrayfields = dol_sort_array($arrayfields, 'position');
155 
156 
157 
158 /*
159  * Actions
160  */
161 
162 if (GETPOST('cancel', 'alpha')) {
163  $action = 'list';
164  $massaction = '';
165 }
166 if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') {
167  $massaction = '';
168 }
169 
170 $parameters = array();
171 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
172 if ($reshook < 0) {
173  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
174 }
175 
176 if (empty($reshook)) {
177  // Selection of new fields
178  include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
179 
180  // Purge search criteria
181  if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
182  foreach ($object->fields as $key => $val) {
183  $search[$key] = '';
184  if (preg_match('/^(date|timestamp|datetime)/', $val['type'])) {
185  $search[$key.'_dtstart'] = '';
186  $search[$key.'_dtend'] = '';
187  }
188  }
189  $search['sellby_dtstart'] = '';
190  $search['eatby_dtstart'] = '';
191  $search['sellby_dtend'] = '';
192  $search['eatby_dtend'] = '';
193  $sref = "";
194  $snom = "";
195  $search_all = "";
196  $tosell = "";
197  $tobuy = "";
198  $search_sale = "";
199  $search_categ = "";
200  $search_warehouse_categ = "";
201  $search_toolowstock = '';
202  $search_subjecttolotserial = '';
203  $search_batch = '';
204  $search_warehouse = '';
205  $fourn_id = '';
206  $sbarcode = '';
207  $search_stock_physique = '';
208  $toselect = array();
209  $search_array_options = array();
210  }
211  if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')
212  || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) {
213  $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation
214  }
215 
216  // Mass actions
217  /*$objectclass = 'MyObject';
218  $objectlabel = 'MyObject';
219  $uploaddir = $conf->mymodule->dir_output;
220  include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
221  */
222 }
223 
224 
225 
226 /*
227  * View
228  */
229 
230 $form = new Form($db);
231 $htmlother = new FormOther($db);
232 
233 $now = dol_now();
234 
235 $helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
236 $title = $langs->trans("ProductsAndServices");
237 $morejs = array();
238 $morecss = array();
239 
240 $sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
241 $sql .= ' p.fk_product_type, p.tms as datem,';
242 $sql .= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte, p.desiredstock, p.stock, p.tosell, p.tobuy, p.tobatch,';
243 $sql .= ' ps.fk_entrepot, ps.reel,';
244 $sql .= ' e.ref as warehouse_ref, e.lieu as warehouse_lieu, e.fk_parent as warehouse_parent,';
245 $sql .= ' pb.batch, pb.eatby as oldeatby, pb.sellby as oldsellby,';
246 $sql .= ' pl.rowid as lotid, pl.eatby, pl.sellby,';
247 $sql .= ' SUM(pb.qty) as stock_physique, COUNT(pb.rowid) as nbinbatchtable';
248 // Add fields from hooks
249 $parameters = array();
250 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook
251 $sql .= $hookmanager->resPrint;
252 $sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
253 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as ps on p.rowid = ps.fk_product'; // Detail for each warehouse
254 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'entrepot as e on ps.fk_entrepot = e.rowid'; // Link on unique key
255 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_batch as pb on pb.fk_product_stock = ps.rowid'; // Detail for each lot on each warehouse
256 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_lot as pl on pl.fk_product = p.rowid AND pl.batch = pb.batch'; // Link on unique key
257 // Add table from hooks
258 $parameters = array();
259 $reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook
260 $sql .= $hookmanager->resPrint;
261 $sql .= " WHERE p.entity IN (".getEntity('product').") AND e.entity IN (".getEntity('stock').")";
262 if (!empty($search_categ) && $search_categ != '-1') {
263  $sql .= " AND ";
264  if ($search_categ == -2) {
265  $sql .= " NOT EXISTS ";
266  } else {
267  $sql .= " EXISTS ";
268  }
269  $sql .= "(";
270  $sql .= " SELECT cp.fk_categorie, cp.fk_product";
271  $sql .= " FROM " . MAIN_DB_PREFIX . "categorie_product as cp";
272  $sql .= " WHERE cp.fk_product = p.rowid"; // Join for the needed table to filter by categ
273  if ($search_categ > 0) {
274  $sql .= " AND cp.fk_categorie = " . ((int) $search_categ);
275  }
276  $sql .= ")";
277 }
278 if (!empty($search_warehouse_categ) && $search_warehouse_categ != '-1') {
279  $sql .= " AND ";
280  if ($search_warehouse_categ == -2) {
281  $sql .= " NOT EXISTS ";
282  } else {
283  $sql .= " EXISTS ";
284  }
285  $sql .= "(";
286  $sql .= " SELECT cp.fk_categorie, cp.fk_warehouse";
287  $sql .= " FROM " . MAIN_DB_PREFIX . "categorie_warehouse as cp";
288  $sql .= " WHERE cp.fk_warehouse = e.rowid"; // Join for the needed table to filter by categ
289  if ($search_warehouse_categ > 0) {
290  $sql .= " AND cp.fk_categorie = " . ((int) $search_warehouse_categ);
291  }
292  $sql .= ")";
293 }
294 if ($search_all) {
295  $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $search_all);
296 }
297 // if the type is not 1, we show all products (type = 0,2,3)
298 if (dol_strlen($type)) {
299  if ($type == 1) {
300  $sql .= " AND p.fk_product_type = '1'";
301  } else {
302  $sql .= " AND p.fk_product_type <> '1'";
303  }
304 }
305 if ($search_subjecttolotserial) {
306  $sql .= " AND p.tobatch > 0";
307 }
308 if ($sref) {
309  $sql .= natural_search("p.ref", $sref);
310 }
311 if ($search_barcode) {
312  $sql .= natural_search("p.barcode", $search_barcode);
313 }
314 if ($snom) {
315  $sql .= natural_search("p.label", $snom);
316 }
317 if (!empty($tosell)) {
318  $sql .= " AND p.tosell = ".((int) $tosell);
319 }
320 if (!empty($tobuy)) {
321  $sql .= " AND p.tobuy = ".((int) $tobuy);
322 }
323 if (!empty($canvas)) {
324  $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
325 }
326 if ($fourn_id > 0) {
327  $sql .= " AND p.rowid = pf.fk_product AND pf.fk_soc = ".((int) $fourn_id);
328 }
329 if ($search_warehouse) {
330  $sql .= natural_search("e.ref", $search_warehouse);
331 }
332 if ($search_batch) {
333  $sql .= natural_search("pb.batch", $search_batch);
334 }
335 
336 foreach ($search as $key => $val) {
337  if (array_key_exists($key, $object->fields)) {
338  if ($key == 'status' && $search[$key] == -1) {
339  continue;
340  }
341  $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0);
342  if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) {
343  if ($search[$key] == '-1' || ($search[$key] === '0' && (empty($object->fields[$key]['arrayofkeyval']) || !array_key_exists('0', $object->fields[$key]['arrayofkeyval'])))) {
344  $search[$key] = '';
345  }
346  $mode_search = 2;
347  }
348  if ($search[$key] != '') {
349  $sql .= natural_search("t.".$db->escape($key), $search[$key], (($key == 'status') ? 2 : $mode_search));
350  }
351  } else {
352  if (preg_match('/(_dtstart|_dtend)$/', $key) && $search[$key] != '') {
353  $columnName = preg_replace('/(_dtstart|_dtend)$/', '', $key);
354  if ($columnName == 'eatby' || $columnName == 'sellby') {
355  if (preg_match('/_dtstart$/', $key)) {
356  $sql .= " AND pl.".$db->escape($columnName)." >= '".$db->idate($search[$key])."'";
357  }
358  if (preg_match('/_dtend$/', $key)) {
359  $sql .= " AND pl.".$db->escape($columnName)." <= '".$db->idate($search[$key])."'";
360  }
361  }
362  }
363  }
364 }
365 // Add where from hooks
366 $parameters = array();
367 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
368 $sql .= $hookmanager->resPrint;
369 
370 $sql .= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,";
371 $sql .= " p.fk_product_type, p.tms,";
372 $sql .= " p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock, p.stock, p.tosell, p.tobuy, p.tobatch,";
373 $sql .= " ps.fk_entrepot, ps.reel,";
374 $sql .= " e.ref, e.lieu, e.fk_parent,";
375 $sql .= " pb.batch, pb.eatby, pb.sellby,";
376 $sql .= " pl.rowid, pl.eatby, pl.sellby";
377 // Add GROUP BY from hooks
378 $parameters = array();
379 $reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook
380 $sql .= $hookmanager->resPrint;
381 $sql_having = '';
382 if ($search_toolowstock) {
383  $sql_having .= " HAVING SUM(".$db->ifsql('ps.reel IS NULL', '0', 'ps.reel').") < p.seuil_stock_alerte"; // Not used yet
384 }
385 if ($search_stock_physique != '') {
386  $natural_search_physique = natural_search('SUM(' . $db->ifsql('pb.qty IS NULL', $db->ifsql('ps.reel IS NULL', '0', 'ps.reel'), 'pb.qty') . ')', $search_stock_physique, 1, 1);
387  $natural_search_physique = " " . substr($natural_search_physique, 1, -1); // remove first "(" and last ")" characters
388  if (!empty($sql_having)) {
389  $sql_having .= " AND";
390  } else {
391  $sql_having .= " HAVING";
392  }
393  $sql_having .= $natural_search_physique;
394 }
395 // Add HAVING from hooks
396 $parameters = array();
397 $reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook
398 if (!empty($hookmanager->resPrint)) {
399  if (!empty($sql_having)) {
400  $sql_having .= " AND";
401  } else {
402  $sql_having .= " HAVING";
403  }
404  $sql_having .= $hookmanager->resPrint;
405 }
406 if (!empty($sql_having)) {
407  $sql .= $sql_having;
408 }
409 
410 //print $sql;
411 
412 // Count total nb of records
413 $nbtotalofrecords = '';
414 if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
415  $resql = $db->query($sql);
416  $nbtotalofrecords = $db->num_rows($resql);
417 
418  if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0
419  $page = 0;
420  $offset = 0;
421  }
422  $db->free($resql);
423 }
424 
425 // Complete request and execute it with limit
426 $sql .= $db->order($sortfield, $sortorder);
427 if ($limit) {
428  $sql .= $db->plimit($limit + 1, $offset);
429 }
430 
431 $resql = $db->query($sql);
432 if (!$resql) {
433  dol_print_error($db);
434  exit;
435 }
436 
437 $num = $db->num_rows($resql);
438 
439 $i = 0;
440 
441 if ($num == 1 && GETPOST('autojumpifoneonly') && ($search_all or $snom or $sref)) {
442  $objp = $db->fetch_object($resql);
443  header("Location: card.php?id=$objp->rowid");
444  exit;
445 }
446 
447 if (isset($type)) {
448  if ($type == 1) {
449  $texte = $langs->trans("Services");
450  } else {
451  $texte = $langs->trans("Products");
452  }
453 } else {
454  $texte = $langs->trans("ProductsAndServices");
455 }
456 $texte .= ' ('.$langs->trans("StocksByLotSerial").')';
457 
458 $param = '';
459 if (!empty($mode)) {
460  $param .= '&mode='.urlencode($mode);
461 }
462 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
463  $param .= '&contextpage='.urlencode($contextpage);
464 }
465 if ($limit > 0 && $limit != $conf->liste_limit) {
466  $param .= '&limit='.((int) $limit);
467 }
468 foreach ($search as $key => $val) {
469  if (is_array($search[$key]) && count($search[$key])) {
470  foreach ($search[$key] as $skey) {
471  if ($skey != '') {
472  $param .= '&search_'.$key.'[]='.urlencode($skey);
473  }
474  }
475  } elseif ($search[$key] != '') {
476  $param .= '&search_'.$key.'='.urlencode($search[$key]);
477  }
478 }
479 if ($optioncss != '') {
480  $param .= '&optioncss='.urlencode($optioncss);
481 }
482 if ($search_all) {
483  $param .= "&search_all=".urlencode($search_all);
484 }
485 if ($tosell) {
486  $param .= "&tosell=".urlencode($tosell);
487 }
488 if ($tobuy) {
489  $param .= "&tobuy=".urlencode($tobuy);
490 }
491 if ($type != '') {
492  $param .= "&type=".urlencode($type);
493 }
494 if ($fourn_id) {
495  $param .= "&fourn_id=".urlencode($fourn_id);
496 }
497 if ($snom) {
498  $param .= "&snom=".urlencode($snom);
499 }
500 if ($sref) {
501  $param .= "&sref=".urlencode($sref);
502 }
503 if ($search_batch) {
504  $param .= "&search_batch=".urlencode($search_batch);
505 }
506 if ($sbarcode) {
507  $param .= "&sbarcode=".urlencode($sbarcode);
508 }
509 if ($search_warehouse) {
510  $param .= "&search_warehouse=".urlencode($search_warehouse);
511 }
512 if ($search_toolowstock) {
513  $param .= "&search_toolowstock=".urlencode($search_toolowstock);
514 }
515 if ($search_subjecttolotserial) {
516  $param .= "&search_subjecttolotserial=".urlencode($search_subjecttolotserial);
517 }
518 if ($search_sale) {
519  $param .= "&search_sale=".urlencode($search_sale);
520 }
521 if (!empty($search_categ) && $search_categ != '-1') {
522  $param .= "&search_categ=".urlencode($search_categ);
523 }
524 if (!empty($search_warehouse_categ) && $search_warehouse_categ != '-1') {
525  $param .= "&search_warehouse_categ=".urlencode($search_warehouse_categ);
526 }
527 if ($search_stock_physique) {
528  $param .= '&search_stock_physique=' . urlencode($search_stock_physique);
529 }
530 /*if ($eatby) $param.="&eatby=".$eatby;
531 if ($sellby) $param.="&sellby=".$sellby;*/
532 
533 llxHeader("", $title, $helpurl, $texte);
534 
535 print '<form id="searchFormList" action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">'."\n";
536 if ($optioncss != '') {
537  print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
538 }
539 print '<input type="hidden" name="token" value="'.newToken().'">';
540 print '<input type="hidden" name="action" value="list">';
541 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
542 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
543 print '<input type="hidden" name="type" value="'.$type.'">';
544 print '<input type="hidden" name="page" value="'.$page.'">';
545 print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
546 print '<input type="hidden" name="mode" value="'.$mode.'">';
547 
548 print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit, 0, 0, 1);
549 
550 /*
551 if ($search_categ > 0) {
552  print "<div id='ways'>";
553  $c = new Categorie($db);
554  $c->fetch($search_categ);
555  $ways = $c->print_all_ways(' &gt; ', 'product/reassortlot.php');
556  print " &gt; ".$ways[0]."<br>\n";
557  print "</div><br>";
558 }
559 */
560 
561 // Filter on categories
562 $moreforfilter = '';
563 if (isModEnabled('categorie')) {
564  $moreforfilter .= '<div class="divsearchfield">';
565  $moreforfilter .= img_picto($langs->trans('ProductsCategoriesShort'), 'category', 'class="pictofixedwidth"');
566  $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_PRODUCT, $search_categ, 'search_categ', 1, $langs->trans("ProductsCategoryShort"), 'maxwidth400');
567  $moreforfilter .= '</div>';
568 }
569 // Filter on warehouse categories
570 if (isModEnabled('categorie')) {
571  $moreforfilter .= '<div class="divsearchfield">';
572  $moreforfilter .= img_picto($langs->trans('StockCategoriesShort'), 'category', 'class="pictofixedwidth"');
573  $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_WAREHOUSE, $search_warehouse_categ, 'search_warehouse_categ', 1, $langs->trans("StockCategoriesShort"), 'maxwidth400');
574  $moreforfilter .= '</div>';
575 }
576 
577 $moreforfilter.='<label for="search_subjecttolotserial">'.$langs->trans("SubjectToLotSerialOnly").' </label><input type="checkbox" id="search_subjecttolotserial" name="search_subjecttolotserial" value="1"'.($search_subjecttolotserial?' checked':'').'>';
578 
579 
580 if (!empty($moreforfilter)) {
581  print '<div class="liste_titre liste_titre_bydiv centpercent">';
582  print $moreforfilter;
583  $parameters = array();
584  $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
585  print $hookmanager->resPrint;
586  print '</div>';
587 }
588 
589 
590 print '<div class="div-table-responsive">';
591 print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
592 
593 // Fields title search
594 // --------------------------------------------------------------------
595 print '<tr class="liste_titre_filter">';
596 // Action column
597 if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
598  print '<td class="liste_titre maxwidthsearch">';
599  $searchpicto = $form->showFilterButtons();
600  print $searchpicto;
601  print '</td>';
602 }
603 print '<td class="liste_titre">';
604 print '<input class="flat" type="text" name="sref" size="6" value="'.dol_escape_htmltag($sref).'">';
605 print '</td>';
606 print '<td class="liste_titre">';
607 print '<input class="flat" type="text" name="snom" size="8" value="'.dol_escape_htmltag($snom).'">';
608 print '</td>';
609 if (isModEnabled("service") && $type == 1) {
610  print '<td class="liste_titre">';
611  print '&nbsp;';
612  print '</td>';
613 }
614 
615 print '<td class="liste_titre"><input class="flat" type="text" name="search_warehouse" size="6" value="'.dol_escape_htmltag($search_warehouse).'"></td>';
616 print '<td class="liste_titre center"><input class="flat" type="text" name="search_batch" size="6" value="'.dol_escape_htmltag($search_batch).'"></td>';
617 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
618  print '<td class="liste_titre center">';
619  $key = 'sellby';
620  print '<div class="nowrap">';
621  print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
622  print '</div>';
623  print '<div class="nowrap">';
624  print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
625  print '</div>';
626  print '</td>';
627 }
628 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
629  print '<td class="liste_titre center">';
630  $key = 'eatby';
631  print '<div class="nowrap">';
632  print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
633  print '</div>';
634  print '<div class="nowrap">';
635  print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
636  print '</div>';
637  print '</td>';
638 }
639 // Physical stock
640 print '<td class="liste_titre right">';
641 print '<input class="flat" type="text" size="5" name="search_stock_physique" value="'.dol_escape_htmltag($search_stock_physique).'">';
642 print '</td>';
643 print '<td class="liste_titre">&nbsp;</td>';
644 print '<td class="liste_titre">&nbsp;</td>';
645 print '<td class="liste_titre">&nbsp;</td>';
646 $parameters = array();
647 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
648 print $hookmanager->resPrint;
649 // Action column
650 if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
651  print '<td class="liste_titre maxwidthsearch">';
652  $searchpicto = $form->showFilterButtons();
653  print $searchpicto;
654  print '</td>';
655 }
656 print '</tr>'."\n";
657 
658 $totalarray = array();
659 $totalarray['nbfield'] = 0;
660 
661 // Fields title label
662 // --------------------------------------------------------------------
663 print '<tr class="liste_titre">';
664 // Action column
665 if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
667 }
668 print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "p.ref", '', $param, "", $sortfield, $sortorder);
669 print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "p.label", '', $param, "", $sortfield, $sortorder);
670 if (isModEnabled("service") && $type == 1) {
671  print_liste_field_titre("Duration", $_SERVER["PHP_SELF"], "p.duration", '', $param, "", $sortfield, $sortorder, 'center ');
672 }
673 print_liste_field_titre("Warehouse", $_SERVER["PHP_SELF"], "e.ref", '', $param, "", $sortfield, $sortorder);
674 //print_liste_field_titre("DesiredStock", $_SERVER["PHP_SELF"], "p.desiredstock",$param,"",'',$sortfield,$sortorder, 'right );
675 print_liste_field_titre("Batch", $_SERVER["PHP_SELF"], "pb.batch", '', $param, "", $sortfield, $sortorder, 'center ');
676 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
677  print_liste_field_titre("SellByDate", $_SERVER["PHP_SELF"], "pl.sellby", '', $param, "", $sortfield, $sortorder, 'center ');
678 }
679 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
680  print_liste_field_titre("EatByDate", $_SERVER["PHP_SELF"], "pl.eatby", '', $param, "", $sortfield, $sortorder, 'center ');
681 }
682 print_liste_field_titre("PhysicalStock", $_SERVER["PHP_SELF"], "stock_physique", '', $param, "", $sortfield, $sortorder, 'right ');
683 // TODO Add info of running suppliers/customers orders
684 //print_liste_field_titre("TheoreticalStock",$_SERVER["PHP_SELF"], "stock_theorique",$param,"",'',$sortfield,$sortorder, 'right ');
686 print_liste_field_titre("ProductStatusOnSell", $_SERVER["PHP_SELF"], "p.tosell", "", $param, '', $sortfield, $sortorder, 'right ');
687 print_liste_field_titre("ProductStatusOnBuy", $_SERVER["PHP_SELF"], "p.tobuy", "", $param, '', $sortfield, $sortorder, 'right ');
688 // Hook fields
689 $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
690 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
691 print $hookmanager->resPrint;
692 if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
694 }
695 print "</tr>\n";
696 
697 $product_static = new Product($db);
698 $product_lot_static = new Productlot($db);
699 $warehousetmp = new Entrepot($db);
700 
701 // Loop on record
702 // --------------------------------------------------------------------
703 $i = 0;
704 $savnbfield = $totalarray['nbfield'];
705 $totalarray['nbfield'] = 0;
706 $imaxinloop = ($limit ? min($num, $limit) : $num);
707 while ($i < $imaxinloop) {
708  $objp = $db->fetch_object($resql);
709 
710  // Multilangs
711  if (getDolGlobalInt('MAIN_MULTILANGS')) { // si l'option est active
712  // TODO Use a cache
713  $sql = "SELECT label";
714  $sql .= " FROM ".MAIN_DB_PREFIX."product_lang";
715  $sql .= " WHERE fk_product = ".((int) $objp->rowid);
716  $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
717  $sql .= " LIMIT 1";
718 
719  $result = $db->query($sql);
720  if ($result) {
721  $objtp = $db->fetch_object($result);
722  if (!empty($objtp->label)) {
723  $objp->label = $objtp->label;
724  }
725  }
726  }
727 
728  $product_static->ref = $objp->ref;
729  $product_static->id = $objp->rowid;
730  $product_static->label = $objp->label;
731  $product_static->type = $objp->fk_product_type;
732  $product_static->entity = $objp->entity;
733  $product_static->status = $objp->tosell;
734  $product_static->status_buy = $objp->tobuy;
735  $product_static->status_batch = $objp->tobatch;
736 
737  $product_lot_static->batch = $objp->batch;
738  $product_lot_static->fk_product = $objp->rowid;
739  $product_lot_static->id = $objp->lotid;
740  $product_lot_static->eatby = $objp->eatby;
741  $product_lot_static->sellby = $objp->sellby;
742 
743 
744  $warehousetmp->id = $objp->fk_entrepot;
745  $warehousetmp->ref = $objp->warehouse_ref;
746  $warehousetmp->label = $objp->warehouse_ref;
747  $warehousetmp->fk_parent = $objp->warehouse_parent;
748 
749  print '<tr>';
750 
751  // Action column
752  if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
753  print '<td></td>';
754  if (!$i) {
755  $totalarray['nbfield']++;
756  }
757  }
758 
759  // Ref
760  print '<td class="nowrap">';
761  print $product_static->getNomUrl(1, '', 16);
762  //if ($objp->stock_theorique < $objp->seuil_stock_alerte) print ' '.img_warning($langs->trans("StockTooLow"));
763  print '</td>';
764  if (!$i) {
765  $totalarray['nbfield']++;
766  }
767 
768  // Label
769  print '<td>'.$objp->label.'</td>';
770  if (!$i) {
771  $totalarray['nbfield']++;
772  }
773 
774  if (isModEnabled("service") && $type == 1) {
775  print '<td class="center">';
776  $regs = array();
777  if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) {
778  print $regs[1].' '.$langs->trans("DurationYear");
779  } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) {
780  print $regs[1].' '.$langs->trans("DurationMonth");
781  } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) {
782  print $regs[1].' '.$langs->trans("DurationDay");
783  } else {
784  print $objp->duration;
785  }
786  if (!$i) {
787  $totalarray['nbfield']++;
788  }
789  print '</td>';
790  }
791  //print '<td class="right">'.$objp->stock_theorique.'</td>';
792  //print '<td class="right">'.$objp->seuil_stock_alerte.'</td>';
793  //print '<td class="right">'.$objp->desiredstock.'</td>';
794 
795  // Warehouse
796  print '<td class="nowrap">';
797  if ($objp->fk_entrepot > 0) {
798  print $warehousetmp->getNomUrl(1);
799  }
800  if (!$i) {
801  $totalarray['nbfield']++;
802  }
803  print '</td>';
804 
805  // Lot
806  print '<td class="center nowrap">';
807  if ($product_lot_static->batch) {
808  print $product_lot_static->getNomUrl(1);
809  }
810  if (!$i) {
811  $totalarray['nbfield']++;
812  }
813  print '</td>';
814 
815  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
816  print '<td class="center">'.dol_print_date($db->jdate($objp->sellby), 'day').'</td>';
817  if (!$i) {
818  $totalarray['nbfield']++;
819  }
820  }
821 
822  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
823  print '<td class="center">'.dol_print_date($db->jdate($objp->eatby), 'day').'</td>';
824  if (!$i) {
825  $totalarray['nbfield']++;
826  }
827  }
828 
829  print '<td class="right">';
830  //if ($objp->seuil_stock_alerte && ($objp->stock_physique < $objp->seuil_stock_alerte)) print img_warning($langs->trans("StockTooLow")).' ';
831  if (is_null($objp->stock_physique)) {
832  if (!empty($objp->reel)) {
833  if ($objp->reel < 0) { print '<span class="warning">'; }
834  print price2num($objp->reel, 'MS');
835  if ($objp->reel < 0) { print '</span>'; }
836  }
837  } else {
838  if (!empty($objp->stock_physique)) {
839  if ($objp->stock_physique < 0) { print '<span class="warning">'; }
840  print price2num($objp->stock_physique, 'MS');
841  if ($objp->stock_physique < 0) { print '</span>'; }
842  }
843  }
844  print '</td>';
845  if (!$i) {
846  $totalarray['nbfield']++;
847  }
848 
849  print '<td class="right">';
850  print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
851  print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$product_static->id.'&search_warehouse='.$objp->fk_entrepot.'&search_batch='.($objp->batch != 'Undefined' ? $objp->batch : 'Undefined').'">'.$langs->trans("Movements").'</a>';
852  print '</td>';
853  if (!$i) {
854  $totalarray['nbfield']++;
855  }
856 
857  print '<td class="right nowrap">'.$product_static->LibStatut($objp->statut, 5, 0).'</td>';
858  if (!$i) {
859  $totalarray['nbfield']++;
860  }
861 
862  print '<td class="right nowrap">'.$product_static->LibStatut($objp->tobuy, 5, 1).'</td>';
863  if (!$i) {
864  $totalarray['nbfield']++;
865  }
866 
867  // Fields values from hook
868  $parameters = array('obj'=>$objp);
869  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $product); // Note that $action and $object may have been modified by hook
870  print $hookmanager->resPrint;
871 
872  // Action column
873  if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
874  print '<td></td>';
875  if (!$i) {
876  $totalarray['nbfield']++;
877  }
878  }
879 
880  print "</tr>\n";
881  $i++;
882 }
883 
884 // If no record found
885 if ($num == 0) {
886  $colspan = 2;
887  foreach ($arrayfields as $key => $val) {
888  if (!empty($val['checked'])) {
889  $colspan++;
890  }
891  }
892  print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
893 }
894 
895 
896 $db->free($resql);
897 
898 print '</table>'."\n";
899 print '</div>'."\n";
900 
901 print '</form>'."\n";
902 
903 
904 // End of page
905 llxFooter();
906 $db->close();
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
Class to manage canvas.
Class to manage warehouses.
Class to manage generation of HTML components Only common components must be here.
Classe permettant la generation de composants html autre Only common components are here.
Class to manage products or services.
Class with list of lots and properties.
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
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
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...
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
isModEnabled($module)
Is Dolibarr module enabled.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.