Fixes issue 32265: Fix price including taxes at document level
authorAlvaro Ferraz <alvaro.ferraz@openbravo.com>
Fri, 03 Mar 2017 14:08:55 +0100
changeset 31600 86dcf5d294d9
parent 31599 b3ee13f262a4
child 31601 7eea6a2a5f22
Fixes issue 32265: Fix price including taxes at document level

Do not round line amounts and tax bases, and header tax bases, in case price including taxes at document level, when document is in draft status.
Round them when completing the document.
Call again line triggers to calculate again amounts and taxes without rounding when reactivating the document.
Do not calculate document net amount incrementally in case price including taxes as we need to sum rounded taxes instead of round the sum of taxes.
Adjust taxes at line level in case price including taxes to make sure line tax base amount + line tax amount is equals line gross amount.
Adjust taxes at document level, when completing the document, in case price including taxes at document level, to make sure document tax base amount + document tax amount is equals document gross amount.
Adjust line amount, when completing the document, in case price including taxes at document level, to make sure sum of line net amounts is equals document net amount.
When reactivating price including taxes invoices with manual taxes, no recalculate taxes will be automatically deleted.
src-db/database/model/functions/C_GET_NET_AMOUNT_FROM_GROSS.xml
src-db/database/model/functions/C_INVOICELINETAX_INSERT.xml
src-db/database/model/functions/C_INVOICE_POST.xml
src-db/database/model/functions/C_ORDERLINETAX_INSERT.xml
src-db/database/model/functions/C_ORDER_POST1.xml
src-db/database/model/tables/C_ORDERLINETAX.xml
src-db/database/model/tables/C_ORDERTAX.xml
src-db/database/model/triggers/C_INVLINE_CHK_RESTRICTIONS_TRG.xml
src-db/database/model/triggers/C_INVOICELINETAX_TRG.xml
src-db/database/model/triggers/C_INVOICELINE_BEFORE_TRG.xml
src-db/database/model/triggers/C_INVOICELINE_TRG2.xml
src-db/database/model/triggers/C_ORDERLINETAX_TRG.xml
src-db/database/model/triggers/C_ORDERLINE_TRG.xml
src-db/database/model/triggers/C_ORDERLINE_TRG2.xml
--- a/src-db/database/model/functions/C_GET_NET_AMOUNT_FROM_GROSS.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/functions/C_GET_NET_AMOUNT_FROM_GROSS.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -11,7 +11,7 @@
         <default/>
       </parameter>
       <parameter name="p_stdprecision" type="NUMERIC" mode="in">
