dolibarr  17.0.4
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 // Security check
43 if ($user->socid) {
44  $socid = $user->socid;
45 }
46 $result = restrictedArea($user, 'produit|service');
47 
48 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
49 $hookmanager->initHooks(array('stockatdate'));
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 $fk_warehouse = GETPOST('fk_warehouse', 'int');
71 
72 $sortfield = GETPOST('sortfield', 'aZ09comma');
73 $sortorder = GETPOST('sortorder', 'aZ09comma');
74 $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
75 if (empty($page) || $page == -1) {
76  $page = 0;
77 } // If $page is not defined, or '' or -1
78 $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;
79 $offset = $limit * $page;
80 if (!$sortfield) {
81  $sortfield = 'p.ref';
82 }
83 if (!$sortorder) {
84  $sortorder = 'ASC';
85 }
86 
87 $parameters = array();
88 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
89 if ($reshook < 0) {
90  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
91 }
92 
93 $dateIsValid = true;
94 if ($mode == 'future') {
95  if ($date && $date < $now) {
96  setEventMessages($langs->trans("ErrorDateMustBeInFuture"), null, 'errors');
97  $dateIsValid = false;
98  }
99 } else {
100  if ($date && $date > $now) {
101  setEventMessages($langs->trans("ErrorDateMustBeBeforeToday"), null, 'errors');
102  $dateIsValid = false;
103  }
104 }
105 
106 
107 /*
108  * Actions
109  */
110 
111 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
112  $date = '';
113  $productid = 0;
114  $fk_warehouse = 0;
115  $search_ref = '';
116  $search_nom = '';
117 }
118 
119 $warehouseStatus = array();
120 if (!empty($conf->global->ENTREPOT_EXTRA_STATUS)) {
121  //$warehouseStatus[] = Entrepot::STATUS_CLOSED;
122  $warehouseStatus[] = Entrepot::STATUS_OPEN_ALL;
123  $warehouseStatus[] = Entrepot::STATUS_OPEN_INTERNAL;
124 }
125 
126 // Get array with current stock per product, warehouse
127 $stock_prod_warehouse = array();
128 $stock_prod = array();
129 if ($date && $dateIsValid) { // Avoid heavy sql if mandatory date is not defined
130  $sql = "SELECT ps.fk_product, ps.fk_entrepot as fk_warehouse,";
131  $sql .= " SUM(ps.reel) AS stock";
132  $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps";
133  $sql .= ", ".MAIN_DB_PREFIX."entrepot as w";
134  $sql .= ", ".MAIN_DB_PREFIX."product as p";
135  $sql .= " WHERE w.entity IN (".getEntity('stock').")";
136  $sql .= " AND w.rowid = ps.fk_entrepot AND p.rowid = ps.fk_product ";
137  if (!empty($conf->global->ENTREPOT_EXTRA_STATUS) && count($warehouseStatus)) {
138  $sql .= " AND w.statut IN (".$db->sanitize(implode(',', $warehouseStatus)).")";
139  }
140  if ($productid > 0) {
141  $sql .= " AND ps.fk_product = ".((int) $productid);
142  }
143  if ($fk_warehouse > 0) {
144  $sql .= " AND ps.fk_entrepot = ".((int) $fk_warehouse);
145  }
146  if ($search_ref) {
147  $sql .= " AND p.ref LIKE '%".$db->escape($search_ref)."%' ";
148  }
149  if ($search_nom) {
150  $sql .= " AND p.label LIKE '%".$db->escape($search_nom)."%' ";
151  }
152  $sql .= " GROUP BY fk_product, fk_entrepot";
153  //print $sql;
154 
155  $resql = $db->query($sql);
156  if ($resql) {
157  $num = $db->num_rows($resql);
158  $i = 0;
159 
160  while ($i < $num) {
161  $obj = $db->fetch_object($resql);
162 
163  $tmp_fk_product = $obj->fk_product;
164  $tmp_fk_warehouse = $obj->fk_warehouse;
165  $stock = $obj->stock;
166 
167  $stock_prod_warehouse[$tmp_fk_product][$tmp_fk_warehouse] = $stock;
168  $stock_prod[$tmp_fk_product] = (isset($stock_prod[$tmp_fk_product]) ? $stock_prod[$tmp_fk_product] : 0) + $stock;
169 
170  $i++;
171  }
172 
173  $db->free($resql);
174  } else {
175  dol_print_error($db);
176  }
177  //var_dump($stock_prod_warehouse);
178 } elseif ($action == 'filter') {
179  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
180 }
181 
182 // Get array with list of stock movements between date and now (for product/warehouse=
183 $movements_prod_warehouse = array();
184 $movements_prod = array();
185 $movements_prod_warehouse_nb = array();
186 $movements_prod_nb = array();
187 if ($date && $dateIsValid) {
188  $sql = "SELECT sm.fk_product, sm.fk_entrepot, SUM(sm.value) AS stock, COUNT(sm.rowid) AS nbofmovement";
189  $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as sm";
190  $sql .= ", ".MAIN_DB_PREFIX."entrepot as w";
191  $sql .= ", ".MAIN_DB_PREFIX."product as p";
192  $sql .= " WHERE w.entity IN (".getEntity('stock').")";
193  $sql .= " AND w.rowid = sm.fk_entrepot AND p.rowid = sm.fk_product ";
194  if (!empty($conf->global->ENTREPOT_EXTRA_STATUS) && count($warehouseStatus)) {
195  $sql .= " AND w.statut IN (".$db->sanitize(implode(',', $warehouseStatus)).")";
196  }
197  if ($mode == 'future') {
198  $sql .= " AND sm.datem <= '".$db->idate($dateendofday)."'";
199  } else {
200  $sql .= " AND sm.datem >= '".$db->idate($dateendofday)."'";
201  }
202  if ($productid > 0) {
203  $sql .= " AND sm.fk_product = ".((int) $productid);
204  }
205  if ($fk_warehouse > 0) {
206  $sql .= " AND sm.fk_entrepot = ".((int) $fk_warehouse);
207  }
208  if ($search_ref) {
209  $sql .= " AND p.ref LIKE '%".$db->escape($search_ref)."%' ";
210  }
211  if ($search_nom) {
212  $sql .= " AND p.label LIKE '%".$db->escape($search_nom)."%' ";
213  }
214  $sql .= " GROUP BY sm.fk_product, sm.fk_entrepot";
215 
216  $resql = $db->query($sql);
217 
218  if ($resql) {
219  $num = $db->num_rows($resql);
220  $i = 0;
221 
222  while ($i < $num) {
223  $obj = $db->fetch_object($resql);
224  $fk_product = $obj->fk_product;
225  $fk_entrepot = $obj->fk_entrepot;
226  $stock = $obj->stock;
227  $nbofmovement = $obj->nbofmovement;
228 
229  // Pour llx_product_stock.reel
230  $movements_prod_warehouse[$fk_product][$fk_entrepot] = $stock;
231  $movements_prod_warehouse_nb[$fk_product][$fk_entrepot] = $nbofmovement;
232 
233  // Pour llx_product.stock
234  $movements_prod[$fk_product] += $stock;
235  $movements_prod_nb[$fk_product] += $nbofmovement;
236 
237  $i++;
238  }
239 
240  $db->free($resql);
241  } else {
242  dol_print_error($db);
243  }
244 }
245 //var_dump($movements_prod_warehouse);
246 //var_dump($movements_prod);
247 
248 
249 /*
250  * View
251  */
252 
253 $form = new Form($db);
254 $formproduct = new FormProduct($db);
255 $prod = new Product($db);
256 
257 $num = 0;
258 
259 $title = $langs->trans('StockAtDate');
260 
261 $sql = 'SELECT p.rowid, p.ref, p.label, p.description, p.price, p.pmp,';
262 $sql .= ' p.price_ttc, p.price_base_type, p.fk_product_type, p.desiredstock, p.seuil_stock_alerte,';
263 $sql .= ' p.tms as datem, p.duration, p.tobuy, p.stock, ';
264 if ($fk_warehouse > 0) {
265  $sql .= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue";
266  $sql .= ', SUM(ps.reel) as stock_reel';
267 } else {
268  $sql .= " SUM(p.pmp * p.stock) as estimatedvalue, SUM(p.price * p.stock) as sellvalue";
269 }
270 // Add fields from hooks
271 $parameters = array();
272 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
273 $sql .= $hookmanager->resPrint;
274 
275 $sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
276 if ($fk_warehouse > 0) {
277  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as ps ON p.rowid = ps.fk_product AND ps.fk_entrepot = '.((int) $fk_warehouse);
278 }
279 // Add fields from hooks
280 $parameters = array();
281 $reshook = $hookmanager->executeHooks('printFieldListJoin', $parameters); // Note that $action and $object may have been modified by hook
282 $sql .= $hookmanager->resPrint;
283 $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
284 if ($productid > 0) {
285  $sql .= " AND p.rowid = ".((int) $productid);
286 }
287 if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
288  $sql .= " AND p.fk_product_type = 0";
289 }
290 if (!empty($canvas)) {
291  $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
292 }
293 if ($search_ref) {
294  $sql .= " AND p.ref LIKE '%".$db->escape($search_ref)."%' ";
295 }
296 if ($search_nom) {
297  $sql .= " AND p.label LIKE '%".$db->escape($search_nom)."%' ";
298 }
299 if ($fk_warehouse > 0) {
300  $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,';
301  $sql .= ' p.tms, p.duration, p.tobuy, p.stock';
302 } else {
303  $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,';
304  $sql .= ' p.tms, p.duration, p.tobuy, p.stock';
305 }
306 // Add where from hooks
307 $parameters = array();
308 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
309 $sql .= $hookmanager->resPrint;
310 
311 if ($sortfield == 'stock_reel' && $fk_warehouse <= 0) {
312  $sortfield = 'stock';
313 }
314 if ($sortfield == 'stock' && $fk_warehouse > 0) {
315  $sortfield = 'stock_reel';
316 }
317 $sql .= $db->order($sortfield, $sortorder);
318 
320 if ($date && $dateIsValid) { // We avoid a heavy sql if mandatory parameter date not yet defined
321  if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
322  $result = $db->query($sql);
323  $nbtotalofrecords = $db->num_rows($result);
324  if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
325  $page = 0;
326  $offset = 0;
327  }
328  }
329 
330  $sql .= $db->plimit($limit + 1, $offset);
331 
332  //print $sql;
333  $resql = $db->query($sql);
334  if (empty($resql)) {
335  dol_print_error($db);
336  exit;
337  }
338 
339  $num = $db->num_rows($resql);
340 }
341 
342 $i = 0;
343 //print $sql;
344 
345 $helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|';
346 $helpurl .= 'ES:M&oacute;dulo_Stocks';
347 
348 llxHeader('', $title, $helpurl, '');
349 
350 $head = array();
351 
352 $head[0][0] = DOL_URL_ROOT.'/product/stock/stockatdate.php';
353 $head[0][1] = $langs->trans("StockAtDateInPast");
354 $head[0][2] = 'stockatdatepast';
355 
356 $head[1][0] = DOL_URL_ROOT.'/product/stock/stockatdate.php?mode=future';
357 $head[1][1] = $langs->trans("StockAtDateInFuture");
358 $head[1][2] = 'stockatdatefuture';
359 
360 
361 print load_fiche_titre($langs->trans('StockAtDate'), '', 'stock');
362 
363 print dol_get_fiche_head($head, ($mode == 'future' ? 'stockatdatefuture' : 'stockatdatepast'), '', -1, '');
364 
365 $desc = $langs->trans("StockAtDatePastDesc");
366 if ($mode == 'future') {
367  $desc = $langs->trans("StockAtDateFutureDesc");
368 }
369 print '<span class="opacitymedium">'.$desc.'</span><br>'."\n";
370 print '<br>'."\n";
371 
372 print '<form name="formFilterWarehouse" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
373 print '<input type="hidden" name="token" value="'.newToken().'">';
374 print '<input type="hidden" name="action" value="filter">';
375 print '<input type="hidden" name="mode" value="'.$mode.'">';
376 
377 print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
378 print '<span class="fieldrequired">'.$langs->trans('Date').'</span> '.$form->selectDate(($date ? $date : -1), 'date');
379 
380 print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddingrightonly">&nbsp;</span> ';
381 print img_picto('', 'product', 'class="pictofiwedwidth"').' ';
382 print '</span> ';
383 print $form->select_produits($productid, 'productid', '', 0, 0, -1, 2, '', 0, array(), 0, $langs->trans('Product'), 0, 'maxwidth300', 0, '', null, 1);
384 
385 if ($mode != 'future') {
386  // 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
387  print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddingrightonly">&nbsp;</span> ';
388  print img_picto('', 'stock', 'class="pictofiwedwidth"');
389  print '</span> ';
390  print $formproduct->selectWarehouses((GETPOSTISSET('fk_warehouse') ? $fk_warehouse : 'ifonenodefault'), 'fk_warehouse', '', 1, 0, 0, $langs->trans('Warehouse'), 0, 0, null, '', null, 1, false, 'e.ref');
391 }
392 
393 print '</div>';
394 
395 $parameters = array();
396 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
397 if (empty($reshook)) {
398  print $hookmanager->resPrint;
399 }
400 
401 print '<div class="inline-block valignmiddle">';
402 print '<input type="submit" class="button" name="valid" value="'.$langs->trans('Refresh').'">';
403 print '</div>';
404 
405 //print '</form>';
406 
407 $param = '';
408 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
409  $param .= '&contextpage='.urlencode($contextpage);
410 }
411 if ($limit > 0 && $limit != $conf->liste_limit) {
412  $param .= '&limit='.urlencode($limit);
413 }
414 $param .= '&mode='.$mode;
415 if ($fk_warehouse > 0) {
416  $param .= '&fk_warehouse='.$fk_warehouse;
417 }
418 if ($productid > 0) {
419  $param .= '&productid='.$productid;
420 }
421 if (GETPOST('dateday', 'int') > 0) {
422  $param .= '&dateday='.GETPOST('dateday', 'int');
423 }
424 if (GETPOST('datemonth', 'int') > 0) {
425  $param .= '&datemonth='.GETPOST('datemonth', 'int');
426 }
427 if (GETPOST('dateyear', 'int') > 0) {
428  $param .= '&dateyear='.GETPOST('dateyear', 'int');
429 }
430 
431 // TODO Move this into the title line ?
432 print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'stock', 0, '', '', $limit, 0, 0, 1);
433 
434 print '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
435 print '<table class="liste centpercent">';
436 
437 $stocklabel = $langs->trans('StockAtDate');
438 if ($mode == 'future') {
439  $stocklabel = $langs->trans("VirtualStockAtDate");
440 }
441 
442 //print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">';
443 print '<input type="hidden" name="token" value="'.newToken().'">';
444 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
445 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
446 print '<input type="hidden" name="type" value="'.$type.'">';
447 print '<input type="hidden" name="mode" value="'.$mode.'">';
448 
449 // Fields title search
450 print '<tr class="liste_titre_filter">';
451 print '<td class="liste_titre"><input class="flat" type="text" name="search_ref" size="8" value="'.dol_escape_htmltag($search_ref).'"></td>';
452 print '<td class="liste_titre"><input class="flat" type="text" name="search_nom" size="8" value="'.dol_escape_htmltag($search_nom).'"></td>';
453 print '<td class="liste_titre"></td>';
454 print '<td class="liste_titre"></td>';
455 print '<td class="liste_titre"></td>';
456 if ($mode == 'future') {
457  print '<td class="liste_titre"></td>';
458 } else {
459  print '<td class="liste_titre"></td>';
460  print '<td class="liste_titre"></td>';
461 }
462 // Fields from hook
463 $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
464 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
465 print $hookmanager->resPrint;
466 
467 print '<td class="liste_titre maxwidthsearch">';
468 $searchpicto = $form->showFilterAndCheckAddButtons(0);
469 print $searchpicto;
470 print '</td>';
471 print '</tr>';
472 
473 $fieldtosortcurrentstock = 'stock';
474 if ($fk_warehouse > 0) {
475  $fieldtosortcurrentstock = 'stock_reel';
476 }
477 
478 // Lines of title
479 print '<tr class="liste_titre">';
480 print_liste_field_titre('Ref', $_SERVER["PHP_SELF"], 'p.ref', $param, '', '', $sortfield, $sortorder);
481 print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', '', $sortfield, $sortorder);
482 
483 if ($mode == 'future') {
484  print_liste_field_titre('CurrentStock', $_SERVER["PHP_SELF"], $fieldtosortcurrentstock, $param, '', '', $sortfield, $sortorder, 'right ');
485  print_liste_field_titre('', $_SERVER["PHP_SELF"]);
486  print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockAtDateDesc');
487  print_liste_field_titre('VirtualStock', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockDesc');
488 } else {
489  print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
490  print_liste_field_titre("EstimatedStockValue", $_SERVER["PHP_SELF"], "estimatedvalue", '', $param, '', $sortfield, $sortorder, 'right ', $langs->trans("AtDate"), 1);
491  print_liste_field_titre("EstimatedStockValueSell", $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'right ', $langs->trans("AtDate"), 1);
492  print_liste_field_titre('', $_SERVER["PHP_SELF"]);
493  print_liste_field_titre('CurrentStock', $_SERVER["PHP_SELF"], $fieldtosortcurrentstock, $param, '', '', $sortfield, $sortorder, 'right ');
494 }
495 print_liste_field_titre('', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
496 
497 // Hook fields
498 $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
499 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
500 print $hookmanager->resPrint;
501 
502 print "</tr>\n";
503 
504 $totalbuyingprice = 0;
505 $totalcurrentstock = 0;
506 $totalvirtualstock = 0;
507 
508 $i = 0;
509 while ($i < ($limit ? min($num, $limit) : $num)) {
510  $objp = $db->fetch_object($resql);
511 
512  if (!empty($conf->global->STOCK_SUPPORTS_SERVICES) || $objp->fk_product_type == 0) {
513  $prod->fetch($objp->rowid);
514 
515  // Multilangs
516  /*if (getDolGlobalInt('MAIN_MULTILANGS'))
517  {
518  $sql = 'SELECT label,description';
519  $sql .= ' FROM '.MAIN_DB_PREFIX.'product_lang';
520  $sql .= ' WHERE fk_product = '.((int) $objp->rowid);
521  $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
522  $sql .= ' LIMIT 1';
523 
524  $resqlm = $db->query($sql);
525  if ($resqlm)
526  {
527  $objtp = $db->fetch_object($resqlm);
528  if (!empty($objtp->description)) $objp->description = $objtp->description;
529  if (!empty($objtp->label)) $objp->label = $objtp->label;
530  }
531  }*/
532 
533  $currentstock = '';
534  if ($fk_warehouse > 0) {
535  //if ($productid > 0) {
536  $currentstock = $stock_prod_warehouse[$objp->rowid][$fk_warehouse];
537  //} else {
538  // $currentstock = $objp->stock_reel;
539  //}
540  } else {
541  //if ($productid > 0) {
542  $currentstock = $stock_prod[$objp->rowid];
543  //} else {
544  // $currentstock = $objp->stock;
545  //}
546  }
547 
548  if ($mode == 'future') {
549  $prod->load_stock('warehouseopen, warehouseinternal', 0, $dateendofday);
550  $stock = $prod->stock_theorique;
551  $prod->load_stock('warehouseopen, warehouseinternal', 0);
552  $virtualstock = $prod->stock_theorique;
553  } else {
554  if ($fk_warehouse > 0) {
555  $stock = $currentstock - $movements_prod_warehouse[$objp->rowid][$fk_warehouse];
556  $nbofmovement = $movements_prod_warehouse_nb[$objp->rowid][$fk_warehouse];
557  } else {
558  $stock = $currentstock - $movements_prod[$objp->rowid];
559  $nbofmovement = $movements_prod_nb[$objp->rowid];
560  }
561  }
562 
563 
564  print '<tr class="oddeven">';
565 
566  // Product ref
567  print '<td class="nowrap">'.$prod->getNomUrl(1, '').'</td>';
568 
569  // Product label
570  print '<td>'.$objp->label;
571  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
572  print '</td>';
573 
574  if ($mode == 'future') {
575  // Current stock
576  print '<td class="right">'.$currentstock.'</td>';
577  $totalcurrentstock += $currentstock;
578 
579  print '<td class="right"></td>';
580 
581  // Virtual stock at date
582  print '<td class="right">'.$stock.'</td>';
583 
584  // Final virtual stock
585  print '<td class="right">'.$virtualstock.'</td>';
586  $totalvirtualstock += $virtualstock;
587  } else {
588  // Stock at date
589  print '<td class="right">'.($stock ? $stock : '<span class="opacitymedium">'.$stock.'</span>').'</td>';
590 
591  // PMP value
592  print '<td class="right">';
593  if (price2num($stock * $objp->pmp, 'MT')) {
594  print '<span class="amount">'.price(price2num($stock * $objp->pmp, 'MT'), 1).'</span>';
595  } else {
596  print '';
597  }
598  $totalbuyingprice += $stock * $objp->pmp;
599  print '</td>';
600 
601  // Selling value
602  print '<td class="right">';
603  if (empty($conf->global->PRODUIT_MULTIPRICES)) {
604  print price(price2num($objp->sellvalue, 'MT'), 1);
605  } else {
606  $htmltext = $langs->trans("OptionMULTIPRICESIsOn");
607  print $form->textwithtooltip('<span class="opacitymedium">'.$langs->trans("Variable").'</span>', $htmltext);
608  }
609  print'</td>';
610 
611  print '<td class="right">';
612  if ($nbofmovement > 0) {
613  print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$objp->rowid.($fk_warehouse > 0 ? '&search_warehouse='.$fk_warehouse : '').'">'.$langs->trans("Movements").'</a>';
614  print ' <span class="tabs"><span class="badge">'.$nbofmovement.'</span></span>';
615  }
616  print '</td>';
617 
618  // Current stock
619  print '<td class="right">'.($currentstock ? $currentstock : '<span class="opacitymedium">0</span>').'</td>';
620  $totalcurrentstock += $currentstock;
621  }
622 
623  // Action
624  print '<td class="right"></td>';
625 
626  // Fields from hook
627  $parameters = array('objp'=>$objp);
628  $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
629  print $hookmanager->resPrint;
630 
631  print '</tr>'."\n";
632  }
633  $i++;
634 }
635 
636 $parameters = array('sql'=>$sql);
637 $reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook
638 print $hookmanager->resPrint;
639 
640 $colspan = 8;
641 if ($mode == 'future') {
642  $colspan++;
643 }
644 
645 
646 if (empty($date) || !$dateIsValid) {
647  print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("EnterADateCriteria").'</span></td></tr>';
648 } else {
649  print '<tr class="liste_total">';
650  print '<td>'.$langs->trans("Totalforthispage").'</td>';
651  print '<td></td>';
652  if ($mode == 'future') {
653  print '<td class="right">'.price(price2num($totalcurrentstock, 'MS')).'</td>';
654  print '<td></td>';
655  print '<td></td>';
656  print '<td class="right">'.price(price2num($totalvirtualstock, 'MS')).'</td>';
657  } else {
658  print '<td></td>';
659  print '<td class="right">'.price(price2num($totalbuyingprice, 'MT')).'</td>';
660  print '<td></td>';
661  print '<td></td>';
662  print '<td class="right">'.($productid > 0 ? price(price2num($totalcurrentstock, 'MS')) : '').'</td>';
663  }
664  print '<td></td>';
665  print '</tr>';
666 }
667 
668 print '</table>';
669 print '</div>';
670 
671 if (!empty($resql)) {
672  $db->free($resql);
673 }
674 
675 print dol_get_fiche_end();
676 
677 print '</form>';
678 
679 llxFooter();
680 
681 $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') &&!empty($user->rights->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') &&!empty($user->rights->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)) $resql
Social contributions to pay.
Definition: index.php:745
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='')
Show tabs of a record.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
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.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
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.
dol_now($mode='auto')
Return date for now.
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.
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.
$nbtotalofrecords
Count total nb of records.
Definition: list.php:329
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.