IDEMPIERE-5768 : Adding Credit manager factory to override or extend … (#1949)
* IDEMPIERE-5768 : Adding Credit manager factory to override or extend credit management * IDEMPIERE-5768 : Fixing as as per code review comments from Hengsin * IDEMPIERE-5768: Use component annotation instead of xml service definition * IDEMPIERE-5768: Adding Unit tests and Making return type of CheckCreditStatus to be object instead of String. * IDEMPIERE-5768: Fixing as per code review comment. * IDEMPIERE-5768: Removed explicit rollback from test cases
This commit is contained in:
parent
5aba739d37
commit
18f925fd2f
|
@ -48,6 +48,7 @@ import org.compiere.model.MPaymentProcessor;
|
||||||
import org.compiere.model.MSysConfig;
|
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.PO;
|
||||||
import org.compiere.model.PaymentInterface;
|
import org.compiere.model.PaymentInterface;
|
||||||
import org.compiere.model.PaymentProcessor;
|
import org.compiere.model.PaymentProcessor;
|
||||||
import org.compiere.model.StandardTaxProvider;
|
import org.compiere.model.StandardTaxProvider;
|
||||||
|
@ -1087,4 +1088,42 @@ public class Core {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get Credit Manager
|
||||||
|
*
|
||||||
|
* @param PO
|
||||||
|
* @return instance of the ICreditManager
|
||||||
|
*/
|
||||||
|
public static ICreditManager getCreditManager(PO po)
|
||||||
|
{
|
||||||
|
if (po == null)
|
||||||
|
{
|
||||||
|
s_log.log(Level.SEVERE, "Invalid PO");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICreditManager myCreditManager = null;
|
||||||
|
|
||||||
|
List<ICreditManagerFactory> factoryList = Service.locator().list(ICreditManagerFactory.class).getServices();
|
||||||
|
if (factoryList != null)
|
||||||
|
{
|
||||||
|
for (ICreditManagerFactory factory : factoryList)
|
||||||
|
{
|
||||||
|
myCreditManager = factory.getCreditManager(po);
|
||||||
|
if (myCreditManager != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myCreditManager == null)
|
||||||
|
{
|
||||||
|
s_log.log(Level.CONFIG, "For " + po.get_TableName() + " not found any service/extension registry.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return myCreditManager;
|
||||||
|
} // getCreditManager
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.adempiere.base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POJO for Credit Status
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since August 04, 2023
|
||||||
|
*/
|
||||||
|
public class CreditStatus
|
||||||
|
{
|
||||||
|
protected String errorMsg;
|
||||||
|
protected boolean isError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit Status Load Constructor
|
||||||
|
*
|
||||||
|
* @param errorMsg
|
||||||
|
* @param isError
|
||||||
|
*/
|
||||||
|
public CreditStatus(String errorMsg, boolean isError)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.errorMsg = errorMsg;
|
||||||
|
this.isError = isError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMsg()
|
||||||
|
{
|
||||||
|
return errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorMsg(String errorMsg)
|
||||||
|
{
|
||||||
|
this.errorMsg = errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isError()
|
||||||
|
{
|
||||||
|
return isError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setError(boolean isError)
|
||||||
|
{
|
||||||
|
this.isError = isError;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.adempiere.base;
|
||||||
|
|
||||||
|
import org.compiere.model.MInOut;
|
||||||
|
import org.compiere.model.MInvoice;
|
||||||
|
import org.compiere.model.MOrder;
|
||||||
|
import org.compiere.model.MPayment;
|
||||||
|
import org.compiere.model.PO;
|
||||||
|
import org.compiere.model.credit.CreditManagerInOut;
|
||||||
|
import org.compiere.model.credit.CreditManagerInvoice;
|
||||||
|
import org.compiere.model.credit.CreditManagerOrder;
|
||||||
|
import org.compiere.model.credit.CreditManagerPayment;
|
||||||
|
import org.osgi.service.component.annotations.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Credit Manager Factory
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since June 25, 2023
|
||||||
|
*/
|
||||||
|
@Component(immediate = true, service = ICreditManagerFactory.class)
|
||||||
|
public class DefaultCreditManagerFactory implements ICreditManagerFactory
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICreditManager getCreditManager(PO po)
|
||||||
|
{
|
||||||
|
if (po instanceof MOrder)
|
||||||
|
return new CreditManagerOrder((MOrder) po);
|
||||||
|
else if (po instanceof MInvoice)
|
||||||
|
return new CreditManagerInvoice((MInvoice) po);
|
||||||
|
else if (po instanceof MPayment)
|
||||||
|
return new CreditManagerPayment((MPayment) po);
|
||||||
|
else if (po instanceof MInOut)
|
||||||
|
return new CreditManagerInOut((MInOut) po);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.adempiere.base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for Credit Manager implementor
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since June 25, 2023
|
||||||
|
*/
|
||||||
|
public interface ICreditManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check credit status as per document action
|
||||||
|
*
|
||||||
|
* @param docAction Document Action
|
||||||
|
* @return Credit Status POJO
|
||||||
|
*/
|
||||||
|
public CreditStatus checkCreditStatus(String docAction);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.adempiere.base;
|
||||||
|
|
||||||
|
import org.compiere.model.PO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for Credit Manager Factory
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since June 25, 2023
|
||||||
|
*/
|
||||||
|
public interface ICreditManagerFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* get Credit Manager
|
||||||
|
*
|
||||||
|
* @param po Model class
|
||||||
|
* @return instance of the ICreditManager
|
||||||
|
*/
|
||||||
|
public ICreditManager getCreditManager(PO po);
|
||||||
|
}
|
|
@ -29,6 +29,8 @@ import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.adempiere.base.Core;
|
import org.adempiere.base.Core;
|
||||||
|
import org.adempiere.base.CreditStatus;
|
||||||
|
import org.adempiere.base.ICreditManager;
|
||||||
import org.adempiere.exceptions.AdempiereException;
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.adempiere.exceptions.DBException;
|
import org.adempiere.exceptions.DBException;
|
||||||
import org.adempiere.exceptions.NegativeInventoryDisallowedException;
|
import org.adempiere.exceptions.NegativeInventoryDisallowedException;
|
||||||
|
@ -1454,41 +1456,15 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credit Check
|
// Credit Check
|
||||||
if (isSOTrx() && !isReversal() && !isCustomerReturn())
|
ICreditManager creditManager = Core.getCreditManager(this);
|
||||||
|
if (creditManager != null)
|
||||||
{
|
{
|
||||||
I_C_Order order = getC_Order();
|
CreditStatus status = creditManager.checkCreditStatus(DOCACTION_Prepare);
|
||||||
if (order != null && MDocType.DOCSUBTYPESO_PrepayOrder.equals(order.getC_DocType().getDocSubTypeSO())
|
if (status.isError())
|
||||||
&& !MSysConfig.getBooleanValue(MSysConfig.CHECK_CREDIT_ON_PREPAY_ORDER, true, getAD_Client_ID(), getAD_Org_ID())) {
|
|
||||||
// ignore -- don't validate Prepay Orders depending on sysconfig parameter
|
|
||||||
} else {
|
|
||||||
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
|
|
||||||
if (MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()))
|
|
||||||
{
|
{
|
||||||
m_processMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@="
|
m_processMsg = status.getErrorMsg();
|
||||||
+ bp.getTotalOpenBalance()
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus()))
|
|
||||||
{
|
|
||||||
m_processMsg = "@BPartnerCreditHold@ - @TotalOpenBalance@="
|
|
||||||
+ bp.getTotalOpenBalance()
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
|
||||||
}
|
|
||||||
if (!MBPartner.SOCREDITSTATUS_NoCreditCheck.equals(bp.getSOCreditStatus())
|
|
||||||
&& Env.ZERO.compareTo(bp.getSO_CreditLimit()) != 0)
|
|
||||||
{
|
|
||||||
BigDecimal notInvoicedAmt = MBPartner.getNotInvoicedAmt(getC_BPartner_ID());
|
|
||||||
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus(notInvoicedAmt)))
|
|
||||||
{
|
|
||||||
m_processMsg = "@BPartnerOverSCreditHold@ - @TotalOpenBalance@="
|
|
||||||
+ bp.getTotalOpenBalance() + ", @NotInvoicedAmt@=" + notInvoicedAmt
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lines
|
// Lines
|
||||||
|
@ -1557,7 +1533,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess
|
||||||
* Check if Document is Customer Return.
|
* Check if Document is Customer Return.
|
||||||
* @return True if Document is Customer Return
|
* @return True if Document is Customer Return
|
||||||
*/
|
*/
|
||||||
private boolean isCustomerReturn() {
|
public boolean isCustomerReturn() {
|
||||||
MDocType doctype = MDocType.get(getC_DocType_ID());
|
MDocType doctype = MDocType.get(getC_DocType_ID());
|
||||||
if(isSOTrx() && doctype.getDocBaseType().equals("MMR") && doctype.isSOTrx())
|
if(isSOTrx() && doctype.getDocBaseType().equals("MMR") && doctype.isSOTrx())
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -32,6 +32,8 @@ import java.util.Vector;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.adempiere.base.Core;
|
import org.adempiere.base.Core;
|
||||||
|
import org.adempiere.base.CreditStatus;
|
||||||
|
import org.adempiere.base.ICreditManager;
|
||||||
import org.adempiere.exceptions.AdempiereException;
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.adempiere.exceptions.BPartnerNoAddressException;
|
import org.adempiere.exceptions.BPartnerNoAddressException;
|
||||||
import org.adempiere.exceptions.DBException;
|
import org.adempiere.exceptions.DBException;
|
||||||
|
@ -1737,24 +1739,16 @@ public class MInvoice extends X_C_Invoice implements DocAction, IDocsPostProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credit Status
|
// Credit Status
|
||||||
if (isSOTrx())
|
ICreditManager creditManager = Core.getCreditManager(this);
|
||||||
|
if (creditManager != null)
|
||||||
{
|
{
|
||||||
MDocType doc = (MDocType) getC_DocTypeTarget();
|
CreditStatus status = creditManager.checkCreditStatus(DOCACTION_Prepare);
|
||||||
// IDEMPIERE-365 - just check credit if is going to increase the debt
|
if (status.isError())
|
||||||
if ( (doc.getDocBaseType().equals(MDocType.DOCBASETYPE_ARCreditMemo) && getGrandTotal().signum() < 0 ) ||
|
|
||||||
(doc.getDocBaseType().equals(MDocType.DOCBASETYPE_ARInvoice) && getGrandTotal().signum() > 0 )
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), null);
|
m_processMsg = status.getErrorMsg();
|
||||||
if ( MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()) )
|
|
||||||
{
|
|
||||||
m_processMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@="
|
|
||||||
+ bp.getTotalOpenBalance()
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Landed Costs
|
// Landed Costs
|
||||||
if (!isSOTrx())
|
if (!isSOTrx())
|
||||||
|
@ -2144,76 +2138,15 @@ public class MInvoice extends X_C_Invoice implements DocAction, IDocsPostProcess
|
||||||
if (matchPO > 0)
|
if (matchPO > 0)
|
||||||
info.append(" @M_MatchPO_ID@#").append(matchPO).append(" ");
|
info.append(" @M_MatchPO_ID@#").append(matchPO).append(" ");
|
||||||
|
|
||||||
|
ICreditManager creditManager = Core.getCreditManager(this);
|
||||||
|
if (creditManager != null)
|
||||||
// Update BP Statistics
|
|
||||||
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
|
|
||||||
DB.getDatabase().forUpdate(bp, 0);
|
|
||||||
// Update total revenue and balance / credit limit (reversed on AllocationLine.processIt)
|
|
||||||
BigDecimal invAmt = null;
|
|
||||||
int baseCurrencyId = Env.getContextAsInt(getCtx(), Env.C_CURRENCY_ID);
|
|
||||||
if (getC_Currency_ID() != baseCurrencyId && isOverrideCurrencyRate())
|
|
||||||
{
|
{
|
||||||
invAmt = getGrandTotal(true).multiply(getCurrencyRate());
|
CreditStatus status = creditManager.checkCreditStatus(DOCACTION_Complete);
|
||||||
int stdPrecision = MCurrency.getStdPrecision(getCtx(), baseCurrencyId);
|
if (status.isError())
|
||||||
if (invAmt.scale() > stdPrecision)
|
|
||||||
invAmt = invAmt.setScale(stdPrecision, RoundingMode.HALF_UP);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
invAmt = MConversionRate.convertBase(getCtx(), getGrandTotal(true), // CM adjusted
|
m_processMsg = status.getErrorMsg();
|
||||||
getC_Currency_ID(), getDateAcct(), getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
|
|
||||||
}
|
|
||||||
if (invAmt == null)
|
|
||||||
{
|
|
||||||
m_processMsg = MConversionRateUtil.getErrorMessage(getCtx(), "ErrorConvertingCurrencyToBaseCurrency",
|
|
||||||
getC_Currency_ID(), MClient.get(getCtx()).getC_Currency_ID(), getC_ConversionType_ID(), getDateAcct(), get_TrxName());
|
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
// Total Balance
|
|
||||||
BigDecimal newBalance = bp.getTotalOpenBalance();
|
|
||||||
if (newBalance == null)
|
|
||||||
newBalance = Env.ZERO;
|
|
||||||
if (isSOTrx())
|
|
||||||
{
|
|
||||||
newBalance = newBalance.add(invAmt);
|
|
||||||
//
|
|
||||||
if (bp.getFirstSale() == null)
|
|
||||||
bp.setFirstSale(getDateInvoiced());
|
|
||||||
BigDecimal newLifeAmt = bp.getActualLifeTimeValue();
|
|
||||||
if (newLifeAmt == null)
|
|
||||||
newLifeAmt = invAmt;
|
|
||||||
else
|
|
||||||
newLifeAmt = newLifeAmt.add(invAmt);
|
|
||||||
BigDecimal newCreditAmt = bp.getSO_CreditUsed();
|
|
||||||
if (newCreditAmt == null)
|
|
||||||
newCreditAmt = invAmt;
|
|
||||||
else
|
|
||||||
newCreditAmt = newCreditAmt.add(invAmt);
|
|
||||||
//
|
|
||||||
if (log.isLoggable(Level.FINE)) log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt
|
|
||||||
+ ") BP Life=" + bp.getActualLifeTimeValue() + "->" + newLifeAmt
|
|
||||||
+ ", Credit=" + bp.getSO_CreditUsed() + "->" + newCreditAmt
|
|
||||||
+ ", Balance=" + bp.getTotalOpenBalance() + " -> " + newBalance);
|
|
||||||
bp.setActualLifeTimeValue(newLifeAmt);
|
|
||||||
bp.setSO_CreditUsed(newCreditAmt);
|
|
||||||
} // SO
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newBalance = newBalance.subtract(invAmt);
|
|
||||||
if (log.isLoggable(Level.FINE)) log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt
|
|
||||||
+ ") Balance=" + bp.getTotalOpenBalance() + " -> " + newBalance);
|
|
||||||
}
|
|
||||||
// the payment just created already updated the open balance
|
|
||||||
if ( ! (PAYMENTRULE_Cash.equals(getPaymentRule()) && !fromPOS ) )
|
|
||||||
{
|
|
||||||
bp.setTotalOpenBalance(newBalance);
|
|
||||||
}
|
|
||||||
bp.setSOCreditStatus();
|
|
||||||
if (!bp.save(get_TrxName()))
|
|
||||||
{
|
|
||||||
m_processMsg = "Could not update Business Partner";
|
|
||||||
return DocAction.STATUS_Invalid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// User - Last Result/Contact
|
// User - Last Result/Contact
|
||||||
|
|
|
@ -30,6 +30,8 @@ import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.adempiere.base.Core;
|
import org.adempiere.base.Core;
|
||||||
|
import org.adempiere.base.CreditStatus;
|
||||||
|
import org.adempiere.base.ICreditManager;
|
||||||
import org.adempiere.exceptions.AdempiereException;
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.adempiere.exceptions.BPartnerNoBillToAddressException;
|
import org.adempiere.exceptions.BPartnerNoBillToAddressException;
|
||||||
import org.adempiere.exceptions.BPartnerNoShipToAddressException;
|
import org.adempiere.exceptions.BPartnerNoShipToAddressException;
|
||||||
|
@ -1683,47 +1685,15 @@ public class MOrder extends X_C_Order implements DocAction
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credit Check
|
// Credit Check
|
||||||
if (isSOTrx())
|
ICreditManager creditManager = Core.getCreditManager(this);
|
||||||
|
if (creditManager != null)
|
||||||
{
|
{
|
||||||
if ( MDocType.DOCSUBTYPESO_POSOrder.equals(dt.getDocSubTypeSO())
|
CreditStatus status = creditManager.checkCreditStatus(DOCACTION_Prepare);
|
||||||
&& PAYMENTRULE_Cash.equals(getPaymentRule())
|
if (status.isError())
|
||||||
&& !MSysConfig.getBooleanValue(MSysConfig.CHECK_CREDIT_ON_CASH_POS_ORDER, true, getAD_Client_ID(), getAD_Org_ID())) {
|
|
||||||
// ignore -- don't validate for Cash POS Orders depending on sysconfig parameter
|
|
||||||
} else if (MDocType.DOCSUBTYPESO_PrepayOrder.equals(dt.getDocSubTypeSO())
|
|
||||||
&& !MSysConfig.getBooleanValue(MSysConfig.CHECK_CREDIT_ON_PREPAY_ORDER, true, getAD_Client_ID(), getAD_Org_ID())) {
|
|
||||||
// ignore -- don't validate Prepay Orders depending on sysconfig parameter
|
|
||||||
} else {
|
|
||||||
MBPartner bp = new MBPartner (getCtx(), getBill_BPartner_ID(), get_TrxName()); // bill bp is guaranteed on beforeSave
|
|
||||||
|
|
||||||
if (getGrandTotal().signum() > 0) // IDEMPIERE-365 - just check credit if is going to increase the debt
|
|
||||||
{
|
{
|
||||||
|
m_processMsg = status.getErrorMsg();
|
||||||
if (MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()))
|
|
||||||
{
|
|
||||||
m_processMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@="
|
|
||||||
+ bp.getTotalOpenBalance()
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus()))
|
|
||||||
{
|
|
||||||
m_processMsg = "@BPartnerCreditHold@ - @TotalOpenBalance@="
|
|
||||||
+ bp.getTotalOpenBalance()
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
|
||||||
}
|
|
||||||
BigDecimal grandTotal = MConversionRate.convertBase(getCtx(),
|
|
||||||
getGrandTotal(), getC_Currency_ID(), getDateOrdered(),
|
|
||||||
getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
|
|
||||||
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus(grandTotal)))
|
|
||||||
{
|
|
||||||
m_processMsg = "@BPartnerOverOCreditHold@ - @TotalOpenBalance@="
|
|
||||||
+ bp.getTotalOpenBalance() + ", @GrandTotal@=" + grandTotal
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE);
|
m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE);
|
||||||
|
|
|
@ -29,6 +29,9 @@ import java.util.Properties;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.adempiere.base.Core;
|
||||||
|
import org.adempiere.base.CreditStatus;
|
||||||
|
import org.adempiere.base.ICreditManager;
|
||||||
import org.adempiere.exceptions.AdempiereException;
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.adempiere.exceptions.PeriodClosedException;
|
import org.adempiere.exceptions.PeriodClosedException;
|
||||||
import org.adempiere.util.IProcessUI;
|
import org.adempiere.util.IProcessUI;
|
||||||
|
@ -1985,22 +1988,13 @@ public class MPayment extends X_C_Payment
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not pay when Credit Stop/Hold
|
ICreditManager creditManager = Core.getCreditManager(this);
|
||||||
if (!isReceipt())
|
if (creditManager != null)
|
||||||
{
|
{
|
||||||
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
|
CreditStatus status = creditManager.checkCreditStatus(DOCACTION_Prepare);
|
||||||
if (X_C_BPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()))
|
if (status.isError())
|
||||||
{
|
{
|
||||||
m_processMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@="
|
m_processMsg = status.getErrorMsg();
|
||||||
+ bp.getTotalOpenBalance()
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
|
||||||
}
|
|
||||||
if (X_C_BPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus()))
|
|
||||||
{
|
|
||||||
m_processMsg = "@BPartnerCreditHold@ - @TotalOpenBalance@="
|
|
||||||
+ bp.getTotalOpenBalance()
|
|
||||||
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2066,53 +2060,21 @@ public class MPayment extends X_C_Payment
|
||||||
if (log.isLoggable(Level.INFO)) log.info(toString());
|
if (log.isLoggable(Level.INFO)) log.info(toString());
|
||||||
|
|
||||||
// Charge Handling
|
// Charge Handling
|
||||||
boolean createdAllocationRecords = false;
|
|
||||||
if (getC_Charge_ID() != 0)
|
if (getC_Charge_ID() != 0)
|
||||||
{
|
{
|
||||||
setIsAllocated(true);
|
setIsAllocated(true);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
createdAllocationRecords = allocateIt(); // Create Allocation Records
|
|
||||||
testAllocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update BP for Prepayments
|
ICreditManager creditManager = Core.getCreditManager(this);
|
||||||
if (getC_BPartner_ID() != 0 && getC_Invoice_ID() == 0 && getC_Charge_ID() == 0 && MPaymentAllocate.get(this).length == 0 && !createdAllocationRecords)
|
if (creditManager != null)
|
||||||
{
|
{
|
||||||
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
|
CreditStatus status = creditManager.checkCreditStatus(DOCACTION_Complete);
|
||||||
DB.getDatabase().forUpdate(bp, 0);
|
if (status.isError())
|
||||||
// Update total balance to include this payment
|
|
||||||
BigDecimal payAmt = null;
|
|
||||||
int baseCurrencyId = Env.getContextAsInt(getCtx(), Env.C_CURRENCY_ID);
|
|
||||||
if (getC_Currency_ID() != baseCurrencyId && isOverrideCurrencyRate())
|
|
||||||
{
|
{
|
||||||
payAmt = getConvertedAmt();
|
m_processMsg = status.getErrorMsg();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
payAmt = MConversionRate.convertBase(getCtx(), getPayAmt(),
|
|
||||||
getC_Currency_ID(), getDateAcct(), getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
|
|
||||||
if (payAmt == null)
|
|
||||||
{
|
|
||||||
m_processMsg = MConversionRateUtil.getErrorMessage(getCtx(), "ErrorConvertingCurrencyToBaseCurrency",
|
|
||||||
getC_Currency_ID(), MClient.get(getCtx()).getC_Currency_ID(), getC_ConversionType_ID(), getDateAcct(), get_TrxName());
|
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Total Balance
|
|
||||||
BigDecimal newBalance = bp.getTotalOpenBalance();
|
|
||||||
if (newBalance == null)
|
|
||||||
newBalance = Env.ZERO;
|
|
||||||
if (isReceipt())
|
|
||||||
newBalance = newBalance.subtract(payAmt);
|
|
||||||
else
|
|
||||||
newBalance = newBalance.add(payAmt);
|
|
||||||
|
|
||||||
bp.setTotalOpenBalance(newBalance);
|
|
||||||
bp.setSOCreditStatus();
|
|
||||||
bp.saveEx();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Counter Doc
|
// Counter Doc
|
||||||
MPayment counter = createCounterDoc();
|
MPayment counter = createCounterDoc();
|
||||||
|
@ -2832,13 +2794,10 @@ public class MPayment extends X_C_Payment
|
||||||
//
|
//
|
||||||
info.append(" - @C_AllocationHdr_ID@: ").append(alloc.getDocumentNo());
|
info.append(" - @C_AllocationHdr_ID@: ").append(alloc.getDocumentNo());
|
||||||
|
|
||||||
|
ICreditManager creditManager = Core.getCreditManager(this);
|
||||||
// Update BPartner
|
// Update BPartner
|
||||||
if (getC_BPartner_ID() != 0)
|
if (creditManager != null)
|
||||||
{
|
creditManager.checkCreditStatus(accrual ? DOCACTION_Reverse_Accrual : DOCACTION_Reverse_Correct);
|
||||||
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
|
|
||||||
bp.setTotalOpenBalance();
|
|
||||||
bp.saveEx(get_TrxName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.compiere.model.credit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import org.adempiere.base.CreditStatus;
|
||||||
|
import org.adempiere.base.ICreditManager;
|
||||||
|
import org.compiere.model.I_C_Order;
|
||||||
|
import org.compiere.model.MBPartner;
|
||||||
|
import org.compiere.model.MDocType;
|
||||||
|
import org.compiere.model.MInOut;
|
||||||
|
import org.compiere.model.MSysConfig;
|
||||||
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit Manager for InOut
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since June 25, 2023
|
||||||
|
*/
|
||||||
|
public class CreditManagerInOut implements ICreditManager
|
||||||
|
{
|
||||||
|
private MInOut mInOut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InOut Credit Manager Load Constructor
|
||||||
|
*
|
||||||
|
* @param po MInOut
|
||||||
|
*/
|
||||||
|
public CreditManagerInOut(MInOut po)
|
||||||
|
{
|
||||||
|
this.mInOut = po;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CreditStatus checkCreditStatus(String docAction)
|
||||||
|
{
|
||||||
|
String errorMsg = null;
|
||||||
|
if (MInOut.DOCACTION_Prepare.equals(docAction) && mInOut.isSOTrx() && !mInOut.isReversal() && !mInOut.isCustomerReturn())
|
||||||
|
{
|
||||||
|
I_C_Order order = mInOut.getC_Order();
|
||||||
|
if (order != null
|
||||||
|
&& MDocType.DOCSUBTYPESO_PrepayOrder.equals(order.getC_DocType().getDocSubTypeSO())
|
||||||
|
&& !MSysConfig.getBooleanValue(MSysConfig.CHECK_CREDIT_ON_PREPAY_ORDER, true, mInOut.getAD_Client_ID(), mInOut.getAD_Org_ID()))
|
||||||
|
{
|
||||||
|
// ignore -- don't validate Prepay Orders depending on sysconfig parameter
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MBPartner bp = new MBPartner(mInOut.getCtx(), mInOut.getC_BPartner_ID(), mInOut.get_TrxName());
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus()))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerCreditHold@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
if (!MBPartner.SOCREDITSTATUS_NoCreditCheck.equals(bp.getSOCreditStatus())
|
||||||
|
&& Env.ZERO.compareTo(bp.getSO_CreditLimit()) != 0)
|
||||||
|
{
|
||||||
|
BigDecimal notInvoicedAmt = MBPartner.getNotInvoicedAmt(mInOut.getC_BPartner_ID());
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus(notInvoicedAmt)))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerOverSCreditHold@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @NotInvoicedAmt@=" + notInvoicedAmt
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CreditStatus(errorMsg, !Util.isEmpty(errorMsg));
|
||||||
|
} // creditCheck
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.compiere.model.credit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.adempiere.base.CreditStatus;
|
||||||
|
import org.adempiere.base.ICreditManager;
|
||||||
|
import org.compiere.model.MBPartner;
|
||||||
|
import org.compiere.model.MClient;
|
||||||
|
import org.compiere.model.MConversionRate;
|
||||||
|
import org.compiere.model.MConversionRateUtil;
|
||||||
|
import org.compiere.model.MCurrency;
|
||||||
|
import org.compiere.model.MDocType;
|
||||||
|
import org.compiere.model.MInvoice;
|
||||||
|
import org.compiere.util.CLogger;
|
||||||
|
import org.compiere.util.DB;
|
||||||
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit Manager for Invoice
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since June 25, 2023
|
||||||
|
*/
|
||||||
|
public class CreditManagerInvoice implements ICreditManager
|
||||||
|
{
|
||||||
|
/** Logger */
|
||||||
|
protected transient CLogger log = CLogger.getCLogger(CreditManagerInvoice.class);
|
||||||
|
|
||||||
|
private MInvoice mInvoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Credit Manager Load Constructor
|
||||||
|
*
|
||||||
|
* @param po MInvoice
|
||||||
|
*/
|
||||||
|
public CreditManagerInvoice(MInvoice po)
|
||||||
|
{
|
||||||
|
this.mInvoice = po;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CreditStatus checkCreditStatus(String docAction)
|
||||||
|
{
|
||||||
|
String errorMsg = null;
|
||||||
|
if (MInvoice.DOCACTION_Prepare.equals(docAction) && mInvoice.isSOTrx())
|
||||||
|
{
|
||||||
|
MDocType doc = (MDocType) mInvoice.getC_DocTypeTarget();
|
||||||
|
// IDEMPIERE-365 - just check credit if is going to increase the debt
|
||||||
|
if ((doc.getDocBaseType().equals(MDocType.DOCBASETYPE_ARCreditMemo) && mInvoice.getGrandTotal().signum() < 0)
|
||||||
|
|| (doc.getDocBaseType().equals(MDocType.DOCBASETYPE_ARInvoice) && mInvoice.getGrandTotal().signum() > 0))
|
||||||
|
{
|
||||||
|
MBPartner bp = new MBPartner(mInvoice.getCtx(), mInvoice.getC_BPartner_ID(), mInvoice.get_TrxName());
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (MInvoice.DOCACTION_Complete.equals(docAction))
|
||||||
|
{
|
||||||
|
// POS supports multiple payments
|
||||||
|
boolean fromPOS = false;
|
||||||
|
if (mInvoice.getC_Order_ID() > 0)
|
||||||
|
{
|
||||||
|
fromPOS = mInvoice.getC_Order().getC_POS_ID() > 0;
|
||||||
|
}
|
||||||
|
// Update BP Statistics
|
||||||
|
MBPartner bp = new MBPartner(mInvoice.getCtx(), mInvoice.getC_BPartner_ID(), mInvoice.get_TrxName());
|
||||||
|
DB.getDatabase().forUpdate(bp, 0);
|
||||||
|
// Update total revenue and balance / credit limit (reversed on
|
||||||
|
// AllocationLine.processIt)
|
||||||
|
BigDecimal invAmt = null;
|
||||||
|
int baseCurrencyId = Env.getContextAsInt(mInvoice.getCtx(), Env.C_CURRENCY_ID);
|
||||||
|
if (mInvoice.getC_Currency_ID() != baseCurrencyId && mInvoice.isOverrideCurrencyRate())
|
||||||
|
{
|
||||||
|
invAmt = mInvoice.getGrandTotal(true).multiply(mInvoice.getCurrencyRate());
|
||||||
|
int stdPrecision = MCurrency.getStdPrecision(mInvoice.getCtx(), baseCurrencyId);
|
||||||
|
if (invAmt.scale() > stdPrecision)
|
||||||
|
invAmt = invAmt.setScale(stdPrecision, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
invAmt = MConversionRate.convertBase( mInvoice.getCtx(),
|
||||||
|
mInvoice.getGrandTotal(true), // CM adjusted
|
||||||
|
mInvoice.getC_Currency_ID(),
|
||||||
|
mInvoice.getDateAcct(),
|
||||||
|
mInvoice.getC_ConversionType_ID(),
|
||||||
|
mInvoice.getAD_Client_ID(),
|
||||||
|
mInvoice.getAD_Org_ID());
|
||||||
|
}
|
||||||
|
if (invAmt == null)
|
||||||
|
{
|
||||||
|
errorMsg = MConversionRateUtil.getErrorMessage( mInvoice.getCtx(),
|
||||||
|
"ErrorConvertingCurrencyToBaseCurrency",
|
||||||
|
mInvoice.getC_Currency_ID(),
|
||||||
|
MClient.get(mInvoice.getCtx()).getC_Currency_ID(),
|
||||||
|
mInvoice.getC_ConversionType_ID(),
|
||||||
|
mInvoice.getDateAcct(),
|
||||||
|
mInvoice.get_TrxName());
|
||||||
|
}
|
||||||
|
// Total Balance
|
||||||
|
BigDecimal newBalance = bp.getTotalOpenBalance();
|
||||||
|
if (newBalance == null)
|
||||||
|
newBalance = Env.ZERO;
|
||||||
|
if (mInvoice.isSOTrx())
|
||||||
|
{
|
||||||
|
newBalance = newBalance.add(invAmt);
|
||||||
|
//
|
||||||
|
if (bp.getFirstSale() == null)
|
||||||
|
bp.setFirstSale(mInvoice.getDateInvoiced());
|
||||||
|
|
||||||
|
BigDecimal newLifeAmt = bp.getActualLifeTimeValue();
|
||||||
|
if (newLifeAmt == null)
|
||||||
|
newLifeAmt = invAmt;
|
||||||
|
else
|
||||||
|
newLifeAmt = newLifeAmt.add(invAmt);
|
||||||
|
|
||||||
|
BigDecimal newCreditAmt = bp.getSO_CreditUsed();
|
||||||
|
if (newCreditAmt == null)
|
||||||
|
newCreditAmt = invAmt;
|
||||||
|
else
|
||||||
|
newCreditAmt = newCreditAmt.add(invAmt);
|
||||||
|
//
|
||||||
|
if (log.isLoggable(Level.FINE))
|
||||||
|
log.fine( "GrandTotal=" + mInvoice.getGrandTotal(true) + "(" + invAmt
|
||||||
|
+ ") BP Life=" + bp.getActualLifeTimeValue() + "->" + newLifeAmt
|
||||||
|
+ ", Credit=" + bp.getSO_CreditUsed() + "->" + newCreditAmt
|
||||||
|
+ ", Balance=" + bp.getTotalOpenBalance() + " -> " + newBalance);
|
||||||
|
bp.setActualLifeTimeValue(newLifeAmt);
|
||||||
|
bp.setSO_CreditUsed(newCreditAmt);
|
||||||
|
} // SO
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newBalance = newBalance.subtract(invAmt);
|
||||||
|
if (log.isLoggable(Level.FINE))
|
||||||
|
log.fine( "GrandTotal=" + mInvoice.getGrandTotal(true) + "(" + invAmt
|
||||||
|
+ ") Balance=" + bp.getTotalOpenBalance() + " -> " + newBalance);
|
||||||
|
}
|
||||||
|
// the payment just created already updated the open balance
|
||||||
|
if (!(MInvoice.PAYMENTRULE_Cash.equals(mInvoice.getPaymentRule()) && !fromPOS))
|
||||||
|
{
|
||||||
|
bp.setTotalOpenBalance(newBalance);
|
||||||
|
}
|
||||||
|
bp.setSOCreditStatus();
|
||||||
|
if (!bp.save(mInvoice.get_TrxName()))
|
||||||
|
{
|
||||||
|
errorMsg = "Could not update Business Partner";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new CreditStatus(errorMsg, !Util.isEmpty(errorMsg));
|
||||||
|
} // creditCheck
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.compiere.model.credit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.adempiere.base.CreditStatus;
|
||||||
|
import org.adempiere.base.ICreditManager;
|
||||||
|
import org.compiere.model.MBPartner;
|
||||||
|
import org.compiere.model.MConversionRate;
|
||||||
|
import org.compiere.model.MDocType;
|
||||||
|
import org.compiere.model.MOrder;
|
||||||
|
import org.compiere.model.MSysConfig;
|
||||||
|
import org.compiere.util.Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit Manager for Order
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since June 25, 2023
|
||||||
|
*/
|
||||||
|
public class CreditManagerOrder implements ICreditManager
|
||||||
|
{
|
||||||
|
|
||||||
|
private MOrder order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Order Credit Manager Load Constructor
|
||||||
|
*
|
||||||
|
* @param po MOrder
|
||||||
|
*/
|
||||||
|
public CreditManagerOrder(MOrder po)
|
||||||
|
{
|
||||||
|
this.order = po;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CreditStatus checkCreditStatus(String docAction)
|
||||||
|
{
|
||||||
|
String errorMsg = null;
|
||||||
|
if (MOrder.DOCACTION_Prepare.equals(docAction) && order.isSOTrx())
|
||||||
|
{
|
||||||
|
Properties ctx = order.getCtx();
|
||||||
|
MDocType dt = MDocType.get(ctx, order.getC_DocTypeTarget_ID());
|
||||||
|
if (MDocType.DOCSUBTYPESO_POSOrder.equals(dt.getDocSubTypeSO())
|
||||||
|
&& MOrder.PAYMENTRULE_Cash.equals(order.getPaymentRule())
|
||||||
|
&& !MSysConfig.getBooleanValue(MSysConfig.CHECK_CREDIT_ON_CASH_POS_ORDER, true, order.getAD_Client_ID(), order.getAD_Org_ID()))
|
||||||
|
{
|
||||||
|
// ignore -- don't validate for Cash POS Orders depending on sysconfig parameter
|
||||||
|
}
|
||||||
|
else if (MDocType.DOCSUBTYPESO_PrepayOrder.equals(dt.getDocSubTypeSO())
|
||||||
|
&& !MSysConfig.getBooleanValue(MSysConfig.CHECK_CREDIT_ON_PREPAY_ORDER, true, order.getAD_Client_ID(), order.getAD_Org_ID()))
|
||||||
|
{
|
||||||
|
// ignore -- don't validate Prepay Orders depending on sysconfig parameter
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// bill bp is guaranteed on beforeSave
|
||||||
|
MBPartner bp = new MBPartner(ctx, order.getBill_BPartner_ID(), order.get_TrxName());
|
||||||
|
// IDEMPIERE-365 - just check credit if is going to increase the debt
|
||||||
|
if (order.getGrandTotal().signum() > 0)
|
||||||
|
{
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus()))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerCreditHold@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal grandTotal = MConversionRate.convertBase(ctx, order.getGrandTotal(), order.getC_Currency_ID(),
|
||||||
|
order.getDateOrdered(), order.getC_ConversionType_ID(),
|
||||||
|
order.getAD_Client_ID(), order.getAD_Org_ID());
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus(grandTotal)))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerOverOCreditHold@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @GrandTotal@=" + grandTotal
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new CreditStatus(errorMsg, !Util.isEmpty(errorMsg));
|
||||||
|
} // creditCheck
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.compiere.model.credit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.adempiere.base.CreditStatus;
|
||||||
|
import org.adempiere.base.ICreditManager;
|
||||||
|
import org.compiere.model.MBPartner;
|
||||||
|
import org.compiere.model.MClient;
|
||||||
|
import org.compiere.model.MConversionRate;
|
||||||
|
import org.compiere.model.MConversionRateUtil;
|
||||||
|
import org.compiere.model.MPayment;
|
||||||
|
import org.compiere.model.MPaymentAllocate;
|
||||||
|
import org.compiere.util.DB;
|
||||||
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit Manager for Payment
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since June 25, 2023
|
||||||
|
*/
|
||||||
|
public class CreditManagerPayment implements ICreditManager
|
||||||
|
{
|
||||||
|
private MPayment payment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment Credit Manager Load Constructor
|
||||||
|
*
|
||||||
|
* @param po MPayment
|
||||||
|
*/
|
||||||
|
public CreditManagerPayment(MPayment po)
|
||||||
|
{
|
||||||
|
this.payment = po;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CreditStatus checkCreditStatus(String docAction)
|
||||||
|
{
|
||||||
|
String errorMsg = null;
|
||||||
|
if (MPayment.DOCACTION_Prepare.equals(docAction) && !payment.isReceipt())
|
||||||
|
{ // Do not pay when Credit Stop/Hold and issue refund to customer
|
||||||
|
MBPartner bp = new MBPartner(payment.getCtx(), payment.getC_BPartner_ID(), payment.get_TrxName());
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
if (MBPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus()))
|
||||||
|
{
|
||||||
|
errorMsg = "@BPartnerCreditHold@ - @TotalOpenBalance@=" + bp.getTotalOpenBalance()
|
||||||
|
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (MPayment.DOCACTION_Complete.equals(docAction))
|
||||||
|
{
|
||||||
|
// Charge Handling
|
||||||
|
boolean createdAllocationRecords = false;
|
||||||
|
if (payment.getC_Charge_ID() == 0)
|
||||||
|
{
|
||||||
|
createdAllocationRecords = payment.allocateIt(); // Create Allocation Records
|
||||||
|
payment.testAllocation();
|
||||||
|
}
|
||||||
|
// Update BP for Prepayments
|
||||||
|
if (payment.getC_BPartner_ID() != 0
|
||||||
|
&& payment.getC_Invoice_ID() == 0
|
||||||
|
&& payment.getC_Charge_ID() == 0
|
||||||
|
&& MPaymentAllocate.get(payment).length == 0
|
||||||
|
&& !createdAllocationRecords)
|
||||||
|
{
|
||||||
|
Properties ctx = payment.getCtx();
|
||||||
|
MBPartner bp = new MBPartner(ctx, payment.getC_BPartner_ID(), payment.get_TrxName());
|
||||||
|
DB.getDatabase().forUpdate(bp, 0);
|
||||||
|
// Update total balance to include this payment
|
||||||
|
BigDecimal payAmt = null;
|
||||||
|
int baseCurrencyId = Env.getContextAsInt(ctx, Env.C_CURRENCY_ID);
|
||||||
|
if (payment.getC_Currency_ID() != baseCurrencyId && payment.isOverrideCurrencyRate())
|
||||||
|
{
|
||||||
|
payAmt = payment.getConvertedAmt();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
payAmt = MConversionRate.convertBase( ctx, payment.getPayAmt(),
|
||||||
|
payment.getC_Currency_ID(),
|
||||||
|
payment.getDateAcct(),
|
||||||
|
payment.getC_ConversionType_ID(),
|
||||||
|
payment.getAD_Client_ID(),
|
||||||
|
payment.getAD_Org_ID());
|
||||||
|
|
||||||
|
if (payAmt == null)
|
||||||
|
{
|
||||||
|
errorMsg = MConversionRateUtil.getErrorMessage( ctx, "ErrorConvertingCurrencyToBaseCurrency",
|
||||||
|
payment.getC_Currency_ID(),
|
||||||
|
MClient.get(ctx).getC_Currency_ID(),
|
||||||
|
payment.getC_ConversionType_ID(),
|
||||||
|
payment.getDateAcct(), payment.get_TrxName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Total Balance
|
||||||
|
BigDecimal newBalance = bp.getTotalOpenBalance();
|
||||||
|
if (newBalance == null)
|
||||||
|
newBalance = Env.ZERO;
|
||||||
|
if (payment.isReceipt())
|
||||||
|
newBalance = newBalance.subtract(payAmt);
|
||||||
|
else
|
||||||
|
newBalance = newBalance.add(payAmt);
|
||||||
|
|
||||||
|
bp.setTotalOpenBalance(newBalance);
|
||||||
|
bp.setSOCreditStatus();
|
||||||
|
bp.saveEx();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (MPayment.DOCACTION_Reverse_Accrual.equals(docAction) || MPayment.DOCACTION_Reverse_Correct.equals(docAction))
|
||||||
|
{
|
||||||
|
if (payment.getC_BPartner_ID() != 0)
|
||||||
|
{
|
||||||
|
MBPartner bp = new MBPartner(payment.getCtx(), payment.getC_BPartner_ID(), payment.get_TrxName());
|
||||||
|
bp.setTotalOpenBalance();
|
||||||
|
bp.saveEx(payment.get_TrxName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new CreditStatus(errorMsg, !Util.isEmpty(errorMsg));
|
||||||
|
} // creditCheck
|
||||||
|
}
|
|
@ -121,12 +121,12 @@ public class InOutTest extends AbstractTestCase {
|
||||||
try {
|
try {
|
||||||
MOrder order = createPurchaseOrder(bpartner, currentDate, priceList.getM_PriceList_ID(), Company_ConversionType_ID);
|
MOrder order = createPurchaseOrder(bpartner, currentDate, priceList.getM_PriceList_ID(), Company_ConversionType_ID);
|
||||||
BigDecimal qtyOrdered = new BigDecimal(500);
|
BigDecimal qtyOrdered = new BigDecimal(500);
|
||||||
MOrderLine orderLine = createPurchaseOrderLine(order, 10, product, qtyOrdered, priceInAud);
|
MOrderLine orderLine = createOrderLine(order, 10, product, qtyOrdered, priceInAud);
|
||||||
completeDocument(order);
|
completeDocument(order);
|
||||||
|
|
||||||
MInOut receipt = createMMReceipt(order, currentDate);
|
MInOut receipt = createMMReceipt(order, currentDate);
|
||||||
BigDecimal qtyDelivered = new BigDecimal(500);
|
BigDecimal qtyDelivered = new BigDecimal(500);
|
||||||
MInOutLine receiptLine = createMMReceiptLine(receipt, orderLine, qtyDelivered);
|
MInOutLine receiptLine = createInOutLine(receipt, orderLine, qtyDelivered);
|
||||||
completeDocument(receipt);
|
completeDocument(receipt);
|
||||||
postDocument(receipt);
|
postDocument(receipt);
|
||||||
|
|
||||||
|
@ -162,11 +162,11 @@ public class InOutTest extends AbstractTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
order = createPurchaseOrder(bpartner, currentDate, priceList.getM_PriceList_ID(), Spot_ConversionType_ID);
|
order = createPurchaseOrder(bpartner, currentDate, priceList.getM_PriceList_ID(), Spot_ConversionType_ID);
|
||||||
orderLine = createPurchaseOrderLine(order, 10, product, qtyOrdered, priceInAud);
|
orderLine = createOrderLine(order, 10, product, qtyOrdered, priceInAud);
|
||||||
completeDocument(order);
|
completeDocument(order);
|
||||||
|
|
||||||
receipt = createMMReceipt(order, currentDate);
|
receipt = createMMReceipt(order, currentDate);
|
||||||
receiptLine = createMMReceiptLine(receipt, orderLine, qtyDelivered);
|
receiptLine = createInOutLine(receipt, orderLine, qtyDelivered);
|
||||||
completeDocument(receipt);
|
completeDocument(receipt);
|
||||||
postDocument(receipt);
|
postDocument(receipt);
|
||||||
|
|
||||||
|
@ -251,12 +251,12 @@ public class InOutTest extends AbstractTestCase {
|
||||||
try {
|
try {
|
||||||
MOrder order = createPurchaseOrder(bpartner, currentDate, priceList.getM_PriceList_ID(), Company_ConversionType_ID);
|
MOrder order = createPurchaseOrder(bpartner, currentDate, priceList.getM_PriceList_ID(), Company_ConversionType_ID);
|
||||||
BigDecimal qtyOrdered = BigDecimal.TEN;
|
BigDecimal qtyOrdered = BigDecimal.TEN;
|
||||||
MOrderLine orderLine = createPurchaseOrderLine(order, 10, product, qtyOrdered, priceInAud);
|
MOrderLine orderLine = createOrderLine(order, 10, product, qtyOrdered, priceInAud);
|
||||||
completeDocument(order);
|
completeDocument(order);
|
||||||
|
|
||||||
MInOut receipt = createMMReceipt(order, currentDate);
|
MInOut receipt = createMMReceipt(order, currentDate);
|
||||||
BigDecimal qtyDelivered = BigDecimal.TEN;
|
BigDecimal qtyDelivered = BigDecimal.TEN;
|
||||||
MInOutLine receiptLine = createMMReceiptLine(receipt, orderLine, qtyDelivered);
|
MInOutLine receiptLine = createInOutLine(receipt, orderLine, qtyDelivered);
|
||||||
completeDocument(receipt);
|
completeDocument(receipt);
|
||||||
postDocument(receipt);
|
postDocument(receipt);
|
||||||
|
|
||||||
|
@ -384,22 +384,35 @@ public class InOutTest extends AbstractTestCase {
|
||||||
ConversionRateHelper.deleteConversionRate(cr);
|
ConversionRateHelper.deleteConversionRate(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MOrder createPurchaseOrder(MBPartner bpartner, Timestamp date, int M_PriceList_ID, int C_ConversionType_ID) {
|
private MOrder createPurchaseOrder(MBPartner bpartner, Timestamp date, int M_PriceList_ID, int C_ConversionType_ID)
|
||||||
|
{
|
||||||
|
return createOrder(bpartner, date, M_PriceList_ID, C_ConversionType_ID, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MOrder createSalseOrder(MBPartner bpartner, Timestamp date, int M_PriceList_ID, int C_ConversionType_ID)
|
||||||
|
{
|
||||||
|
return createOrder(bpartner, date, M_PriceList_ID, C_ConversionType_ID, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MOrder createOrder(MBPartner bpartner, Timestamp date, int M_PriceList_ID, int C_ConversionType_ID, boolean isSOTrx)
|
||||||
|
{
|
||||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
|
order.setAD_Org_ID(DictionaryIDs.AD_Org.HQ.id);
|
||||||
order.setBPartner(bpartner);
|
order.setBPartner(bpartner);
|
||||||
order.setIsSOTrx(false);
|
order.setIsSOTrx(isSOTrx);
|
||||||
order.setC_DocTypeTarget_ID();
|
order.setC_DocTypeTarget_ID();
|
||||||
order.setDateOrdered(date);
|
order.setDateOrdered(date);
|
||||||
order.setDateAcct(date);
|
order.setDateAcct(date);
|
||||||
order.setM_PriceList_ID(M_PriceList_ID);
|
order.setM_PriceList_ID(M_PriceList_ID);
|
||||||
order.setC_ConversionType_ID(C_ConversionType_ID);
|
order.setC_ConversionType_ID(C_ConversionType_ID);
|
||||||
|
order.setM_Warehouse_ID(DictionaryIDs.M_Warehouse.HQ.id);
|
||||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
order.setDocAction(DocAction.ACTION_Complete);
|
order.setDocAction(DocAction.ACTION_Complete);
|
||||||
order.saveEx();
|
order.saveEx();
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MOrderLine createPurchaseOrderLine(MOrder order, int line, MProduct product, BigDecimal qty, BigDecimal price) {
|
private MOrderLine createOrderLine(MOrder order, int line, MProduct product, BigDecimal qty, BigDecimal price) {
|
||||||
MOrderLine orderLine = new MOrderLine(order);
|
MOrderLine orderLine = new MOrderLine(order);
|
||||||
orderLine.setLine(line);
|
orderLine.setLine(line);
|
||||||
orderLine.setProduct(product);
|
orderLine.setProduct(product);
|
||||||
|
@ -415,13 +428,20 @@ public class InOutTest extends AbstractTestCase {
|
||||||
return receipt;
|
return receipt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MInOutLine createMMReceiptLine(MInOut receipt, MOrderLine orderLine, BigDecimal qty) {
|
|
||||||
MInOutLine receiptLine = new MInOutLine(receipt);
|
private MInOut createShipment(MOrder order, Timestamp date) {
|
||||||
|
MInOut receipt = new MInOut(order, DictionaryIDs.C_DocType.MM_SHIPMENT.id, date); // MM Shipment
|
||||||
|
receipt.saveEx();
|
||||||
|
return receipt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MInOutLine createInOutLine(MInOut mInOut, MOrderLine orderLine, BigDecimal qty) {
|
||||||
|
MInOutLine receiptLine = new MInOutLine(mInOut);
|
||||||
receiptLine.setC_OrderLine_ID(orderLine.get_ID());
|
receiptLine.setC_OrderLine_ID(orderLine.get_ID());
|
||||||
receiptLine.setLine(orderLine.getLine());
|
receiptLine.setLine(orderLine.getLine());
|
||||||
receiptLine.setProduct(orderLine.getProduct());
|
receiptLine.setProduct(orderLine.getProduct());
|
||||||
receiptLine.setQty(qty);
|
receiptLine.setQty(qty);
|
||||||
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
|
MWarehouse wh = MWarehouse.get(Env.getCtx(), mInOut.getM_Warehouse_ID());
|
||||||
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
||||||
receiptLine.setM_Locator_ID(M_Locator_ID);
|
receiptLine.setM_Locator_ID(M_Locator_ID);
|
||||||
receiptLine.saveEx();
|
receiptLine.saveEx();
|
||||||
|
@ -500,4 +520,46 @@ public class InOutTest extends AbstractTestCase {
|
||||||
assertEquals(shipperAccount, inout.getShipperAccount(), "Unexpected shipper account");
|
assertEquals(shipperAccount, inout.getShipperAccount(), "Unexpected shipper account");
|
||||||
assertEquals(MInOut.FREIGHTCHARGES_Collect, inout.getFreightCharges(), "Unexpected freight charges rule");
|
assertEquals(MInOut.FREIGHTCHARGES_Collect, inout.getFreightCharges(), "Unexpected freight charges rule");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cases for Credit Check
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreditCheckInOut()
|
||||||
|
{
|
||||||
|
MBPartner bpartner = MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.TREE_FARM.id, getTrxName());
|
||||||
|
bpartner.setSOCreditStatus(MBPartner.SOCREDITSTATUS_NoCreditCheck);
|
||||||
|
bpartner.saveEx();
|
||||||
|
|
||||||
|
MProduct product = MProduct.get(Env.getCtx(), DictionaryIDs.M_Product.ELM.id);
|
||||||
|
Timestamp currentDate = Env.getContextAsDate(Env.getCtx(), "#Date");
|
||||||
|
|
||||||
|
MOrder order = createSalseOrder(bpartner, currentDate, DictionaryIDs.M_PriceList.STANDARD.id, DictionaryIDs.C_ConversionType.COMPANY.id);
|
||||||
|
MOrderLine orderLine = createOrderLine(order, 10, product, new BigDecimal(500), new BigDecimal(23.32));
|
||||||
|
completeDocument(order);
|
||||||
|
|
||||||
|
MInOut receipt = createShipment(order, currentDate);
|
||||||
|
BigDecimal qtyDelivered = new BigDecimal(500);
|
||||||
|
createInOutLine(receipt, orderLine, qtyDelivered);
|
||||||
|
|
||||||
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Prepare);
|
||||||
|
receipt.load(getTrxName());
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_InProgress, receipt.getDocStatus());
|
||||||
|
|
||||||
|
bpartner.setSOCreditStatus(MBPartner.SOCREDITSTATUS_CreditStop);
|
||||||
|
bpartner.saveEx();
|
||||||
|
|
||||||
|
receipt.load(getTrxName());
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Prepare);
|
||||||
|
assertTrue(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Invalid, receipt.getDocStatus());
|
||||||
|
|
||||||
|
bpartner.setSOCreditStatus(MBPartner.SOCREDITSTATUS_CreditHold);
|
||||||
|
bpartner.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Prepare);
|
||||||
|
assertTrue(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Invalid, receipt.getDocStatus());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 2016 Logilite Technologies LLP *
|
||||||
|
* This program is free software; you can redistribute it and/or modify it *
|
||||||
|
* under the terms version 2 of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation. 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., *
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||||
|
*****************************************************************************/
|
||||||
|
package org.idempiere.test.base;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
import org.compiere.model.MBPartner;
|
||||||
|
import org.compiere.model.MInvoice;
|
||||||
|
import org.compiere.model.MInvoiceLine;
|
||||||
|
import org.compiere.model.MProduct;
|
||||||
|
import org.compiere.process.DocAction;
|
||||||
|
import org.compiere.process.ProcessInfo;
|
||||||
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.TimeUtil;
|
||||||
|
import org.compiere.wf.MWorkflow;
|
||||||
|
import org.idempiere.test.AbstractTestCase;
|
||||||
|
import org.idempiere.test.DictionaryIDs;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Test cases.
|
||||||
|
*
|
||||||
|
* @author Logilite Technologies
|
||||||
|
* @since August 07, 2023
|
||||||
|
*/
|
||||||
|
public class InvoiceTest extends AbstractTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public InvoiceTest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cases for Credit Check
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreditCheckInvoice()
|
||||||
|
{
|
||||||
|
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
||||||
|
// Joe Block
|
||||||
|
MBPartner bp = MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.JOE_BLOCK.id, getTrxName());
|
||||||
|
bp.setSOCreditStatus(MBPartner.SOCREDITSTATUS_CreditStop);
|
||||||
|
bp.saveEx();
|
||||||
|
|
||||||
|
MInvoice invoice = new MInvoice(Env.getCtx(), 0, getTrxName());
|
||||||
|
invoice.setBPartner(bp);
|
||||||
|
invoice.setAD_Org_ID(DictionaryIDs.AD_Org.HQ.id);
|
||||||
|
invoice.setC_DocTypeTarget_ID(MInvoice.DOCBASETYPE_ARInvoice);
|
||||||
|
invoice.setDateInvoiced(today);
|
||||||
|
invoice.setDateAcct(today);
|
||||||
|
invoice.setM_PriceList_ID(DictionaryIDs.M_PriceList.STANDARD.id);
|
||||||
|
invoice.setPaymentRule(MInvoice.PAYMENTRULE_OnCredit);
|
||||||
|
invoice.saveEx();
|
||||||
|
|
||||||
|
MInvoiceLine invoiceLine = new MInvoiceLine(Env.getCtx(), 0, getTrxName());
|
||||||
|
invoiceLine.setInvoice(invoice);
|
||||||
|
invoiceLine.setC_Invoice_ID(invoice.getC_Invoice_ID());
|
||||||
|
invoiceLine.setAD_Org_ID(DictionaryIDs.AD_Org.HQ.id);
|
||||||
|
invoiceLine.setLine(10);
|
||||||
|
invoiceLine.setProduct(MProduct.get(Env.getCtx(), DictionaryIDs.M_Product.FERTILIZER_50.id));
|
||||||
|
invoiceLine.setQty(new BigDecimal("1"));
|
||||||
|
invoiceLine.saveEx();
|
||||||
|
|
||||||
|
invoice.load(getTrxName());
|
||||||
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Prepare);
|
||||||
|
assertTrue(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Invalid, invoice.getDocStatus());
|
||||||
|
|
||||||
|
bp.setSOCreditStatus(MBPartner.SOCREDITSTATUS_NoCreditCheck);
|
||||||
|
bp.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus());
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,12 +25,21 @@
|
||||||
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.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
import org.compiere.model.MBPartner;
|
||||||
import org.compiere.model.MPayment;
|
import org.compiere.model.MPayment;
|
||||||
|
import org.compiere.process.DocAction;
|
||||||
|
import org.compiere.process.ProcessInfo;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.TimeUtil;
|
||||||
import org.compiere.util.Util;
|
import org.compiere.util.Util;
|
||||||
|
import org.compiere.wf.MWorkflow;
|
||||||
import org.idempiere.test.AbstractTestCase;
|
import org.idempiere.test.AbstractTestCase;
|
||||||
import org.idempiere.test.DictionaryIDs;
|
import org.idempiere.test.DictionaryIDs;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -63,4 +72,44 @@ public class PaymentTest extends AbstractTestCase {
|
||||||
payment.saveEx();
|
payment.saveEx();
|
||||||
assertTrue(Util.isEmpty(payment.getCreditCardVV()), "Credit card verification code not clear after change of tender type: "+payment.getCreditCardVV());
|
assertTrue(Util.isEmpty(payment.getCreditCardVV()), "Credit card verification code not clear after change of tender type: "+payment.getCreditCardVV());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cases for Credit Check
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreditCheckPayment()
|
||||||
|
{
|
||||||
|
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
||||||
|
// Joe Block
|
||||||
|
MBPartner bp = MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.JOE_BLOCK.id, getTrxName());
|
||||||
|
bp.setSOCreditStatus(MBPartner.SOCREDITSTATUS_CreditStop);
|
||||||
|
bp.saveEx();
|
||||||
|
|
||||||
|
MPayment payment = new MPayment(Env.getCtx(), 0, getTrxName());
|
||||||
|
payment.setC_BPartner_ID(bp.getC_BPartner_ID());
|
||||||
|
payment.setC_BankAccount_ID(DictionaryIDs.C_BankAccount.HQ_POS_CASH.id);
|
||||||
|
payment.setC_Currency_ID(DictionaryIDs.C_Currency.USD.id);
|
||||||
|
payment.setAD_Org_ID(DictionaryIDs.AD_Org.HQ.id);
|
||||||
|
payment.setC_DocType_ID(false);
|
||||||
|
payment.setDateTrx(today);
|
||||||
|
payment.setPayAmt(new BigDecimal(1000));
|
||||||
|
payment.setDateAcct(today);
|
||||||
|
payment.saveEx();
|
||||||
|
|
||||||
|
payment.load(getTrxName());
|
||||||
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(payment, DocAction.ACTION_Prepare);
|
||||||
|
assertTrue(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Invalid, payment.getDocStatus());
|
||||||
|
|
||||||
|
bp.setSOCreditStatus(MBPartner.SOCREDITSTATUS_NoCreditCheck);
|
||||||
|
bp.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(payment, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Completed, payment.getDocStatus());
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(payment, DocAction.ACTION_Reverse_Accrual);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Reversed, payment.getDocStatus());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1596,4 +1596,48 @@ public class SalesOrderTest extends AbstractTestCase {
|
||||||
assertFalse(pi.isError(), pi.getSummary());
|
assertFalse(pi.isError(), pi.getSummary());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cases for Credit Check
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreditCheckOrder()
|
||||||
|
{
|
||||||
|
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
||||||
|
// Joe Block
|
||||||
|
MBPartner bp = MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.JOE_BLOCK.id, getTrxName());
|
||||||
|
bp.setSOCreditStatus(MBPartner.SOCREDITSTATUS_CreditHold);
|
||||||
|
bp.saveEx();
|
||||||
|
|
||||||
|
// test 2 - credit Check
|
||||||
|
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
|
order.setM_Warehouse_ID(DictionaryIDs.AD_Org.HQ.id);
|
||||||
|
order.setBPartner(bp);
|
||||||
|
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
||||||
|
order.setDeliveryRule(MOrder.DELIVERYRULE_Availability);
|
||||||
|
order.setM_Warehouse_ID(DictionaryIDs.M_Warehouse.HQ.id);
|
||||||
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
order.setDocAction(DocAction.ACTION_Prepare);
|
||||||
|
order.setDatePromised(today);
|
||||||
|
order.saveEx();
|
||||||
|
|
||||||
|
MOrderLine line1 = new MOrderLine(order);
|
||||||
|
line1.setLine(10);
|
||||||
|
// Azalea Bush
|
||||||
|
line1.setProduct(MProduct.get(Env.getCtx(), DictionaryIDs.M_Product.AZALEA_BUSH.id));
|
||||||
|
line1.setQty(new BigDecimal("1"));
|
||||||
|
line1.setDatePromised(today);
|
||||||
|
line1.saveEx();
|
||||||
|
|
||||||
|
order.load(getTrxName());
|
||||||
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Prepare);
|
||||||
|
assertTrue(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Invalid, order.getDocStatus());
|
||||||
|
|
||||||
|
bp.setSOCreditStatus(MBPartner.SOCREDITSTATUS_CreditStop);
|
||||||
|
bp.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Prepare);
|
||||||
|
assertTrue(info.isError(), info.getSummary());
|
||||||
|
assertEquals(DocAction.STATUS_Invalid, order.getDocStatus());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue