IDEMPIERE-378 Implement Reverse Accrual. #1. Make consistent the implementation of VoidIt for allocation, invoice, inout, inventory, payment and movement ( Based on patch from Armen Rizal ). #2. Remove the use of conditional calculation for open balance - hard to maintain and source of intermittent bug. #3. More efficient update of open balance for allocation. #4. Lock bp record before open balance update to prevent issue with stale data.

This commit is contained in:
Heng Sin Low 2013-04-09 11:12:06 +08:00
parent 4f0c58a751
commit 558641d959
7 changed files with 473 additions and 119 deletions

View File

@ -22,8 +22,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
@ -58,7 +56,9 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
*/
private static final long serialVersionUID = 8726957992840702609L;
/** Tolerance Gain and Loss */
private static final BigDecimal TOLERANCE = new BigDecimal (0.02);
/**
* Get Allocations of Payment
* @param ctx context
@ -321,19 +321,17 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
}
// Mark as Inactive
setIsActive(false); // updated DB for line delete/process
String sql = "UPDATE C_AllocationHdr SET IsActive='N' WHERE C_AllocationHdr_ID=?";
DB.executeUpdate(sql, getC_AllocationHdr_ID(), trxName);
// Unlink
getLines(true);
HashSet<Integer> bps = new HashSet<Integer>();
if (!updateBP(true))
return false;
for (int i = 0; i < m_lines.length; i++)
{
MAllocationLine line = m_lines[i];
bps.add(new Integer(line.getC_BPartner_ID()));
line.deleteEx(true, trxName);
}
updateBP(bps);
return true;
} // beforeDelete
@ -400,7 +398,7 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
// Std Period open?
MPeriod.testPeriodOpen(getCtx(), getDateAcct(), MDocType.DOCBASETYPE_PaymentAllocation, getAD_Org_ID());
getLines(false);
getLines(true);
if (m_lines.length == 0)
{
m_processMsg = "@NoLines@";
@ -497,13 +495,14 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
// Link
getLines(false);
HashSet<Integer> bps = new HashSet<Integer>();
if(!updateBP(isReversal()))
return DocAction.STATUS_Invalid;
for (int i = 0; i < m_lines.length; i++)
{
MAllocationLine line = m_lines[i];
bps.add(new Integer(line.processIt(false))); // not reverse
}
updateBP(bps);
line.processIt(isReversal());
}
// User Validation
String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE);
@ -526,29 +525,73 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
public boolean voidIt()
{
if (log.isLoggable(Level.INFO)) log.info(toString());
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
boolean accrual = false;
try
{
MPeriod.testPeriodOpen(getCtx(), getDateTrx(), MPeriodControl.DOCBASETYPE_PaymentAllocation, getAD_Org_ID());
}
catch (PeriodClosedException e)
{
accrual = true;
}
boolean retValue = reverseIt(accrual);
boolean retValue = false;
if (DOCSTATUS_Closed.equals(getDocStatus())
|| DOCSTATUS_Reversed.equals(getDocStatus())
|| DOCSTATUS_Voided.equals(getDocStatus()))
{
m_processMsg = "Document Closed: " + getDocStatus();
setDocAction(DOCACTION_None);
return false;
}
// Not Processed
if (DOCSTATUS_Drafted.equals(getDocStatus())
|| DOCSTATUS_Invalid.equals(getDocStatus())
|| DOCSTATUS_InProgress.equals(getDocStatus())
|| DOCSTATUS_Approved.equals(getDocStatus())
|| DOCSTATUS_NotApproved.equals(getDocStatus()) )
{
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
// Set lines to 0
MAllocationLine[] lines = getLines(true);
if(!updateBP(true))
return false;
for (int i = 0; i < lines.length; i++)
{
MAllocationLine line = lines[i];
line.setAmount(Env.ZERO);
line.setDiscountAmt(Env.ZERO);
line.setWriteOffAmt(Env.ZERO);
line.setOverUnderAmt(Env.ZERO);
line.saveEx();
// Unlink invoices
line.processIt(true);
}
addDescription(Msg.getMsg(getCtx(), "Voided"));
retValue = true;
}
else
{
boolean accrual = false;
try
{
MPeriod.testPeriodOpen(getCtx(), getDateTrx(), MPeriodControl.DOCBASETYPE_PaymentAllocation, getAD_Org_ID());
}
catch (PeriodClosedException e)
{
accrual = true;
}
if (accrual)
return reverseAccrualIt();
else
return reverseCorrectIt();
}
// After Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_VOID);
if (m_processMsg != null)
return false;
setProcessed(true);
setDocAction(DOCACTION_None);
return retValue;
@ -752,8 +795,17 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
*/
private boolean reverseIt(boolean accrual)
{
if (!isActive())
throw new IllegalStateException("Allocation already reversed (not active)");
if (!isActive()
|| getDocStatus().equals(DOCSTATUS_Voided) // Goodwill.co.id
|| getDocStatus().equals(DOCSTATUS_Reversed))
{
// Goodwill: don't throw exception here
// BF: Reverse is not allowed at Payment void when Allocation is already reversed at Invoice void
//throw new IllegalStateException("Allocation already reversed (not active)");
log.warning("Allocation already reversed (not active)");
return true;
}
Timestamp reversalDate = accrual ? Env.getContextAsDate(getCtx(), "#Date") : getDateAcct();
if (reversalDate == null) {
@ -787,6 +839,8 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
return false;
}
}
reversal.setReversal(true);
reversal.setDocumentNo(getDocumentNo()+"^");
reversal.addDescription("{->" + getDocumentNo() + ")");
//
if (!DocumentEngine.processIt(reversal, DocAction.ACTION_Complete))
@ -820,42 +874,261 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
// Unlink Invoices
getLines(true);
HashSet<Integer> bps = new HashSet<Integer>();
if(!updateBP(true))
return false;
for (int i = 0; i < m_lines.length; i++)
{
MAllocationLine line = m_lines[i];
line.setIsActive(false);
line.setAmount(Env.ZERO);
line.setDiscountAmt(Env.ZERO);
line.setWriteOffAmt(Env.ZERO);
line.setOverUnderAmt(Env.ZERO);
line.saveEx();
bps.add(new Integer(line.processIt(true))); // reverse
}
updateBP(bps);
line.processIt(true); // reverse
}
addDescription(Msg.getMsg(getCtx(), "Voided"));
}
setProcessed(true);
setDocStatus(DOCSTATUS_Reversed); // may come from void
setDocAction(DOCACTION_None);
return true;
} // reverse
/**
* Update Open Balance of BP's
* @param bps list of business partners
*/
private void updateBP(HashSet<Integer> bps)
private boolean updateBP(boolean reverse)
{
if (log.isLoggable(Level.INFO)) log.info("#" + bps.size());
Iterator<Integer> it = bps.iterator();
while (it.hasNext())
{
int C_BPartner_ID = it.next();
MBPartner bp = new MBPartner(getCtx(), C_BPartner_ID, get_TrxName());
bp.setTotalOpenBalance(); // recalculates from scratch
// bp.setSOCreditStatus(); // called automatically
if (bp.save()) {
if (log.isLoggable(Level.FINE)) log.fine(bp.toString());
} else {
log.log(Level.SEVERE, "BP not updated - " + bp);
}
}
} // updateBP
getLines(false);
for (MAllocationLine line : m_lines) {
int C_Payment_ID = line.getC_Payment_ID();
int C_BPartner_ID = line.getC_BPartner_ID();
int M_Invoice_ID = line.getC_Invoice_ID();
if ((C_BPartner_ID == 0) || ((M_Invoice_ID == 0) && (C_Payment_ID == 0)))
continue;
boolean isSOTrxInvoice = false;
MInvoice invoice = M_Invoice_ID > 0 ? new MInvoice (getCtx(), M_Invoice_ID, get_TrxName()) : null;
if (M_Invoice_ID > 0)
isSOTrxInvoice = invoice.isSOTrx();
MBPartner bpartner = new MBPartner (getCtx(), line.getC_BPartner_ID(), get_TrxName());
DB.getDatabase().forUpdate(bpartner, 0);
BigDecimal allocAmt = line.getAmount().add(line.getDiscountAmt()).add(line.getWriteOffAmt());
BigDecimal openBalanceDiff = Env.ZERO;
MClient client = MClient.get(getCtx(), getAD_Client_ID());
boolean paymentProcessed = false;
boolean paymentIsReceipt = false;
// Retrieve payment information
if (C_Payment_ID > 0)
{
MPayment payment = null;
int convTypeID = 0;
Timestamp paymentDate = null;
payment = new MPayment (getCtx(), C_Payment_ID, get_TrxName());
convTypeID = payment.getC_ConversionType_ID();
paymentDate = payment.getDateAcct();
paymentProcessed = payment.isProcessed();
paymentIsReceipt = payment.isReceipt();
// Adjust open amount with allocated amount.
if (paymentProcessed)
{
if (invoice != null)
{
// If payment is already processed, only adjust open balance by discount and write off amounts.
BigDecimal amt = MConversionRate.convertBase(getCtx(), line.getWriteOffAmt().add(line.getDiscountAmt()),
getC_Currency_ID(), paymentDate, convTypeID, getAD_Client_ID(), getAD_Org_ID());
if (amt == null)
{
m_processMsg = "Could not convert allocation C_Currency_ID=" + getC_Currency_ID()
+ " to base C_Currency_ID=" + MClient.get(getCtx()).getC_Currency_ID() + ", C_ConversionType_ID=" + convTypeID
+ ", conversion date= " + paymentDate;
return false;
}
openBalanceDiff = openBalanceDiff.add(amt);
}
else
{
// Allocating payment to payment.
BigDecimal amt = MConversionRate.convertBase(getCtx(), allocAmt,
getC_Currency_ID(), paymentDate, convTypeID, getAD_Client_ID(), getAD_Org_ID());
if (amt == null)
{
m_processMsg = "Could not convert allocation C_Currency_ID=" + getC_Currency_ID()
+ " to base C_Currency_ID=" + MClient.get(getCtx()).getC_Currency_ID() + ", C_ConversionType_ID=" + convTypeID
+ ", conversion date= " + paymentDate;
return false;
}
openBalanceDiff = openBalanceDiff.add(amt);
}
} else {
// If payment has not been processed, adjust open balance by entire allocated amount.
BigDecimal allocAmtBase = MConversionRate.convertBase(getCtx(), allocAmt,
getC_Currency_ID(), getDateAcct(), convTypeID, getAD_Client_ID(), getAD_Org_ID());
if (allocAmtBase == null)
{
m_processMsg = "Could not convert allocation C_Currency_ID=" + getC_Currency_ID()
+ " to base C_Currency_ID=" + MClient.get(getCtx()).getC_Currency_ID() + ", C_ConversionType_ID=" + convTypeID
+ ", conversion date= " + getDateAcct();
return false;
}
openBalanceDiff = openBalanceDiff.add(allocAmtBase);
}
}
else if (invoice != null)
{
// adjust open balance by discount and write off amounts.
BigDecimal amt = MConversionRate.convertBase(getCtx(), line.getWriteOffAmt().add(line.getDiscountAmt()),
getC_Currency_ID(), invoice.getDateAcct(), invoice.getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
if (amt == null)
{
m_processMsg = "Could not convert allocation C_Currency_ID=" + getC_Currency_ID()
+ " to base C_Currency_ID=" + MClient.get(getCtx()).getC_Currency_ID() + ", C_ConversionType_ID=" + invoice.getC_ConversionType_ID()
+ ", conversion date= " + invoice.getDateAcct();
return false;
}
openBalanceDiff = openBalanceDiff.add(amt);
}
// Adjust open amount for currency gain/loss
if ((invoice != null) &&
((getC_Currency_ID() != client.getC_Currency_ID()) ||
(getC_Currency_ID() != invoice.getC_Currency_ID())))
{
if (getC_Currency_ID() != invoice.getC_Currency_ID())
{
allocAmt = MConversionRate.convert(getCtx(), allocAmt,
getC_Currency_ID(), invoice.getC_Currency_ID(), getDateAcct(), invoice.getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
if (allocAmt == null)
{
m_processMsg = "Could not convert allocation C_Currency_ID=" + getC_Currency_ID()
+ " to invoice C_Currency_ID=" + invoice.getC_Currency_ID() + ", C_ConversionType_ID=" + invoice.getC_ConversionType_ID()
+ ", conversion date= " + getDateAcct();
return false;
}
}
BigDecimal invAmtAccted = MConversionRate.convertBase(getCtx(), invoice.getGrandTotal(),
invoice.getC_Currency_ID(), invoice.getDateAcct(), invoice.getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
if (invAmtAccted == null)
{
m_processMsg = "Could not convert invoice C_Currency_ID=" + getC_Currency_ID()
+ " to base C_Currency_ID=" + invoice.getC_Currency_ID() + ", C_ConversionType_ID=" + invoice.getC_ConversionType_ID()
+ ", date= " + invoice.getDateAcct();
return false;
}
BigDecimal allocAmtAccted = MConversionRate.convertBase(getCtx(), allocAmt,
invoice.getC_Currency_ID(), getDateAcct(), invoice.getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
if (allocAmtAccted == null)
{
m_processMsg = "Could not convert invoice C_Currency_ID=" + invoice.getC_Currency_ID()
+ " to base C_Currency_ID=" + MClient.get(getCtx()).getC_Currency_ID() + ", C_ConversionType_ID=" + invoice.getC_ConversionType_ID()
+ ", conversion date= " + getDateAcct();
return false;
}
if (allocAmt.compareTo(invoice.getGrandTotal()) == 0)
{
openBalanceDiff = openBalanceDiff.add(invAmtAccted).subtract(allocAmtAccted);
}
else
{
// allocation as a percentage of the invoice
double multiplier = allocAmt.doubleValue() / invoice.getGrandTotal().doubleValue();
// Reduce Orig Invoice Accounted
invAmtAccted = invAmtAccted.multiply(new BigDecimal(multiplier));
// Difference based on percentage of Orig Invoice
openBalanceDiff = openBalanceDiff.add(invAmtAccted).subtract(allocAmtAccted); // gain is negative
// ignore Tolerance
if (openBalanceDiff.abs().compareTo(TOLERANCE) < 0)
openBalanceDiff = Env.ZERO;
// Round
int precision = MCurrency.getStdPrecision(getCtx(), client.getC_Currency_ID());
if (openBalanceDiff.scale() > precision)
openBalanceDiff = openBalanceDiff.setScale(precision, BigDecimal.ROUND_HALF_UP);
}
}
// Total Balance
BigDecimal newBalance = bpartner.getTotalOpenBalance();
if (newBalance == null)
newBalance = Env.ZERO;
BigDecimal originalBalance = new BigDecimal(newBalance.toString());
if (openBalanceDiff.signum() != 0)
{
if (reverse)
newBalance = newBalance.add(openBalanceDiff);
else
newBalance = newBalance.subtract(openBalanceDiff);
}
// Update BP Credit Used only for Customer Invoices and for payment-to-payment allocations.
BigDecimal newCreditAmt = Env.ZERO;
if (isSOTrxInvoice || (invoice == null && paymentIsReceipt && paymentProcessed))
{
if (invoice == null)
openBalanceDiff = openBalanceDiff.negate();
newCreditAmt = bpartner.getSO_CreditUsed();
if(reverse)
{
if (newCreditAmt == null)
newCreditAmt = openBalanceDiff;
else
newCreditAmt = newCreditAmt.add(openBalanceDiff);
}
else
{
if (newCreditAmt == null)
newCreditAmt = openBalanceDiff.negate();
else
newCreditAmt = newCreditAmt.subtract(openBalanceDiff);
}
if (log.isLoggable(Level.FINE))
{
log.fine("TotalOpenBalance=" + bpartner.getTotalOpenBalance() + "(" + openBalanceDiff
+ ", Credit=" + bpartner.getSO_CreditUsed() + "->" + newCreditAmt
+ ", Balance=" + bpartner.getTotalOpenBalance() + " -> " + newBalance);
}
bpartner.setSO_CreditUsed(newCreditAmt);
}
else
{
if (log.isLoggable(Level.FINE))
{
log.fine("TotalOpenBalance=" + bpartner.getTotalOpenBalance() + "(" + openBalanceDiff
+ ", Balance=" + bpartner.getTotalOpenBalance() + " -> " + newBalance);
}
}
if (newBalance.compareTo(originalBalance) != 0)
bpartner.setTotalOpenBalance(newBalance);
bpartner.setSOCreditStatus();
if (!bpartner.save(get_TrxName()))
{
m_processMsg = "Could not update Business Partner";
return false;
}
} // for all lines
return true;
} // updateBP
/**
* Document Status is Complete or Closed
* @return true if CO, CL or RE
@ -938,8 +1211,30 @@ public final class MAllocationHdr extends X_C_AllocationHdr implements DocAction
line.saveEx();
count++;
}
if (fromLines.length != count)
log.log(Level.WARNING, "Line difference - From=" + fromLines.length + " <> Saved=" + count);
return count;
} // copyLinesFrom
// Goodwill.co.id
/** Reversal Flag */
private boolean m_reversal = false;
/**
* Set Reversal
* @param reversal reversal
*/
private void setReversal(boolean reversal)
{
m_reversal = reversal;
} // setReversal
/**
* Is Reversal
* @return reversal
*/
private boolean isReversal()
{
return m_reversal;
} // isReversal
} // MAllocation

View File

@ -289,8 +289,6 @@ public class MBPartner extends X_C_BPartner
private Integer m_primaryC_BPartner_Location_ID = null;
/** Prim User */
private Integer m_primaryAD_User_ID = null;
/** Credit Limit recently calculated */
private boolean m_TotalOpenBalanceSet = false;
/** BP Group */
private MBPGroup m_group = null;
@ -692,7 +690,6 @@ public class MBPartner extends X_C_BPartner
pstmt = null;
}
//
m_TotalOpenBalanceSet = true;
if (SO_CreditUsed != null)
super.setSO_CreditUsed (SO_CreditUsed);
if (TotalOpenBalance != null)
@ -736,19 +733,6 @@ public class MBPartner extends X_C_BPartner
super.setActualLifeTimeValue (ActualLifeTimeValue);
} // setActualLifeTimeValue
/**
* Get Total Open Balance
* @param calculate if null calculate it
* @return Open Balance
*/
public BigDecimal getTotalOpenBalance (boolean calculate)
{
if (getTotalOpenBalance().signum() == 0 && calculate)
setTotalOpenBalance();
return super.getTotalOpenBalance ();
} // getTotalOpenBalance
/**
* Set Credit Status
*/
@ -762,7 +746,7 @@ public class MBPartner extends X_C_BPartner
return;
// Above Credit Limit
if (creditLimit.compareTo(getTotalOpenBalance(!m_TotalOpenBalanceSet)) < 0)
if (creditLimit.compareTo(getTotalOpenBalance()) < 0)
setSOCreditStatus(SOCREDITSTATUS_CreditHold);
else
{
@ -795,7 +779,7 @@ public class MBPartner extends X_C_BPartner
// Above (reduced) Credit Limit
creditLimit = creditLimit.subtract(additionalAmt);
if (creditLimit.compareTo(getTotalOpenBalance(!m_TotalOpenBalanceSet)) < 0)
if (creditLimit.compareTo(getTotalOpenBalance()) < 0)
return SOCREDITSTATUS_CreditHold;
// Above Watch Limit
@ -827,16 +811,6 @@ public class MBPartner extends X_C_BPartner
|| SOCREDITSTATUS_CreditHold.equals(status);
} // isCreditStopHold
/**
* Set Total Open Balance
* @param TotalOpenBalance
*/
public void setTotalOpenBalance (BigDecimal TotalOpenBalance)
{
m_TotalOpenBalanceSet = false;
super.setTotalOpenBalance (TotalOpenBalance);
} // setTotalOpenBalance
/**
* Get BP Group
* @return group

View File

@ -26,6 +26,7 @@ import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.exceptions.PeriodClosedException;
import org.compiere.print.MPrintFormat;
import org.compiere.print.ReportEngine;
import org.compiere.process.DocAction;
@ -2020,11 +2021,7 @@ public class MInOut extends X_M_InOut implements DocAction
*/
public boolean voidIt()
{
if (log.isLoggable(Level.INFO)) log.info(toString());
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
if (log.isLoggable(Level.INFO)) log.info(toString());
if (DOCSTATUS_Closed.equals(getDocStatus())
|| DOCSTATUS_Reversed.equals(getDocStatus())
@ -2041,6 +2038,11 @@ public class MInOut extends X_M_InOut implements DocAction
|| DOCSTATUS_Approved.equals(getDocStatus())
|| DOCSTATUS_NotApproved.equals(getDocStatus()) )
{
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
// Set lines to 0
MInOutLine[] lines = getLines(false);
for (int i = 0; i < lines.length; i++)
@ -2063,7 +2065,20 @@ public class MInOut extends X_M_InOut implements DocAction
}
else
{
return reverseCorrectIt();
boolean accrual = false;
try
{
MPeriod.testPeriodOpen(getCtx(), getDateAcct(), getC_DocType_ID(), getAD_Org_ID());
}
catch (PeriodClosedException e)
{
accrual = true;
}
if (accrual)
return reverseAccrualIt();
else
return reverseCorrectIt();
}
// After Void

View File

@ -24,6 +24,7 @@ import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.PeriodClosedException;
import org.compiere.process.DocAction;
import org.compiere.process.DocumentEngine;
import org.compiere.util.CCache;
@ -665,11 +666,7 @@ public class MInventory extends X_M_Inventory implements DocAction
public boolean voidIt()
{
if (log.isLoggable(Level.INFO)) log.info(toString());
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
if (DOCSTATUS_Closed.equals(getDocStatus())
|| DOCSTATUS_Reversed.equals(getDocStatus())
|| DOCSTATUS_Voided.equals(getDocStatus()))
@ -685,6 +682,11 @@ public class MInventory extends X_M_Inventory implements DocAction
|| DOCSTATUS_Approved.equals(getDocStatus())
|| DOCSTATUS_NotApproved.equals(getDocStatus()) )
{
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
// Set lines to 0
MInventoryLine[] lines = getLines(false);
for (int i = 0; i < lines.length; i++)
@ -705,7 +707,20 @@ public class MInventory extends X_M_Inventory implements DocAction
}
else
{
return reverseCorrectIt();
boolean accrual = false;
try
{
MPeriod.testPeriodOpen(getCtx(), getMovementDate(), getC_DocType_ID(), getAD_Org_ID());
}
catch (PeriodClosedException e)
{
accrual = true;
}
if (accrual)
return reverseAccrualIt();
else
return reverseCorrectIt();
}
// After Void

View File

@ -30,6 +30,7 @@ import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.exceptions.BPartnerNoAddressException;
import org.adempiere.exceptions.DBException;
import org.adempiere.exceptions.PeriodClosedException;
import org.compiere.print.MPrintFormat;
import org.compiere.print.ReportEngine;
import org.compiere.process.DocAction;
@ -1863,6 +1864,7 @@ public class MInvoice extends X_C_Invoice implements DocAction
// 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 = MConversionRate.convertBase(getCtx(), getGrandTotal(true), // CM adjusted
getC_Currency_ID(), getDateAcct(), getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
@ -1873,7 +1875,7 @@ public class MInvoice extends X_C_Invoice implements DocAction
return DocAction.STATUS_Invalid;
}
// Total Balance
BigDecimal newBalance = bp.getTotalOpenBalance(false);
BigDecimal newBalance = bp.getTotalOpenBalance();
if (newBalance == null)
newBalance = Env.ZERO;
if (isSOTrx())
@ -1896,7 +1898,7 @@ public class MInvoice extends X_C_Invoice implements DocAction
if (log.isLoggable(Level.FINE)) log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt
+ ") BP Life=" + bp.getActualLifeTimeValue() + "->" + newLifeAmt
+ ", Credit=" + bp.getSO_CreditUsed() + "->" + newCreditAmt
+ ", Balance=" + bp.getTotalOpenBalance(false) + " -> " + newBalance);
+ ", Balance=" + bp.getTotalOpenBalance() + " -> " + newBalance);
bp.setActualLifeTimeValue(newLifeAmt);
bp.setSO_CreditUsed(newCreditAmt);
} // SO
@ -1904,7 +1906,7 @@ public class MInvoice extends X_C_Invoice implements DocAction
{
newBalance = newBalance.subtract(invAmt);
if (log.isLoggable(Level.FINE)) log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt
+ ") Balance=" + bp.getTotalOpenBalance(false) + " -> " + newBalance);
+ ") Balance=" + bp.getTotalOpenBalance() + " -> " + newBalance);
}
bp.setTotalOpenBalance(newBalance);
bp.setSOCreditStatus();
@ -2169,11 +2171,7 @@ public class MInvoice extends X_C_Invoice implements DocAction
public boolean voidIt()
{
if (log.isLoggable(Level.INFO)) log.info(toString());
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
if (DOCSTATUS_Closed.equals(getDocStatus())
|| DOCSTATUS_Reversed.equals(getDocStatus())
|| DOCSTATUS_Voided.equals(getDocStatus()))
@ -2190,6 +2188,11 @@ public class MInvoice extends X_C_Invoice implements DocAction
|| DOCSTATUS_Approved.equals(getDocStatus())
|| DOCSTATUS_NotApproved.equals(getDocStatus()) )
{
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
// Set lines to 0
MInvoiceLine[] lines = getLines(false);
for (int i = 0; i < lines.length; i++)
@ -2221,7 +2224,20 @@ public class MInvoice extends X_C_Invoice implements DocAction
}
else
{
return reverseCorrectIt();
boolean accrual = false;
try
{
MPeriod.testPeriodOpen(getCtx(), getDateAcct(), getC_DocType_ID(), getAD_Org_ID());
}
catch (PeriodClosedException e)
{
accrual = true;
}
if (accrual)
return reverseAccrualIt();
else
return reverseCorrectIt();
}
// After Void

