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