IDEMPIERE-4127 GL Inventory Clearing - Minor rounding variances

This commit is contained in:
hengsin 2020-03-02 13:08:19 +08:00
parent e0906eb102
commit c8d858836f
3 changed files with 383 additions and 226 deletions

View File

@ -21,6 +21,7 @@ import java.math.RoundingMode;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@ -75,8 +76,8 @@ public class Doc_AllocationHdr extends Doc
private static final BigDecimal TOLERANCE = BigDecimal.valueOf(0.02); private static final BigDecimal TOLERANCE = BigDecimal.valueOf(0.02);
/** Facts */ /** Facts */
private ArrayList<Fact> m_facts = null; private ArrayList<Fact> m_facts = null;
BigDecimal gainLossAmt =Env.ZERO; private Hashtable<Integer, BigDecimal> htGainLossAmtByInv = new Hashtable<Integer, BigDecimal>();
private BigDecimal cmGainLossAmt=Env.ZERO; private Hashtable<Integer, BigDecimal> htGainLossAmtByCM = new Hashtable<Integer, BigDecimal>();
private ArrayList<FactLine> gainLossFactList; private ArrayList<FactLine> gainLossFactList;
@ -741,18 +742,32 @@ public class Doc_AllocationHdr extends Doc
.append(" FROM Fact_Acct ") .append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?") .append("WHERE AD_Table_ID=? AND Record_ID=?")
.append(" AND C_AcctSchema_ID=?") .append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID=?")
.append(" AND PostingType='A'"); .append(" AND PostingType='A'");
// For Invoice // For Invoice
List<Object> valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), List<Object> valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
MInvoice.Table_ID, invoice.getC_Invoice_ID(), as.getC_AcctSchema_ID()); MInvoice.Table_ID, invoice.getC_Invoice_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
if (valuesInv != null) { if (valuesInv != null) {
if (invoice.isSOTrx()) { if (invoice.getReversal_ID() == 0 || invoice.get_ID() < invoice.getReversal_ID())
invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr {
invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) {
} else { invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr } else {
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
}
}
else
{
if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) {
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
} else {
invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr
invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr
}
} }
} }
@ -786,7 +801,7 @@ public class Doc_AllocationHdr extends Doc
acctDifference = invoiceAccounted.subtract(allocationAccounted.abs()); acctDifference = invoiceAccounted.subtract(allocationAccounted.abs());
} }
// Full Payment in currency // Full Payment in currency
if (allocationSource.compareTo(invoiceSource) == 0) if (allocationSource.abs().compareTo(invoiceSource.abs()) == 0)
{ {
acctDifference = invoiceAccounted.subtract(allocationAccounted.abs()); // gain is negative acctDifference = invoiceAccounted.subtract(allocationAccounted.abs()); // gain is negative
@ -822,13 +837,21 @@ public class Doc_AllocationHdr extends Doc
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct()); MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct()); MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
BigDecimal cmGainLossAmt = htGainLossAmtByCM.get(invoice.getC_Invoice_ID());
if (cmGainLossAmt == null)
cmGainLossAmt = Env.ZERO;
BigDecimal gainLossAmt = htGainLossAmtByInv.get(invoice.getC_Invoice_ID());
if (gainLossAmt == null)
gainLossAmt = Env.ZERO;
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0) if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0)
cmGainLossAmt = cmGainLossAmt.add(acctDifference); cmGainLossAmt = cmGainLossAmt.add(acctDifference);
else else
gainLossAmt = gainLossAmt.add(acctDifference); gainLossAmt = gainLossAmt.add(acctDifference);
htGainLossAmtByCM.put(invoice.getC_Invoice_ID(), cmGainLossAmt);
htGainLossAmtByInv.put(invoice.getC_Invoice_ID(), gainLossAmt);
// //
if (invoice.isSOTrx()) if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo()))
{ {
FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference); FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString()); fl.setDescription(description.toString());
@ -1049,112 +1072,164 @@ public class Doc_AllocationHdr extends Doc
* @param payment payment * @param payment payment
* @return Error Message or null if OK * @return Error Message or null if OK
*/ */
private String createInvoiceRounding(MAcctSchema as, Fact fact, MAccount bpAcct) { private String createInvoiceRounding(MAcctSchema as, Fact fact, MAccount bpAcct)
{
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
ResultSet rs = null; ResultSet rs = null;
// Invoice AR/AP // Invoice AR/AP
BigDecimal totalInvoiceSource = BigDecimal.ZERO;
BigDecimal totalInvoiceAccounted = BigDecimal.ZERO;
boolean isCMReversal =false ;
MInvoice invoice = null;
MPayment payment = null;
ArrayList<MInvoice> invList = new ArrayList<MInvoice>(); ArrayList<MInvoice> invList = new ArrayList<MInvoice>();
ArrayList<MPayment> payList = new ArrayList<MPayment>();
Hashtable<Integer, Integer> htInvAllocLine = new Hashtable<Integer, Integer>();
for (int i = 0; i < p_lines.length; i++) for (int i = 0; i < p_lines.length; i++)
{ {
MInvoice invoice = null;
MPayment payment = null;
DocLine_Allocation line = (DocLine_Allocation)p_lines[i]; DocLine_Allocation line = (DocLine_Allocation)p_lines[i];
if (line.getC_Invoice_ID() != 0) if (line.getC_Invoice_ID() != 0)
invoice = new MInvoice (getCtx(), line.getC_Invoice_ID(), getTrxName());
if (line.getC_Payment_ID() != 0)
payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName());
if (invoice != null )
{ {
boolean isDebit = false; invoice = new MInvoice (getCtx(), line.getC_Invoice_ID(), getTrxName());
// to cater for invoice reverse-accrual. if (!invList.contains(invoice))
if (invoice.isSOTrx() && !invoice.isCreditMemo()) invList.add(invoice);
isDebit = true; htInvAllocLine.put(invoice.getC_Invoice_ID(), line.get_ID());
else if (!invoice.isSOTrx() && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) }
isDebit = true; if (line.getC_Payment_ID() != 0)
else if (invoice.isSOTrx() && invoice.isCreditMemo() && invoice.getReversal_ID() == 0) {
isDebit = true; payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName());
// if (!payList.contains(payment))
StringBuilder sql = new StringBuilder("SELECT ") payList.add(payment);
.append((isDebit )
? "SUM(AmtSourceDr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceCr), SUM(AmtAcctCr)") // po
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?") // Invoice
.append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'")
.append(" AND Account_ID= ? ");
pstmt = null;
rs = null;
try
{
pstmt = DB.prepareStatement(sql.toString(), getTrxName());
pstmt.setInt(1, MInvoice.Table_ID);
pstmt.setInt(2, invoice.getC_Invoice_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID());
pstmt.setInt(4, bpAcct.getAccount_ID());
rs = pstmt.executeQuery();
if (rs.next())
{
BigDecimal invoiceSource = rs.getBigDecimal(1);
BigDecimal invoiceAccounted = rs.getBigDecimal(2);
if ( !invList.contains(invoice))
{
totalInvoiceSource =totalInvoiceSource.add(invoiceSource);
totalInvoiceAccounted =totalInvoiceAccounted.add(invoiceAccounted);
}
invList.add(invoice);
}
}
catch (Exception e)
{
throw new RuntimeException(e.getLocalizedMessage(), e);
}
finally {
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
} }
} }
BigDecimal allocInvoiceSource = BigDecimal.ZERO;
BigDecimal allocInvoiceAccounted = BigDecimal.ZERO; Hashtable<Integer, BigDecimal> htInvSource = new Hashtable<Integer, BigDecimal>();
MAllocationLine allocationLine = null; Hashtable<Integer, BigDecimal> htInvAccounted = new Hashtable<Integer, BigDecimal>();
FactLine[] factlines = fact.getLines(); for (MInvoice invoice : invList)
boolean isExcludeCMGainLoss = false; {
for (FactLine factLine : factlines) { boolean isDebit = false;
if (bpAcct != null) { // to cater for invoice reverse-accrual.
if (factLine.getAccount_ID() == bpAcct.getAccount_ID() ) if (invoice.getReversal_ID() == 0 || invoice.get_ID() < invoice.getReversal_ID())
{
if (invoice.isSOTrx() && !invoice.isCreditMemo())
isDebit = true;
else if (!invoice.isSOTrx() && invoice.isCreditMemo())
isDebit = true;
}
else
{
if (!invoice.isSOTrx() && !invoice.isCreditMemo())
isDebit = true;
else if (invoice.isSOTrx() && invoice.isCreditMemo())
isDebit = true;
}
//
StringBuilder sql = new StringBuilder("SELECT ")
.append((isDebit )
? "SUM(AmtSourceDr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceCr), SUM(AmtAcctCr)") // po
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?") // Invoice
.append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'")
.append(" AND Account_ID= ? ");
pstmt = null;
rs = null;
try
{
pstmt = DB.prepareStatement(sql.toString(), getTrxName());
pstmt.setInt(1, MInvoice.Table_ID);
pstmt.setInt(2, invoice.getC_Invoice_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID());
pstmt.setInt(4, bpAcct.getAccount_ID());
rs = pstmt.executeQuery();
if (rs.next())
{ {
if (factLine.getLine_ID() != 0 ) BigDecimal invoiceSource = rs.getBigDecimal(1);
BigDecimal invoiceAccounted = rs.getBigDecimal(2);
htInvSource.put(invoice.getC_Invoice_ID(), invoiceSource);
htInvAccounted.put(invoice.getC_Invoice_ID(), invoiceAccounted);
}
}
catch (Exception e)
{
throw new RuntimeException(e.getLocalizedMessage(), e);
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
}
Hashtable<Integer, BigDecimal> htAllocInvSource = new Hashtable<Integer, BigDecimal>();
Hashtable<Integer, BigDecimal> htAllocInvAccounted = new Hashtable<Integer, BigDecimal>();
Hashtable<Integer, Boolean> htIsExcludeCMGainLoss = new Hashtable<Integer, Boolean>();
Hashtable<Integer, Boolean> htIsCMReversal = new Hashtable<Integer, Boolean>();
FactLine[] factlines = fact.getLines();
for (FactLine factLine : factlines)
{
if (bpAcct != null)
{
if (factLine.getAccount_ID() == bpAcct.getAccount_ID())
{
MAllocationLine allocationLine = null;
if (factLine.getLine_ID() != 0)
allocationLine = new MAllocationLine(getCtx(), factLine.getLine_ID(), getTrxName()); allocationLine = new MAllocationLine(getCtx(), factLine.getLine_ID(), getTrxName());
MInvoice invoice = null;
MPayment payment = null;
if (allocationLine != null) if (allocationLine != null)
{
invoice = allocationLine.getInvoice(); invoice = allocationLine.getInvoice();
if (allocationLine.getC_Payment_ID() > 0)
payment = new MPayment (getCtx(), allocationLine.getC_Payment_ID(), getTrxName());
}
BigDecimal allocInvoiceSource = htAllocInvSource.get(allocationLine.getC_Invoice_ID());
if (allocInvoiceSource == null)
allocInvoiceSource = Env.ZERO;
BigDecimal allocInvoiceAccounted = htAllocInvAccounted.get(allocationLine.getC_Invoice_ID());
if (allocInvoiceAccounted == null)
allocInvoiceAccounted = Env.ZERO;
BigDecimal cmGainLossAmt = htGainLossAmtByCM.get(invoice.getC_Invoice_ID());
if (cmGainLossAmt == null)
cmGainLossAmt = Env.ZERO;
BigDecimal gainLossAmt = htGainLossAmtByInv.get(invoice.getC_Invoice_ID());
if (gainLossAmt == null)
gainLossAmt = Env.ZERO;
Boolean isExcludeCMGainLoss = htIsExcludeCMGainLoss.get(invoice.getC_Invoice_ID());
if (isExcludeCMGainLoss == null)
isExcludeCMGainLoss = Boolean.FALSE;
Boolean isCMReversal = htIsCMReversal.get(invoice.getC_Invoice_ID());
if (isCMReversal == null)
isCMReversal = Boolean.FALSE;
if (invoice.isSOTrx()) if (invoice.isSOTrx())
{ {
if (factLine.getC_Currency_ID() != as.getC_Currency_ID()) if (factLine.getC_Currency_ID() != as.getC_Currency_ID())
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceCr()); {
if (!invoice.isCreditMemo())
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceCr());
else
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr());
}
if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo()) if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo())
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr());
else if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo())
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) { if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0)
{
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
if (!invoice.getDateAcct().equals(getDateAcct())) if (!invoice.getDateAcct().equals(getDateAcct()))
isCMReversal =true; isCMReversal = true;
} }
if (invoice!=null) if (invoice!=null)
{ {
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) { if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 )
{
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs()); allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs());
cmGainLossAmt = Env.ZERO; cmGainLossAmt = Env.ZERO;
} }
if (gainLossFactList.contains(factLine)) { if (gainLossFactList.contains(factLine))
{
isExcludeCMGainLoss = true; isExcludeCMGainLoss = true;
} }
} }
@ -1164,8 +1239,8 @@ public class Doc_AllocationHdr extends Doc
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr());
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
} }
}
} else else
{ {
if (as.getC_Currency_ID() != factLine.getC_Currency_ID()) if (as.getC_Currency_ID() != factLine.getC_Currency_ID())
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr());
@ -1173,58 +1248,100 @@ public class Doc_AllocationHdr extends Doc
if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo()) if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo())
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) { if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0)
{
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr());
// this is to cater for reverse-accrual. // this is to cater for reverse-accrual.
if (!invoice.getDateAcct().equals(getDateAcct())) if (!invoice.getDateAcct().equals(getDateAcct()))
isCMReversal =true; isCMReversal = true;
} }
if (invoice!=null ) if (invoice != null)
{ {
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) { if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0)
{
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs()); allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs());
cmGainLossAmt = Env.ZERO; cmGainLossAmt = Env.ZERO;
} }
if (gainLossFactList.contains(factLine)) { if (gainLossFactList.contains(factLine))
{
isExcludeCMGainLoss = true; isExcludeCMGainLoss = true;
} }
} }
} }
htAllocInvSource.put(invoice.getC_Invoice_ID(), allocInvoiceSource);
htAllocInvAccounted.put(invoice.getC_Invoice_ID(), allocInvoiceAccounted);
htGainLossAmtByCM.put(invoice.getC_Invoice_ID(), cmGainLossAmt);
htGainLossAmtByInv.put(invoice.getC_Invoice_ID(), gainLossAmt);
htIsExcludeCMGainLoss.put(invoice.getC_Invoice_ID(), isExcludeCMGainLoss);
htIsCMReversal.put(invoice.getC_Invoice_ID(), isCMReversal);
} }
} }
} }
for (MInvoice invoice : invList)
BigDecimal acctDifference = null; // gain is negative
//
StringBuilder description = new StringBuilder("Invoice=(").append(getC_Currency_ID()).append(")").append(allocInvoiceSource).append("/").append(allocInvoiceAccounted);
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
boolean isBPartnerAdjust = true;
if (allocInvoiceSource.abs().compareTo(totalInvoiceSource.abs()) == 0)
{ {
if (isExcludeCMGainLoss) BigDecimal invoiceSource = htInvSource.get(invoice.getC_Invoice_ID());
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt); if (invoiceSource == null)
if (payment != null && payment.getReversal_ID() > 0 ) invoiceSource = Env.ZERO;
allocInvoiceAccounted = allocInvoiceAccounted.subtract(gainLossAmt); BigDecimal invoiceAccounted = htInvAccounted.get(invoice.getC_Invoice_ID());
else if (invoiceAccounted == null)
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt); invoiceAccounted = Env.ZERO;
if (isCMReversal) BigDecimal allocInvoiceSource = htAllocInvSource.get(invoice.getC_Invoice_ID());
acctDifference = totalInvoiceAccounted.subtract(allocInvoiceAccounted.abs()); if (allocInvoiceSource == null)
else allocInvoiceSource = Env.ZERO;
acctDifference = allocInvoiceAccounted.subtract(totalInvoiceAccounted.abs()); // gain is positive for receipt BigDecimal allocInvoiceAccounted = htAllocInvAccounted.get(invoice.getC_Invoice_ID());
if (allocInvoiceAccounted == null)
allocInvoiceAccounted = Env.ZERO;
BigDecimal cmGainLossAmt = htGainLossAmtByCM.get(invoice.getC_Invoice_ID());
if (cmGainLossAmt == null)
cmGainLossAmt = Env.ZERO;
BigDecimal gainLossAmt = htGainLossAmtByInv.get(invoice.getC_Invoice_ID());
if (gainLossAmt == null)
gainLossAmt = Env.ZERO;
Boolean isExcludeCMGainLoss = htIsExcludeCMGainLoss.get(invoice.getC_Invoice_ID());
if (isExcludeCMGainLoss == null)
isExcludeCMGainLoss = Boolean.FALSE;
Boolean isCMReversal = htIsCMReversal.get(invoice.getC_Invoice_ID());
if (isCMReversal == null)
isCMReversal = Boolean.FALSE;
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference); BigDecimal acctDifference = null; // gain is negative
if (log.isLoggable(Level.FINE)) log.fine(d2.toString()); //
description.append(" - ").append(d2); StringBuilder description = new StringBuilder("Invoice=(").append(getC_Currency_ID()).append(")").append(allocInvoiceSource).append("/").append(allocInvoiceAccounted);
} else{ if (log.isLoggable(Level.FINE)) log.fine(description.toString());
MAllocationHdr[] allocations = MAllocationHdr.getOfInvoice(getCtx(), invoice.get_ID(), getTrxName()); boolean isBPartnerAdjust = true;
for (MAllocationHdr alloc : allocations) if (allocInvoiceSource.abs().compareTo(invoiceSource.abs()) == 0)
{ {
StringBuilder sql = new StringBuilder("SELECT ") if (isExcludeCMGainLoss)
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt);
for (MPayment payment : payList)
{
if (payment != null && payment.getReversal_ID() > 0 )
allocInvoiceAccounted = allocInvoiceAccounted.subtract(gainLossAmt);
else
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt);
}
if (isCMReversal)
acctDifference = invoiceAccounted.subtract(allocInvoiceAccounted.abs());
else
acctDifference = allocInvoiceAccounted.subtract(invoiceAccounted.abs()); // gain is positive for receipt
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
}
else
{
MAllocationHdr[] allocations = MAllocationHdr.getOfInvoice(getCtx(), invoice.get_ID(), getTrxName());
for (MAllocationHdr alloc : allocations)
{
if (alloc.get_ID() == get_ID())
continue;
StringBuilder sql = new StringBuilder("SELECT ")
.append(invoice.isSOTrx() .append(invoice.isSOTrx()
? "SUM(AmtSourceCr), SUM(AmtAcctCr), SUM(AmtAcctDr)" // so ? "SUM(AmtSourceCr), SUM(AmtAcctCr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtAcctCr)") // po : "SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtAcctCr)") // po
@ -1232,7 +1349,8 @@ public class Doc_AllocationHdr extends Doc
.append("WHERE AD_Table_ID=? AND Record_ID=?") // allocation .append("WHERE AD_Table_ID=? AND Record_ID=?") // allocation
.append(" AND C_AcctSchema_ID=?") .append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'") .append(" AND PostingType='A'")
.append(" AND Account_ID= ? "); .append(" AND Account_ID=?")
.append(" AND Line_ID IN (SELECT C_AllocationLine_ID FROM C_AllocationLine WHERE C_AllocationHdr_ID=? AND C_Invoice_ID=?)");
pstmt = null; pstmt = null;
rs = null; rs = null;
try try
@ -1242,15 +1360,17 @@ public class Doc_AllocationHdr extends Doc
pstmt.setInt(2, alloc.get_ID()); pstmt.setInt(2, alloc.get_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID()); pstmt.setInt(3, as.getC_AcctSchema_ID());
pstmt.setInt(4, bpAcct.getAccount_ID()); pstmt.setInt(4, bpAcct.getAccount_ID());
pstmt.setInt(5, alloc.get_ID());
pstmt.setInt(6, invoice.getC_Invoice_ID());
rs = pstmt.executeQuery(); rs = pstmt.executeQuery();
if (rs.next()) if (rs.next())
{ {
BigDecimal allocateSource = rs.getBigDecimal(1); BigDecimal allocateSource = rs.getBigDecimal(1);
BigDecimal allocateAccounted = rs.getBigDecimal(2); BigDecimal allocateAccounted = rs.getBigDecimal(2);
BigDecimal allocateCredit = rs.getBigDecimal(3); BigDecimal allocateCredit = rs.getBigDecimal(3);
allocInvoiceSource =allocInvoiceSource.add(allocateSource != null ? allocateSource: BigDecimal.ZERO); allocInvoiceSource = allocInvoiceSource.add(allocateSource != null ? allocateSource: BigDecimal.ZERO);
allocInvoiceAccounted =allocInvoiceAccounted.add(allocateAccounted != null ? allocateAccounted : BigDecimal.ZERO); allocInvoiceAccounted = allocInvoiceAccounted.add(allocateAccounted != null ? allocateAccounted : BigDecimal.ZERO);
allocInvoiceAccounted= allocInvoiceAccounted.subtract(allocateCredit != null ? allocateCredit : BigDecimal.ZERO); allocInvoiceAccounted = allocInvoiceAccounted.subtract(allocateCredit != null ? allocateCredit : BigDecimal.ZERO);
} }
} }
@ -1258,88 +1378,100 @@ public class Doc_AllocationHdr extends Doc
{ {
throw new RuntimeException(e.getLocalizedMessage(), e); throw new RuntimeException(e.getLocalizedMessage(), e);
} }
finally { finally
{
DB.close(rs, pstmt); DB.close(rs, pstmt);
rs = null; pstmt = null; rs = null; pstmt = null;
}
} }
double multiplier = allocInvoiceSource.doubleValue() / invoiceSource.doubleValue();
// Reduce Orig Invoice Accounted
BigDecimal reduceOrigAccounted = invoiceAccounted.multiply(BigDecimal.valueOf(multiplier));
if (reduceOrigAccounted.compareTo(invoiceAccounted) < 0 )
invoiceAccounted = reduceOrigAccounted;
if (isExcludeCMGainLoss)
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt);
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt);
// Difference based on percentage of Orig Invoice
acctDifference = allocInvoiceAccounted.subtract(invoiceAccounted);
// ignore Tolerance
if (acctDifference.abs().compareTo(BigDecimal.valueOf(0.01)) < 0)
acctDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (acctDifference.scale() > precision)
acctDifference = acctDifference.setScale(precision, RoundingMode.HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(acctDifference).append(" - Multiplier=").append(multiplier);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
} }
double multiplier = allocInvoiceSource.doubleValue() / totalInvoiceSource.doubleValue();
// Reduce Orig Invoice Accounted if (acctDifference.signum() == 0)
BigDecimal reduceOrigAccounted = totalInvoiceAccounted.multiply(BigDecimal.valueOf(multiplier));
if (reduceOrigAccounted.compareTo(totalInvoiceAccounted) < 0 )
totalInvoiceAccounted = reduceOrigAccounted;
if (isExcludeCMGainLoss)
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt);
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt);
// Difference based on percentage of Orig Invoice
acctDifference = allocInvoiceAccounted.subtract(totalInvoiceAccounted);
// ignore Tolerance
if (acctDifference.abs().compareTo(BigDecimal.valueOf(0.01)) < 0)
acctDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (acctDifference.scale() > precision)
acctDifference = acctDifference.setScale(precision, RoundingMode.HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(acctDifference).append(" - Multiplier=").append(multiplier);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
}
if (acctDifference.signum() == 0)
{
log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (acctDifference.abs().compareTo(TOLERANCE) <= 0)
{
if (invoice.isSOTrx())
{ {
FactLine fl = null; log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (acctDifference.abs().compareTo(TOLERANCE) <= 0)
{
Integer C_AllocationLine_ID = htInvAllocLine.get(invoice.getC_Invoice_ID());
if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo()))
{
FactLine fl = null;
if (!isBPartnerAdjust) if (!isBPartnerAdjust)
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference); fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference);
else else
fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference); fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString()); fl.setDescription(description.toString());
fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID);
if (!fact.isAcctBalanced()) if (!fact.isAcctBalanced())
{ {
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID() ) if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID())
{ {
fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate()); fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate());
} else }
else
{ {
fl = fact.createLine (null, loss, gain,as.getC_Currency_ID(), acctDifference.negate()); fl = fact.createLine (null, loss, gain,as.getC_Currency_ID(), acctDifference.negate());
} }
} }
}else fl.setDescription(description.toString());
fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID);
}
else
{ {
FactLine fl = null; FactLine fl = null;
if (!isBPartnerAdjust) if (!isBPartnerAdjust)
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate()); fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate());
else else
fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference.negate()); fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description.toString()); fl.setDescription(description.toString());
fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID);
if (!fact.isAcctBalanced()) if (!fact.isAcctBalanced())
{ {
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID() ) if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID())
{ {
fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference); fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference);
} else { }
fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference); else
{
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference);
} }
} }
fl.setDescription(description.toString());
fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID);
} }
} }
}
return null; return null;
} // createInvoiceRounding } // createInvoiceRounding