-        <default/>
+        <default><![CDATA[NULL]]></default>
       </parameter>
       <body><![CDATA[/*************************************************************************
 * The contents of this file are subject to the Openbravo  Public  License
@@ -31,10 +31,9 @@
 ************************************************************************/
 
 v_ResultStr VARCHAR(2000) := '';
-v_message VARCHAR2(2000) := '';
+v_calcPrecision NUMBER:= 50;
+v_TaxAmount NUMBER;
 v_NetAmount NUMBER;
-v_TaxAmount NUMBER;
-v_calcPrecision NUMBER:= 50;
 
 BEGIN --BODY
 
@@ -42,18 +41,11 @@
     RETURN 0;
   END IF;
 
-  IF (p_stdprecision > v_calcPrecision) THEN
-    v_calcPrecision := p_stdprecision;
+  v_TaxAmount := C_GET_TAX_AMT_FROM_NET(p_tax_id, p_grossamt, p_alternatetaxbaseamt, v_calcPrecision, 0);
+  v_NetAmount := ROUND(p_grossamt * (p_grossamt  / (p_grossamt + v_TaxAmount)), v_calcPrecision);
+  IF (p_stdprecision IS NOT NULL) THEN
+    v_NetAmount := ROUND(v_NetAmount, p_stdprecision);
   END IF;
-
-  v_TaxAmount := C_GET_TAX_AMT_FROM_NET(p_tax_id, p_grossamt, p_alternatetaxbaseamt, v_calcPrecision, 0);
-  DBMS_OUTPUT.PUT_LINE('Unit tax ' || v_TaxAmount);
-  v_NetAmount := ROUND(p_grossamt * (p_grossamt  / (p_grossamt + v_TaxAmount)), p_stdprecision);
-
-  --TODO: Call function to recalculate alternate taxbase amount.
-
-  --TODO: If alternate taxbase amount is different recalculate line net amount c_tax_from_net_amt function.
-
   RETURN v_NetAmount;
 
 EXCEPTION
--- a/src-db/database/model/functions/C_INVOICELINETAX_INSERT.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/functions/C_INVOICELINETAX_INSERT.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -40,7 +40,7 @@
 * under the License.
 * The Original Code is Openbravo ERP.
 * The Initial Developer of the Original Code is Openbravo SLU
-* All portions are Copyright (C) 2010-2016 Openbravo SLU
+* All portions are Copyright (C) 2010-2017 Openbravo SLU
 * All Rights Reserved.
 * Contributor(s):  ______________________________________.
 ************************************************************************/
@@ -78,7 +78,7 @@
       v_TaxBaseAmount:=0;
     END IF;
     IF (v_BaseAmount='TAX' OR v_BaseAmount='LNATAX' OR v_BaseAmount='TBATAX') THEN
-      SELECT COALESCE(SUM(TAXAMT),0) + v_TaxBaseAmount
+      SELECT COALESCE(SUM(TAXAMT), 0) + v_TaxBaseAmount
       INTO v_TaxBaseAmount
       FROM C_INVOICELINETAX, C_TAX
       WHERE C_INVOICELINETAX.C_TAX_ID = C_TAX.C_TAX_ID
@@ -103,12 +103,12 @@
       INSERT
       INTO C_INVOICELINETAX (
       C_InvoiceLineTax_ID, C_InvoiceLine_ID, C_Invoice_ID, C_Tax_ID, AD_Client_ID, AD_Org_ID,
-      IsActive, Created, CreatedBy, Updated,
-      UpdatedBy, TaxBaseAmt, TaxAmt, Line)
+      IsActive, Created, CreatedBy, Updated, UpdatedBy,
+      TaxBaseAmt, TaxAmt, Line)
       VALUES (
       GET_UUID(), p_invoiceline_id, p_invoice_id, p_tax_id, v_Client_ID, p_org_id,
-      'Y', now(), p_user_id, now(),
-      p_user_id, v_TaxBaseAmount, ROUND(v_TaxBaseAmount*v_Rate / 100, p_StdPrecision), v_LineNo);
+      'Y', now(), p_user_id, now(), p_user_id,
+      v_TaxBaseAmount, ROUND(ROUND(v_TaxBaseAmount, p_StdPrecision) * v_Rate/100, p_StdPrecision), v_LineNo);
     ELSE
       FOR Cur_Taxes IN
         (SELECT C_Tax_ID, RATE
--- a/src-db/database/model/functions/C_INVOICE_POST.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/functions/C_INVOICE_POST.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -60,6 +60,7 @@
   Cur_lineqty RECORD;
   Cur_InvoiceTax RECORD;
   Cur_Offer RECORD;
+  Cur_Tax RECORD;
 
   -- Record Info
   v_Client_ID VARCHAR2(32);
@@ -152,7 +153,8 @@
   Cur_InvoiceNetLine RECORD;
 
   v_LineMax NUMBER:=0;
-  v_precision NUMBER;
+  v_pricePrecision C_Currency.PricePrecision%TYPE;
+  v_stdPrecision C_Currency.StdPrecision%TYPE;
   v_gross_unit_price NUMBER;
   v_line_gross_amount NUMBER;
   v_Isquantityvariable CHAR(1);
@@ -172,7 +174,6 @@
 
   v_iscashvat C_Invoice.IsCashVat%TYPE;
   v_invoiceline_qtysum NUMBER;
-  v_PriceList_ID varchar2(32);
   v_prepaymentamt NUMBER;
   v_prepayment_inorders NUMBER;
   v_hasTaxes NUMBER;
@@ -214,11 +215,133 @@
   END IF;
 BEGIN --BODY
 
-  /*Invoiceline acct dimension*/
-  SELECT C_INVOICE.ISSOTRX , C_INVOICE.c_bpartner_id
-  INTO v_IsSOTrx, v_BPartner_ID
-  FROM C_INVOICE
-  WHERE C_INVOICE_ID = v_Record_ID;
+  SELECT i.ISSOTRX , i.c_bpartner_id, i.DocAction, c.PricePrecision, c.StdPrecision, p.IsTaxIncluded
+  INTO v_IsSOTrx, v_BPartner_ID, v_DocAction, v_pricePrecision, v_stdPrecision, v_isTaxIncluded
+  FROM C_INVOICE i
+  JOIN C_CURRENCY c
+  ON i.C_CURRENCY_ID = c.C_CURRENCY_ID
+  JOIN M_PRICELIST p
+  ON i.M_PRICELIST_ID = p.M_PRICELIST_ID
+  WHERE i.C_INVOICE_ID = v_Record_ID;
+
+  /**************************************************************************
+   * Round amounts and taxes
+   *************************************************************************/
+  IF (v_DocAction = 'CO' AND v_isTaxIncluded = 'Y') THEN
+
+    -- Disable triggers
+    INSERT INTO AD_Session_Status (ad_session_status_id, ad_client_id, ad_org_id, isactive, created, createdby, updated, updatedby, isimporting)
+    VALUES (get_uuid(), '0', '0', 'Y', now(), '0', now(), '0', 'Y');
+
+    -- Round
+    UPDATE C_INVOICELINE
+    SET LineNetAmt = round(LineNetAmt, v_stdPrecision)
+    WHERE C_Invoice_ID = v_Record_ID;
+
+    UPDATE C_INVOICELINETAX
+    SET TaxBaseAmt = round(TaxBaseAmt, v_stdPrecision)
+    WHERE C_Invoice_ID = v_Record_ID;
+
+    UPDATE C_INVOICETAX
+    SET TaxBaseAmt = round(TaxBaseAmt, v_stdPrecision)
+    WHERE C_Invoice_ID = v_Record_ID
+    AND Recalculate = 'Y';
+
+    -- Adjust
+    FOR CUR_Tax IN (
+      SELECT it.C_Tax_ID, COALESCE((MIN(it.DocTaxBaseAmt) + MIN(it.DocTaxAmt)) - (SUM(ilt.LineTaxBaseAmt) + SUM(ilt.LineTaxAmt)), 0) as TaxAdjustment, COALESCE(MIN(it.DocTaxBaseAmt) - SUM(ilt.LineTaxBaseAmt), 0) as LineAdjustment
+      FROM (
+        SELECT c_tax_get_root(it.c_tax_id) as C_Tax_ID, CASE WHEN MIN(it.TaxBaseAmt) > 0 THEN MIN(it.TaxBaseAmt) ELSE MAX(it.TaxBaseAmt) END as DocTaxBaseAmt, SUM(it.TaxAmt) as DocTaxAmt, MIN(it.Line) as Line
+        FROM C_InvoiceTax it
+        JOIN C_Tax t
+        ON it.C_Tax_ID = t.C_Tax_ID
+        WHERE it.C_Invoice_ID = v_Record_ID
+        AND it.Recalculate = 'Y'
+        AND t.DocTaxAmount = 'D'
+        GROUP BY c_tax_get_root(it.c_tax_id)
+      ) it
+      JOIN (
+        SELECT c_tax_get_root(ilt.c_tax_id) as C_Tax_ID, CASE WHEN MIN(ilt.TaxBaseAmt) > 0 THEN MIN(ilt.TaxBaseAmt) ELSE MAX(ilt.TaxBaseAmt) END as LineTaxBaseAmt, SUM(ilt.TaxAmt) as LineTaxAmt
+        FROM C_InvoiceLineTax ilt
+        JOIN C_Tax t
+        ON ilt.C_Tax_ID = t.C_Tax_ID
+        WHERE ilt.C_Invoice_ID = v_Record_ID
+        AND t.DocTaxAmount = 'D'
+        GROUP BY ilt.C_InvoiceLine_ID, c_tax_get_root(ilt.c_tax_id)
+      ) ilt
+      ON ilt.C_Tax_ID = it.C_Tax_ID
+      GROUP BY it.C_Tax_ID, it.Line
+      HAVING COALESCE(MIN(it.DocTaxBaseAmt), 0) <> COALESCE(SUM(ilt.LineTaxBaseAmt), 0)
+      OR COALESCE(MIN(it.DocTaxBaseAmt) + MIN(it.DocTaxAmt), 0) <> COALESCE(SUM(ilt.LineTaxBaseAmt) + SUM(ilt.LineTaxAmt), 0)
+      ORDER BY it.Line
+    )
+    LOOP
+      -- Adjust TaxAmt
+      IF (CUR_Tax.TaxAdjustment <> 0) THEN
+        FOR CUR_Line IN (
+          SELECT it.C_InvoiceTax_ID, it.C_Tax_ID, t.Line
+          FROM C_InvoiceTax it
+          JOIN C_Tax t
+          ON it.C_Tax_ID = t.C_Tax_ID
+          WHERE it.C_Invoice_ID = v_Record_ID
+          AND it.Recalculate = 'Y'
+          AND c_tax_get_root(it.C_Tax_ID) = CUR_Tax.C_Tax_ID
+          ORDER BY ABS(it.TaxAmt) DESC, t.Line DESC
+        )
+        LOOP
+          UPDATE C_INVOICETAX
+          SET TaxAmt = TaxAmt - CUR_Tax.TaxAdjustment
+          WHERE C_InvoiceTax_ID = CUR_Line.C_InvoiceTax_ID;
+
+          UPDATE C_INVOICETAX it
+          SET TaxBaseAmt = TaxBaseAmt - CUR_Tax.TaxAdjustment
+          WHERE it.C_Invoice_ID = v_Record_ID
+          AND it.Recalculate = 'Y'
+          AND c_tax_get_root(it.C_Tax_ID) = CUR_Tax.C_Tax_ID
+          AND EXISTS (
+            SELECT 1
+            FROM C_Tax t
+            WHERE t.C_Tax_ID = it.C_Tax_ID
+            AND ((t.Cascade = 'Y'
+            AND t.Line > CUR_Line.Line)
+            OR (t.BaseAmount IN ('TAX', 'LNATAX', 'TBATAX')
+            AND C_TAX_ISMEMBER(t.C_TaxBase_ID, CUR_Line.C_Tax_ID) = 1
+            AND t.IsSummary = 'N'))
+          );
+
+          EXIT;
+        END LOOP;
+      END IF;
+
+      -- Adjust LineNetAmt
+      IF (CUR_Tax.LineAdjustment <> 0) THEN
+        FOR CUR_Line IN (
+          SELECT il.C_InvoiceLine_ID
+          FROM C_InvoiceLine il
+          WHERE il.C_Invoice_ID = v_Record_ID
+          AND EXISTS (
+            SELECT 1
+            FROM C_InvoiceLineTax ilt
+            WHERE il.C_InvoiceLine_ID = ilt.C_InvoiceLine_ID
+            AND c_tax_get_root(ilt.C_Tax_ID) = CUR_Tax.c_Tax_ID
+          )
+          ORDER BY ABS(il.LineNetAmt) DESC, il.Line DESC
+        )
+        LOOP
+          UPDATE C_INVOICELINE
+          SET LineNetAmt = LineNetAmt + CUR_Tax.LineAdjustment
+          WHERE C_InvoiceLine_ID = CUR_Line.C_InvoiceLine_ID;
+
+          EXIT;
+        END LOOP;
+      END IF;
+    END LOOP;
+
+    -- Enable triggers
+    DELETE FROM AD_Session_Status
+    WHERE isimporting = 'Y';
+
+  END IF;
 
   SELECT CASE WHEN (m.ISSOTRX='Y') THEN customer_blocking  ELSE vendor_blocking END ,  
   CASE WHEN (m.ISSOTRX='Y') THEN so_invoice_blocking ELSE po_invoice_blocking  END, name, DocAction
@@ -231,6 +354,7 @@
     RAISE_APPLICATION_ERROR(-20000,'@ThebusinessPartner@'||' '|| v_bpartner_name ||' '||'@BusinessPartnerBlocked@');
   END IF;
 
+  /*Invoiceline acct dimension*/
   IF (v_IsSOTrx = 'N') THEN
     FOR Cur_line IN
       (SELECT C_INVOICELINE.C_InvoiceLine_ID,
@@ -258,14 +382,14 @@
       i.AD_Client_ID, i.AD_Org_ID, i.UpdatedBy, i.DocumentNo,
       i.C_Order_ID, i.IsSOTrx, i.C_BPartner_ID, i.AD_User_ID,
       i.C_Currency_ID, i.POReference, i.Posted,
-      i.c_Project_Id, i.C_WithHolding_ID, i.IsCashVat, i.M_PriceList_ID, i.prepaymentamt
+      i.c_Project_Id, i.C_WithHolding_ID, i.IsCashVat, i.prepaymentamt
   INTO v_Processing, v_Processed, v_DocAction, v_DocStatus,
       v_DocType_ID, v_DocTypeTarget_ID,
       v_PaymentRule, v_PaymentTerm, v_DateAcct, v_DateInvoiced,
       v_Client_ID, v_Org_ID, v_UpdatedBy, v_DocumentNo,
       v_Order_ID, v_IsSOTrx, v_BPartner_ID, v_BPartner_User_ID,
       v_Currency_ID, v_POReference, v_Posted,
-      v_C_Project_Id, cWithHoldID, v_iscashvat, v_PriceList_ID, v_prepaymentamt
+      v_C_Project_Id, cWithHoldID, v_iscashvat, v_prepaymentamt
   FROM C_INVOICE i
   WHERE i.C_Invoice_ID=v_Record_ID FOR UPDATE;
 
@@ -273,11 +397,6 @@
   INTO  v_isreturndoctype    
   FROM  c_doctype dt  
   WHERE dt.c_doctype_id= v_DocTypeTarget_ID;
-
-  SELECT pl.istaxincluded
-  INTO   v_istaxincluded
-  FROM   m_pricelist pl 
-  WHERE pl.m_pricelist_id= v_PriceList_ID;
   
   DBMS_OUTPUT.PUT_LINE('Invoice_ID=' || v_Record_ID ||', DocAction=' || v_DocAction || ', DocStatus=' || v_DocStatus || ', DocType_ID=' || v_DocType_ID || ', DocTypeTarget_ID=' || v_DocTypeTarget_ID) ;
   /**
@@ -1072,6 +1191,42 @@
       DELETE FROM C_INVOICELINE
       WHERE C_INVOICE_DISCOUNT_ID IS NOT NULL
         AND C_INVOICE_ID=v_Record_ID;
+
+      /**************************************************************************
+       * Recalculate amounts and taxes
+       *************************************************************************/
+      IF (v_isTaxIncluded = 'Y') THEN
+
+        -- Remove header amounts and taxes
+        DELETE FROM C_INVOICETAX WHERE C_Invoice_ID = v_Record_ID;
+        UPDATE C_INVOICE SET TotalLines = 0, GrandTotal = 0 WHERE C_Invoice_ID = v_Record_ID;
+
+        FOR Cur_line IN (
+          SELECT C_InvoiceLine_ID
+          FROM C_INVOICELINE
+          WHERE C_Invoice_ID = v_Record_ID
+        ) LOOP
+
+          -- Disable triggers
+          INSERT INTO AD_Session_Status (ad_session_status_id, ad_client_id, ad_org_id, isactive, created, createdby, updated, updatedby, isimporting)
+          VALUES (get_uuid(), '0', '0', 'Y', now(), '0', now(), '0', 'Y');
+
+          -- Remove line amounts and taxes
+          DELETE FROM C_INVOICELINETAX WHERE C_InvoiceLine_ID = Cur_line.C_InvoiceLine_ID;
+          SELECT Line_Gross_Amount INTO v_line_gross_amount FROM C_INVOICELINE WHERE C_InvoiceLine_ID = Cur_line.C_InvoiceLine_ID;
+          UPDATE C_INVOICELINE SET Line_Gross_Amount = 0 WHERE C_InvoiceLine_ID = Cur_line.C_InvoiceLine_ID;
+
+          -- Enable triggers
+          DELETE FROM AD_Session_Status
+          WHERE isimporting = 'Y';
+
+          -- Recalculate amounts and taxes
+          UPDATE C_INVOICELINE SET Line_Gross_Amount = v_line_gross_amount WHERE C_InvoiceLine_ID = Cur_line.C_InvoiceLine_ID;
+
+        END LOOP;
+
+      END IF;
+
       END_PROCESSING:=TRUE;
     END IF;
   END IF;--END_PROCESSING
@@ -1200,9 +1355,6 @@
     SELECT MAX(LINE) INTO v_InvoiceLineSeqNo
     FROM C_INVOICELINE
     WHERE C_INVOICE_ID=v_Record_ID;
-    SELECT PricePrecision INTO v_precision
-    FROM C_INVOICE i, C_CURRENCY c
-    WHERE i.C_INVOICE_ID = v_Record_ID AND i.C_CURRENCY_ID = c.C_CURRENCY_ID;
     FOR Cur_CInvoiceDiscount IN
       (SELECT C_INVOICE_DISCOUNT.C_INVOICE_DISCOUNT_ID, C_DISCOUNT.DISCOUNT, C_DISCOUNT.M_PRODUCT_ID, C_DISCOUNT.NAME,
            C_INVOICE_DISCOUNT.CASCADE, C_DISCOUNT.C_DISCOUNT_ID, M_PRODUCT.C_UOM_ID,
@@ -1234,7 +1386,7 @@
           ELSE
             v_line_gross_amount:=(-1) * Cur_TaxDiscount.LINEGROSSAMT * Cur_CInvoiceDiscount.Discount/100;
           END IF;
-          v_Discount:= C_GET_NET_PRICE_FROM_GROSS(Cur_TaxDiscount.C_TAX_ID, v_line_gross_amount, 0, v_precision, 1);
+          v_Discount:= C_GET_NET_PRICE_FROM_GROSS(Cur_TaxDiscount.C_TAX_ID, v_line_gross_amount, 0, v_pricePrecision, 1);
           v_gross_unit_price:= v_line_gross_amount;
         ELSE
           IF (Cur_CInvoiceDiscount.CASCADE='Y') THEN
@@ -1298,7 +1450,7 @@
            0, Cur_CInvoiceDiscount.C_UOM_ID, Cur_TaxDiscount.C_TAX_ID, NULL,
            NULL, NULL, 'N' ,
            NULL, NULL, v_Discount,
-           ROUND(v_gross_unit_price, v_precision), v_Discount  ,ROUND(v_line_gross_amount, v_precision),
+           ROUND(v_gross_unit_price, v_pricePrecision), v_Discount  ,ROUND(v_line_gross_amount, v_pricePrecision),
            v_isdeferred_inv, v_defplantype_inv, v_periodnumber_inv, v_period_inv,
            NULL, NULL
           );
--- a/src-db/database/model/functions/C_ORDERLINETAX_INSERT.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/functions/C_ORDERLINETAX_INSERT.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -40,7 +40,7 @@
 * under the License.
 * The Original Code is Openbravo ERP.
 * The Initial Developer of the Original Code is Openbravo SLU
-* All portions are Copyright (C) 2010-2016 Openbravo SLU
+* All portions are Copyright (C) 2010-2017 Openbravo SLU
 * All Rights Reserved.
 * Contributor(s):  ______________________________________.
 ************************************************************************/
@@ -78,7 +78,7 @@
       v_TaxBaseAmount:=0;
     END IF;
     IF (v_BaseAmount='TAX' OR v_BaseAmount='LNATAX' OR v_BaseAmount='TBATAX') THEN
-      SELECT COALESCE(SUM(TAXAMT),0) + v_TaxBaseAmount
+      SELECT COALESCE(SUM(TAXAMT), 0) + v_TaxBaseAmount
       INTO v_TaxBaseAmount
       FROM C_ORDERLINETAX, C_TAX
       WHERE C_ORDERLINETAX.C_TAX_ID = C_TAX.C_TAX_ID
@@ -103,12 +103,12 @@
       INSERT
       INTO C_ORDERLINETAX (
       C_OrderLineTax_ID, C_OrderLine_ID, C_Order_ID, C_Tax_ID, AD_Client_ID, AD_Org_ID,
-      IsActive, Created, CreatedBy, Updated,
-      UpdatedBy, TaxBaseAmt, TaxAmt, Line)
+      IsActive, Created, CreatedBy, Updated, UpdatedBy,
+      TaxBaseAmt, TaxAmt, Line)
       VALUES (
       GET_UUID(), p_orderline_id, p_order_id, p_tax_id, v_Client_ID, p_org_id,
-      'Y', now(), p_user_id, now(),
-      p_user_id, v_TaxBaseAmount, ROUND(v_TaxBaseAmount*v_Rate / 100, p_StdPrecision), v_LineNo);
+      'Y', now(), p_user_id, now(), p_user_id,
+      v_TaxBaseAmount, ROUND(ROUND(v_TaxBaseAmount, p_StdPrecision) * v_Rate/100, p_StdPrecision), v_LineNo);
     ELSE
       FOR Cur_Taxes IN
         (SELECT C_Tax_ID, RATE
--- a/src-db/database/model/functions/C_ORDER_POST1.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/functions/C_ORDER_POST1.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -22,7 +22,7 @@
 * under the License.
 * The Original Code is Openbravo ERP.
 * The Initial Developer of the Original Code is Openbravo SLU
-* All portions are Copyright (C) 2001-2016 Openbravo SLU
+* All portions are Copyright (C) 2001-2017 Openbravo SLU
 * All Rights Reserved.
 * Contributor(s):  ______________________________________.
 ************************************************************************/
@@ -42,6 +42,7 @@
     Cur_Parameter RECORD;
     Cur_line RECORD;
     Cur_Order RECORD;
+    Cur_Tax RECORD;
   -- Record Info
   v_Client_ID VARCHAR2(32);
   v_Org_ID VARCHAR2(32);
@@ -95,7 +96,6 @@
   v_c_Bpartner_ID VARCHAR2(32);
   v_c_currency_ID VARCHAR2(32);
   v_C_PROJECT_ID VARCHAR2(32);
-  v_PriceList_ID VARCHAR2(32);
   FINISH_PROCESS BOOLEAN:=FALSE;
   END_PROCESSING BOOLEAN:=FALSE;
   v_CBPartner_ID VARCHAR2(32);
@@ -108,7 +108,8 @@
   Cur_TaxDiscount RECORD;
   v_OrderLine VARCHAR2(32);
   v_Discount NUMBER;
-  v_precision NUMBER;
+  v_pricePrecision C_Currency.PricePrecision%TYPE;
+  v_stdPrecision C_Currency.StdPrecision%TYPE;
   Cur_OrderLine RECORD;
   v_DiscountExist NUMBER;
   v_gross_unit_price NUMBER;
@@ -156,13 +157,132 @@
     END IF;
     DBMS_OUTPUT.PUT_LINE('  Record_ID=' || v_Record_ID) ;
   BEGIN --BODY
-  
+
+  SELECT o.ISSOTRX, o.c_bpartner_id, o.DocAction, c.PricePrecision, c.StdPrecision, p.IsTaxIncluded
+  INTO v_IsSOTrx, v_c_Bpartner_ID, v_DocAction, v_pricePrecision, v_stdPrecision, v_isTaxIncluded
+  FROM C_ORDER o
+  JOIN C_CURRENCY c
+  ON o.C_CURRENCY_ID = c.C_CURRENCY_ID
+  JOIN M_PRICELIST p
+  ON o.M_PRICELIST_ID = p.M_PRICELIST_ID
+  WHERE o.C_ORDER_ID = v_Record_ID;
+
+  /**************************************************************************
+   * Round amounts and taxes
+   *************************************************************************/
+  IF (v_DocAction = 'CO' AND v_isTaxIncluded = 'Y') THEN
+
+    -- Disable triggers
+    INSERT INTO AD_Session_Status (ad_session_status_id, ad_client_id, ad_org_id, isactive, created, createdby, updated, updatedby, isimporting)
+    VALUES (get_uuid(), '0', '0', 'Y', now(), '0', now(), '0', 'Y');
+
+    -- Round
+    UPDATE C_ORDERLINE
+    SET LineNetAmt = round(LineNetAmt, v_stdPrecision)
+    WHERE C_Order_ID = v_Record_ID;
+
+    UPDATE C_ORDERLINETAX
+    SET TaxBaseAmt = round(TaxBaseAmt, v_stdPrecision)
+    WHERE C_Order_ID = v_Record_ID;
+
+    UPDATE C_ORDERTAX
+    SET TaxBaseAmt = round(TaxBaseAmt, v_stdPrecision)
+    WHERE C_Order_ID = v_Record_ID;
+
+    -- Adjust
+    FOR CUR_Tax IN (
+      SELECT ot.C_Tax_ID, COALESCE((MIN(ot.DocTaxBaseAmt) + MIN(ot.DocTaxAmt)) - (SUM(olt.LineTaxBaseAmt) + SUM(olt.LineTaxAmt)), 0) as TaxAdjustment, COALESCE(MIN(ot.DocTaxBaseAmt) - SUM(olt.LineTaxBaseAmt), 0) as LineAdjustment
+      FROM (
+        SELECT c_tax_get_root(ot.c_tax_id) as C_Tax_ID, CASE WHEN MIN(ot.TaxBaseAmt) > 0 THEN MIN(ot.TaxBaseAmt) ELSE MAX(ot.TaxBaseAmt) END as DocTaxBaseAmt, SUM(ot.TaxAmt) as DocTaxAmt, MIN(ot.Line) as Line
+        FROM C_OrderTax ot
+        JOIN C_Tax t
+        ON ot.C_Tax_ID = t.C_Tax_ID
+        WHERE ot.C_Order_ID = v_Record_ID
+        AND t.DocTaxAmount = 'D'
+        GROUP BY c_tax_get_root(ot.c_tax_id)
+      ) ot
+      JOIN (
+        SELECT c_tax_get_root(olt.c_tax_id) as C_Tax_ID, CASE WHEN MIN(olt.TaxBaseAmt) > 0 THEN MIN(olt.TaxBaseAmt) ELSE MAX(olt.TaxBaseAmt) END as LineTaxBaseAmt, SUM(olt.TaxAmt) as LineTaxAmt
+        FROM C_OrderLineTax olt
+        JOIN C_Tax t
+        ON olt.C_Tax_ID = t.C_Tax_ID
+        WHERE olt.C_Order_ID = v_Record_ID
+        AND t.DocTaxAmount = 'D'
+        GROUP BY olt.C_OrderLine_ID, c_tax_get_root(olt.c_tax_id)
+      ) olt
+      ON olt.C_Tax_ID = ot.C_Tax_ID
+      GROUP BY ot.C_Tax_ID, ot.Line
+      HAVING COALESCE(MIN(ot.DocTaxBaseAmt), 0) <> COALESCE(SUM(olt.LineTaxBaseAmt), 0)
+      OR COALESCE(MIN(ot.DocTaxBaseAmt) + MIN(ot.DocTaxAmt), 0) <> COALESCE(SUM(olt.LineTaxBaseAmt) + SUM(olt.LineTaxAmt), 0)
+      ORDER BY ot.Line
+    )
+    LOOP
+      -- Adjust TaxAmt
+      IF (CUR_Tax.TaxAdjustment <> 0) THEN
+        FOR CUR_Line IN (
+          SELECT ot.C_OrderTax_ID, ot.C_Tax_ID, t.Line
+          FROM C_OrderTax ot
+          JOIN C_Tax t
+          ON ot.C_Tax_ID = t.C_Tax_ID
+          WHERE ot.C_Order_ID = v_Record_ID
+          AND c_tax_get_root(ot.C_Tax_ID) = CUR_Tax.C_Tax_ID
+          ORDER BY ABS(ot.TaxAmt) DESC, t.Line DESC
+        )
+        LOOP
+          UPDATE C_ORDERTAX
+          SET TaxAmt = TaxAmt - CUR_Tax.TaxAdjustment
+          WHERE C_OrderTax_ID = CUR_Line.C_OrderTax_ID;
+
+          UPDATE C_ORDERTAX ot
+          SET TaxBaseAmt = TaxBaseAmt - CUR_Tax.TaxAdjustment
+          WHERE ot.C_Order_ID = v_Record_ID
+          AND c_tax_get_root(ot.C_Tax_ID) = CUR_Tax.C_Tax_ID
+          AND EXISTS (
+            SELECT 1
+            FROM C_Tax t
+            WHERE t.C_Tax_ID = ot.C_Tax_ID
+            AND ((t.Cascade = 'Y'
+            AND t.Line > CUR_Line.Line)
+            OR (t.BaseAmount IN ('TAX', 'LNATAX', 'TBATAX')
+            AND C_TAX_ISMEMBER(t.C_TaxBase_ID, CUR_Line.C_Tax_ID) = 1
+            AND t.IsSummary = 'N'))
+          );
+
+          EXIT;
+        END LOOP;
+      END IF;
+
+      -- Adjust LineNetAmt
+      IF (CUR_Tax.LineAdjustment <> 0) THEN
+        FOR CUR_Line IN (
+          SELECT ol.C_OrderLine_ID
+          FROM C_OrderLine ol
+          WHERE ol.C_Order_ID = v_Record_ID
+          AND EXISTS (
+            SELECT 1
+            FROM C_OrderLineTax olt
+            WHERE ol.C_OrderLine_ID = olt.C_OrderLine_ID
+            AND c_tax_get_root(olt.C_Tax_ID) = CUR_Tax.c_Tax_ID
+          )
+          ORDER BY ABS(ol.LineNetAmt) DESC, ol.Line DESC
+        )
+        LOOP
+          UPDATE C_ORDERLINE
+          SET LineNetAmt = LineNetAmt + CUR_Tax.LineAdjustment
+          WHERE C_OrderLine_ID = CUR_Line.C_OrderLine_ID;
+
+          EXIT;
+        END LOOP;
+      END IF;
+    END LOOP;
+
+    -- Enable triggers
+    DELETE FROM AD_Session_Status
+    WHERE isimporting = 'Y';
+
+  END IF;
+
   /*Orderline acct dimension*/
-  SELECT C_ORDER.ISSOTRX , C_ORDER.c_bpartner_id, DocAction
-  INTO v_IsSOTrx, v_c_Bpartner_ID, v_DocAction
-  FROM C_ORDER
-  WHERE C_ORDER_ID = v_Record_ID;
-  
   IF (v_IsSOTrx = 'N') THEN
     FOR Cur_line IN
       (SELECT C_ORDERLINE.C_OrderLine_ID,
@@ -214,19 +334,14 @@
       C_DocType_ID, C_DocTypeTarget_ID, c_order.AD_Client_ID,
       c_order.AD_Org_ID, c_order.UpdatedBy, M_Warehouse_ID, TRUNC(DateOrdered),
       Issotrx, c_Bpartner_Id, c_order.c_currency_id, C_PROJECT_ID,
-      C_BPartner_ID, M_PriceList_ID, invoicerule, c_order.IsCashVat
+      C_BPartner_ID, invoicerule, c_order.IsCashVat
     INTO v_IsProcessing, v_IsProcessed, v_DocAction, v_DocStatus,
       v_DocType_ID, v_DocTypeTarget_ID, v_Client_ID,
       v_Org_ID, v_UpdatedBy, v_M_Warehouse_ID, v_Date,
       v_isSoTrx, v_c_Bpartner_Id, v_c_currency_id, v_C_PROJECT_ID,
-      v_CBPartner_ID, v_PriceList_ID, v_invoicerule, v_iscashvat
+      v_CBPartner_ID, v_invoicerule, v_iscashvat
     FROM C_ORDER
     WHERE C_Order_ID=v_Record_ID  FOR UPDATE  ;
-
-    SELECT m_pricelist.istaxincluded
-    INTO v_istaxincluded
-    FROM m_pricelist 
-    WHERE m_pricelist_id= v_PriceList_ID;
     
     -- Get current DocSubTypeSO
     SELECT DocSubTypeSO
@@ -637,6 +752,41 @@
           END IF;
         END IF;
 
+        /**************************************************************************
+         * Recalculate amounts and taxes
+         *************************************************************************/
+        IF (v_isTaxIncluded = 'Y') THEN
+
+          -- Remove header amounts and taxes
+          DELETE FROM C_ORDERTAX WHERE C_Order_ID = v_Record_ID;
+          UPDATE C_ORDER SET TotalLines = 0, GrandTotal = 0 WHERE C_Order_ID = v_Record_ID;
+
+          FOR Cur_line IN (
+            SELECT C_OrderLine_ID
+            FROM C_ORDERLINE
+            WHERE C_Order_ID = v_Record_ID
+          ) LOOP
+
+            -- Disable triggers
+            INSERT INTO AD_Session_Status (ad_session_status_id, ad_client_id, ad_org_id, isactive, created, createdby, updated, updatedby, isimporting)
+            VALUES (get_uuid(), '0', '0', 'Y', now(), '0', now(), '0', 'Y');
+
+            -- Remove line amounts and taxes
+            DELETE FROM C_ORDERLINETAX WHERE C_OrderLine_ID = Cur_line.C_OrderLine_ID;
+            SELECT Line_Gross_Amount INTO v_line_gross_amount FROM C_ORDERLINE WHERE C_OrderLine_ID = Cur_line.C_OrderLine_ID;
+            UPDATE C_ORDERLINE SET Line_Gross_Amount = 0 WHERE C_OrderLine_ID = Cur_line.C_OrderLine_ID;
+
+            -- Enable triggers
+            DELETE FROM AD_Session_Status
+            WHERE isimporting = 'Y';
+
+            -- Recalculate amounts and taxes
+            UPDATE C_ORDERLINE SET Line_Gross_Amount = v_line_gross_amount WHERE C_OrderLine_ID = Cur_line.C_OrderLine_ID;
+
+          END LOOP;
+
+        END IF;
+
         UPDATE C_ORDER
         SET DocStatus='DR', -- Draft
             DocAction='CO',
@@ -935,14 +1085,10 @@
         v_CumDiscount:=0;
         v_OldCumDiscount:=0;
         v_Line:=10;
-        v_precision:=0;
         SELECT MAX(LINE)
           INTO v_OrderLineSeqNo
         FROM C_ORDERLINE
         WHERE C_ORDER_ID=v_Record_ID;
-        SELECT PricePrecision INTO v_precision
-        FROM C_ORDER o, C_CURRENCY c
-        WHERE o.C_ORDER_ID = v_Record_ID AND  o.C_CURRENCY_ID = c.C_CURRENCY_ID;
         FOR Cur_COrderDiscount IN
            (SELECT C_ORDER_DISCOUNT.C_ORDER_DISCOUNT_ID, C_DISCOUNT.DISCOUNT, C_DISCOUNT.M_PRODUCT_ID, C_DISCOUNT.NAME,
               C_ORDER_DISCOUNT.CASCADE, C_DISCOUNT.C_DISCOUNT_ID, M_PRODUCT.C_UOM_ID
@@ -974,7 +1120,7 @@
               ELSE
                 v_line_gross_amount:=(-1) * Cur_TaxDiscount.LINEGROSSAMT * Cur_COrderDiscount.Discount/100;
               END IF;
-              v_Discount:= C_GET_NET_PRICE_FROM_GROSS(Cur_TaxDiscount.C_TAX_ID, v_line_gross_amount, 0, v_precision, 1);
+              v_Discount:= C_GET_NET_PRICE_FROM_GROSS(Cur_TaxDiscount.C_TAX_ID, v_line_gross_amount, 0, v_pricePrecision, 1);
               v_gross_unit_price:= v_line_gross_amount;
             ELSE
               IF (Cur_COrderDiscount.CASCADE='Y') THEN
@@ -1013,11 +1159,11 @@
                   now(), now(), now(), now(), Cur_COrderDiscount.NAME,
                   Cur_COrderDiscount.M_PRODUCT_ID, v_M_Warehouse_ID, 'N', Cur_COrderDiscount.C_UOM_ID, 1,
                   0, 0, 0, NULL, v_c_currency_id,
-                  ROUND(v_Discount,v_precision), ROUND(v_Discount,v_precision), ROUND(v_Discount,v_precision), ROUND(v_Discount,v_precision), 0, 0,
+                  ROUND(v_Discount, v_pricePrecision), ROUND(v_Discount, v_pricePrecision), ROUND(v_Discount, v_pricePrecision), ROUND(v_Discount, v_pricePrecision), 0, 0,
                   NULL, NULL, Cur_TaxDiscount.C_TAX_ID, NULL, NULL,
                   NULL, 'N', NULL, NULL, NULL, NULL,
-                  NULL, ROUND(v_Discount,v_precision), NULL,
-                  ROUND(v_gross_unit_price, v_precision), ROUND(v_Discount,v_precision),ROUND(v_line_gross_amount, v_precision)
+                  NULL, ROUND(v_Discount, v_pricePrecision), NULL,
+                  ROUND(v_gross_unit_price, v_pricePrecision), ROUND(v_Discount, v_pricePrecision),ROUND(v_line_gross_amount, v_pricePrecision)
                 );
 
               UPDATE C_ORDERLINE
@@ -1025,7 +1171,7 @@
               WHERE C_ORDERLINE_ID=v_OrderLine;
             ELSE
               UPDATE C_ORDERLINE 
-              SET pricelist = ROUND(v_Discount,v_precision), priceactual = ROUND(v_Discount,v_precision), pricelimit = ROUND(v_Discount,v_precision), linenetamt = ROUND(v_Discount,v_precision), pricestd = ROUND(v_Discount,v_precision)
+              SET pricelist = ROUND(v_Discount, v_pricePrecision), priceactual = ROUND(v_Discount, v_pricePrecision), pricelimit = ROUND(v_Discount, v_pricePrecision), linenetamt = ROUND(v_Discount, v_pricePrecision), pricestd = ROUND(v_Discount, v_pricePrecision)
               WHERE C_ORDERLINE.C_ORDER_DISCOUNT_ID = Cur_COrderDiscount.C_ORDER_DISCOUNT_ID
                 AND C_ORDERLINE.C_TAX_ID = Cur_TaxDiscount.C_TAX_ID;
             END IF;
--- a/src-db/database/model/tables/C_ORDERLINETAX.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/tables/C_ORDERLINETAX.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -72,6 +72,9 @@
       <foreign-key foreignTable="C_TAX" name="C_ORDERLINETAX_C_TAX">
         <reference local="C_TAX_ID" foreign="C_TAX_ID"/>
       </foreign-key>
+      <index name="C_ORDERLINETAX_ORDERID" unique="false">
+        <index-column name="C_ORDER_ID"/>
+      </index>
       <index name="C_ORDERLINETAX_ORDERLINE" unique="false">
         <index-column name="C_ORDERLINE_ID"/>
       </index>
--- a/src-db/database/model/tables/C_ORDERTAX.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/tables/C_ORDERTAX.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -65,6 +65,9 @@
       <foreign-key foreignTable="C_TAX" name="C_ORDERTAX_C_TAX">
         <reference local="C_TAX_ID" foreign="C_TAX_ID"/>
       </foreign-key>
+      <index name="C_ORDERTAX_ORDERID" unique="false">
+        <index-column name="C_ORDER_ID"/>
+      </index>
       <unique name="C_ORDERTAX_ORDER_TAX_UN">
         <unique-column name="C_ORDER_ID"/>
         <unique-column name="C_TAX_ID"/>
--- a/src-db/database/model/triggers/C_INVLINE_CHK_RESTRICTIONS_TRG.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/triggers/C_INVLINE_CHK_RESTRICTIONS_TRG.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -18,7 +18,7 @@
     * under the License.
     * The Original Code is Openbravo ERP.
     * The Initial Developer of the Original Code is Openbravo SLU
-    * All portions are Copyright (C) 2001-2016 Openbravo SLU
+    * All portions are Copyright (C) 2001-2017 Openbravo SLU
     * All Rights Reserved.
     * Contributor(s):  ______________________________________.
     ************************************************************************/
@@ -107,8 +107,6 @@
     INTO v_Prec
     FROM C_CURRENCY
     WHERE C_CURRENCY_ID=v_Currency;
-    :NEW.LineNetAmt:=ROUND(:NEW.LineNetAmt, v_Prec) ;
-    :NEW.ChargeAmt:=ROUND(:NEW.ChargeAmt, v_Prec) ;
 
     IF (:NEW.ISEDITLINENETAMT='Y' AND ROUND(TO_NUMBER(:NEW.QTYINVOICED) * TO_NUMBER(:NEW.PRICEACTUAL),v_Prec)!=TO_NUMBER(:NEW.LINENETAMT)) THEN
       RAISE_APPLICATION_ERROR(-20000, '@LineAmountNotCorrect@') ;
--- a/src-db/database/model/triggers/C_INVOICELINETAX_TRG.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/triggers/C_INVOICELINETAX_TRG.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -17,7 +17,7 @@
   * parts created by ComPiere are Copyright (C) ComPiere, Inc.;
   * All Rights Reserved.
   * Contributor(s): Openbravo SLU
-  * Contributions are Copyright (C) 2010-2016 Openbravo, S.L.U.
+  * Contributions are Copyright (C) 2010-2017 Openbravo, S.L.U.
   *
   * Specifically, this derivative work is based upon the following Compiere
   * file and version.
@@ -27,14 +27,18 @@
 v_LineNo  NUMBER;
 v_C_Invoice_ID C_INVOICELINETAX.C_INVOICE_ID%TYPE;
 v_C_Tax_ID C_INVOICELINETAX.C_TAX_ID%TYPE;
-v_c_invoicetax_id C_INVOICETAX.C_INVOICETAX_ID%TYPE;
+v_C_InvoiceTax_ID C_INVOICETAX.C_INVOICETAX_ID%TYPE;
 v_Prec C_CURRENCY.STDPRECISION%TYPE;
 v_DocTaxAmount C_TAX.DOCTAXAMOUNT%TYPE;
 v_Rate  C_TAX.RATE%TYPE;
+v_Cascade C_TAX.CASCADE%TYPE;
+v_BaseAmount C_TAX.BASEAMOUNT%TYPE;
+v_TaxBase_ID C_TAX.C_TAXBASE_ID%TYPE;
+v_Line C_TAX.LINE%TYPE;
 v_Processed   VARCHAR(60);
 v_Increment_Amount C_ORDERTAX.TAXAMT%TYPE ;
 v_Increment_Base C_ORDERTAX.TAXBASEAMT%TYPE ;
-v_istaxincluded CHAR(1);
+v_IsTaxIncluded M_PRICELIST.IsTaxIncluded%TYPE;
     
 BEGIN
     
@@ -49,17 +53,18 @@
       v_C_Invoice_ID:=:OLD.C_INVOICE_ID;
     END IF;
 
-    SELECT C_CURRENCY.STDPRECISION, PROCESSED,  M_PRICELIST.istaxincluded
-    INTO v_Prec, v_Processed, v_istaxincluded
+    SELECT C_CURRENCY.STDPRECISION, PROCESSED, M_PRICELIST.ISTAXINCLUDED
+    INTO v_Prec, v_Processed, v_IsTaxIncluded
     FROM C_INVOICE, C_CURRENCY, M_PRICELIST
     WHERE C_INVOICE.C_CURRENCY_ID = C_CURRENCY.C_CURRENCY_ID
     AND C_INVOICE.M_PRICELIST_ID = M_PRICELIST.M_PRICELIST_ID
     AND C_INVOICE_ID = v_C_Invoice_ID;
     
-    SELECT DOCTAXAMOUNT, RATE
-    INTO v_DocTaxAmount, v_Rate
+    SELECT DocTaxAmount, Rate, Cascade, BaseAmount, C_TaxBase_ID, Line
+    INTO v_DocTaxAmount, v_Rate, v_Cascade, v_BaseAmount, v_TaxBase_ID, v_Line
     FROM C_TAX
     WHERE C_TAX_ID = v_C_Tax_ID;
+
   IF ( INSERTING ) THEN
     v_Increment_Amount := :NEW.TAXAMT ;
     v_Increment_Base := :NEW.TAXBASEAMT ;
@@ -72,15 +77,37 @@
   END IF;
 
   IF (INSERTING OR UPDATING) THEN
-    SELECT COUNT(C_TAX_ID), MAX(c_invoicetax_id) INTO v_Count, v_c_invoicetax_id
+    SELECT COUNT(C_TAX_ID), MAX(c_invoicetax_id) INTO v_Count, v_C_InvoiceTax_ID
     FROM C_INVOICETAX
-    WHERE C_INVOICE_ID = :NEW.C_Invoice_ID
-    AND C_TAX_ID = :NEW.C_TAX_ID
+    WHERE C_Invoice_ID = :new.C_Invoice_ID
+    AND C_Tax_ID = :new.C_Tax_ID
     AND Recalculate = 'Y';
     IF(v_Count>0) THEN
-      UPDATE C_INVOICETAX SET TAXAMT = (CASE WHEN v_DocTaxAmount='D' THEN ROUND((TAXBASEAMT + v_Increment_Base) * v_Rate/100, v_Prec) ELSE (TAXAMT + v_Increment_Amount) END), 
-      TAXBASEAMT=TAXBASEAMT + v_Increment_Base
-      WHERE C_INVOICETAX_ID = v_c_invoicetax_id;
+      IF (v_DocTaxAmount = 'D' AND (v_Cascade = 'Y' OR v_BaseAmount IN ('TAX', 'LNATAX', 'TBATAX'))) THEN
+        SELECT COALESCE(CASE WHEN MAX(it.TaxBaseAmt) > 0 THEN MAX(ROUND(it.TaxBaseAmt, v_Prec)) ELSE MIN(ROUND(it.TaxBaseAmt, v_Prec)) END + SUM(it.TaxAmt), 0)
+        INTO v_Increment_Base
+        FROM C_InvoiceTax it
+        JOIN C_Tax t
+        ON it.C_Tax_ID = t.C_Tax_ID
+        WHERE it.C_Invoice_ID = :new.C_Invoice_ID
+        AND c_tax_get_root(it.C_Tax_ID) = c_tax_get_root(:new.C_Tax_ID)
+        AND it.Recalculate = 'Y'
+        AND ((v_Cascade = 'Y'
+        AND t.Line < v_Line)
+        OR (v_BaseAmount IN ('TAX', 'LNATAX', 'TBATAX')
+        AND C_TAX_ISMEMBER(v_TaxBase_ID, t.C_Tax_ID) = 1
+        AND t.IsSummary = 'N'));
+
+        UPDATE C_INVOICETAX
+        SET TAXAMT = ROUND((v_Increment_Base) * v_Rate/100, v_Prec),
+        TAXBASEAMT = v_Increment_Base
+        WHERE C_InvoiceTax_ID = v_C_InvoiceTax_ID;
+      ELSE
+        UPDATE C_INVOICETAX
+        SET TAXAMT = CASE WHEN v_DocTaxAmount='D' THEN ROUND(ROUND(TAXBASEAMT + v_Increment_Base, v_Prec) * v_Rate/100, v_Prec) ELSE (TAXAMT + v_Increment_Amount) END,
+        TAXBASEAMT = TAXBASEAMT + v_Increment_Base
+        WHERE C_InvoiceTax_ID = v_C_InvoiceTax_ID;
+      END IF;
     ELSE
       SELECT COALESCE(MAX(LINE),0) + 10
       INTO v_LineNo
@@ -100,15 +127,41 @@
   IF (v_Processed='Y') THEN 
     RAISE_APPLICATION_ERROR(-20000, '@20501@') ;
   ELSE
-    UPDATE C_INVOICETAX SET TAXAMT = (CASE WHEN v_DocTaxAmount='D' THEN ROUND((TAXBASEAMT - :OLD.TAXBASEAMT) * v_Rate/100, v_Prec) ELSE (TAXAMT - :OLD.TAXAMT) END), TAXBASEAMT=TAXBASEAMT - :OLD.TAXBASEAMT
-    WHERE C_INVOICE_ID = :OLD.C_Invoice_ID
-    AND C_TAX_ID = :OLD.C_TAX_ID
-    AND Recalculate = 'Y';
-    
+    IF (v_DocTaxAmount = 'D' AND (v_Cascade = 'Y' OR v_BaseAmount IN ('TAX', 'LNATAX', 'TBATAX'))) THEN
+      SELECT COALESCE(CASE WHEN MAX(it.TaxBaseAmt) > 0 THEN MAX(ROUND(it.TaxBaseAmt, v_Prec)) ELSE MIN(ROUND(it.TaxBaseAmt, v_Prec)) END + SUM(it.TaxAmt), 0)
+      INTO v_Increment_Base
+      FROM C_InvoiceTax it
+      JOIN C_Tax t
+      ON it.C_Tax_ID = t.C_Tax_ID
+      WHERE it.C_Invoice_ID = :old.C_Invoice_ID
+      AND c_tax_get_root(it.C_Tax_ID) = c_tax_get_root(:old.C_Tax_ID)
+      AND it.Recalculate = 'Y'
+      AND ((v_Cascade = 'Y'
+      AND t.Line < v_Line)
+      OR (v_BaseAmount IN ('TAX', 'LNATAX', 'TBATAX')
+      AND C_TAX_ISMEMBER(v_TaxBase_ID, t.C_Tax_ID) = 1
+      AND t.IsSummary = 'N'));
+
+      UPDATE C_INVOICETAX
+      SET TAXAMT = ROUND(v_Increment_Base * v_Rate/100, v_Prec),
+      TAXBASEAMT = v_Increment_Base
+      WHERE C_Invoice_ID = :old.C_Invoice_ID
+      AND C_Tax_ID = :old.C_Tax_ID
+      AND Recalculate = 'Y';
+    ELSE
+      UPDATE C_INVOICETAX
+      SET TAXAMT = CASE WHEN v_DocTaxAmount = 'D' THEN ROUND(ROUND(TAXBASEAMT - :OLD.TAXBASEAMT, v_Prec) * v_Rate/100, v_Prec) ELSE (TAXAMT - :OLD.TAXAMT) END,
+      TAXBASEAMT = TAXBASEAMT - :OLD.TAXBASEAMT
+      WHERE C_Invoice_ID = :old.C_Invoice_ID
+      AND C_Tax_ID = :old.C_Tax_ID
+      AND Recalculate = 'Y';
+    END IF;
+
     DELETE FROM C_INVOICETAX 
     WHERE C_INVOICE_ID = :OLD.C_Invoice_ID
     AND C_TAX_ID = :OLD.C_TAX_ID
-    AND TAXAMT=0 AND TAXBASEAMT=0;
+    AND ROUND(TAXBASEAMT, v_Prec) = 0
+    AND TAXAMT = 0;
     
   END IF;
 END IF;
--- a/src-db/database/model/triggers/C_INVOICELINE_BEFORE_TRG.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/triggers/C_INVOICELINE_BEFORE_TRG.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -40,6 +40,7 @@
   v_PriceLine NUMBER;
   v_CalcLine NUMBER;
   v_execute CHAR(1):='N';
+  v_DocTaxAmount C_TAX.DocTaxAmount%TYPE;
           
   TYPE RECORD IS REF CURSOR;
   Cur_BOM RECORD;  
@@ -68,6 +69,7 @@
           v_execute:='Y';
     ELSIF(UPDATING) THEN
         IF(:old.LineNetAmt <> :new.LineNetAmt
+          OR :old.Line_Gross_Amount <> :new.Line_Gross_Amount
           OR :old.gross_unit_price <> :new.gross_unit_price
           OR :old.c_tax_id <> :new.c_tax_id
           OR :old.qtyinvoiced <> :new.qtyinvoiced) THEN
@@ -119,16 +121,26 @@
         v_PriceActual := v_NetActual / :new.qtyinvoiced;     
       ELSE
         -- Regular taxes
-        v_NetActual := C_GET_NET_AMOUNT_FROM_GROSS(:new.c_tax_id, :new.line_gross_amount, :new.taxbaseamt, v_std_Prec);
-        v_PriceActual := ROUND(v_NetActual / :new.qtyinvoiced, v_price_prec);
+        SELECT COALESCE(MIN(DocTaxAmount), 'L') INTO v_DocTaxAmount FROM C_Tax WHERE (C_Tax_ID = :new.C_Tax_ID OR Parent_Tax_ID = :new.C_Tax_ID) AND IsSummary = 'N';
+        IF (v_DocTaxAmount = 'D') THEN
+          v_NetActual := C_GET_NET_AMOUNT_FROM_GROSS(:new.c_tax_id, :new.line_gross_amount, :new.taxbaseamt);
+        ELSE
+          v_NetActual := C_GET_NET_AMOUNT_FROM_GROSS(:new.c_tax_id, :new.line_gross_amount, :new.taxbaseamt, v_std_Prec);
+        END IF;
+        IF (:new.qtyinvoiced <> 0) THEN
+          v_PriceActual := ROUND(ROUND(v_NetActual, v_std_Prec) / :new.qtyinvoiced, v_price_prec);
+        ELSE
+          v_PriceActual := 0;
+        END IF;
       END IF;      
       
       :NEW.pricestd := v_priceactual;
       :NEW.pricelist := v_priceactual;
       :NEW.pricelimit := v_priceactual;
       :NEW.priceactual := v_priceactual;
-      :new.taxbaseamt := v_NetActual;
+      :new.taxbaseamt := ROUND(v_NetActual, v_std_Prec);
       :new.LineNetAmt := v_NetActual;
+
     END IF;
   END IF;
 
--- a/src-db/database/model/triggers/C_INVOICELINE_TRG2.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/triggers/C_INVOICELINE_TRG2.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -22,13 +22,16 @@
 
 
   v_Processed C_ORDER.PROCESSED%TYPE;
-  v_ID VARCHAR2(32);
+  v_ID C_INVOICELINE.C_INVOICE_ID%TYPE;
   v_oldLine NUMBER;
   v_newLineNetAmt NUMBER;
   v_newLineAlternate NUMBER;
-  v_taxAmt NUMBER;
+  v_taxBaseAmt C_INVOICETAX.TAXBASEAMT%TYPE;
+  v_taxAmt C_INVOICETAX.TAXAMT%TYPE;
   v_Prec C_CURRENCY.STDPRECISION%TYPE;
   v_PricePrec C_CURRENCY.PRICEPRECISION%TYPE;
+  v_DocTaxAmount C_TAX.DocTaxAmount%TYPE;
+
   v_istaxincluded CHAR(1) ;
   v_oldGrossAmt NUMBER:=0;
   v_newGrossAmt NUMBER:=0;
@@ -54,7 +57,6 @@
   
   v_PriceLine NUMBER;
   v_CalcLine NUMBER;
-  v_maxline NUMBER;    
           
   TYPE RECORD IS REF CURSOR;
   Cur_BOM RECORD;          
@@ -67,9 +69,9 @@
 -- This trigger is used for calculate the applied offers f0r the invoice
 
 IF (DELETING) THEN
-  v_ID:=:OLD.C_INVOICE_ID;
+  v_ID := :OLD.C_INVOICE_ID;
 ELSE
-  v_ID:=:NEW.C_INVOICE_ID;
+  v_ID := :NEW.C_INVOICE_ID;
 END IF;
  IF INSERTING OR UPDATING THEN
    IF (:new.c_orderline_id IS NULL) THEN
@@ -167,8 +169,12 @@
           v_LineAlternate := v_BaseLineAlternate - v_LineAlternateAcum;
         END IF;
         IF (v_istaxincluded = 'Y') THEN
-          v_CalcLine := C_GET_NET_AMOUNT_FROM_GROSS(Cur_BOM.TAX, v_Line, v_LineAlternate, v_Prec);
-          select coalesce(max(line), 0) into v_maxline from c_invoicelinetax where c_invoiceline_id = :new.C_InvoiceLine_ID;
+          SELECT COALESCE(MIN(DocTaxAmount), 'L') INTO v_DocTaxAmount FROM C_Tax WHERE (C_Tax_ID = Cur_BOM.TAX OR Parent_Tax_ID = Cur_BOM.TAX) AND IsSummary = 'N';
+          IF (v_DocTaxAmount = 'D') THEN
+            v_CalcLine := C_GET_NET_AMOUNT_FROM_GROSS(Cur_BOM.TAX, v_Line, v_LineAlternate);
+          ELSE
+            v_CalcLine := C_GET_NET_AMOUNT_FROM_GROSS(Cur_BOM.TAX, v_Line, v_LineAlternate, v_Prec);
+          END IF;
           C_INVOICELINETAX_INSERT(:new.AD_Org_ID, :new.C_Invoice_ID, :new.C_InvoiceLine_ID, :new.UpdatedBy, Cur_BOM.TAX, Cur_BOM.TAX, v_CalcLine, v_CalcLine, v_Prec);
         ELSE
           C_INVOICELINETAX_INSERT(:new.AD_Org_ID, :new.C_Invoice_ID, :new.C_InvoiceLine_ID, :new.UpdatedBy, Cur_BOM.TAX, Cur_BOM.TAX, v_Line, v_LineAlternate, v_Prec);
@@ -177,56 +183,49 @@
     ELSE
       -- Regular taxes
       C_INVOICELINETAX_INSERT(:new.AD_Org_ID, :new.C_Invoice_ID, :new.C_InvoiceLine_ID, :new.UpdatedBy, :new.C_Tax_ID, :new.C_Tax_ID, v_newLineNetAmt, v_newLineAlternate, v_Prec);    
-    END IF;  
-
+    END IF;
     IF (v_istaxincluded = 'Y') THEN
-      C_INVOICELINETAX_ROUNDING(:new.C_InvoiceLine_ID, :new.line_gross_amount, v_newLineNetAmt);
-    END IF;  
+      C_INVOICELINETAX_ROUNDING(:new.C_InvoiceLine_ID, :new.line_gross_amount, ROUND(v_newLineNetAmt, v_Prec));
+    END IF;
               
    END IF;
-  -- Get Total Tax Amt
-   SELECT SUM(TaxAmt)
-     INTO v_taxAmt
-   FROM C_InvoiceTax
-   WHERE C_Invoice_ID=:new.C_Invoice_ID;
+   -- Get Total Tax Base Amt and Tax Amt
+   SELECT COALESCE(SUM(it.TaxBaseAmt), 0), COALESCE(SUM(it.TaxAmt), 0)
+   INTO v_taxBaseAmt, v_taxAmt
+   FROM (
+     SELECT CASE WHEN MIN(it.TaxBaseAmt) > 0 THEN MIN(ROUND(it.TaxBaseAmt, v_Prec)) ELSE MAX(ROUND(it.TaxBaseAmt, v_Prec)) END as TaxBaseAmt, SUM(it.TaxAmt) as TaxAmt
+     FROM C_InvoiceTax it
+     WHERE it.C_Invoice_ID = :new.C_Invoice_ID
+     GROUP BY c_tax_get_root(it.c_tax_id)
+   ) it;
   -- DBMS_OUTPUT.PUT_LINE('TaxAmt = ' || v_taxAmt);
    -- Update Header
-       -- Get Total Tax Amt
    UPDATE C_Invoice
-     SET TotalLines = TotalLines - v_oldLine + v_newLineNetAmt,
-     GrandTotal = CASE v_istaxincluded
-                     WHEN 'Y' THEN grandtotal - v_oldgrossamt + v_newgrossamt
-                     ELSE TotalLines - v_oldLine + v_newLineNetAmt + COALESCE(v_taxAmt, 0)
-                  END
-   --  Updated = SysDate -- Don't update as otherwise it does not save changes
+   SET TotalLines = CASE WHEN v_istaxincluded = 'Y' THEN CASE WHEN v_taxAmt = 0 THEN grandtotal - v_oldgrossamt + v_newgrossamt ELSE v_taxBaseAmt END ELSE TotalLines - v_oldLine + v_newLineNetAmt END,
+   GrandTotal = CASE WHEN v_istaxincluded = 'Y' THEN grandtotal - v_oldgrossamt + v_newgrossamt ELSE TotalLines - v_oldLine + v_newLineNetAmt + v_taxAmt END
    WHERE C_Invoice_ID = :new.C_Invoice_ID;
    END IF;
   ELSE -- DELETING
    IF (v_istaxincluded = 'Y') THEN
      v_oldgrossamt := :old.line_gross_amount;
    END IF;
-   SELECT SUM(TaxAmt)
-     INTO v_taxAmt
-   FROM C_InvoiceTax
-   WHERE C_Invoice_ID=:old.C_Invoice_ID;
+   -- Get Total Tax Base Amt and Tax Amt
+   SELECT COALESCE(SUM(it.TaxBaseAmt), 0), COALESCE(SUM(it.TaxAmt), 0)
+   INTO v_taxBaseAmt, v_taxAmt
+   FROM (
+     SELECT CASE WHEN MIN(it.TaxBaseAmt) > 0 THEN MIN(ROUND(it.TaxBaseAmt, v_Prec)) ELSE MAX(ROUND(it.TaxBaseAmt, v_Prec)) END as TaxBaseAmt, SUM(it.TaxAmt) as TaxAmt
+     FROM C_InvoiceTax it
+     WHERE it.C_Invoice_ID = :old.C_Invoice_ID
+     GROUP BY c_tax_get_root(it.c_tax_id)
+   ) it;
   -- DBMS_OUTPUT.PUT_LINE('TaxAmt = ' || v_taxAmt);
    -- Update Header
    UPDATE C_Invoice
-     SET TotalLines = TotalLines - v_oldLine + v_newLineNetAmt,
-     GrandTotal = CASE v_istaxincluded
-                       WHEN 'Y' THEN grandtotal - v_oldgrossamt
-                       ELSE TotalLines - v_oldLine + v_newLineNetAmt + COALESCE(v_taxAmt, 0)
-                  END
-   --  Updated = SysDate -- Don't update as otherwise it does not save changes
+   SET TotalLines = CASE WHEN v_istaxincluded = 'Y' THEN CASE WHEN v_taxAmt = 0 THEN grandtotal - v_oldgrossamt ELSE v_taxBaseAmt END ELSE TotalLines - v_oldLine + v_newLineNetAmt END,
+   GrandTotal = CASE WHEN v_istaxincluded = 'Y' THEN grandtotal - v_oldgrossamt ELSE TotalLines - v_oldLine + v_newLineNetAmt + v_taxAmt END
    WHERE C_Invoice_ID=:old.C_Invoice_ID;
   END IF;
-  IF (v_istaxincluded = 'Y') THEN
-    SELECT totallines, grandtotal INTO v_totallines, v_grandtotal
-    FROM C_invoice
-    WHERE c_invoice_id = v_id;
-    C_INVOICETAX_ROUNDING(v_id, v_grandtotal, v_totallines);
-  END IF;
-   
+
  END IF;
 
 
--- a/src-db/database/model/triggers/C_ORDERLINETAX_TRG.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/triggers/C_ORDERLINETAX_TRG.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -17,7 +17,7 @@
   * parts created by ComPiere are Copyright (C) ComPiere, Inc.;
   * All Rights Reserved.
   * Contributor(s): Openbravo SLU
-  * Contributions are Copyright (C) 2010-2014 Openbravo, S.L.U.
+  * Contributions are Copyright (C) 2010-2017 Openbravo, S.L.U.
   *
   * Specifically, this derivative work is based upon the following Compiere
   * file and version.
@@ -27,11 +27,17 @@
 v_LineNo  NUMBER;
 v_C_Order_ID C_ORDERLINETAX.C_ORDER_ID%TYPE;
 v_C_Tax_ID C_ORDERLINETAX.C_TAX_ID%TYPE;
+v_C_OrderTax_ID C_ORDERTAX.C_ORDERTAX_ID%TYPE;
 v_Prec C_CURRENCY.STDPRECISION%TYPE;
 v_DocTaxAmount C_TAX.DOCTAXAMOUNT%TYPE;
 v_Rate  C_TAX.RATE%TYPE;
+v_Cascade C_TAX.CASCADE%TYPE;
+v_BaseAmount C_TAX.BASEAMOUNT%TYPE;
+v_TaxBase_ID C_TAX.C_TAXBASE_ID%TYPE;
+v_Line C_TAX.LINE%TYPE;
 v_Increment_Amount C_ORDERTAX.TAXAMT%TYPE ;
 v_Increment_Base C_ORDERTAX.TAXBASEAMT%TYPE ;
+v_IsTaxIncluded M_PRICELIST.IsTaxIncluded%TYPE;
 v_Processed VARCHAR(60) ;
 v_DocAction VARCHAR(60);
 BEGIN
@@ -47,14 +53,15 @@
       v_C_Order_ID:=:OLD.C_ORDER_ID;
     END IF;
 
-    SELECT C_CURRENCY.STDPRECISION
-    INTO v_Prec
-    FROM C_ORDER, C_CURRENCY
+    SELECT C_CURRENCY.STDPRECISION, M_PRICELIST.ISTAXINCLUDED
+    INTO v_Prec, v_IsTaxIncluded
+    FROM C_ORDER, C_CURRENCY, M_PRICELIST
     WHERE C_ORDER.C_CURRENCY_ID = C_CURRENCY.C_CURRENCY_ID
+    AND C_ORDER.M_PRICELIST_ID = M_PRICELIST.M_PRICELIST_ID
     AND C_ORDER_ID = v_C_Order_ID;
     
-    SELECT DOCTAXAMOUNT, RATE
-    INTO v_DocTaxAmount, v_Rate
+    SELECT DocTaxAmount, Rate, Cascade, BaseAmount, C_TaxBase_ID, Line
+    INTO v_DocTaxAmount, v_Rate, v_Cascade, v_BaseAmount, v_TaxBase_ID, v_Line
     FROM C_TAX
     WHERE C_TAX_ID = v_C_Tax_ID;
 
@@ -70,17 +77,35 @@
   END IF;
     
   IF (INSERTING OR UPDATING) THEN
-    SELECT COUNT(1) INTO v_Count
+    SELECT COUNT(C_TAX_ID), MAX(c_ordertax_id) INTO v_Count, v_C_OrderTax_ID
     FROM C_ORDERTAX
-    WHERE C_ORDER_ID = :NEW.C_Order_ID
-    AND C_TAX_ID = :NEW.C_TAX_ID;
+    WHERE C_Order_ID = :new.C_Order_ID
+    AND C_Tax_ID = :new.C_Tax_ID;
     IF(v_Count>0) THEN
-      UPDATE C_ORDERTAX
-      SET TAXAMT = (CASE WHEN v_DocTaxAmount='D' THEN ROUND((TAXBASEAMT + v_Increment_Base) * v_Rate/100, v_Prec) ELSE (TAXAMT + v_Increment_Amount) END),
-          TAXBASEAMT=TAXBASEAMT + v_Increment_Base
-      WHERE C_ORDER_ID = :NEW.C_Order_ID
-        AND C_TAX_ID = :NEW.C_TAX_ID;
+      IF (v_DocTaxAmount = 'D' AND (v_Cascade = 'Y' OR v_BaseAmount IN ('TAX', 'LNATAX', 'TBATAX'))) THEN
+        SELECT COALESCE(CASE WHEN MAX(ot.TaxBaseAmt) > 0 THEN MAX(ROUND(ot.TaxBaseAmt, v_Prec)) ELSE MIN(ROUND(ot.TaxBaseAmt, v_Prec)) END + SUM(ot.TaxAmt), 0)
+        INTO v_Increment_Base
+        FROM C_OrderTax ot
+        JOIN C_Tax t
+        ON ot.C_Tax_ID = t.C_Tax_ID
+        WHERE ot.C_Order_ID = :new.C_Order_ID
+        AND c_tax_get_root(ot.C_Tax_ID) = c_tax_get_root(:new.C_Tax_ID)
+        AND ((v_Cascade = 'Y'
+        AND t.Line < v_Line)
+        OR (v_BaseAmount IN ('TAX', 'LNATAX', 'TBATAX')
+        AND C_TAX_ISMEMBER(v_TaxBase_ID, t.C_Tax_ID) = 1
+        AND t.IsSummary = 'N'));
 
+        UPDATE C_ORDERTAX
+        SET TAXAMT = ROUND(v_Increment_Base * v_Rate/100, v_Prec),
+        TAXBASEAMT = v_Increment_Base
+        WHERE C_OrderTax_ID = v_C_OrderTax_ID;
+      ELSE
+        UPDATE C_ORDERTAX
+        SET TAXAMT = CASE WHEN v_DocTaxAmount='D' THEN ROUND(ROUND(TAXBASEAMT + v_Increment_Base, v_Prec) * v_Rate/100, v_Prec) ELSE (TAXAMT + v_Increment_Amount) END,
+        TAXBASEAMT = TAXBASEAMT + v_Increment_Base
+        WHERE C_OrderTax_ID = v_C_OrderTax_ID;
+      END IF;
     ELSE
       SELECT COALESCE(MAX(LINE),0) + 10
       INTO v_LineNo
@@ -106,14 +131,37 @@
     IF (v_Processed='Y' AND v_DocAction <> 'CL') THEN
 	RAISE_APPLICATION_ERROR(-20000, '@20501@') ;
     END IF;
-    UPDATE C_ORDERTAX SET TAXAMT = (CASE WHEN v_DocTaxAmount='D' THEN ROUND((TAXBASEAMT - :OLD.TAXBASEAMT) * v_Rate/100, v_Prec) ELSE (TAXAMT - :OLD.TAXAMT) END), TAXBASEAMT=TAXBASEAMT - :OLD.TAXBASEAMT
-    WHERE C_ORDER_ID = :OLD.C_Order_ID
-    AND C_TAX_ID = :OLD.C_TAX_ID;
-    
+    IF (v_DocTaxAmount = 'D' AND (v_Cascade = 'Y' OR v_BaseAmount IN ('TAX', 'LNATAX', 'TBATAX'))) THEN
+      SELECT COALESCE(CASE WHEN MAX(ot.TaxBaseAmt) > 0 THEN MAX(ROUND(ot.TaxBaseAmt, v_Prec)) ELSE MIN(ROUND(ot.TaxBaseAmt, v_Prec)) END + SUM(ot.TaxAmt), 0)
+      INTO v_Increment_Base
+      FROM C_OrderTax ot
+      JOIN C_Tax t
+      ON ot.C_Tax_ID = t.C_Tax_ID
+      WHERE ot.C_Order_ID = :old.C_Order_ID
+      AND c_tax_get_root(ot.C_Tax_ID) = c_tax_get_root(:old.C_Tax_ID)
+      AND ((v_Cascade = 'Y'
+      AND t.Line < v_Line)
+      OR (v_BaseAmount IN ('TAX', 'LNATAX', 'TBATAX')
+      AND C_TAX_ISMEMBER(v_TaxBase_ID, t.C_Tax_ID) = 1
+      AND t.IsSummary = 'N'));
+
+      UPDATE C_ORDERTAX
+      SET TAXAMT = ROUND(v_Increment_Base * v_Rate/100, v_Prec),
+      TAXBASEAMT = v_Increment_Base
+      WHERE C_Order_ID = :old.C_Order_ID
+      AND C_Tax_ID = :old.C_Tax_ID;
+    ELSE
+      UPDATE C_ORDERTAX
+      SET TAXAMT = CASE WHEN v_DocTaxAmount = 'D' THEN ROUND(ROUND(TAXBASEAMT - :OLD.TAXBASEAMT, v_Prec) * v_Rate/100, v_Prec) ELSE (TAXAMT - :OLD.TAXAMT) END,
+      TAXBASEAMT = TAXBASEAMT - :OLD.TAXBASEAMT
+      WHERE C_Order_ID = :OLD.C_Order_ID
+      AND C_Tax_ID = :OLD.C_Tax_ID;
+    END IF;
     DELETE FROM C_ORDERTAX 
     WHERE C_ORDER_ID = :OLD.C_Order_ID
     AND C_TAX_ID = :OLD.C_TAX_ID
-    AND TAXAMT=0 AND TAXBASEAMT=0;
+    AND ROUND(TAXBASEAMT, v_Prec) = 0
+    AND TAXAMT = 0;
   END IF;
 END C_ORDERLINETAX_TRG
 ]]></body>
