From 2c97d0855a49a2ae9c189dc4d584e33b3c061f7e Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Tue, 28 Jun 2016 17:51:29 +0200
Subject: [PATCH] Fix: On template invoice, edition of line was not complete.

---
 .../facture/class/facture-rec.class.php       | 107 ++++++++++-
 htdocs/compta/facture/fiche-rec.php           | 166 +++++++++++++++++-
 2 files changed, 269 insertions(+), 4 deletions(-)

diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php
index 1cf7bbf1c6e..357835fbb77 100644
--- a/htdocs/compta/facture/class/facture-rec.class.php
+++ b/htdocs/compta/facture/class/facture-rec.class.php
@@ -509,7 +509,7 @@ class FactureRec extends CommonInvoice
 	    
 		$facid=$this->id;
 
-		dol_syslog("FactureRec::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,fk_product=$fk_product,remise_percent=$remise_percent,date_start=$date_start,date_end=$date_end,ventil=$ventil,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit", LOG_DEBUG);
+		dol_syslog(get_class($this)."::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,fk_product=$fk_product,remise_percent=$remise_percent,date_start=$date_start,date_end=$date_end,ventil=$ventil,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit", LOG_DEBUG);
 		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
 
 		// Check parameters
@@ -604,6 +604,111 @@ class FactureRec extends CommonInvoice
 		}
 	}
 
