diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php
index 95ddde4719f3739060f40711feff45046263ce31..55f259aa2fe1c5462a73879aef525daf8b19bc39 100644
--- a/htdocs/compta/facture.php
+++ b/htdocs/compta/facture.php
@@ -126,8 +126,8 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e
 if (empty($reshook))
 {
     if ($cancel) $action='';
-    
-	include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once
+
+	include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once
 
 	include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php';		// Must be include, not include_once
 
@@ -672,7 +672,7 @@ if (empty($reshook))
 
 	/*
 	 * Insert new invoice in database
-	*/
+	 */
 	else if ($action == 'add' && $user->rights->facture->creer)
 	{
 		if ($socid > 0) $object->socid = GETPOST('socid', 'int');
@@ -722,7 +722,7 @@ if (empty($reshook))
 				$object->location_incoterms = GETPOST('location_incoterms', 'alpha');
 				$object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
 				$object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int');
-				
+
 				// Proprietes particulieres a facture de remplacement
 				$object->fk_facture_source = $_POST['fac_replacement'];
 				$object->type = Facture::TYPE_REPLACEMENT;
@@ -868,6 +868,15 @@ if (empty($reshook))
 				$object->ref_client     = $_POST['ref_client'];
 				$object->ref_int     	= $_POST['ref_int'];
 				$object->modelpdf       = $_POST['model'];
+				$object->fk_project		= $_POST['projectid'];
+				$object->cond_reglement_id	= ($_POST['type'] == 3?1:$_POST['cond_reglement_id']);
+				$object->mode_reglement_id	= $_POST['mode_reglement_id'];
+	            $object->fk_account         = GETPOST('fk_account', 'int');
+				$object->amount				= $_POST['amount'];
+				$object->remise_absolue		= $_POST['remise_absolue'];
+				$object->remise_percent		= $_POST['remise_percent'];
+				$object->fk_incoterms 		= GETPOST('incoterm_id', 'int');
+				$object->location_incoterms = GETPOST('location_incoterms', 'alpha');
 				$object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
 				$object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int');
 				
diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php
index 8e4e05037a8cc9e7eb9611237f3edcb92e05c573..0acd58f0202dc21fda28ab57d65ee555e204eee6 100644
--- a/htdocs/compta/facture/class/facture-rec.class.php
+++ b/htdocs/compta/facture/class/facture-rec.class.php
@@ -348,7 +348,7 @@ class FactureRec extends CommonInvoice
  	 */
 	function fetch_lines()
 	{
-		$sql = 'SELECT l.rowid, l.fk_product, l.product_type, l.label as custom_label, l.description, l.price, l.qty, l.tva_tx, ';
+		$sql = 'SELECT l.rowid, l.fk_product, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.tva_tx, ';
 		$sql.= ' l.remise, l.remise_percent, l.subprice,';
 		$sql.= ' l.total_ht, l.total_tva, l.total_ttc,';
 		$sql.= ' l.rang, l.special_code,';
@@ -358,7 +358,7 @@ class FactureRec extends CommonInvoice
 		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid';
 		$sql.= ' WHERE l.fk_facture = '.$this->id;
 
-		dol_syslog('Facture::fetch_lines', LOG_DEBUG);
+		dol_syslog('FactureRec::fetch_lines', LOG_DEBUG);
 		$result = $this->db->query($sql);
 		if ($result)
 		{
@@ -369,10 +369,13 @@ class FactureRec extends CommonInvoice
 				$objp = $this->db->fetch_object($result);
 				$line = new FactureLigne($this->db);
 
+				$line->id	            = $objp->rowid;
 				$line->rowid	        = $objp->rowid;
 				$line->label            = $objp->custom_label;		// Label line
 				$line->desc             = $objp->description;		// Description line
+				$line->description      = $objp->description;		// Description line
 				$line->product_type     = $objp->product_type;		// Type of line
+				$line->ref              = $objp->product_ref;		// Ref product
 				$line->product_ref      = $objp->product_ref;		// Ref product
 				$line->libelle          = $objp->product_label;		// deprecated
 				$line->product_label	= $objp->product_label;		// Label product
@@ -904,3 +907,52 @@ class FactureRec extends CommonInvoice
         }
     }
 }
+
+
+
+/**
+ *	Class to manage invoice lines of templates.
+ *  Saved into database table llx_facturedet_rec
+ */
+class FactureLigneRec extends CommonInvoiceLine
+{
+    
+    /**
+     * 	Delete line in database
+     *
+     *	@return		int		<0 if KO, >0 if OK
+     */
+    function delete()
+    {
+        global $conf,$langs,$user;
+    
+        $error=0;
+    
+        $this->db->begin();
+    
+        // Call trigger
+        /*$result=$this->call_trigger('LINEBILLREC_DELETE',$user);
+        if ($result < 0)
+        {
+            $this->db->rollback();
+            return -1;
+        }*/
+        // End call triggers
+    
+    
+        $sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet_rec WHERE rowid = ".($this->rowid > 0 ? $this->rowid : $this->id);
+        dol_syslog(get_class($this)."::delete", LOG_DEBUG);
+        if ($this->db->query($sql) )
+        {
+            $this->db->commit();
+            return 1;
+        }
+        else
+        {
+            $this->error=$this->db->error()." sql=".$sql;
+            $this->db->rollback();
+            return -1;
+        }
+    }
+    
+}
\ No newline at end of file
diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php
index b7531719646f9f59291194da303c586ef47cabc4..4dbf4b9020a89d953eb26474b453497825cb0cf5 100644
--- a/htdocs/compta/facture/class/facture.class.php
+++ b/htdocs/compta/facture/class/facture.class.php
@@ -280,7 +280,7 @@ class Facture extends CommonInvoice
 
 			$this->socid 		     = $_facrec->socid;
 			
-			$this->fk_project        = $_facrec->fk_project;
+			$this->fk_project        = GETPOST('projectid','int') > 0 ? GETPOST('projectid','int') : $_facrec->fk_project;
 			$this->fk_account        = $_facrec->fk_account;
 			$this->cond_reglement_id = $_facrec->cond_reglement_id;
 			$this->mode_reglement_id = $_facrec->mode_reglement_id;
diff --git a/htdocs/compta/facture/fiche-rec.php b/htdocs/compta/facture/fiche-rec.php
index 7f4c5282098125f3d18274bc1bfecb7a09779230..ad9626718c643e75787ae85d61ed3dfcdf05d02e 100644
--- a/htdocs/compta/facture/fiche-rec.php
+++ b/htdocs/compta/facture/fiche-rec.php
@@ -32,18 +32,23 @@ require '../../main.inc.php';
 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
 
 $langs->load('bills');
 $langs->load('compta');
 
 // Security check
 $id=(GETPOST('facid','int')?GETPOST('facid','int'):GETPOST('id','int'));
+$confirm = GETPOST('confirm', 'alpha');
+$cancel = GETPOST('cancel', 'alpha');
+$lineid=GETPOST('lineid','int');
 $ref=GETPOST('ref','alpha');
 $action=GETPOST('action', 'alpha');
 if ($user->societe_id) $socid=$user->societe_id;
 $objecttype = 'facture_rec';
 if ($action == "create" || $action == "add") $objecttype = '';
 $result = restrictedArea($user, 'facture', $id, $objecttype);
+$projectid = GETPOST('projectid','int');
 
 if ($page == -1)
 {
@@ -68,10 +73,16 @@ if (($id > 0 || $ref) && $action != 'create' && $action != 'add')
 	}
 }
 
