IDEMPIERE-5056 Order and Invoice: Tax lookup interface (#1253)

* IDEMPIERE-5056 Order and Invoice: Tax lookup interface

* IDEMPIERE-5056 Order and Invoice: Tax lookup interface

- add default value for MSysConfig.getValue call.
This commit is contained in:
hengsin 2022-03-23 22:00:08 +08:00 committed by GitHub
parent d4532196a2
commit 3090f2384b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 444 additions and 28 deletions

View File

@ -0,0 +1,14 @@
-- IDEMPIERE-5056 Order and Invoice: Tax lookup interface
SELECT register_migration_script('202203171454_IDEMPIERE-5056.sql') FROM dual;
SET SQLBLANKLINES ON
SET DEFINE OFF
-- Mar 17, 2022, 2:54:31 PM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200198,0,0,TO_TIMESTAMP('2022-03-17 14:54:30','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-03-17 14:54:30','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','TAX_LOOKUP_SERVICE','50001','D','S','1161c587-6449-448a-9cb9-2fb600cf2b35')
;
-- Mar 17, 2022, 2:56:49 PM MYT
UPDATE AD_SysConfig SET Value='org.adempiere.base.DefaultTaxLookup', Description='OSGi component name of tax lookup service', ConfigurationLevel='C',Updated=TO_TIMESTAMP('2022-03-17 14:56:49','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200198
;

View File

@ -0,0 +1,11 @@
-- IDEMPIERE-5056 Order and Invoice: Tax lookup interface
SELECT register_migration_script('202203171454_IDEMPIERE-5056.sql') FROM dual;
-- Mar 17, 2022, 2:54:31 PM MYT
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200198,0,0,TO_TIMESTAMP('2022-03-17 14:54:30','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-03-17 14:54:30','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','TAX_LOOKUP_SERVICE','50001','D','S','1161c587-6449-448a-9cb9-2fb600cf2b35')
;
-- Mar 17, 2022, 2:56:49 PM MYT
UPDATE AD_SysConfig SET Value='org.adempiere.base.DefaultTaxLookup', Description='OSGi component name of tax lookup service', ConfigurationLevel='C',Updated=TO_TIMESTAMP('2022-03-17 14:56:49','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200198
;

View File

@ -36,7 +36,6 @@ import org.compiere.model.MOrderLine;
import org.compiere.model.MRMA; import org.compiere.model.MRMA;
import org.compiere.model.MRMALine; import org.compiere.model.MRMALine;
import org.compiere.model.Query; import org.compiere.model.Query;
import org.compiere.model.Tax;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
@ -160,11 +159,15 @@ public class CalloutRMA extends CalloutEngine {
pp.setPriceDate(invoice.getDateInvoiced()); pp.setPriceDate(invoice.getDateInvoiced());
precision = invoice.getPrecision(); precision = invoice.getPrecision();
taxId = Tax.get(ctx, M_Product_ID, 0, String deliveryViaRule = null;
if (invoice.getC_Order_ID() > 0) {
deliveryViaRule = new MOrder(ctx, invoice.getC_Order_ID(), null).getDeliveryViaRule();
}
taxId = Core.getTaxLookup().get(ctx, M_Product_ID, 0,
invoice.getDateInvoiced(), invoice.getDateInvoiced(), invoice.getDateInvoiced(), invoice.getDateInvoiced(),
AD_Org_ID, rma.getShipment().getM_Warehouse_ID(), AD_Org_ID, rma.getShipment().getM_Warehouse_ID(),
invoice.getC_BPartner_Location_ID(), // should be bill to invoice.getC_BPartner_Location_ID(), // should be bill to
invoice.getC_BPartner_Location_ID(), rma.isSOTrx(), null); invoice.getC_BPartner_Location_ID(), rma.isSOTrx(), deliveryViaRule, null);
} }
else else
{ {
@ -175,11 +178,11 @@ public class CalloutRMA extends CalloutEngine {
pp.setPriceDate(order.getDateOrdered()); pp.setPriceDate(order.getDateOrdered());
precision = order.getPrecision(); precision = order.getPrecision();
taxId = Tax.get(ctx, M_Product_ID, 0, taxId = Core.getTaxLookup().get(ctx, M_Product_ID, 0,
order.getDateOrdered(), order.getDateOrdered(), order.getDateOrdered(), order.getDateOrdered(),
AD_Org_ID, order.getM_Warehouse_ID(), AD_Org_ID, order.getM_Warehouse_ID(),
order.getC_BPartner_Location_ID(), // should be bill to order.getC_BPartner_Location_ID(), // should be bill to
order.getC_BPartner_Location_ID(), rma.isSOTrx(), null); order.getC_BPartner_Location_ID(), rma.isSOTrx(), order.getDeliveryViaRule(), null);
} }
else else
return "No Invoice/Order found the Shipment/Receipt associated"; return "No Invoice/Order found the Shipment/Receipt associated";

View File

@ -488,9 +488,10 @@ public class CalloutInvoice extends CalloutEngine
if (log.isLoggable(Level.FINE)) log.fine("Warehouse=" + M_Warehouse_ID); if (log.isLoggable(Level.FINE)) log.fine("Warehouse=" + M_Warehouse_ID);
// //
int C_Tax_ID = Tax.get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, String deliveryViaRule = getLineDeliveryViaRule(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,
Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y"), null); Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y"), deliveryViaRule, null);
if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID); if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID);
// //
if (C_Tax_ID == 0) if (C_Tax_ID == 0)
@ -501,7 +502,29 @@ public class CalloutInvoice extends CalloutEngine
return amt (ctx, WindowNo, mTab, mField, value); return amt (ctx, WindowNo, mTab, mField, value);
} // tax } // tax
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");
if (C_OrderLine_ID > 0) {
MOrderLine orderLine = new MOrderLine(ctx, C_OrderLine_ID, null);
return orderLine.getParent().getDeliveryViaRule();
}
}
if (mTab.getValue("M_InOutLine_ID") != null) {
int M_InOutLine_ID = (Integer) mTab.getValue("M_InOutLine_ID");
if (M_InOutLine_ID > 0) {
MInOutLine ioLine = new MInOutLine(ctx, M_InOutLine_ID, null);
return ioLine.getParent().getDeliveryViaRule();
}
}
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.getDeliveryViaRule();
}
return null;
}
/** /**
* Invoice - Amount. * Invoice - Amount.
* - called from QtyInvoiced, PriceActual * - called from QtyInvoiced, PriceActual

View File

@ -25,6 +25,7 @@ import java.sql.Timestamp;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.base.Core;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.DisplayType; import org.compiere.util.DisplayType;
@ -317,9 +318,10 @@ public class CalloutInvoiceBatch extends CalloutEngine
if (log.isLoggable(Level.FINE)) log.fine("Warehouse=" + M_Warehouse_ID); if (log.isLoggable(Level.FINE)) log.fine("Warehouse=" + M_Warehouse_ID);
// //
int C_Tax_ID = Tax.get(ctx, 0, C_Charge_ID, billDate, shipDate, String deliveryViaRule = getLineDeliveryViaRule(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,
Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y"), null); Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y"), deliveryViaRule, null);
if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID); if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID);
// //
if (C_Tax_ID == 0) if (C_Tax_ID == 0)
@ -330,7 +332,36 @@ public class CalloutInvoiceBatch extends CalloutEngine
return amt (ctx, WindowNo, mTab, mField, value); return amt (ctx, WindowNo, mTab, mField, value);
} // tax } // tax
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");
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().getDeliveryViaRule();
}
int M_InOutLine_ID = invoiceLine.getM_InOutLine_ID();
if (M_InOutLine_ID > 0) {
MInOutLine ioLine = new MInOutLine(ctx, M_InOutLine_ID, null);
return ioLine.getParent().getDeliveryViaRule();
}
}
}
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.getDeliveryViaRule();
}
}
}
return null;
}
/** /**
* Invoice - Amount. * Invoice - Amount.
* - called from QtyEntered, PriceEntered * - called from QtyEntered, PriceEntered

View File

@ -981,9 +981,10 @@ public class CalloutOrder extends CalloutEngine
if (log.isLoggable(Level.FINE)) log.fine("Bill BP_Location=" + billC_BPartner_Location_ID); if (log.isLoggable(Level.FINE)) log.fine("Bill BP_Location=" + billC_BPartner_Location_ID);
// //
int C_Tax_ID = Tax.get (ctx, M_Product_ID, C_Charge_ID, billDate, shipDate, String deliveryViaRule = Env.getContext(ctx, WindowNo, I_C_Order.COLUMNNAME_DeliveryViaRule, 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,
"Y".equals(Env.getContext(ctx, WindowNo, "IsSOTrx")), null); "Y".equals(Env.getContext(ctx, WindowNo, "IsSOTrx")), deliveryViaRule, null);
if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID); if (log.isLoggable(Level.INFO)) log.info("Tax ID=" + C_Tax_ID);
// //
if (C_Tax_ID == 0) if (C_Tax_ID == 0)

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.adempiere.base.DefaultTaxLookup">
<service>
<provide interface="org.adempiere.base.ITaxLookup"/>
</service>
<implementation class="org.adempiere.base.DefaultTaxLookup"/>
</scr:component>

View File

@ -45,6 +45,7 @@ import org.compiere.model.MAddressValidation;
import org.compiere.model.MAuthorizationAccount; import org.compiere.model.MAuthorizationAccount;
import org.compiere.model.MBankAccountProcessor; import org.compiere.model.MBankAccountProcessor;
import org.compiere.model.MPaymentProcessor; import org.compiere.model.MPaymentProcessor;
import org.compiere.model.MSysConfig;
import org.compiere.model.MTaxProvider; import org.compiere.model.MTaxProvider;
import org.compiere.model.ModelValidator; import org.compiere.model.ModelValidator;
import org.compiere.model.PaymentInterface; import org.compiere.model.PaymentInterface;
@ -1061,4 +1062,18 @@ public class Core {
return DefaultReservationTracerFactory.getInstance(); return DefaultReservationTracerFactory.getInstance();
} }
/**
* Get tax lookup service
* @return ITaxLookup service
*/
public static ITaxLookup getTaxLookup() {
String service = MSysConfig.getValue(MSysConfig.TAX_LOOKUP_SERVICE, DefaultTaxLookup.class.getName(), Env.getAD_Client_ID(Env.getCtx()));
IServiceHolder<ITaxLookup> serviceHolder = Service.locator().locate(ITaxLookup.class, service, null);
if (serviceHolder != null)
return serviceHolder.getService();
//fall back, should not reach here
return new DefaultTaxLookup();
}
} }

