dolibarr 20.0.0
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') ? GETPOSTINT('type') : 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 = GETPOSTINT("fourn_id");
50$sbarcode = GETPOSTINT("sbarcode");
51$search_stock_physique = GETPOST('search_stock_physique', 'alpha');
52
53$sortfield = GETPOST('sortfield', 'aZ09comma');
54$sortorder = GETPOST('sortorder', 'aZ09comma');
55$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
56if (empty($page) || $page < 0) {
57 $page = 0;
58}
59if (!$sortfield) {
60 $sortfield = "p.ref";
61}
62if (!$sortorder) {
63 $sortorder = "ASC";
64}
65$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $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 = GETPOSTINT('catid');
75} else {
76 $search_categ = GETPOSTINT('search_categ');
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 (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')
91 || getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER')
92 || getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')
93 || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION')
94 || getDolGlobalString('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$result = restrictedArea($user, 'stock');
107
108$object = new Product($db);
109
110
111/*
112 * Actions
113 */
114
115if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
116 $sref = "";
117 $snom = "";
118 $sall = "";
119 $tosell = "";
120 $tobuy = "";
121 $search_sale = "";
122 $search_categ = "";
123 $search_toolowstock = '';
124 $fourn_id = '';
125 $sbarcode = '';
126 $search_stock_physique = '';
127}
128
129
130
131/*
132 * View
133 */
134
135$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
136
137$form = new Form($db);
138$htmlother = new FormOther($db);
139if (!empty($objp->stock_physique) && $objp->stock_physique < 0) {
140 print '<span class="warning">';
141}
142
143$sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
144$sql .= ' p.fk_product_type, p.tms as datem,';
145$sql .= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte, p.desiredstock,';
146if (getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
147 $sql .= ' p.stock as stock_physique';
148} else {
149 $sql .= ' SUM(s.reel) as stock_physique';
150}
151if (getDolGlobalString('PRODUCT_USE_UNITS')) {
152 $sql .= ', u.short_label as unit_short';
153}
154// Add fields from hooks
155$parameters = array();
156$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook
157$sql .= $hookmanager->resPrint;
158$sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
159if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
160 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product_stock as s ON p.rowid = s.fk_product';
161}
162if (getDolGlobalString('PRODUCT_USE_UNITS')) {
163 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_units as u on p.fk_unit = u.rowid';
164}
165// Add table from hooks
166$parameters = array();
167$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook
168$sql .= $hookmanager->resPrint;
169$sql .= " WHERE p.entity IN (".getEntity('product').")";
170if (!empty($search_categ) && $search_categ != '-1') {
171 $sql .= " AND ";
172 if ($search_categ == -2) {
173 $sql .= " NOT EXISTS ";
174 } else {
175 $sql .= " EXISTS ";
176 }
177 $sql .= "(";
178 $sql .= " SELECT cp.fk_categorie, cp.fk_product";
179 $sql .= " FROM " . MAIN_DB_PREFIX . "categorie_product as cp";
180 $sql .= " WHERE cp.fk_product = p.rowid"; // Join for the needed table to filter by categ
181 if ($search_categ > 0) {
182 $sql .= " AND cp.fk_categorie = " . ((int) $search_categ);
183 }
184 $sql .= ")";
185}
186if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
187 if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_VIRTUAL_WITH_NO_PHYSICAL')) {
188 $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') . "))";
189 } else {
190 $sql .= " AND
191 (
192 EXISTS
193 (SELECT e.rowid
194 FROM " . MAIN_DB_PREFIX . "entrepot as e
195 WHERE e.rowid = s.fk_entrepot AND e.entity IN (" . getEntity('stock') . "))
196 OR (
197 SELECT SUM(cd1.qty) as qty
198 FROM " . MAIN_DB_PREFIX . "commande_fournisseurdet as cd1
199 LEFT JOIN " . MAIN_DB_PREFIX . "commande_fournisseur as c1
200 ON c1.rowid = cd1.fk_commande
201 WHERE c1.entity IN (1) AND cd1.fk_product = p.rowid AND c1.fk_statut in (3,4) AND cd1.qty <> 0
202 ) IS NOT NULL
203 OR (
204 SELECT SUM(cd2.qty) as qty
205 FROM " . MAIN_DB_PREFIX . "commandedet as cd2
206 LEFT JOIN " . MAIN_DB_PREFIX . "commande as c2 ON c2.rowid = cd2.fk_commande
207 WHERE c2.entity IN (1) AND cd2.fk_product = p.rowid AND c2.fk_statut in (1,2) AND cd2.qty <> 0
208 ) IS NOT NULL
209 OR (
210 SELECT SUM(ed3.qty) as qty
211 FROM " . MAIN_DB_PREFIX . "expeditiondet as ed3
212 LEFT JOIN " . MAIN_DB_PREFIX . "expedition as e3 ON e3.rowid = ed3.fk_expedition
213 LEFT JOIN " . MAIN_DB_PREFIX . "commandedet as cd3 ON ed3.fk_elementdet = cd3.rowid
214 LEFT JOIN " . MAIN_DB_PREFIX . "commande as c3 ON c3.rowid = cd3.fk_commande
215 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
216 ) IS NOT NULL
217 OR (
218 SELECT SUM(mp4.qty) as qty
219 FROM " . MAIN_DB_PREFIX . "mrp_production as mp4
220 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)
221 WHERE mp4.fk_product = p.rowid AND mp4.qty <> 0
222 ) IS NOT NULL
223 ) ";
224 }
225}
226if ($sall) {
227 $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $sall);
228}
229// if the type is not 1, we show all products (type = 0,2,3)
230if (dol_strlen($type)) {
231 if ($type == 1) {
232 $sql .= " AND p.fk_product_type = '1'";
233 } else {
234 $sql .= " AND p.fk_product_type <> '1'";
235 }
236}
237if ($sref) {
238 $sql .= natural_search('p.ref', $sref);
239}
240if ($search_barcode) {
241 $sql .= natural_search('p.barcode', $search_barcode);
242}
243if ($snom) {
244 $sql .= natural_search('p.label', $snom);
245}
246if (!empty($tosell)) {
247 $sql .= " AND p.tosell = ".((int) $tosell);
248}
249if (!empty($tobuy)) {
250 $sql .= " AND p.tobuy = ".((int) $tobuy);
251}
252if (!empty($canvas)) {
253 $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
254}
255if ($fourn_id > 0) {
256 $sql .= " AND p.rowid = pf.fk_product AND pf.fk_soc = ".((int) $fourn_id);
257}
258if (getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
259 if ($search_toolowstock) {
260 $sql .= " AND p.stock < p.seuil_stock_alerte";
261 }
262 if ($search_stock_physique != '') {
263 $sql .= natural_search('p.stock', $search_stock_physique, 1, 1);
264 }
265}
266// Add where from hooks
267$parameters = array();
268$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
269$sql .= $hookmanager->resPrint;
270if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
271 $sql .= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,";
272 $sql .= " p.fk_product_type, p.tms, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock";
273}
274
275// Add GROUP BY from hooks
276$parameters = array();
277$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook
278$sql .= $hookmanager->resPrint;
279
280$sql_having = '';
281if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
282 if ($search_toolowstock) {
283 $sql_having .= " HAVING SUM(" . $db->ifsql('s.reel IS NULL', '0', 's.reel') . ") < p.seuil_stock_alerte";
284 }
285 if ($search_stock_physique != '') {
286 //$natural_search_physique = natural_search('HAVING SUM(' . $db->ifsql('s.reel IS NULL', '0', 's.reel') . ')', $search_stock_physique, 1, 1);
287 $natural_search_physique = natural_search('SUM(' . $db->ifsql('s.reel IS NULL', '0', 's.reel') . ')', $search_stock_physique, 1, 1);
288 $natural_search_physique = " " . substr($natural_search_physique, 1, -1); // remove first "(" and last ")" characters
289 if (!empty($sql_having)) {
290 $sql_having .= " AND";
291 } else {
292 $sql_having .= " HAVING";
293 }
294 $sql_having .= $natural_search_physique;
295 }
296}
297
298// Add HAVING from hooks
299$parameters = array();
300$reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook
301if (!empty($hookmanager->resPrint)) {
302 if (!empty($sql_having)) {
303 $sql_having .= " AND";
304 } else {
305 $sql_having .= " HAVING";
306 }
307 $sql_having .= $hookmanager->resPrint;
308}
309
310if (!empty($sql_having)) {
311 $sql .= $sql_having;
312}
313$sql .= $db->order($sortfield, $sortorder);
314
315// Count total nb of records
316$nbtotalofrecords = '';
317if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
318 $result = $db->query($sql);
319 $nbtotalofrecords = $db->num_rows($result);
320 if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
321 $page = 0;
322 $offset = 0;
323 }
324}
325
326$sql .= $db->plimit($limit + 1, $offset);
327
328$resql = $db->query($sql);
329if ($resql) {
330 $num = $db->num_rows($resql);
331
332 $i = 0;
333
334 if ($num == 1 && GETPOST('autojumpifoneonly') && ($sall || $snom || $sref)) {
335 $objp = $db->fetch_object($resql);
336 header("Location: card.php?id=$objp->rowid");
337 exit;
338 }
339
340 if (isset($type)) {
341 if ($type == 1) {
342 $texte = $langs->trans("Services");
343 } else {
344 $texte = $langs->trans("Products");
345 }
346 } else {
347 $texte = $langs->trans("ProductsAndServices");
348 }
349 $texte .= ' ('.$langs->trans("MenuStocks").')';
350
351 $param = '';
352 if ($limit > 0 && $limit != $conf->liste_limit) {
353 $param .= '&limit='.((int) $limit);
354 }
355 if ($sall) {
356 $param .= "&sall=".urlencode($sall);
357 }
358 if ($tosell) {
359 $param .= "&tosell=".urlencode($tosell);
360 }
361 if ($tobuy) {
362 $param .= "&tobuy=".urlencode($tobuy);
363 }
364 if ($type != '') {
365 $param .= "&type=".urlencode((string) ($type));
366 }
367 if ($fourn_id) {
368 $param .= "&fourn_id=".urlencode((string) ($fourn_id));
369 }
370 if ($snom) {
371 $param .= "&snom=".urlencode($snom);
372 }
373 if ($sref) {
374 $param .= "&sref=".urlencode($sref);
375 }
376 if ($search_sale) {
377 $param .= "&search_sale=".urlencode($search_sale);
378 }
379 if ($search_categ > 0) {
380 $param .= "&search_categ=".urlencode((string) ($search_categ));
381 }
382 if ($search_toolowstock) {
383 $param .= "&search_toolowstock=".urlencode($search_toolowstock);
384 }
385 if ($sbarcode) {
386 $param .= "&sbarcode=".urlencode((string) ($sbarcode));
387 }
388 if ($search_stock_physique) {
389 $param .= '&search_stock_physique=' . urlencode($search_stock_physique);
390 }
391
392 llxHeader("", $texte, $helpurl, '', 0, 0, '', '', '', 'mod-product page-reassort');
393
394 print '<form action="'.$_SERVER["PHP_SELF"].'" method="post" name="formulaire">';
395 print '<input type="hidden" name="token" value="'.newToken().'">';
396 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
397 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
398 print '<input type="hidden" name="page" value="'.$page.'">';
399 print '<input type="hidden" name="type" value="'.$type.'">';
400
401 print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit);
402
403 if ($search_categ > 0) {
404 print "<div id='ways'>";
405 $c = new Categorie($db);
406 $c->fetch($search_categ);
407 $ways = $c->print_all_ways(' &gt; ', 'product/reassort.php');
408 print " &gt; ".$ways[0]."<br>\n";
409 print "</div><br>";
410 }
411
412 // Filter on categories
413 $moreforfilter = '';
414 if (isModEnabled('category')) {
415 $moreforfilter .= '<div class="divsearchfield">';
416 $moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"');
417 $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_PRODUCT, $search_categ, 'search_categ', 1);
418 $moreforfilter .= '</div>';
419 }
420
421 $moreforfilter .= '<div class="divsearchfield">';
422 $moreforfilter .= '<label for="search_toolowstock">'.$langs->trans("StockTooLow").' </label><input type="checkbox" id="search_toolowstock" name="search_toolowstock" value="1"'.($search_toolowstock ? ' checked' : '').'>';
423 $moreforfilter .= '</div>';
424
425 if (!empty($moreforfilter)) {
426 print '<div class="liste_titre liste_titre_bydiv centpercent">';
427 print $moreforfilter;
428 $parameters = array();
429 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
430 print $hookmanager->resPrint;
431 print '</div>';
432 }
433
434 $formProduct = new FormProduct($db);
435 $formProduct->loadWarehouses();
436 $warehouses_list = $formProduct->cache_warehouses;
437 $nb_warehouse = count($warehouses_list);
438 $colspan_warehouse = 1;
439 if (getDolGlobalString('STOCK_DETAIL_ON_WAREHOUSE')) {
440 $colspan_warehouse = $nb_warehouse > 1 ? $nb_warehouse + 1 : 1;
441 }
442
443 print '<div class="div-table-responsive">';
444 print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
445
446 // Fields title search
447 print '<tr class="liste_titre_filter">';
448 // Action column
449 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
450 print '<td class="liste_titre maxwidthsearch">';
451 $searchpicto = $form->showFilterAndCheckAddButtons(0);
452 print $searchpicto;
453 print '</td>';
454 }
455 print '<td class="liste_titre">';
456 print '<input class="flat" type="text" name="sref" size="6" value="'.$sref.'">';
457 print '</td>';
458 print '<td class="liste_titre">';
459 print '<input class="flat" type="text" name="snom" size="8" value="'.$snom.'">';
460 print '</td>';
461 // Duration
462 if (isModEnabled("service") && $type == 1) {
463 print '<td class="liste_titre">';
464 print '&nbsp;';
465 print '</td>';
466 }
467 // Stock limit
468 print '<td class="liste_titre">&nbsp;</td>';
469 print '<td class="liste_titre right">&nbsp;</td>';
470 // Physical stock
471 print '<td class="liste_titre right">';
472 print '<input class="flat" type="text" size="5" name="search_stock_physique" value="'.dol_escape_htmltag($search_stock_physique).'">';
473 print '</td>';
474 if ($virtualdiffersfromphysical) {
475 print '<td class="liste_titre">&nbsp;</td>';
476 }
477 print '<td class="liste_titre">&nbsp;</td>';
478 print '<td class="liste_titre" colspan="'.$colspan_warehouse.'">&nbsp;</td>';
479 print '<td class="liste_titre"></td>';
480 $parameters = array();
481 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
482 print $hookmanager->resPrint;
483 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
484 print '<td class="liste_titre maxwidthsearch">';
485 $searchpicto = $form->showFilterAndCheckAddButtons(0);
486 print $searchpicto;
487 print '</td>';
488 }
489 print '</tr>';
490
491 // Line for column titles
492 print '<tr class="liste_titre">';
493 // Action column
494 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
496 }
497 print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "p.ref", '', $param, "", $sortfield, $sortorder);
498 print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "p.label", '', $param, "", $sortfield, $sortorder);
499 if (isModEnabled("service") && $type == 1) {
500 print_liste_field_titre("Duration", $_SERVER["PHP_SELF"], "p.duration", '', $param, "", $sortfield, $sortorder, 'center ');
501 }
502 print_liste_field_titre("StockLimit", $_SERVER["PHP_SELF"], "p.seuil_stock_alerte", '', $param, "", $sortfield, $sortorder, 'right ');
503 print_liste_field_titre("DesiredStock", $_SERVER["PHP_SELF"], "p.desiredstock", '', $param, "", $sortfield, $sortorder, 'right ');
504 print_liste_field_titre("PhysicalStock", $_SERVER["PHP_SELF"], "stock_physique", '', $param, "", $sortfield, $sortorder, 'right ');
505 // Details per warehouse
506 if (getDolGlobalString('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)
507 if ($nb_warehouse > 1) {
508 foreach ($warehouses_list as &$wh) {
509 print_liste_field_titre($wh['label'], '', '', '', '', '', '', '', 'right ');
510 }
511 }
512 }
513 if ($virtualdiffersfromphysical) {
514 print_liste_field_titre("VirtualStock", $_SERVER["PHP_SELF"], "", '', $param, "", $sortfield, $sortorder, 'right ', 'VirtualStockDesc');
515 }
516 // Units
517 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
518 print_liste_field_titre("Unit", $_SERVER["PHP_SELF"], "unit_short", '', $param, 'align="right"', $sortfield, $sortorder);
519 }
521 print_liste_field_titre("ProductStatusOnSell", $_SERVER["PHP_SELF"], "p.tosell", '', $param, "", $sortfield, $sortorder, 'right ');
522 print_liste_field_titre("ProductStatusOnBuy", $_SERVER["PHP_SELF"], "p.tobuy", '', $param, "", $sortfield, $sortorder, 'right ');
523 // Hook fields
524 $parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
525 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
526 print $hookmanager->resPrint;
527 // Action column
528 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
530 }
531 print "</tr>\n";
532
533 while ($i < min($num, $limit)) {
534 $objp = $db->fetch_object($resql);
535
536 $product = new Product($db);
537 $product->fetch($objp->rowid);
538 $product->load_stock();
539
540 print '<tr>';
541 // Action column
542 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
543 print '<td></td>';
544 }
545 print '<td class="nowrap">';
546 print $product->getNomUrl(1, '', 16);
547 //if ($objp->stock_theorique < $objp->seuil_stock_alerte) print ' '.img_warning($langs->trans("StockTooLow"));
548 print '</td>';
549 print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($product->label).'">'.dol_escape_htmltag($product->label).'</td>';
550
551 if (isModEnabled("service") && $type == 1) {
552 print '<td class="center">';
553 if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) {
554 print $regs[1].' '.$langs->trans("DurationYear");
555 } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) {
556 print $regs[1].' '.$langs->trans("DurationMonth");
557 } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) {
558 print $regs[1].' '.$langs->trans("DurationDay");
559 } else {
560 print $objp->duration;
561 }
562 print '</td>';
563 }
564 //print '<td class="right">'.$objp->stock_theorique.'</td>';
565 print '<td class="right">';
566 print $objp->seuil_stock_alerte;
567 print '</td>';
568 print '<td class="right">';
569 print $objp->desiredstock;
570 print '</td>';
571 // Real stock
572 print '<td class="right">';
573 if ($objp->seuil_stock_alerte != '' && ($objp->stock_physique < $objp->seuil_stock_alerte)) {
574 print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
575 }
576 if ($objp->stock_physique < 0) {
577 print '<span class="warning">';
578 }
579 print price(price2num($objp->stock_physique, 'MS'), 0, $langs, 1, 0);
580 if ($objp->stock_physique < 0) {
581 print '</span>';
582 }
583 print '</td>';
584
585 // Details per warehouse
586 if (getDolGlobalString('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)
587 if ($nb_warehouse > 1) {
588 foreach ($warehouses_list as &$wh) {
589 print '<td class="right">';
590 print price(empty($product->stock_warehouse[$wh['id']]->real) ? 0 : price2num($product->stock_warehouse[$wh['id']]->real, 'MS'), 0, $langs, 1, 0);
591 print '</td>';
592 }
593 }
594 }
595
596 // Virtual stock
597 if ($virtualdiffersfromphysical) {
598 print '<td class="right">';
599 if ($objp->seuil_stock_alerte != '' && ($product->stock_theorique < (float) $objp->seuil_stock_alerte)) {
600 print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
601 }
602 if ($objp->stock_physique < 0) {
603 print '<span class="warning">';
604 }
605 print price(price2num($product->stock_theorique, 'MS'), 0, $langs, 1, 0);
606 if ($objp->stock_physique < 0) {
607 print '</span>';
608 }
609 print '</td>';
610 }
611 // Units
612 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
613 print '<td class="left">'.dol_escape_htmltag($objp->unit_short).'</td>';
614 }
615 print '<td class="center nowraponall">';
616 print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
617 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$product->id.'">'.$langs->trans("Movements").'</a>';
618 print '</td>';
619 print '<td class="right nowrap">'.$product->LibStatut($objp->statut, 5, 0).'</td>';
620 print '<td class="right nowrap">'.$product->LibStatut($objp->tobuy, 5, 1).'</td>';
621 // Fields from hook
622 $parameters = array('obj' => $objp);
623 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $product); // Note that $action and $object may have been modified by hook
624 print $hookmanager->resPrint;
625 // Action column
626 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
627 print '<td></td>';
628 }
629
630 print "</tr>\n";
631 $i++;
632 }
633
634 print "</table>";
635 print '</div>';
636
637 print '</form>';
638
639 $db->free($resql);
640} else {
641 dol_print_error($db);
642}
643
644// End of page
645llxFooter();
646$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()
Empty header.
Definition wrapper.php:55
llxFooter()
Empty footer.
Definition wrapper.php:69
Class to manage canvas.
Class to manage categories.
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 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.
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.
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 a Dolibarr global constant int value.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $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, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
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 dolibarr global constant string value.
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.