--- a/src-db/database/model/triggers/C_ORDERLINE_TRG.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/triggers/C_ORDERLINE_TRG.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -47,7 +47,8 @@
   v_NetActual NUMBER;
   v_PriceLine NUMBER;
   v_CalcLine NUMBER;
-          
+  v_DocTaxAmount C_TAX.DocTaxAmount%TYPE;
+
   TYPE RECORD IS REF CURSOR;
   Cur_BOM RECORD;
 
@@ -229,16 +230,26 @@
       v_PriceActual := ROUND(v_NetActual / :new.qtyordered, v_price_prec);     
     ELSE
       -- Regular taxes
-      v_NetActual := C_GET_NET_AMOUNT_FROM_GROSS(:new.c_tax_id, :new.line_gross_amount, :new.taxbaseamt, v_Prec);
-      v_PriceActual := ROUND(v_NetActual / :NEW.qtyordered, v_price_prec);
+      SELECT COALESCE(MIN(DocTaxAmount), 'L') INTO v_DocTaxAmount FROM C_Tax WHERE (C_Tax_ID = :new.C_Tax_ID OR Parent_Tax_ID = :new.C_Tax_ID) AND IsSummary = 'N';
+      IF (v_DocTaxAmount = 'D') THEN
+        v_NetActual := C_GET_NET_AMOUNT_FROM_GROSS(:new.c_tax_id, :new.line_gross_amount, :new.taxbaseamt);
+      ELSE
+        v_NetActual := C_GET_NET_AMOUNT_FROM_GROSS(:new.c_tax_id, :new.line_gross_amount, :new.taxbaseamt, v_Prec);
+      END IF;
+      IF (:new.qtyordered <> 0) THEN
+        v_PriceActual := ROUND(ROUND(v_NetActual, v_Prec) / :new.qtyordered, v_price_prec);
+      ELSE
+        v_PriceActual := 0;
+      END IF;
     END IF;      
     
     :NEW.pricestd := v_priceactual;
     :NEW.pricelist := v_priceactual;
     :NEW.pricelimit := v_priceactual;
     :NEW.priceactual := v_priceactual;
