BF [ 1733602 ] - Price List including Tax Error
http://sourceforge.net/tracker/?func=detail&aid=1733602&group_id=176962&atid=879332 This relates to order lines and invoice lines when the product or charge includes tax on the price list but the user changes the tax. In this case, we work out the tax component included in the price at the default rate for the tax category and then adjust it for the new tax rate applied.
This commit is contained in:
parent
79fe864fb5
commit
6f76307c6c
|
@ -40,6 +40,10 @@ import org.compiere.util.Msg;
|
||||||
* @author Teo Sarca, www.arhipac.ro
|
* @author Teo Sarca, www.arhipac.ro
|
||||||
* <li>BF [ 2804142 ] MInvoice.setRMALine should work only for CreditMemo invoices
|
* <li>BF [ 2804142 ] MInvoice.setRMALine should work only for CreditMemo invoices
|
||||||
* https://sourceforge.net/tracker/?func=detail&aid=2804142&group_id=176962&atid=879332
|
* https://sourceforge.net/tracker/?func=detail&aid=2804142&group_id=176962&atid=879332
|
||||||
|
* @author Michael Judd, www.akunagroup.com
|
||||||
|
* <li>BF [ 1733602 ] Price List including Tax Error - when a user changes the orderline or
|
||||||
|
* invoice line for a product on a price list that includes tax, the net amount is
|
||||||
|
* incorrectly calculated.
|
||||||
*/
|
*/
|
||||||
public class MInvoiceLine extends X_C_InvoiceLine
|
public class MInvoiceLine extends X_C_InvoiceLine
|
||||||
{
|
{
|
||||||
|
@ -97,6 +101,9 @@ public class MInvoiceLine extends X_C_InvoiceLine
|
||||||
/** Static Logger */
|
/** Static Logger */
|
||||||
private static CLogger s_log = CLogger.getCLogger (MInvoiceLine.class);
|
private static CLogger s_log = CLogger.getCLogger (MInvoiceLine.class);
|
||||||
|
|
||||||
|
/** Tax */
|
||||||
|
private MTax m_tax = null;
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Invoice Line Constructor
|
* Invoice Line Constructor
|
||||||
|
@ -157,6 +164,8 @@ public class MInvoiceLine extends X_C_InvoiceLine
|
||||||
private boolean m_IsSOTrx = true;
|
private boolean m_IsSOTrx = true;
|
||||||
private boolean m_priceSet = false;
|
private boolean m_priceSet = false;
|
||||||
private MProduct m_product = null;
|
private MProduct m_product = null;
|
||||||
|
/** Charge */
|
||||||
|
private MCharge m_charge = null;
|
||||||
|
|
||||||
/** Cached Name of the line */
|
/** Cached Name of the line */
|
||||||
private String m_name = null;
|
private String m_name = null;
|
||||||
|
@ -433,7 +442,7 @@ public class MInvoiceLine extends X_C_InvoiceLine
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculare Tax Amt.
|
* Calculate Tax Amt.
|
||||||
* Assumes Line Net is calculated
|
* Assumes Line Net is calculated
|
||||||
*/
|
*/
|
||||||
public void setTaxAmt ()
|
public void setTaxAmt ()
|
||||||
|
@ -461,11 +470,73 @@ public class MInvoiceLine extends X_C_InvoiceLine
|
||||||
public void setLineNetAmt ()
|
public void setLineNetAmt ()
|
||||||
{
|
{
|
||||||
// Calculations & Rounding
|
// Calculations & Rounding
|
||||||
BigDecimal net = getPriceActual().multiply(getQtyInvoiced());
|
BigDecimal bd = getPriceActual().multiply(getQtyInvoiced());
|
||||||
if (net.scale() > getPrecision())
|
|
||||||
net = net.setScale(getPrecision(), BigDecimal.ROUND_HALF_UP);
|
boolean documentLevel = getTax().isDocumentLevel();
|
||||||
super.setLineNetAmt (net);
|
|
||||||
|
// juddm: Tax Exempt & Tax Included in Price List & not Document Level - Adjust Line Amount
|
||||||
|
// http://sourceforge.net/tracker/index.php?func=detail&aid=1733602&group_id=176962&atid=879332
|
||||||
|
if (isTaxIncluded() && !documentLevel) {
|
||||||
|
BigDecimal taxStdAmt = Env.ZERO, taxThisAmt = Env.ZERO;
|
||||||
|
|
||||||
|
MTax invoiceTax = getTax();
|
||||||
|
MTax stdTax = null;
|
||||||
|
|
||||||
|
if (getProduct() == null)
|
||||||
|
{
|
||||||
|
if (getCharge() != null) // Charge
|
||||||
|
{
|
||||||
|
stdTax = new MTax (getCtx(),
|
||||||
|
((MTaxCategory) getCharge().getC_TaxCategory()).getDefaultTax().getC_Tax_ID(),
|
||||||
|
get_TrxName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else // Product
|
||||||
|
stdTax = new MTax (getCtx(),
|
||||||
|
((MTaxCategory) getProduct().getC_TaxCategory()).getDefaultTax().getC_Tax_ID(),
|
||||||
|
get_TrxName());
|
||||||
|
|
||||||
|
if (stdTax != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
log.fine("stdTax rate is " + stdTax.getRate());
|
||||||
|
log.fine("invoiceTax rate is " + invoiceTax.getRate());
|
||||||
|
|
||||||
|
taxThisAmt = taxThisAmt.add(invoiceTax.calculateTax(bd, isTaxIncluded(), getPrecision()));
|
||||||
|
taxStdAmt = taxStdAmt.add(stdTax.calculateTax(bd, isTaxIncluded(), getPrecision()));
|
||||||
|
|
||||||
|
bd = bd.subtract(taxStdAmt).add(taxThisAmt);
|
||||||
|
|
||||||
|
log.fine("Price List includes Tax and Tax Changed on Invoice Line: New Tax Amt: "
|
||||||
|
+ taxThisAmt + " Standard Tax Amt: " + taxStdAmt + " Line Net Amt: " + bd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bd.scale() > getPrecision())
|
||||||
|
bd = bd.setScale(getPrecision(), BigDecimal.ROUND_HALF_UP);
|
||||||
|
super.setLineNetAmt (bd);
|
||||||
} // setLineNetAmt
|
} // setLineNetAmt
|
||||||
|
/**
|
||||||
|
* Get Charge
|
||||||
|
* @return product or null
|
||||||
|
*/
|
||||||
|
public MCharge getCharge()
|
||||||
|
{
|
||||||
|
if (m_charge == null && getC_Charge_ID() != 0)
|
||||||
|
m_charge = MCharge.get (getCtx(), getC_Charge_ID());
|
||||||
|
return m_charge;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get Tax
|
||||||
|
* @return tax
|
||||||
|
*/
|
||||||
|
protected MTax getTax()
|
||||||
|
{
|
||||||
|
if (m_tax == null)
|
||||||
|
m_tax = MTax.get(getCtx(), getC_Tax_ID());
|
||||||
|
return m_tax;
|
||||||
|
} // getTax
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Qty Invoiced/Entered.
|
* Set Qty Invoiced/Entered.
|
||||||
|
@ -837,9 +908,16 @@ public class MInvoiceLine extends X_C_InvoiceLine
|
||||||
if (tax != null) {
|
if (tax != null) {
|
||||||
if (!tax.calculateTaxFromLines())
|
if (!tax.calculateTaxFromLines())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// red1 - solving BUGS #[ 1701331 ] , #[ 1786103 ]
|
// red1 - solving BUGS #[ 1701331 ] , #[ 1786103 ]
|
||||||
if (!tax.save(get_TrxName()))
|
if (tax.getTaxAmt().signum() != 0) {
|
||||||
return false;
|
if (!tax.save(get_TrxName()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!tax.is_new() && !tax.delete(false, get_TrxName()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,10 @@ import org.compiere.util.Msg;
|
||||||
*
|
*
|
||||||
* @author Teo Sarca, SC ARHIPAC SERVICE SRL
|
* @author Teo Sarca, SC ARHIPAC SERVICE SRL
|
||||||
* <li>BF [ 2588043 ] Insufficient message ProductNotOnPriceList
|
* <li>BF [ 2588043 ] Insufficient message ProductNotOnPriceList
|
||||||
|
* @author Michael Judd, www.akunagroup.com
|
||||||
|
* <li>BF [ 1733602 ] Price List including Tax Error - when a user changes the orderline or
|
||||||
|
* invoice line for a product on a price list that includes tax, the net amount is
|
||||||
|
* incorrectly calculated.
|
||||||
*/
|
*/
|
||||||
public class MOrderLine extends X_C_OrderLine
|
public class MOrderLine extends X_C_OrderLine
|
||||||
{
|
{
|
||||||
|
@ -197,10 +201,15 @@ public class MOrderLine extends X_C_OrderLine
|
||||||
// Product Pricing
|
// Product Pricing
|
||||||
private MProductPricing m_productPrice = null;
|
private MProductPricing m_productPrice = null;
|
||||||
|
|
||||||
|
/** Tax */
|
||||||
|
private MTax m_tax = null;
|
||||||
|
|
||||||
/** Cached Currency Precision */
|
/** Cached Currency Precision */
|
||||||
private Integer m_precision = null;
|
private Integer m_precision = null;
|
||||||
/** Product */
|
/** Product */
|
||||||
private MProduct m_product = null;
|
private MProduct m_product = null;
|
||||||
|
/** Charge */
|
||||||
|
private MCharge m_charge = null;
|
||||||
/** Parent */
|
/** Parent */
|
||||||
private MOrder m_parent = null;
|
private MOrder m_parent = null;
|
||||||
|
|
||||||
|
@ -352,11 +361,75 @@ public class MOrderLine extends X_C_OrderLine
|
||||||
public void setLineNetAmt ()
|
public void setLineNetAmt ()
|
||||||
{
|
{
|
||||||
BigDecimal bd = getPriceActual().multiply(getQtyOrdered());
|
BigDecimal bd = getPriceActual().multiply(getQtyOrdered());
|
||||||
|
|
||||||
|
boolean documentLevel = getTax().isDocumentLevel();
|
||||||
|
|
||||||
|
// juddm: Tax Exempt & Tax Included in Price List & not Document Level - Adjust Line Amount
|
||||||
|
// http://sourceforge.net/tracker/index.php?func=detail&aid=1733602&group_id=176962&atid=879332
|
||||||
|
if (isTaxIncluded() && !documentLevel) {
|
||||||
|
BigDecimal taxStdAmt = Env.ZERO, taxThisAmt = Env.ZERO;
|
||||||
|
|
||||||
|
MTax orderTax = getTax();
|
||||||
|
MTax stdTax = null;
|
||||||
|
|
||||||
|
// get the standard tax
|
||||||
|
if (getProduct() == null)
|
||||||
|
{
|
||||||
|
if (getCharge() != null) // Charge
|
||||||
|
{
|
||||||
|
stdTax = new MTax (getCtx(),
|
||||||
|
((MTaxCategory) getCharge().getC_TaxCategory()).getDefaultTax().getC_Tax_ID(),
|
||||||
|
get_TrxName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else // Product
|
||||||
|
stdTax = new MTax (getCtx(),
|
||||||
|
((MTaxCategory) getProduct().getC_TaxCategory()).getDefaultTax().getC_Tax_ID(),
|
||||||
|
get_TrxName());
|
||||||
|
|
||||||
|
if (stdTax != null)
|
||||||
|
{
|
||||||
|
log.fine("stdTax rate is " + stdTax.getRate());
|
||||||
|
log.fine("orderTax rate is " + orderTax.getRate());
|
||||||
|
|
||||||
|
taxThisAmt = taxThisAmt.add(orderTax.calculateTax(bd, isTaxIncluded(), getPrecision()));
|
||||||
|
taxStdAmt = taxStdAmt.add(stdTax.calculateTax(bd, isTaxIncluded(), getPrecision()));
|
||||||
|
|
||||||
|
bd = bd.subtract(taxStdAmt).add(taxThisAmt);
|
||||||
|
|
||||||
|
log.fine("Price List includes Tax and Tax Changed on Order Line: New Tax Amt: "
|
||||||
|
+ taxThisAmt + " Standard Tax Amt: " + taxStdAmt + " Line Net Amt: " + bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (bd.scale() > getPrecision())
|
if (bd.scale() > getPrecision())
|
||||||
bd = bd.setScale(getPrecision(), BigDecimal.ROUND_HALF_UP);
|
bd = bd.setScale(getPrecision(), BigDecimal.ROUND_HALF_UP);
|
||||||
super.setLineNetAmt (bd);
|
super.setLineNetAmt (bd);
|
||||||
} // setLineNetAmt
|
} // setLineNetAmt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Charge
|
||||||
|
* @return product or null
|
||||||
|
*/
|
||||||
|
public MCharge getCharge()
|
||||||
|
{
|
||||||
|
if (m_charge == null && getC_Charge_ID() != 0)
|
||||||
|
m_charge = MCharge.get (getCtx(), getC_Charge_ID());
|
||||||
|
return m_charge;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get Tax
|
||||||
|
* @return tax
|
||||||
|
*/
|
||||||
|
protected MTax getTax()
|
||||||
|
{
|
||||||
|
if (m_tax == null)
|
||||||
|
m_tax = MTax.get(getCtx(), getC_Tax_ID());
|
||||||
|
return m_tax;
|
||||||
|
} // getTax
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Currency Precision from Currency
|
* Get Currency Precision from Currency
|
||||||
* @return precision
|
* @return precision
|
||||||
|
@ -808,6 +881,7 @@ public class MOrderLine extends X_C_OrderLine
|
||||||
if (storages[i].getM_AttributeSetInstance_ID() == getM_AttributeSetInstance_ID())
|
if (storages[i].getM_AttributeSetInstance_ID() == getM_AttributeSetInstance_ID())
|
||||||
qty = qty.add(storages[i].getQtyOnHand());
|
qty = qty.add(storages[i].getQtyOnHand());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getQtyOrdered().compareTo(qty) > 0)
|
if (getQtyOrdered().compareTo(qty) > 0)
|
||||||
{
|
{
|
||||||
log.warning("Qty - Stock=" + qty + ", Ordered=" + getQtyOrdered());
|
log.warning("Qty - Stock=" + qty + ", Ordered=" + getQtyOrdered());
|
||||||
|
|
|
@ -18,6 +18,9 @@ package org.compiere.model;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tax Category Model
|
* Tax Category Model
|
||||||
|
@ -51,7 +54,7 @@ public class MTaxCategory extends X_C_TaxCategory
|
||||||
/**
|
/**
|
||||||
* Load Constructor
|
* Load Constructor
|
||||||
* @param ctx context
|
* @param ctx context
|
||||||
* @param rs resukt set
|
* @param rs result set
|
||||||
* @param trxName trx
|
* @param trxName trx
|
||||||
*/
|
*/
|
||||||
public MTaxCategory (Properties ctx, ResultSet rs, String trxName)
|
public MTaxCategory (Properties ctx, ResultSet rs, String trxName)
|
||||||
|
@ -59,4 +62,28 @@ public class MTaxCategory extends X_C_TaxCategory
|
||||||
super (ctx, rs, trxName);
|
super (ctx, rs, trxName);
|
||||||
} // MTaxCategory
|
} // MTaxCategory
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getDefaultTax
|
||||||
|
* Get the default tax id associated with this tax category
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public MTax getDefaultTax()
|
||||||
|
{
|
||||||
|
MTax m_tax = new MTax(getCtx(), 0, get_TrxName());
|
||||||
|
|
||||||
|
String whereClause = COLUMNNAME_C_TaxCategory_ID+"=? AND "+ COLUMNNAME_IsDefault+"='Y'";
|
||||||
|
List<MTax> list = new Query(getCtx(), MTax.Table_Name, whereClause, get_TrxName())
|
||||||
|
.setParameters(new Object[]{getC_TaxCategory_ID()})
|
||||||
|
.list();
|
||||||
|
if (list.size() == 1)
|
||||||
|
m_tax = list.get(0);
|
||||||
|
else {
|
||||||
|
// Error - should only be one default
|
||||||
|
throw new AdempiereException("TooManyDefaults");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return m_tax;
|
||||||
|
} // getDefaultTax
|
||||||
} // MTaxCategory
|
} // MTaxCategory
|
||||||
|
|
Loading…
Reference in New Issue