+	/**
+	 * 	Update a line to invoice
+	 *
+	 *  @param     	int			$rowid           	Id of line to update
+	 *	@param    	string		$desc            	Description de la ligne
+	 *	@param    	double		$pu_ht              Prix unitaire HT (> 0 even for credit note)
+	 *	@param    	double		$qty             	Quantite
+	 *	@param    	double		$txtva           	Taux de tva force, sinon -1
+	 *	@param    	int			$fk_product      	Id du produit/service predefini
+	 *	@param    	double		$remise_percent  	Pourcentage de remise de la ligne
+	 *	@param		string		$price_base_type	HT or TTC
+	 *	@param    	int			$info_bits			Bits de type de lignes
+	 *	@param    	int			$fk_remise_except	Id remise
+	 *	@param    	double		$pu_ttc             Prix unitaire TTC (> 0 even for credit note)
+	 *	@param		int			$type				Type of line (0=product, 1=service)
+	 *	@param      int			$rang               Position of line
+	 *	@param		int			$special_code		Special code
+	 *	@param		string		$label				Label of the line
+	 *	@param		string		$fk_unit			Unit
+	 *	@return    	int             				<0 if KO, Id of line if OK
+	 */
+	function updateline($rowid, $desc, $pu_ht, $qty, $txtva, $fk_product=0, $remise_percent=0, $price_base_type='HT', $info_bits=0, $fk_remise_except='', $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $label='', $fk_unit=null)
+	{
+	    global $mysoc;
+	     
+	    $facid=$this->id;
+	
+	    dol_syslog(get_class($this)."::updateline facid=".$facid." rowid=$rowid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,fk_product=$fk_product,remise_percent=$remise_percent,date_start=$date_start,date_end=$date_end,ventil=$ventil,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit", LOG_DEBUG);
+	    include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
+	
+	    // Check parameters
+	    if ($type < 0) return -1;
+	
+	    if ($this->brouillon)
+	    {
+	        // Clean parameters
+	        $remise_percent=price2num($remise_percent);
+	        $qty=price2num($qty);
+	        if (! $qty) $qty=1;
+	        if (! $info_bits) $info_bits=0;
+	        $pu_ht=price2num($pu_ht);
+	        $pu_ttc=price2num($pu_ttc);
+	        $txtva=price2num($txtva);
+	
+	        if ($price_base_type=='HT')
+	        {
+	            $pu=$pu_ht;
+	        }
+	        else
+	        {
+	            $pu=$pu_ttc;
+	        }
+	
+	        // Calcul du total TTC et de la TVA pour la ligne a partir de
+	        // qty, pu, remise_percent et txtva
+	        // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
+	        // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
+	        $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, 0, 0, 0, $price_base_type, $info_bits, $type, $mysoc);
+	        $total_ht  = $tabprice[0];
+	        $total_tva = $tabprice[1];
+	        $total_ttc = $tabprice[2];
+	        	
+	        $product_type=$type;
+	        if ($fk_product)
+	        {
+	            $product=new Product($this->db);
+	            $result=$product->fetch($fk_product);
+	            $product_type=$product->type;
+	        }
+	
+	        $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
+	        $sql.= "fk_facture = '".$facid."'";
+	        $sql.= ", label=".(! empty($label)?"'".$this->db->escape($label)."'":"null");
+	        $sql.= ", description='".$this->db->escape($desc)."'";
+	        $sql.= ", price=".price2num($pu_ht);
+	        $sql.= ", qty=".price2num($qty);
+	        $sql.= ", tva_tx=".price2num($txtva);
+	        $sql.= ", fk_product=".(! empty($fk_product)?"'".$fk_product."'":"null");
+	        $sql.= ", product_type=".$product_type;
+	        $sql.= ", remise_percent='".price2num($remise_percent)."'";
+	        $sql.= ", subprice='".price2num($pu_ht)."'";
+	        $sql.= ", total_ht='".price2num($total_ht)."'";
+	        $sql.= ", total_tva='".price2num($total_tva)."'";
+	        $sql.= ", total_ttc='".price2num($total_ttc)."'";
+	        $sql.= ", rang=".$rang;
+	        $sql.= ", special_code=".$special_code;
+	        $sql.= ", fk_unit=".($fk_unit?"'".$this->db->escape($fk_unit)."'":"null");
+	        $sql.= " WHERE rowid = ".$rowid;
+	        
+	        dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
+	        if ($this->db->query($sql))
+	        {
+	            $this->id=$facid;
+	            $this->update_price();
+	            return 1;
+	        }
+	        else
+	        {
+	            $this->error=$this->db->lasterror();
+	            return -1;
+	        }
+	    }
+	}	
+	
+	
 	/**
 	 * Return the next date of 
 	 * 
diff --git a/htdocs/compta/facture/fiche-rec.php b/htdocs/compta/facture/fiche-rec.php
index 7b2d7076aca..198b08cb451 100644
--- a/htdocs/compta/facture/fiche-rec.php
+++ b/htdocs/compta/facture/fiche-rec.php
@@ -552,9 +552,9 @@ if ($action == 'addline' && $user->rights->facture->creer)
 
             if ($result > 0)
             {
-                // Define output language
                 /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
                 {
+                    // Define output language
                     $outputlangs = $langs;
                     $newlang = '';
                     if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang = GETPOST('lang_id','alpha');
@@ -615,8 +615,168 @@ if ($action == 'addline' && $user->rights->facture->creer)
     }
 }
 
+elseif ($action == 'updateligne' && $user->rights->facture->creer && ! GETPOST('cancel'))
+{
+    if (! $object->fetch($id) > 0)	dol_print_error($db);
+    $object->fetch_thirdparty();
+
+    // Clean parameters
+    $date_start = '';
+    $date_end = '';
+    //$date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear'));
+    //$date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear'));
+    $description = dol_htmlcleanlastbr(GETPOST('product_desc') ? GETPOST('product_desc') : GETPOST('desc'));
+    $pu_ht = GETPOST('price_ht');
+    $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
+    $qty = GETPOST('qty');
+
+    // Define info_bits
+    $info_bits = 0;
+    if (preg_match('/\*/', $vat_rate))
+        $info_bits |= 0x01;
+
+        // Define vat_rate
+        $vat_rate = str_replace('*', '', $vat_rate);
+        $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty);
+        $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty);
+
+        // Add buying price
+        $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
+        $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : '');       // If buying_price is '0', we muste keep this value
+
+        // Extrafields
+        $extrafieldsline = new ExtraFields($db);
+        $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line);
+        $array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline);
+        // Unset extrafield
+        if (is_array($extralabelsline)) {
+            // Get extra fields
+            foreach ($extralabelsline as $key => $value) {
+                unset($_POST["options_" . $key]);
+            }
+        }
+
+        // Define special_code for special lines
+        $special_code=GETPOST('special_code');
+        if (! GETPOST('qty')) $special_code=3;
+
+        /*$line = new FactureLigne($db);
+        $line->fetch(GETPOST('lineid'));
+        $percent = $line->get_prev_progress($object->id);
+
+        if (GETPOST('progress') < $percent)
+        {
+            $mesg = '<div class="warning">' . $langs->trans("CantBeLessThanMinPercent") . '</div>';
+            setEventMessages($mesg, null, 'warnings');
+            $error++;
+            $result = -1;
+        }*/
+
+        // Check minimum price
+        $productid = GETPOST('productid', 'int');
+        if (! empty($productid))
+        {
+            $product = new Product($db);
+            $product->fetch($productid);
+
+            $type = $product->type;
+
+            $price_min = $product->price_min;
+            if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->thirdparty->price_level))
+                $price_min = $product->multiprices_min [$object->thirdparty->price_level];
+
+                $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
+
+                // Check price is not lower than minimum (check is done only for standard or replacement invoices)
+                if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT) && $price_min && (price2num($pu_ht) * (1 - price2num(GETPOST('remise_percent')) / 100) < price2num($price_min))) {
+                    setEventMessages($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $conf->currency)), null, 'errors');
+                    $error ++;
+                }
+        } else {
+            $type = GETPOST('type');
+            $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
+
+            // Check parameters
+            if (GETPOST('type') < 0) {
+                setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
+                $error ++;
+            }
+        }
+        if ($qty < 0) {
+            $langs->load("errors");
+            setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
+            $error ++;
+        }
+
+        // Update line
+        if (! $error) {
+            $result = $object->updateline(GETPOST('lineid'), $description, $pu_ht, $qty,
+                $vat_rate, GETPOST('productid'), GETPOST('remise_percent'), 'HT', $info_bits, 0, 0, $type,
+                0, $special_code, $label, GETPOST('units'));
+
+            if ($result >= 0) {
+                /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
+                    // Define output language
+                    $outputlangs = $langs;
+                    $newlang = '';
+                    if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id'))
+                        $newlang = GETPOST('lang_id');
+                        if ($conf->global->MAIN_MULTILANGS && empty($newlang))
+                            $newlang = $object->thirdparty->default_lang;
+                            if (! empty($newlang)) {
+                                $outputlangs = new Translate("", $conf);
+                                $outputlangs->setDefaultLang($newlang);
+                            }
+
+                            $ret = $object->fetch($id); // Reload to get new records
+                            $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
+                }*/
+
+                $object->fetch($object->id);    // Reload lines
+                
+                unset($_POST['qty']);
+                unset($_POST['type']);
+                unset($_POST['productid']);
+                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');
+            }
+        }
+}
+
 // Do we click on purge search criteria ?
-if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter")) // Both test are required to be compatible with all browsers
+if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All test are required to be compatible with all browsers
 {
     $search_ref='';
     $search_societe='';
@@ -1302,7 +1462,7 @@ else
 		// Show object lines
 		if (! empty($object->lines))
 		{
-		    $disableedit=1;
+		    //$disableedit=1;
 		    //$disablemove=1;
 		    $ret = $object->printObjectLines($action, $mysoc, $soc, $lineid, 0);      // No date selector for template invoice
 		}
-- 
GitLab