From cad01851d5308a3b8570230ee737a87c6c018823 Mon Sep 17 00:00:00 2001 From: Carlos Ruiz Date: Fri, 31 May 2024 10:28:29 +0200 Subject: [PATCH] IDEMPIERE-6159 Add drop ship location to ITaxLookup (#2380) --- .../src/org/adempiere/model/CalloutRMA.java | 9 +- .../org/compiere/model/CalloutInvoice.java | 35 +++- .../compiere/model/CalloutInvoiceBatch.java | 44 ++++- .../src/org/compiere/model/CalloutOrder.java | 3 +- .../org/adempiere/base/DefaultTaxLookup.java | 18 +- .../src/org/adempiere/base/ITaxLookup.java | 60 +++++++ .../src/org/compiere/model/MInvoiceLine.java | 7 +- .../src/org/compiere/model/MOrderLine.java | 2 +- .../src/org/compiere/model/MRMALine.java | 8 +- .../src/org/compiere/model/Tax.java | 161 +++++++++++++----- org.idempiere.test/META-INF/MANIFEST.MF | 2 +- ...dempiere.test.model.MTaxTest_TaxLookup.xml | 7 + .../src/org/idempiere/test/DictionaryIDs.java | 34 +++- .../org/idempiere/test/model/MTaxTest.java | 127 ++++++++++++-- .../test/model/MTaxTest_TaxLookup.java | 53 ++++++ 15 files changed, 496 insertions(+), 74 deletions(-) create mode 100644 org.idempiere.test/OSGI-INF/org.idempiere.test.model.MTaxTest_TaxLookup.xml create mode 100644 org.idempiere.test/src/org/idempiere/test/model/MTaxTest_TaxLookup.java diff --git a/org.adempiere.base.callout/src/org/adempiere/model/CalloutRMA.java b/org.adempiere.base.callout/src/org/adempiere/model/CalloutRMA.java index d71138b047..338762ac5a 100644 --- a/org.adempiere.base.callout/src/org/adempiere/model/CalloutRMA.java +++ b/org.adempiere.base.callout/src/org/adempiere/model/CalloutRMA.java @@ -156,6 +156,11 @@ public class CalloutRMA extends CalloutEngine { MInvoice invoice = rma.getOriginalInvoice(); if (invoice != null) { + int dropshipLocationId = -1; + MOrder order = invoice.getOriginalOrder(); + if (order != null) + dropshipLocationId = order.getDropShip_Location_ID(); + pp.setM_PriceList_ID(invoice.getM_PriceList_ID()); pp.setPriceDate(invoice.getDateInvoiced()); @@ -168,7 +173,7 @@ public class CalloutRMA extends CalloutEngine { invoice.getDateInvoiced(), invoice.getDateInvoiced(), AD_Org_ID, rma.getShipment().getM_Warehouse_ID(), invoice.getC_BPartner_Location_ID(), // should be bill to - invoice.getC_BPartner_Location_ID(), rma.isSOTrx(), deliveryViaRule, null); + invoice.getC_BPartner_Location_ID(), dropshipLocationId, rma.isSOTrx(), deliveryViaRule, null); } else { @@ -183,7 +188,7 @@ public class CalloutRMA extends CalloutEngine { order.getDateOrdered(), order.getDateOrdered(), AD_Org_ID, order.getM_Warehouse_ID(), order.getC_BPartner_Location_ID(), // should be bill to - order.getC_BPartner_Location_ID(), rma.isSOTrx(), order.getDeliveryViaRule(), null); + order.getC_BPartner_Location_ID(), order.getDropShip_Location_ID(), rma.isSOTrx(), order.getDeliveryViaRule(), null); } else return "No Invoice/Order found the Shipment/Receipt associated"; diff --git a/org.adempiere.base.callout/src/org/compiere/model/CalloutInvoice.java b/org.adempiere.base.callout/src/org/compiere/model/CalloutInvoice.java index e2db5081a5..f4b8ae324d 100644 --- a/org.adempiere.base.callout/src/org/compiere/model/CalloutInvoice.java +++ b/org.adempiere.base.callout/src/org/compiere/model/CalloutInvoice.java @@ -488,8 +488,9 @@ public class CalloutInvoice extends CalloutEngine // String deliveryViaRule = getLineDeliveryViaRule(ctx, WindowNo, mTab); + int dropshipLocationId = getDropShipLocationId(ctx, WindowNo, mTab); int C_Tax_ID = Core.getTaxLookup().get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, - AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, + AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, dropshipLocationId, Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y"), deliveryViaRule, null); if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID); // @@ -501,6 +502,13 @@ public class CalloutInvoice extends CalloutEngine return amt (ctx, WindowNo, mTab, mField, value); } // tax + /** + * Get the delivery via rule from the related order + * @param ctx + * @param windowNo + * @param mTab + * @return + */ private String getLineDeliveryViaRule(Properties ctx, int windowNo, GridTab mTab) { if (mTab.getValue("C_OrderLine_ID") != null) { int C_OrderLine_ID = (Integer) mTab.getValue("C_OrderLine_ID"); @@ -523,7 +531,30 @@ public class CalloutInvoice extends CalloutEngine } return null; } - + + /** + * Get the drop shipment location ID from the related order + * @param ctx + * @param windowNo + * @param mTab + * @return + */ + private int getDropShipLocationId(Properties ctx, int windowNo, GridTab mTab) { + if (mTab.getValue("C_OrderLine_ID") != null) { + int C_OrderLine_ID = (Integer) mTab.getValue("C_OrderLine_ID"); + if (C_OrderLine_ID > 0) { + MOrderLine orderLine = new MOrderLine(ctx, C_OrderLine_ID, null); + return orderLine.getParent().getDropShip_Location_ID(); + } + } + int C_Order_ID = Env.getContextAsInt(ctx, windowNo, "C_Order_ID", true); + if (C_Order_ID > 0) { + MOrder order = new MOrder(ctx, C_Order_ID, null); + return order.getDropShip_Location_ID(); + } + return -1; + } + /** * Invoice - Amount. * - called from QtyInvoiced, PriceActual diff --git a/org.adempiere.base.callout/src/org/compiere/model/CalloutInvoiceBatch.java b/org.adempiere.base.callout/src/org/compiere/model/CalloutInvoiceBatch.java index cee2fe3d5c..52e367199e 100644 --- a/org.adempiere.base.callout/src/org/compiere/model/CalloutInvoiceBatch.java +++ b/org.adempiere.base.callout/src/org/compiere/model/CalloutInvoiceBatch.java @@ -319,8 +319,9 @@ public class CalloutInvoiceBatch extends CalloutEngine // String deliveryViaRule = getLineDeliveryViaRule(ctx, WindowNo, mTab); + int dropshipLocationId = getDropShipLocationId(ctx, WindowNo, mTab); int C_Tax_ID = Core.getTaxLookup().get(ctx, 0, C_Charge_ID, billDate, shipDate, - AD_Org_ID, M_Warehouse_ID, C_BPartner_Location_ID, C_BPartner_Location_ID, + AD_Org_ID, M_Warehouse_ID, C_BPartner_Location_ID, C_BPartner_Location_ID, dropshipLocationId, Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y"), deliveryViaRule, null); if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID); // @@ -332,6 +333,13 @@ public class CalloutInvoiceBatch extends CalloutEngine return amt (ctx, WindowNo, mTab, mField, value); } // tax + /** + * Get the drop shipment location ID from the related order + * @param ctx + * @param windowNo + * @param mTab + * @return + */ private String getLineDeliveryViaRule(Properties ctx, int windowNo, GridTab mTab) { if (mTab.getValue("C_InvoiceLine_ID") != null) { int C_InvoiceLine_ID = (Integer) mTab.getValue("C_InvoiceLine_ID"); @@ -361,7 +369,39 @@ public class CalloutInvoiceBatch extends CalloutEngine } return null; } - + + /** + * Get the drop shipment location ID from the related order + * @param ctx + * @param windowNo + * @param mTab + * @return + */ + private int getDropShipLocationId(Properties ctx, int windowNo, GridTab mTab) { + if (mTab.getValue("C_InvoiceLine_ID") != null) { + int C_InvoiceLine_ID = (Integer) mTab.getValue("C_InvoiceLine_ID"); + if (C_InvoiceLine_ID > 0) { + MInvoiceLine invoiceLine = new MInvoiceLine(ctx, C_InvoiceLine_ID, null); + int C_OrderLine_ID = invoiceLine.getC_OrderLine_ID(); + if (C_OrderLine_ID > 0) { + MOrderLine orderLine = new MOrderLine(ctx, C_OrderLine_ID, null); + return orderLine.getParent().getDropShip_Location_ID(); + } + } + } + if (mTab.getValue("C_Invoice_ID") != null) { + int C_Invoice_ID = (Integer) mTab.getValue("C_Invoice_ID"); + if (C_Invoice_ID > 0) { + MInvoice invoice = new MInvoice(ctx, C_Invoice_ID, null); + I_C_Order order = invoice.getC_Order(); + if (order != null) { + return order.getDropShip_Location_ID(); + } + } + } + return -1; + } + /** * Invoice - Amount. * - called from QtyEntered, PriceEntered diff --git a/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java b/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java index 43856064c1..2df87e1ee1 100644 --- a/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java +++ b/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java @@ -972,8 +972,9 @@ public class CalloutOrder extends CalloutEngine // String deliveryViaRule = Env.getContext(ctx, WindowNo, I_C_Order.COLUMNNAME_DeliveryViaRule, true); + int dropshipLocationId = Env.getContextAsInt(ctx, WindowNo, I_C_Order.COLUMNNAME_DropShip_Location_ID, true); int C_Tax_ID = Core.getTaxLookup().get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, - AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, + AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, dropshipLocationId, "Y".equals(Env.getContext(ctx, WindowNo, "IsSOTrx")), deliveryViaRule, null); if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID); // diff --git a/org.adempiere.base/src/org/adempiere/base/DefaultTaxLookup.java b/org.adempiere.base/src/org/adempiere/base/DefaultTaxLookup.java index 997083ae95..93b38eb052 100644 --- a/org.adempiere.base/src/org/adempiere/base/DefaultTaxLookup.java +++ b/org.adempiere.base/src/org/adempiere/base/DefaultTaxLookup.java @@ -51,10 +51,19 @@ public class DefaultTaxLookup implements ITaxLookup { public int get(Properties ctx, int M_Product_ID, int C_Charge_ID, Timestamp billDate, Timestamp shipDate, int AD_Org_ID, int M_Warehouse_ID, int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, boolean IsSOTrx, String deliveryViaRule, String trxName) { - return Tax.get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, + return Tax.get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, deliveryViaRule, trxName); } + @Override + public int get(Properties ctx, int M_Product_ID, int C_Charge_ID, Timestamp billDate, Timestamp shipDate, + int AD_Org_ID, int M_Warehouse_ID, int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, + int dropshipC_BPartner_Location_ID, + boolean IsSOTrx, String deliveryViaRule, String trxName) { + return Tax.get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, + dropshipC_BPartner_Location_ID, IsSOTrx, deliveryViaRule, trxName); + } + @Override public int get(Properties ctx, int C_TaxCategory_ID, boolean IsSOTrx, Timestamp shipDate, int shipFromC_Location_ID, int shipToC_Location_ID, Timestamp billDate, int billFromC_Location_ID, int billToC_Location_ID, @@ -62,4 +71,11 @@ public class DefaultTaxLookup implements ITaxLookup { return Tax.get(ctx, C_TaxCategory_ID, IsSOTrx, shipDate, shipFromC_Location_ID, shipToC_Location_ID, billDate, billFromC_Location_ID, billToC_Location_ID, trxName); } + @Override + public int get(Properties ctx, int C_TaxCategory_ID, boolean IsSOTrx, Timestamp shipDate, int shipFromC_Location_ID, + int shipToC_Location_ID, int dropshipC_Location_ID, Timestamp billDate, int billFromC_Location_ID, int billToC_Location_ID, + String trxName) { + return Tax.get(ctx, C_TaxCategory_ID, IsSOTrx, shipDate, shipFromC_Location_ID, shipToC_Location_ID, dropshipC_Location_ID, billDate, billFromC_Location_ID, billToC_Location_ID, trxName); + } + } diff --git a/org.adempiere.base/src/org/adempiere/base/ITaxLookup.java b/org.adempiere.base/src/org/adempiere/base/ITaxLookup.java index 7861059f86..6d014aa019 100644 --- a/org.adempiere.base/src/org/adempiere/base/ITaxLookup.java +++ b/org.adempiere.base/src/org/adempiere/base/ITaxLookup.java @@ -55,6 +55,37 @@ public interface ITaxLookup { int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, boolean IsSOTrx, String deliveryViaRule, String trxName); + /** + * Find C_Tax_ID by Product/Charge + Warehouse Location + BPartner Location + DeliveryViaRule + * @param ctx + * @param M_Product_ID + * @param C_Charge_ID + * @param billDate Billing Date + * @param shipDate Shipment Date + * @param AD_Org_ID + * @param M_Warehouse_ID + * @param billC_BPartner_Location_ID Bill to location + * @param shipC_BPartner_Location_ID Ship to location + * @param dropshipC_BPartner_Location_ID Drop Ship to location (ignored if not implemented) + * @param IsSOTrx + * @param deliveryViaRule Order/Invoice's Delivery Via Rule + * @param trxName + * @return C_Tax_ID + */ + public default int get (Properties ctx, int M_Product_ID, int C_Charge_ID, + Timestamp billDate, Timestamp shipDate, + int AD_Org_ID, int M_Warehouse_ID, + int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, + int dropshipC_BPartner_Location_ID, + boolean IsSOTrx, String deliveryViaRule, String trxName) { + // fallback to default method without dropshipC_BPartner_Location_ID if not implemented + return get(ctx, M_Product_ID, C_Charge_ID, + billDate, shipDate, + AD_Org_ID, M_Warehouse_ID, + billC_BPartner_Location_ID, shipC_BPartner_Location_ID, + IsSOTrx, deliveryViaRule, trxName); + } + /** * Find C_Tax_ID * @param ctx @@ -73,4 +104,33 @@ public interface ITaxLookup { int C_TaxCategory_ID, boolean IsSOTrx, Timestamp shipDate, int shipFromC_Location_ID, int shipToC_Location_ID, Timestamp billDate, int billFromC_Location_ID, int billToC_Location_ID, String trxName); + + /** + * Find C_Tax_ID + * @param ctx + * @param C_TaxCategory_ID + * @param IsSOTrx + * @param shipDate Shipment Date + * @param shipFromC_Location_ID Shipping from (not use in default lookup implementation) + * @param shipToC_Location_ID Shipping to (not use in default lookup implementation) + * @param dropshipC_Location_ID Drop Ship location + * @param billDate Billing Date + * @param billFromC_Location_ID Billing from (Tax Location from) + * @param billToC_Location_ID Billing to (Tax Location to) + * @param deliveryRule Order/Invoice's Delivery Via Rule + * @param trxName + * @return C_Tax_ID + */ + public default int get (Properties ctx, + int C_TaxCategory_ID, boolean IsSOTrx, + Timestamp shipDate, int shipFromC_Location_ID, int shipToC_Location_ID, + int dropshipC_Location_ID, + Timestamp billDate, int billFromC_Location_ID, int billToC_Location_ID, String trxName) { + // fallback to default method without dropshipC_BPartner_Location_ID if not implemented + return get(ctx, + C_TaxCategory_ID, IsSOTrx, + shipDate, shipFromC_Location_ID, shipToC_Location_ID, + billDate, billFromC_Location_ID, billToC_Location_ID, trxName); + } + } diff --git a/org.adempiere.base/src/org/compiere/model/MInvoiceLine.java b/org.adempiere.base/src/org/compiere/model/MInvoiceLine.java index 3bd339d7d2..16c5c758e8 100644 --- a/org.adempiere.base/src/org/compiere/model/MInvoiceLine.java +++ b/org.adempiere.base/src/org/compiere/model/MInvoiceLine.java @@ -500,8 +500,11 @@ public class MInvoiceLine extends X_C_InvoiceLine int M_Warehouse_ID = Env.getContextAsInt(getCtx(), Env.M_WAREHOUSE_ID); // String deliveryViaRule = null; + int dropShipLocationId = -1; if (getC_OrderLine_ID() > 0) { - deliveryViaRule = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName()).getParent().getDeliveryViaRule(); + MOrder order = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName()).getParent(); + deliveryViaRule = order.getDeliveryViaRule(); + dropShipLocationId = order.getDropShip_Location_ID(); } else if (getM_InOutLine_ID() > 0) { deliveryViaRule = new MInOutLine(getCtx(), getM_InOutLine_ID(), get_TrxName()).getParent().getDeliveryViaRule(); } else if (getParent().getC_Order_ID() > 0) { @@ -510,7 +513,7 @@ public class MInvoiceLine extends X_C_InvoiceLine int C_Tax_ID = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID() , m_DateInvoiced, m_DateInvoiced, getAD_Org_ID(), M_Warehouse_ID, m_C_BPartner_Location_ID, // should be bill to - m_C_BPartner_Location_ID, m_IsSOTrx, deliveryViaRule, get_TrxName()); + m_C_BPartner_Location_ID, dropShipLocationId, m_IsSOTrx, deliveryViaRule, get_TrxName()); if (C_Tax_ID == 0) { log.log(Level.SEVERE, "No Tax found"); diff --git a/org.adempiere.base/src/org/compiere/model/MOrderLine.java b/org.adempiere.base/src/org/compiere/model/MOrderLine.java index bbdc0946df..0213e477d1 100644 --- a/org.adempiere.base/src/org/compiere/model/MOrderLine.java +++ b/org.adempiere.base/src/org/compiere/model/MOrderLine.java @@ -348,7 +348,7 @@ public class MOrderLine extends X_C_OrderLine int ii = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID(), getDateOrdered(), getDateOrdered(), getAD_Org_ID(), getM_Warehouse_ID(), getC_BPartner_Location_ID(), // should be bill to - getC_BPartner_Location_ID(), m_IsSOTrx, getParent().getDeliveryViaRule(), get_TrxName()); + getC_BPartner_Location_ID(), getParent().getDropShip_Location_ID(), m_IsSOTrx, getParent().getDeliveryViaRule(), get_TrxName()); if (ii == 0) { log.log(Level.SEVERE, "No Tax found"); diff --git a/org.adempiere.base/src/org/compiere/model/MRMALine.java b/org.adempiere.base/src/org/compiere/model/MRMALine.java index 3d6295e213..0a89a4bb5d 100644 --- a/org.adempiere.base/src/org/compiere/model/MRMALine.java +++ b/org.adempiere.base/src/org/compiere/model/MRMALine.java @@ -181,6 +181,10 @@ public class MRMALine extends X_M_RMALine MInvoice invoice = getParent().getOriginalInvoice(); if (invoice != null) { + int dropshipLocationId = -1; + MOrder order = invoice.getOriginalOrder(); + if (order != null) + dropshipLocationId = order.getDropShip_Location_ID(); pp.setM_PriceList_ID(invoice.getM_PriceList_ID()); pp.setPriceDate(invoice.getDateInvoiced()); @@ -192,7 +196,7 @@ public class MRMALine extends X_M_RMALine taxId = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID(), invoice.getDateInvoiced(), invoice.getDateInvoiced(), getAD_Org_ID(), getParent().getShipment().getM_Warehouse_ID(), invoice.getC_BPartner_Location_ID(), // should be bill to - invoice.getC_BPartner_Location_ID(), getParent().isSOTrx(), deliveryViaRule, get_TrxName()); + invoice.getC_BPartner_Location_ID(), dropshipLocationId, getParent().isSOTrx(), deliveryViaRule, get_TrxName()); } else { @@ -206,7 +210,7 @@ public class MRMALine extends X_M_RMALine taxId = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID(), order.getDateOrdered(), order.getDateOrdered(), getAD_Org_ID(), order.getM_Warehouse_ID(), order.getC_BPartner_Location_ID(), // should be bill to - order.getC_BPartner_Location_ID(), getParent().isSOTrx(), order.getDeliveryViaRule(), get_TrxName()); + order.getC_BPartner_Location_ID(), order.getDropShip_Location_ID(), getParent().isSOTrx(), order.getDeliveryViaRule(), get_TrxName()); } else throw new IllegalStateException("No Invoice/Order found the Shipment/Receipt associated"); diff --git a/org.adempiere.base/src/org/compiere/model/Tax.java b/org.adempiere.base/src/org/compiere/model/Tax.java index 77127e2d87..876b0412aa 100644 --- a/org.adempiere.base/src/org/compiere/model/Tax.java +++ b/org.adempiere.base/src/org/compiere/model/Tax.java @@ -68,7 +68,7 @@ public class Tax int AD_Org_ID, int M_Warehouse_ID, int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, boolean IsSOTrx) { - return get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, null); + return get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, -1, IsSOTrx, null); } @@ -93,6 +93,7 @@ public class Tax * @param M_Warehouse_ID warehouse (ignored) * @param billC_BPartner_Location_ID invoice location * @param shipC_BPartner_Location_ID ship location (ignored) + * @param dropshipC_BPartner_Location_ID ship location (ignored) * @param IsSOTrx is a sales trx * @param trxName * @return C_Tax_ID @@ -101,11 +102,11 @@ public class Tax public static int get (Properties ctx, int M_Product_ID, int C_Charge_ID, Timestamp billDate, Timestamp shipDate, int AD_Org_ID, int M_Warehouse_ID, - int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, + int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, int dropshipC_BPartner_Location_ID, boolean IsSOTrx, String trxName) { return get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, - billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, null, trxName); + billC_BPartner_Location_ID, shipC_BPartner_Location_ID, dropshipC_BPartner_Location_ID, IsSOTrx, null, trxName); } /************************************************************************** @@ -135,18 +136,59 @@ public class Tax * @return C_Tax_ID * @throws TaxCriteriaNotFoundException if a criteria was not found */ + public static int get (Properties ctx, int M_Product_ID, int C_Charge_ID, + Timestamp billDate, Timestamp shipDate, + int AD_Org_ID, int M_Warehouse_ID, + int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, + boolean IsSOTrx, String deliveryViaRule, String trxName) + { + return get(ctx, M_Product_ID, C_Charge_ID, + billDate, shipDate, + AD_Org_ID, M_Warehouse_ID, + billC_BPartner_Location_ID, shipC_BPartner_Location_ID, -1, + IsSOTrx, deliveryViaRule, trxName); + } + + /************************************************************************** + * Get Tax ID - converts parameters to call Get Tax. + *
{@code
+	 *		M_Product_ID/C_Charge_ID	->	C_TaxCategory_ID
+	 *		billDate, shipDate			->	billDate, shipDate
+	 *		AD_Org_ID					->	billFromC_Location_ID
+	 *		M_Warehouse_ID				->	shipFromC_Location_ID
+	 *		billC_BPartner_Location_ID  ->	billToC_Location_ID
+	 *		shipC_BPartner_Location_ID 	->	shipToC_Location_ID
+	 *
+	 *  if IsSOTrx is false, bill and ship are reversed
+	 *  }
+ * @param ctx context + * @param M_Product_ID product + * @param C_Charge_ID product + * @param billDate invoice date + * @param shipDate ship date (ignored) + * @param AD_Org_ID org + * @param M_Warehouse_ID warehouse (ignored) + * @param billC_BPartner_Location_ID invoice location + * @param shipC_BPartner_Location_ID ship location (ignored) + * @param dropshipC_BPartner_Location_ID dropship location + * @param IsSOTrx is a sales trx + * @param deliveryViaRule if Delivery Via Rule is PickUp, use Warehouse Location instead of Billing Location as Tax Location to + * @param trxName + * @return C_Tax_ID + * @throws TaxCriteriaNotFoundException if a criteria was not found + */ public static int get (Properties ctx, int M_Product_ID, int C_Charge_ID, Timestamp billDate, Timestamp shipDate, int AD_Org_ID, int M_Warehouse_ID, - int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, + int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, int dropshipC_BPartner_Location_ID, boolean IsSOTrx, String deliveryViaRule, String trxName) { if (M_Product_ID != 0) return getProduct (ctx, M_Product_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, - billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, deliveryViaRule, trxName); + billC_BPartner_Location_ID, shipC_BPartner_Location_ID, dropshipC_BPartner_Location_ID, IsSOTrx, deliveryViaRule, trxName); else if (C_Charge_ID != 0) return getCharge (ctx, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, - billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, deliveryViaRule, trxName); + billC_BPartner_Location_ID, shipC_BPartner_Location_ID, dropshipC_BPartner_Location_ID, IsSOTrx, deliveryViaRule, trxName); else return getExemptTax (ctx, AD_Org_ID, trxName); } // get @@ -207,7 +249,7 @@ public class Tax boolean IsSOTrx, String trxName) { return getCharge(ctx, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, - billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, null, trxName); + billC_BPartner_Location_ID, shipC_BPartner_Location_ID, -1, IsSOTrx, null, trxName); } /** @@ -231,6 +273,7 @@ public class Tax * @param M_Warehouse_ID warehouse (ignored) * @param billC_BPartner_Location_ID invoice location * @param shipC_BPartner_Location_ID ship location (ignored) + * @param dropshipC_BPartner_Location_ID * @param IsSOTrx is a sales trx * @param deliveryViaRule if Delivery Via Rule is PickUp, use Warehouse Location instead of Billing Location as Tax Location to * @param trxName @@ -241,12 +284,13 @@ public class Tax public static int getCharge (Properties ctx, int C_Charge_ID, Timestamp billDate, Timestamp shipDate, int AD_Org_ID, int M_Warehouse_ID, - int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, + int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, int dropshipC_BPartner_Location_ID, boolean IsSOTrx, String deliveryViaRule, String trxName) { int C_TaxCategory_ID = 0; int shipFromC_Location_ID = 0; int shipToC_Location_ID = 0; + int dropshipC_Location_ID = 0; int billFromC_Location_ID = 0; int billToC_Location_ID = 0; int warehouseC_Location_ID = 0; @@ -256,24 +300,26 @@ public class Tax // Get all at once String sql = "SELECT c.C_TaxCategory_ID, o.C_Location_ID, il.C_Location_ID, b.IsTaxExempt, b.IsPOTaxExempt," - + " w.C_Location_ID, sl.C_Location_ID " - + "FROM C_Charge c, AD_OrgInfo o," - + " C_BPartner_Location il INNER JOIN C_BPartner b ON (il.C_BPartner_ID=b.C_BPartner_ID) " - + " LEFT OUTER JOIN M_Warehouse w ON (w.M_Warehouse_ID=?), C_BPartner_Location sl " - + "WHERE c.C_Charge_ID=?" - + " AND o.AD_Org_ID=?" - + " AND il.C_BPartner_Location_ID=?" - + " AND sl.C_BPartner_Location_ID=?"; + + " w.C_Location_ID, sl.C_Location_ID, dsl.C_Location_ID " + + "FROM C_Charge c" + + " JOIN AD_OrgInfo o ON (o.AD_Org_ID=?)" + + " JOIN C_BPartner_Location il ON (il.C_BPartner_Location_ID=?)" + + " INNER JOIN C_BPartner b ON (il.C_BPartner_ID=b.C_BPartner_ID) " + + " LEFT OUTER JOIN M_Warehouse w ON (w.M_Warehouse_ID=?)" + + " JOIN C_BPartner_Location sl ON (sl.C_BPartner_Location_ID=?)" + + " LEFT JOIN C_BPartner_Location dsl ON (dsl.C_BPartner_Location_ID=?)" + + "WHERE c.C_Charge_ID=?"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement (sql, trxName); - pstmt.setInt (1, M_Warehouse_ID); - pstmt.setInt (2, C_Charge_ID); - pstmt.setInt (3, AD_Org_ID); - pstmt.setInt (4, billC_BPartner_Location_ID); - pstmt.setInt (5, shipC_BPartner_Location_ID); + pstmt.setInt (1, AD_Org_ID); + pstmt.setInt (2, billC_BPartner_Location_ID); + pstmt.setInt (3, M_Warehouse_ID); + pstmt.setInt (4, shipC_BPartner_Location_ID); + pstmt.setInt (5, dropshipC_BPartner_Location_ID); + pstmt.setInt (6, C_Charge_ID); rs = pstmt.executeQuery (); boolean found = false; if (rs.next ()) @@ -286,6 +332,7 @@ public class Tax IsTaxExempt = IsSOTrx ? IsSOTaxExempt : IsPOTaxExempt; shipFromC_Location_ID = rs.getInt (6); shipToC_Location_ID = rs.getInt (7); + dropshipC_Location_ID = rs.getInt (8); warehouseC_Location_ID = rs.getInt(6); found = true; } @@ -331,9 +378,10 @@ public class Tax + ", billFromC_Location_ID=" + billFromC_Location_ID + ", billToC_Location_ID=" + billToC_Location_ID + ", shipFromC_Location_ID=" + shipFromC_Location_ID - + ", shipToC_Location_ID=" + shipToC_Location_ID); + + ", shipToC_Location_ID=" + shipToC_Location_ID + + ", dropshipC_Location_ID=" + dropshipC_Location_ID); return Core.getTaxLookup().get (ctx, C_TaxCategory_ID, IsSOTrx, - shipDate, shipFromC_Location_ID, shipToC_Location_ID, + shipDate, shipFromC_Location_ID, shipToC_Location_ID, dropshipC_Location_ID, billDate, billFromC_Location_ID, billToC_Location_ID, trxName); } // getCharge @@ -393,7 +441,7 @@ public class Tax boolean IsSOTrx, String trxName) { return getProduct(ctx, M_Product_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, - billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, null, trxName); + billC_BPartner_Location_ID, shipC_BPartner_Location_ID, -1, IsSOTrx, null, trxName); } /** @@ -417,6 +465,7 @@ public class Tax * @param M_Warehouse_ID warehouse (ignored) * @param billC_BPartner_Location_ID invoice location * @param shipC_BPartner_Location_ID ship location (ignored) + * @param dropshipC_BPartner_Location_ID * @param IsSOTrx is a sales trx * @param deliveryViaRule if Delivery Via Rule is PickUp, use Warehouse Location instead of Billing Location as Tax Location to * @param trxName @@ -426,7 +475,7 @@ public class Tax public static int getProduct (Properties ctx, int M_Product_ID, Timestamp billDate, Timestamp shipDate, int AD_Org_ID, int M_Warehouse_ID, - int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, + int billC_BPartner_Location_ID, int shipC_BPartner_Location_ID, int dropshipC_BPartner_Location_ID, boolean IsSOTrx, String deliveryViaRule, String trxName) { String variable = ""; @@ -436,6 +485,7 @@ public class Tax int billFromC_Location_ID = 0; int billToC_Location_ID = 0; int warehouseC_Location_ID = 0; + int dropshipC_Location_ID = 0; String IsTaxExempt = null; String IsSOTaxExempt = null; String IsPOTaxExempt = null; @@ -447,20 +497,22 @@ public class Tax { // Get all at once sql = "SELECT p.C_TaxCategory_ID, o.C_Location_ID, il.C_Location_ID, b.IsTaxExempt, b.IsPOTaxExempt, " - + " w.C_Location_ID, sl.C_Location_ID " - + "FROM M_Product p, AD_OrgInfo o," - + " C_BPartner_Location il INNER JOIN C_BPartner b ON (il.C_BPartner_ID=b.C_BPartner_ID) " - + " LEFT OUTER JOIN M_Warehouse w ON (w.M_Warehouse_ID=?), C_BPartner_Location sl " - + "WHERE p.M_Product_ID=?" - + " AND o.AD_Org_ID=?" - + " AND il.C_BPartner_Location_ID=?" - + " AND sl.C_BPartner_Location_ID=?"; + + " w.C_Location_ID, sl.C_Location_ID, dsl.C_Location_ID " + + "FROM M_Product p" + + " JOIN AD_OrgInfo o ON (o.AD_Org_ID=?)" + + " JOIN C_BPartner_Location il ON (il.C_BPartner_Location_ID=?)" + + " INNER JOIN C_BPartner b ON (il.C_BPartner_ID=b.C_BPartner_ID)" + + " LEFT OUTER JOIN M_Warehouse w ON (w.M_Warehouse_ID=?)" + + " JOIN C_BPartner_Location sl ON (sl.C_BPartner_Location_ID=?)" + + " LEFT JOIN C_BPartner_Location dsl ON (dsl.C_BPartner_Location_ID=?) " + + "WHERE p.M_Product_ID=?"; pstmt = DB.prepareStatement(sql, trxName); - pstmt.setInt(1, M_Warehouse_ID); - pstmt.setInt(2, M_Product_ID); - pstmt.setInt(3, AD_Org_ID); - pstmt.setInt(4, billC_BPartner_Location_ID); - pstmt.setInt(5, shipC_BPartner_Location_ID); + pstmt.setInt(1, AD_Org_ID); + pstmt.setInt(2, billC_BPartner_Location_ID); + pstmt.setInt(3, M_Warehouse_ID); + pstmt.setInt(4, shipC_BPartner_Location_ID); + pstmt.setInt(5, dropshipC_BPartner_Location_ID); + pstmt.setInt(6, M_Product_ID); rs = pstmt.executeQuery(); boolean found = false; if (rs.next()) @@ -473,6 +525,7 @@ public class Tax IsTaxExempt = IsSOTrx ? IsSOTaxExempt : IsPOTaxExempt; shipFromC_Location_ID = rs.getInt(6); shipToC_Location_ID = rs.getInt(7); + dropshipC_Location_ID = rs.getInt(8); warehouseC_Location_ID = rs.getInt(6); found = true; } @@ -502,9 +555,10 @@ public class Tax + ", billFromC_Location_ID=" + billFromC_Location_ID + ", billToC_Location_ID=" + billToC_Location_ID + ", shipFromC_Location_ID=" + shipFromC_Location_ID - + ", shipToC_Location_ID=" + shipToC_Location_ID); + + ", shipToC_Location_ID=" + shipToC_Location_ID + + ", dropshipC_Location_ID=" + dropshipC_Location_ID); return Core.getTaxLookup().get(ctx, C_TaxCategory_ID, IsSOTrx, - shipDate, shipFromC_Location_ID, shipToC_Location_ID, + shipDate, shipFromC_Location_ID, shipToC_Location_ID, dropshipC_Location_ID, billDate, billFromC_Location_ID, billToC_Location_ID, trxName); } @@ -665,6 +719,33 @@ public class Tax int C_TaxCategory_ID, boolean IsSOTrx, Timestamp shipDate, int shipFromC_Location_ID, int shipToC_Location_ID, Timestamp billDate, int billFromC_Location_ID, int billToC_Location_ID, String trxName) + { + return get (ctx, + C_TaxCategory_ID, IsSOTrx, + shipDate, shipFromC_Location_ID, shipToC_Location_ID, -1, + billDate, billFromC_Location_ID, billToC_Location_ID, trxName); + } + + /************************************************************************** + * Get Tax ID (Detail). + * @param ctx context + * @param C_TaxCategory_ID tax category + * @param IsSOTrx Sales Order Trx + * @param shipDate ship date (ignored) + * @param shipFromC_Location_ID ship from (ignored) + * @param shipToC_Location_ID ship to (ignored) + * @param dropshipC_Location_ID + * @param billDate invoice date + * @param billFromC_Location_ID invoice from (Tax Location from) + * @param billToC_Location_ID invoice to (Tax Location to) + * @param trxName Transaction + * @return C_Tax_ID + * @throws TaxNotFoundException if no tax found for given criteria + */ + public static int get (Properties ctx, + int C_TaxCategory_ID, boolean IsSOTrx, + Timestamp shipDate, int shipFromC_Location_ID, int shipToC_Location_ID, int dropshipC_Location_ID, + Timestamp billDate, int billFromC_Location_ID, int billToC_Location_ID, String trxName) { // C_TaxCategory contains CommodityCode diff --git a/org.idempiere.test/META-INF/MANIFEST.MF b/org.idempiere.test/META-INF/MANIFEST.MF index b076e9dc5b..f69db550a6 100644 --- a/org.idempiere.test/META-INF/MANIFEST.MF +++ b/org.idempiere.test/META-INF/MANIFEST.MF @@ -43,4 +43,4 @@ Bundle-Activator: org.idempiere.test.TestActivator Bundle-RequiredExecutionEnvironment: JavaSE-17 Export-Package: org.idempiere.test Bundle-ClassPath: . -Service-Component: OSGI-INF/org.idempiere.test.event.MyComponent.xml +Service-Component: OSGI-INF/*.xml diff --git a/org.idempiere.test/OSGI-INF/org.idempiere.test.model.MTaxTest_TaxLookup.xml b/org.idempiere.test/OSGI-INF/org.idempiere.test.model.MTaxTest_TaxLookup.xml new file mode 100644 index 0000000000..214fd2904f --- /dev/null +++ b/org.idempiere.test/OSGI-INF/org.idempiere.test.model.MTaxTest_TaxLookup.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/org.idempiere.test/src/org/idempiere/test/DictionaryIDs.java b/org.idempiere.test/src/org/idempiere/test/DictionaryIDs.java index ce180f06d5..b5b89310a1 100644 --- a/org.idempiere.test/src/org/idempiere/test/DictionaryIDs.java +++ b/org.idempiere.test/src/org/idempiere/test/DictionaryIDs.java @@ -96,7 +96,17 @@ public final class DictionaryIDs { this.id = id; } } - + + public enum AD_SysConfig { + TAX_LOOKUP_SERVICE(200198); + + public final int id; + + private AD_SysConfig(int id) { + this.id = id; + } + } + public enum AD_User { GARDEN_ADMIN(101), GARDEN_USER(102), @@ -295,7 +305,17 @@ public final class DictionaryIDs { this.id = id; } } - + + public enum C_Location { + ORG_WH_HQ(114); + + public final int id; + + private C_Location(int id) { + this.id = id; + } + } + public enum C_PaymentTerm { NET_30(100), NET_30_DAYS(107), @@ -345,6 +365,16 @@ public final class DictionaryIDs { } } + public enum C_Region { + CT(102); + + public final int id; + + private C_Region(int id) { + this.id = id; + } + } + public enum C_Tax { STANDARD(104), CT_SALES(105), diff --git a/org.idempiere.test/src/org/idempiere/test/model/MTaxTest.java b/org.idempiere.test/src/org/idempiere/test/model/MTaxTest.java index 1fb4095a12..6886600bef 100644 --- a/org.idempiere.test/src/org/idempiere/test/model/MTaxTest.java +++ b/org.idempiere.test/src/org/idempiere/test/model/MTaxTest.java @@ -31,6 +31,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.Properties; import org.adempiere.base.Core; import org.compiere.model.MAccount; @@ -44,6 +45,7 @@ import org.compiere.model.MInOut; import org.compiere.model.MInOutLine; import org.compiere.model.MInvoice; import org.compiere.model.MInvoiceLine; +import org.compiere.model.MLocation; import org.compiere.model.MMatchPO; import org.compiere.model.MOrder; import org.compiere.model.MOrderLine; @@ -51,11 +53,13 @@ import org.compiere.model.MPriceList; import org.compiere.model.MPriceListVersion; import org.compiere.model.MProduct; import org.compiere.model.MProductPrice; +import org.compiere.model.MSysConfig; import org.compiere.model.MTax; import org.compiere.model.MTaxCategory; import org.compiere.model.MWarehouse; import org.compiere.model.ProductCost; import org.compiere.model.Tax; +import org.compiere.model.X_C_Order; import org.compiere.process.DocAction; import org.compiere.process.DocumentEngine; import org.compiere.process.ProcessInfo; @@ -66,12 +70,14 @@ import org.compiere.wf.MWorkflow; import org.idempiere.test.AbstractTestCase; import org.idempiere.test.DictionaryIDs; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Isolated; /** * * @author hengsin * */ +@Isolated public class MTaxTest extends AbstractTestCase { public MTaxTest() { @@ -95,26 +101,110 @@ public class MTaxTest extends AbstractTestCase { @Test public void testTaxLookup() { - int taxExemptId = Tax.getExemptTax(Env.getCtx(), getAD_Org_ID(), getTrxName()); + Properties ctx = Env.getCtx(); + String trxName = getTrxName(); + + int taxExemptId = Tax.getExemptTax(ctx, getAD_Org_ID(), trxName); assertTrue(taxExemptId>0, "Fail to get tax exempt Id"); - - MBPartner bp = new MBPartner(Env.getCtx(), DictionaryIDs.C_BPartner.JOE_BLOCK.id, getTrxName()); - bp.setIsTaxExempt(true); - bp.saveEx(); - - int id = Core.getTaxLookup().get(Env.getCtx(), DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, getLoginDate(), getLoginDate(), getAD_Org_ID(), getM_Warehouse_ID(), - bp.getPrimaryC_BPartner_Location_ID(), bp.getPrimaryC_BPartner_Location_ID(), true, null, getTrxName()); - assertEquals(taxExemptId, id, "Unexpected tax id"); - - bp.setIsTaxExempt(false); - bp.saveEx(); - - id = Core.getTaxLookup().get(Env.getCtx(), DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, getLoginDate(), getLoginDate(), getAD_Org_ID(), getM_Warehouse_ID(), - bp.getPrimaryC_BPartner_Location_ID(), bp.getPrimaryC_BPartner_Location_ID(), true, null, getTrxName()); - assertTrue(id != taxExemptId, "Unexpected tax id: " + id); - assertEquals(DictionaryIDs.C_Tax.STANDARD.id, id, "Unexpected tax id"); + + MBPartner bpTree = new MBPartner(ctx, DictionaryIDs.C_BPartner.TREE_FARM.id, trxName); + MBPartner bpPatio = new MBPartner(ctx, DictionaryIDs.C_BPartner.PATIO.id, trxName); + MBPartner bpCW = new MBPartner(ctx, DictionaryIDs.C_BPartner.C_AND_W.id, trxName); + MBPartner bpSeed = new MBPartner(ctx, DictionaryIDs.C_BPartner.SEED_FARM.id, trxName); + MBPartner bpJoe = new MBPartner(ctx, DictionaryIDs.C_BPartner.JOE_BLOCK.id, trxName); + bpJoe.setIsTaxExempt(true); + bpJoe.saveEx(); + + expectedTaxLookup(DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, + getAD_Org_ID(), getM_Warehouse_ID(), + bpJoe.getPrimaryC_BPartner_Location_ID(), bpJoe.getPrimaryC_BPartner_Location_ID(), -1, + true, null, taxExemptId); + + bpJoe.setIsTaxExempt(false); + bpJoe.saveEx(); + + expectedTaxLookup(DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, + getAD_Org_ID(), getM_Warehouse_ID(), + bpJoe.getPrimaryC_BPartner_Location_ID(), bpJoe.getPrimaryC_BPartner_Location_ID(), -1, + true, null, DictionaryIDs.C_Tax.STANDARD.id); + + // Sales charge from Germany (Org Fertilizer) to USA (Joe Block) -> expected Exempt + expectedTaxLookup(0, DictionaryIDs.C_Charge.FREIGHT.id, + DictionaryIDs.AD_Org.FERTILIZER.id, DictionaryIDs.M_Warehouse.FERTILIZER.id, + bpJoe.getPrimaryC_BPartner_Location_ID(), bpJoe.getPrimaryC_BPartner_Location_ID(), -1, + true, null, taxExemptId); + + // Purchase charge from USA New York (Patio BP) to USA Oregon (HQ Warehouse) -> expected Standard + expectedTaxLookup(0, DictionaryIDs.C_Charge.FREIGHT.id, + DictionaryIDs.AD_Org.HQ.id, DictionaryIDs.M_Warehouse.HQ.id, + bpPatio.getPrimaryC_BPartner_Location_ID(), bpPatio.getPrimaryC_BPartner_Location_ID(), -1, + false, null, DictionaryIDs.C_Tax.STANDARD.id); + + // Change location of Org HQ to Connecticut CT + MLocation location = new MLocation(ctx, DictionaryIDs.C_Location.ORG_WH_HQ.id, trxName); + location.setC_Region_ID(DictionaryIDs.C_Region.CT.id); + location.saveEx(); + // Sales charge from USA Connecticut (Org HQ modified) to USA Connecticut (C&W) -> expected CT Sales + expectedTaxLookup(0, DictionaryIDs.C_Charge.FREIGHT.id, + DictionaryIDs.AD_Org.HQ.id, DictionaryIDs.M_Warehouse.HQ.id, + bpCW.getPrimaryC_BPartner_Location_ID(), bpCW.getPrimaryC_BPartner_Location_ID(), -1, + true, null, DictionaryIDs.C_Tax.CT_SALES.id); + + // Sales product from USA Connecticut (Org HQ modified) to USA New Jersey (TreeFarm) -> expected Standard + expectedTaxLookup(DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, + DictionaryIDs.AD_Org.HQ.id, DictionaryIDs.M_Warehouse.HQ.id, + bpTree.getPrimaryC_BPartner_Location_ID(), bpTree.getPrimaryC_BPartner_Location_ID(), -1, + true, null, DictionaryIDs.C_Tax.STANDARD.id); + + // Sales product from USA Connecticut (Org HQ modified) to USA New Jersey (TreeFarm) - pick rule -> expected CT Sales + expectedTaxLookup(DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, + DictionaryIDs.AD_Org.HQ.id, DictionaryIDs.M_Warehouse.HQ.id, + bpTree.getPrimaryC_BPartner_Location_ID(), bpTree.getPrimaryC_BPartner_Location_ID(), -1, + true, X_C_Order.DELIVERYVIARULE_Pickup, DictionaryIDs.C_Tax.CT_SALES.id); + + // Purchase product from USA New York (Patio BP) to Germany (HQ Fertilizer) -> expected Exempt + expectedTaxLookup(DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, + DictionaryIDs.AD_Org.FERTILIZER.id, DictionaryIDs.M_Warehouse.FERTILIZER.id, + bpPatio.getPrimaryC_BPartner_Location_ID(), bpPatio.getPrimaryC_BPartner_Location_ID(), -1, + false, null, taxExemptId); + + // Purchase product from USA Connecticut (Seed Farm BP) to Germany (HQ Fertilizer) drop ship to BP C&W -> expected Exempt (core) + expectedTaxLookup(DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, + DictionaryIDs.AD_Org.FERTILIZER.id, DictionaryIDs.M_Warehouse.FERTILIZER.id, + bpSeed.getPrimaryC_BPartner_Location_ID(), bpSeed.getPrimaryC_BPartner_Location_ID(), bpCW.getPrimaryC_BPartner_Location_ID(), + false, null, taxExemptId); + + MSysConfig sysCfgTaxLookup = new MSysConfig(ctx, DictionaryIDs.AD_SysConfig.TAX_LOOKUP_SERVICE.id, null); + String oldValue = sysCfgTaxLookup.getValue(); + try { + sysCfgTaxLookup.setValue(MTaxTest_TaxLookup.class.getName()); + sysCfgTaxLookup.saveCrossTenantSafeEx(); + CacheMgt.get().reset(MSysConfig.Table_Name); + + // Drop Ship Case with custom tax lookup + // Purchase product from USA Connecticut (Seed Farm BP) to Germany (HQ Fertilizer) drop ship to BP C&W -> expected CT Sales (custom tax lookup) + expectedTaxLookup(DictionaryIDs.M_Product.AZALEA_BUSH.id, 0, + DictionaryIDs.AD_Org.FERTILIZER.id, DictionaryIDs.M_Warehouse.FERTILIZER.id, + bpSeed.getPrimaryC_BPartner_Location_ID(), bpSeed.getPrimaryC_BPartner_Location_ID(), bpCW.getPrimaryC_BPartner_Location_ID(), + false, null, DictionaryIDs.C_Tax.CT_SALES.id); + } finally { + sysCfgTaxLookup.setValue(oldValue); + sysCfgTaxLookup.saveCrossTenantSafeEx(); + } + } - + + private void expectedTaxLookup(int prodId, int chargeId, int orgId, int warehouseId, int billLocationId, int shipLocationId, int dropshipLocation, boolean isSOTrx, String deliveryViaRule, int expectedTaxId) { + Properties ctx = Env.getCtx(); + String trxName = getTrxName(); + + int id = Core.getTaxLookup().get(ctx, prodId, chargeId, getLoginDate(), getLoginDate(), orgId, warehouseId, + billLocationId, shipLocationId, + dropshipLocation, + isSOTrx, deliveryViaRule, trxName); + assertEquals(expectedTaxId, id, "Unexpected tax id"); + } + @Test public void testDistributeTaxToProductCost() { MProduct product = null; @@ -402,4 +492,5 @@ public class MTaxTest extends AbstractTestCase { category.deleteEx(true); } } + } diff --git a/org.idempiere.test/src/org/idempiere/test/model/MTaxTest_TaxLookup.java b/org.idempiere.test/src/org/idempiere/test/model/MTaxTest_TaxLookup.java new file mode 100644 index 0000000000..b9af633822 --- /dev/null +++ b/org.idempiere.test/src/org/idempiere/test/model/MTaxTest_TaxLookup.java @@ -0,0 +1,53 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - Diego Ruiz - BX Service * + **********************************************************************/ +package org.idempiere.test.model; + +import java.sql.Timestamp; +import java.util.Properties; + +import org.adempiere.base.DefaultTaxLookup; +import org.adempiere.base.ITaxLookup; +import org.osgi.service.component.annotations.Component; + +// test case copied from bxservice/de.bxservice.europeantaxprovider plugin +@Component(immediate = true, service = {ITaxLookup.class}) +public class MTaxTest_TaxLookup extends DefaultTaxLookup { + + @Override + public int get(Properties ctx, int C_TaxCategory_ID, boolean IsSOTrx, Timestamp shipDate, int shipFromC_Location_ID, + int shipToC_Location_ID, int dropshipToC_Location_ID, Timestamp billDate, int billFromC_Location_ID, int billToC_Location_ID, + String trxName) { + if (IsSOTrx) { + billToC_Location_ID = shipToC_Location_ID; + } else { + if (dropshipToC_Location_ID > 0 && dropshipToC_Location_ID != shipToC_Location_ID) + billToC_Location_ID = dropshipToC_Location_ID; + billFromC_Location_ID = shipFromC_Location_ID; + } + + return super.get(ctx, C_TaxCategory_ID, IsSOTrx, shipDate, shipFromC_Location_ID, shipToC_Location_ID, billDate, billFromC_Location_ID, billToC_Location_ID, trxName); + } + +}