dolibarr 22.0.5
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($hookmanager->resPrint)) {
410 if (!empty($sql_having)) {
411 $sql_having .= " AND";
412 } else {
413 $sql_having .= " HAVING";
414 }
415 $sql_having .= $hookmanager->resPrint;
416}
417if (!empty($sql_having)) {
418 $sql .= $sql_having;
419}
420
421//print $sql;
422
423// Count total nb of records
424$nbtotalofrecords = '';
425if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
426 $resql = $db->query($sql);
427 $nbtotalofrecords = $db->num_rows($resql);
428
429 if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0
430 $page = 0;
431 $offset = 0;
432 }
433 $db->free($resql);
434}
435
436// Complete request and execute it with limit
437$sql .= $db->order($sortfield, $sortorder);
438if ($limit) {
439 $sql .= $db->plimit($limit + 1, $offset);
440}
441
442$resql = $db->query($sql);
443if (!$resql) {
444 dol_print_error($db);
445 exit;
446}
447
448$num = $db->num_rows($resql);
449
450$i = 0;
451
452if ($num == 1 && GETPOST('autojumpifoneonly') && ($search_all || $snom || $sref)) {
453 $objp = $db->fetch_object($resql);
454 header("Location: card.php?id=$objp->rowid");
455 exit;
456}
457
458if (isset($type)) {
459 if ($type == 1) {
460 $texte = $langs->trans("Services");
461 } else {
462 $texte = $langs->trans("Products");
463 }
464} else {
465 $texte = $langs->trans("ProductsAndServices");
466}
467$texte .= ' ('.$langs->trans("StocksByLotSerial").')';
468
469$param = '';
470if (!empty($mode)) {
471 $param .= '&mode='.urlencode($mode);
472}
473if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
474 $param .= '&contextpage='.urlencode($contextpage);
475}
476if ($limit > 0 && $limit != $conf->liste_limit) {
477 $param .= '&limit='.((int) $limit);
478}
479foreach ($search as $key => $val) {
480 if (is_array($search[$key]) && count($search[$key])) {
481 foreach ($search[$key] as $skey) {
482 if ($skey != '') {
483 $param .= '&search_'.$key.'[]='.urlencode($skey);
484 }
485 }
486 } elseif ($search[$key] != '') {
487 $param .= '&search_'.$key.'='.urlencode($search[$key]);
488 }
489}
490if ($optioncss != '') {
491 $param .= '&optioncss='.urlencode($optioncss);
492}
493if ($search_all) {
494 $param .= "&search_all=".urlencode($search_all);
495}
496if ($tosell) {
497 $param .= "&tosell=".urlencode($tosell);
498}
499if ($tobuy) {
500 $param .= "&tobuy=".urlencode($tobuy);
501}
502if ($type != '') {
503 $param .= "&type=".urlencode((string) ($type));
504}
505if ($fourn_id) {
506 $param .= "&fourn_id=".urlencode((string) ($fourn_id));
507}
508if ($snom) {
509 $param .= "&snom=".urlencode($snom);
510}
511if ($sref) {
512 $param .= "&sref=".urlencode($sref);
513}
514if ($search_batch) {
515 $param .= "&search_batch=".urlencode($search_batch);
516}
517if ($sbarcode) {
518 $param .= "&sbarcode=".urlencode((string) ($sbarcode));
519}
520if ($search_warehouse) {
521 $param .= "&search_warehouse=".urlencode($search_warehouse);
522}
523if ($search_toolowstock) {
524 $param .= "&search_toolowstock=".urlencode($search_toolowstock);
525}
526if ($search_subjecttolotserial) {
527 $param .= "&search_subjecttolotserial=".urlencode($search_subjecttolotserial);
528}
529if ($search_sale) {
530 $param .= "&search_sale=".urlencode($search_sale);
531}
532if (!empty($search_categ) && $search_categ != '-1') {
533 $param .= "&search_categ=".urlencode((string) ($search_categ));
534}
535if (!empty($search_warehouse_categ) && $search_warehouse_categ != '-1') {
536 $param .= "&search_warehouse_categ=".urlencode((string) ($search_warehouse_categ));
537}
538if ($search_stock_physique) {
539 $param .= '&search_stock_physique=' . urlencode($search_stock_physique);
540}
541/*if ($eatby) $param.="&eatby=".$eatby;
542if ($sellby) $param.="&sellby=".$sellby;*/
543
544llxHeader("", $title, $helpurl, $texte, 0, 0, '', '', '', 'mod-product page-reassortlot');
545
546print '<form id="searchFormList" action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">'."\n";
547if ($optioncss != '') {
548 print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
549}
550print '<input type="hidden" name="token" value="'.newToken().'">';
551print '<input type="hidden" name="action" value="list">';
552print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
553print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
554print '<input type="hidden" name="type" value="'.$type.'">';
555print '<input type="hidden" name="page" value="'.$page.'">';
556print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
557print '<input type="hidden" name="mode" value="'.$mode.'">';
558
559print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit, 0, 0, 1);
560
561/*
562if ($search_categ > 0) {
563 print "<div id='ways'>";
564 $c = new Categorie($db);
565 $c->fetch($search_categ);
566 $ways = $c->print_all_ways(' &gt; ', 'product/reassortlot.php');
567 print " &gt; ".$ways[0]."<br>\n";
568 print "</div><br>";
569}
570*/
571
572// Filter on categories
573$moreforfilter = '';
574if (isModEnabled('category')) {
575 $moreforfilter .= '<div class="divsearchfield">';
576 $moreforfilter .= img_picto($langs->trans('ProductsCategoriesShort'), 'category', 'class="pictofixedwidth"');
577 $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_PRODUCT, $search_categ, 'search_categ', 1, $langs->trans("ProductsCategoryShort"), 'maxwidth400');
578 $moreforfilter .= '</div>';
579}
580// Filter on warehouse categories
581if (isModEnabled('category')) {
582 $moreforfilter .= '<div class="divsearchfield">';
583 $moreforfilter .= img_picto($langs->trans('StockCategoriesShort'), 'category', 'class="pictofixedwidth"');
584 $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_WAREHOUSE, $search_warehouse_categ, 'search_warehouse_categ', 1, $langs->trans("StockCategoriesShort"), 'maxwidth400');
585 $moreforfilter .= '</div>';
586}
587
588$moreforfilter .= '<label for="search_subjecttolotserial">'.$langs->trans("SubjectToLotSerialOnly").' </label><input type="checkbox" id="search_subjecttolotserial" name="search_subjecttolotserial" value="1"'.($search_subjecttolotserial ? ' checked' : '').'>';
589
590
591print '<div class="liste_titre liste_titre_bydiv centpercent">';
592print $moreforfilter;
593$parameters = array();
594$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
595print $hookmanager->resPrint;
596print '</div>';
597
598print '<div class="div-table-responsive">';
599print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
600
601// Fields title search
602// --------------------------------------------------------------------
603print '<tr class="liste_titre_filter">';
604// Action column
605if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
606 print '<td class="liste_titre maxwidthsearch">';
607 $searchpicto = $form->showFilterButtons();
608 print $searchpicto;
609 print '</td>';
610}
611print '<td class="liste_titre">';
612print '<input class="flat" type="text" name="sref" size="6" value="'.dol_escape_htmltag($sref).'">';
613print '</td>';
614print '<td class="liste_titre">';
615print '<input class="flat" type="text" name="snom" size="8" value="'.dol_escape_htmltag($snom).'">';
616print '</td>';
617if (isModEnabled("service") && $type == 1) {
618 print '<td class="liste_titre">';
619 print '&nbsp;';
620 print '</td>';
621}
622
623print '<td class="liste_titre"><input class="flat" type="text" name="search_warehouse" size="6" value="'.dol_escape_htmltag($search_warehouse).'"></td>';
624print '<td class="liste_titre center"><input class="flat" type="text" name="search_batch" size="6" value="'.dol_escape_htmltag($search_batch).'"></td>';
625if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
626 print '<td class="liste_titre center">';
627 $key = 'sellby';
628 print '<div class="nowrap">';
629 print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
630 print '</div>';
631 print '<div class="nowrap">';
632 print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
633 print '</div>';
634 print '</td>';
635}
636if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
637 print '<td class="liste_titre center">';
638 $key = 'eatby';
639 print '<div class="nowrap">';
640 print $form->selectDate($search[$key.'_dtstart'] ? $search[$key.'_dtstart'] : '', "search_".$key."_dtstart", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
641 print '</div>';
642 print '<div class="nowrap">';
643 print $form->selectDate($search[$key.'_dtend'] ? $search[$key.'_dtend'] : '', "search_".$key."_dtend", 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
644 print '</div>';
645 print '</td>';
646}
647// Physical stock
648print '<td class="liste_titre right">';
649print '<input class="flat" type="text" size="5" name="search_stock_physique" value="'.dol_escape_htmltag($search_stock_physique).'">';
650print '</td>';
651print '<td class="liste_titre">&nbsp;</td>';
652print '<td class="liste_titre">&nbsp;</td>';
653print '<td class="liste_titre">&nbsp;</td>';
654$parameters = array();
655$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
656print $hookmanager->resPrint;
657// Action column
658if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
659 print '<td class="liste_titre maxwidthsearch">';
660 $searchpicto = $form->showFilterButtons();
661 print $searchpicto;
662 print '</td>';
663}
664print '</tr>'."\n";
665
666$totalarray = array();
667$totalarray['nbfield'] = 0;
668
669// Fields title label
670// --------------------------------------------------------------------
671print '<tr class="liste_titre">';
672// Action column
673if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
675}
676print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "p.ref", '', $param, "", $sortfield, $sortorder);
677print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "p.label", '', $param, "", $sortfield, $sortorder);
678if (isModEnabled("service") && $type == 1) {
679 print_liste_field_titre("Duration", $_SERVER["PHP_SELF"], "p.duration", '', $param, "", $sortfield, $sortorder, 'center ');
680}
681print_liste_field_titre("Warehouse", $_SERVER["PHP_SELF"], "e.ref", '', $param, "", $sortfield, $sortorder);
682//print_liste_field_titre("DesiredStock", $_SERVER["PHP_SELF"], "p.desiredstock",$param,"",'',$sortfield,$sortorder, 'right );
683print_liste_field_titre("Batch", $_SERVER["PHP_SELF"], "pb.batch", '', $param, "", $sortfield, $sortorder, 'center ');
684if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
685 print_liste_field_titre("SellByDate", $_SERVER["PHP_SELF"], "pl.sellby", '', $param, "", $sortfield, $sortorder, 'center ');
686}
687if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
688 print_liste_field_titre("EatByDate", $_SERVER["PHP_SELF"], "pl.eatby", '', $param, "", $sortfield, $sortorder, 'center ');
689}
690print_liste_field_titre("PhysicalStock", $_SERVER["PHP_SELF"], "stock_physique", '', $param, "", $sortfield, $sortorder, 'right ');
691// TODO Add info of running suppliers/customers orders
692//print_liste_field_titre("TheoreticalStock",$_SERVER["PHP_SELF"], "stock_theorique",$param,"",'',$sortfield,$sortorder, 'right ');
694print_liste_field_titre("ProductStatusOnSell", $_SERVER["PHP_SELF"], "p.tosell", "", $param, '', $sortfield, $sortorder, 'right ');
695print_liste_field_titre("ProductStatusOnBuy", $_SERVER["PHP_SELF"], "p.tobuy", "", $param, '', $sortfield, $sortorder, 'right ');
696// Hook fields
697$parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
698$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
699print $hookmanager->resPrint;
700if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
702}
703print "</tr>\n";
704
705$product_static = new Product($db);
706$product_lot_static = new Productlot($db);
707$warehousetmp = new Entrepot($db);
708
709// Loop on record
710// --------------------------------------------------------------------
711$i = 0;
712$savnbfield = $totalarray['nbfield'];
713$totalarray['nbfield'] = 0;
714$imaxinloop = ($limit ? min($num, $limit) : $num);
715while ($i < $imaxinloop) {
716 $objp = $db->fetch_object($resql);
717
718 // Multilangs
719 if (getDolGlobalInt('MAIN_MULTILANGS')) { // si l'option est active
720 // TODO Use a cache
721 $sql = "SELECT label";
722 $sql .= " FROM ".MAIN_DB_PREFIX."product_lang";
723 $sql .= " WHERE fk_product = ".((int) $objp->rowid);
724 $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
725 $sql .= " LIMIT 1";
726
727 $result = $db->query($sql);
728 if ($result) {
729 $objtp = $db->fetch_object($result);
730 if (!empty($objtp->label)) {
731 $objp->label = $objtp->label;
732 }
733 }
734 }
735
736 $product_static->ref = $objp->ref;
737 $product_static->id = $objp->rowid;
738 $product_static->label = $objp->label;
739 $product_static->type = $objp->fk_product_type;
740 $product_static->entity = $objp->entity;
741 $product_static->status = $objp->tosell;
742 $product_static->status_buy = $objp->tobuy;
743 $product_static->status_batch = $objp->tobatch;
744
745 $product_lot_static->batch = $objp->batch;
746 $product_lot_static->fk_product = $objp->rowid;
747 $product_lot_static->id = $objp->lotid;
748 $product_lot_static->eatby = $objp->eatby;
749 $product_lot_static->sellby = $objp->sellby;
750
751
752 $warehousetmp->id = $objp->fk_entrepot;
753 $warehousetmp->ref = $objp->warehouse_ref;
754 $warehousetmp->label = $objp->warehouse_ref;
755 $warehousetmp->fk_parent = $objp->warehouse_parent;
756
757 print '<tr>';
758
759 // Action column
760 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
761 print '<td></td>';
762 if (!$i) {
763 $totalarray['nbfield']++;
764 }
765 }
766
767 // Ref
768 print '<td class="tdoverflowmax250">';
769 print $product_static->getNomUrl(1);
770 //if ($objp->stock_theorique < $objp->seuil_stock_alerte) print ' '.img_warning($langs->trans("StockTooLow"));
771 print '</td>';
772 if (!$i) {
773 $totalarray['nbfield']++;
774 }
775
776 // Label
777 print '<td class="tdoverflowmax150">'.$objp->label.'</td>';
778 if (!$i) {
779 $totalarray['nbfield']++;
780 }
781
782 if (isModEnabled("service") && $type == 1) {
783 print '<td class="center">';
784 $regs = array();
785 if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) {
786 print $regs[1].' '.$langs->trans("DurationYear");
787 } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) {
788 print $regs[1].' '.$langs->trans("DurationMonth");
789 } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) {
790 print $regs[1].' '.$langs->trans("DurationDay");
791 } else {
792 print $objp->duration;
793 }
794 if (!$i) {
795 $totalarray['nbfield']++;
796 }
797 print '</td>';
798 }
799 //print '<td class="right">'.$objp->stock_theorique.'</td>';
800 //print '<td class="right">'.$objp->seuil_stock_alerte.'</td>';
801 //print '<td class="right">'.$objp->desiredstock.'</td>';
802
803 // Warehouse
804 print '<td class="nowrap">';
805 if ($objp->fk_entrepot > 0) {
806 print $warehousetmp->getNomUrl(1);
807 }
808 if (!$i) {
809 $totalarray['nbfield']++;
810 }
811 print '</td>';
812
813 // Lot
814 print '<td class="center nowrap">';
815 if ($product_lot_static->batch) {
816 print $product_lot_static->getNomUrl(1);
817 }
818 if (!$i) {
819 $totalarray['nbfield']++;
820 }
821 print '</td>';
822
823 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
824 print '<td class="center">'.dol_print_date($db->jdate($objp->sellby), 'day').'</td>';
825 if (!$i) {
826 $totalarray['nbfield']++;
827 }
828 }
829
830 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
831 print '<td class="center">'.dol_print_date($db->jdate($objp->eatby), 'day').'</td>';
832 if (!$i) {
833 $totalarray['nbfield']++;
834 }
835 }
836
837 print '<td class="right">';
838 //if ($objp->seuil_stock_alerte && ($objp->stock_physique < $objp->seuil_stock_alerte)) print img_warning($langs->trans("StockTooLow")).' ';
839 if (is_null($objp->stock_physique)) {
840 if (!empty($objp->reel)) {
841 if ($objp->reel < 0) {
842 print '<span class="warning">';
843 }
844 print price2num($objp->reel, 'MS');
845 if ($objp->reel < 0) {
846 print '</span>';
847 }
848 print($objp->stock_physique < 0 ? ' '.img_warning() : '');
849 }
850 } else {
851 if (!empty($objp->stock_physique)) {
852 if ($objp->stock_physique < 0) {
853 print '<span class="warning">';
854 }
855 print price2num($objp->stock_physique, 'MS');
856 if ($objp->stock_physique < 0) {
857 print '</span>';
858 }
859 print($objp->stock_physique < 0 ? ' '.img_warning() : (($objp->stock_physique > 1 && $objp->tobatch == 2) ? ' '.img_warning($langs->trans('IlligalQtyForSerialNumbers')) : ''));
860 }
861 }
862 print '</td>';
863 if (!$i) {
864 $totalarray['nbfield']++;
865 }
866
867 print '<td class="right">';
868 print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
869 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>';
870 print '</td>';
871 if (!$i) {
872 $totalarray['nbfield']++;
873 }
874
875 print '<td class="right nowrap">'.$product_static->LibStatut($objp->statut, 5, 0).'</td>';
876 if (!$i) {
877 $totalarray['nbfield']++;
878 }
879
880 print '<td class="right nowrap">'.$product_static->LibStatut($objp->tobuy, 5, 1).'</td>';
881 if (!$i) {
882 $totalarray['nbfield']++;
883 }
884
885 // Fields values from hook
886 $parameters = array('obj' => $objp);
887 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $product); // Note that $action and $object may have been modified by hook
888 print $hookmanager->resPrint;
889
890 // Action column
891 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
892 print '<td></td>';
893 if (!$i) {
894 $totalarray['nbfield']++;
895 }
896 }
897
898 print "</tr>\n";
899 $i++;
900}
901
902// If no record found
903if ($num == 0) {
904 $colspan = 2;
905 foreach ($arrayfields as $key => $val) {
906 if (!empty($val['checked'])) {
907 $colspan++;
908 }
909 }
910 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
911}
912
913
914$db->free($resql);
915
916print '</table>'."\n";
917print '</div>'."\n";
918
919print '</form>'."\n";
920
921
922// End of page
923llxFooter();
924$db->close();
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
$totalarray
Definition export.php:1206
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_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 '.
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 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.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
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.