-    :new.taxbaseamt := v_NetActual;
+    :new.taxbaseamt := ROUND(v_NetActual, v_Prec);
     :new.LineNetAmt := v_NetActual;
+
   ELSE
     -- Price including taxes = 'N'
     -- Modified by I.Ciordia. Sometimes js fails calculting lineNet
--- a/src-db/database/model/triggers/C_ORDERLINE_TRG2.xml	Thu Feb 16 12:58:57 2017 +0100
+++ b/src-db/database/model/triggers/C_ORDERLINE_TRG2.xml	Fri Mar 03 14:08:55 2017 +0100
@@ -26,18 +26,18 @@
 
   v_istaxincluded CHAR(1) ;
   v_Processed C_ORDER.PROCESSED%TYPE;
-  v_ID VARCHAR2(32);
+  v_ID C_ORDERLINE.C_ORDER_ID%TYPE;
   v_oldLine NUMBER;
   v_newLineNetAmt NUMBER;
   v_newLineAlternate NUMBER;
   v_oldGrossAmt NUMBER:=0;
   v_newGrossAmt NUMBER:=0;
-  v_totallines NUMBER:=0;
-  v_grandtotal NUMBER:=0;
-  v_taxAmt NUMBER;
+  v_taxBaseAmt C_ORDERTAX.TAXBASEAMT%TYPE;
+  v_taxAmt C_ORDERTAX.TAXAMT%TYPE;
   v_Prec C_CURRENCY.STDPRECISION%TYPE;
   v_PricePrec C_CURRENCY.PRICEPRECISION%TYPE;
   v_AttrSetValueType M_Product.AttrSetValueType%TYPE;