View File

@ -24,6 +24,7 @@ import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.PeriodClosedException;
import org.compiere.process.DocAction;
import org.compiere.process.DocumentEngine;
import org.compiere.util.CLogger;
@ -610,11 +611,7 @@ public class MMovement extends X_M_Movement implements DocAction
public boolean voidIt()
{
if (log.isLoggable(Level.INFO)) log.info(toString());
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
if (DOCSTATUS_Closed.equals(getDocStatus())
|| DOCSTATUS_Reversed.equals(getDocStatus())
|| DOCSTATUS_Voided.equals(getDocStatus()))
@ -630,6 +627,11 @@ public class MMovement extends X_M_Movement implements DocAction
|| DOCSTATUS_Approved.equals(getDocStatus())
|| DOCSTATUS_NotApproved.equals(getDocStatus()) )
{
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
// Set lines to 0
MMovementLine[] lines = getLines(false);
for (int i = 0; i < lines.length; i++)
@ -646,7 +648,20 @@ public class MMovement extends X_M_Movement implements DocAction
}
else
{
return reverseCorrectIt();
boolean accrual = false;
try
{
MPeriod.testPeriodOpen(getCtx(), getMovementDate(), getC_DocType_ID(), getAD_Org_ID());
}
catch (PeriodClosedException e)
{
accrual = true;
}
if (accrual)
return reverseAccrualIt();
else
return reverseCorrectIt();
}
// After Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_VOID);

