dolibarr 18.0.6
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
30require '../../main.inc.php';
31require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
32require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
35require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
36require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
37require_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
46if ($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 = '';
59if (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');
70if (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
76if (GETPOST('fk_warehouse', 'int')) {
77 $search_fk_warehouse = array(GETPOST('fk_warehouse', 'int'));
78}
79// Clean value -1
80foreach ($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');
89if (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;
94if (!$sortfield) {
95 $sortfield = 'p.ref';
96}
97if (!$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
103if ($reshook < 0) {
104 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
105}
106
107$dateIsValid = true;
108if ($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
125if (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();
134if (!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();
143if ($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();
201if ($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, ';
278if (!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';
290if (!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').')';
298if ($productid > 0) {
299 $sql .= " AND p.rowid = ".((int) $productid);
300}
301if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
302 $sql .= " AND p.fk_product_type = 0";
303}
304if (!empty($canvas)) {
305 $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
306}
307if ($search_ref) {
308 $sql .= natural_search('p.ref', $search_ref);
309}
310if ($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
320if ($sortfield == 'stock_reel' && empty($search_fk_warehouse)) {
321 $sortfield = 'stock';
322}
323if ($sortfield == 'stock' && !empty($search_fk_warehouse)) {
324 $sortfield = 'stock_reel';
325}
326$sql .= $db->order($sortfield, $sortorder);
327
328$nbtotalofrecords = '';
329if ($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
356llxHeader('', $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
369print load_fiche_titre($langs->trans('StockAtDate'), '', 'stock');
370
371print dol_get_fiche_head($head, ($mode == 'future' ? 'stockatdatefuture' : 'stockatdatepast'), '', -1, '');
372
373$desc = $langs->trans("StockAtDatePastDesc");
374if ($mode == 'future') {
375 $desc = $langs->trans("StockAtDateFutureDesc");
376}
377print '<span class="opacitymedium">'.$desc.'</span><br>'."\n";
378print '<br>'."\n";
379
380print '<form name="formFilterWarehouse" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
381print '<input type="hidden" name="token" value="'.newToken().'">';
382print '<input type="hidden" name="action" value="filter">';
383print '<input type="hidden" name="mode" value="'.$mode.'">';
384
385print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
386print '<span class="fieldrequired">'.$langs->trans('Date').'</span> '.$form->selectDate(($date ? $date : -1), 'date');
387
388print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddingrightonly">&nbsp;</span> ';
389print img_picto('', 'product', 'class="pictofiwedwidth"').' ';
390print '</span> ';
391print $form->select_produits($productid, 'productid', '', 0, 0, -1, 2, '', 0, array(), 0, $langs->trans('Product'), 0, 'maxwidth300', 0, '', null, 1);
392
393if ($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
402print '</div>';
403
404$parameters = array();
405$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
406if (empty($reshook)) {
407 print $hookmanager->resPrint;
408}
409
410print '<div class="inline-block valignmiddle">';
411print '<input type="submit" class="button" name="valid" value="'.$langs->trans('Refresh').'">';
412print '</div>';
413
414//print '</form>';
415
416$param = '';
417if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
418 $param .= '&contextpage='.urlencode($contextpage);
419}
420if ($limit > 0 && $limit != $conf->liste_limit) {
421 $param .= '&limit='.((int) $limit);
422}
423$param .= '&mode='.$mode;
424if (!empty($search_fk_warehouse)) {
425 foreach ($search_fk_warehouse as $val) {
426 $param .= '&search_fk_warehouse[]='.$val;
427 }
428}
429if ($productid > 0) {
430 $param .= '&productid='.(int) $productid;
431}
432if (GETPOST('dateday', 'int') > 0) {
433 $param .= '&dateday='.GETPOST('dateday', 'int');
434}
435if (GETPOST('datemonth', 'int') > 0) {
436 $param .= '&datemonth='.GETPOST('datemonth', 'int');
437}
438if (GETPOST('dateyear', 'int') > 0) {
439 $param .= '&dateyear='.GETPOST('dateyear', 'int');
440}
441
442// TODO Move this into the title line ?
443print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'stock', 0, '', '', $limit, 0, 0, 1);
444
445print '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
446print '<table class="liste centpercent">';
447
448$stocklabel = $langs->trans('StockAtDate');
449if ($mode == 'future') {
450 $stocklabel = $langs->trans("VirtualStockAtDate");
451}
452
453print '<input type="hidden" name="token" value="'.newToken().'">';
454print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
455print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
456print '<input type="hidden" name="type" value="'.$type.'">';
457print '<input type="hidden" name="mode" value="'.$mode.'">';
458
459// Fields title search
460print '<tr class="liste_titre_filter">';
461print '<td class="liste_titre"><input class="flat" type="text" name="search_ref" size="8" value="'.dol_escape_htmltag($search_ref).'"></td>';
462print '<td class="liste_titre"><input class="flat" type="text" name="search_nom" size="8" value="'.dol_escape_htmltag($search_nom).'"></td>';
463print '<td class="liste_titre"></td>';
464print '<td class="liste_titre"></td>';
465print '<td class="liste_titre"></td>';
466if ($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
475print $hookmanager->resPrint;
476
477print '<td class="liste_titre maxwidthsearch">';
478$searchpicto = $form->showFilterAndCheckAddButtons(0);
479print $searchpicto;
480print '</td>';
481print '</tr>';
482
483$fieldtosortcurrentstock = 'stock';
484if (!empty($search_fk_warehouse)) {
485 $fieldtosortcurrentstock = 'stock_reel';
486}
487
488// Lines of title
489print '<tr class="liste_titre">';
490print_liste_field_titre('ProductRef', $_SERVER["PHP_SELF"], 'p.ref', $param, '', '', $sortfield, $sortorder);
491print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', '', $sortfield, $sortorder);
492
493if ($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
506// Hook fields
507$parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
508$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
509print $hookmanager->resPrint;
510
511print_liste_field_titre('', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
512
513print "</tr>\n";
514
515$totalbuyingprice = 0;
516$totalcurrentstock = 0;
517$totalvirtualstock = 0;
518
519$i = 0;
520while ($i < ($limit ? min($num, $limit) : $num)) {
521 $objp = $db->fetch_object($resql);
522
523 if (!empty($conf->global->STOCK_SUPPORTS_SERVICES) || $objp->fk_product_type == 0) {
524 $prod->fetch($objp->rowid);
525
526 // Multilangs
527 /*if (getDolGlobalInt('MAIN_MULTILANGS'))
528 {
529 $sql = 'SELECT label,description';
530 $sql .= ' FROM '.MAIN_DB_PREFIX.'product_lang';
531 $sql .= ' WHERE fk_product = '.((int) $objp->rowid);
532 $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
533 $sql .= ' LIMIT 1';
534
535 $resqlm = $db->query($sql);
536 if ($resqlm)
537 {
538 $objtp = $db->fetch_object($resqlm);
539 if (!empty($objtp->description)) $objp->description = $objtp->description;
540 if (!empty($objtp->label)) $objp->label = $objtp->label;
541 }
542 }*/
543
544 $currentstock = '';
545 if (!empty($search_fk_warehouse)) {
546 //if ($productid > 0) {
547 foreach ($search_fk_warehouse as $val) {
548 if (!is_numeric($currentstock)) {
549 $currentstock = 0;
550 }
551 $currentstock += $stock_prod_warehouse[$objp->rowid][$val];
552 }
553 //} else {
554 // $currentstock = $objp->stock_reel;
555 //}
556 } else {
557 //if ($productid > 0) {
558 $currentstock = $stock_prod[$objp->rowid];
559 //} else {
560 // $currentstock = $objp->stock;
561 //}
562 }
563
564 if ($mode == 'future') {
565 $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0, $dateendofday);
566 $stock = $prod->stock_theorique; // virtual stock at a date
567 $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0);
568 $virtualstock = $prod->stock_theorique; // virtual stock in infinite future
569 } else {
570 $stock = $currentstock;
571 $nbofmovement = 0;
572 if (!empty($search_fk_warehouse)) {
573 foreach ($search_fk_warehouse as $val) {
574 $stock -= $movements_prod_warehouse[$objp->rowid][$val];
575 $nbofmovement += $movements_prod_warehouse_nb[$objp->rowid][$val];
576 }
577 } else {
578 $stock -= $movements_prod[$objp->rowid];
579 $nbofmovement += $movements_prod_nb[$objp->rowid];
580 }
581 }
582
583
584 print '<tr class="oddeven">';
585
586 // Product ref
587 print '<td class="nowrap">'.$prod->getNomUrl(1, '').'</td>';
588
589 // Product label
590 print '<td>';
591 print dol_escape_htmltag($objp->label);
592 print '</td>';
593
594 if ($mode == 'future') {
595 // Current stock
596 print '<td class="right">'.$currentstock.'</td>';
597 $totalcurrentstock += $currentstock;
598
599 print '<td class="right"></td>';
600
601 // Virtual stock at date
602 print '<td class="right">'.$stock.'</td>';
603
604 // Final virtual stock
605 print '<td class="right">'.$virtualstock.'</td>';
606 $totalvirtualstock += $virtualstock;
607 } else {
608 // Stock at date
609 print '<td class="right">'.($stock ? $stock : '<span class="opacitymedium">'.$stock.'</span>').'</td>';
610
611 // PMP value
612 print '<td class="right">';
613 if (price2num($stock * $objp->pmp, 'MT')) {
614 print '<span class="amount">'.price(price2num($stock * $objp->pmp, 'MT'), 1).'</span>';
615 } else {
616 print '';
617 }
618 $totalbuyingprice += $stock * $objp->pmp;
619 print '</td>';
620
621 // Selling value
622 print '<td class="right">';
623 if (empty($conf->global->PRODUIT_MULTIPRICES)) {
624 print price(price2num($objp->sellvalue, 'MT'), 1);
625 } else {
626 $htmltext = $langs->trans("OptionMULTIPRICESIsOn");
627 print $form->textwithtooltip('<span class="opacitymedium">'.$langs->trans("Variable").'</span>', $htmltext);
628 }
629 print'</td>';
630
631 print '<td class="right">';
632 if ($nbofmovement > 0) {
633 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$objp->rowid;
634 foreach ($search_fk_warehouse as $val) {
635 print ($val > 0 ? '&search_warehouse='.$val : '');
636 }
637 print '">'.$langs->trans("Movements").'</a>';
638 print ' <span class="tabs"><span class="badge">'.$nbofmovement.'</span></span>';
639 }
640 print '</td>';
641
642 // Current stock
643 print '<td class="right">'.($currentstock ? $currentstock : '<span class="opacitymedium">0</span>').'</td>';
644 $totalcurrentstock += $currentstock;
645 }
646
647 // Fields from hook
648 $parameters = array('objp'=>$objp);
649 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
650 print $hookmanager->resPrint;
651
652 // Action
653 print '<td class="right"></td>';
654
655 print '</tr>'."\n";
656 }
657 $i++;
658}
659
660$parameters = array('sql'=>$sql);
661$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook
662print $hookmanager->resPrint;
663
664$colspan = 8;
665if ($mode == 'future') {
666 $colspan++;
667}
668
669
670if (empty($date) || !$dateIsValid) {
671 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("EnterADateCriteria").'</span></td></tr>';
672} else {
673 print '<tr class="liste_total">';
674 print '<td>'.$langs->trans("Totalforthispage").'</td>';
675 print '<td></td>';
676 if ($mode == 'future') {
677 print '<td class="right">'.price(price2num($totalcurrentstock, 'MS')).'</td>';
678 print '<td></td>';
679 print '<td></td>';
680 print '<td class="right">'.price(price2num($totalvirtualstock, 'MS')).'</td>';
681 } else {
682 print '<td></td>';
683 print '<td class="right">'.price(price2num($totalbuyingprice, 'MT')).'</td>';
684 print '<td></td>';
685 print '<td></td>';
686 print '<td class="right">'.($productid > 0 ? price(price2num($totalcurrentstock, 'MS')) : '').'</td>';
687 }
688 print '<td></td>';
689 print '</tr>';
690}
691
692print '</table>';
693print '</div>';
694
695if (!empty($resql)) {
696 $db->free($resql);
697}
698
699print dol_get_fiche_end();
700
701print '</form>';
702
703llxFooter();
704
705$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.
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.
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.