print $formproduct->selectWarehouses($id_sw, 'id_sw', '', 1);
print '</td>';
// Out warehouse
print '<td>';
print $formproduct->selectWarehouses($id_tw, 'id_tw', '', 1);
print '</td>';
// Qty
print '<td align="center"><input type="text" size="4" class="flat" name="qty" value="' . $qty . '"></td>';
// Button to add line
if (!$listofdata) {
    print '<td align="right"><input type="submit" class="button" name="addline" value="' . dol_escape_htmltag($titletoadd) . '"></td>';
}
print '</tr>';
foreach ($listofdata as $key => $val) {
    $var = !$var;
    $productstatic->fetch_opt($val['id_product']);
    $warehousestatics->fetch($val['id_sw']);
    $warehousestatict->fetch($val['id_tw']);
    print '<tr ' . $bc[$var] . '>';
    print '<td>' . $productstatic->getNomUrl(1) . '</td>';
    print '<td>';
    $oldref = $productstatic->ref;
    $productstatic->ref = $productstatic->label;
    print $productstatic->getNomUrl(1);
    $productstatic->ref = $oldref;
    print '</td>';
    print '<td>';
    print $warehousestatics->getNomUrl(1);
    print '</td>';
    print '<td>';
    print $warehousestatict->getNomUrl(1);
 /**
  *	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;
     }
 }