dolibarr 19.0.3
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 (getDolGlobalString('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 (getDolGlobalString('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 (getDolGlobalString('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 currentvalue, 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 currentvalue, 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 (!getDolGlobalString('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$totalsellingprice = 0;
517$totalcurrentstock = 0;
518$totalvirtualstock = 0;
519
520$i = 0;
521while ($i < ($limit ? min($num, $limit) : $num)) {
522 $objp = $db->fetch_object($resql);
523
524 if (getDolGlobalString('STOCK_SUPPORTS_SERVICES') || $objp->fk_product_type == 0) {
525 $prod->fetch($objp->rowid);
526
527 // Multilangs
528 /*if (getDolGlobalInt('MAIN_MULTILANGS'))
529 {
530 $sql = 'SELECT label,description';
531 $sql .= ' FROM '.MAIN_DB_PREFIX.'product_lang';
532 $sql .= ' WHERE fk_product = '.((int) $objp->rowid);
533 $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
534 $sql .= ' LIMIT 1';
535
536 $resqlm = $db->query($sql);
537 if ($resqlm)
538 {
539 $objtp = $db->fetch_object($resqlm);
540 if (!empty($objtp->description)) $objp->description = $objtp->description;
541 if (!empty($objtp->label)) $objp->label = $objtp->label;
542 }
543 }*/
544
545 $currentstock = '';
546 if (!empty($search_fk_warehouse)) {
547 //if ($productid > 0) {
548 foreach ($search_fk_warehouse as $val) {
549 if (!is_numeric($currentstock)) {
550 $currentstock = 0;
551 }
552 $currentstock += $stock_prod_warehouse[$objp->rowid][$val];
553 }
554 //} else {
555 // $currentstock = $objp->stock_reel;
556 //}
557 } else {
558 //if ($productid > 0) {
559 $currentstock = $stock_prod[$objp->rowid];
560 //} else {
561 // $currentstock = $objp->stock;
562 //}
563 }
564
565 if ($mode == 'future') {
566 $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0, $dateendofday);
567 $stock = $prod->stock_theorique; // virtual stock at a date
568 $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0);
569 $virtualstock = $prod->stock_theorique; // virtual stock in infinite future
570 } else {
571 $stock = $currentstock;
572 $nbofmovement = 0;
573 if (!empty($search_fk_warehouse)) {
574 foreach ($search_fk_warehouse as $val) {
575 $stock -= $movements_prod_warehouse[$objp->rowid][$val];
576 $nbofmovement += $movements_prod_warehouse_nb[$objp->rowid][$val];
577 }
578 } else {
579 $stock -= $movements_prod[$objp->rowid];
580 $nbofmovement += $movements_prod_nb[$objp->rowid];
581 }
582 }
583
584
585 print '<tr class="oddeven">';
586
587 // Product ref
588 print '<td class="nowrap">'.$prod->getNomUrl(1, '').'</td>';
589
590 // Product label
591 print '<td>';
592 print dol_escape_htmltag($objp->label);
593 print '</td>';
594
595 if ($mode == 'future') {
596 // Current stock
597 print '<td class="right">'.$currentstock.'</td>';
598 $totalcurrentstock += $currentstock;
599
600 print '<td class="right"></td>';
601
602 // Virtual stock at date
603 print '<td class="right">'.$stock.'</td>';
604
605 // Final virtual stock
606 print '<td class="right">'.$virtualstock.'</td>';
607 $totalvirtualstock += $virtualstock;
608 } else {
609 // Stock at date
610 print '<td class="right">'.($stock ? $stock : '<span class="opacitymedium">'.$stock.'</span>').'</td>';
611
612 // PMP value
613 print '<td class="right">';
614 $estimatedvalue = $stock * $objp->pmp;
615 if (price2num($estimatedvalue, 'MT')) {
616 print '<span class="amount">'.price(price2num($estimatedvalue, 'MT'), 1).'</span>';
617 } else {
618 print '';
619 }
620 $totalbuyingprice += $estimatedvalue;
621 print '</td>';
622
623 // Selling value
624 print '<td class="right">';
625 if (!getDolGlobalString('PRODUIT_MULTIPRICES')) {
626 print '<span class="amount">';
627 if ($stock || (float) ($stock * $objp->price)) {
628 print price(price2num($stock * $objp->price, 'MT'), 1);
629 }
630 print '</span>';
631 $totalsellingprice += $stock * $objp->price;
632 } else {
633 $htmltext = $langs->trans("OptionMULTIPRICESIsOn");
634 print $form->textwithtooltip('<span class="opacitymedium">'.$langs->trans("Variable").'</span>', $htmltext);
635 }
636 print '</td>';
637
638 print '<td class="right">';
639 if ($nbofmovement > 0) {
640 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$objp->rowid;
641 foreach ($search_fk_warehouse as $val) {
642 print($val > 0 ? '&search_warehouse='.$val : '');
643 }
644 print '">'.$langs->trans("Movements").'</a>';
645 print ' <span class="tabs"><span class="badge">'.$nbofmovement.'</span></span>';
646 }
647 print '</td>';
648
649 // Current stock
650 print '<td class="right">'.($currentstock ? $currentstock : '<span class="opacitymedium">0</span>').'</td>';
651 $totalcurrentstock += $currentstock;
652 }
653
654 // Fields from hook
655 $parameters = array('objp'=>$objp);
656 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
657 print $hookmanager->resPrint;
658
659 // Action
660 print '<td class="right"></td>';
661
662 print '</tr>'."\n";
663 }
664 $i++;
665}
666
667$parameters = array('sql'=>$sql);
668$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook
669print $hookmanager->resPrint;
670
671$colspan = 8;
672if ($mode == 'future') {
673 $colspan++;
674}
675
676
677if (empty($date) || !$dateIsValid) {
678 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("EnterADateCriteria").'</span></td></tr>';
679} else {
680 print '<tr class="liste_total">';
681 print '<td>'.$langs->trans("Totalforthispage").'</td>';
682 print '<td></td>';
683 if ($mode == 'future') {
684 print '<td class="right">'.price(price2num($totalcurrentstock, 'MS')).'</td>';
685 print '<td></td>';
686 print '<td></td>';
687 print '<td class="right">'.price(price2num($totalvirtualstock, 'MS')).'</td>';
688 } else {
689 print '<td></td>';
690 print '<td class="right">'.price(price2num($totalbuyingprice, 'MT')).'</td>';
691 if (!getDolGlobalString('PRODUIT_MULTIPRICES')) {
692 print '<td class="right">'.price(price2num($totalsellingprice, 'MT')).'</td>';
693 } else {
694 print '<td></td>';
695 }
696 print '<td></td>';
697 print '<td class="right">'.($productid > 0 ? price(price2num($totalcurrentstock, 'MS')) : '').'</td>';
698 }
699 print '<td></td>';
700 print '</tr>';
701}
702
703print '</table>';
704print '</div>';
705
706if (!empty($resql)) {
707 $db->free($resql);
708}
709
710print dol_get_fiche_end();
711
712print '</form>';
713
714llxFooter();
715
716$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:55
llxFooter()
Empty footer.
Definition wrapper.php:69
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 a 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.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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.