Example #1
0
 /**
  * Get properties of a product object
  *
  * Return an array with product informations
  *
  * @param 	int 	$id     ID of product
  * @param   string  $ref    Product ref
  * @param   string  $ref_ext    Product ref ext
  * @return 	array|mixed data without useless information
  * 
  * @url	GET product/{id}
  * @throws 	RestException
  */
 function get($id = '', $ref = '', $ref_ext = '')
 {
     if (!DolibarrApiAccess::$user->rights->produit->lire) {
         throw new RestException(401);
     }
     $result = $this->product->fetch($id, $ref, $ref_ext);
     if (!$result) {
         throw new RestException(404, 'Product not found');
     }
     if (!DolibarrApi::_checkAccessToResource('product', $this->product->id)) {
         throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
     }
     $this->product->load_stock();
     return $this->_cleanObjectDatas($this->product);
 }
 function isLineShippable(&$line, &$TSomme)
 {
     global $conf, $user;
     $db =& $this->db;
     $TSomme[$line->fk_product] += $line->qty_toship;
     if (!isset($line->stock) && $line->fk_product > 0) {
         if (empty($this->TProduct[$line->fk_product])) {
             $produit = new Product($db);
             $produit->fetch($line->fk_product);
             $produit->load_stock(false);
             $this->TProduct[$line->fk_product] = $produit;
         } else {
             $produit =& $this->TProduct[$line->fk_product];
         }
         $line->stock = $produit->stock_reel;
         // Filtre par entrepot de l'utilisateur
         if (!empty($conf->global->SHIPPABLEORDER_ENTREPOT_BY_USER) && !empty($user->array_options['options_entrepot_preferentiel'])) {
             $line->stock = $produit->stock_warehouse[$user->array_options['options_entrepot_preferentiel']]->real;
         } elseif (!empty($conf->global->SHIPPABLEORDER_SPECIFIC_WAREHOUSE)) {
             $line->stock = 0;
             //Récupération des entrepôts valide
             $TIdWarehouse = explode(',', $conf->global->SHIPPABLEORDER_SPECIFIC_WAREHOUSE);
             foreach ($produit->stock_warehouse as $identrepot => $objecttemp) {
                 if (in_array($identrepot, $TIdWarehouse)) {
                     $line->stock += $objecttemp->real;
                 }
             }
         }
     }
     if ($conf->global->SHIPPABLE_ORDER_ALLOW_SHIPPING_IF_NOT_ENOUGH_STOCK) {
         $isShippable = 1;
         $qtyShippable = $line->qty;
         $line->stock = $line->qty;
     } else {
         if ($line->stock <= 0 || $line->qty_toship <= 0) {
             $isShippable = 0;
             $qtyShippable = 0;
         } else {
             if ($TSomme[$line->fk_product] <= $line->stock) {
                 $isShippable = 1;
                 $qtyShippable = $line->qty_toship;
             } else {
                 $isShippable = 2;
                 $qtyShippable = $line->qty_toship - $TSomme[$line->fk_product] + $line->stock;
             }
         }
     }
     $this->TlinesShippable[$line->id] = array('stock' => $line->stock, 'shippable' => $isShippable, 'to_ship' => $line->qty_toship, 'qty_shippable' => $qtyShippable);
     return $isShippable;
 }
Example #3
0
        }
    } else {
        setEventMessages($pdluo->error, null, 'errors');
    }
    header("Location: product.php?id=" . $id);
    exit;
}
/*
 * View
 */
