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