View File

@ -28,6 +28,7 @@ import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.exceptions.PeriodClosedException;
import org.adempiere.util.IProcessUI;
import org.adempiere.util.PaymentUtil;
import org.compiere.process.DocAction;
@ -1920,6 +1921,7 @@ public final class MPayment extends X_C_Payment
if (getC_BPartner_ID() != 0 && getC_Invoice_ID() == 0 && getC_Charge_ID() == 0 && MPaymentAllocate.get(this).length == 0)
{
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
DB.getDatabase().forUpdate(bp, 0);
// Update total balance to include this payment
BigDecimal payAmt = MConversionRate.convertBase(getCtx(), getPayAmt(),
getC_Currency_ID(), getDateAcct(), getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
@ -1930,7 +1932,7 @@ public final class MPayment extends X_C_Payment
return DocAction.STATUS_Invalid;
}
// Total Balance
BigDecimal newBalance = bp.getTotalOpenBalance(false);
BigDecimal newBalance = bp.getTotalOpenBalance();
if (newBalance == null)
newBalance = Env.ZERO;
if (isReceipt())
@ -2361,6 +2363,12 @@ public final class MPayment extends X_C_Payment
for (int i = 0; i < allocations.length; i++)
{
allocations[i].set_TrxName(get_TrxName());
if (DOCSTATUS_Reversed.equals(allocations[i].getDocStatus())
|| DOCSTATUS_Voided.equals(allocations[i].getDocStatus()))
{
continue;
}
if (accrual)
{
allocations[i].setDocAction(DocAction.ACTION_Reverse_Accrual);
@ -2409,11 +2417,7 @@ public final class MPayment extends X_C_Payment
*/
public boolean voidIt()
{
if (log.isLoggable(Level.INFO)) log.info(toString());
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
if (log.isLoggable(Level.INFO)) log.info(toString());
if (DOCSTATUS_Closed.equals(getDocStatus())
|| DOCSTATUS_Reversed.equals(getDocStatus())
@ -2434,6 +2438,11 @@ public final class MPayment extends X_C_Payment
|| DOCSTATUS_Approved.equals(getDocStatus())
|| DOCSTATUS_NotApproved.equals(getDocStatus()) )
{
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
if (!voidOnlinePayment())
return false;
@ -2447,7 +2456,22 @@ public final class MPayment extends X_C_Payment
deAllocate(false);
}
else
return reverseCorrectIt();
{
boolean accrual = false;
try
{
MPeriod.testPeriodOpen(getCtx(), getDateAcct(), getC_DocType_ID(), getAD_Org_ID());
}
catch (PeriodClosedException e)
{
accrual = true;
}
if (accrual)
return reverseAccrualIt();
else
return reverseCorrectIt();
}
//
// After Void