View File

@ -0,0 +1,64 @@
/***********************************************************************
* 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: *
* - hengsin *
**********************************************************************/
package org.adempiere.base;
import java.sql.Timestamp;
import java.util.Properties;
import org.compiere.model.Tax;
import org.osgi.service.component.annotations.Component;
/**
* @author hengsin
*
*/
@Component(immediate = true, service = {ITaxLookup.class})
public class DefaultTaxLookup implements ITaxLookup {
/**
* default constructor
*/
public DefaultTaxLookup() {
}
/* (non-Javadoc)
* @see org.adempiere.base.ITaxLookup#get(java.util.Properties, int, int, java.sql.Timestamp, java.sql.Timestamp, int, int, int, int, boolean, java.lang.String)
*/
@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,
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,
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,
String trxName) {
return Tax.get(ctx, C_TaxCategory_ID, IsSOTrx, shipDate, shipFromC_Location_ID, shipToC_Location_ID, billDate, billFromC_Location_ID, billToC_Location_ID, trxName);
}
}

View File

@ -0,0 +1,78 @@
/***********************************************************************
* 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: *
* - hengsin *
**********************************************************************/
package org.adempiere.base;
import java.sql.Timestamp;
import java.util.Properties;
/**
* Interface to lookup C_Tax record id
* @author hengsin
*
*/
public interface ITaxLookup {
/**
* 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 IsSOTrx
* @param deliveryViaRule Order/Invoice's Delivery Via Rule
* @param trxName
* @return C_Tax_ID
*/
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);
/**
* 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 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 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, String trxName);
}

View File

@ -477,10 +477,18 @@ public class MInvoiceLine extends X_C_InvoiceLine
// //
int M_Warehouse_ID = Env.getContextAsInt(getCtx(), Env.M_WAREHOUSE_ID); int M_Warehouse_ID = Env.getContextAsInt(getCtx(), Env.M_WAREHOUSE_ID);
// //
int C_Tax_ID = Tax.get(getCtx(), getM_Product_ID(), getC_Charge_ID() , m_DateInvoiced, m_DateInvoiced, String deliveryViaRule = null;
if (getC_OrderLine_ID() > 0) {
deliveryViaRule = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName()).getParent().getDeliveryViaRule();
} else if (getM_InOutLine_ID() > 0) {
deliveryViaRule = new MInOutLine(getCtx(), getM_InOutLine_ID(), get_TrxName()).getParent().getDeliveryViaRule();
} else if (getParent().getC_Order_ID() > 0) {
deliveryViaRule = new MOrder(getCtx(), getParent().getC_Order_ID(), get_TrxName()).getDeliveryViaRule();
}
int C_Tax_ID = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID() , m_DateInvoiced, m_DateInvoiced,
getAD_Org_ID(), M_Warehouse_ID, getAD_Org_ID(), M_Warehouse_ID,
m_C_BPartner_Location_ID, // should be bill to m_C_BPartner_Location_ID, // should be bill to
m_C_BPartner_Location_ID, m_IsSOTrx, get_TrxName()); m_C_BPartner_Location_ID, m_IsSOTrx, deliveryViaRule, get_TrxName());
if (C_Tax_ID == 0) if (C_Tax_ID == 0)
{ {
log.log(Level.SEVERE, "No Tax found"); log.log(Level.SEVERE, "No Tax found");

View File

@ -329,10 +329,10 @@ public class MOrderLine extends X_C_OrderLine
*/ */
public boolean setTax() public boolean setTax()
{ {
int ii = Tax.get(getCtx(), getM_Product_ID(), getC_Charge_ID(), getDateOrdered(), getDateOrdered(), int ii = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID(), getDateOrdered(), getDateOrdered(),
getAD_Org_ID(), getM_Warehouse_ID(), getAD_Org_ID(), getM_Warehouse_ID(),
getC_BPartner_Location_ID(), // should be bill to getC_BPartner_Location_ID(), // should be bill to
getC_BPartner_Location_ID(), m_IsSOTrx, get_TrxName()); getC_BPartner_Location_ID(), m_IsSOTrx, getParent().getDeliveryViaRule(), get_TrxName());
if (ii == 0) if (ii == 0)
{ {
log.log(Level.SEVERE, "No Tax found"); log.log(Level.SEVERE, "No Tax found");

View File

@ -162,10 +162,14 @@ public class MRMALine extends X_M_RMALine
pp.setPriceDate(invoice.getDateInvoiced()); pp.setPriceDate(invoice.getDateInvoiced());
precision = invoice.getPrecision(); precision = invoice.getPrecision();
taxId = Tax.get(getCtx(), getM_Product_ID(), getC_Charge_ID(), invoice.getDateInvoiced(), invoice.getDateInvoiced(), String deliveryViaRule = null;
if (invoice.getC_Order_ID() > 0) {
deliveryViaRule = new MOrder(getCtx(), invoice.getC_Order_ID(), get_TrxName()).getDeliveryViaRule();
}
taxId = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID(), invoice.getDateInvoiced(), invoice.getDateInvoiced(),
getAD_Org_ID(), getParent().getShipment().getM_Warehouse_ID(), getAD_Org_ID(), getParent().getShipment().getM_Warehouse_ID(),
invoice.getC_BPartner_Location_ID(), // should be bill to invoice.getC_BPartner_Location_ID(), // should be bill to
invoice.getC_BPartner_Location_ID(), getParent().isSOTrx(), get_TrxName()); invoice.getC_BPartner_Location_ID(), getParent().isSOTrx(), deliveryViaRule, get_TrxName());
} }
else else
{ {
@ -176,10 +180,10 @@ public class MRMALine extends X_M_RMALine
pp.setPriceDate(order.getDateOrdered()); pp.setPriceDate(order.getDateOrdered());
precision = order.getPrecision(); precision = order.getPrecision();
taxId = Tax.get(getCtx(), getM_Product_ID(), getC_Charge_ID(), order.getDateOrdered(), order.getDateOrdered(), taxId = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID(), order.getDateOrdered(), order.getDateOrdered(),
getAD_Org_ID(), order.getM_Warehouse_ID(), getAD_Org_ID(), order.getM_Warehouse_ID(),
order.getC_BPartner_Location_ID(), // should be bill to order.getC_BPartner_Location_ID(), // should be bill to
order.getC_BPartner_Location_ID(), getParent().isSOTrx(), get_TrxName()); order.getC_BPartner_Location_ID(), getParent().isSOTrx(), order.getDeliveryViaRule(), get_TrxName());
} }
else else
throw new IllegalStateException("No Invoice/Order found the Shipment/Receipt associated"); throw new IllegalStateException("No Invoice/Order found the Shipment/Receipt associated");

