dolibarr 24.0.0-beta
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 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;
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 (isset($type)) {
351 if ($type == 1) {
352 $texte = $langs->trans("Services");
353 } else {
354 $texte = $langs->trans("Products");
355 }
356 } else {
357 $texte = $langs->trans("ProductsAndServices");
358 }
359 $texte .= ' ('.$langs->trans("MenuStocks").')';
360
361 $param = '';
362 if ($limit > 0 && $limit != $conf->liste_limit) {
363 $param .= '&limit='.((int) $limit);
364 }
365 if ($sall) {
366 $param .= "&sall=".urlencode($sall);
367 }
368 if ($tosell) {
369 $param .= "&tosell=".urlencode($tosell);
370 }
371 if ($tobuy) {
372 $param .= "&tobuy=".urlencode($tobuy);
373 }
374 if ($type != '') {
375 $param .= "&type=".urlencode((string) ($type));
376 }
377 if ($fourn_id) {
378 $param .= "&fourn_id=".urlencode((string) ($fourn_id));
379 }
380 if ($snom) {
381 $param .= "&snom=".urlencode($snom);
382 }
383 if ($sref) {
384 $param .= "&sref=".urlencode($sref);
385 }
386 if ($search_sale) {
387 $param .= "&search_sale=".urlencode($search_sale);
388 }
389 if ($search_categ > 0) {
390 $param .= "&search_categ=".urlencode((string) ($search_categ));
391 }
392 if ($search_toolowstock) {
393 $param .= "&search_toolowstock=".urlencode($search_toolowstock);
394 }
395 if ($sbarcode) {
396 $param .= "&sbarcode=".urlencode((string) ($sbarcode));
397 }
398 if ($search_stock_physique) {
399 $param .= '&search_stock_physique=' . urlencode($search_stock_physique);
400 }
401
402 llxHeader("", $texte, $helpurl, '', 0, 0, '', '', '', 'mod-product page-reassort');
403
404 print '<form action="'.$_SERVER["PHP_SELF"].'" method="post" name="formulaire">';
405 print '<input type="hidden" name="token" value="'.newToken().'">';
406 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
407 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
408 print '<input type="hidden" name="page" value="'.$page.'">';
409 print '<input type="hidden" name="type" value="'.$type.'">';
410
411 print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit);
412
413 if ($search_categ > 0) {
414 print "<div id='ways'>";
415 $c = new Categorie($db);
416 $c->fetch($search_categ);
417 $ways = $c->print_all_ways('auto', 'product/reassort.php');
418 print " &gt; ".$ways[0]."<br>\n";
419 print "</div><br>";
420 }
421
422 // Filter on categories
423 $moreforfilter = '';
424 if (isModEnabled('category')) {
425 $moreforfilter .= '<div class="divsearchfield">';
426 $moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"');
427 $moreforfilter .= $htmlother->select_categories(Categorie::TYPE_PRODUCT, $search_categ, 'search_categ', 1);
428 $moreforfilter .= '</div>';
429 }
430
431 $moreforfilter .= '<div class="divsearchfield">';
432 $moreforfilter .= '<label for="search_toolowstock">'.$langs->trans("StockTooLow").' </label><input type="checkbox" id="search_toolowstock" name="search_toolowstock" value="1"'.($search_toolowstock ? ' checked' : '').'>';
433 $moreforfilter .= '</div>';
434
435 print '<div class="liste_titre liste_titre_bydiv centpercent">';
436 print $moreforfilter;
437 $parameters = array();
438 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
439 print $hookmanager->resPrint;
440 print '</div>';
441
442 $formProduct = new FormProduct($db);
443 $formProduct->loadWarehouses();
444 $warehouses_list = $formProduct->cache_warehouses;
445 $nb_warehouse = count($warehouses_list);
446 $colspan_warehouse = 1;
447 $colspan = 0;
448 if (getDolGlobalString('STOCK_DETAIL_ON_WAREHOUSE')) {
449 $colspan_warehouse = $nb_warehouse > 1 ? $nb_warehouse + 1 : 1;
450 }
451
452 print '<div class="div-table-responsive">';
453 print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
454
455 // Fields title search
456 print '<tr class="liste_titre_filter">';
457 // Action column
458 if ($conf->main_checkbox_left_column) {
459 print '<td class="liste_titre maxwidthsearch">';
460 $searchpicto = $form->showFilterAndCheckAddButtons(0);
461 print $searchpicto;
462 print '</td>';
463 $colspan++;
464 }
465 print '<td class="liste_titre">';
466 print '<input class="flat" type="text" name="sref" size="6" value="'.$sref.'">';
467 print '</td>';
468 $colspan++;
469 print '<td class="liste_titre">';
470 print '<input class="flat" type="text" name="snom" size="8" value="'.$snom.'">';
471 print '</td>';
472 $colspan++;
473 // Duration
474 if (isModEnabled("service") && $type == 1) {
475 print '<td class="liste_titre">';
476 print '&nbsp;';
477 print '</td>';
478 $colspan++;
479 }
480 // Stock limit
481 print '<td class="liste_titre">&nbsp;</td>';
482 $colspan++;
483 print '<td class="liste_titre right">&nbsp;</td>';
484 $colspan++;
485 // Physical stock
486 print '<td class="liste_titre right">';
487 print '<input class="flat" type="text" size="5" name="search_stock_physique" value="'.dol_escape_htmltag($search_stock_physique).'">';
488 print '</td>';
489 $colspan++;
490 if ($virtualdiffersfromphysical) {
491 print '<td class="liste_titre">&nbsp;</td>';
492 $colspan++;
493 }
494 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
495 print '<td class="liste_titre"></td>';
496 $colspan++;
497 }
498 $parameters = array();
499 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
500 print $hookmanager->resPrint;
501 print '<td class="liste_titre">&nbsp;</td>';
502 $colspan++;
503 print '<td class="liste_titre" colspan="'.$colspan_warehouse.'">&nbsp;</td>';
504 $colspan++;
505 print '<td class="liste_titre"></td>';
506 $colspan++;
507 if (!$conf->main_checkbox_left_column) {
508 print '<td class="liste_titre maxwidthsearch">';
509 $searchpicto = $form->showFilterAndCheckAddButtons(0);
510 print $searchpicto;
511 print '</td>';
512 $colspan++;
513 }
514 print '</tr>';
515
516 // Line for column titles
517 print '<tr class="liste_titre">';
518 // Action column
519 if ($conf->main_checkbox_left_column) {
521 }
522 print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "p.ref", '', $param, "", $sortfield, $sortorder);
523 print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "p.label", '', $param, "", $sortfield, $sortorder);
524 if (isModEnabled("service") && $type == 1) {
525 print_liste_field_titre("Duration", $_SERVER["PHP_SELF"], "p.duration", '', $param, "", $sortfield, $sortorder, 'center ');
526 }
527 print_liste_field_titre("StockLimit", $_SERVER["PHP_SELF"], "p.seuil_stock_alerte", '', $param, "", $sortfield, $sortorder, 'right ');
528 print_liste_field_titre("DesiredStock", $_SERVER["PHP_SELF"], "p.desiredstock", '', $param, "", $sortfield, $sortorder, 'right ');
529 print_liste_field_titre("PhysicalStock", $_SERVER["PHP_SELF"], "stock_physique", '', $param, "", $sortfield, $sortorder, 'right ');
530 // Details per warehouse
531 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)
532 if ($nb_warehouse > 1) {
533 foreach ($warehouses_list as &$wh) {
534 print_liste_field_titre($wh['label'], '', '', '', '', '', '', '', 'right ');
535 }
536 }
537 }
538 if ($virtualdiffersfromphysical) {
539 print_liste_field_titre("VirtualStock", $_SERVER["PHP_SELF"], "", '', $param, "", $sortfield, $sortorder, 'right ', 'VirtualStockDesc');
540 }
541 // Units
542 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
543 print_liste_field_titre("Unit", $_SERVER["PHP_SELF"], "unit_short", '', $param, 'align="right"', $sortfield, $sortorder);
544 }
545 // Hook fields
546 $parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
547 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
548 print $hookmanager->resPrint;
550 print_liste_field_titre("ProductStatusOnSell", $_SERVER["PHP_SELF"], "p.tosell", '', $param, "", $sortfield, $sortorder, 'right ');
551 print_liste_field_titre("ProductStatusOnBuy", $_SERVER["PHP_SELF"], "p.tobuy", '', $param, "", $sortfield, $sortorder, 'right ');
552 // Action column
553 if (!$conf->main_checkbox_left_column) {
555 }
556 print "</tr>\n";
557
558 while ($i < min($num, $limit)) {
559 $objp = $db->fetch_object($resql);
560
561 $product = new Product($db);
562 $product->fetch($objp->rowid);
563 $product->load_stock();
564
565 print '<tr>';
566 // Action column
567 if ($conf->main_checkbox_left_column) {
568 print '<td></td>';
569 }
570 print '<td class="tdoverflowmax250">';
571 print $product->getNomUrl(1);
572 //if ($objp->stock_theorique < $objp->seuil_stock_alerte) print ' '.img_warning($langs->trans("StockTooLow"));
573 print '</td>';
574 print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($product->label).'">'.dol_escape_htmltag($product->label).'</td>';
575
576 if (isModEnabled("service") && $type == 1) {
577 print '<td class="center">';
578 $regs = array();
579 if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) {
580 print $regs[1].' '.$langs->trans("DurationYear");
581 } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) {
582 print $regs[1].' '.$langs->trans("DurationMonth");
583 } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) {
584 print $regs[1].' '.$langs->trans("DurationDay");
585 } else {
586 print $objp->duration;
587 }
588 print '</td>';
589 }
590 //print '<td class="right">'.$objp->stock_theorique.'</td>';
591 print '<td class="right">';
592 print $objp->seuil_stock_alerte;
593 print '</td>';
594 print '<td class="right">';
595 print $objp->desiredstock;
596 print '</td>';
597 // Real stock
598 print '<td class="right">';
599 if ($objp->seuil_stock_alerte != '' && ($objp->stock_physique < $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($objp->stock_physique, 'MS'), 0, $langs, 1, 0);
606 if ($objp->stock_physique < 0) {
607 print '</span>';
608 }
609 print '</td>';
610
611 // Details per warehouse
612 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)
613 if ($nb_warehouse > 1) {
614 foreach ($warehouses_list as &$wh) {
615 print '<td class="right">';
616 print price(empty($product->stock_warehouse[$wh['id']]->real) ? 0 : price2num($product->stock_warehouse[$wh['id']]->real, 'MS'), 0, $langs, 1, 0);
617 print '</td>';
618 }
619 }
620 }
621
622 // Virtual stock
623 if ($virtualdiffersfromphysical) {
624 print '<td class="right">';
625 if ($objp->seuil_stock_alerte != '' && ($product->stock_theorique < (float) $objp->seuil_stock_alerte)) {
626 print img_warning($langs->trans("StockLowerThanLimit", $objp->seuil_stock_alerte)).' ';
627 }
628 if ($objp->stock_physique < 0) {
629 print '<span class="warning">';
630 }
631 print price(price2num($product->stock_theorique, 'MS'), 0, $langs, 1, 0);
632 if ($objp->stock_physique < 0) {
633 print '</span>';
634 }
635 print '</td>';
636 }
637 // Units
638 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
639 print '<td class="left">'.dol_escape_htmltag($objp->unit_short).'</td>';
640 }
641 // Fields from hook
642 $parameters = array('obj' => $objp);
643 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $product); // Note that $action and $object may have been modified by hook
644 print $hookmanager->resPrint;
645 print '<td class="center nowraponall">';
646 print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
647 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$product->id.'">'.$langs->trans("Movements").'</a>';
648 print '</td>';
649 print '<td class="right nowrap">'.$product->LibStatut($objp->statut, 5, 0).'</td>';
650 print '<td class="right nowrap">'.$product->LibStatut($objp->tobuy, 5, 1).'</td>';
651 // Action column
652 if (!$conf->main_checkbox_left_column) {
653 print '<td></td>';
654 }
655
656 print "</tr>\n";
657 $i++;
658 }
659 if ($num == 0) {
660 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
661 }
662
663 print "</table>";
664 print '</div>';
665
666 print '</form>';
667
668 $db->free($resql);
669} else {
671}
672
673// End of page
674llxFooter();
675$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.
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.
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 '.
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)
Return value of a param into GET or POST supervariable.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
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.