+  v_DocTaxAmount C_TAX.DocTaxAmount%TYPE;
 
   v_oldLineAlternate NUMBER;
   v_create CHAR(1):='Y';
@@ -59,7 +59,6 @@
   
   v_PriceLine NUMBER;
   v_CalcLine NUMBER;
-  v_maxline NUMBER;
           
   TYPE RECORD IS REF CURSOR;
   Cur_BOM RECORD;        
@@ -69,9 +68,9 @@
     END IF;
 
 IF (DELETING) THEN
-  v_ID:=:OLD.C_ORDER_ID;
+  v_ID := :OLD.C_ORDER_ID;
 ELSE
-  v_ID:=:NEW.C_ORDER_ID;
+  v_ID := :NEW.C_ORDER_ID;
 END IF;
 
 IF (UPDATING) THEN
@@ -179,8 +178,12 @@
           v_LineAlternate := v_BaseLineAlternate - v_LineAlternateAcum;
         END IF;
         IF (v_istaxincluded = 'Y') THEN
-          v_CalcLine := C_GET_NET_AMOUNT_FROM_GROSS(Cur_BOM.TAX, v_Line, v_LineAlternate, v_Prec);
-          select coalesce(max(line), 0) into v_maxline from c_orderlinetax where c_orderline_id = :new.C_OrderLine_ID;
+          SELECT COALESCE(MIN(DocTaxAmount), 'L') INTO v_DocTaxAmount FROM C_Tax WHERE (C_Tax_ID = Cur_BOM.TAX OR Parent_Tax_ID = Cur_BOM.TAX) AND IsSummary = 'N';
+          IF (v_DocTaxAmount = 'D') THEN
+            v_CalcLine := C_GET_NET_AMOUNT_FROM_GROSS(Cur_BOM.TAX, v_Line, v_LineAlternate);
+          ELSE
+            v_CalcLine := C_GET_NET_AMOUNT_FROM_GROSS(Cur_BOM.TAX, v_Line, v_LineAlternate, v_Prec);
+          END IF;
           C_ORDERLINETAX_INSERT(:new.AD_Org_ID, :new.C_Order_ID, :new.C_OrderLine_ID, :new.UpdatedBy, Cur_BOM.TAX, Cur_BOM.TAX, v_CalcLine, v_CalcLine, v_Prec);
         ELSE
           C_ORDERLINETAX_INSERT(:new.AD_Org_ID, :new.C_Order_ID, :new.C_OrderLine_ID, :new.UpdatedBy, Cur_BOM.TAX, Cur_BOM.TAX, v_Line, v_LineAlternate, v_Prec);