View File

@ -161,6 +161,7 @@ public class MSysConfig extends X_AD_SysConfig
public static final String SYSTEM_IN_MAINTENANCE_MODE = "SYSTEM_IN_MAINTENANCE_MODE"; public static final String SYSTEM_IN_MAINTENANCE_MODE = "SYSTEM_IN_MAINTENANCE_MODE";
public static final String SYSTEM_INSERT_CHANGELOG = "SYSTEM_INSERT_CHANGELOG"; public static final String SYSTEM_INSERT_CHANGELOG = "SYSTEM_INSERT_CHANGELOG";
public static final String SYSTEM_NATIVE_SEQUENCE = "SYSTEM_NATIVE_SEQUENCE"; public static final String SYSTEM_NATIVE_SEQUENCE = "SYSTEM_NATIVE_SEQUENCE";
public static final String TAX_LOOKUP_SERVICE="TAX_LOOKUP_SERVICE";
public static final String TOP_MARGIN_PIXELS_FOR_HEADER = "TOP_MARGIN_PIXELS_FOR_HEADER"; public static final String TOP_MARGIN_PIXELS_FOR_HEADER = "TOP_MARGIN_PIXELS_FOR_HEADER";
public static final String TRACE_ALL_TRX_CONNECTION_GET = "TRACE_ALL_TRX_CONNECTION_GET"; public static final String TRACE_ALL_TRX_CONNECTION_GET = "TRACE_ALL_TRX_CONNECTION_GET";
public static final String TWOPACK_COMMIT_DDL = "2PACK_COMMIT_DDL"; public static final String TWOPACK_COMMIT_DDL = "2PACK_COMMIT_DDL";

