From 6a70af2b67ab26b4baa538d9efd7269d72f522e1 Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Tue, 9 Dec 2014 14:03:10 +0100
Subject: [PATCH] Fixed: bug into produc batch management

---
 htdocs/core/modules/modProductBatch.class.php |  2 +-
 .../stock/class/mouvementstock.class.php      | 41 ++++++++++++++-----
 htdocs/product/stock/product.php              | 33 ++++++++-------
 3 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/htdocs/core/modules/modProductBatch.class.php b/htdocs/core/modules/modProductBatch.class.php
index 6eb358aa99d..4dd7d0a81ae 100644
--- a/htdocs/core/modules/modProductBatch.class.php
+++ b/htdocs/core/modules/modProductBatch.class.php
@@ -49,7 +49,7 @@ class modProductBatch extends DolibarrModules
 		$this->name = preg_replace('/^mod/i','',get_class($this));
 		$this->description = "Batch number, eat-by and sell-by date management module";
 
-		$this->rights_class = 'stock';
+		$this->rights_class = 'productbatch';
 		// Possible values for version are: 'development', 'experimental', 'dolibarr' or version
 		$this->version = 'experimental';
 		// Key used in llx_const table to save module status enabled/disabled (where dluo is value of property name of module in uppercase)
diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php
index 9e508f41461..24ca13da355 100644
--- a/htdocs/product/stock/class/mouvementstock.class.php
+++ b/htdocs/product/stock/class/mouvementstock.class.php
@@ -163,21 +163,40 @@ class MouvementStock extends CommonObject
 			{
 				$newpmp=0;
 				$newpmpwarehouse=0;
-				// Note: PMP is calculated on stock input only (type = 0 or 3). If type == 0 or 3, qty should be > 0.
+				// Note: PMP is calculated on stock input only (type of movement = 0 or 3). If type == 0 or 3, qty should be > 0.
 				// Note: Price should always be >0 or 0. PMP should be always >0 (calculated on input)
 				if (($type == 0 || $type == 3) && $price > 0)
 				{
+					// If we will change PMP for the warehouse we edit and the product, we must first check/clean that PMP is defined
+					// on every stock entry with old value (so global updated value will match recalculated value from product_stock)
+					$sql = "UPDATE ".MAIN_DB_PREFIX."product_stock SET pmp = ".($oldpmp?$oldpmp:'0');
+					$sql.= " WHERE pmp = 0 AND fk_product = ".$fk_product;
+					dol_syslog(get_class($this)."::_create", LOG_DEBUG);
+					$resql=$this->db->query($sql);
+					if (! $resql)
+					{
+						$this->error=$this->db->lasterror();
+						$error = -4;
+					}
+					
 					$oldqtytouse=($oldqty >= 0?$oldqty:0);
 					// We make a test on oldpmp>0 to avoid to use normal rule on old data with no pmp field defined
 					if ($oldpmp > 0) $newpmp=price2num((($oldqtytouse * $oldpmp) + ($qty * $price)) / ($oldqtytouse + $qty), 'MU');
-					else $newpmp=$price;
-					$oldqtywarehousetouse=($oldqtywarehouse >= 0?$oldqtywarehouse:0);
+					else 
+					{
+						$newpmp=$price; // For this product, PMP was not yet set. We will set it later.
+					}
+					$oldqtywarehousetouse=$oldqtywarehouse;
 					if ($oldpmpwarehouse > 0) $newpmpwarehouse=price2num((($oldqtywarehousetouse * $oldpmpwarehouse) + ($qty * $price)) / ($oldqtywarehousetouse + $qty), 'MU');
 					else $newpmpwarehouse=$price;
 
-					//print "oldqtytouse=".$oldqtytouse." oldpmp=".$oldpmp." oldqtywarehousetouse=".$oldqtywarehousetouse." oldpmpwarehouse=".$oldpmpwarehouse." ";
-					//print "qty=".$qty." newpmp=".$newpmp." newpmpwarehouse=".$newpmpwarehouse;
-					//exit;
+					/*print "oldqtytouse=".$oldqtytouse." oldpmp=".$oldpmp." oldqtywarehousetouse=".$oldqtywarehousetouse." oldpmpwarehouse=".$oldpmpwarehouse." ";
+					print "qty=".$qty." newpmp=".$newpmp." newpmpwarehouse=".$newpmpwarehouse;
+					exit;*/
+				}
+				else if ($type == 1 || $type == 2)
+				{
+					// After a stock decrease, we don't change value of PMP for product.					
 				}
 				else
 				{
@@ -207,14 +226,17 @@ class MouvementStock extends CommonObject
 				{
 					$this->error=$this->db->lasterror();
 					$error = -3;
-				} else if(empty($fk_product_stock)){
+				} 
+				else if(empty($fk_product_stock))
+				{
 					$fk_product_stock = $this->db->last_insert_id(MAIN_DB_PREFIX."product_stock");
 				}
 
-				}
+			}
 
 			// Update detail stock for sell-by date