@@ -190,45 +193,43 @@
       -- Regular taxes
       C_ORDERLINETAX_INSERT(:new.AD_Org_ID, :new.C_Order_ID, :new.C_OrderLine_ID, :new.UpdatedBy, :new.C_Tax_ID, :new.C_Tax_ID, v_newLineNetAmt, v_newLineAlternate, v_Prec);    
     END IF;
-    
     IF (v_istaxincluded = 'Y') THEN
-      C_ORDERLINETAX_ROUNDING(:new.C_OrderLine_ID, :new.line_gross_amount, v_newLineNetAmt);
+      C_ORDERLINETAX_ROUNDING(:new.C_OrderLine_ID, :new.line_gross_amount, ROUND(v_newLineNetAmt, v_Prec));
     END IF;
 
-    -- Get Total Tax Amt
-    SELECT SUM(TaxAmt) INTO v_taxAmt
-    FROM C_OrderTax
-    WHERE C_Order_ID=:new.C_Order_ID;
+    -- Get Total Tax Base Amt and Tax Amt
+    SELECT COALESCE(SUM(ot.TaxBaseAmt), 0), COALESCE(SUM(ot.TaxAmt), 0)
+    INTO v_taxBaseAmt, v_taxAmt
+    FROM (
+      SELECT CASE WHEN MIN(ot.TaxBaseAmt) > 0 THEN MIN(ROUND(ot.TaxBaseAmt, v_Prec)) ELSE MAX(ROUND(ot.TaxBaseAmt, v_Prec)) END as TaxBaseAmt, SUM(ot.TaxAmt) as TaxAmt
+      FROM C_OrderTax ot
+      WHERE ot.C_Order_ID = :new.C_Order_ID
+      GROUP BY c_tax_get_root(ot.c_tax_id)
+    ) ot;
     -- DBMS_OUTPUT.PUT_LINE('TaxAmt = ' || v_taxAmt);
     -- Update Header
     UPDATE C_Order