+
 /*
  * Actions
  */
 
+// Set note
+$permissionnote=$user->rights->facture->creer;	// Used by the include of actions_setnotes.inc.php
+include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php';	// Must be include, not include_once
+
+include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php';	// Must be include, not include_once
 
 // Create predefined invoice
 if ($action == 'add')
@@ -119,6 +130,8 @@ if ($action == 'add')
 		$object->nb_gen_max = $nb_gen_max;
 		$object->auto_validate = GETPOST('auto_validate', 'int');
 		
+		$object->fk_project = $projectid;
+		
 		$date_next_execution = dol_mktime($rehour, $remin, 0, $remonth, $reday, $reyear);
 		$object->date_when = $date_next_execution;
 
@@ -233,9 +246,329 @@ elseif ($action == 'setauto_validate' && $user->rights->facture->creer)
 {
 	$object->setAutoValidate(GETPOST('auto_validate', 'int'));
 }
-// Set note
-$permissionnote=$user->rights->facture->creer;	// Used by the include of actions_setnotes.inc.php
-include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php';	// Must be include, not includ_once
+
+// Delete line
+if ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights->facture->creer)
+{
+    $object->fetch($id);
+    $object->fetch_thirdparty();
+
+    $db->begin();
+    
+    $line=new FactureLigneRec($db);
+    
+    // For triggers
+    $line->id = $lineid;
+    
+    if ($line->delete() > 0)
+    {
+        $result=$object->update_price(1);
+    
+        if ($result > 0)
+        {
+            $db->commit();
+            $object->fetch($object->id);    // Reload lines
+        }
+        else
+        {
+            $db->rollback();
+            setEventMessages($db->lasterror(), null, 'errors');
+        }
+    }
+    else
+    {
+        $db->rollback();
+        setEventMessages($line->error, $line->errors, 'errors');
+    }
+}
+
+// Add a new line
+if ($action == 'addline' && $user->rights->facture->creer)
+{
+    $langs->load('errors');
+    $error = 0;
+
+    // Set if we used free entry or predefined product
+    $predef='';
+    $product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):'');
+    $price_ht = GETPOST('price_ht');
+    if (GETPOST('prod_entry_mode') == 'free')
+    {
+        $idprod=0;
+        $tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
+    }
+    else
+    {
+        $idprod=GETPOST('idprod', 'int');
+        $tva_tx = '';
+    }
+
+    $qty = GETPOST('qty' . $predef);
+    $remise_percent = GETPOST('remise_percent' . $predef);
+
+    // Extrafields
+    $extrafieldsline = new ExtraFields($db);
+    $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line);
+    $array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline, $predef);
+    // Unset extrafield
+    if (is_array($extralabelsline)) {
+        // Get extra fields
+        foreach ($extralabelsline as $key => $value) {
+            unset($_POST["options_" . $key . $predef]);
+        }
+    }
+
+    if (empty($idprod) && ($price_ht < 0) && ($qty < 0)) {
+        setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
+        $error ++;
+    }
+    if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && GETPOST('type') < 0) {
+        setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
+        $error ++;
+    }
+    if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '')) 	// Unit price can be 0 but not ''
+    {
+        setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
+        $error ++;
+    }
+    if ($qty == '') {
+        setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
+        $error ++;
+    }
+    if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && empty($product_desc)) {
+        setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
+        $error ++;
+    }
+    if ($qty < 0) {
+        $langs->load("errors");
+        setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
+        $error ++;
+    }
+    
+    if (! $error && ($qty >= 0) && (! empty($product_desc) || ! empty($idprod))) {
+        $ret = $object->fetch($id);
+        if ($ret < 0) {
+            dol_print_error($db, $object->error);
+            exit();
+        }
+        $ret = $object->fetch_thirdparty();
+
+        // Clean parameters
+        $date_start = dol_mktime(GETPOST('date_start' . $predef . 'hour'), GETPOST('date_start' . $predef . 'min'), GETPOST('date_start' . $predef . 'sec'), GETPOST('date_start' . $predef . 'month'), GETPOST('date_start' . $predef . 'day'), GETPOST('date_start' . $predef . 'year'));
+        $date_end = dol_mktime(GETPOST('date_end' . $predef . 'hour'), GETPOST('date_end' . $predef . 'min'), GETPOST('date_end' . $predef . 'sec'), GETPOST('date_end' . $predef . 'month'), GETPOST('date_end' . $predef . 'day'), GETPOST('date_end' . $predef . 'year'));
+        $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
+
+        // Define special_code for special lines
+        $special_code = 0;
+        // if (empty($_POST['qty'])) $special_code=3; // Options should not exists on invoices
+
+        // Ecrase $pu par celui du produit
+        // Ecrase $desc par celui du produit
+        // Ecrase $txtva par celui du produit
+        // Ecrase $base_price_type par celui du produit
+        // Replaces $fk_unit with the product's
+        if (! empty($idprod))
+        {
+            $prod = new Product($db);
+            $prod->fetch($idprod);
+
+            $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
+
+            // Update if prices fields are defined
+            $tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
+            $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
+            if (empty($tva_tx)) $tva_npr=0;
+            	
+            $pu_ht = $prod->price;
+            $pu_ttc = $prod->price_ttc;
+            $price_min = $prod->price_min;
+            $price_base_type = $prod->price_base_type;
+
+            // We define price for product
+            if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->thirdparty->price_level))
+            {
+                $pu_ht = $prod->multiprices[$object->thirdparty->price_level];
+                $pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
+                $price_min = $prod->multiprices_min[$object->thirdparty->price_level];
+                $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
+                if (! empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL))  // using this option is a bug. kept for backward compatibility
+                {
+                    if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) $tva_tx=$prod->multiprices_tva_tx[$object->thirdparty->price_level];
+                    if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) $tva_npr=$prod->multiprices_recuperableonly[$object->thirdparty->price_level];
+                    if (empty($tva_tx)) $tva_npr=0;
+                }
+            }
+            elseif (! empty($conf->global->PRODUIT_CUSTOMER_PRICES))
+            {
+                require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
+
+                $prodcustprice = new Productcustomerprice($db);
+
+                $filter = array('t.fk_product' => $prod->id,'t.fk_soc' => $object->thirdparty->id);
+
+                $result = $prodcustprice->fetch_all('', '', 0, 0, $filter);
+                if ($result) {
+                    if (count($prodcustprice->lines) > 0) {
+                        $pu_ht = price($prodcustprice->lines[0]->price);
+                        $pu_ttc = price($prodcustprice->lines[0]->price_ttc);
+                        $price_base_type = $prodcustprice->lines[0]->price_base_type;
+                        $prod->tva_tx = $prodcustprice->lines[0]->tva_tx;
+                    }
+                }
+            }
+
+            // if price ht was forced (ie: from gui when calculated by margin rate and cost price)
+            if (! empty($price_ht))
+            {
+                $pu_ht = price2num($price_ht, 'MU');
+                $pu_ttc = price2num($pu_ht * (1 + ($tva_tx / 100)), 'MU');
+            }
+            // On reevalue prix selon taux tva car taux tva transaction peut etre different
+            // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur).
+            elseif ($tva_tx != $prod->tva_tx)
+            {
+                if ($price_base_type != 'HT')
+                {
+                    $pu_ht = price2num($pu_ttc / (1 + ($tva_tx / 100)), 'MU');
+                }
+                else
+                {
+                    $pu_ttc = price2num($pu_ht * (1 + ($tva_tx / 100)), 'MU');
+                }
+            }
+
+            $desc = '';
+
+            // Define output language
+            if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
+                $outputlangs = $langs;
+                $newlang = '';
+                if (empty($newlang) && GETPOST('lang_id'))
+                    $newlang = GETPOST('lang_id');
+                    if (empty($newlang))
+                        $newlang = $object->thirdparty->default_lang;
+                        if (! empty($newlang)) {
+                            $outputlangs = new Translate("", $conf);
+                            $outputlangs->setDefaultLang($newlang);
+                        }
+
+                        $desc = (! empty($prod->multilangs [$outputlangs->defaultlang] ["description"])) ? $prod->multilangs [$outputlangs->defaultlang] ["description"] : $prod->description;
+            } else {
+                $desc = $prod->description;
+            }
+
+            $desc = dol_concatdesc($desc, $product_desc);
+
+            // Add custom code and origin country into description
+            if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (! empty($prod->customcode) || ! empty($prod->country_code))) {
+                $tmptxt = '(';
+                if (! empty($prod->customcode))
+                    $tmptxt .= $langs->transnoentitiesnoconv("CustomCode") . ': ' . $prod->customcode;
+                    if (! empty($prod->customcode) && ! empty($prod->country_code))
+                        $tmptxt .= ' - ';
+                        if (! empty($prod->country_code))
+                            $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin") . ': ' . getCountry($prod->country_code, 0, $db, $langs, 0);
+                            $tmptxt .= ')';
+                            $desc = dol_concatdesc($desc, $tmptxt);
+            }
+
+            $type = $prod->type;
+            $fk_unit = $prod->fk_unit;
+        } else {
+            $pu_ht = price2num($price_ht, 'MU');
+            $pu_ttc = price2num(GETPOST('price_ttc'), 'MU');
+            $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
+            $tva_tx = str_replace('*', '', $tva_tx);
+            if (empty($tva_tx)) $tva_npr=0;
+            $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
+            $desc = $product_desc;
+            $type = GETPOST('type');
+            $fk_unit= GETPOST('units', 'alpha');
+        }
+        
+        // Margin
+        $fournprice = price2num(GETPOST('fournprice' . $predef) ? GETPOST('fournprice' . $predef) : '');
+        $buyingprice = price2num(GETPOST('buying_price' . $predef) != '' ? GETPOST('buying_price' . $predef) : '');    // If buying_price is '0', we must keep this value
+
+        // Local Taxes
+        $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
+        $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
+        	
+        $info_bits = 0;
+        if ($tva_npr)
+            $info_bits |= 0x01;
+
+        if (! empty($price_min) && (price2num($pu_ht) * (1 - price2num($remise_percent) / 100) < price2num($price_min))) {
+            $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $conf->currency));
+            setEventMessages($mesg, null, 'errors');
+        } else {
+            // Insert line
+            $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $idprod, $remise_percent, $price_base_type, $info_bits, '', $pu_ttc, $type, - 1, $special_code, $label, $fk_unit);
+
+            if ($result > 0)
+            {
+                // Define output language
+                /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
+                {
+                    $outputlangs = $langs;
+                    $newlang = '';
+                    if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang = GETPOST('lang_id','alpha');
+                    if ($conf->global->MAIN_MULTILANGS && empty($newlang))	$newlang = $object->thirdparty->default_lang;
+                    if (! empty($newlang)) {
+                        $outputlangs = new Translate("", $conf);
+                        $outputlangs->setDefaultLang($newlang);
+                    }
+                    $model=$object->modelpdf;
+                    $ret = $object->fetch($id); // Reload to get new records
+
+                    $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
+                    if ($result < 0) setEventMessages($object->error, $object->errors, 'errors');
+                }*/
+                $object->fetch($object->id);    // Reload lines
+                
+                unset($_POST['prod_entry_mode']);
+
+                unset($_POST['qty']);
+                unset($_POST['type']);
+                unset($_POST['remise_percent']);
+                unset($_POST['price_ht']);
+                unset($_POST['multicurrency_price_ht']);
+                unset($_POST['price_ttc']);
+                unset($_POST['tva_tx']);
+                unset($_POST['product_ref']);
+                unset($_POST['product_label']);
+                unset($_POST['product_desc']);
+                unset($_POST['fournprice']);
+                unset($_POST['buying_price']);
+                unset($_POST['np_marginRate']);
+                unset($_POST['np_markRate']);
+                unset($_POST['dp_desc']);
+                unset($_POST['idprod']);
+                unset($_POST['units']);
+
+                unset($_POST['date_starthour']);
+                unset($_POST['date_startmin']);
+                unset($_POST['date_startsec']);
+                unset($_POST['date_startday']);
+                unset($_POST['date_startmonth']);
+                unset($_POST['date_startyear']);
+                unset($_POST['date_endhour']);
+                unset($_POST['date_endmin']);
+                unset($_POST['date_endsec']);
+                unset($_POST['date_endday']);
+                unset($_POST['date_endmonth']);
+                unset($_POST['date_endyear']);
+
+                unset($_POST['situations']);
+                unset($_POST['progress']);
+            } else {
+                setEventMessages($object->error, $object->errors, 'errors');
+            }
+
+            $action = '';
+        }
+    }
+}
 
 
 
