dolibarr 18.0.6
reassort.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2015 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) 2019 Juanjo Menent <jmenent@2byte.es>
8 * Copyright (C) 2023 Vincent de Grandpré <vincent@de-grandpre.quebec>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
30// Load Dolibarr environment
31require '../main.inc.php';
32require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
34require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
35require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
36
37// Load translation files required by the page
38$langs->loadLangs(array('products', 'stocks'));
39
40$action = GETPOST('action', 'aZ09');
41$sref = GETPOST("sref", 'alpha');
42$snom = GETPOST("snom", 'alpha');
43$sall = trim((GETPOST('search_all', 'alphanohtml') != '') ?GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'));
44$type = GETPOSTISSET('type') ? GETPOST('type', 'int') : Product::TYPE_PRODUCT;
45$search_barcode = GETPOST("search_barcode", 'alpha');
46$search_toolowstock = GETPOST('search_toolowstock');
47$tosell = GETPOST("tosell");
48$tobuy = GETPOST("tobuy");
49$fourn_id = GETPOST("fourn_id", 'int');
50$sbarcode = GETPOST("sbarcode", 'int');
51$search_stock_physique = GETPOST('search_stock_physique', 'alpha');
52
53$sortfield = GETPOST('sortfield', 'aZ09comma');
54$sortorder = GETPOST('sortorder', 'aZ09comma');
55$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
56if (empty($page) || $page < 0) {
57 $page = 0;
58}
59if (!$sortfield) {
60 $sortfield = "p.ref";
61}
62if (!$sortorder) {
63 $sortorder = "ASC";
64}
65$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
66if (empty($page) || $page == -1) {
67 $page = 0;
68} // If $page is not defined, or '' or -1
69$offset = $limit * $page;
70
71// Load sale and categ filters
72$search_sale = GETPOST("search_sale");
73if (GETPOSTISSET('catid')) {
74 $search_categ = GETPOST('catid', 'int');
75} else {
76 $search_categ = GETPOST('search_categ', 'int');
77}
78
79// Get object canvas (By default, this is not defined, so standard usage of dolibarr)
80$canvas = GETPOST("canvas");
81$objcanvas = null;
82if (!empty($canvas)) {
83 require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
84 $objcanvas = new Canvas($db, $action);
85 $objcanvas->getCanvas('product', 'list', $canvas);
86}
87
88// Define virtualdiffersfromphysical
89$virtualdiffersfromphysical = 0;
90if (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)
91 || !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)
92 || !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)
93 || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)
94 || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)
95 || isModEnabled('mrp')) {
96 $virtualdiffersfromphysical = 1; // According to increase/decrease stock options, virtual and physical stock may differs.
97}
98
99// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
100$hookmanager->initHooks(array('productreassortlist'));
101
102if ($user->socid) {
103 $socid = $user->socid;
104}
105$result = restrictedArea($user, 'produit|service', 0, 'product&product');
106
107$object = new Product($db);
108
109/*
110 * Actions
111 */
112
113if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
114 $sref = "";
115 $snom = "";
116 $sall = "";
117 $tosell = "";
118 $tobuy = "";
119 $search_sale = "";
120 $search_categ = "";
121 $search_toolowstock = '';
122 $fourn_id = '';
123 $sbarcode = '';
124 $search_stock_physique = '';
125}
126
127
128
129/*
130 * View
131 */
132
133$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
134
135$form = new Form($db);
136$htmlother = new FormOther($db);
137if (!empty($objp->stock_physique) && $objp->stock_physique < 0) { print '<span class="warning">'; }
138
139$sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
140$sql .= ' p.fk_product_type, p.tms as datem,';
141$sql .= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte, p.desiredstock,';
142$sql .= ' SUM(s.reel) as stock_physique';
143if (!empty($conf->global->PRODUCT_USE_UNITS)) {
144 $sql .= ', u.short_label as unit_short';
145}
146// Add fields from hooks
147$parameters = array();
148$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook
149$sql .= $hookmanager->resPrint;
150$sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
151$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s ON p.rowid = s.fk_product';
152if (!empty($conf->global->PRODUCT_USE_UNITS)) {
153 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_units as u on p.fk_unit = u.rowid';
154}
155// Add table from hooks
156$parameters = array();
157$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook
158$sql .= $hookmanager->resPrint;
159$sql .= " WHERE p.entity IN (".getEntity('product').")";
160if (!empty($search_categ) && $search_categ != '-1') {
161 $sql .= " AND ";
162 if ($search_categ == -2) {
163 $sql .= " NOT EXISTS ";
164 } else {
165 $sql .= " EXISTS ";
166 }
167 $sql .= "(";
168 $sql .= " SELECT cp.fk_categorie, cp.fk_product";
169 $sql .= " FROM " . MAIN_DB_PREFIX . "categorie_product as cp";
170 $sql .= " WHERE cp.fk_product = p.rowid"; // Join for the needed table to filter by categ
171 if ($search_categ > 0) {
172 $sql .= " AND cp.fk_categorie = " . ((int) $search_categ);
173 }
174 $sql .= ")";
175}
176if (empty($conf->global->PRODUCT_STOCK_LIST_SHOW_VIRTUAL_WITH_NO_PHYSICAL)) {
177 $sql .= " AND EXISTS (SELECT e.rowid FROM ".MAIN_DB_PREFIX."entrepot as e WHERE e.rowid = s.fk_entrepot AND e.entity IN (".getEntity('stock')."))";
178} else {
179 $sql .= " AND
180 (
181 EXISTS
182 (SELECT e.rowid
183 FROM ".MAIN_DB_PREFIX."entrepot as e
184 WHERE e.rowid = s.fk_entrepot AND e.entity IN (".getEntity('stock')."))
185 OR (
186 SELECT SUM(cd1.qty) as qty
187 FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd1
188 LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseur as c1
189 ON c1.rowid = cd1.fk_commande
190 WHERE c1.entity IN (1) AND cd1.fk_product = p.rowid AND c1.fk_statut in (3,4) AND cd1.qty <> 0
191 ) IS NOT NULL
192 OR (
193 SELECT SUM(cd2.qty) as qty
194 FROM ".MAIN_DB_PREFIX."commandedet as cd2
195 LEFT JOIN ".MAIN_DB_PREFIX."commande as c2 ON c2.rowid = cd2.fk_commande
196 WHERE c2.entity IN (1) AND cd2.fk_product = p.rowid AND c2.fk_statut in (1,2) AND cd2.qty <> 0
197 ) IS NOT NULL
198 OR (
199 SELECT SUM(ed3.qty) as qty
200 FROM ".MAIN_DB_PREFIX."expeditiondet as ed3
201 LEFT JOIN ".MAIN_DB_PREFIX."expedition as e3 ON e3.rowid = ed3.fk_expedition
202 LEFT JOIN ".MAIN_DB_PREFIX."commandedet as cd3 ON ed3.fk_origin_line = cd3.rowid
203 LEFT JOIN ".MAIN_DB_PREFIX."commande as c3 ON c3.rowid = cd3.fk_commande
204 WHERE e3.entity IN (1) AND cd3.fk_product = p.rowid AND c3.fk_statut IN (1,2) AND e3.fk_statut IN (1,2) AND ed3.qty <> 0
205 ) IS NOT NULL
206 OR (
207 SELECT SUM(mp4.qty) as qty
208 FROM ".MAIN_DB_PREFIX."mrp_production as mp4
209 LEFT JOIN ".MAIN_DB_PREFIX."mrp_mo as m4 ON m4.rowid = mp4.fk_mo AND m4.entity IN (1) AND m4.status IN (1,2)
210 WHERE mp4.fk_product = p.rowid AND mp4.qty <> 0
211 ) IS NOT NULL
212 ) ";
213}
214if ($sall) {
215 $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $sall);
216}
217// if the type is not 1, we show all products (type = 0,2,3)
218if (dol_strlen($type)) {
219 if ($type == 1) {
220 $sql .= " AND p.fk_product_type = '1'";
221 } else {
222 $sql .= " AND p.fk_product_type <> '1'";
223 }
224}
225if ($sref) {
226 $sql .= natural_search('p.ref', $sref);
227}
228if ($search_barcode) {
229 $sql .= natural_search('p.barcode', $search_barcode);
230}
231if ($snom) {
232 $sql .= natural_search('p.label', $snom);
233}
234if (!empty($tosell)) {
235 $sql .= " AND p.tosell = ".((int) $tosell);
236}
237if (!empty($tobuy)) {
238 $sql .= " AND p.tobuy = ".((int) $tobuy);
239}
240if (!empty($canvas)) {
241 $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
242}
243if ($fourn_id > 0) {
244 $sql .= " AND p.rowid = pf.fk_product AND pf.fk_soc = ".((int) $fourn_id);
245}
246// Add where from hooks
247$parameters = array();
248$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
249$sql .= $hookmanager->resPrint;
250$sql .= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,";
251$sql .= " p.fk_product_type, p.tms, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock";
252
253// Add GROUP BY from hooks
254$parameters = array();
255$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook
256$sql .= $hookmanager->resPrint;
257
258$sql_having = '';
259if ($search_toolowstock) {
260 $sql_having .= " HAVING SUM(".$db->ifsql('s.reel IS NULL', '0', 's.reel').") < p.seuil_stock_alerte";
261}
262if ($search_stock_physique != '') {
263 //$natural_search_physique = natural_search('HAVING SUM(' . $db->ifsql('s.reel IS NULL', '0', 's.reel') . ')', $search_stock_physique, 1, 1);
264 $natural_search_physique = natural_search('SUM(' . $db->ifsql('s.reel IS NULL', '0', 's.reel') . ')', $search_stock_physique, 1, 1);
265 $natural_search_physique = " " . substr($natural_search_physique, 1, -1); // remove first "(" and last ")" characters
266 if (!empty($sql_having)) {
267 $sql_having .= " AND";
268 } else {
269 $sql_having .= " HAVING";
270 }
271 $sql_having .= $natural_search_physique;
272}
273
274// Add HAVING from hooks
275$parameters = array();
276$reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook
277if (!empty($hookmanager->resPrint)) {
278 if (!empty($sql_having)) {
279 $sql_having .= " AND";
280 } else {
281 $sql_having .= " HAVING";
282 }
283 $sql_having .= $hookmanager->resPrint;
284}
285
286if (!empty($sql_having)) {
287 $sql .= $sql_having;
288}
289$sql .= $db->order($sortfield, $sortorder);
290
291// Count total nb of records
292$nbtotalofrecords = '';
293if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
294 $result = $db->query($sql);
295 $nbtotalofrecords = $db->num_rows($result);
296 if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
297 $page = 0;
298 $offset = 0;
299 }
300}
301
302$sql .= $db->plimit($limit + 1, $offset);
303
304$resql = $db->query($sql);
305if ($resql) {
306 $num = $db->num_rows($resql);
307
308 $i = 0;
309
310 if ($num == 1 && GETPOST('autojumpifoneonly') && ($sall || $snom || $sref)) {
311 $objp = $db->fetch_object($resql);
312 header("Location: card.php?id=$objp->rowid");
313 exit;
314 }
315
316 if (isset($type)) {
317 if ($type == 1) {
318 $texte = $langs->trans("Services");
319 } else {
320 $texte = $langs->trans("Products");
321 }
322 } else {
323 $texte = $langs->trans("ProductsAndServices");
324 }
325 $texte .= ' ('.$langs->trans("MenuStocks").')';
326
327 $param = '';
328 if ($limit > 0 && $limit != $conf->liste_limit) {
329 $param .= '&limit='.((int) $limit);
330 }
331 if ($sall) {
332 $param .= "&sall=".urlencode($sall);
333 }
334 if ($tosell) {
335 $param .= "&tosell=".urlencode($tosell);
336 }
337 if ($tobuy) {
338 $param .= "&tobuy=".urlencode($tobuy);
339 }
340 if ($type != '') {
341 $param .= "&type=".urlencode($type);
342 }
343 if ($fourn_id) {
344 $param .= "&fourn_id=".urlencode($fourn_id);
345 }
346 if ($snom) {
347 $param .= "&snom=".urlencode($snom);
348 }
349 if ($sref) {
350 $param .= "&sref=".urlencode($sref);
351 }
352 if ($search_sale) {
353 $param .= "&search_sale=".urlencode($search_sale);
354 }
355 if ($search_categ > 0) {
356 $param .= "&search_categ=".urlencode($search_categ);
357 }
358 if ($search_toolowstock) {
359 $param .= "&search_toolowstock=".urlencode($search_toolowstock);
360 }
361 if ($sbarcode) {
362 $param .= "&sbarcode=".urlencode($sbarcode);
363 }
364 if ($search_stock_physique) {
365 $param .= '&search_stock_physique=' . urlencode($search_stock_physique);
366 }
367
368 llxHeader("", $texte, $helpurl);
369
370 print '<form action="'.$_SERVER["PHP_SELF"].'" method="post" name="formulaire">';
371 print '<input type="hidden" name="token" value="'.newToken().'">';
372 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
373 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
374 print '<input type="hidden" name="page" value="'.$page.'">';
375 print '<input type="hidden" name="type" value="'.$type.'">';
376
377 print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit);
378
379 if ($search_categ > 0) {
380 print "<div id='ways'>";
381 $c = new Categorie($db);
382 $c->fetch($search_categ);
383 $ways = $c->print_all_ways(' &gt; ', 'product/reassort.php');
384 print " &gt; ".$ways[0]."<br>\n";
385 print "</div><br>";
386 }
387
388 // Filter on categories
389 $moreforfilter = '';
390 if (isModEnabled('categorie')) {
391 $moreforfilter .= '<div class="divsearchfield">';
392 $moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"');
393 $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_PRODUCT, $search_categ, 'search_categ', 1);
394 $moreforfilter .= '</div>';
395 }
396
397 $moreforfilter .= '<div class="divsearchfield">';
398 $moreforfilter .= '<label for="search_toolowstock">'.$langs->trans("StockTooLow").' </label><input type="checkbox" id="search_toolowstock" name="search_toolowstock" value="1"'.($search_toolowstock ? ' checked' : '').'>';
399 $moreforfilter .= '</div>';
400
401 if (!empty($moreforfilter)) {
402 print '<div class="liste_titre liste_titre_bydiv centpercent">';
403 print $moreforfilter;
404 $parameters = array();
405 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
406 print $hookmanager->resPrint;
407 print '</div>';
408 }
409
410 $formProduct = new FormProduct($db);
411 $formProduct->loadWarehouses();
412 $warehouses_list = $formProduct->cache_warehouses;
413 $nb_warehouse = count($warehouses_list);
414 $colspan_warehouse = 1;
415 if (!empty($conf->global->STOCK_DETAIL_ON_WAREHOUSE)) {
416 $colspan_warehouse = $nb_warehouse > 1 ? $nb_warehouse + 1 : 1;
417 }
418
419 print '<div class="div-table-responsive">';
420 print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
421
422 // Fields title search
423 print '<tr class="liste_titre_filter">';
424 // Action column
425 if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
426 print '<td class="liste_titre maxwidthsearch">';
427 $searchpicto = $form->showFilterAndCheckAddButtons(0);
428 print $searchpicto;
429 print '</td>';
430 }
431 print '<td class="liste_titre">';
432 print '<input class="flat" type="text" name="sref" size="6" value="'.$sref.'">';
433 print '</td>';
434 print '<td class="liste_titre">';
435 print '<input class="flat" type="text" name="snom" size="8" value="'.$snom.'">';
436 print '</td>';
437 // Duration
438 if (isModEnabled("service") && $type == 1) {
439 print '<td class="liste_titre">';
440 print '&nbsp;';
441 print '</td>';
442 }
443 // Stock limit
444 print '<td class="liste_titre">&nbsp;</td>';
445 print '<td class="liste_titre right">&nbsp;</td>';
446 // Physical stock
447 print '<td class="liste_titre right">';
448 print '<input class="flat" type="text" size="5" name="search_stock_physique" value="'.dol_escape_htmltag($search_stock_physique).'">';
449 print '</td>';
450 if ($virtualdiffersfromphysical) {
451 print '<td class="liste_titre">&nbsp;</td>';
452 }
453 print '<td class="liste_titre">&nbsp;</td>';
454 print '<td class="liste_titre" colspan="'.$colspan_warehouse.'">&nbsp;</td>';
455 print '<td class="liste_titre"></td>';
456 $parameters = array();
457 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
458 print $hookmanager->resPrint;
459 if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
460 print '<td class="liste_titre maxwidthsearch">';
461 $searchpicto = $form->showFilterAndCheckAddButtons(0);
462 print $searchpicto;
463 print '</td>';
464 }
465 print '</tr>';
466
467 // Line for column titles
468 print '<tr class="liste_titre">';
469 // Action column
470 if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
472 }
473 print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "p.ref", '', $param, "", $sortfield, $sortorder);
474 print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "p.label", '', $param, "", $sortfield, $sortorder);
475 if (isModEnabled("service") && $type == 1) {
476 print_liste_field_titre("Duration", $_SERVER["PHP_SELF"], "p.duration", '', $param, "", $sortfield, $sortorder, 'center ');
477 }
478 print_liste_field_titre("StockLimit", $_SERVER["PHP_SELF"], "p.seuil_stock_alerte", '', $param, "", $sortfield, $sortorder, 'right ');
479 print_liste_field_titre("DesiredStock", $_SERVER["PHP_SELF"], "p.desiredstock", '', $param, "", $sortfield, $sortorder, 'right ');
480 print_liste_field_titre("PhysicalStock", $_SERVER["PHP_SELF"], "stock_physique", '', $param, "", $sortfield, $sortorder, 'right ');
481 // Details per warehouse
482 if (!empty($conf->global->STOCK_DETAIL_ON_WAREHOUSE)) { // TODO This should be moved into the selection of fields on page product/list (page product/stock will be removed and replaced with product/list with its own context)
483 if ($nb_warehouse > 1) {
484 foreach ($warehouses_list as &$wh) {
485 print_liste_field_titre($wh['label'], '', '', '', '', '', '', '', 'right ');
486 }
487 }
488 }
489 if ($virtualdiffersfromphysical) {
490 print_liste_field_titre("VirtualStock", $_SERVER["PHP_SELF"], "", '', $param, "", $sortfield, $sortorder, 'right ', 'VirtualStockDesc');
491 }
492 // Units
493 if (!empty($conf->global->PRODUCT_USE_UNITS)) {
494 print_liste_field_titre("Unit", $_SERVER["PHP_SELF"], "unit_short", '', $param, 'align="right"', $sortfield, $sortorder);
495 }
497 print_liste_field_titre("ProductStatusOnSell", $_SERVER["PHP_SELF"], "p.tosell", '', $param, "", $sortfield, $sortorder, 'right ');
498 print_liste_field_titre("ProductStatusOnBuy", $_SERVER["PHP_SELF"], "p.tobuy", '', $param, "", $sortfield, $sortorder, 'right ');
499 // Hook fields
500 $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
501 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
502 print $hookmanager->resPrint;
503 // Action column
504 if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
506 }
507 print "</tr>\n";
508
509 while ($i < min($num, $limit)) {
510 $objp = $db->fetch_object($resql);
511
512 $product = new Product($db);
513 $product->fetch($objp->rowid);
514 $product->load_stock();
515
516 print '<tr>';
517 // Action column
518 if (!empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
519 print '<td></td>';
520 }
521 print '<td class="nowrap">';
522 print $product->getNomUrl(1, '', 16);
523 //if ($objp->stock_theorique < $objp->seuil_stock_alerte) print ' '.img_warning($langs->trans("StockTooLow"));
524 print '</td>';
525 print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($product->label).'">'.dol_escape_htmltag($product->label).'</td>';
526
527 if (isModEnabled("service") && $type == 1) {
528 print '<td class="center">';
529 if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) {
530 print $regs[1].' '.$langs->trans("DurationYear");
531 } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) {
532 print $regs[1].' '.$langs->trans("DurationMonth");
533 } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) {
534 print $regs[1].' '.$langs->trans("DurationDay");
535 } else {
536 print $objp->duration;
537 }
538 print '</td>';
539 }
540 //print '<td class="right">'.$objp->stock_theorique.'</td>';
541 print '<td class="right">';
542 print $objp->seuil_stock_alerte;
543 print '</td>';
544 print '<td class="right">';
545 print $objp->desiredstock;
546 print '</td>';
547 // Real stock
548 print '<td class="right">';
549 if ($objp->seuil_stock_alerte != '' && ($objp->stock_physique < $objp->seuil_stock_alerte)) {
550 print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
551 }
552 if ($objp->stock_physique < 0) { print '<span class="warning">'; }
553 print price(price2num($objp->stock_physique, 'MS'), 0, $langs, 1, 0);
554 if ($objp->stock_physique < 0) { print '</span>'; }
555 print '</td>';
556
557 // Details per warehouse
558 if (!empty($conf->global->STOCK_DETAIL_ON_WAREHOUSE)) { // TODO This should be moved into the selection of fields on page product/list (page product/stock will be removed and replaced with product/list with its own context)
559 if ($nb_warehouse > 1) {
560 foreach ($warehouses_list as &$wh) {
561 print '<td class="right">';
562 print price(empty($product->stock_warehouse[$wh['id']]->real) ? 0 : price2num($product->stock_warehouse[$wh['id']]->real, 'MS'), 0, $langs, 1, 0);
563 print '</td>';
564 }
565 }
566 }
567
568 // Virtual stock
569 if ($virtualdiffersfromphysical) {
570 print '<td class="right">';
571 if ($objp->seuil_stock_alerte != '' && ($product->stock_theorique < (float) $objp->seuil_stock_alerte)) {
572 print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
573 }
574 if ($objp->stock_physique < 0) { print '<span class="warning">'; }
575 print price(price2num($product->stock_theorique, 'MS'), 0, $langs, 1, 0);
576 if ($objp->stock_physique < 0) { print '</span>'; }
577 print '</td>';
578 }
579 // Units
580 if (!empty($conf->global->PRODUCT_USE_UNITS)) {
581 print '<td class="left">'.dol_escape_htmltag($objp->unit_short).'</td>';
582 }
583 print '<td class="center nowraponall">';
584 print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
585 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$product->id.'">'.$langs->trans("Movements").'</a>';
586 print '</td>';
587 print '<td class="right nowrap">'.$product->LibStatut($objp->statut, 5, 0).'</td>';
588 print '<td class="right nowrap">'.$product->LibStatut($objp->tobuy, 5, 1).'</td>';
589 // Fields from hook
590 $parameters = array('obj'=>$objp);
591 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $product); // Note that $action and $object may have been modified by hook
592 print $hookmanager->resPrint;
593 // Action column
594 if (empty($conf->global->MAIN_CHECKBOX_LEFT_COLUMN)) {
595 print '<td></td>';
596 }
597
598 print "</tr>\n";
599 $i++;
600 }
601
602 print "</table>";
603 print '</div>';
604
605 print '</form>';
606
607 $db->free($resql);
608} else {
609 dol_print_error($db);
610}
611
612// End of page
613llxFooter();
614$db->close();
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:56
llxFooter()
Empty footer.
Definition wrapper.php:70
Class to manage canvas.
Class to manage categories.
Class to manage generation of HTML components Only common components must be here.
Classe permettant la generation de composants html autre Only common components are here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage products or services.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
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.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
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.