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