@@ -262,7 +595,8 @@ if ($action == 'create')
 
 	$object = new Facture($db);   // Source invoice
 	$product_static = new Product($db);
-
+	$formproject = new FormProjets($db);
+	
 	if ($object->fetch($id, $ref) > 0)
 	{
 		print '<form action="fiche-rec.php" method="post">';
@@ -281,14 +615,14 @@ if ($action == 'create')
 		$object->fetch_thirdparty();
 
 		// Third party
-		print '<tr><td>'.$langs->trans("Customer").'</td><td>'.$object->thirdparty->getNomUrl(1,'customer').'</td>';
+		print '<tr><td class="titlefieldcreate">'.$langs->trans("Customer").'</td><td>'.$object->thirdparty->getNomUrl(1,'customer').'</td>';
 		print '<td>';
 		print $langs->trans("Comment");
 		print '</td></tr>';
 
 		// Title
 		print '<tr><td class="fieldrequired">'.$langs->trans("Title").'</td><td>';
-		print '<input class="flat" type="text" name="titre" size="24" value="'.$_POST["titre"].'">';
+		print '<input class="flat quatrevingtpercent" type="text" name="titre" value="'.$_POST["titre"].'">';
 		print '</td>';
 
 		// Note
@@ -310,18 +644,16 @@ if ($action == 'create')
 		print "</td></tr>";
 
 		// Project
-		if (! empty($conf->projet->enabled))
-		{
-			print "<tr><td>".$langs->trans("Project")."</td><td>";
-			if ($object->fk_project > 0)
-			{
-				$project = new Project($db);
-				$project->fetch($object->fk_project);
-				print $project->getNomUrl(1);
-			}
-			print "</td></tr>";
-		}
-
+    	if (! empty($conf->projet->enabled) && is_object($object->thirdparty) && $object->thirdparty->id > 0)
+    	{
+    	    $projectid = $object->fk_project;
+    		$langs->load('projects');
+    		print '<tr><td>' . $langs->trans('Project') . '</td><td colspan="2">';
+    		$numprojet = $formproject->select_projects($socid, $projectid, 'projectid', 0);
+    		print ' &nbsp; <a href="'.DOL_URL_ROOT.'/projet/card.php?socid=' . $soc->id . '&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$soc->id).'">' . $langs->trans("AddProject") . '</a>';
+    		print '</td></tr>';
+    	}
+    	
 		// Bank account
 		if ($object->fk_account > 0)
 		{
@@ -342,7 +674,7 @@ if ($action == 'create')
 		print '<table class="border" width="100%">';
 		
 		// Frequency
-		print "<tr><td>".$form->textwithpicto($langs->trans("Frequency"), $langs->transnoentitiesnoconv('toolTipFrequency'))."</td><td>";
+		print '<tr><td class="titlefieldcreate">'.$form->textwithpicto($langs->trans("Frequency"), $langs->transnoentitiesnoconv('toolTipFrequency'))."</td><td>";
 		print "<input type='text' name='frequency' value='".GETPOST('frequency', 'int')."' size='5' />&nbsp;".$form->selectarray('unit_frequency', array('d'=>$langs->trans('Day'), 'm'=>$langs->trans('Month'), 'y'=>$langs->trans('Year')), (GETPOST('unit_frequency')?GETPOST('unit_frequency'):'m'));
 		print "</td></tr>";
 		
@@ -375,6 +707,7 @@ if ($action == 'create')
 
 		print load_fiche_titre($title, '', '');
 
+		
 		/*
 		 * Invoice lines
 		 */
@@ -580,9 +913,16 @@ else
 	{
 		$object->fetch_thirdparty();
 
+		// Confirmation de la suppression d'une ligne produit
+    	if ($action == 'ask_deleteline') {
+    		$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1);
+    	}
+    
+    	print $formconfirm;
+    	
 		$author = new User($db);
 		$author->fetch($object->user_author);
-
+		
 		$head=array();
 		$h=0;
 		$head[$h][0] = $_SERVER["PHP_SELF"].'?id='.$object->id;
@@ -851,96 +1191,45 @@ else
     		print '<br>';
 		}		
 		
-		/*
-		 * Lines
-		 */
-
-		print '<table class="noborder noshadow" width="100%">';
-		print '<tr class="liste_titre">';
-		print '<td>'.$langs->trans("Description").'</td>';
-		print '<td align="right">'.$langs->trans("VAT").'</td>';
-		print '<td align="right">'.$langs->trans("PriceUHT").'</td>';
-		print '<td align="center">'.$langs->trans("Qty").'</td>';
-		print '<td align="center">'.$langs->trans("ReductionShort").'</td>';
-		if ($conf->global->PRODUCT_USE_UNITS) {
-			print '<td align="left">'.$langs->trans("Unit").'</td>';
+		// Lines
+		print '	<form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '#add' : '#line_' . GETPOST('lineid')) . '" method="POST">
+        	<input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '">
+        	<input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateligne') . '">
+        	<input type="hidden" name="mode" value="">
+        	<input type="hidden" name="id" value="' . $object->id . '">
+        	';
+		
+		if (! empty($conf->use_javascript_ajax) && $object->statut == 0) {
+		    include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
 		}
-		print '</tr>';
-
-		$num = count($object->lines);
-		$i = 0;
-		$var=true;
-		while ($i < $num)
+		
+		print '<table id="tablelines" class="noborder noshadow" width="100%">';
+		// Show object lines
+		if (! empty($object->lines))
 		{
-			$var=!$var;
-
-			$product_static=new Product($db);
-
-			// Show product and description
-			$type=(isset($object->lines[$i]->product_type)?$object->lines[$i]->product_type:$object->lines[$i]->fk_product_type);
-			// Try to enhance type detection using date_start and date_end for free lines when type
-			// was not saved.
-			if (! empty($objp->date_start)) $type=1;
-			if (! empty($objp->date_end)) $type=1;
-
-			// Show line
-			print "<tr ".$bc[$var].">";
-			if ($object->lines[$i]->fk_product > 0)
-			{
-				print '<td>';
-				print '<a name="'.$object->lines[$i]->id.'"></a>'; // ancre pour retourner sur la ligne
-
-				// Show product and description
-				$product_static->type=$object->lines[$i]->fk_product_type;
-				$product_static->id=$object->lines[$i]->fk_product;
-				$product_static->ref=$object->lines[$i]->product_ref;
-				$text=$product_static->getNomUrl(1);
-				$text.= ' - '.(! empty($object->lines[$i]->label)?$object->lines[$i]->label:$object->lines[$i]->product_label);
-				$description=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($object->lines[$i]->desc));
-				print $form->textwithtooltip($text,$description,3,'','',$i);
-
-				// Show range
-				print_date_range($object->lines[$i]->date_start, $object->lines[$i]->date_end);
-
-				// Add description in form
-				if (! empty($conf->global->PRODUIT_DESC_IN_FORM))
-					print (! empty($object->lines[$i]->desc) && $object->lines[$i]->desc!=$fac->lines[$i]->product_label)?'<br>'.dol_htmlentitiesbr($object->lines[$i]->desc):'';
-
-				print '</td>';
-			}
-			else
-			{
-				print '<td>';
-
-				if ($type==1) $text = img_object($langs->trans('Service'),'service');
-				else $text = img_object($langs->trans('Product'),'product');
-
-				if (! empty($object->lines[$i]->label)) {
-
-					$text.= ' <strong>'.$object->lines[$i]->label.'</strong>';
-					print $form->textwithtooltip($text,dol_htmlentitiesbr($object->lines[$i]->desc),3,'','',$i);
-
-				} else {
-
-					print $text.' '.nl2br($object->lines[$i]->desc);
-				}
-
-				// Show range
-				print_date_range($object->lines[$i]->date_start, $object->lines[$i]->date_end);
-
-				print '</td>';
-			}
-			print '<td align="right">'.vatrate($object->lines[$i]->tva_tx, 1).'</td>';
-			print '<td align="right">'.price($object->lines[$i]->price).'</td>';
-			print '<td align="center">'.$object->lines[$i]->qty.'</td>';
-			print '<td align="center">'.$object->lines[$i]->remise_percent.' %</td>';
-			if ($conf->global->PRODUCT_USE_UNITS) {
-				print "<td align=\"left\">".$object->lines[$i]->getLabelOfUnit()."</td>";
-			}
-			print "</tr>\n";
-			$i++;
+		    $disableedit=1;
+		    $disablemove=1;
+		    $ret = $object->printObjectLines($action, $mysoc, $soc, $lineid, 0);      // No date selector for template invoice
 		}
-		print '</table>';
+		
+		// Form to add new line
+		if ($object->statut == 0 && $user->rights->facture->creer && $action != 'valid' && $action != 'editline')
+		{
+		    if ($action != 'editline')
+		    {
+    		    $var = true;
+    		
+    		    // Add free products/services
+    		    $object->formAddObjectLine(0, $mysoc, $soc);                          // No date selector for template invoice  
+    		
+    		    $parameters = array();
+    		    $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+		    }
+		}
+		
+		print "</table>\n";
+		
+		print "</form>\n";
 
 		dol_fiche_end();
 		
diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php
index 33c70d57ae6c30c923aac29d2c384f640799f39d..ec02fce3daeb99b52cbe9b12597f4edd69f634ee 100644
--- a/htdocs/core/class/commonobject.class.php
+++ b/htdocs/core/class/commonobject.class.php
@@ -3236,7 +3236,7 @@ abstract class CommonObject
 	 */
 	function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0)
 	{
-		global $conf, $hookmanager, $inputalsopricewithtax, $usemargins, $langs, $user;
+		global $conf, $hookmanager, $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $langs, $user;
 
 		// Define usemargins
 		$usemargins=0;
@@ -3365,7 +3365,8 @@ abstract class CommonObject
 	function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0)
 	{
 		global $conf,$langs,$user,$object,$hookmanager;
-		global $form,$bc,$bcdd, $object_rights;
+		global $form,$bc,$bcdd;
+		global $object_rights, $disableedit, $disablemove;   // TODO We should not use global var for this !
 
 		$object_rights = $this->getRights();
 
@@ -4458,7 +4459,10 @@ abstract class CommonObject
 	{
 		global $user;
 
-		return $user->rights->{$this->element};
+		$element = $this->element;
+		if ($element == 'facturerec') $element='facture';
+
+		return $user->rights->{$element};
 	}
 
 	/**
diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php
index 77b58bd83cdb3bcf6b6816af6c650195f0dcb922..f89184cedc1d7119a4204b59cf82ad55c023060b 100644
--- a/htdocs/core/tpl/objectline_create.tpl.php
+++ b/htdocs/core/tpl/objectline_create.tpl.php
@@ -46,7 +46,7 @@ if (empty($inputalsopricewithtax)) $inputalsopricewithtax=0;
 
 // Define colspan for button Add
 $colspan = 3;	// Col total ht + col edit + col delete
-if (in_array($object->element,array('propal', 'supplier_proposal','facture','invoice','commande','order','order_supplier','invoice_supplier'))) $colspan++;	// With this, there is a column move button
+if (in_array($object->element,array('propal', 'supplier_proposal','facture','facturerec','invoice','commande','order','order_supplier','invoice_supplier'))) $colspan++;	// With this, there is a column move button
 //print $object->element;
 ?>
 
@@ -360,6 +360,7 @@ if ((! empty($conf->service->enabled) || ($object->element == 'contrat')) && $da
 			'propal',
 			'supplier_proposal',
 			'facture',
+		    'facturerec',
 			'invoice',
 			'commande',
 			'order',
diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php
index c264bac205d49718933441ba371c517aee9d8e6f..967d9f8197010cb5acf085599bb45bb0c5656269 100644
--- a/htdocs/core/tpl/objectline_view.tpl.php
+++ b/htdocs/core/tpl/objectline_view.tpl.php
@@ -30,7 +30,9 @@
  * $senderissupplier (0 by default, 1 for supplier invoices/orders)
  * $inputalsopricewithtax (0 by default, 1 to also show column with unit price including tax)
  * $usemargins (0 to disable all margins columns, 1 to show according to margin setup)
- *
+ * $object_rights->creer initialized from = $object->getRights()
+ * $disableedit, $disablemove
+ * 
  * $type, $text, $description, $line
  */
 
@@ -201,9 +203,10 @@ if (empty($usemargins)) $usemargins=0;
 		<?php } ?>
 	<?php } ?>
 
