dolibarr  20.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  *
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
31 require '../main.inc.php';
32 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
35 require_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");
56 if (empty($page) || $page < 0) {
57  $page = 0;
58 }
59 if (!$sortfield) {
60  $sortfield = "p.ref";
61 }
62 if (!$sortorder) {
63  $sortorder = "ASC";
64 }
65 $limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
66 if (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");
73 if (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;
82 if (!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;
90 if (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 
102 if ($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 
115 if (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);
139 if (!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,';
146 if (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 }
151 if (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';
159 if (!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 }
162 if (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').")";
170 if (!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 }
186 if (!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 }
226 if ($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)
230 if (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 }
237 if ($sref) {
238  $sql .= natural_search('p.ref', $sref);
239 }
240 if ($search_barcode) {
241  $sql .= natural_search('p.barcode', $search_barcode);
242 }
243 if ($snom) {
244  $sql .= natural_search('p.label', $snom);
245 }
246 if (!empty($tosell)) {
247  $sql .= " AND p.tosell = ".((int) $tosell);
248 }
249 if (!empty($tobuy)) {
250  $sql .= " AND p.tobuy = ".((int) $tobuy);
251 }
252 if (!empty($canvas)) {
253  $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
254 }
255 if ($fourn_id > 0) {
256  $sql .= " AND p.rowid = pf.fk_product AND pf.fk_soc = ".((int) $fourn_id);
257 }
258 if (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;
270 if (!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 = '';
281 if (!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
301 if (!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 
310 if (!empty($sql_having)) {
311  $sql .= $sql_having;
312 }
313 $sql .= $db->order($sortfield, $sortorder);
314 
315 // Count total nb of records
316 $nbtotalofrecords = '';
317 if (!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);
329 if ($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);
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); // 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
645 llxFooter();
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.
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:745
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...
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 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.