View File

@ -23,6 +23,7 @@ import java.sql.Timestamp;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.base.Core;
import org.adempiere.exceptions.DBException; import org.adempiere.exceptions.DBException;
import org.adempiere.exceptions.TaxCriteriaNotFoundException; import org.adempiere.exceptions.TaxCriteriaNotFoundException;
import org.adempiere.exceptions.TaxForChangeNotFoundException; import org.adempiere.exceptions.TaxForChangeNotFoundException;
@ -93,6 +94,7 @@ public class Tax
* @param billC_BPartner_Location_ID invoice location * @param billC_BPartner_Location_ID invoice location
* @param shipC_BPartner_Location_ID ship location (ignored) * @param shipC_BPartner_Location_ID ship location (ignored)
* @param IsSOTrx is a sales trx * @param IsSOTrx is a sales trx
* @param trxName
* @return C_Tax_ID * @return C_Tax_ID
* @throws TaxCriteriaNotFoundException if a criteria was not found * @throws TaxCriteriaNotFoundException if a criteria was not found
*/ */
@ -101,13 +103,50 @@ public class Tax
int AD_Org_ID, int M_Warehouse_ID, 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,
boolean IsSOTrx, String trxName) 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);
}
/**************************************************************************
* Get Tax ID - converts parameters to call Get Tax.
* <pre>{@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
* }</pre>
* @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 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,
boolean IsSOTrx, String deliveryViaRule, String trxName)
{ {
if (M_Product_ID != 0) if (M_Product_ID != 0)
return getProduct (ctx, M_Product_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, return getProduct (ctx, M_Product_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID,
billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, trxName); billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, deliveryViaRule, trxName);
else if (C_Charge_ID != 0) else if (C_Charge_ID != 0)
return getCharge (ctx, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, return getCharge (ctx, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID,
billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, trxName); billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, deliveryViaRule, trxName);
else else
return getExemptTax (ctx, AD_Org_ID, trxName); return getExemptTax (ctx, AD_Org_ID, trxName);
} // get } // get
@ -134,6 +173,42 @@ public class Tax
return getCharge(ctx, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, null); return getCharge(ctx, C_Charge_ID, billDate, shipDate, AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID, IsSOTrx, null);
} }
/**
* Get Tax ID - converts parameters to call Get Tax.
* <pre>{@code
* C_Charge_ID -> C_TaxCategory_ID
* billDate -> billDate
* shipDate -> shipDate (ignored)
* AD_Org_ID -> billFromC_Location_ID
* M_Warehouse_ID -> shipFromC_Location_ID (ignored)
* billC_BPartner_Location_ID -> billToC_Location_ID
* shipC_BPartner_Location_ID -> shipToC_Location_ID (ignored)
*
* if IsSOTrx is false, bill and ship are reversed
* }</pre>
* @param ctx context
* @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 IsSOTrx is a sales trx
* @param trxName
* @return C_Tax_ID
* @throws TaxForChangeNotFoundException if criteria not found for given change
* @throws TaxCriteriaNotFoundException if a criteria was not found
*/
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,
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);
}
/** /**
* Get Tax ID - converts parameters to call Get Tax. * Get Tax ID - converts parameters to call Get Tax.
@ -157,6 +232,8 @@ public class Tax
* @param billC_BPartner_Location_ID invoice location * @param billC_BPartner_Location_ID invoice location
* @param shipC_BPartner_Location_ID ship location (ignored) * @param shipC_BPartner_Location_ID ship location (ignored)
* @param IsSOTrx is a sales trx * @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 * @return C_Tax_ID
* @throws TaxForChangeNotFoundException if criteria not found for given change * @throws TaxForChangeNotFoundException if criteria not found for given change
* @throws TaxCriteriaNotFoundException if a criteria was not found * @throws TaxCriteriaNotFoundException if a criteria was not found
@ -165,13 +242,14 @@ public class Tax
Timestamp billDate, Timestamp shipDate, Timestamp billDate, Timestamp shipDate,
int AD_Org_ID, int M_Warehouse_ID, 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,
boolean IsSOTrx, String trxName) boolean IsSOTrx, String deliveryViaRule, String trxName)
{ {
int C_TaxCategory_ID = 0; int C_TaxCategory_ID = 0;
int shipFromC_Location_ID = 0; int shipFromC_Location_ID = 0;
int shipToC_Location_ID = 0; int shipToC_Location_ID = 0;
int billFromC_Location_ID = 0; int billFromC_Location_ID = 0;
int billToC_Location_ID = 0; int billToC_Location_ID = 0;
int warehouseC_Location_ID = 0;
String IsTaxExempt = null; String IsTaxExempt = null;
String IsSOTaxExempt = null; String IsSOTaxExempt = null;
String IsPOTaxExempt = null; String IsPOTaxExempt = null;
@ -208,6 +286,7 @@ public class Tax
IsTaxExempt = IsSOTrx ? IsSOTaxExempt : IsPOTaxExempt; IsTaxExempt = IsSOTrx ? IsSOTaxExempt : IsPOTaxExempt;
shipFromC_Location_ID = rs.getInt (6); shipFromC_Location_ID = rs.getInt (6);
shipToC_Location_ID = rs.getInt (7); shipToC_Location_ID = rs.getInt (7);
warehouseC_Location_ID = rs.getInt(6);
found = true; found = true;
} }
DB.close(rs, pstmt); DB.close(rs, pstmt);
@ -243,13 +322,17 @@ public class Tax
shipFromC_Location_ID = shipToC_Location_ID; shipFromC_Location_ID = shipToC_Location_ID;
shipToC_Location_ID = temp; shipToC_Location_ID = temp;
} }
else if (X_C_Order.DELIVERYVIARULE_Pickup.equals(deliveryViaRule))
{
billToC_Location_ID = warehouseC_Location_ID;
}
// //
if (log.isLoggable(Level.FINE)) log.fine("getCharge - C_TaxCategory_ID=" + C_TaxCategory_ID if (log.isLoggable(Level.FINE)) log.fine("getCharge - C_TaxCategory_ID=" + C_TaxCategory_ID
+ ", billFromC_Location_ID=" + billFromC_Location_ID + ", billFromC_Location_ID=" + billFromC_Location_ID
+ ", billToC_Location_ID=" + billToC_Location_ID + ", billToC_Location_ID=" + billToC_Location_ID
+ ", shipFromC_Location_ID=" + shipFromC_Location_ID + ", shipFromC_Location_ID=" + shipFromC_Location_ID
+ ", shipToC_Location_ID=" + shipToC_Location_ID); + ", shipToC_Location_ID=" + shipToC_Location_ID);
return get (ctx, C_TaxCategory_ID, IsSOTrx, return Core.getTaxLookup().get (ctx, C_TaxCategory_ID, IsSOTrx,
shipDate, shipFromC_Location_ID, shipToC_Location_ID, shipDate, shipFromC_Location_ID, shipToC_Location_ID,
billDate, billFromC_Location_ID, billToC_Location_ID, trxName); billDate, billFromC_Location_ID, billToC_Location_ID, trxName);
} // getCharge } // getCharge
@ -299,6 +382,7 @@ public class Tax
* @param billC_BPartner_Location_ID invoice location * @param billC_BPartner_Location_ID invoice location
* @param shipC_BPartner_Location_ID ship location (ignored) * @param shipC_BPartner_Location_ID ship location (ignored)
* @param IsSOTrx is a sales trx * @param IsSOTrx is a sales trx
* @param trxName
* @return C_Tax_ID * @return C_Tax_ID
* If error it returns 0 and sets error log (TaxCriteriaNotFound) * If error it returns 0 and sets error log (TaxCriteriaNotFound)
*/ */
@ -307,6 +391,43 @@ public class Tax
int AD_Org_ID, int M_Warehouse_ID, 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,
boolean IsSOTrx, String trxName) 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);
}
/**
* Get Tax ID - converts parameters to call Get Tax.
* <pre>{@code
* M_Product_ID -> C_TaxCategory_ID
* billDate -> billDate
* shipDate -> shipDate (ignored)
* AD_Org_ID -> billFromC_Location_ID
* M_Warehouse_ID -> shipFromC_Location_ID (ignored)
* billC_BPartner_Location_ID -> billToC_Location_ID
* shipC_BPartner_Location_ID -> shipToC_Location_ID (ignored)
*
* if IsSOTrx is false, bill and ship are reversed
* }</pre>
* @param ctx context
* @param M_Product_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 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
* If error it returns 0 and sets error log (TaxCriteriaNotFound)
*/
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,
boolean IsSOTrx, String deliveryViaRule, String trxName)
{ {
String variable = ""; String variable = "";
int C_TaxCategory_ID = 0; int C_TaxCategory_ID = 0;
@ -314,6 +435,7 @@ public class Tax
int shipToC_Location_ID = 0; int shipToC_Location_ID = 0;
int billFromC_Location_ID = 0; int billFromC_Location_ID = 0;
int billToC_Location_ID = 0; int billToC_Location_ID = 0;
int warehouseC_Location_ID = 0;
String IsTaxExempt = null; String IsTaxExempt = null;
String IsSOTaxExempt = null; String IsSOTaxExempt = null;
String IsPOTaxExempt = null; String IsPOTaxExempt = null;
@ -351,6 +473,7 @@ public class Tax
IsTaxExempt = IsSOTrx ? IsSOTaxExempt : IsPOTaxExempt; IsTaxExempt = IsSOTrx ? IsSOTaxExempt : IsPOTaxExempt;
shipFromC_Location_ID = rs.getInt(6); shipFromC_Location_ID = rs.getInt(6);
shipToC_Location_ID = rs.getInt(7); shipToC_Location_ID = rs.getInt(7);
warehouseC_Location_ID = rs.getInt(6);
found = true; found = true;
} }
DB.close(rs, pstmt); DB.close(rs, pstmt);
@ -371,12 +494,16 @@ public class Tax
shipFromC_Location_ID = shipToC_Location_ID; shipFromC_Location_ID = shipToC_Location_ID;
shipToC_Location_ID = temp; shipToC_Location_ID = temp;
} }
else if (X_C_Order.DELIVERYVIARULE_Pickup.equals(deliveryViaRule))
{
billToC_Location_ID = warehouseC_Location_ID;
}
if (log.isLoggable(Level.FINE)) log.fine("getProduct - C_TaxCategory_ID=" + C_TaxCategory_ID if (log.isLoggable(Level.FINE)) log.fine("getProduct - C_TaxCategory_ID=" + C_TaxCategory_ID
+ ", billFromC_Location_ID=" + billFromC_Location_ID + ", billFromC_Location_ID=" + billFromC_Location_ID
+ ", billToC_Location_ID=" + billToC_Location_ID + ", billToC_Location_ID=" + billToC_Location_ID
+ ", shipFromC_Location_ID=" + shipFromC_Location_ID + ", shipFromC_Location_ID=" + shipFromC_Location_ID
+ ", shipToC_Location_ID=" + shipToC_Location_ID); + ", shipToC_Location_ID=" + shipToC_Location_ID);
return get(ctx, C_TaxCategory_ID, IsSOTrx, return Core.getTaxLookup().get(ctx, C_TaxCategory_ID, IsSOTrx,
shipDate, shipFromC_Location_ID, shipToC_Location_ID, shipDate, shipFromC_Location_ID, shipToC_Location_ID,
billDate, billFromC_Location_ID, billToC_Location_ID, trxName); billDate, billFromC_Location_ID, billToC_Location_ID, trxName);
} }
@ -528,8 +655,8 @@ public class Tax
* @param shipFromC_Location_ID ship from (ignored) * @param shipFromC_Location_ID ship from (ignored)
* @param shipToC_Location_ID ship to (ignored) * @param shipToC_Location_ID ship to (ignored)
* @param billDate invoice date * @param billDate invoice date
* @param billFromC_Location_ID invoice from * @param billFromC_Location_ID invoice from (Tax Location from)
* @param billToC_Location_ID invoice to * @param billToC_Location_ID invoice to (Tax Location to)
* @param trxName Transaction * @param trxName Transaction
* @return C_Tax_ID * @return C_Tax_ID
* @throws TaxNotFoundException if no tax found for given criteria * @throws TaxNotFoundException if no tax found for given criteria

