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:
parent
4f0c58a751
commit
558641d959
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue