/****************************************************************************** * 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 }