View File

@ -763,6 +763,21 @@ public class Doc_MatchInv extends Doc
cr.setQty(getQty().multiply(multiplier).negate()); cr.setQty(getQty().multiply(multiplier).negate());
} }
} }
// Rounding correction
if (refInvLine != null && refInvLine.getParent().getC_Currency_ID() != as.getC_Currency_ID()) // in foreign currency
{
p_Error = createInvoiceGainLoss(as, fact, expense, refInvLine.getParent(), dr.getAmtSourceCr(), dr.getAmtAcctCr());
if (p_Error != null)
return null;
}
if (m_invoiceLine != null && m_invoiceLine.getParent().getC_Currency_ID() != as.getC_Currency_ID()) // in foreign currency
{
p_Error = createInvoiceGainLoss(as, fact, expense, m_invoiceLine.getParent(), cr.getAmtSourceDr(), cr.getAmtAcctDr());
if (p_Error != null)
return null;
}
if (m_matchInv.getReversal_ID() == 0) if (m_matchInv.getReversal_ID() == 0)
{ {
cr.setC_Activity_ID(m_invoiceLine.getC_Activity_ID()); cr.setC_Activity_ID(m_invoiceLine.getC_Activity_ID());
@ -880,7 +895,7 @@ public class Doc_MatchInv extends Doc
return null; return null;
// //
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID()) if (m_matchInv.getReversal_ID() == 0)
{ {
String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv " String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv "
+ "WHERE C_InvoiceLine_ID IN (SELECT C_InvoiceLine_ID FROM C_InvoiceLine WHERE C_Invoice_ID=?) " + "WHERE C_InvoiceLine_ID IN (SELECT C_InvoiceLine_ID FROM C_InvoiceLine WHERE C_Invoice_ID=?) "
@ -939,15 +954,28 @@ public class Doc_MatchInv extends Doc
if (totalAmtAcctCr == null) if (totalAmtAcctCr == null)
totalAmtAcctCr = Env.ZERO; totalAmtAcctCr = Env.ZERO;
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) if (m_matchInv.getReversal_ID() == 0)
{ {
matchInvSource = matchInvSource.add(totalAmtSourceCr); if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr); {
} matchInvSource = matchInvSource.add(totalAmtSourceCr);
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0) matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
{ }
matchInvSource = matchInvSource.add(totalAmtSourceDr); else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr); {
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
}
else if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr);
}
else
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr);
}
} }
else else
{ {
@ -955,13 +983,13 @@ public class Doc_MatchInv extends Doc
{ {
matchInvSource = matchInvSource.add(totalAmtSourceDr); matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr); matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
acctDifference = totalAmtAcctCr.negate(); acctDifference = totalAmtAcctCr;
} }
else else
{ {
matchInvSource = matchInvSource.add(totalAmtSourceCr); matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr); matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
acctDifference = totalAmtSourceDr.negate(); acctDifference = totalAmtAcctDr.negate();
} }
} }
} }
@ -1050,7 +1078,7 @@ public class Doc_MatchInv extends Doc
if (receiptSource == null || receiptAccounted == null) if (receiptSource == null || receiptAccounted == null)
return null; return null;
// //
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID()) if (m_matchInv.getReversal_ID() == 0)
{ {
String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv " String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv "
+ "WHERE M_InOutLine_ID IN (SELECT M_InOutLine_ID FROM M_InOutLine WHERE M_InOut_ID=?) " + "WHERE M_InOutLine_ID IN (SELECT M_InOutLine_ID FROM M_InOutLine WHERE M_InOut_ID=?) "
@ -1110,45 +1138,42 @@ public class Doc_MatchInv extends Doc
if (totalAmtAcctCr == null) if (totalAmtAcctCr == null)
totalAmtAcctCr = Env.ZERO; totalAmtAcctCr = Env.ZERO;
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) if (m_matchInv.getReversal_ID() == 0)
{ {
matchInvSource = matchInvSource.add(totalAmtSourceCr); if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
}
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
}
else
{
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID())
{ {
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0) matchInvSource = matchInvSource.add(totalAmtSourceCr);
{ matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
matchInvSource = matchInvSource.add(totalAmtSourceDr); }
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr); else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
} {
else matchInvSource = matchInvSource.add(totalAmtSourceDr);
{ matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
matchInvSource = matchInvSource.add(totalAmtSourceCr); }
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr); else if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
} {
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr);
} }
else else
{ {
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0) matchInvSource = matchInvSource.add(totalAmtSourceCr);
{ matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr);
matchInvSource = matchInvSource.add(totalAmtSourceDr); }
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr); }
acctDifference = totalAmtAcctCr.negate(); else
} {
else if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
{ {
matchInvSource = matchInvSource.add(totalAmtSourceCr); matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr); matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
acctDifference = totalAmtAcctDr.negate(); acctDifference = totalAmtAcctCr.negate();;
} }
else
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
acctDifference = totalAmtAcctDr;
} }
} }
} }

View File

@ -1616,10 +1616,10 @@ public class MInOut extends X_M_InOut implements DocAction
} }
if (!po.isPosted()) if (!po.isPosted())
addDocsPostProcess(po); addDocsPostProcess(po);
MMatchInv matchInvCreated = po.getMatchInvCreated();
if (matchInvCreated != null) { MMatchInv[] matchInvList = MMatchInv.getInOut(getCtx(), getM_InOut_ID(), get_TrxName());
for (MMatchInv matchInvCreated : matchInvList)
addDocsPostProcess(matchInvCreated); addDocsPostProcess(matchInvCreated);
}
} }
// Update PO with ASI // Update PO with ASI
if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0 if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0