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