View File

@ -25,8 +25,12 @@
package org.idempiere.test.model; package org.idempiere.test.model;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.adempiere.base.Core;
import org.compiere.model.MBPartner;
import org.compiere.model.MTax; import org.compiere.model.MTax;
import org.compiere.model.Tax;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.TimeUtil; import org.compiere.util.TimeUtil;
import org.idempiere.test.AbstractTestCase; import org.idempiere.test.AbstractTestCase;
@ -42,6 +46,9 @@ public class MTaxTest extends AbstractTestCase {
private static final int STANDARD_TAX_ID = 104; private static final int STANDARD_TAX_ID = 104;
private static final int STANDARD_TAX_CATEGORY_ID=107; private static final int STANDARD_TAX_CATEGORY_ID=107;
private final static int BP_JOE_BLOCK = 118;
private static final int PRODUCT_MULCH = 137;
public MTaxTest() { public MTaxTest() {
} }
@ -60,4 +67,26 @@ public class MTaxTest extends AbstractTestCase {
tax.saveEx(); tax.saveEx();
assertEquals(0, tax.getParent_Tax_ID(), "Unexpected parent tax id"); assertEquals(0, tax.getParent_Tax_ID(), "Unexpected parent tax id");
} }
@Test
public void testTaxLookup() {
int taxExemptId = Tax.getExemptTax(Env.getCtx(), getAD_Org_ID(), getTrxName());
assertTrue(taxExemptId>0, "Fail to get tax exempt Id");
MBPartner bp = new MBPartner(Env.getCtx(), BP_JOE_BLOCK, getTrxName());
bp.setIsTaxExempt(true);
bp.saveEx();
int id = Core.getTaxLookup().get(Env.getCtx(), PRODUCT_MULCH, 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(), PRODUCT_MULCH, 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(STANDARD_TAX_ID, id, "Unexpected tax id");
}
} }