-	<?php if ($this->statut == 0  && ($object_rights->creer)) { ?>
+	<?php 
+	if ($this->statut == 0  && ($object_rights->creer)) { ?>
 	<td class="linecoledit" align="center"><?php $coldisplay++; ?>
-		<?php if (($line->info_bits & 2) == 2) { ?>
+		<?php if (($line->info_bits & 2) == 2 || ! empty($disableedit)) { ?>
 		<?php } else { ?>
 		<a href="<?php echo $_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=editline&amp;lineid='.$line->id.'#line_'.$line->id; ?>">
 		<?php echo img_edit(); ?>
@@ -221,7 +224,8 @@ if (empty($usemargins)) $usemargins=0;
 		?>
 	</td>
 
-	<?php if ($num > 1 && empty($conf->browser->phone) && ($this->situation_counter == 1 || !$this->situation_cycle_ref)) { ?>
+	<?php 
+	if ($num > 1 && empty($conf->browser->phone) && ($this->situation_counter == 1 || !$this->situation_cycle_ref) && empty($disablemove)) { ?>
 	<td align="center" class="linecolmove tdlineupdown"><?php $coldisplay++; ?>
 		<?php if ($i > 0) { ?>
 		<a class="lineupdown" href="<?php echo $_SERVER["PHP_SELF"].'?id='.$this->id.'&amp;action=up&amp;rowid='.$line->id; ?>">
@@ -235,7 +239,7 @@ if (empty($usemargins)) $usemargins=0;
 		<?php } ?>
 	</td>
     <?php } else { ?>
-    <td align="center"<?php echo (empty($conf->browser->phone)?' class="linecolmove tdlineupdown"':' class="linecolmove"'); ?>><?php $coldisplay++; ?></td>
+    <td align="center"<?php echo ((empty($conf->browser->phone) && empty($disablemove)) ?' class="linecolmove tdlineupdown"':' class="linecolmove"'); ?>><?php $coldisplay++; ?></td>
 	<?php } ?>
 <?php } else { ?>
 	<td colspan="3"><?php $coldisplay=$coldisplay+3; ?></td>