-    SET TotalLines = TotalLines - v_oldLine + v_newLineNetAmt,
-        GrandTotal = CASE v_istaxincluded
-                       WHEN 'Y' THEN grandtotal - v_oldgrossamt + v_newgrossamt
-                       ELSE TotalLines - v_oldLine + v_newLineNetAmt + COALESCE(v_taxAmt, 0)
-                       END
-      WHERE C_Order_ID = :new.C_Order_ID;
+    SET TotalLines = CASE WHEN v_istaxincluded = 'Y' THEN CASE WHEN v_taxAmt = 0 THEN grandtotal - v_oldgrossamt + v_newgrossamt ELSE v_taxBaseAmt END ELSE TotalLines - v_oldLine + v_newLineNetAmt END,
+    GrandTotal = CASE WHEN v_istaxincluded = 'Y' THEN grandtotal - v_oldgrossamt + v_newgrossamt ELSE TotalLines - v_oldLine + v_newLineNetAmt + v_taxAmt END
+    WHERE C_Order_ID = :new.C_Order_ID;
     END IF;
   ELSE -- DELETING
-    SELECT SUM(TaxAmt) INTO v_taxAmt
-    FROM C_OrderTax
-    WHERE C_Order_ID=:old.C_Order_ID;
+    -- Get Total Tax Base Amt and Tax Amt
+    SELECT COALESCE(SUM(ot.TaxBaseAmt), 0), COALESCE(SUM(ot.TaxAmt), 0)
+    INTO v_taxBaseAmt, v_taxAmt
+    FROM (
+      SELECT CASE WHEN MIN(ot.TaxBaseAmt) > 0 THEN MIN(ROUND(ot.TaxBaseAmt, v_Prec)) ELSE MAX(ROUND(ot.TaxBaseAmt, v_Prec)) END as TaxBaseAmt, SUM(ot.TaxAmt) as TaxAmt
+      FROM C_OrderTax ot
+      WHERE ot.C_Order_ID = :old.C_Order_ID
+      GROUP BY c_tax_get_root(ot.c_tax_id)
+    ) ot;
     -- DBMS_OUTPUT.PUT_LINE('TaxAmt = ' || v_taxAmt);
     -- Update Header
     UPDATE C_Order
