dolibarr  19.0.0-dev
stockatdate.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
3  * Copyright (C) 2013-2020 Laurent Destaileur <ely@users.sourceforge.net>
4  * Copyright (C) 2014 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2016 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2016 ATM Consulting <support@atm-consulting.fr>
7  * Copyright (C) 2019-2021 Frédéric France <frederic.france@netlogic.fr>
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  */
22 
29 // Load Dolibarr environment
30 require '../../main.inc.php';
31 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
37 require_once './lib/replenishment.lib.php';
38 
39 // Load translation files required by the page
40 $langs->loadLangs(array('products', 'stocks', 'orders'));
41 
42 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
43 $hookmanager->initHooks(array('stockatdate'));
44 
45 // Security check
46 if ($user->socid) {
47  $socid = $user->socid;
48 }
49 $result = restrictedArea($user, 'produit|service');
50 
51 //checks if a product has been ordered
52 
53 $action = GETPOST('action', 'aZ09');
54 $type = GETPOST('type', 'int');
55 $mode = GETPOST('mode', 'alpha');
56 
57 $date = '';
58 $dateendofday = '';
59 if (GETPOSTISSET('dateday') && GETPOSTISSET('datemonth') && GETPOSTISSET('dateyear')) {
60  $date = dol_mktime(0, 0, 0, GETPOST('datemonth', 'int'), GETPOST('dateday', 'int'), GETPOST('dateyear', 'int'));
61  $dateendofday = dol_mktime(23, 59, 59, GETPOST('datemonth', 'int'), GETPOST('dateday', 'int'), GETPOST('dateyear', 'int'));
62 }
63 
64 $search_ref = GETPOST('search_ref', 'alphanohtml');
65 $search_nom = GETPOST('search_nom', 'alphanohtml');
66 
67 $now = dol_now();
68 
69 $productid = GETPOST('productid', 'int');
70 if (GETPOSTISARRAY('search_fk_warehouse')) {
71  $search_fk_warehouse = GETPOST('search_fk_warehouse', 'array:int');
72 } else {
73  $search_fk_warehouse = array(GETPOST('search_fk_warehouse', 'int'));
74 }
75 // For backward compatibility
76 if (GETPOST('fk_warehouse', 'int')) {
77  $search_fk_warehouse = array(GETPOST('fk_warehouse', 'int'));
78 }
79 // Clean value -1
80 foreach ($search_fk_warehouse as $key => $val) {
81  if ($val == -1 || empty($val)) {
82  unset($search_fk_warehouse[$key]);
83  }
84 }
85 
86 $sortfield = GETPOST('sortfield', 'aZ09comma');
87 $sortorder = GETPOST('sortorder', 'aZ09comma');
88 $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
89 if (empty($page) || $page == -1) {
90  $page = 0;
91 } // If $page is not defined, or '' or -1
92 $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;
93 $offset = $limit * $page;
94 if (!$sortfield) {
95  $sortfield = 'p.ref';
96 }
97 if (!$sortorder) {
98  $sortorder = 'ASC';
99 }
100 
101 $parameters = array();
102 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
103 if ($reshook < 0) {
104  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
105 }
106 
107 $dateIsValid = true;
108 if ($mode == 'future') {
109  if ($date && $date < $now) {
110  setEventMessages($langs->trans("ErrorDateMustBeInFuture"), null, 'errors');
111  $dateIsValid = false;
112  }
113 } else {
114  if ($date && $date > $now) {
115  setEventMessages($langs->trans("ErrorDateMustBeBeforeToday"), null, 'errors');
116  $dateIsValid = false;
117  }
118 }
119 
120 
121 /*
122  * Actions
123  */
124 
125 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // Both test are required to be compatible with all browsers
126  $date = '';
127  $productid = 0;
128  $search_fk_warehouse = array();
129  $search_ref = '';
130  $search_nom = '';
131 }
132 
133 $warehouseStatus = array();
134 if (!empty($conf->global->ENTREPOT_EXTRA_STATUS)) {
135  //$warehouseStatus[] = Entrepot::STATUS_CLOSED;
136  $warehouseStatus[] = Entrepot::STATUS_OPEN_ALL;
137  $warehouseStatus[] = Entrepot::STATUS_OPEN_INTERNAL;
138 }
139 
140 // Get array with current stock per product, warehouse
141 $stock_prod_warehouse = array();
142 $stock_prod = array();
143 if ($date && $dateIsValid) { // Avoid heavy sql if mandatory date is not defined
144  $sql = "SELECT ps.fk_product, ps.fk_entrepot as fk_warehouse,";
145  $sql .= " SUM(ps.reel) AS stock";
146  $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps";
147  $sql .= ", ".MAIN_DB_PREFIX."entrepot as w";
148  $sql .= ", ".MAIN_DB_PREFIX."product as p";
149  $sql .= " WHERE w.entity IN (".getEntity('stock').")";
150  $sql .= " AND w.rowid = ps.fk_entrepot AND p.rowid = ps.fk_product";
151  if (!empty($conf->global->ENTREPOT_EXTRA_STATUS) && count($warehouseStatus)) {
152  $sql .= " AND w.statut IN (".$db->sanitize(implode(',', $warehouseStatus)).")";
153  }
154  if ($productid > 0) {
155  $sql .= " AND ps.fk_product = ".((int) $productid);
156  }
157  if (! empty($search_fk_warehouse)) {
158  $sql .= " AND ps.fk_entrepot IN (".$db->sanitize(join(",", $search_fk_warehouse)).")";
159  }
160  if ($search_ref) {
161  $sql .= natural_search("p.ref", $search_ref);
162  }
163  if ($search_nom) {
164  $sql .= natural_search("p.label", $search_nom);
165  }
166  $sql .= " GROUP BY fk_product, fk_entrepot";
167  //print $sql;
168 
169  $resql = $db->query($sql);
170  if ($resql) {
171  $num = $db->num_rows($resql);
172  $i = 0;
173 
174  while ($i < $num) {
175  $obj = $db->fetch_object($resql);
176 
177  $tmp_fk_product = $obj->fk_product;
178  $tmp_fk_warehouse = $obj->fk_warehouse;
179  $stock = $obj->stock;
180 
181  $stock_prod_warehouse[$tmp_fk_product][$tmp_fk_warehouse] = $stock;
182  $stock_prod[$tmp_fk_product] = (isset($stock_prod[$tmp_fk_product]) ? $stock_prod[$tmp_fk_product] : 0) + $stock;
183 
184  $i++;
185  }
186 
187  $db->free($resql);
188  } else {
189  dol_print_error($db);
190  }
191  //var_dump($stock_prod_warehouse);
192 } elseif ($action == 'filter') {
193  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
194 }
195 
196 // Get array with list of stock movements between date and now (for product/warehouse=
197 $movements_prod_warehouse = array();
198 $movements_prod = array();
199 $movements_prod_warehouse_nb = array();
200 $movements_prod_nb = array();
201 if ($date && $dateIsValid) {
202  $sql = "SELECT sm.fk_product, sm.fk_entrepot, SUM(sm.value) AS stock, COUNT(sm.rowid) AS nbofmovement";
203  $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as sm";
204  $sql .= ", ".MAIN_DB_PREFIX."entrepot as w";
205  $sql .= ", ".MAIN_DB_PREFIX."product as p";
206  $sql .= " WHERE w.entity IN (".getEntity('stock').")";
207  $sql .= " AND w.rowid = sm.fk_entrepot AND p.rowid = sm.fk_product ";
208  if (!empty($conf->global->ENTREPOT_EXTRA_STATUS) && count($warehouseStatus)) {
209  $sql .= " AND w.statut IN (".$db->sanitize(implode(',', $warehouseStatus)).")";
210  }
211  if ($mode == 'future') {
212  $sql .= " AND sm.datem <= '".$db->idate($dateendofday)."'";
213  } else {
214  $sql .= " AND sm.datem >= '".$db->idate($dateendofday)."'";
215  }
216  if ($productid > 0) {
217  $sql .= " AND sm.fk_product = ".((int) $productid);
218  }
219  if (!empty($search_fk_warehouse)) {
220  $sql .= " AND sm.fk_entrepot IN (".$db->sanitize(join(",", $search_fk_warehouse)).")";
221  }
222  if ($search_ref) {
223  $sql .= " AND p.ref LIKE '%".$db->escape($search_ref)."%' ";
224  }
225  if ($search_nom) {
226  $sql .= " AND p.label LIKE '%".$db->escape($search_nom)."%' ";
227  }
228  $sql .= " GROUP BY sm.fk_product, sm.fk_entrepot";
229 
230  $resql = $db->query($sql);
231 
232  if ($resql) {
233  $num = $db->num_rows($resql);
234  $i = 0;
235 
236  while ($i < $num) {
237  $obj = $db->fetch_object($resql);
238  $fk_product = $obj->fk_product;
239  $fk_entrepot = $obj->fk_entrepot;
240  $stock = $obj->stock;
241  $nbofmovement = $obj->nbofmovement;
242 
243  // Pour llx_product_stock.reel
244  $movements_prod_warehouse[$fk_product][$fk_entrepot] = $stock;
245  $movements_prod_warehouse_nb[$fk_product][$fk_entrepot] = $nbofmovement;
246 
247  // Pour llx_product.stock
248  $movements_prod[$fk_product] += $stock;
249  $movements_prod_nb[$fk_product] += $nbofmovement;
250 
251  $i++;
252  }
253 
254  $db->free($resql);
255  } else {
256  dol_print_error($db);
257  }
258 }
259 //var_dump($movements_prod_warehouse);
260 //var_dump($movements_prod);
261 
262 
263 /*
264  * View
265  */
266 
267 $form = new Form($db);
268 $formproduct = new FormProduct($db);
269 $prod = new Product($db);
270 
271 $num = 0;
272 
273 $title = $langs->trans('StockAtDate');
274 
275 $sql = 'SELECT p.rowid, p.ref, p.label, p.description, p.price, p.pmp,';
276 $sql .= ' p.price_ttc, p.price_base_type, p.fk_product_type, p.desiredstock, p.seuil_stock_alerte,';
277 $sql .= ' p.tms as datem, p.duration, p.tobuy, p.stock, ';
278 if (!empty($search_fk_warehouse)) {
279  $sql .= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue";
280  $sql .= ', SUM(ps.reel) as stock_reel';
281 } else {
282  $sql .= " SUM(p.pmp * p.stock) as estimatedvalue, SUM(p.price * p.stock) as sellvalue";
283 }
284 // Add fields from hooks
285 $parameters = array();
286 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
287 $sql .= $hookmanager->resPrint;
288 
289 $sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
290 if (!empty($search_fk_warehouse)) {
291  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as ps ON p.rowid = ps.fk_product AND ps.fk_entrepot IN ('.$db->sanitize(join(",", $search_fk_warehouse)).")";
292 }
293 // Add fields from hooks
294 $parameters = array();
295 $reshook = $hookmanager->executeHooks('printFieldListJoin', $parameters); // Note that $action and $object may have been modified by hook
296 $sql .= $hookmanager->resPrint;
297 $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
298 if ($productid > 0) {
299  $sql .= " AND p.rowid = ".((int) $productid);
300 }
301 if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
302  $sql .= " AND p.fk_product_type = 0";
303 }
304 if (!empty($canvas)) {
305  $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
306 }
307 if ($search_ref) {
308  $sql .= natural_search('p.ref', $search_ref);
309 }
310 if ($search_nom) {
311  $sql .= natural_search('p.label', $search_nom);
312 }
313 $sql .= ' GROUP BY p.rowid, p.ref, p.label, p.description, p.price, p.pmp, p.price_ttc, p.price_base_type, p.fk_product_type, p.desiredstock, p.seuil_stock_alerte,';
314 $sql .= ' p.tms, p.duration, p.tobuy, p.stock';
315 // Add where from hooks
316 $parameters = array();
317 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
318 $sql .= $hookmanager->resPrint;
319 
320 if ($sortfield == 'stock_reel' && empty($search_fk_warehouse)) {
321  $sortfield = 'stock';
322 }
323 if ($sortfield == 'stock' && !empty($search_fk_warehouse)) {
324  $sortfield = 'stock_reel';
325 }
326 $sql .= $db->order($sortfield, $sortorder);
327 
328 $nbtotalofrecords = 0;
329 if ($date && $dateIsValid) { // We avoid a heavy sql if mandatory parameter date not yet defined
330  if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
331  $result = $db->query($sql);
332  $nbtotalofrecords = $db->num_rows($result);
333  if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
334  $page = 0;
335  $offset = 0;
336  }
337  }
338 
339  $sql .= $db->plimit($limit + 1, $offset);
340 
341  //print $sql;
342  $resql = $db->query($sql);
343  if (empty($resql)) {
344  dol_print_error($db);
345  exit;
346  }
347 
348  $num = $db->num_rows($resql);
349 }
350 
351 $i = 0;
352 
353 $helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|';
354 $helpurl .= 'ES:M&oacute;dulo_Stocks';
355 
356 llxHeader('', $title, $helpurl, '');
357 
358 $head = array();
359 
360 $head[0][0] = DOL_URL_ROOT.'/product/stock/stockatdate.php';
361 $head[0][1] = $langs->trans("StockAtDateInPast");
362 $head[0][2] = 'stockatdatepast';
363 
364 $head[1][0] = DOL_URL_ROOT.'/product/stock/stockatdate.php?mode=future';
365 $head[1][1] = $langs->trans("StockAtDateInFuture");
366 $head[1][2] = 'stockatdatefuture';
367 
368 
369 print load_fiche_titre($langs->trans('StockAtDate'), '', 'stock');
370 
371 print dol_get_fiche_head($head, ($mode == 'future' ? 'stockatdatefuture' : 'stockatdatepast'), '', -1, '');
372 
373 $desc = $langs->trans("StockAtDatePastDesc");
374 if ($mode == 'future') {
375  $desc = $langs->trans("StockAtDateFutureDesc");
376 }
377 print '<span class="opacitymedium">'.$desc.'</span><br>'."\n";
378 print '<br>'."\n";
379 
380 print '<form name="formFilterWarehouse" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
381 print '<input type="hidden" name="token" value="'.newToken().'">';
382 print '<input type="hidden" name="action" value="filter">';
383 print '<input type="hidden" name="mode" value="'.$mode.'">';
384 
385 print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
386 print '<span class="fieldrequired">'.$langs->trans('Date').'</span> '.$form->selectDate(($date ? $date : -1), 'date');
387 
388 print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddingrightonly">&nbsp;</span> ';
389 print img_picto('', 'product', 'class="pictofiwedwidth"').' ';
390 print '</span> ';
391 print $form->select_produits($productid, 'productid', '', 0, 0, -1, 2, '', 0, array(), 0, $langs->trans('Product'), 0, 'maxwidth300', 0, '', null, 1);
392 
393 if ($mode != 'future') {
394  // A virtual stock in future has no sense on a per warehouse view, so no filter on warehouse is available for stock at date in future
395  print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddingrightonly">&nbsp;</span> ';
396  print img_picto('', 'stock', 'class="pictofixedwidth"').$langs->trans("Warehouse").' :';
397  print '</span> ';
398  $selected = ((GETPOSTISSET('search_fk_warehouse') || GETPOSTISSET('fk_warehouse')) ? $search_fk_warehouse : 'ifonenodefault');
399  print $formproduct->selectWarehouses($selected, 'search_fk_warehouse', '', 1, 0, 0, $langs->trans('Warehouse'), 0, 0, null, 'minwidth200', null, 1, false, 'e.ref', 1);
400 }
401 
402 print '</div>';
403 
404 $parameters = array();
405 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
406 if (empty($reshook)) {
407  print $hookmanager->resPrint;
408 }
409 
410 print '<div class="inline-block valignmiddle">';
411 print '<input type="submit" class="button" name="valid" value="'.$langs->trans('Refresh').'">';
412 print '</div>';
413 
414 //print '</form>';
415 
416 $param = '';
417 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
418  $param .= '&contextpage='.urlencode($contextpage);
419 }
420 if ($limit > 0 && $limit != $conf->liste_limit) {
421  $param .= '&limit='.((int) $limit);
422 }
423 $param .= '&mode='.$mode;
424 if (!empty($search_fk_warehouse)) {
425  foreach ($search_fk_warehouse as $val) {
426  $param .= '&search_fk_warehouse[]='.$val;
427  }
428 }
429 if ($productid > 0) {
430  $param .= '&productid='.$productid;
431 }
432 if (GETPOST('dateday', 'int') > 0) {
433  $param .= '&dateday='.GETPOST('dateday', 'int');
434 }
435 if (GETPOST('datemonth', 'int') > 0) {
436  $param .= '&datemonth='.GETPOST('datemonth', 'int');
437 }
438 if (GETPOST('dateyear', 'int') > 0) {
439  $param .= '&dateyear='.GETPOST('dateyear', 'int');
440 }
441 
442 // TODO Move this into the title line ?
443 print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'stock', 0, '', '', $limit, 0, 0, 1);
444 
445 print '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
446 print '<table class="liste centpercent">';
447 
448 $stocklabel = $langs->trans('StockAtDate');
449 if ($mode == 'future') {
450  $stocklabel = $langs->trans("VirtualStockAtDate");
451 }
452 
453 print '<input type="hidden" name="token" value="'.newToken().'">';
454 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
455 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
456 print '<input type="hidden" name="type" value="'.$type.'">';
457 print '<input type="hidden" name="mode" value="'.$mode.'">';
458 
459 // Fields title search
460 print '<tr class="liste_titre_filter">';
461 print '<td class="liste_titre"><input class="flat" type="text" name="search_ref" size="8" value="'.dol_escape_htmltag($search_ref).'"></td>';
462 print '<td class="liste_titre"><input class="flat" type="text" name="search_nom" size="8" value="'.dol_escape_htmltag($search_nom).'"></td>';
463 print '<td class="liste_titre"></td>';
464 print '<td class="liste_titre"></td>';
465 print '<td class="liste_titre"></td>';
466 if ($mode == 'future') {
467  print '<td class="liste_titre"></td>';
468 } else {
469  print '<td class="liste_titre"></td>';
470  print '<td class="liste_titre"></td>';
471 }
472 // Fields from hook
473 $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
474 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
475 print $hookmanager->resPrint;
476 
477 print '<td class="liste_titre maxwidthsearch">';
478 $searchpicto = $form->showFilterAndCheckAddButtons(0);
479 print $searchpicto;
480 print '</td>';
481 print '</tr>';
482 
483 $fieldtosortcurrentstock = 'stock';
484 if (!empty($search_fk_warehouse)) {
485  $fieldtosortcurrentstock = 'stock_reel';
486 }
487 
488 // Lines of title
489 print '<tr class="liste_titre">';
490 print_liste_field_titre('Ref', $_SERVER["PHP_SELF"], 'p.ref', $param, '', '', $sortfield, $sortorder);
491 print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', '', $sortfield, $sortorder);
492 
493 if ($mode == 'future') {
494  print_liste_field_titre('CurrentStock', $_SERVER["PHP_SELF"], $fieldtosortcurrentstock, $param, '', '', $sortfield, $sortorder, 'right ');
495  print_liste_field_titre('', $_SERVER["PHP_SELF"]);
496  print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockAtDateDesc');
497  print_liste_field_titre('VirtualStock', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockDesc');
498 } else {
499  print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
500  print_liste_field_titre("EstimatedStockValue", $_SERVER["PHP_SELF"], "estimatedvalue", '', $param, '', $sortfield, $sortorder, 'right ', $langs->trans("AtDate"), 1);
501  print_liste_field_titre("EstimatedStockValueSell", $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'right ', $langs->trans("AtDate"), 1);
502  print_liste_field_titre('', $_SERVER["PHP_SELF"]);
503  print_liste_field_titre('CurrentStock', $_SERVER["PHP_SELF"], $fieldtosortcurrentstock, $param, '', '', $sortfield, $sortorder, 'right ');
504 }
505 print_liste_field_titre('', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
506 
507 // Hook fields
508 $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
509 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
510 print $hookmanager->resPrint;
511 
512 print "</tr>\n";
513 
514 $totalbuyingprice = 0;
515 $totalcurrentstock = 0;
516 $totalvirtualstock = 0;
517 
518 $i = 0;
519 while ($i < ($limit ? min($num, $limit) : $num)) {
520  $objp = $db->fetch_object($resql);
521 
522  if (!empty($conf->global->STOCK_SUPPORTS_SERVICES) || $objp->fk_product_type == 0) {
523  $prod->fetch($objp->rowid);
524 
525  // Multilangs
526  /*if (getDolGlobalInt('MAIN_MULTILANGS'))
527  {
528  $sql = 'SELECT label,description';
529  $sql .= ' FROM '.MAIN_DB_PREFIX.'product_lang';
530  $sql .= ' WHERE fk_product = '.((int) $objp->rowid);
531  $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
532  $sql .= ' LIMIT 1';
533 
534  $resqlm = $db->query($sql);
535  if ($resqlm)
536  {
537  $objtp = $db->fetch_object($resqlm);
538  if (!empty($objtp->description)) $objp->description = $objtp->description;
539  if (!empty($objtp->label)) $objp->label = $objtp->label;
540  }
541  }*/
542 
543  $currentstock = '';
544  if (!empty($search_fk_warehouse)) {
545  //if ($productid > 0) {
546  foreach ($search_fk_warehouse as $val) {
547  if (!is_numeric($currentstock)) {
548  $currentstock = 0;
549  }
550  $currentstock += $stock_prod_warehouse[$objp->rowid][$val];
551  }
552  //} else {
553  // $currentstock = $objp->stock_reel;
554  //}
555  } else {
556  //if ($productid > 0) {
557  $currentstock = $stock_prod[$objp->rowid];
558  //} else {
559  // $currentstock = $objp->stock;
560  //}
561  }
562 
563  if ($mode == 'future') {
564  $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0, $dateendofday);
565  $stock = $prod->stock_theorique; // virtual stock at a date
566  $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0);
567  $virtualstock = $prod->stock_theorique; // virtual stock in infinite future
568  } else {
569  $stock = $currentstock;
570  $nbofmovement = 0;
571  if (!empty($search_fk_warehouse)) {
572  foreach ($search_fk_warehouse as $val) {
573  $stock -= $movements_prod_warehouse[$objp->rowid][$val];
574  $nbofmovement += $movements_prod_warehouse_nb[$objp->rowid][$val];
575  }
576  } else {
577  $stock -= $movements_prod[$objp->rowid];
578  $nbofmovement += $movements_prod_nb[$objp->rowid];
579  }
580  }
581 
582 
583  print '<tr class="oddeven">';
584 
585  // Product ref
586  print '<td class="nowrap">'.$prod->getNomUrl(1, '').'</td>';
587 
588  // Product label
589  print '<td>'.$objp->label;
590  print '<input type="hidden" name="desc'.$i.'" value="'.dol_escape_htmltag($objp->description).'">'; // TODO Remove this and make a fetch to get description when creating order instead of a GETPOST
591  print '</td>';
592 
593  if ($mode == 'future') {
594  // Current stock
595  print '<td class="right">'.$currentstock.'</td>';
596  $totalcurrentstock += $currentstock;
597 
598  print '<td class="right"></td>';
599 
600  // Virtual stock at date
601  print '<td class="right">'.$stock.'</td>';
602 
603  // Final virtual stock
604  print '<td class="right">'.$virtualstock.'</td>';
605  $totalvirtualstock += $virtualstock;
606  } else {
607  // Stock at date
608  print '<td class="right">'.($stock ? $stock : '<span class="opacitymedium">'.$stock.'</span>').'</td>';
609 
610  // PMP value
611  print '<td class="right">';
612  if (price2num($stock * $objp->pmp, 'MT')) {
613  print '<span class="amount">'.price(price2num($stock * $objp->pmp, 'MT'), 1).'</span>';
614  } else {
615  print '';
616  }
617  $totalbuyingprice += $stock * $objp->pmp;
618  print '</td>';
619 
620  // Selling value
621  print '<td class="right">';
622  if (empty($conf->global->PRODUIT_MULTIPRICES)) {
623  print price(price2num($objp->sellvalue, 'MT'), 1);
624  } else {
625  $htmltext = $langs->trans("OptionMULTIPRICESIsOn");
626  print $form->textwithtooltip('<span class="opacitymedium">'.$langs->trans("Variable").'</span>', $htmltext);
627  }
628  print'</td>';
629 
630  print '<td class="right">';
631  if ($nbofmovement > 0) {
632  print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$objp->rowid;
633  foreach ($search_fk_warehouse as $val) {
634  print ($val > 0 ? '&search_warehouse='.$val : '');
635  }
636  print '">'.$langs->trans("Movements").'</a>';
637  print ' <span class="tabs"><span class="badge">'.$nbofmovement.'</span></span>';
638  }
639  print '</td>';
640 
641  // Current stock
642  print '<td class="right">'.($currentstock ? $currentstock : '<span class="opacitymedium">0</span>').'</td>';
643  $totalcurrentstock += $currentstock;
644  }
645 
646  // Action
647  print '<td class="right"></td>';
648 
649  // Fields from hook
650  $parameters = array('objp'=>$objp);
651  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
652  print $hookmanager->resPrint;
653 
654  print '</tr>'."\n";
655  }
656  $i++;
657 }
658 
659 $parameters = array('sql'=>$sql);
660 $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook
661 print $hookmanager->resPrint;
662 
663 $colspan = 8;
664 if ($mode == 'future') {
665  $colspan++;
666 }
667 
668 
669 if (empty($date) || !$dateIsValid) {
670  print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("EnterADateCriteria").'</span></td></tr>';
671 } else {
672  print '<tr class="liste_total">';
673  print '<td>'.$langs->trans("Totalforthispage").'</td>';
674  print '<td></td>';
675  if ($mode == 'future') {
676  print '<td class="right">'.price(price2num($totalcurrentstock, 'MS')).'</td>';
677  print '<td></td>';
678  print '<td></td>';
679  print '<td class="right">'.price(price2num($totalvirtualstock, 'MS')).'</td>';
680  } else {
681  print '<td></td>';
682  print '<td class="right">'.price(price2num($totalbuyingprice, 'MT')).'</td>';
683  print '<td></td>';
684  print '<td></td>';
685  print '<td class="right">'.($productid > 0 ? price(price2num($totalcurrentstock, 'MS')) : '').'</td>';
686  }
687  print '<td></td>';
688  print '</tr>';
689 }
690 
691 print '</table>';
692 print '</div>';
693 
694 if (!empty($resql)) {
695  $db->free($resql);
696 }
697 
698 print dol_get_fiche_end();
699 
700 print '</form>';
701 
702 llxFooter();
703 
704 $db->close();
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage products or services.
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->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') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_get_fiche_end($notab=0)
Return tab footer of a card.
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...
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.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
print_barre_liste($titre, $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.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
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.