-			if (($product->hasbatch()) && (! $error) && (! $skip_sellby)){
+			if (($product->hasbatch()) && (! $error) && (! $skip_sellby))
+			{
 				$param_batch=array('fk_product_stock' =>$fk_product_stock, 'eatby'=>$eatby,'sellby'=>$sellby,'batchnumber'=>$batch);
 				$result=$this->_create_batch($param_batch, $qty);
 				if ($result<0) $error++;
@@ -245,7 +267,6 @@ class MouvementStock extends CommonObject
 
 		if ($movestock && ! $error)
 		{
-
 			$this->product_id = $fk_product;
 			$this->entrepot_id = $entrepot_id;
 			$this->qty = $qty;
diff --git a/htdocs/product/stock/product.php b/htdocs/product/stock/product.php
index f6dfe3150b1..e7be28b96bd 100644
--- a/htdocs/product/stock/product.php
+++ b/htdocs/product/stock/product.php
@@ -122,10 +122,11 @@ if ($action == "correct_stock" && ! $cancel)
 		if (is_numeric(GETPOST("nbpiece")) && $id)
 		{
 			if (empty($product)) {
-			$product = new Product($db);
-			$result=$product->fetch($id);
+				$product = new Product($db);
+				$result=$product->fetch($id);
 			}
-			if ($product->hasbatch()) {
+			if ($product->hasbatch()) 
+			{
 				$d_eatby=dol_mktime(12, 0, 0, $_POST['eatbymonth'], $_POST['eatbyday'], $_POST['eatbyyear']);
 				$d_sellby=dol_mktime(12, 0, 0, $_POST['sellbymonth'], $_POST['sellbyday'], $_POST['sellbyyear']);
 				$result=$product->correct_stock_batch(
@@ -139,15 +140,17 @@ if ($action == "correct_stock" && ! $cancel)
 					$d_sellby,
 					GETPOST('batch_number')
 				);		// We do not change value of stock for a correction
-			} else {
-			$result=$product->correct_stock(
-	    		$user,
-	    		GETPOST("id_entrepot"),
-	    		GETPOST("nbpiece"),
-	    		GETPOST("mouvement"),
-	    		GETPOST("label"),
-	    		$priceunit
-			);		// We do not change value of stock for a correction
+			} 
+			else
+			{
+				$result=$product->correct_stock(
+		    		$user,
+		    		GETPOST("id_entrepot"),
+		    		GETPOST("nbpiece"),
+		    		GETPOST("mouvement"),
+		    		GETPOST("label"),
+		    		$priceunit
+				);		// We do not change value of stock for a correction
 			}
 
 			if ($result > 0)
@@ -645,8 +648,8 @@ if ($resql)
 		print '</tr>'; ;
 		$total += $obj->reel;
 		if (price2num($obj->pmp)) $totalwithpmp += $obj->reel;
-		$totalvalue = $totalvalue + price2num($obj->pmp*$obj->reel,'MU'); // Ditto : Show PMP from movement or from product
-        $totalvaluesell = $totalvaluesell + price2num($product->price*$obj->reel,'MU'); // Ditto : Show PMP from movement or from product
+		$totalvalue = $totalvalue + ($obj->pmp*$obj->reel); // Ditto : Show PMP from movement or from product
+        $totalvaluesell = $totalvaluesell + ($product->price*$obj->reel); // Ditto : Show PMP from movement or from product
 		//Batch Detail
 		if ((! empty($conf->productbatch->enabled)) && $product->hasbatch()) 
 		{
@@ -670,7 +673,7 @@ else dol_print_error($db);
 print '<tr class="liste_total"><td align="right" class="liste_total" colspan="4">'.$langs->trans("Total").':</td>';
 print '<td class="liste_total" align="right">'.$total.'</td>';
 print '<td class="liste_total" align="right">';
-print ($totalwithpmp?price($totalvalue/$totalwithpmp):'&nbsp;');
+print ($totalwithpmp?price(price2num(price2num($totalvalue,'MT')/$totalwithpmp,'MT')):'&nbsp;');	// This value may have rounding errors
 print '</td>';
 // Value purchase
 print '<td class="liste_total" align="right">';
-- 
GitLab