diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang
index 75a12d517d0..f46307a21ae 100644
--- a/htdocs/langs/en_US/errors.lang
+++ b/htdocs/langs/en_US/errors.lang
@@ -136,7 +136,8 @@ ErrorNewValueCantMatchOldValue=New value can't be equal to old one
ErrorFailedToValidatePasswordReset=Failed to reinit password. May be the reinit was already done (this link can be used only one time). If not, try to restart the reinit process.
ErrorToConnectToMysqlCheckInstance=Connect to database fails. Check database server is running (for example, with mysql/mariadb, you can launch it from command line with 'sudo service mysql start').
ErrorFailedToAddContact=Failed to add contact
-ErrorDateMustBeBeforeToday=The date cannot be greater than today
+ErrorDateMustBeBeforeToday=The date must be lower than today
+ErrorDateMustBeInFuture=The date must be greater than today
ErrorPaymentModeDefinedToWithoutSetup=A payment mode was set to type %s but setup of module Invoice was not completed to define information to show for this payment mode.
ErrorPHPNeedModule=Error, your PHP must have module %s installed to use this feature.
ErrorOpenIDSetupNotComplete=You setup Dolibarr config file to allow OpenID authentication, but URL of OpenID service is not defined into constant %s
diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang
index 41c88747498..9ce03f64942 100644
--- a/htdocs/langs/en_US/stocks.lang
+++ b/htdocs/langs/en_US/stocks.lang
@@ -95,6 +95,8 @@ RealStock=Real Stock
RealStockDesc=Physical/real stock is the stock currently in the warehouses.
RealStockWillAutomaticallyWhen=The real stock will be modified according to this rule (as defined in the Stock module):
VirtualStock=Virtual stock
+VirtualStockAtDate=Virtual stock at date
+VirtualStockAtDateDesc=Virtual stock atonce all pending orders that are planned to be done before the date will be finished
VirtualStockDesc=Virtual stock is the calculated stock available once all open/pending actions (that affect stocks) are closed (purchase orders received, sales orders shipped, manufacturing orders produced, etc)
IdWarehouse=Id warehouse
DescWareHouse=Description warehouse
diff --git a/htdocs/product/stock/stockatdate.php b/htdocs/product/stock/stockatdate.php
index 288db71fb15..9b03d5ecfc4 100644
--- a/htdocs/product/stock/stockatdate.php
+++ b/htdocs/product/stock/stockatdate.php
@@ -1,6 +1,6 @@
- * Copyright (C) 2013-2018 Laurent Destaileur
+ * Copyright (C) 2013-2020 Laurent Destaileur
* Copyright (C) 2014 Regis Houssin
* Copyright (C) 2016 Juanjo Menent
* Copyright (C) 2016 ATM Consulting
@@ -59,9 +59,10 @@ if (GETPOSTISSET('dateday') && GETPOSTISSET('datemonth') && GETPOSTISSET('dateye
$dateendofday = dol_mktime(23, 59, 59, GETPOST('datemonth', 'int'), GETPOST('dateday', 'int'), GETPOST('dateyear', 'int'));
}
+$now = dol_now();
+
$productid = GETPOST('productid', 'int');
$fk_warehouse = GETPOST('fk_warehouse', 'int');
-$texte = '';
$sortfield = GETPOST('sortfield', 'alpha');
$sortorder = GETPOST('sortorder', 'alpha');
@@ -80,6 +81,19 @@ $parameters = array();
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
+$dateIsValid= true;
+if ($mode == 'future') {
+ if ($date && $date < $now) {
+ setEventMessages($langs->trans("ErrorDateMustBeInFuture"), null, 'errors');
+ $dateIsValid= false;
+ }
+} else {
+ if ($date && $date > $now) {
+ setEventMessages($langs->trans("ErrorDateMustBeBeforeToday"), null, 'errors');
+ $dateIsValid= false;
+ }
+}
+
/*
* Actions
@@ -99,11 +113,10 @@ if ($conf->global->ENTREPOT_EXTRA_STATUS) {
$warehouseStatus[] = Entrepot::STATUS_OPEN_INTERNAL;
}
-
// Get array with current stock per product, warehouse
$stock_prod_warehouse = array();
$stock_prod = array();
-if ($date) { // Avoid heavy sql if mandatory date is not defined
+if ($date && $dateIsValid) { // Avoid heavy sql if mandatory date is not defined
$sql = "SELECT ps.fk_product, ps.fk_entrepot as fk_warehouse,";
$sql .= " SUM(ps.reel) AS stock";
$sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps";
@@ -146,13 +159,17 @@ if ($date) { // Avoid heavy sql if mandatory date is not defined
dol_print_error($db);
}
//var_dump($stock_prod_warehouse);
+} elseif ($action == 'filter') {
+ setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
}
// Get array with list of stock movements between date and now (for product/warehouse=
$movements_prod_warehouse = array();
$movements_prod = array();
-if ($date) {
- $sql = "SELECT sm.fk_product, sm.fk_entrepot, SUM(sm.value) AS stock";
+$movements_prod_warehouse_nb = array();
+$movements_prod_nb = array();
+if ($date && $dateIsValid) {
+ $sql = "SELECT sm.fk_product, sm.fk_entrepot, SUM(sm.value) AS stock, COUNT(sm.rowid) AS nbofmovement";
$sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as sm";
$sql .= ", ".MAIN_DB_PREFIX."entrepot as w";
$sql .= " WHERE w.entity IN (".getEntity('stock').")";
@@ -184,12 +201,15 @@ if ($date) {
$fk_product = $obj->fk_product;
$fk_entrepot = $obj->fk_entrepot;
$stock = $obj->stock;
+ $nbofmovement = $obj->nbofmovement;
// Pour llx_product_stock.reel
$movements_prod_warehouse[$fk_product][$fk_entrepot] = $stock;
+ $movements_prod_warehouse_nb[$fk_product][$fk_entrepot] = $nbofmovement;
// Pour llx_product.stock
$movements_prod[$fk_product] += $stock;
+ $movements_prod_nb[$fk_product] += $nbofmovement;
$i++;
}
@@ -259,7 +279,7 @@ if ($sortfield == 'stock' && $fk_warehouse > 0) {
}
$sql .= $db->order($sortfield, $sortorder);
-if ($date) { // We avoid a heavy sql if mandatory parameter date not yet defined
+if ($date && $dateIsValid) { // We avoid a heavy sql if mandatory parameter date not yet defined
$nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
{
@@ -355,7 +375,7 @@ print '