$form = new Form($db);
$formproduct = new FormProduct($db);
if ($id > 0 || $ref) {
    $object = new Product($db);
    $result = $object->fetch($id, $ref);
    $object->load_stock();
    $help_url = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
    llxHeader("", $langs->trans("CardProduct" . $object->type), $help_url);
    if ($result > 0) {
        $head = product_prepare_head($object);
        $titre = $langs->trans("CardProduct" . $object->type);
        $picto = $object->type == Product::TYPE_SERVICE ? 'service' : 'product';
        dol_fiche_head($head, 'stock', $titre, 0, $picto);
        dol_htmloutput_events();
        dol_banner_tab($object, 'ref', '', $user->societe_id ? 0 : 1, 'ref');
        print '<div class="fichecenter">';
        print '<div class="underbanner clearboth"></div>';
        print '<table class="border tableforfield" width="100%">';
        if ($conf->productbatch->enabled) {
            print '<tr><td class="titlefield">' . $langs->trans("ManageLotSerial") . '</td><td>';
            print $object->getLibStatut(0, 2);
 print '<table class="nobordernopadding"><tr class="nocellnopadd">';
 print '<td class="nobordernopadding nowrap">';
 print $generic_commande->getNomUrl(1, $viewstatut != 2 ? 0 : $objp->fk_statut);
 print '</td>';
 // Shippable Icon
 if ($objp->fk_statut > 0 && $objp->fk_statut < 3 && !empty($conf->global->SHIPPABLE_ORDER_ICON_IN_LIST)) {
     $notshippable = 0;
     $text_info = '';
     $nbprod = 0;
     for ($lig = 0; $lig < count($generic_commande->lines); $lig++) {
         if ($generic_commande->lines[$lig]->product_type == 0) {
             $nbprod++;
             // order contains real products
             $generic_product->id = $generic_commande->lines[$lig]->fk_product;
             if (empty($productstat_cache[$generic_commande->lines[$lig]->fk_product])) {
                 $generic_product->load_stock(true);
                 $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stock_reel'] = $generic_product->stock_reel;
             } else {
                 $generic_product->stock_reel = $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stock_reel'];
             }
             // stock order and stock order_supplier
             $stock_order = 0;
             $stock_order_supplier = 0;
             if (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) {
                 if (!empty($conf->commande->enabled)) {
                     if (empty($productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_customer'])) {
                         $generic_product->load_stats_commande(0, '1,2');
                         $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_customer'] = $generic_product->stats_commande['qty'];
                     } else {
                         $generic_product->stats_commande['qty'] = $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_customer'];
                     }
Example #5
0
			dol_fiche_end();


			// List of subproducts
			$prods_arbo = $product->get_arbo_each_prod();
			if (count($prods_arbo) > 0)
			{
				print '<tr><td colspan="2">';
				print '<b>'.$langs->trans("ProductAssociationList").'</b><br>';
				print '<table class="nobordernopadding">';
				foreach($prods_arbo as $value)
				{
					$productstatic->id=$value['id'];
					$productstatic->type=$value['type'];
					$productstatic->ref=$value['fullpath'];
					if ($conf->stock->enabled) $productstatic->load_stock();
					//var_dump($value);
					//print '<pre>'.$productstatic->ref.'</pre>';
					//print $productstatic->getNomUrl(1).'<br>';
					//print $value[0];	// This contains a tr line.
					print '<tr>';
					print '<td>'.$productstatic->getNomUrl(1,'composition').' ('.$value['nb'].') &nbsp &nbsp</td>';
					if ($conf->stock->enabled) print '<td>'.$langs->trans("Stock").' : <b>'.$productstatic->stock_reel.'</b></td>';
					print '</tr>';
				}
				print '</table>';
				print '</td></tr>';
			}

			// Number of parent products
			print '<tr><td>'.$langs->trans("ParentProductsNumber").'</td><td>'.count($prodsfather).'</td>';
Example #6
0
print_liste_field_titre($langs->trans('Supplier'), $_SERVER["PHP_SELF"], '', $param, '', 'align="right"', $sortfield, $sortorder);
print "</tr>\n";
// Lignes des champs de filtre
print '<tr class="liste_titre">' . '<td class="liste_titre">&nbsp;</td>' . '<td class="liste_titre"><input class="flat" type="text" name="sref" size="8" value="' . dol_escape_htmltag($sref) . '"></td>' . '<td class="liste_titre"><input class="flat" type="text" name="snom" size="8" value="' . dol_escape_htmltag($snom) . '"></td>';
if (!empty($conf->service->enabled) && $type == 1) {
    print '<td class="liste_titre">&nbsp;</td>';
}
print '<td class="liste_titre">&nbsp;</td>' . '<td class="liste_titre" align="right">&nbsp;</td>' . '<td class="liste_titre" align="right">' . $langs->trans('AlertOnly') . '&nbsp;<input type="checkbox" id="salert" name="salert" ' . (!empty($alertchecked) ? $alertchecked : '') . '></td>' . '<td class="liste_titre" align="right">&nbsp;</td>' . '<td class="liste_titre">&nbsp;</td>' . '<td class="liste_titre" align="right">' . '<input class="liste_titre" name="button_search" type="image" src="' . img_picto($langs->trans("Search"), 'search.png', '', '', 1) . '" value="' . dol_escape_htmltag($langs->trans("Search")) . '" title="' . dol_escape_htmltag($langs->trans("Search")) . '">' . '<input type="image" class="liste_titre" src="' . img_picto($langs->trans("Search"), 'searchclear.png', '', '', 1) . '" name="button_removefilter" value="' . dol_escape_htmltag($langs->trans("RemoveFilter")) . '" title="' . dol_escape_htmltag($langs->trans("RemoveFilter")) . '">' . '</td>';
print '</tr>';
$prod = new Product($db);
$var = True;
while ($i < ($limit ? min($num, $limit) : $num)) {
    $objp = $db->fetch_object($resql);
    if (!empty($conf->global->STOCK_SUPPORTS_SERVICES) || $objp->fk_product_type == 0) {
        $prod->fetch($objp->rowid);
        $prod->load_stock();
        // Multilangs
        if (!empty($conf->global->MAIN_MULTILANGS)) {
            $sql = 'SELECT label';
            $sql .= ' FROM ' . MAIN_DB_PREFIX . 'product_lang';
            $sql .= ' WHERE fk_product = ' . $objp->rowid;
            $sql .= ' AND lang = "' . $langs->getDefaultLang() . '"';
            $sql .= ' LIMIT 1';
            $resqlm = $db->query($sql);
            if ($resqlm) {
                $objtp = $db->fetch_object($resqlm);
                if (!empty($objtp->label)) {
                    $objp->label = $objtp->label;
                }
            }
        }
 /**
  * Function called when a Dolibarrr business event is done.
  * All functions "run_trigger" are triggered if file
  * is inside directory core/triggers
  *
  * 	@param		string		$action		Event action code
  * 	@param		Object		$object		Object
  * 	@param		User		$user		Object user
  * 	@param		Translate	$langs		Object langs
  * 	@param		conf		$conf		Object conf
  * 	@return		int						<0 if KO, 0 if no triggered ran, >0 if OK
  */
 public function run_trigger($action, $object, $user, $langs, $conf)
 {
     if ($action === 'ORDER_VALIDATE') {
         global $conf, $db;
         if ($conf->global->CREATE_OF_ON_ORDER_VALIDATE) {
             define('INC_FROM_DOLIBARR', true);
             dol_include_once('/product/class/product.class.php');
             dol_include_once('/of/config.php');
             dol_include_once('/of/class/ordre_fabrication_asset.class.php');
             $PDOdb = new TPDOdb();
             foreach ($object->lines as $line) {
                 // Uniquement si c'est un produit
                 if (!empty($line->fk_product) && $line->fk_product_type == 0) {
                     // On charge le produit pour vérifier son stock
                     $prod = new Product($db);
                     $prod->fetch($line->fk_product);
                     $prod->load_stock();
                     if ($prod->stock_reel < $line->qty) {
                         $assetOF = new TAssetOF();
                         $assetOF->fk_commande = $_REQUEST['id'];
                         $assetOF->fk_soc = $object->socid;
                         $assetOF->addLine($PDOdb, $line->fk_product, 'TO_MAKE', $line->qty);
                         $assetOF->save($PDOdb);
                     }
                 }
             }
         }
     } elseif ($action === 'ORDER_CANCEL') {
         if ($conf->global->DELETE_OF_ON_ORDER_CANCEL) {
             define('INC_FROM_DOLIBARR', true);
             dol_include_once('/of/config.php');
             dol_include_once('/of/class/ordre_fabrication_asset.class.php');
             $PDOdb = new TPDOdb();
             // On récupère les identifiants des of créés à partir de cette commande
             $TID_OF_command = TAssetOF::getTID_OF_command($_REQUEST['id']);
             foreach ($TID_OF_command as $id_of) {
                 $asset = new TAssetOF();
                 $asset->load($PDOdb, $id_of);
                 if ($asset->status == "DRAFT" || $asset->status == "VALID") {
                     $asset->delete($PDOdb);
                 }
             }
         }
     } elseif ($action === 'TASK_TIMESPENT_CREATE') {
         if ($conf->workstation->enabled) {
             define('INC_FROM_DOLIBARR', true);
             dol_include_once('/of/config.php');
             dol_include_once('/of/class/ordre_fabrication_asset.class.php');
             $PDOdb = new TPDOdb();
             $PDOdb->Execute("SELECT rowid \n\t\t\t\t\t\tFROM " . MAIN_DB_PREFIX . "asset_workstation_of \n\t\t\t\t\t\tWHERE fk_project_task=" . $object->id);
             if ($obj = $PDOdb->Get_line()) {
                 $wsof = new TAssetWorkstationOF();
                 $wsof->load($PDOdb, $obj->rowid);
                 $wsof->nb_hour_real = ($object->duration_effective + $object->timespent_duration) / 3600;
                 // Parce que Dolibarr mets le THM à jour après la création de la tâche :/
                 $sql = "UPDATE " . MAIN_DB_PREFIX . "projet_task_time";
                 $sql .= " SET thm = (SELECT thm FROM " . MAIN_DB_PREFIX . "user WHERE rowid = " . $object->timespent_fk_user . ")";
                 // set average hour rate of user
                 $sql .= " WHERE rowid = " . $object->timespent_id;
                 $object->db->query($sql);
                 $wsof->db =& $object->db;
                 $wsof->save($PDOdb);
             }
         }
     } elseif ($action === 'ORDERSUPPLIER_ADD_LIVRAISON') {
         global $db;
         if ($conf->of->enabled) {
             define('INC_FROM_DOLIBARR', true);
             dol_include_once('/of/config.php');
             dol_include_once('/of/class/ordre_fabrication_asset.class.php');
             $resql = $db->query('SELECT fk_statut FROM llx_commande_fournisseur WHERE rowid = ' . $_REQUEST['id']);
             $res = $db->fetch_object($resql);
             if ($res->fk_statut == 5) {
                 // La livraison est totale
                 //On cherche l'OF lié
                 $resql = $db->query("SELECT fk_source \n\t\t\t\t\t\t\t\t\t\t\tFROM " . MAIN_DB_PREFIX . "element_element \n\t\t\t\t\t\t\t\t\t\t\tWHERE fk_target = " . $_REQUEST['id'] . " \n\t\t\t\t\t\t\t\t\t\t\t\tAND sourcetype = 'ordre_fabrication' \n\t\t\t\t\t\t\t\t\t\t\t\tAND targettype = 'order_supplier'");
                 $res = $db->fetch_object($resql);
                 $id_of = $res->fk_source;
                 if ($id_of > 0) {
                     $of = new TAssetOF();
                     $of->load($PDOdb, $id_of);
                     if ($of->status != 'CLOSE') {
                         $of->closeOF($PDOdb);
                         setEventMessage($langs->trans('OFAttachedClosedAutomatically', '<a href="' . dol_buildpath('/of/fiche_of.php?id=' . $id_of, 2) . '">' . $of->numero . '</a>'));
                     }
                 }
             }
         }
     }
     return 0;
 }
Example #8
0
             if ($product_fourn->product_fourn_price_id > 0) {
                 if (!empty($conf->fournisseur->enabled) && $user->rights->fournisseur->lire) {
                     $htmltext = $product_fourn->display_price_product_fournisseur(1, 1, 0, 1);
                     print $form->textwithpicto(price($product_fourn->fourn_unitprice) . ' ' . $langs->trans("HT"), $htmltext);
                 } else {
                     print price($product_fourn->fourn_unitprice) . ' ' . $langs->trans("HT");
                 }
             }
         }
     }
     print '</td>';
 }
 if (!empty($conf->stock->enabled) && $user->rights->stock->lire && $type != 1) {
     if ($objp->fk_product_type != 1) {
         $product_static->id = $objp->rowid;
         $product_static->load_stock();
     }
 }
 // Desired stock
 if (!empty($arrayfields['p.desiredstock']['checked'])) {
     print '<td align="right">';
     if ($objp->fk_product_type != 1) {
         print $objp->desiredstock;
     }
     print '</td>';
 }
 // Desired stock
 if (!empty($arrayfields['p.tobatch']['checked'])) {
     print '<td align="center">';
     print yn($objp->tobatch);
     print '</td>';
Example #9
0
 /**
  * Add a expedition line.
  * If STOCK_WAREHOUSE_NOT_REQUIRED_FOR_SHIPMENTS is set, you can add a shipment line, with no stock source defined
  * If STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT is not set, you can add a shipment line, even if not enough into stock
  *
  * @param 	int		$entrepot_id		Id of warehouse
  * @param 	int		$id					Id of source line (order line)
  * @param 	int		$qty				Quantity
  * @param	array		$array_options		extrafields array
  * @return	int							<0 if KO, >0 if OK
  */
 function addline($entrepot_id, $id, $qty, $array_options = 0)
 {
     global $conf, $langs;
     $num = count($this->lines);
     $line = new ExpeditionLigne($this->db);
     $line->entrepot_id = $entrepot_id;
     $line->origin_line_id = $id;
     $line->qty = $qty;
     $orderline = new OrderLine($this->db);
     $orderline->fetch($id);
     if (!empty($conf->stock->enabled) && !empty($orderline->fk_product)) {
         $fk_product = $orderline->fk_product;
         if (!($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_SHIPMENTS)) {
             $langs->load("errors");
             $this->error = $langs->trans("ErrorWarehouseRequiredIntoShipmentLine");
             return -1;
         }
         if ($conf->global->STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT) {
             // Check must be done for stock of product into warehouse if $entrepot_id defined
             $product = new Product($this->db);
             $result = $product->fetch($fk_product);
             $product_type = $product->type;
             if ($entrepot_id > 0) {
                 $product->load_stock();
                 $product_stock = $product->stock_warehouse[$entrepot_id]->real;
             } else {
                 $product_stock = $product->stock_reel;
             }
             if ($product_type == 0 && $product_stock < $qty) {
                 $this->error = $langs->trans('ErrorStockIsNotEnough');
                 $this->db->rollback();
                 return -3;
             }
         }
     }
     // extrafields
     if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options) > 0) {
         // For avoid conflicts if trigger used
         $line->array_options = $array_options;
     }
     $this->lines[$num] = $line;
 }
 /**
  *	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;
     }
 }
 /**
  *      Create object into database
  *      @param      User	$user        	User that create
  *      @param      Array	$toPrint	    Array with products to print
  *      @return     int         			<0 if KO, Id of created object if OK
  */
 function multicreate($user, $toPrint)
 {
     global $conf, $langs;
     $error = 0;
     require_once DOL_DOCUMENT_ROOT . "/product/class/product.class.php";
     $product = new Product($this->db);
     foreach ($toPrint as $prodid) {
         $result = $product->fetch($prodid);
         if ($result) {
             if ($conf->stock->enabled) {
                 $product->load_stock();
                 $qty = $product->stock_reel;
             }
         }
         $res = $this->fetch($this->id, $product->id);
         if ($res == 1) {
             $qty = $this->qty + $qty;
             $this->qty = $qty;
             $res = $this->update($user, $notrigger);
             if ($res != 1) {
                 $error++;
                 $this->errors[] = "Error " . $this->db->lasterror();
             }
         } else {
             // Insert request
             $sql = "INSERT INTO " . MAIN_DB_PREFIX . "labelprint(";
             $sql .= "entity,";
             $sql .= "fk_product,";
             $sql .= "qty,";
             $sql .= "fk_user,";
             $sql .= "datec,";
             $sql .= "price_level";
             $sql .= ") VALUES (";
             $sql .= " " . $conf->entity . ",";
             $sql .= " " . $product->id . ",";
             $sql .= " " . $qty . ",";
             $sql .= " " . $user->id . ",";
             $sql .= " " . (!isset($this->datec) || dol_strlen($this->datec) == 0 ? 'NULL' : $this->db->idate($this->datec)) . ",";
             $sql .= " " . (!isset($this->price_level) ? 1 : $this->price_level) . "";
             $sql .= ")";
             //$this->db->begin();
             dol_syslog(get_class($this) . "::create sql=" . $sql, LOG_DEBUG);
             $resql = $this->db->query($sql);
             if (!$resql) {
                 $error++;
                 $this->errors[] = "Error " . $this->db->lasterror();
             }
         }
     }
     if (!$error) {
         $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "labelprint");
     }
     // Commit or rollback
     if ($error) {
         foreach ($this->errors as $errmsg) {
             dol_syslog(get_class($this) . "::multicreate " . $errmsg, LOG_ERR);
             $this->error .= $this->error ? ', ' . $errmsg : $errmsg;
         }
         //$this->db->rollback();
         return -1 * $error;
     } else {
         //$this->db->commit();
         return $this->id;
     }
 }
 function import2Dolibarr($object, $typeimport)
 {
     global $conf;
     global $langs;
     $this->process_msg = '';
     $error = 0;
     $fp = @fopen($this->filename, "r");
     if ($fp) {
         switch ($object) {
             case 'ImportStock':
                 $doliprod = new Product($this->db);
                 $i = 0;
                 while ($ligne = fgetcsv($fp, 1000, ";")) {
                     $doliprod->id = '';
                     $i++;
                     if ($this->firstline && $i == 1) {
                         continue;
                     }
                     if ($conf->global->IMPORT_BARCODE) {
                         $ligne[0] = $this->get_product_by_barcode($ligne[0]);
                     }
                     if ($doliprod->fetch('', $ligne[0]) <= 0) {
                         $this->process_msg .= $langs->trans("ErrProdNoExist", $ligne[0], $doliprod->error) . "\n";
                     } else {
                         $pid = $doliprod->id;
                         $doliprod->ref = $ligne[0];
                         $entrepot = $ligne[1];
                         $newstock = $ligne[2];
                         $price = $ligne[3];
                         if ($conf->global->IMPORT_TOTAL_STOCK) {
                             $doliprod->load_stock();
                             dol_syslog("stock produit " . $doliprod->stock_warehouse[$entrepot]->real . " entrepot " . $entrepot . " " . $doliprod->stock_reel, LOG_DEBUG);
                             // correction de stock
                             $delta = 0;
                             if ($newstock > $doliprod->stock_warehouse[$entrepot]->real) {
                                 $delta = $newstock - $doliprod->stock_warehouse[$entrepot]->real;
                                 $sens = 0;
                             } elseif ($newstock < $doliprod->stock_warehouse[$entrepot]->real) {
                                 $delta = $doliprod->stock_warehouse[$entrepot]->real - $newstock;
                                 $sens = 1;
                             }
                             if ($delta) {
                                 $res = $doliprod->correct_stock($this->user, $entrepot, $delta, $sens, $langs->trans("StockCorrection"), $price);
                                 if ($res < 0) {
                                     $this->process_msg .= $langs->trans("ErrMovStock", $ligne[0], $doliprod->error) . "\n";
                                     $error++;
                                 }
                             }
                             dol_syslog("maj stock delta = " . $delta . " sens " . $sens, LOG_DEBUG);
                         } else {
                             $res = $doliprod->correct_stock($this->user, $entrepot, abs($newstock), $newstock > 0 ? 0 : 1, $langs->trans("StockCorrection"), $price);
                             if ($res < 0) {
                                 $this->process_msg .= $langs->trans("ErrMovStock", $ligne[0], $doliprod->error) . "\n";
                                 $error++;
                             }
                         }
                     }
                 }
                 break;
             case 'ImportProduct':
                 //$doliprod = new Product($this->db);
                 $i = 0;
                 while ($ligne = fgetcsv($fp, 1000, ";")) {
                     $i++;
                     $doliprod = new Product($this->db);
                     $doliprod->id = '';
                     if ($this->firstline && $i == 1) {
                         continue;
                     }
                     if ($doliprod->fetch('', $ligne[0]) < 0) {
                         $this->process_msg .= $langs->trans("ErrProdNoExist", $ligne[0], $doliprod->error) . "\n";
                     } else {
                         $pid = $doliprod->id;
                         $doliprod->ref = $ligne[0];
                         if (!empty($ligne[1])) {
                             $doliprod->libelle = $ligne[1];
                         }
                         if (!empty($ligne[2])) {
                             $doliprod->status = $ligne[2];
                         }
                         $doliprod->status_buy = 1;
                         if (!empty($ligne[3])) {
                             $doliprod->description = $ligne[3];
                         }
                         if (!empty($ligne[4])) {
                             $doliprod->price = $ligne[4];
                         }
                         if (!empty($ligne[5])) {
                             $doliprod->tva_tx = $ligne[5];
                         }
                         if (!empty($ligne[6])) {
                             $doliprod->weight = $ligne[6];
                         }
                         if (!empty($ligne[7])) {
                             $doliprod->volume = $ligne[7];
                         }
                         if (!empty($ligne[9])) {
                             $doliprod->barcode = $ligne[9];
                         }
                         if (!empty($ligne[9])) {
                             $doliprod->barcode_type = dol_getIdFromCode($this->db, $ligne[10], 'c_barcode_type', 'libelle', 'rowid');
                         }
                         if (!empty($ligne[10])) {
                             $doliprod->type = $ligne[11];
                         }
                         $doliprod->price_base_type = 'HT';
                         $this->db->begin;
                         switch ($typeimport) {
                             case 'C':
                                 if ($pid > 0) {
                                     if ($doliprod->update($pid, $this->user) < 0) {
                                         $this->process_msg .= $langs->trans("ErrProductUpdate", $ligne[0], $doliprod->error) . "\n";
                                         $error++;
                                     }
                                     if ($doliprod->updatePrice($doliprod->price, $doliprod->price_base_type, $this->user) < 0) {
                                         $this->process_msg .= $langs->trans("ErrProductUpdate", $ligne[0], $doliprod->error) . "\n";
                                         $error++;
                                     }
                                 } else {
                                     if ($doliprod->create($this->user) < 0) {
                                         $this->process_msg .= $langs->trans("ErrProductCreate", $ligne[0], $doliprod->error) . "\n";
                                         $error++;
                                     } else {
                                         // image et code barre
                                         if ($ligne[8]) {
                                             $this->add_photo_web($conf->produit->dir_output, $ligne[8], $doliprod->id);
                                         }
                                         /*if ($ligne[9]) {
                                         			if ($doliprod->setValueFrom('fk_barcode_type', 2) < 0){
                                         				$this->process_msg .= $langs->trans("ErrProductCreate", $ligne[0], $doliprod->error)."\n"; // TODO paramétrer
                                         				$error++;
                                         			}
                                         			if ($doliprod->setValueFrom('barcode', $ligne[9]) < 0 ){
                                         				$this->process_msg .= $langs->trans("ErrProductCreate", $ligne[0], $doliprod->error)."\n";
                                         				$error++;
                                         			}
                                         		}*/
                                     }
                                 }
                                 break;
                                 /*case 'M':
                                 		if ($pid>0) 
                                 		{
                                 			if ($doliprod->update($pid, $this->user) < 0){
                                 				$this->process_msg .= $langs->trans("ErrProductUpdate", $ligne[0], $doliprod->error)."\n";
                                 				$error++;
                                 			}
                                 			if (version_compare(DOL_VERSION, 3.5) >= 0){
                                 				if ($doliprod->updatePrice($doliprod->price, $doliprod->price_base_type, $this->user) < 0){
                                 					$this->process_msg .= $langs->trans("ErrProductUpdate", $ligne[0], $doliprod->error)."\n";
                                 					$error++;
                                 				}
                                 			}
                                 			else{
                                 				if ($doliprod->updatePrice($doliprod->id, $doliprod->price, $doliprod->price_base_type, $this->user) < 0){
                                 					$this->process_msg .= $langs->trans("ErrProductUpdate", $ligne[0], $doliprod->error)."\n";
                                 					$error++;
                                 				}
                                 			}
                                 		}
                                 		else $this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("ErrProdNoExist", $ligne[0])."\n";
                                 		break;*/
                             /*case 'M':
                             		if ($pid>0) 
                             		{
                             			if ($doliprod->update($pid, $this->user) < 0){
                             				$this->process_msg .= $langs->trans("ErrProductUpdate", $ligne[0], $doliprod->error)."\n";
                             				$error++;
                             			}
                             			if (version_compare(DOL_VERSION, 3.5) >= 0){
                             				if ($doliprod->updatePrice($doliprod->price, $doliprod->price_base_type, $this->user) < 0){
                             					$this->process_msg .= $langs->trans("ErrProductUpdate", $ligne[0], $doliprod->error)."\n";
                             					$error++;
                             				}
                             			}
                             			else{
                             				if ($doliprod->updatePrice($doliprod->id, $doliprod->price, $doliprod->price_base_type, $this->user) < 0){
                             					$this->process_msg .= $langs->trans("ErrProductUpdate", $ligne[0], $doliprod->error)."\n";
                             					$error++;
                             				}
                             			}
                             		}
                             		else $this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("ErrProdNoExist", $ligne[0])."\n";
                             		break;*/
                             case 'D':
                                 if ($pid > 0) {
                                     if ($doliprod->delete($pid) < 0) {
                                         $this->process_msg .= $langs->trans("ErrProductDelete", $ligne[0], $doliprod->error) . "\n";
                                         $error++;
                                     }
                                 } else {
                                     $this->process_msg .= $langs->trans("Untreated", $i) . ' ' . $langs->trans("ErrProdNoExist", $ligne[0]) . "\n";
                                 }
                         }
                         if (!$error) {
                             $this->db->commit();
                         } else {
                             $this->db->rollback();
                         }
                     }
                 }
                 // while
                 break;
             case 'ImportThirtdparty':
                 $i = 0;
                 //$societe = new Societe($this->db);
                 while ($ligne = fgetcsv($fp, 1000, ";")) {
                     $i++;
                     $societe = new Societe($this->db);
                     if ($this->firstline && $i == 1) {
                         continue;
                     }
                     if (!$ligne[0]) {
                         $this->process_msg .= $langs->trans("Untreated", $i) . " " . $langs->trans("ErrNameRequired") . "\n";
                         continue;
                     }
                     // vérifier par code_client
                     if ($ligne[13]) {
                         $sid = $this->get_socbyclientcode($ligne[13]);
                     } else {
                         if ($ligne[14]) {
                             $sid = $this->get_socbysuplliercode($ligne[14]);
                         }
                     }
                     if ($sid > 0) {
                         $societe->fetch($sid);
                     } else {
                         $sid = $societe->fetch('', $ligne[0]);
                     }
                     if ($ligne[12]) {
                         $pid = dol_getIdFromCode($this->db, $ligne[12], "c_pays", "code", "rowid");
                     } else {
                         $pid = '';
                     }
                     if ($pid <= 0) {
                         $pid = '';
                     }
                     $did = '';
                     $societe->id = $sid;
                     $societe->name = $ligne[0];
                     $societe->particulier = 0;
                     //Société
                     $societe->address = $ligne[1] . "\n" . $ligne[2] . "\n" . $ligne[3];
                     $societe->zip = $ligne[4];
                     $societe->town = $ligne[5];
                     $societe->state_id = $did;
                     if ($ligne[12]) {
                         $societe->country_code = $ligne[12];
                     }
                     $societe->country_id = $pid;
                     dol_syslog("codes {$pid} " . $lige[12], LOG_DEBUG);
                     $societe->phone = $ligne[6];
                     $societe->fax = $ligne[7];
                     $societe->email = $ligne[8];
                     $societe->url = $ligne[9];
                     $societe->idprof1 = $ligne[10];
                     switch ($ligne[11]) {
                         case '0':
                             $societe->fournisseur = 0;
                             $societe->client = $ligne[11];
                             break;
                         case '1':
                             $societe->fournisseur = 0;
                             $societe->client = $ligne[11];
                             break;
                         case '2':
                             $societe->fournisseur = 0;
                             $societe->client = $ligne[11];
                             break;
                         case '10':
                             $societe->client = 0;
                             $societe->fournisseur = 1;
                             break;
                         default:
                             break;
                     }
                     if ($ligne[13]) {
                         $societe->code_client = $ligne[13];
                     }
                     if ($ligne[14]) {
                         $societe->code_fournisseur = $ligne[14];
                     }
                     /*if ($ligne[15]) $societe->array_options["options_zone"]=$ligne[15];
                     				if (!empty($ligne[16])) $societe->array_options["options_CA"]=$ligne[16];
                     
                     				if (!empty($ligne[17]))
                     				{
                     					   if ($ligne[17] <= 5) $societe->effectif_id = 1;
                     					   elseif ($ligne[17] <= 10) $societe->effectif_id = 2;
                     					   elseif ($ligne[17] <= 50) $societe->effectif_id = 3;
                     					   elseif ($ligne[17] <= 100) $societe->effectif_id = 4;
                     					   elseif ($ligne[17] <= 500) $societe->effectif_id = 5;
                     					   else $societe->effectif_id = 7;
                     				}
                     				dol_syslog("effectif " . $lige[17].'  '.$societe->effectif_id." ".print_r($societe->array_options, true), LOG_DEBUG);*/
                     $this->db->begin;
                     switch ($typeimport) {
                         case 'C':
                             if ($sid > 0) {
                                 if ($societe->update($sid, $this->user) < 0) {
                                     $this->process_msg .= $langs->trans("ErrCompanyUpdate", $ligne[0], $societe->error) . "\n";
                                     $error++;
                                 }
                             } elseif ($societe->create($this->user) < 0) {
                                 $this->process_msg .= $langs->trans("ErrCompanyCreate", $ligne[0], $societe->error) . "\n";
                                 $error++;
                             }
                             break;
                             /*case 'M':
                             		if ($sid>0) 
                             		{
                             			if ($societe->update($sid, $this->user) < 0){
                             				$this->process_msg .= $langs->trans("ErrCompanyUpdate", $ligne[0], $societe->error)."\n";
                             				$error++;
                             			}
                             		}
                             		else $this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("CompanyNoExist", $ligne[0])."\n";
                             		break;*/
                         /*case 'M':
                         		if ($sid>0) 
                         		{
                         			if ($societe->update($sid, $this->user) < 0){
                         				$this->process_msg .= $langs->trans("ErrCompanyUpdate", $ligne[0], $societe->error)."\n";
                         				$error++;
                         			}
                         		}
                         		else $this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("CompanyNoExist", $ligne[0])."\n";
                         		break;*/
                         case 'D':
                             if ($sid > 0) {
                                 if ($societe->delete($sid) < 0) {
                                     $this->process_msg .= $langs->trans("ErrCompanyDelete", $ligne[0], $societe->error) . "\n";
                                     $error++;
                                 }
                             } else {
                                 $this->process_msg .= $langs->trans("Untreated", $i) . ' ' . $langs->trans("CompanyNoExist", $ligne[0]) . "\n";
                             }
                     }
                     if (!$error) {
                         $this->db->commit();
                     } else {
                         $this->db->rollback();
                     }
                 }
                 break;
             case 'ImportContact':
                 $i = 0;
                 //$contact=new Contact($this->db);
                 //$societe = new Societe($this->db);
                 while ($ligne = fgetcsv($fp, 1000, ";")) {
                     $i++;
                     $contact = new Contact($this->db);
                     $societe = new Societe($this->db);
                     if ($this->firstline && $i == 1) {
                         continue;
                     }
                     //if ($societe->fetch('',$ligne[0]) < 0 ) $this->process_msg .= "erreur lecture Société "."\n";
                     if ($ligne[0]) {
                         $socid = $this->get_socbyclientcode($ligne[0]);
                     } else {
                         if ($ligne[1]) {
                             $socid = $this->get_socbysuplliercode($ligne[1]);
                         }
                     }
                     if ($socid < 0) {
                         $this->process_msg .= $i . " " . $langs->trans("ErrCompanyRequired") . "\n";
                     } else {
                         $societe->fetch($socid);
                     }
                     if (!$societe->id) {
                         $this->process_msg .= $langs->trans("ErrCompanyNoExist", $ligne[0] . " " . $ligne[1]) . "\n";
                         continue;
                     }
                     if (empty($ligne[2])) {
                         $this->process_msg .= $langs->trans("Untreated", $i) . " " . $langs->trans("ErrNameRequired") . "\n";
                         continue;
                     }
                     $contactid = $this->get_contact_id($socid, $ligne[2], $ligne[3]);
                     $contact->id = $contactid;
                     $contact->civilite_id = $ligne[4];
                     $contact->lastname = $ligne[2];
                     $contact->firstname = $ligne[3];
                     if ($ligne[5] || $ligne[6] || $ligne[7]) {
                         $contact->address = $ligne[5] . "\n" . $ligne[6] . "\n" . $ligne[7];
                     } else {
                         $contact->address = $societe->address;
                     }
                     if ($ligne[8]) {
                         $contact->zip = $ligne[8];
                     } else {
                         $contact->zip = $societe->zip;
                     }
                     if ($ligne[9]) {
                         $contact->town = $ligne[9];
                     } else {
                         $contact->town = $societe->town;
                     }
                     if ($ligne[10]) {
                         $pid = dol_getIdFromCode($this->db, $ligne[10], "c_pays", "code", "rowid");
                         if ($pid <= 0) {
                             $pid = '';
                         }
                         $contact->country_id = $pid;
                         $contact->country_code = $ligne[10];
                     } else {
                         $contact->country_id = $societe->country_id;
                         $contact->country_code = $societe->country_code;
                     }
                     $contact->socid = $socid;
                     // fk_soc
                     $contact->status = 1;
                     $contact->email = $ligne[11];
                     $contact->phone_pro = $ligne[12];
                     $contact->fax = $ligne[13];
                     $contact->phone_mobile = $ligne[14];
                     $contact->priv = 0;
                     $this->db - begin;
                     switch ($typeimport) {
                         case 'C':
                             if ($contactid > 0) {
                                 if ($contact->update($contactid, $this->user) < 0) {
                                     $this->process_msg .= $langs->trans("ErrContactUpdate", $ligne[2], $contact->error) . "\n";
                                     $error++;
                                 }
                             } elseif ($contact->create($this->user) < 0) {
                                 $this->process_msg .= $langs->trans("ErrContactCreate", $ligne[2], $contact->error) . "\n";
                                 $error++;
                             }
                             break;
                             /*case 'M':
                             		if ($contactid>0) 
                             		{
                             			if ($contact->update($contactid, $this->user) < 0){
                             				$this->process_msg .= $langs->trans("ErrContactUpdate", $ligne[2], $contact->error)."\n";
                             				$error++;
                             			}
                             		}
                             		else $this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("ContactNoExist", $ligne[2])."\n";
                             		break;*/
                         /*case 'M':
                         		if ($contactid>0) 
                         		{
                         			if ($contact->update($contactid, $this->user) < 0){
                         				$this->process_msg .= $langs->trans("ErrContactUpdate", $ligne[2], $contact->error)."\n";
                         				$error++;
                         			}
                         		}
                         		else $this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("ContactNoExist", $ligne[2])."\n";
                         		break;*/
                         case 'D':
                             if ($contactid > 0) {
                                 if ($contact->delete($contactid) < 0) {
                                     $this->process_msg .= $langs->trans("ErrContactDelete", $ligne[2], $contact->error) . "\n";
                                     $error++;
                                 }
                             } else {
                                 $this->process_msg .= $langs->trans("Untreated", $i) . ' ' . $langs->trans("ContactNoExist", $ligne[2]) . "\n";
                             }
                     }
                     if (!$error) {
                         $this->db->commit();
                     } else {
                         $this->db->rollback();
                     }
                 }
                 break;
                 /*case 'ImportActions':
                 			$i=0;
                 			$contact=new Contact($this->db);
                 			$societe = new Societe($this->db);
                 			$actioncomm = new ActionComm($this->db);
                 			$actuser = new User($this->db);
                 			
                 			while ($ligne = fgetcsv($fp,1000,";"))
                 			{
                 				$i++;
                 				if ($this->firstline && $i== 1) continue;
                 				
                 				//if ($societe->fetch('',$ligne[0]) < 0 ) $this->process_msg .= "erreur lecture Société "."\n";
                 				//else $socid = $societe->id;
                 				$socid = $this->get_socbyclientcode($ligne[0]);
                 				if ($socid < 0 ) $this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("ErrCompanyRequired")."\n";
                 				else $societe->fetch($socid);
                 				$socid = $societe->id;
                 				
                 				if (!$socid) 
                 				{
                 					$this->process_msg .= $langs->trans("ErrCompanyNoExist", $ligne[0])."\n";
                 					continue;
                 				}
                 								
                 				//action sur un contact de la soc
                 				if ($ligne[1])
                 				{
                 					$contactid = $this->get_contact_id($socid, $ligne[1], $ligne[2]) ;
                 					
                 					if ($contactid < 0) {
                 						$this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("ContactNoExist", $ligne[1].' '. $ligne[2])."\n";
                 						// réinitialiser ??
                 						continue;
                 					}
                 					else $contact->fetch($contactid);
                 					
                 				}
                 				
                 
                 				$usertodo = '';
                 				if ($ligne[9])
                 				{
                 					$usertodo=new User($this->db);
                 					if ( $usertodo->fetch('',$ligne[9]) < 0 ) $this->process_msg .= $langs->trans("ErrUserNoExist", $ligne[9])."\n";
                 				}
                 				$userdone= '' ;
                 				if ($ligne[10])
                 				{
                 					$usertodo=new User($this->db);
                 					if ( $usertodo->fetch('',$ligne[10]) < 0 ) $this->process_msg .= $langs->trans("ErrUserNoExist", $ligne[10])."\n";
                 					
                 				}
                 				$datep = '';
                 				if ($ligne[6])
                 				{
                 					// voir date
                 					$n = sscanf($ligne[6],"%02d/%02d/%04d", $d_day, $d_mon, $d_year);
                 					if ($n==3) $datep=dol_mktime(12, 0, 0, $d_mon, $d_day, $d_year);
                 					if (!$datep) $this->process_msg .= $langs->trans("ErrDateConversion", $ligne[6])."\n";
                 				}
                 				else $datep ='';
                 				$datef='';
                 				if ($ligne[7])
                 				{
                 					// voir la date
                 					$n = sscanf($ligne[7],"%02d/%02d/%04d", $d_day, $d_mon, $d_year);
                 					if ($n==3)$datef=dol_mktime(12, 0, 0, $d_mon, $d_day, $d_year);
                 					if (!$datef) $this->process_msg .= $langs->trans("ErrDateConversion", $ligne[7])."\n";
                 				}
                 				else $datef ='';
                 				//$datef='';
                 				$actioncomm->societe = $societe;
                 				if ($ligne[1]) $actioncomm->contact = $contact;
                 				else $actioncomm->contact = '';
                 				$actioncomm->type_code = $ligne[3];
                 				$actioncomm->priority = $ligne[4];
                 				$actioncomm->location = '' ;
                 				$actioncomm->label = $ligne[5];
                 				$actioncomm->datep = $datep;
                 				$actioncomm->datef = $datef;
                 				$actioncomm->percentage = $ligne[8];
                 				$actioncomm->usertodo = $usertodo;
                 				$actioncomm->userdone = $userdone;
                 				$actioncomm->note =$ligne[11];
                 				
                 				switch ($typeimport)
                 				{					
                 				case 'C':
                 					$this->db->begin();
                 					if ($actioncomm->add($this->user) < 0) 
                 					{ 
                 						$this->process_msg .= $langs->trans("ErrActionCreate", $ligne[5], $actioncomm->error)."\n";
                 						$this->db->rollback();
                 					}
                 					else $this->db->commit();
                 					break;
                 				case 'M':
                 					$this->db->begin();
                 					if($actioncomm->update($user) < 0){
                 						$this->process_msg .= $langs->trans("ErrActionUpdate", $ligne[5], $actioncomm->error)."\n";
                 						$this->db->rollback();
                 					}
                 					else $this->db->commit();
                 					break;
                 				case 'D':
                 					$this->db->begin();
                 					if($actioncomm->delete() < 0){
                 						$this->process_msg .= $langs->trans("ErrActionDelete", $ligne[5], $actioncomm->error)."\n";
                 						$this->db->rollback();
                 					}
                 					else $this->db->commit();
                 					break;
                 				}
                 			}
                 				
                 			break;*/
             /*case 'ImportActions':
             			$i=0;
             			$contact=new Contact($this->db);
             			$societe = new Societe($this->db);
             			$actioncomm = new ActionComm($this->db);
             			$actuser = new User($this->db);
             			
             			while ($ligne = fgetcsv($fp,1000,";"))
             			{
             				$i++;
             				if ($this->firstline && $i== 1) continue;
             				
             				//if ($societe->fetch('',$ligne[0]) < 0 ) $this->process_msg .= "erreur lecture Société "."\n";
             				//else $socid = $societe->id;
             				$socid = $this->get_socbyclientcode($ligne[0]);
             				if ($socid < 0 ) $this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("ErrCompanyRequired")."\n";
             				else $societe->fetch($socid);
             				$socid = $societe->id;
             				
             				if (!$socid) 
             				{
             					$this->process_msg .= $langs->trans("ErrCompanyNoExist", $ligne[0])."\n";
             					continue;
             				}
             								
             				//action sur un contact de la soc
             				if ($ligne[1])
             				{
             					$contactid = $this->get_contact_id($socid, $ligne[1], $ligne[2]) ;
             					
             					if ($contactid < 0) {
             						$this->process_msg .= $langs->trans("Untreated", $i).' '.$langs->trans("ContactNoExist", $ligne[1].' '. $ligne[2])."\n";
             						// réinitialiser ??
             						continue;
             					}
             					else $contact->fetch($contactid);
             					
             				}
             				
             
             				$usertodo = '';
             				if ($ligne[9])
             				{
             					$usertodo=new User($this->db);
             					if ( $usertodo->fetch('',$ligne[9]) < 0 ) $this->process_msg .= $langs->trans("ErrUserNoExist", $ligne[9])."\n";
             				}
             				$userdone= '' ;
             				if ($ligne[10])
             				{
             					$usertodo=new User($this->db);
             					if ( $usertodo->fetch('',$ligne[10]) < 0 ) $this->process_msg .= $langs->trans("ErrUserNoExist", $ligne[10])."\n";
             					
             				}
             				$datep = '';
             				if ($ligne[6])
             				{
             					// voir date
             					$n = sscanf($ligne[6],"%02d/%02d/%04d", $d_day, $d_mon, $d_year);
             					if ($n==3) $datep=dol_mktime(12, 0, 0, $d_mon, $d_day, $d_year);
             					if (!$datep) $this->process_msg .= $langs->trans("ErrDateConversion", $ligne[6])."\n";
             				}
             				else $datep ='';
             				$datef='';
             				if ($ligne[7])
             				{
             					// voir la date
             					$n = sscanf($ligne[7],"%02d/%02d/%04d", $d_day, $d_mon, $d_year);
             					if ($n==3)$datef=dol_mktime(12, 0, 0, $d_mon, $d_day, $d_year);
             					if (!$datef) $this->process_msg .= $langs->trans("ErrDateConversion", $ligne[7])."\n";
             				}
             				else $datef ='';
             				//$datef='';
             				$actioncomm->societe = $societe;
             				if ($ligne[1]) $actioncomm->contact = $contact;
             				else $actioncomm->contact = '';
             				$actioncomm->type_code = $ligne[3];
             				$actioncomm->priority = $ligne[4];
             				$actioncomm->location = '' ;
             				$actioncomm->label = $ligne[5];
             				$actioncomm->datep = $datep;
             				$actioncomm->datef = $datef;
             				$actioncomm->percentage = $ligne[8];
             				$actioncomm->usertodo = $usertodo;
             				$actioncomm->userdone = $userdone;
             				$actioncomm->note =$ligne[11];
             				
             				switch ($typeimport)
             				{					
             				case 'C':
             					$this->db->begin();
             					if ($actioncomm->add($this->user) < 0) 
             					{ 
             						$this->process_msg .= $langs->trans("ErrActionCreate", $ligne[5], $actioncomm->error)."\n";
             						$this->db->rollback();
             					}
             					else $this->db->commit();
             					break;
             				case 'M':
             					$this->db->begin();
             					if($actioncomm->update($user) < 0){
             						$this->process_msg .= $langs->trans("ErrActionUpdate", $ligne[5], $actioncomm->error)."\n";
             						$this->db->rollback();
             					}
             					else $this->db->commit();
             					break;
             				case 'D':
             					$this->db->begin();
             					if($actioncomm->delete() < 0){
             						$this->process_msg .= $langs->trans("ErrActionDelete", $ligne[5], $actioncomm->error)."\n";
             						$this->db->rollback();
             					}
             					else $this->db->commit();
             					break;
             				}
             			}
             				
             			break;*/
             case 'Importtarif':
                 // ref four
                 $i = 0;
                 $this->process_msg = '';
                 $error = 0;
                 /*$doliprod = new Product($this->db);
                 		$product = new ProductFournisseur($this->db);
                 		$societe = new Societe($this->db);*/
                 while ($ligne = fgetcsv($fp, 1000, ";")) {
                     $doliprod->id = '';
                     $i++;
                     $doliprod = new Product($this->db);
                     $product = new ProductFournisseur($this->db);
                     $societe = new Societe($this->db);
                     if ($this->firstline && $i == 1) {
                         continue;
                     }
                     // recherche du fournisseur
                     if ($societe->fetch('', $ligne[2]) > 0) {
                         $sid = $societe->id;
                     } else {
                         $this->process_msg .= $langs->trans("Untreated", $i) . " " . $langs->trans("ErrComppanyNoExist", $ligne[2]) . "\n";
                         $sid = '';
                     }
                     if ($doliprod->fetch('', $ligne[0]) > 0) {
                         $pid = $doliprod->id;
                     } else {
                         $this->process_msg .= $langs->trans("Untreated", $i) . " " . $langs->trans("ErrProductNoExist", $ligne[0], $doliprod->error) . "\n";
                         $pid = '';
                     }
                     if ($sid > 0 && $pid > 0) {
                         $result = $product->fetch($doliprod->id);
                         if ($result > 0) {
                             $this->db->begin();
                             switch ($typeimport) {
                                 case 'C':
                                     $ret = $product->add_fournisseur($this->user, $sid, $ligne[1], $ligne[3]);
                                     if ($ret < 0 && $ret != -3) {
                                         $this->process_msg .= $langs->trans("Untreated", $i) . " " . $langs->trans("ErrCreatePrice", $product->error) . "\n";
                                         $error++;
                                     }
                                     $ret = $product->update_buyprice($ligne[3], $ligne[4], $this->user, 'HT', $supplier, '', $ligne[1], $ligne[5]);
                                     if ($ret < 0 && $ret != -3) {
                                         $this->process_msg .= $langs->trans("Untreated", $i) . " " . $langs->trans("ErrCreatePrice", $product->error) . "\n";
                                         $error++;
                                     }
                                     break;
                                     /*case 'M':
                                     		{
                                     			// gestion du prix obligatoire
                                     			$supplier=new Fournisseur($this->db);
                                     			$result=$supplier->fetch($sid);
                                     			
                                     			$ret=$product->update_buyprice($ligne[3], $ligne[4] , $this->user, 'HT', $supplier, '', $ligne[1], $ligne[5] );
                                     			if ($ret < 0)
                                     			{
                                     				$this->process_msg .= $langs->trans("Untreated", $i)." ".$langs->trans("Qty").$ligne[3]. ", ".$langs->trans("Price").$ligne[4]." ".$langs->trans("ErrUpdatePrice", $product->error)."\n";
                                     				$error ++;
                                     			}
                                     			
                                     		}
                                     		break;*/
                                 /*case 'M':
                                 		{
                                 			// gestion du prix obligatoire
                                 			$supplier=new Fournisseur($this->db);
                                 			$result=$supplier->fetch($sid);
                                 			
                                 			$ret=$product->update_buyprice($ligne[3], $ligne[4] , $this->user, 'HT', $supplier, '', $ligne[1], $ligne[5] );
                                 			if ($ret < 0)
                                 			{
                                 				$this->process_msg .= $langs->trans("Untreated", $i)." ".$langs->trans("Qty").$ligne[3]. ", ".$langs->trans("Price").$ligne[4]." ".$langs->trans("ErrUpdatePrice", $product->error)."\n";
                                 				$error ++;
                                 			}
                                 			
                                 		}
                                 		break;*/
                                 case 'D':
                                     // suprresion de la ligne avec le même nb d'article et le même prix
                                     $sql = "SELECT pfp.rowid FROM " . MAIN_DB_PREFIX . "product_fournisseur_price as pfp";
                                     $sql .= " WHERE pfp.quantity = '" . $ligne[3] . "' AND pfp.ref_fourn = '" . $ligne[1];
                                     $sql .= "' AND pfp.fk_soc = '" . $sid . "' AND pfp.fk_product='" . $pid . "'";
                                     $sql .= " AND pfp.entity = " . $conf->entity;
                                     $resql = $this->db->query($sql);
                                     if ($resql) {
                                         $obj = $this->db->fetch_object($resql);
                                         if ($obj->rowid > 0) {
                                             $result = $product->remove_product_fournisseur_price($obj->rowid);
                                         } else {
                                             $this->process_msg .= $langs->trans("Untreated", $i) . ' ' . $langs->trans("ErrDeletePrice", $product->error) . "\n";
                                             $error++;
                                         }
                                     } else {
                                         $this->process_msg .= "Error SQL= " . $sql . "\n";
                                         $error++;
                                     }
                                     break;
                             }
                             //switch
                         }
                         if (!$error) {
                             $this->db->commit();
                         } else {
                             $this->db->rollback();
                         }
                     }
                     // fournisseur trouvé
                 }
                 // traitement ligne
                 // while reffour
                 break;
         }
         // fin switch
         fclose($fp);
     } else {
         $this->error = $langs->trans("ErrOpenFile") . $nomfich;
         $error = -1;
     }
     return $error;
 }
function _fiche_ligne(&$form, &$of, $type)
{
    global $db, $conf, $langs, $hookmanager;
    //TODO rules guys ! To Facto ! AA
    $formProduct = new FormProduct($db);
    $PDOdb = new TPDOdb();
    $TRes = array();
    foreach ($of->TAssetOFLine as $k => &$TAssetOFLine) {
        $product =& $TAssetOFLine->product;
        if (is_null($product)) {
            $product = new Product($db);
            $product->fetch($TAssetOFLine->fk_product);
            $product->fetch_optionals();
        }
        $conditionnement = $TAssetOFLine->conditionnement;
        if (!empty($conf->asset->enabled)) {
            $TAssetType = new TAsset_type();
            $TAssetType->load($PDOdb, $product->array_options['options_type_asset']);
            $conditionnement_unit = $TAssetType->measuring_units == 'unit' || $TAssetType->gestion_stock == 'UNIT' ? 'unité(s)' : $TAssetOFLine->libUnite();
        } else {
            $conditionnement_unit = 'unité(s)';
            // TODO translate
        }
        //$conditionnement_unit = $TAssetOFLine->libUnite();
        if ($TAssetOFLine->measuring_units != 'unit' && !empty($TAssetOFLine->measuring_units)) {
            $conditionnement_label = ' / ' . $conditionnement . " " . $conditionnement_unit;
            $conditionnement_label_edit = ' par ' . $form->texte('', 'TAssetOFLine[' . $k . '][conditionnement]', $conditionnement, 5, 5, '', '') . $conditionnement_unit;
        } else {
            $conditionnement_label = $conditionnement_label_edit = '';
        }
        if ($TAssetOFLine->type == "NEEDED" && $type == "NEEDED") {
            $stock_needed = TAssetOF::getProductStock($product->id);
            $TLine = array('id' => $TAssetOFLine->getId(), 'idprod' => $form->hidden('TAssetOFLine[' . $k . '][fk_product]', $product->id), 'lot_number' => $of->status == 'DRAFT' ? $form->texte('', 'TAssetOFLine[' . $k . '][lot_number]', $TAssetOFLine->lot_number, 15, 50, 'type_product="NEEDED" fk_product="' . $product->id . '" rel="lot-' . $TAssetOFLine->getId() . '" ', 'TAssetOFLineLot') : $TAssetOFLine->lot_number, 'libelle' => $product->getNomUrl(1) . ' ' . $product->label . ' - ' . ($stock_needed > 0 ? $langs->trans("Stock") . " : " . $stock_needed : '<span style="color:red;font-weight:bold;">' . $langs->trans("Stock") . " : " . $stock_needed . '</span>') . _fiche_ligne_asset($PDOdb, $form, $of, $TAssetOFLine, 'NEEDED'), 'qty_needed' => $TAssetOFLine->qty_needed . $conditionnement_label, 'qty' => $of->status == 'DRAFT' ? $form->texte('', 'TAssetOFLine[' . $k . '][qty]', $TAssetOFLine->qty, 5, 50) : $TAssetOFLine->qty, 'qty_used' => $of->status == 'OPEN' || $of->status == 'CLOSE' ? $form->texte('', 'TAssetOFLine[' . $k . '][qty_used]', $TAssetOFLine->qty_used, 5, 50) : $TAssetOFLine->qty_used, 'qty_toadd' => $TAssetOFLine->qty - $TAssetOFLine->qty_used, 'workstations' => $conf->workstation->enabled ? $TAssetOFLine->visu_checkbox_workstation($db, $of, $form, 'TAssetOFLine[' . $k . '][fk_workstation][]') : '', 'delete' => $form->type_aff == 'edit' && ($of->status == 'DRAFT' || !empty($conf->global->OF_USE_DESTOCKAGE_PARTIEL) && $of->status != 'CLOSE' && empty($TAssetOFLine->qty_used)) ? '<a href="javascript:deleteLine(' . $TAssetOFLine->getId() . ',\'NEEDED\');">' . img_picto('Supprimer', 'delete.png') . '</a>' : '', 'fk_entrepot' => !empty($conf->global->ASSET_MANUAL_WAREHOUSE) && ($of->status == 'DRAFT' || $of->status == 'VALID') && $form->type_aff == 'edit' ? $formProduct->selectWarehouses($TAssetOFLine->fk_entrepot, 'TAssetOFLine[' . $k . '][fk_entrepot]', '', 0, 0, $TAssetOFLine->fk_product) : $TAssetOFLine->getLibelleEntrepot($PDOdb), 'note_private' => $of->status == 'DRAFT' ? $form->zonetexte('', 'TAssetOFLine[' . $k . '][note_private]', $TAssetOFLine->note_private, 50, 1) : $TAssetOFLine->note_private);
            $action = $form->type_aff;
            $parameter = array('of' => &$of, 'line' => &$TLine, 'type' => 'NEEDED');
            $res = $hookmanager->executeHooks('lineObjectOptions', $parameter, $TAssetOFLine, $action);
            if ($res > 0 && !empty($hookmanager->resArray)) {
                $TLine = $hookmanager->resArray;
            }
            $TRes[] = $TLine;
        } elseif ($TAssetOFLine->type == "TO_MAKE" && $type == "TO_MAKE") {
            if (empty($TAssetOFLine->TFournisseurPrice)) {
                $TAssetOFLine->loadFournisseurPrice($PDOdb);
            }
            // Permet de sélectionner par défaut "(Fournisseur "Interne" => Fabrication interne)" si le produit TO_MAKE n'a pas de stock lorsqu'on est en mode edit et que la ligne TO_MAKE n'a pas encore de prix fournisseur enregistré
            dol_include_once('/product/class/product.class.php');
            $p = new Product($db);
            $selected = 0;
            if ($p->fetch($TAssetOFLine->fk_product)) {
                $p->load_stock();
                $p->stock_reel;
                if ($TAssetOFLine->type === 'TO_MAKE' && $p->stock_reel <= 0 && $_REQUEST['action'] === 'edit') {
                    $selected = -2;
                }
            }
            // *************************************************************
            $Tab = array();
            foreach ($TAssetOFLine->TFournisseurPrice as &$objPrice) {
                $label = "";
                //Si on a un prix fournisseur pour le produit
                if ($objPrice->price > 0) {
                    $unit = $objPrice->quantity == 1 ? 'Unité' : 'Unités';
                    $label .= floatval($objPrice->price) . ' ' . $conf->currency . ' - ' . $objPrice->quantity . ' ' . $unit . ' -';
                }
                //Affiche le nom du fournisseur
                $label .= ' (Fournisseur "' . utf8_encode($objPrice->name) . '"';
                //Prix unitaire minimum si renseigné dans le PF
                if ($objPrice->quantity > 0) {
                    ' ' . $objPrice->quantity . ' pièce(s) min,';
                }
                //Affiche le type du PF :
                if ($objPrice->compose_fourni) {
                    //			soit on fabrique les composants
                    $label .= ' => Fabrication interne';
                } elseif ($objPrice->quantity <= 0) {
                    //			soit on a le produit finis déjà en stock
                    $label .= ' => Sortie de stock';
                }
                if ($objPrice->quantity > 0) {
                    //				soit on commande a un fournisseur
                    $label .= ' => Commande fournisseur';
                }
                $label .= ")";
                $Tab[$objPrice->rowid] = array('label' => $label, 'compose_fourni' => $objPrice->compose_fourni ? $objPrice->compose_fourni : 0);
            }
            if ($conf->nomenclature->enabled) {
                dol_include_once('/nomenclature/class/nomenclature.class.php');
                if ($of->status == 'DRAFT' && !$TAssetOFLine->nomenclature_valide) {
                    $TNomenclature = TNomenclature::get($PDOdb, $TAssetOFLine->fk_product, true);
                    if (count($TNomenclature) > 0) {
                        $nomenclature = '<div>' . $form->combo('', 'TAssetOFLine[' . $k . '][fk_nomenclature]', $TNomenclature, $TAssetOFLine->fk_nomenclature);
                        if ($form->type_aff == 'edit') {
                            $nomenclature .= '<a href="#" class="valider_nomenclature" data-id_of="' . $of->getId() . '" data-product="' . $TAssetOFLine->fk_product . '" data-of_line="' . $TAssetOFLine->rowid . '">Valider</a>';
                        } else {
                            $nomenclature .= " - Nomenclature à sélectionner";
                        }
                        $nomenclature .= '</div>';
                    } else {
                        $nomenclature = '';
                    }
                } else {
                    $n = new TNomenclature();
                    $n->load($PDOdb, $TAssetOFLine->fk_nomenclature);
                    $nomenclature = '<div>' . (string) $n;
                    $picture = $TAssetOFLine->nomenclature_valide ? 'ok.png' : 'no.png';
                    $nomenclature .= ' <img src="img/' . $picture . '" style="padding-left: 2px; vertical-align: middle;" /></div>';
                }
            }
            //($of->status=='DRAFT') ? $form->combo('', 'TAssetOFLine['.$k.'][fk_nomenclature]', _getArrayNomenclature($PDOdb, $TAssetOFLine), $TAssetOFLine->fk_nomenclature) : _getTitleNomenclature($PDOdb, $TAssetOFLine->fk_nomenclature)
            $stock_tomake = TAssetOF::getProductStock($product->id);
            $TLine = array('id' => $TAssetOFLine->getId(), 'idprod' => $form->hidden('TAssetOFLine[' . $k . '][fk_product]', $product->id), 'lot_number' => $of->status == 'DRAFT' ? $form->texte('', 'TAssetOFLine[' . $k . '][lot_number]', $TAssetOFLine->lot_number, 15, 50, 'type_product="TO_MAKE" fk_product="' . $product->id . '"', 'TAssetOFLineLot') : $TAssetOFLine->lot_number, 'libelle' => $product->getNomUrl(1) . ' ' . $product->label . ' - ' . $langs->trans("Stock") . " : " . $stock_tomake . _fiche_ligne_asset($PDOdb, $form, $of, $TAssetOFLine, false), 'nomenclature' => $nomenclature, 'addneeded' => $form->type_aff == 'edit' && $of->status == 'DRAFT' ? '<a href="#null" statut="' . $of->status . '" onclick="addAllLines(' . $of->getId() . ',' . $TAssetOFLine->getId() . ',this);">' . img_picto('Mettre à jour les produits nécessaires', 'object_technic.png') . '</a>' : '', 'qty' => $of->status == 'DRAFT' ? $form->texte('', 'TAssetOFLine[' . $k . '][qty]', $TAssetOFLine->qty, 5, 5, '', '') . $conditionnement_label_edit : $TAssetOFLine->qty . $conditionnement_label, 'qty_used' => $of->status == 'OPEN' || $of->status == 'CLOSE' ? $form->texte('', 'TAssetOFLine[' . $k . '][qty_used]', $TAssetOFLine->qty_used, 5, 5, '', '') . $conditionnement_label_edit : $TAssetOFLine->qty_used . $conditionnement_label, 'fk_product_fournisseur_price' => $form->combo('', 'TAssetOFLine[' . $k . '][fk_product_fournisseur_price]', $Tab, $TAssetOFLine->fk_product_fournisseur_price != 0 ? $TAssetOFLine->fk_product_fournisseur_price : $selected, 1, '', 'style="max-width:250px;"'), 'delete' => $form->type_aff == 'edit' && $of->status == 'DRAFT' ? '<a href="#null" onclick="deleteLine(' . $TAssetOFLine->getId() . ',\'TO_MAKE\');">' . img_picto('Supprimer', 'delete.png') . '</a>' : '', 'fk_entrepot' => !empty($conf->global->ASSET_MANUAL_WAREHOUSE) && ($of->status == 'DRAFT' || $of->status == 'VALID' || $of->status == 'NEEDOFFER' || $of->status == 'ONORDER' || $of->status == 'OPEN') && $form->type_aff == 'edit' ? $formProduct->selectWarehouses($TAssetOFLine->fk_entrepot, 'TAssetOFLine[' . $k . '][fk_entrepot]', '', 0, 0, $TAssetOFLine->fk_product) : $TAssetOFLine->getLibelleEntrepot($PDOdb));
            $action = $form->type_aff;
            $parameter = array('of' => &$of, 'line' => &$TLine, 'type' => 'TO_MAKE');
            $res = $hookmanager->executeHooks('lineObjectOptions', $parameter, $TAssetOFLine, $action);
            if ($res > 0 && !empty($hookmanager->resArray)) {
                $TLine = $hookmanager->resArray;
            }
            $TRes[] = $TLine;
        }
    }
    return $TRes;
}
 function addMoreLine($parameters, &$object, &$action, $hookmanager)
 {
     global $db, $conf, $langs;
     if (!empty($conf->global->OF_SHOW_QTY_THEORIQUE_MOINS_OF)) {
         $langs->load('asset@asset');
         dol_include_once('/product/class/procudt.class.php');
         $product = new Product($db);
         $fk_product = GETPOST('id', 'int');
         $ref_product = GETPOST('ref', 'alpha');
         $f = $product->fetch($fk_product, $ref_product);
         if ($f > 0) {
             $product->load_stock();
             list($qty_to_make, $qty_needed) = $this->_calcQtyOfProductInOf($db, $conf, $product);
             $qty = $product->stock_theorique + $qty_to_make - $qty_needed;
             print '<tr>';
             print '<td>' . $langs->trans('ofLabelQtyTheoriqueMoinsOf') . '</td>';
             print '<td>' . $langs->trans('ofResultQty', $qty, $qty_to_make, $qty_needed) . '</td>';
             print '</tr>';
         }
     }
 }
Example #15
0
	}
}

// Transfer stock from a warehouse to another warehouse
if ($action == "transfert_stock" && ! $_POST["cancel"])
{
	if ($_POST["id_entrepot_source"] <> $_POST["id_entrepot_destination"])
	{
		if (is_numeric($_POST["nbpiece"]) && $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[$_POST["id_entrepot_source"]]->pmp)) $pricesrc=$product->stock_warehouse[$_POST["id_entrepot_source"]]->pmp;
			$pricedest=$pricesrc;

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

			// Remove stock
			$result1=$product->correct_stock(
    			$user,
    			$_POST["id_entrepot_source"],
    			$_POST["nbpiece"],
    			1,
    			$_POST["label"],
 /**
  * 		Add ticket line into database (linked to product/service or not)
  * 		@param    	array	$lines           	Ticket Lines
  *    	@return    	array             			Result of adding
  */
 private function addFactureLines($lines, $idTicket, $isreturn = false)
 {
     global $db;
     $res = 0;
     $object = new Facture($db);
     $object->fetch($idTicket);
     $object->brouillon = 1;
     if (sizeof($lines) > 0) {
         foreach ($lines as $line) {
             if (sizeof($line) > 0) {
                 if ($line['idProduct'] > 0) {
                     $product_static = new Product($db);
                     $product_static->id = $line['idProduct'];
                     $product_static->load_stock();
                     if ($product_static->stock_reel < 1 || $product_static->stock_reel < $line['cant']) {
                         $res = -4;
                     }
                     if (!$isreturn) {
                         $qty = $line['cant'];
                     } else {
                         $qty = $line['cant'] * -1;
                     }
                     $object->brouillon = 1;
                     $line['discount'] = $line['discount'] + $object->remise_percent;
                     $line['description'] = $line['description'] . " " . $line['note'];
                     // TODO buscar el pmp del producto para este almacén, si es cero, pmp en general.
                     $terminal = $_SESSION['TERMINAL_ID'];
                     $cash = new Cash($db);
                     $cash->fetch($terminal);
                     $warehouse = $cash->fk_warehouse;
                     $sql = "SELECT\tp.pmp as totpmp, (select ps.pmp FROM " . MAIN_DB_PREFIX . "product_stock as ps ";
                     $sql .= " WHERE ps.fk_product = " . $line["idProduct"] . " AND ps.fk_entrepot = " . $warehouse . ") as warepmp ";
                     $sql .= " FROM " . MAIN_DB_PREFIX . "product as p WHERE p.rowid = " . $line["idProduct"];
                     $resql = $db->query($sql);
                     if ($resql) {
                         $objp = $db->fetch_object($resql);
                         $pmp = $objp->warepmp;
                         if ($pmp <= 0) {
                             $pmp = $objp->totpmp;
                             if ($pmp <= 0 && $conf->global->ForceBuyingPriceIfNull) {
                                 $pmp = $line['price'];
                             }
                         }
                     }
                     $res = $object->addline($line['description'], $line['price'], $qty, $line['tva_tx'], $line['localtax1_tx'], $line['localtax2_tx'], $line['idProduct'], $line['discount'], '', '', 0, 0, '', $line['price_base_type'], $line['price_ttc'], $line['fk_product_type'], -1, 0, '', 0, 0, null, $pmp);
                 }
             } else {
                 $res = -1;
             }
         }
     }
     return $res;
 }
Example #17
0
 if ($conf->stock->enabled) {
     $langs->load("stocks");
     if ($objp->fk_statut > 0 && $objp->fk_statut < 3) {
         $notshippable = 0;
         $warning = 0;
         $text_info = '';
         $nbprod = 0;
         $numlines = count($generic_commande->lines);
         // Loop on each line of order
         for ($lig = 0; $lig < $numlines; $lig++) {
             if ($generic_commande->lines[$lig]->product_type == 0 && $generic_commande->lines[$lig]->fk_product > 0) {
                 $nbprod++;
                 // order contains real products
                 $generic_product->id = $generic_commande->lines[$lig]->fk_product;
                 if (empty($productstat_cache[$generic_commande->lines[$lig]->fk_product])) {
                     $generic_product->load_stock();
                     $generic_product->load_virtual_stock();
                     $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stock_reel'] = $generic_product->stock_reel;
                     $productstat_cachevirtual[$generic_commande->lines[$lig]->fk_product]['stock_reel'] = $generic_product->stock_theorique;
                 } else {
                     $generic_product->stock_reel = $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stock_reel'];
                     $generic_product->stock_theorique = $productstat_cachevirtual[$generic_commande->lines[$lig]->fk_product]['stock_reel'] = $generic_product->stock_theorique;
                 }
                 if (empty($conf->global->SHIPPABLE_ORDER_ICON_IN_LIST)) {
                     $text_info .= $generic_commande->lines[$lig]->qty . ' X ' . $generic_commande->lines[$lig]->ref . '&nbsp;' . dol_trunc($generic_commande->lines[$lig]->product_label, 25);
                     $text_info .= ' - ' . $langs->trans("Stock") . ': ' . $generic_product->stock_reel;
                     $text_info .= ' - ' . $langs->trans("VirtualStock") . ': ' . $generic_product->stock_theorique;
                     $text_info .= '<br>';
                     if ($generic_commande->lines[$lig]->qty > $generic_product->stock_reel) {
                         $notshippable++;
                     }
/**
 * Update a product or service
 *
 * @param	array		$authentication		Array of authentication information
 * @param	Product		$product			Product
 * @return	array							Array result
 */
function updateProductOrService($authentication, $product)
{
    global $db, $conf, $langs;
    $now = dol_now();
    dol_syslog("Function: updateProductOrService login="******"You must choose between price or price_net to provide price.";
    }
    if ($product['barcode'] && !$product['barcode_type']) {
        $errror++;
        $errorcode = 'KO';
        $errorlabel = "You must set a barcode type when setting a barcode.";
    }
    if (!$error) {
        include_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
        $newobject = new Product($db);
        $newobject->fetch($product['id']);
        if (isset($product['ref'])) {
            $newobject->ref = $product['ref'];
        }
        if (isset($product['ref_ext'])) {
            $newobject->ref_ext = $product['ref_ext'];
        }
        $newobject->type = $product['type'];
        $newobject->libelle = $product['label'];
        // @deprecated
        $newobject->label = $product['label'];
        $newobject->description = $product['description'];
        $newobject->note = $product['note'];
        $newobject->status = $product['status_tosell'];
        $newobject->status_buy = $product['status_tobuy'];
        $newobject->price = $product['price_net'];
        $newobject->price_ttc = $product['price'];
        $newobject->tva_tx = $product['vat_rate'];
        $newobject->price_base_type = $product['price_base_type'];
        $newobject->date_creation = $now;
        if ($product['barcode']) {
            $newobject->barcode = $product['barcode'];
            $newobject->barcode_type = $product['barcode_type'];
        }
        $newobject->stock_reel = $product['stock_real'];
        $newobject->pmp = $product['pmp'];
        $newobject->seuil_stock_alert = $product['stock_alert'];
        $newobject->country_id = $product['country_id'];
        if ($product['country_code']) {
            $newobject->country_id = getCountry($product['country_code'], 3);
        }
        $newobject->customcode = $product['customcode'];
        $newobject->canvas = $product['canvas'];
        /*foreach($product['lines'] as $line)
          {
              $newline=new FactureLigne($db);
              $newline->type=$line['type'];
              $newline->desc=$line['desc'];
              $newline->fk_product=$line['fk_product'];
              $newline->total_ht=$line['total_net'];
              $newline->total_vat=$line['total_vat'];
              $newline->total_ttc=$line['total'];
              $newline->vat=$line['vat_rate'];
              $newline->qty=$line['qty'];
              $newline->fk_product=$line['product_id'];
          }*/
        //var_dump($product['ref_ext']);
        //var_dump($product['lines'][0]['type']);
        $extrafields = new ExtraFields($db);
        $extralabels = $extrafields->fetch_name_optionals_label('product', true);
        foreach ($extrafields->attribute_label as $key => $label) {
            $key = 'options_' . $key;
            $newobject->array_options[$key] = $product[$key];
        }
        $db->begin();
        $result = $newobject->update($newobject->id, $fuser);
        if ($result <= 0) {
            $error++;
        } else {
            // Update stock if stock count is provided and differs from database after creation or update
            if (isset($product['stock_real']) && $product['stock_real'] != '' && !empty($conf->global->stock->enabled)) {
                require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
                $savstockreal = $newobject->stock_reel;
                $newobject->load_stock();
                // This overwrite ->stock_reel
                $getstockreal = $newobject->stock_reel;
                if ($savstockreal != $getstockreal) {
                    $warehouse = new Entrepot($this->db);
                    $warehouse->fetch(0, $product['warehouse_ref']);
                    if ($warehouse->id > 0) {
                        if ($savstockreal - $getstockreal > 0) {
                            $result = $newobject->correct_stock($fuser, $warehouse->id, $savstockreal - $getstockreal, 0, 'Correction from external call (Web Service)', 0, 'WS' . dol_print_date($now, 'dayhourlog'));
                        }
                        if ($savstockreal - $getstockreal > 0) {
                            $result = $newobject->correct_stock($fuser, $warehouse->id, $savstockreal - $getstockreal, 1, 'Correction from external call (Web Service)', 0, 'WS' . dol_print_date($now, 'dayhourlog'));
                        }
                        if ($result <= 0) {
                            $error++;
                            $newobject->error = 'You set a different value for stock, but correction of stock count (before=' . $getstockreal . ', after=' . $savstockreal . ') fails with error ' . $newobject->error;
                        }
                    } else {
                        $error++;
                        $newobject->error = 'You set a different value for stock but we failed to find warehouse ' . $product['warehouse_ref'] . ' to make correction.';
                    }
                }
            }
        }
        if (!$error) {
            if ($newobject->price_base_type == 'HT') {
                $result = $newobject->updatePrice($newobject->price, $newobject->price_base_type, $fuser);
                if ($result <= 0) {
                    $error++;
                }
            } elseif ($newobject->price_base_type == 'TTC') {
                $result = $newobject->updatePrice($newobject->price_ttc, $newobject->price_base_type);
                if ($result <= 0) {
                    $error++;
                }
            }
        }
        if (!$error) {
            $db->commit();
            $objectresp = array('result' => array('result_code' => 'OK', 'result_label' => ''), 'id' => $newobject->id, 'ref' => $newobject->ref);
        } else {
            $db->rollback();
            $error++;
            $errorcode = 'KO';
            $errorlabel = $newobject->error;
        }
    }
    if ($error) {
        $objectresp = array('result' => array('result_code' => $errorcode, 'result_label' => $errorlabel));
    }
    return $objectresp;
}
/**
 * Get produt or service
 *
 * @param	array		$authentication		Array of authentication information
 * @param	int			$id					Id of object
 * @param	string		$ref				Ref of object
 * @param	string		$ref_ext			Ref external of object
 * @param   string      $lang               Lang to force
 * @return	mixed
 */
function getProductOrService($authentication, $id = '', $ref = '', $ref_ext = '', $lang = '')
{
    global $db, $conf, $langs;
    dol_syslog("Function: getProductOrService login="******" id=" . $id . " ref=" . $ref . " ref_ext=" . $ref_ext);
    $langcode = $lang ? $lang : (empty($conf->global->MAIN_LANG_DEFAULT) ? 'auto' : $conf->global->MAIN_LANG_DEFAULT);
    $langs->setDefaultLang($langcode);
    if ($authentication['entity']) {
        $conf->entity = $authentication['entity'];
    }
    // Init and check authentication
    $objectresp = array();
    $errorcode = '';
    $errorlabel = '';
    $error = 0;
    $fuser = check_authentication($authentication, $error, $errorcode, $errorlabel);
    // Check parameters
    if (!$error && ($id && $ref || $id && $ref_ext || $ref && $ref_ext)) {
        $error++;
        $errorcode = 'BAD_PARAMETERS';
        $errorlabel = "Parameter id, ref and ref_ext can't be both provided. You must choose one or other but not both.";
    }
    if (!$error) {
        $langcode = $lang ? $lang : (empty($conf->global->MAIN_LANG_DEFAULT) ? 'auto' : $conf->global->MAIN_LANG_DEFAULT);
        $langs->setDefaultLang($langcode);
        $fuser->getrights();
        if ($fuser->rights->produit->lire || $fuser->rights->service->lire) {
            $product = new Product($db);
            $result = $product->fetch($id, $ref, $ref_ext);
            if ($result > 0) {
                $product->load_stock();
                $dir = !empty($conf->product->dir_output) ? $conf->product->dir_output : $conf->service->dir_output;
                $pdir = get_exdir($product->id, 2) . $product->id . "/photos/";
                $dir = $dir . '/' . $pdir;
                if (!empty($product->multilangs[$langs->defaultlang]["label"])) {
                    $product->label = $product->multilangs[$langs->defaultlang]["label"];
                }
                if (!empty($product->multilangs[$langs->defaultlang]["description"])) {
                    $product->description = $product->multilangs[$langs->defaultlang]["description"];
                }
                if (!empty($product->multilangs[$langs->defaultlang]["note"])) {
                    $product->note = $product->multilangs[$langs->defaultlang]["note"];
                }
                $productorservice_result_fields = array('id' => $product->id, 'ref' => $product->ref, 'ref_ext' => $product->ref_ext, 'label' => $product->label, 'description' => $product->description, 'date_creation' => dol_print_date($product->date_creation, 'dayhourrfc'), 'date_modification' => dol_print_date($product->date_modification, 'dayhourrfc'), 'note' => $product->note, 'status_tosell' => $product->status, 'status_tobuy' => $product->status_buy, 'type' => $product->type, 'barcode' => $product->barcode, 'barcode_type' => $product->barcode_type, 'country_id' => $product->country_id > 0 ? $product->country_id : '', 'country_code' => $product->country_code, 'custom_code' => $product->customcode, 'price_net' => $product->price, 'price' => $product->price_ttc, 'price_min_net' => $product->price_min, 'price_min' => $product->price_min_ttc, 'price_base_type' => $product->price_base_type, 'vat_rate' => $product->tva_tx, 'vat_npr' => $product->tva_npr, 'localtax1_tx' => $product->localtax1_tx, 'localtax2_tx' => $product->localtax2_tx, 'stock_real' => $product->stock_reel, 'stock_alert' => $product->seuil_stock_alerte, 'pmp' => $product->pmp, 'import_key' => $product->import_key, 'dir' => $pdir, 'images' => $product->liste_photos($dir, $nbmax = 10));
                //Retreive all extrafield for thirdsparty
                // fetch optionals attributes and labels
                $extrafields = new ExtraFields($db);
                $extralabels = $extrafields->fetch_name_optionals_label('product', true);
                //Get extrafield values
                $product->fetch_optionals($product->id, $extralabels);
                foreach ($extrafields->attribute_label as $key => $label) {
                    $productorservice_result_fields = array_merge($productorservice_result_fields, array('options_' . $key => $product->array_options['options_' . $key]));
                }
                // Create
                $objectresp = array('result' => array('result_code' => 'OK', 'result_label' => ''), 'product' => $productorservice_result_fields);
            } else {
                $error++;
                $errorcode = 'NOT_FOUND';
                $errorlabel = 'Object not found for id=' . $id . ' nor ref=' . $ref . ' nor ref_ext=' . $ref_ext;
            }
        } else {
            $error++;
            $errorcode = 'PERMISSION_DENIED';
            $errorlabel = 'User does not have permission for this request';
        }
    }
    if ($error) {
        $objectresp = array('result' => array('result_code' => $errorcode, 'result_label' => $errorlabel));
    }
    //var_dump($objectresp);exit;
    return $objectresp;
}
 /**
  *	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 #21
0
				print '<td width="12%" align="center">'.$langs->trans("Stock").'</td>';
			}
			print "</tr>\n";
		}
		$var=true;
		while ($i < $num)
		{
			$product = new Product($db);

			$line = $commande->lines[$i];
			$var=!$var;
			print "<tr $bc[$var]>\n";
			if ($line->fk_product > 0)
			{
				$product->fetch($line->fk_product);
				$product->load_stock();

				print '<td>';
				print '<a href="'.DOL_URL_ROOT.'/product/fiche.php?id='.$line->fk_product.'">'.img_object($langs->trans("ShowProduct"),"product").' '.$product->ref.'</a> - '.$product->libelle;
				if ($line->description) print nl2br($line->description);
				print '</td>';
			}
			else
			{
				print "<td>".nl2br($line->description)."</td>\n";
			}

			print '<td align="center">'.$line->qty.'</td>';
			/*
			 *
			 */
 function createOfAndCommandesFourn(&$PDOdb)
 {
     global $db, $user;
     dol_include_once("fourn/class/fournisseur.commande.class.php");
     $TabOF = array();
     $TabOF[] = $this->rowid;
     $this->getListeOFEnfants($PDOdb, $TabOF);
     // Boucle pour chaque OF de l'arbre
     foreach ($TabOF as $idOf) {
         // On charge l'OF
         $assetOF = new TAssetOF();
         $assetOF->load($PDOdb, $idOf);
         // Boucle pour chaque produit de l'OF
         foreach ($assetOF->TAssetOFLine as $ofLigne) {
             //pre($ofLigne,true);
             // On cherche le produit "TO_MAKE"
             if ($ofLigne->type == "TO_MAKE") {
                 //pre($ofLigne,true); exit;
                 if ($ofLigne->fk_product_fournisseur_price > 0) {
                     // Fournisseur externe
                     // On récupère la ligne prix fournisseur correspondante
                     $sql = "SELECT rowid, fk_soc, fk_product, price, compose_fourni, quantity, ref_fourn";
                     $sql .= " FROM " . MAIN_DB_PREFIX . "product_fournisseur_price";
                     $sql .= " WHERE rowid = " . $ofLigne->fk_product_fournisseur_price;
                     $resql = $db->query($sql);
                     $res = $db->fetch_object($resql);
                     // Si fabrication interne
                     if ($res->compose_fourni) {
                         // On charge le produit "TO_MAKE"
                         $prod = new Product($db);
                         $prod->fetch($ofLigne->fk_product);
                         $prod->load_stock();
                         $stockProd = 0;
                         // On récupère son stock
                         foreach ($prod->stock_warehouse as $stock) {
                             $stockProd += $stock->real;
                         }
                         // S'il y a suffisemment de stock, on destocke
                         // Sinon, commande fournisseur :
                         if ($stockProd < $ofLigne->qty_needed) {
                             $this->addCommandeFourn($PDOdb, $ofLigne, $res);
                         } else {
                             // Suffisemment de stock, donc destockage :
                             $assetOF->openOF($PDOdb);
                         }
                     } elseif (!$res->compose_fourni) {
                         //Commande Fournisseur
                         $this->addCommandeFourn($PDOdb, $ofLigne, $res);
                         // On récupère les OF enfants pour les supprimer
                         $TabIdEnfantsDirects = $assetOF->getEnfantsDirects();
                         foreach ($TabIdEnfantsDirects as $idOF) {
                             $assetOF->removeChild("TAssetOF", $idOF);
                         }
                         //Suppression des lignes NEEDED puisque inutiles
                         $assetOF->delLineNeeded($PDOdb);
                         $assetOF->unsetChildDeleted = true;
                         $assetOF->save($PDOdb);
                         // On casse la boucle
                         break;
                     }
                 } else {
                     // Fournisseur interne (Bourguignon) [PH - 14/04/15 - FIXME c'est pas que pour bourguignon ?]
                     if ($ofLigne->fk_product_fournisseur_price == -1) {
                         // Sortie de stock, kill OF enfants
                         $TabIdEnfantsDirects = $assetOF->getEnfantsDirects();
                         foreach ($TabIdEnfantsDirects as $idOF) {
                             $assetOF->removeChild("TAssetOF", $idOF);
                         }
                         $assetOF->save($PDOdb);
                         // On casse la boucle
                         break;
                     } elseif ($ofLigne->fk_product_fournisseur_price == -2) {
                         // Fabrication interne
                         //[PH] FIXME - pourquoi on destock maintenant ? On valide tt juste l'OF
                         $prod = new Product($db);
                         $prod->fetch($ofLigne->fk_product);
                         $prod->load_stock();
                         $stockProd = 0;
                         // On récupère son stock
                         foreach ($prod->stock_warehouse as $stock) {
                             $stockProd += $stock->real;
                         }
                         // S'il y a sufisemment de stock, on destocke
                         if ($stockProd >= $ofLigne->qty_needed) {
                             //$assetOF->openOF($PDOdb);
                             $assetOF->status = 'VALID';
                         }
                     }
                 }
             }
         }
     }
 }