dolibarr 19.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
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">';
461// Action column
462if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
463 print '<td class="liste_titre center maxwidthsearch">';
464 $searchpicto = $form->showFilterButtons('left');
465 print $searchpicto;
466 print '</td>';
467}
468print '<td class="liste_titre"><input class="flat" type="text" name="search_ref" size="8" value="'.dol_escape_htmltag($search_ref).'"></td>';
469print '<td class="liste_titre"><input class="flat" type="text" name="search_nom" size="8" value="'.dol_escape_htmltag($search_nom).'"></td>';
470print '<td class="liste_titre"></td>';
471print '<td class="liste_titre"></td>';
472print '<td class="liste_titre"></td>';
473if ($mode == 'future') {
474 print '<td class="liste_titre"></td>';
475} else {
476 print '<td class="liste_titre"></td>';
477 print '<td class="liste_titre"></td>';
478}
479// Fields from hook
480$parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
481$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
482print $hookmanager->resPrint;
483
484// Action column
485if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
486 print '<td class="liste_titre center maxwidthsearch">';
487 $searchpicto = $form->showFilterButtons();
488 print $searchpicto;
489 print '</td>';
490}
491print '</tr>';
492
493$fieldtosortcurrentstock = 'stock';
494if (!empty($search_fk_warehouse)) {
495 $fieldtosortcurrentstock = 'stock_reel';
496}
497
498// Lines of title
499print '<tr class="liste_titre">';
500// Action column
501if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
502 print_liste_field_titre('', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'left ');
503}
504print_liste_field_titre('ProductRef', $_SERVER["PHP_SELF"], 'p.ref', $param, '', '', $sortfield, $sortorder);
505print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', '', $sortfield, $sortorder);
506
507if ($mode == 'future') {
508 print_liste_field_titre('CurrentStock', $_SERVER["PHP_SELF"], $fieldtosortcurrentstock, $param, '', '', $sortfield, $sortorder, 'right ');
509 print_liste_field_titre('', $_SERVER["PHP_SELF"]);
510 print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockAtDateDesc');
511 print_liste_field_titre('VirtualStock', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockDesc');
512} else {
513 print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
514 print_liste_field_titre("EstimatedStockValue", $_SERVER["PHP_SELF"], "currentvalue", '', $param, '', $sortfield, $sortorder, 'right ', $langs->trans("AtDate"), 1);
515 print_liste_field_titre("EstimatedStockValueSell", $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'right ', $langs->trans("AtDate"), 1);
516 print_liste_field_titre('', $_SERVER["PHP_SELF"]);
517 print_liste_field_titre('CurrentStock', $_SERVER["PHP_SELF"], $fieldtosortcurrentstock, $param, '', '', $sortfield, $sortorder, 'right ');
518}
519
520// Hook fields
521$parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
522$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
523print $hookmanager->resPrint;
524
525// Action column
526if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
527 print_liste_field_titre('', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
528}
529
530print "</tr>\n";
531
532$totalbuyingprice = 0;
533$totalsellingprice = 0;
534$totalcurrentstock = 0;
535$totalvirtualstock = 0;
536
537$i = 0;
538while ($i < ($limit ? min($num, $limit) : $num)) {
539 $objp = $db->fetch_object($resql);
540
541 if (getDolGlobalString('STOCK_SUPPORTS_SERVICES') || $objp->fk_product_type == 0) {
542 $prod->fetch($objp->rowid);
543
544 // Multilangs
545 /*if (getDolGlobalInt('MAIN_MULTILANGS'))
546 {
547 $sql = 'SELECT label,description';
548 $sql .= ' FROM '.MAIN_DB_PREFIX.'product_lang';
549 $sql .= ' WHERE fk_product = '.((int) $objp->rowid);
550 $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
551 $sql .= ' LIMIT 1';
552
553 $resqlm = $db->query($sql);
554 if ($resqlm)
555 {
556 $objtp = $db->fetch_object($resqlm);
557 if (!empty($objtp->description)) $objp->description = $objtp->description;
558 if (!empty($objtp->label)) $objp->label = $objtp->label;
559 }
560 }*/
561
562 $currentstock = '';
563 if (!empty($search_fk_warehouse)) {
564 //if ($productid > 0) {
565 foreach ($search_fk_warehouse as $val) {
566 if (!is_numeric($currentstock)) {
567 $currentstock = 0;
568 }
569 $currentstock += $stock_prod_warehouse[$objp->rowid][$val];
570 }
571 //} else {
572 // $currentstock = $objp->stock_reel;
573 //}
574 } else {
575 //if ($productid > 0) {
576 $currentstock = $stock_prod[$objp->rowid];
577 //} else {
578 // $currentstock = $objp->stock;
579 //}
580 }
581
582 if ($mode == 'future') {
583 $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0, $dateendofday);
584 $stock = $prod->stock_theorique; // virtual stock at a date
585 $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0);
586 $virtualstock = $prod->stock_theorique; // virtual stock in infinite future
587 } else {
588 $stock = $currentstock;
589 $nbofmovement = 0;
590 if (!empty($search_fk_warehouse)) {
591 foreach ($search_fk_warehouse as $val) {
592 $stock -= $movements_prod_warehouse[$objp->rowid][$val];
593 $nbofmovement += $movements_prod_warehouse_nb[$objp->rowid][$val];
594 }
595 } else {
596 $stock -= $movements_prod[$objp->rowid];
597 $nbofmovement += $movements_prod_nb[$objp->rowid];
598 }
599 }
600
601
602 print '<tr class="oddeven">';
603
604 // Action column
605 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
606 print '<td class="left"></td>';
607 }
608
609 // Product ref
610 print '<td class="nowrap">'.$prod->getNomUrl(1, '').'</td>';
611
612 // Product label
613 print '<td>';
614 print dol_escape_htmltag($objp->label);
615 print '</td>';
616
617 if ($mode == 'future') {
618 // Current stock
619 print '<td class="right">'.$currentstock.'</td>';
620 $totalcurrentstock += $currentstock;
621
622 print '<td class="right"></td>';
623
624 // Virtual stock at date
625 print '<td class="right">'.$stock.'</td>';
626
627 // Final virtual stock
628 print '<td class="right">'.$virtualstock.'</td>';
629 $totalvirtualstock += $virtualstock;
630 } else {
631 // Stock at date
632 print '<td class="right">'.($stock ? $stock : '<span class="opacitymedium">'.$stock.'</span>').'</td>';
633
634 // PMP value
635 print '<td class="right">';
636 $estimatedvalue = $stock * $objp->pmp;
637 if (price2num($estimatedvalue, 'MT')) {
638 print '<span class="amount">'.price(price2num($estimatedvalue, 'MT'), 1).'</span>';
639 } else {
640 print '';
641 }
642 $totalbuyingprice += $estimatedvalue;
643 print '</td>';
644
645 // Selling value
646 print '<td class="right">';
647 if (!getDolGlobalString('PRODUIT_MULTIPRICES')) {
648 print '<span class="amount">';
649 if ($stock || (float) ($stock * $objp->price)) {
650 print price(price2num($stock * $objp->price, 'MT'), 1);
651 }
652 print '</span>';
653 $totalsellingprice += $stock * $objp->price;
654 } else {
655 $htmltext = $langs->trans("OptionMULTIPRICESIsOn");
656 print $form->textwithtooltip('<span class="opacitymedium">'.$langs->trans("Variable").'</span>', $htmltext);
657 }
658 print '</td>';
659
660 print '<td class="right">';
661 if ($nbofmovement > 0) {
662 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$objp->rowid;
663 foreach ($search_fk_warehouse as $val) {
664 print($val > 0 ? '&search_warehouse='.$val : '');
665 }
666 print '">'.$langs->trans("Movements").'</a>';
667 print ' <span class="tabs"><span class="badge">'.$nbofmovement.'</span></span>';
668 }
669 print '</td>';
670
671 // Current stock
672 print '<td class="right">'.($currentstock ? $currentstock : '<span class="opacitymedium">0</span>').'</td>';
673 $totalcurrentstock += $currentstock;
674 }
675
676 // Fields from hook
677 $parameters = array('objp'=>$objp);
678 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
679 print $hookmanager->resPrint;
680
681 // Action column
682 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
683 print '<td class="right"></td>';
684 }
685
686 print '</tr>'."\n";
687 }
688 $i++;
689}
690
691$parameters = array('sql'=>$sql);
692$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook
693print $hookmanager->resPrint;
694
695$colspan = 8;
696if ($mode == 'future') {
697 $colspan++;
698}
699
700
701if (empty($date) || !$dateIsValid) {
702 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("EnterADateCriteria").'</span></td></tr>';
703} else {
704 print '<tr class="liste_total">';
705 print '<td>'.$langs->trans("Totalforthispage").'</td>';
706 print '<td></td>';
707 if ($mode == 'future') {
708 print '<td class="right">'.price(price2num($totalcurrentstock, 'MS')).'</td>';
709 print '<td></td>';
710 print '<td></td>';
711 print '<td class="right">'.price(price2num($totalvirtualstock, 'MS')).'</td>';
712 } else {
713 print '<td></td>';
714 print '<td class="right">'.price(price2num($totalbuyingprice, 'MT')).'</td>';
715 if (!getDolGlobalString('PRODUIT_MULTIPRICES')) {
716 print '<td class="right">'.price(price2num($totalsellingprice, 'MT')).'</td>';
717 } else {
718 print '<td></td>';
719 }
720 print '<td></td>';
721 print '<td class="right">'.($productid > 0 ? price(price2num($totalcurrentstock, 'MS')) : '').'</td>';
722 }
723 print '<td></td>';
724 print '</tr>';
725}
726
727print '</table>';
728print '</div>';
729
730if (!empty($resql)) {
731 $db->free($resql);
732}
733
734print dol_get_fiche_end();
735
736print '</form>';
737
738llxFooter();
739
740$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.