dolibarr 25.0.0-alpha
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 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
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.'/core/class/html.formother.class.php';
36require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
37require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
38
47// Load translation files required by the page
48$langs->loadLangs(array('products', 'stocks'));
49
50$action = GETPOST('action', 'aZ09');
51$sref = GETPOST("sref", 'alpha');
52$snom = GETPOST("snom", 'alpha');
53$sall = trim(GETPOST('search_all', 'alphanohtml'));
54$type = GETPOSTISSET('type') ? GETPOSTINT('type') : Product::TYPE_PRODUCT;
55$search_barcode = GETPOST("search_barcode", 'alpha');
56$search_toolowstock = GETPOST('search_toolowstock');
57$tosell = GETPOST("tosell");
58$tobuy = GETPOST("tobuy");
59$fourn_id = GETPOSTINT("fourn_id");
60$sbarcode = GETPOSTINT("sbarcode");
61$search_stock_physique = GETPOST('search_stock_physique', 'alpha');
62
63$sortfield = GETPOST('sortfield', 'aZ09comma');
64$sortorder = GETPOST('sortorder', 'aZ09comma');
65$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
66if (empty($page) || $page < 0) {
67 $page = 0;
68}
69if (!$sortfield) {
70 $sortfield = "p.ref";
71}
72if (!$sortorder) {
73 $sortorder = "ASC";
74}
75$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
76if (empty($page) || $page == -1) {
77 $page = 0;
78} // If $page is not defined, or '' or -1
79$offset = $limit * $page;
80
81// Load sale and categ filters
82$search_sale = GETPOST("search_sale");
83if (GETPOSTISSET('catid')) {
84 $search_categ = GETPOSTINT('catid');
85} else {
86 $search_categ = GETPOSTINT('search_categ');
87}
88
89// Get object canvas (By default, this is not defined, so standard usage of dolibarr)
90$canvas = GETPOST("canvas");
91$objcanvas = null;
92if (!empty($canvas)) {
93 require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
94 $objcanvas = new Canvas($db, $action);
95 $objcanvas->getCanvas('product', 'list', $canvas);
96}
97
98// Define virtualdiffersfromphysical
99$virtualdiffersfromphysical = 0;
100if (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')
101 || getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER')
102 || getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')
103 || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION')
104 || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE')
105 || isModEnabled('mrp')) {
106 $virtualdiffersfromphysical = 1; // According to increase/decrease stock options, virtual and physical stock may differs.
107}
108
109// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
110$hookmanager->initHooks(array('productreassortlist'));
111
112if ($user->socid) {
113 $socid = $user->socid;
114}
115$result = restrictedArea($user, 'produit|service', 0, 'product&product');
116$result = restrictedArea($user, 'stock');
117
118$object = new Product($db);
119
120
121/*
122 * Actions
123 */
124
125if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
126 $sref = "";
127 $snom = "";
128 $sall = "";
129 $tosell = "";
130 $tobuy = "";
131 $search_sale = "";
132 $search_categ = "";
133 $search_toolowstock = '';
134 $fourn_id = '';
135 $sbarcode = '';
136 $search_stock_physique = '';
137}
138
139
140
141/*
142 * View
143 */
144
145$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
146
147$form = new Form($db);
148$htmlother = new FormOther($db);
149$sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
150$sql .= ' p.fk_product_type, p.tms as datem,';
151$sql .= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte, p.desiredstock,';
152if (getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
153 $sql .= ' p.stock as stock_physique';
154} else {
155 $sql .= ' SUM(s.reel) as stock_physique';
156}
157if (getDolGlobalString('PRODUCT_USE_UNITS')) {
158 $sql .= ', u.short_label as unit_short';
159}
160// Add fields from hooks
161$parameters = array();
162$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook
163$sql .= $hookmanager->resPrint;
164$sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
165if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
166 $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product_stock as s ON p.rowid = s.fk_product';
167}
168if (getDolGlobalString('PRODUCT_USE_UNITS')) {
169 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_units as u on p.fk_unit = u.rowid';
170}
171// Add table from hooks
172$parameters = array();
173$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object); // Note that $action and $object may have been modified by hook
174$sql .= $hookmanager->resPrint;
175$sql .= " WHERE p.entity IN (".getEntity('product').")";
176if (!empty($search_categ) && $search_categ != '-1') {
177 $sql .= " AND ";
178 if ($search_categ == -2) {
179 $sql .= " NOT EXISTS ";
180 } else {
181 $sql .= " EXISTS ";
182 }
183 $sql .= "(";
184 $sql .= " SELECT cp.fk_categorie, cp.fk_product";
185 $sql .= " FROM " . MAIN_DB_PREFIX . "categorie_product as cp";
186 $sql .= " WHERE cp.fk_product = p.rowid"; // Join for the needed table to filter by categ
187 if ($search_categ > 0) {
188 $sql .= " AND cp.fk_categorie = " . ((int) $search_categ);
189 }
190 $sql .= ")";
191}
192if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
193 if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_VIRTUAL_WITH_NO_PHYSICAL')) {
194 $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') . "))";
195 } else {
196 $sql .= " AND
197 (
198 EXISTS
199 (SELECT e.rowid
200 FROM " . MAIN_DB_PREFIX . "entrepot as e
201 WHERE e.rowid = s.fk_entrepot AND e.entity IN (" . getEntity('stock') . "))
202 OR (
203 SELECT SUM(cd1.qty) as qty
204 FROM " . MAIN_DB_PREFIX . "commande_fournisseurdet as cd1
205 LEFT JOIN " . MAIN_DB_PREFIX . "commande_fournisseur as c1
206 ON c1.rowid = cd1.fk_commande
207 WHERE c1.entity IN (1) AND cd1.fk_product = p.rowid AND c1.fk_statut in (3,4) AND cd1.qty <> 0
208 ) IS NOT NULL
209 OR (
210 SELECT SUM(cd2.qty) as qty
211 FROM " . MAIN_DB_PREFIX . "commandedet as cd2
212 LEFT JOIN " . MAIN_DB_PREFIX . "commande as c2 ON c2.rowid = cd2.fk_commande
213 WHERE c2.entity IN (1) AND cd2.fk_product = p.rowid AND c2.fk_statut in (1,2) AND cd2.qty <> 0
214 ) IS NOT NULL
215 OR (
216 SELECT SUM(ed3.qty) as qty
217 FROM " . MAIN_DB_PREFIX . "expeditiondet as ed3
218 LEFT JOIN " . MAIN_DB_PREFIX . "expedition as e3 ON e3.rowid = ed3.fk_expedition
219 LEFT JOIN " . MAIN_DB_PREFIX . "commandedet as cd3 ON ed3.fk_elementdet = cd3.rowid
220 LEFT JOIN " . MAIN_DB_PREFIX . "commande as c3 ON c3.rowid = cd3.fk_commande
221 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
222 ) IS NOT NULL
223 OR (
224 SELECT SUM(mp4.qty) as qty
225 FROM " . MAIN_DB_PREFIX . "mrp_production as mp4
226 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)
227 WHERE mp4.fk_product = p.rowid AND mp4.qty <> 0
228 ) IS NOT NULL
229 ) ";
230 }
231}
232if ($sall) {
233 $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $sall);
234}
235// if the type is not 1, we show all products (type = 0,2,3)
236if (dol_strlen((string) $type)) {
237 if ($type == 1) {
238 $sql .= " AND p.fk_product_type = '1'";
239 } else {
240 $sql .= " AND p.fk_product_type <> '1'";
241 }
242}
243if ($sref) {
244 $sql .= natural_search('p.ref', $sref);
245}
246if ($search_barcode) {
247 $sql .= natural_search('p.barcode', $search_barcode);
248}
249if ($snom) {
250 $sql .= natural_search('p.label', $snom);
251}
252if (!empty($tosell)) {
253 $sql .= " AND p.tosell = ".((int) $tosell);
254}
255if (!empty($tobuy)) {
256 $sql .= " AND p.tobuy = ".((int) $tobuy);
257}
258if (!empty($canvas)) {
259 $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
260}
261if ($fourn_id > 0) {
262 $sql .= " AND p.rowid = pf.fk_product AND pf.fk_soc = ".((int) $fourn_id);
263}
264if (getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
265 if ($search_toolowstock) {
266 $sql .= " AND p.stock < p.seuil_stock_alerte";
267 }
268 if ($search_stock_physique != '') {
269 $sql .= natural_search('p.stock', $search_stock_physique, 1, 1);
270 }
271}
272// Add where from hooks
273$parameters = array();
274$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
275$sql .= $hookmanager->resPrint;
276if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
277 $sql .= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,";
278 $sql .= " p.fk_product_type, p.tms, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock";
279}
280
281// Add GROUP BY from hooks
282$parameters = array();
283$reshook = $hookmanager->executeHooks('printFieldListGroupBy', $parameters, $object); // Note that $action and $object may have been modified by hook
284$sql .= $hookmanager->resPrint;
285
286$sql_having = '';
287if (!getDolGlobalString('PRODUCT_STOCK_LIST_SHOW_WITH_PRECALCULATED_DENORMALIZED_PHYSICAL_STOCK')) {
288 if ($search_toolowstock) {
289 $sql_having .= " HAVING SUM(" . $db->ifsql('s.reel IS NULL', '0', 's.reel') . ") < p.seuil_stock_alerte";
290 }
291 if ($search_stock_physique != '') {
292 $natural_search_physique = natural_search('__SUM_OF_REEL__', $search_stock_physique, 1, 1);
293 $natural_search_physique = " " . substr(str_replace('__SUM_OF_REEL__', 'SUM(COALESCE(s.reel, 0))', $natural_search_physique), 1, -1); // remove first "(" and last ")" characters
294 if (!empty($sql_having)) {
295 $sql_having .= " AND";
296 } else {
297 $sql_having .= " HAVING";
298 }
299 $sql_having .= $natural_search_physique; // natural_search gives save sql @phan-suppress-current-line SqlInjection
300 }
301}
302
303// Add HAVING from hooks
304$parameters = array();
305$reshook = $hookmanager->executeHooks('printFieldListHaving', $parameters, $object); // Note that $action and $object may have been modified by hook
306if (empty($reshook)) {
307 if (empty($sql_having)) {
308 $sql_having .= " HAVING 1=1";
309 }
310 $sql_having .= $hookmanager->resPrint;
311} else {
312 $sql_having = $hookmanager->resPrint;
313}
314
315if (!empty($sql_having)) {
316 $sql .= $sql_having;
317}
318
319$sql .= $db->order($sortfield, $sortorder);
320
321// Count total nb of records
322$nbtotalofrecords = '';
323if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
324 $result = $db->query($sql);
325 $nbtotalofrecords = $db->num_rows($result);
326 if (($page * $limit) > (int) $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
327 $page = 0;
328 $offset = 0;
329 }
330}
331
332$sql .= $db->plimit($limit + 1, $offset);
333
334$resql = $db->query($sql);
335if ($resql) {
336 $num = $db->num_rows($resql);
337
338 $i = 0;
339
340 if ($num == 1 && GETPOST('autojumpifoneonly') && ($sall || $snom || $sref)) {
341 $objp = $db->fetch_object($resql);
342 header("Location: card.php?id=$objp->rowid");
343 exit;
344 }
345
346 if ($type == 1) {
347 $texte = $langs->trans("Services");
348 } else {
349 $texte = $langs->trans("Products");
350 }
351 $texte .= ' ('.$langs->trans("MenuStocks").')';
352
353 $param = '';
354 if ($limit > 0 && $limit != $conf->liste_limit) {
355 $param .= '&limit='.((int) $limit);
356 }
357 if ($sall) {
358 $param .= "&sall=".urlencode($sall);
359 }
360 if ($tosell) {
361 $param .= "&tosell=".urlencode($tosell);
362 }
363 if ($tobuy) {
364 $param .= "&tobuy=".urlencode($tobuy);
365 }
366 if ($type != '') {
367 $param .= "&type=".urlencode((string) ($type));
368 }
369 if ($fourn_id) {
370 $param .= "&fourn_id=".urlencode((string) ($fourn_id));
371 }
372 if ($snom) {
373 $param .= "&snom=".urlencode($snom);
374 }
375 if ($sref) {
376 $param .= "&sref=".urlencode($sref);
377 }
378 if ($search_sale) {
379 $param .= "&search_sale=".urlencode($search_sale);
380 }
381 if ($search_categ > 0) {
382 $param .= "&search_categ=".urlencode((string) ($search_categ));
383 }
384 if ($search_toolowstock) {
385 $param .= "&search_toolowstock=".urlencode($search_toolowstock);
386 }
387 if ($sbarcode) {
388 $param .= "&sbarcode=".urlencode((string) ($sbarcode));
389 }
390 if ($search_stock_physique) {
391 $param .= '&search_stock_physique=' . urlencode($search_stock_physique);
392 }
393
394 llxHeader("", $texte, $helpurl, '', 0, 0, '', '', '', 'mod-product page-reassort');
395
396 print '<form action="'.$_SERVER["PHP_SELF"].'" method="post" name="formulaire">';
397 print '<input type="hidden" name="token" value="'.newToken().'">';
398 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
399 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
400 print '<input type="hidden" name="page" value="'.$page.'">';
401 print '<input type="hidden" name="type" value="'.$type.'">';
402
403 print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit);
404
405 if ($search_categ > 0) {
406 print "<div id='ways'>";
407 $c = new Categorie($db);
408 $c->fetch($search_categ);
409 $ways = $c->print_all_ways('auto', 'product/reassort.php');
410 print " &gt; ".$ways[0]."<br>\n";
411 print "</div><br>";
412 }
413
414 // Filter on categories
415 $moreforfilter = '';
416 if (isModEnabled('category')) {
417 $moreforfilter .= '<div class="divsearchfield">';
418 $moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"');
419 $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_PRODUCT, $search_categ, 'search_categ', 1);
420 $moreforfilter .= '</div>';
421 }
422
423 $moreforfilter .= '<div class="divsearchfield">';
424 $moreforfilter .= '<label for="search_toolowstock">'.$langs->trans("StockTooLow").' </label><input type="checkbox" id="search_toolowstock" name="search_toolowstock" value="1"'.($search_toolowstock ? ' checked' : '').'>';
425 $moreforfilter .= '</div>';
426
427 print '<div class="liste_titre liste_titre_bydiv centpercent">';
428 print $moreforfilter;
429 $parameters = array();
430 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
431 print $hookmanager->resPrint;
432 print '</div>';
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 $colspan = 0;
440 if (getDolGlobalString('STOCK_DETAIL_ON_WAREHOUSE')) {
441 $colspan_warehouse = $nb_warehouse > 1 ? $nb_warehouse + 1 : 1;
442 }
443
444 print '<div class="div-table-responsive">';
445 print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
446
447 // Fields title search
448 print '<tr class="liste_titre_filter">';
449 // Action column
450 if ($conf->main_checkbox_left_column) {
451 print '<td class="liste_titre maxwidthsearch">';
452 $searchpicto = $form->showFilterAndCheckAddButtons(0);
453 print $searchpicto;
454 print '</td>';
455 $colspan++;
456 }
457 print '<td class="liste_titre">';
458 print '<input class="flat" type="text" name="sref" size="6" value="'.$sref.'">';
459 print '</td>';
460 $colspan++;
461 print '<td class="liste_titre">';
462 print '<input class="flat" type="text" name="snom" size="8" value="'.$snom.'">';
463 print '</td>';
464 $colspan++;
465 // Duration
466 if (isModEnabled("service") && $type == 1) {
467 print '<td class="liste_titre">';
468 print '&nbsp;';
469 print '</td>';
470 $colspan++;
471 }
472 // Stock limit
473 print '<td class="liste_titre">&nbsp;</td>';
474 $colspan++;
475 print '<td class="liste_titre right">&nbsp;</td>';
476 $colspan++;
477 // Physical stock
478 print '<td class="liste_titre right">';
479 print '<input class="flat" type="text" size="5" name="search_stock_physique" value="'.dol_escape_htmltag($search_stock_physique).'">';
480 print '</td>';
481 $colspan++;
482 if ($virtualdiffersfromphysical) {
483 print '<td class="liste_titre">&nbsp;</td>';
484 $colspan++;
485 }
486 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
487 print '<td class="liste_titre"></td>';
488 $colspan++;
489 }
490 $parameters = array();
491 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
492 print $hookmanager->resPrint;
493 print '<td class="liste_titre">&nbsp;</td>';
494 $colspan++;
495 print '<td class="liste_titre" colspan="'.$colspan_warehouse.'">&nbsp;</td>';
496 $colspan++;
497 print '<td class="liste_titre"></td>';
498 $colspan++;
499 if (!$conf->main_checkbox_left_column) {
500 print '<td class="liste_titre maxwidthsearch">';
501 $searchpicto = $form->showFilterAndCheckAddButtons(0);
502 print $searchpicto;
503 print '</td>';
504 $colspan++;
505 }
506 print '</tr>';
507
508 // Line for column titles
509 print '<tr class="liste_titre">';
510 // Action column
511 if ($conf->main_checkbox_left_column) {
513 }
514 print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "p.ref", '', $param, "", $sortfield, $sortorder);
515 print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "p.label", '', $param, "", $sortfield, $sortorder);
516 if (isModEnabled("service") && $type == 1) {
517 print_liste_field_titre("Duration", $_SERVER["PHP_SELF"], "p.duration", '', $param, "", $sortfield, $sortorder, 'center ');
518 }
519 print_liste_field_titre("StockLimit", $_SERVER["PHP_SELF"], "p.seuil_stock_alerte", '', $param, "", $sortfield, $sortorder, 'right ');
520 print_liste_field_titre("DesiredStock", $_SERVER["PHP_SELF"], "p.desiredstock", '', $param, "", $sortfield, $sortorder, 'right ');
521 print_liste_field_titre("PhysicalStock", $_SERVER["PHP_SELF"], "stock_physique", '', $param, "", $sortfield, $sortorder, 'right ');
522 // Details per warehouse
523 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)
524 if ($nb_warehouse > 1) {
525 foreach ($warehouses_list as &$wh) {
526 print_liste_field_titre($wh['label'], '', '', '', '', '', '', '', 'right ');
527 }
528 }
529 }
530 if ($virtualdiffersfromphysical) {
531 print_liste_field_titre("VirtualStock", $_SERVER["PHP_SELF"], "", '', $param, "", $sortfield, $sortorder, 'right ', 'VirtualStockDesc');
532 }
533 // Units
534 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
535 print_liste_field_titre("Unit", $_SERVER["PHP_SELF"], "unit_short", '', $param, 'align="right"', $sortfield, $sortorder);
536 }
537 // Hook fields
538 $parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
539 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
540 print $hookmanager->resPrint;
542 print_liste_field_titre("ProductStatusOnSell", $_SERVER["PHP_SELF"], "p.tosell", '', $param, "", $sortfield, $sortorder, 'right ');
543 print_liste_field_titre("ProductStatusOnBuy", $_SERVER["PHP_SELF"], "p.tobuy", '', $param, "", $sortfield, $sortorder, 'right ');
544 // Action column
545 if (!$conf->main_checkbox_left_column) {
547 }
548 print "</tr>\n";
549
550 while ($i < min($num, $limit)) {
551 $objp = $db->fetch_object($resql);
552
553 $product = new Product($db);
554 $product->fetch($objp->rowid);
555 $product->load_stock();
556
557 print '<tr>';
558 // Action column
559 if ($conf->main_checkbox_left_column) {
560 print '<td></td>';
561 }
562 print '<td class="tdoverflowmax250">';
563 print $product->getNomUrl(1);
564 //if ($objp->stock_theorique < $objp->seuil_stock_alerte) print ' '.img_warning($langs->trans("StockTooLow"));
565 print '</td>';
566 print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($product->label).'">'.dol_escape_htmltag($product->label).'</td>';
567
568 if (isModEnabled("service") && $type == 1) {
569 print '<td class="center">';
570 $regs = array();
571 if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) {
572 print $regs[1].' '.$langs->trans("DurationYear");
573 } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) {
574 print $regs[1].' '.$langs->trans("DurationMonth");
575 } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) {
576 print $regs[1].' '.$langs->trans("DurationDay");
577 } else {
578 print $objp->duration;
579 }
580 print '</td>';
581 }
582 //print '<td class="right">'.$objp->stock_theorique.'</td>';
583 print '<td class="right">';
584 print $objp->seuil_stock_alerte;
585 print '</td>';
586 print '<td class="right">';
587 print $objp->desiredstock;
588 print '</td>';
589 // Real stock
590 print '<td class="right">';
591 if ($objp->seuil_stock_alerte != '' && ($objp->stock_physique < $objp->seuil_stock_alerte)) {
592 print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
593 }
594 if ($objp->stock_physique < 0) {
595 print '<span class="warning">';
596 }
597 print price(price2num($objp->stock_physique, 'MS'), 0, $langs, 1, 0);
598 if ($objp->stock_physique < 0) {
599 print '</span>';
600 }
601 print '</td>';
602
603 // Details per warehouse
604 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)
605 if ($nb_warehouse > 1) {
606 foreach ($warehouses_list as &$wh) {
607 print '<td class="right">';
608 print price(empty($product->stock_warehouse[$wh['id']]->real) ? 0 : price2num($product->stock_warehouse[$wh['id']]->real, 'MS'), 0, $langs, 1, 0);
609 print '</td>';
610 }
611 }
612 }
613
614 // Virtual stock
615 if ($virtualdiffersfromphysical) {
616 print '<td class="right">';
617 if ($objp->seuil_stock_alerte != '' && ($product->stock_theorique < (float) $objp->seuil_stock_alerte)) {
618 print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
619 }
620 if ($objp->stock_physique < 0) {
621 print '<span class="warning">';
622 }
623 print price(price2num($product->stock_theorique, 'MS'), 0, $langs, 1, 0);
624 if ($objp->stock_physique < 0) {
625 print '</span>';
626 }
627 print '</td>';
628 }
629 // Units
630 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
631 print '<td class="left">'.dol_escape_htmltag($objp->unit_short).'</td>';
632 }
633 // Fields from hook
634 $parameters = array('obj' => $objp);
635 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $product); // Note that $action and $object may have been modified by hook
636 print $hookmanager->resPrint;
637 print '<td class="center nowraponall">';
638 print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
639 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$product->id.'">'.$langs->trans("Movements").'</a>';
640 print '</td>';
641 print '<td class="right nowrap">'.$product->LibStatut($objp->statut, 5, 0).'</td>';
642 print '<td class="right nowrap">'.$product->LibStatut($objp->tobuy, 5, 1).'</td>';
643 // Action column
644 if (!$conf->main_checkbox_left_column) {
645 print '<td></td>';
646 }
647
648 print "</tr>\n";
649 $i++;
650 }
651 if ($num == 0) {
652 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
653 }
654
655 print "</table>";
656 print '</div>';
657
658 print '</form>';
659
660 $db->free($resql);
661} else {
662 dol_print_error($db);
663}
664
665// End of page
666llxFooter();
667$db->close();
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
$c
Definition line.php:346
Class to manage canvas.
Class to manage categories.
Class to manage generation of HTML components Only common components must be here.
Class to help generate other html components Only common components are here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage products or services.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
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.
natural_search($fields, $value, $mode=0, $nofirstand=0, $sqltoadd='')
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
print_liste_field_titre($name, $file="", $field="", $begin="", $param="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Definition html.lib.php:181
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $nodie=0, $mode='')
Check permissions of a user to show a page and an object.