-    SET TotalLines = TotalLines - v_oldLine + v_newLineNetAmt,
-        GrandTotal = CASE v_istaxincluded
-                       WHEN 'Y' THEN grandtotal - v_oldgrossamt
-                       ELSE TotalLines - v_oldLine + v_newLineNetAmt + COALESCE(v_taxAmt, 0)
-                     END
+    SET TotalLines = CASE WHEN v_istaxincluded = 'Y' THEN CASE WHEN v_taxAmt = 0 THEN grandtotal - v_oldgrossamt ELSE v_taxBaseAmt END ELSE TotalLines - v_oldLine + v_newLineNetAmt END,
+    GrandTotal = CASE WHEN v_istaxincluded = 'Y' THEN grandtotal - v_oldgrossamt ELSE TotalLines - v_oldLine + v_newLineNetAmt + v_taxAmt END
     WHERE C_Order_ID=:old.C_Order_ID;
   END IF;
-  IF (v_istaxincluded = 'Y') THEN
-    SELECT totallines, grandtotal INTO v_totallines, v_grandtotal
-    FROM c_order
-    WHERE c_order_id = v_id;
-    C_ORDERTAX_ROUNDING(v_id, v_grandtotal, v_totallines);
-  END IF;
 
  IF (INSERTING OR UPDATING) THEN
   --Does not allow to change the attribute set value