Example #1
0
 }
 if (!$error) {
     if ($id) {
         $product = new Product($db);
         $result = $product->fetch($id);
         $db->begin();
         $product->load_stock();
         // Load array product->stock_warehouse
         // Define value of products moved
         $pricesrc = 0;
         //if (isset($product->stock_warehouse[GETPOST("id_entrepot_source")]->pmp)) $pricesrc=$product->stock_warehouse[GETPOST("id_entrepot_source")]->pmp;
         if (isset($product->pmp)) {
             $pricesrc = $product->pmp;
         }
         $pricedest = $pricesrc;
         if ($product->hasbatch()) {
             $pdluo = new Productbatch($db);
             if ($pdluoid > 0) {
                 $result = $pdluo->fetch($pdluoid);
                 if ($result) {
                     $srcwarehouseid = $pdluo->warehouseid;
                     $batch = $pdluo->batch;
                     $eatby = $pdluo->eatby;
                     $sellby = $pdluo->sellby;
                 } else {
                     setEventMessages($pdluo->error, $pdluo->errors, 'errors');
                     $error++;
                 }
             } else {
                 $srcwarehouseid = GETPOST('id_entrepot_source', 'int');
                 $batch = GETPOST('batch_number');
Example #2
0
 print '<input name="qtydelivered' . $indiceAsked . '" id="qtydelivered' . $indiceAsked . '" type="hidden" value="' . $quantityDelivered . '">';
 print '</td>';
 $quantityAsked = $line->qty;
 if ($line->product_type == 1 && empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
     $quantityToBeDelivered = 0;
 } else {
     $quantityToBeDelivered = $quantityAsked - $quantityDelivered;
 }
 $warehouse_id = GETPOST('entrepot_id', 'int');
 $warehouseObject = null;
 if ($warehouse_id > 0 || !($line->fk_product > 0)) {
     //ship from preselected location
     $stock = +$product->stock_warehouse[$warehouse_id]->real;
     // Convert to number
     $deliverableQty = min($quantityToBeDelivered, $stock);
     if (empty($conf->productbatch->enabled) || !($product->hasbatch() && is_object($product->stock_warehouse[$warehouse_id]))) {
         // Quantity to send
         print '<td align="center">';
         if ($line->product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
             print '<input name="idl' . $indiceAsked . '" type="hidden" value="' . $line->id . '">';
             print '<input name="qtyl' . $indiceAsked . '" id="qtyl' . $indiceAsked . '" type="text" size="4" value="' . $deliverableQty . '">';
         } else {
             print $langs->trans("NA");
         }
         print '</td>';
         // Stock
         if (!empty($conf->stock->enabled)) {
             print '<td align="left">';
             if ($line->product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
                 // Show warehouse combo list
                 $ent = "entl" . $indiceAsked;
 /**
  *	Add a movement of stock (in one direction only)
  *
  *	@param		User	$user			User object
  *	@param		int		$fk_product		Id of product
  *	@param		int		$entrepot_id	Id of warehouse
  *	@param		int		$qty			Qty of movement (can be <0 or >0 depending on parameter type)
  *	@param		int		$type			Direction of movement:
  *										0=input (stock increase after stock transfert), 1=output (stock decrease after stock transfer),
  *										2=output (stock decrease), 3=input (stock increase)
  *                                      Note that qty should be > 0 with 0 or 3, < 0 with 1 or 2.
  *	@param		int		$price			Unit price HT of product, used to calculate average weighted price (PMP in french). If 0, average weighted price is not changed.
  *	@param		string	$label			Label of stock movement
  *	@param		string	$inventorycode	Inventory code
  *	@param		string	$datem			Force date of movement
  *	@param		date	$eatby			eat-by date
  *	@param		date	$sellby			sell-by date
  *	@param		string	$batch			batch number
  *	@param		boolean	$skip_batch		If set to true, stock movement is done without impacting batch record
  *	@return		int						<0 if KO, 0 if fk_product is null, >0 if OK
  */
 function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = 0, $label = '', $inventorycode = '', $datem = '', $eatby = '', $sellby = '', $batch = '', $skip_batch = false)
 {
     global $conf, $langs;
     require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
     $error = 0;
     dol_syslog(get_class($this) . "::_create start userid={$user->id}, fk_product={$fk_product}, warehouse={$entrepot_id}, qty={$qty}, type={$type}, price={$price}, label={$label}, inventorycode={$inventorycode}, datem=" . $datem . ", eatby=" . $eatby . ", sellby=" . $sellby . ", batch=" . $batch . ", skip_batch=" . $skip_batch);
     // Clean parameters
     if (empty($price)) {
         $price = 0;
     }
     $now = !empty($datem) ? $datem : dol_now();
     // Check parameters
     if (empty($fk_product)) {
         return 0;
     }
     if ($eatby < 0) {
         $this->errors[] = 'ErrorBadValueForParameterEatBy';
         return -1;
     }
     if ($sellby < 0) {
         $this->errors[] = 'ErrorBadValueForParameterEatBy';
         return -1;
     }
     // Set properties of movement
     $this->product_id = $fk_product;
     $this->entrepot_id = $entrepot_id;
     $this->qty = $qty;
     $this->type = $type;
     $mvid = 0;
     $product = new Product($this->db);
     $result = $product->fetch($fk_product);
     if ($result < 0) {
         dol_print_error('', "Failed to fetch product");
         return -1;
     }
     $this->db->begin();
     $product->load_stock();
     // Test if product require batch data. If yes, and there is not, we throw an error.
     if (!empty($conf->productbatch->enabled) && $product->hasbatch() && !$skip_batch) {
         //if (empty($batch) && empty($eatby) && empty($sellby))
         if (empty($batch)) {
             $this->errors[] = $langs->trans("ErrorTryToMakeMoveOnProductRequiringBatchData", $product->name);
             dol_syslog("Try to make a movement of a product with status_batch on without any batch data");
             $this->db->rollback();
             return -2;
         }
         // If a serial number is provided, we check that sellby and eatby match already existing serial
         $sql = "SELECT pb.rowid, pb.batch, pb.eatby, pb.sellby FROM " . MAIN_DB_PREFIX . "product_batch as pb, " . MAIN_DB_PREFIX . "product_stock as ps";
         $sql .= " WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = " . $fk_product . " AND pb.batch = '" . $this->db->escape($batch) . "'";
         dol_syslog(get_class($this) . "::_create scan serial for this product to check if eatby and sellby match", LOG_DEBUG);
         $resql = $this->db->query($sql);
         if ($resql) {
             $num = $this->db->num_rows($resql);
             $i = 0;
             while ($i < $num) {
                 $obj = $this->db->fetch_object($resql);
                 if ($this->db->jdate($obj->eatby) != $eatby) {
                     $this->errors[] = $langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->eatby), $eatby);
                     dol_syslog($langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->eatby), $eatby));
                     $this->db->rollback();
                     return -3;
                 }
                 if ($this->db->jdate($obj->sellby) != $sellby) {
                     $this->errors[] = $langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->sellby), $sellby);
                     dol_syslog($langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->sellby), $sellby));
                     $this->db->rollback();
                     return -3;
                 }
                 $i++;
             }
         } else {
             dol_print_error($this->db);
             $this->db->rollback();
             return -1;
         }
     }
     // TODO Check qty is ok for stock move.
     if (!empty($conf->productbatch->enabled) && $product->hasbatch() && !$skip_batch) {
     } else {
     }
     // Define if we must make the stock change (If product type is a service or if stock is used also for services)
     $movestock = 0;
     if ($product->type != Product::TYPE_SERVICE || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
         $movestock = 1;
     }
     if ($movestock && $entrepot_id > 0) {
         if (!empty($this->origin)) {
             // This is set by caller for tracking reason
             $origintype = $this->origin->element;
             $fk_origin = $this->origin->id;
         } else {
             $origintype = '';
             $fk_origin = 0;
         }
         $sql = "INSERT INTO " . MAIN_DB_PREFIX . "stock_mouvement(";
         $sql .= " datem, fk_product, batch, eatby, sellby,";
         $sql .= " fk_entrepot, value, type_mouvement, fk_user_author, label, inventorycode, price, fk_origin, origintype";
         $sql .= ")";
         $sql .= " VALUES ('" . $this->db->idate($now) . "', " . $this->product_id . ", ";
         $sql .= " " . ($batch ? "'" . $batch . "'" : "null") . ", ";
         $sql .= " " . ($eatby ? "'" . $this->db->idate($eatby) . "'" : "null") . ", ";
         $sql .= " " . ($sellby ? "'" . $this->db->idate($sellby) . "'" : "null") . ", ";
         $sql .= " " . $this->entrepot_id . ", " . $this->qty . ", " . $this->type . ",";
         $sql .= " " . $user->id . ",";
         $sql .= " '" . $this->db->escape($label) . "',";
         $sql .= " " . ($inventorycode ? "'" . $this->db->escape($inventorycode) . "'" : "null") . ",";
         $sql .= " '" . price2num($price) . "',";
         $sql .= " '" . $fk_origin . "',";
         $sql .= " '" . $origintype . "'";
         $sql .= ")";
         dol_syslog(get_class($this) . "::_create", LOG_DEBUG);
         $resql = $this->db->query($sql);
         if ($resql) {
             $mvid = $this->db->last_insert_id(MAIN_DB_PREFIX . "stock_mouvement");
             $this->id = $mvid;
         } else {
             $this->errors[] = $this->db->lasterror();
             $error = -1;
         }
         // Define current values for qty and pmp
         $oldqty = $product->stock_reel;
         $oldpmp = $product->pmp;
         $oldqtywarehouse = 0;
         //$oldpmpwarehouse=0;
         // Test if there is already a record for couple (warehouse / product)
         $num = 0;
         if (!$error) {
             $sql = "SELECT rowid, reel FROM " . MAIN_DB_PREFIX . "product_stock";
             $sql .= " WHERE fk_entrepot = " . $entrepot_id . " AND fk_product = " . $fk_product;
             // This is a unique key
             dol_syslog(get_class($this) . "::_create", LOG_DEBUG);
             $resql = $this->db->query($sql);
             if ($resql) {
                 $obj = $this->db->fetch_object($resql);
                 if ($obj) {
                     $num = 1;
                     $oldqtywarehouse = $obj->reel;
                     //$oldpmpwarehouse = $obj->pmp;
                     $fk_product_stock = $obj->rowid;
                 }
                 $this->db->free($resql);
             } else {
                 $this->errors[] = $this->db->lasterror();
                 $error = -2;
             }
         }
         // Calculate new PMP.
         $newpmp = 0;
         //$newpmpwarehouse=0;
         if (!$error) {
             // 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->errors[]=$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;
                     // For this product, PMP was not yet set. We set it to input price.
                 }
                 /*
                 		$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;
             } else {
                 if ($type == 1 || $type == 2) {
                     // After a stock decrease, we don't change value of PMP for product.
                     $newpmp = $oldpmp;
                 } else {
                     $newpmp = $oldpmp;
                     //$newpmpwarehouse = $oldpmpwarehouse;
                 }
             }
         }
         // Update stock quantity
         if (!$error) {
             if ($num > 0) {
                 //$sql = "UPDATE ".MAIN_DB_PREFIX."product_stock SET pmp = ".$newpmpwarehouse.", reel = reel + ".$qty;
                 $sql = "UPDATE " . MAIN_DB_PREFIX . "product_stock SET reel = reel + " . $qty;
                 $sql .= " WHERE fk_entrepot = " . $entrepot_id . " AND fk_product = " . $fk_product;
             } else {
                 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "product_stock";
                 //$sql.= " (pmp, reel, fk_entrepot, fk_product) VALUES ";
                 //$sql.= " (".$newpmpwarehouse.", ".$qty.", ".$entrepot_id.", ".$fk_product.")";
                 $sql .= " (reel, fk_entrepot, fk_product) VALUES ";
                 $sql .= " (" . $qty . ", " . $entrepot_id . ", " . $fk_product . ")";
             }
             dol_syslog(get_class($this) . "::_create", LOG_DEBUG);
             $resql = $this->db->query($sql);
             if (!$resql) {
                 $this->errors[] = $this->db->lasterror();
                 $error = -3;
             } else {
                 if (empty($fk_product_stock)) {
                     $fk_product_stock = $this->db->last_insert_id(MAIN_DB_PREFIX . "product_stock");
                 }
             }
         }
         // Update detail stock for batch product
         if (!$error && !empty($conf->productbatch->enabled) && $product->hasbatch() && !$skip_batch) {
             $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++;
             }
         }
         // Update PMP and denormalized value of stock qty at product level
         if (!$error) {
             $sql = "UPDATE " . MAIN_DB_PREFIX . "product SET pmp = " . $newpmp . ", stock = " . $this->db->ifsql("stock IS NULL", 0, "stock") . " + " . $qty;
             $sql .= " WHERE rowid = " . $fk_product;
             // May be this request is better:
             // UPDATE llx_product p SET p.stock= (SELECT SUM(ps.reel) FROM llx_product_stock ps WHERE ps.fk_product = p.rowid);
             dol_syslog(get_class($this) . "::_create", LOG_DEBUG);
             $resql = $this->db->query($sql);
             if (!$resql) {
                 $this->errors[] = $this->db->lasterror();
                 $error = -4;
             }
         }
     }
     // Add movement for sub products (recursive call)
     if (!$error && !empty($conf->global->PRODUIT_SOUSPRODUITS) && empty($conf->global->INDEPENDANT_SUBPRODUCT_STOCK)) {
         $error = $this->_createSubProduct($user, $fk_product, $entrepot_id, $qty, $type, 0, $label, $inventorycode);
         // we use 0 as price, because pmp is not changed for subproduct
     }
     if ($movestock && !$error) {
         // Call trigger
         $result = $this->call_trigger('STOCK_MOVEMENT', $user);
         if ($result < 0) {
             $error++;
         }
         // End call triggers
     }
     if (!$error) {
         $this->db->commit();
         return $mvid;
     } else {
         $this->db->rollback();
         dol_syslog(get_class($this) . "::_create error code=" . $error, LOG_ERR);
         return -6;
     }
 }
Example #4
0
 }
 if (!$error) {
     if ($id) {
         $object = new Product($db);
         $result = $object->fetch($id);
         $db->begin();
         $object->load_stock();
         // Load array product->stock_warehouse
         // Define value of products moved
         $pricesrc = 0;
         //if (isset($object->stock_warehouse[GETPOST("id_entrepot_source")]->pmp)) $pricesrc=$object->stock_warehouse[GETPOST("id_entrepot_source")]->pmp;
         if (isset($object->pmp)) {
             $pricesrc = $object->pmp;
         }
         $pricedest = $pricesrc;
         if ($object->hasbatch()) {
             $pdluo = new Productbatch($db);
             if ($pdluoid > 0) {
                 $result = $pdluo->fetch($pdluoid);
                 if ($result) {
                     $srcwarehouseid = $pdluo->warehouseid;
                     $batch = $pdluo->batch;
                     $eatby = $pdluo->eatby;
                     $sellby = $pdluo->sellby;
                 } else {
                     setEventMessages($pdluo->error, $pdluo->errors, 'errors');
                     $error++;
                 }
             } else {
                 $srcwarehouseid = GETPOST('id_entrepot_source', 'int');
                 $batch = GETPOST('batch_number');
 /**
  *	Add a movement of stock (in one direction only)
  *
  *	@param		User	$user			User object
  *	@param		int		$fk_product		Id of product
  *	@param		int		$entrepot_id	Id of warehouse
  *	@param		int		$qty			Qty of movement (can be <0 or >0)
  *	@param		int		$type			Direction of movement:
  *										0=input (stock increase after stock transfert), 1=output (stock decrease after stock transfer),
  *										2=output (stock decrease), 3=input (stock increase)
  *	@param		int		$price			Unit price HT of product, used to calculate average weighted price (PMP in french). If 0, average weighted price is not changed.
  *	@param		string	$label			Label of stock movement
  *	@param		string	$datem			Force date of movement
  *	@param		date	$eatby			eat-by date
  *	@param		date	$sellby			sell-by date
  *	@param		string	$batch			batch number
  *	@param		boolean	$skip_sellby	If set to true, stock mouvement is done without impacting batch record
  *	@return		int						<0 if KO, 0 if fk_product is null, >0 if OK
  */
 function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = 0, $label = '', $datem = '', $eatby = '', $sellby = '', $batch = '', $skip_sellby = false)
 {
     global $conf, $langs;
     require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
     $error = 0;
     dol_syslog(get_class($this) . "::_create start userid={$user->id}, fk_product={$fk_product}, warehouse={$entrepot_id}, qty={$qty}, type={$type}, price={$price} label={$label}");
     // Clean parameters
     if (empty($price)) {
         $price = 0;
     }
     if (empty($fk_product)) {
         return 0;
     }
     $now = !empty($datem) ? $datem : dol_now();
     $this->db->begin();
     $product = new Product($this->db);
     $result = $product->fetch_opt($fk_product);
     if ($result < 0) {
         dol_print_error('', "Failed to fetch product");
         return -1;
     }
     $product->load_stock();
     // Define if we must make the stock change (If product type is a service or if stock is used also for services)
     $movestock = 0;
     if ($product->type != 1 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
         $movestock = 1;
     }
     if ($movestock && $entrepot_id > 0) {
         if (!empty($this->origin)) {
             $origintype = $this->origin->element;
             $fk_origin = $this->origin->id;
         } else {
             $origintype = '';
             $fk_origin = 0;
         }
         $sql = "INSERT INTO " . MAIN_DB_PREFIX . "stock_mouvement";
         $sql .= " (datem, fk_product, fk_entrepot, value, type_mouvement, fk_user_author, label, price, fk_origin, origintype)";
         $sql .= " VALUES ('" . $this->db->idate($now) . "', " . $fk_product . ", " . $entrepot_id . ", " . $qty . ", " . $type . ",";
         $sql .= " " . $user->id . ",";
         $sql .= " '" . $this->db->escape($label) . "',";
         $sql .= " '" . price2num($price) . "',";
         $sql .= " '" . $fk_origin . "',";
         $sql .= " '" . $origintype . "'";
         $sql .= ")";
         dol_syslog(get_class($this) . "::_create sql=" . $sql, LOG_DEBUG);
         $resql = $this->db->query($sql);
         if ($resql) {
             $mvid = $this->db->last_insert_id(MAIN_DB_PREFIX . "stock_mouvement");
         } else {
             $this->error = $this->db->lasterror();
             dol_syslog(get_class($this) . "::_create " . $this->error, LOG_ERR);
             $error = -1;
         }
         // Define current values for qty and pmp
         $oldqty = $product->stock_reel;
         $oldqtywarehouse = 0;
         $oldpmp = $product->pmp;
         $oldpmpwarehouse = 0;
         // Test if there is already a record for couple (warehouse / product)
         $num = 0;
         if (!$error) {
             $sql = "SELECT rowid, reel, pmp FROM " . MAIN_DB_PREFIX . "product_stock";
             $sql .= " WHERE fk_entrepot = " . $entrepot_id . " AND fk_product = " . $fk_product;
             dol_syslog(get_class($this) . "::_create sql=" . $sql);
             $resql = $this->db->query($sql);
             if ($resql) {
                 $obj = $this->db->fetch_object($resql);
                 if ($obj) {
                     $num = 1;
                     $oldqtywarehouse = $obj->reel;
                     $oldpmpwarehouse = $obj->pmp;
                     $fk_product_stock = $obj->rowid;
                 }
                 $this->db->free($resql);
             } else {
                 $this->error = $this->db->lasterror();
                 dol_syslog(get_class($this) . "::_create echec update " . $this->error, LOG_ERR);
                 $error = -2;
             }
         }
         // Calculate new PMP.
         if (!$error) {
             $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: Price should always be >0 or 0. PMP should be always >0 (calculated on input)
             if (($type == 0 || $type == 3) && $price > 0) {
                 $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;
                 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;
             } else {
                 $newpmp = $oldpmp;
                 $newpmpwarehouse = $oldpmpwarehouse;
             }
         }
         // Update denormalized value of stock in product_stock and product
         if (!$error) {
             if ($num > 0) {
                 $sql = "UPDATE " . MAIN_DB_PREFIX . "product_stock SET pmp = " . $newpmpwarehouse . ", reel = reel + " . $qty;
                 $sql .= " WHERE fk_entrepot = " . $entrepot_id . " AND fk_product = " . $fk_product;
             } else {
                 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "product_stock";
                 $sql .= " (pmp, reel, fk_entrepot, fk_product) VALUES ";
                 $sql .= " (" . $newpmpwarehouse . ", " . $qty . ", " . $entrepot_id . ", " . $fk_product . ")";
             }
             dol_syslog(get_class($this) . "::_create sql=" . $sql);
             $resql = $this->db->query($sql);
             if (!$resql) {
                 $this->error = $this->db->lasterror();
                 dol_syslog(get_class($this) . "::_create " . $this->error, LOG_ERR);
                 $error = -3;
             } 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) {
             $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++;
             }
         }
         if (!$error) {
             $sql = "UPDATE " . MAIN_DB_PREFIX . "product SET pmp = " . $newpmp . ", stock = " . $this->db->ifsql("stock IS NULL", 0, "stock") . " + " . $qty;
             $sql .= " WHERE rowid = " . $fk_product;
             // May be this request is better:
             // UPDATE llx_product p SET p.stock= (SELECT SUM(ps.reel) FROM llx_product_stock ps WHERE ps.fk_product = p.rowid);
             dol_syslog(get_class($this) . "::_create sql=" . $sql);
             $resql = $this->db->query($sql);
             if (!$resql) {
                 $this->error = $this->db->lasterror();
                 dol_syslog(get_class($this) . "::_create " . $this->error, LOG_ERR);
                 $error = -4;
             }
         }
     }
     // Add movement for sub products (recursive call)
     if (!$error && !empty($conf->global->PRODUIT_SOUSPRODUITS)) {
         $error = $this->_createSubProduct($user, $fk_product, $entrepot_id, $qty, $type, 0, $label);
         // we use 0 as price, because pmp is not changed for subproduct
     }
     if ($movestock && !$error) {
         // Appel des triggers
         include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
         $interface = new Interfaces($this->db);
         $this->product_id = $fk_product;
         $this->entrepot_id = $entrepot_id;
         $this->qty = $qty;
         $result = $interface->run_triggers('STOCK_MOVEMENT', $this, $user, $langs, $conf);
         if ($result < 0) {
             $error++;
             $this->errors = $interface->errors;
         }
         // Fin appel triggers
     }
     if (!$error) {
         $this->db->commit();
         return $mvid;
     } else {
         $this->db->rollback();
         dol_syslog(get_class($this) . "::_create error code=" . $error, LOG_ERR);
         return -6;
     }
 }
 $dlc = -1;
 // They are loaded later from serial
 $dluo = -1;
 // They are loaded later from serial
 if (!$error && $id_sw != $id_tw && is_numeric($qty) && $id_product) {
     $result = $product->fetch($id_product);
     $product->load_stock();
     // Load array product->stock_warehouse
     // Define value of products moved
     $pricesrc = 0;
     if (!empty($product->pmp)) {
         $pricesrc = $product->pmp;
     }
     $pricedest = $pricesrc;
     //print 'price src='.$pricesrc.', price dest='.$pricedest;exit;
     if (empty($conf->productbatch->enabled) || !$product->hasbatch()) {
         // Remove stock
         $result1 = $product->correct_stock($user, $id_sw, $qty, 1, GETPOST("label"), $pricesrc, GETPOST("codemove"));
         if ($result1 < 0) {
             $error++;
             setEventMessage($product->errors, 'errors');
         }
         // Add stock
         $result2 = $product->correct_stock($user, $id_tw, $qty, 0, GETPOST("label"), $pricedest, GETPOST("codemove"));
         if ($result2 < 0) {
             $error++;
             setEventMessage($product->errors, 'errors');
         }
     } else {
         $arraybatchinfo = $product->loadBatchInfo($batch);
         if (count($arraybatchinfo) > 0) {
 print '<input name="qtydelivered' . $indiceAsked . '" id="qtydelivered' . $indiceAsked . '" type="hidden" value="' . $quantityDelivered . '">';
 print '</td>';
 $quantityAsked = $line->qty;
 $quantityToBeDelivered = $quantityAsked - $quantityDelivered;
 $defaultqty = 0;
 if (GETPOST('entrepot_id', 'int') > 0) {
     //var_dump($product);
     $stock = $product->stock_warehouse[GETPOST('entrepot_id', 'int')]->real;
     $stock += 0;
     // Convertit en numerique
     $defaultqty = min($quantityToBeDelivered, $stock);
     if ($line->product_type == 1 && empty($conf->global->STOCK_SUPPORTS_SERVICES) || $defaultqty < 0) {
         $defaultqty = 0;
     }
 }
 if (empty($conf->productbatch->enabled) || !($product->hasbatch() and is_object($product->stock_warehouse[GETPOST('entrepot_id', 'int')]))) {
     // Quantity to send
     print '<td align="center">';
     if ($line->product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
         print '<input name="idl' . $indiceAsked . '" type="hidden" value="' . $line->id . '">';
         print '<input name="qtyl' . $indiceAsked . '" id="qtyl' . $indiceAsked . '" type="text" size="4" value="' . $defaultqty . '">';
     } else {
         print $langs->trans("NA");
     }
     print '</td>';
     // Stock
     if (!empty($conf->stock->enabled)) {
         print '<td align="left">';
         if ($line->product_type == 0 || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
             // Show warehouse combo list
             $ent = "entl" . $indiceAsked;
Example #8
0
     $action = 'transfert';
 }
 if (!GETPOST("nbpiece", 'int')) {
     setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
     $error++;
     $action = 'transfert';
 }
 if ($id == GETPOST("id_entrepot_destination", 'int')) {
     setEventMessages($langs->trans("ErrorSrcAndTargetWarehouseMustDiffers"), null, 'errors');
     $error++;
     $action = 'transfert';
 }
 if (!empty($conf->productbatch->enabled)) {
     $product = new Product($db);
     $result = $product->fetch($product_id);
     if ($product->hasbatch() && !GETPOST("batch_number")) {
         setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("batch_number")), null, 'errors');
         $error++;
         $action = 'transfert';
     }
 }
 if (!$error) {
     if ($id) {
         $object = new Entrepot($db);
         $result = $object->fetch($id);
         $db->begin();
         $product->load_stock();
         // Load array product->stock_warehouse
         // Define value of products moved
         $pricesrc = 0;
         //if (isset($product->stock_warehouse[GETPOST("id_entrepot_source")]->pmp)) $pricesrc=$product->stock_warehouse[GETPOST("id_entrepot_source")]->pmp;
			$dluo=-1;		// They are loaded later from serial

			if (! $error && $id_sw <> $id_tw && is_numeric($qty) && $id_product)
			{
				$result=$product->fetch($id_product);

				$product->load_stock();	// Load array product->stock_warehouse

				// Define value of products moved
				$pricesrc=0;
				if (! empty($product->pmp)) $pricesrc=$product->pmp;
				$pricedest=$pricesrc;

				//print 'price src='.$pricesrc.', price dest='.$pricedest;exit;

				if (empty($conf->productbatch->enabled) || ! $product->hasbatch())		// If product does not need lot/serial
				{
					// Remove stock
					$result1=$product->correct_stock(
		    			$user,
		    			$id_sw,
		    			$qty,
		    			1,
		    			GETPOST("label"),
		    			$pricesrc,
						GETPOST("codemove")
					);
					if ($result1 < 0)
					{
						$error++;
						setEventMessages($product->errors, $product->errorss, 'errors');