IDEMPIERE-4263 Wrong matched invoice GL posting (currency balancing) in alternate schema for vendor credit memo if > 1 credit memo line (#250)
* IDEMPIERE-4263 Wrong matched invoice GL posting (currency balancing) in alternate schema for vendor credit memo if > 1 credit memo line
This commit is contained in:
parent
599e13dda3
commit
79d6c1e903
|
@ -23,6 +23,7 @@ import java.sql.SQLException;
|
|||
import java.sql.Savepoint;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -75,6 +76,9 @@ public class Doc_MatchInv extends Doc
|
|||
super(as, MMatchInv.class, rs, DOCTYPE_MatMatchInv, trxName);
|
||||
} // Doc_MatchInv
|
||||
|
||||
/** Tolerance G&L */
|
||||
private static final BigDecimal TOLERANCE = BigDecimal.valueOf(0.02);
|
||||
|
||||
/** Invoice Line */
|
||||
private MInvoiceLine m_invoiceLine = null;
|
||||
/** Material Receipt */
|
||||
|
@ -142,6 +146,13 @@ public class Doc_MatchInv extends Doc
|
|||
public ArrayList<Fact> createFacts (MAcctSchema as)
|
||||
{
|
||||
ArrayList<Fact> facts = new ArrayList<Fact>();
|
||||
// invoice gain/loss accounting fact line list
|
||||
ArrayList<FactLine> invGainLossFactLines = new ArrayList<FactLine>();
|
||||
// invoice list
|
||||
ArrayList<MInvoice> invList = new ArrayList<MInvoice>();
|
||||
// C_Invoice_ID and the current M_MatchInv inventory clearing/expense accounting fact lines
|
||||
HashMap<Integer, ArrayList<FactLine>> htFactLineInv = new HashMap<Integer, ArrayList<FactLine>>();
|
||||
|
||||
// Nothing to do
|
||||
if (getM_Product_ID() == 0 // no Product
|
||||
|| getQty().signum() == 0
|
||||
|
@ -292,16 +303,32 @@ public class Doc_MatchInv extends Doc
|
|||
}
|
||||
}
|
||||
|
||||
// Rounding correction
|
||||
// gain/loss + rounding adjustment
|
||||
if (m_receiptLine != null && m_invoiceLine.getParent().getC_Currency_ID() != as.getC_Currency_ID()) // in foreign currency
|
||||
{
|
||||
p_Error = createReceiptGainLoss(as, fact, getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as), m_receiptLine.getParent(), dr.getAmtSourceDr(), dr.getAmtAcctDr());
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
// gain/loss
|
||||
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.getAmtSourceCr(), cr.getAmtAcctCr());
|
||||
MInvoice invoice = m_invoiceLine.getParent();
|
||||
if (!invList.contains(invoice))
|
||||
invList.add(invoice);
|
||||
ArrayList<FactLine> factLineList = htFactLineInv.get(invoice.get_ID());
|
||||
if (factLineList == null)
|
||||
factLineList = new ArrayList<FactLine>();
|
||||
factLineList.add(cr);
|
||||
htFactLineInv.put(invoice.get_ID(), factLineList);
|
||||
p_Error = createInvoiceGainLoss(as, fact, expense, invoice, cr.getAmtSourceCr(), cr.getAmtAcctCr(), invGainLossFactLines, htFactLineInv);
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
// rounding adjustment
|
||||
if (!htFactLineInv.isEmpty())
|
||||
{
|
||||
p_Error = createInvoiceRoundingCorrection(as, fact, expense, invGainLossFactLines, invList, htFactLineInv);
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
|
@ -587,6 +614,12 @@ public class Doc_MatchInv extends Doc
|
|||
|
||||
private ArrayList<Fact> createMatShipmentFacts(MAcctSchema as) {
|
||||
ArrayList<Fact> facts = new ArrayList<Fact>();
|
||||
// invoice gain/loss accounting fact line list
|
||||
ArrayList<FactLine> invGainLossFactLines = new ArrayList<FactLine>();
|
||||
// invoice list
|
||||
ArrayList<MInvoice> invList = new ArrayList<MInvoice>();
|
||||
// C_Invoice_ID and the current M_MatchInv inventory clearing/expense accounting fact lines
|
||||
HashMap<Integer, ArrayList<FactLine>> htFactLineInv = new HashMap<Integer, ArrayList<FactLine>>();
|
||||
|
||||
// create Fact Header
|
||||
Fact fact = new Fact(this, as, Fact.POST_Actual);
|
||||
|
@ -708,16 +741,33 @@ public class Doc_MatchInv extends Doc
|
|||
}
|
||||
}
|
||||
|
||||
// Rounding correction
|
||||
// gain/loss + rounding adjustment
|
||||
if (m_receiptLine != null && m_invoiceLine.getParent().getC_Currency_ID() != as.getC_Currency_ID()) // in foreign currency
|
||||
{
|
||||
p_Error = createReceiptGainLoss(as, fact, getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as), m_receiptLine.getParent(), dr.getAmtSourceCr(), dr.getAmtAcctCr());
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
|
||||
// gain/loss
|
||||
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());
|
||||
MInvoice invoice = m_invoiceLine.getParent();
|
||||
if (!invList.contains(invoice))
|
||||
invList.add(invoice);
|
||||
ArrayList<FactLine> factLineList = htFactLineInv.get(invoice.get_ID());
|
||||
if (factLineList == null)
|
||||
factLineList = new ArrayList<FactLine>();
|
||||
factLineList.add(cr);
|
||||
htFactLineInv.put(invoice.get_ID(), factLineList);
|
||||
p_Error = createInvoiceGainLoss(as, fact, expense, invoice, cr.getAmtSourceDr(), cr.getAmtAcctDr(), invGainLossFactLines, htFactLineInv);
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
// rounding adjustment
|
||||
if (!htFactLineInv.isEmpty())
|
||||
{
|
||||
p_Error = createInvoiceRoundingCorrection(as, fact, expense, invGainLossFactLines, invList, htFactLineInv);
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
|
@ -795,6 +845,12 @@ public class Doc_MatchInv extends Doc
|
|||
|
||||
public ArrayList<Fact> createCreditMemoFacts(MAcctSchema as) {
|
||||
ArrayList<Fact> facts = new ArrayList<Fact>();
|
||||
// invoice gain/loss accounting fact line list
|
||||
ArrayList<FactLine> invGainLossFactLines = new ArrayList<FactLine>();
|
||||
// invoice list
|
||||
ArrayList<MInvoice> invList = new ArrayList<MInvoice>();
|
||||
// C_Invoice_ID and the current M_MatchInv inventory clearing/expense accounting fact lines
|
||||
HashMap<Integer, ArrayList<FactLine>> htFactLineInv = new HashMap<Integer, ArrayList<FactLine>>();
|
||||
|
||||
// create Fact Header
|
||||
Fact fact = new Fact(this, as, Fact.POST_Actual);
|
||||
|
@ -975,16 +1031,40 @@ public class Doc_MatchInv extends Doc
|
|||
}
|
||||
}
|
||||
|
||||
// Rounding correction
|
||||
// gain / loss
|
||||
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());
|
||||
MInvoice invoice = refInvLine.getParent();
|
||||
if (!invList.contains(invoice))
|
||||
invList.add(invoice);
|
||||
ArrayList<FactLine> factLineList = htFactLineInv.get(invoice.get_ID());
|
||||
if (factLineList == null)
|
||||
factLineList = new ArrayList<FactLine>();
|
||||
factLineList.add(dr);
|
||||
htFactLineInv.put(invoice.get_ID(), factLineList);
|
||||
p_Error = createInvoiceGainLoss(as, fact, expense, invoice, dr.getAmtSourceCr(), dr.getAmtAcctCr(), invGainLossFactLines, htFactLineInv);
|
||||
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());
|
||||
MInvoice invoice = m_invoiceLine.getParent();
|
||||
if (!invList.contains(invoice))
|
||||
invList.add(invoice);
|
||||
ArrayList<FactLine> factLineList = htFactLineInv.get(invoice.get_ID());
|
||||
if (factLineList == null)
|
||||
factLineList = new ArrayList<FactLine>();
|
||||
factLineList.add(cr);
|
||||
htFactLineInv.put(invoice.get_ID(), factLineList);
|
||||
p_Error = createInvoiceGainLoss(as, fact, expense, invoice, cr.getAmtSourceDr(), cr.getAmtAcctDr(), invGainLossFactLines, htFactLineInv);
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
|
||||
// rounding adjustment
|
||||
if (!htFactLineInv.isEmpty())
|
||||
{
|
||||
p_Error = createInvoiceRoundingCorrection(as, fact, expense, invGainLossFactLines, invList, htFactLineInv);
|
||||
if (p_Error != null)
|
||||
return null;
|
||||
}
|
||||
|
@ -1024,7 +1104,7 @@ public class Doc_MatchInv extends Doc
|
|||
BigDecimal debit = dr.getAmtSourceDr();
|
||||
BigDecimal credit = cr.getAmtSourceCr();
|
||||
|
||||
if (debit.compareTo(credit) == 0) {
|
||||
if (debit.compareTo(credit) == 0 && (cr.getAcctBalance().add(dr.getAcctBalance())).compareTo(Env.ZERO) == 0) {
|
||||
fact.remove(dr);
|
||||
fact.remove(cr);
|
||||
}
|
||||
|
@ -1076,7 +1156,8 @@ public class Doc_MatchInv extends Doc
|
|||
}
|
||||
|
||||
private String createInvoiceGainLoss(MAcctSchema as, Fact fact, MAccount acct,
|
||||
MInvoice invoice, BigDecimal matchInvSource, BigDecimal matchInvAccounted)
|
||||
MInvoice invoice, BigDecimal matchInvSource, BigDecimal matchInvAccounted,
|
||||
ArrayList<FactLine> invGainLossFactLines, HashMap<Integer, ArrayList<FactLine>> htFactLineInv)
|
||||
{
|
||||
BigDecimal invoiceSource = null;
|
||||
BigDecimal invoiceAccounted = null;
|
||||
|
@ -1105,126 +1186,46 @@ public class Doc_MatchInv extends Doc
|
|||
if (invoiceSource == null || invoiceAccounted == null)
|
||||
return null;
|
||||
//
|
||||
|
||||
if (m_matchInv.getReversal_ID() == 0)
|
||||
{
|
||||
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=?) "
|
||||
+ "AND COALESCE(Reversal_ID,0)=0";
|
||||
List<List<Object>> list = DB.getSQLArrayObjectsEx(getTrxName(), matchInvLineSql, invoice.get_ID());
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
||||
if (list == null)
|
||||
return null;
|
||||
|
||||
for (int index=0; index < list.size(); index++)
|
||||
{
|
||||
List<Object> l = list.get(index);
|
||||
s.append(l.get(0));
|
||||
if (index != list.size()-1)
|
||||
s.append(",");
|
||||
}
|
||||
|
||||
sql = new StringBuilder()
|
||||
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
|
||||
.append(" FROM Fact_Acct ")
|
||||
.append("WHERE AD_Table_ID=? AND Record_ID IN (").append(s).append(")")
|
||||
.append(" AND Record_ID <> ?")
|
||||
.append(" AND C_AcctSchema_ID=?")
|
||||
.append(" AND Account_ID=?")
|
||||
.append(" AND PostingType='A'");
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = new StringBuilder()
|
||||
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
|
||||
.append(" FROM Fact_Acct ")
|
||||
.append("WHERE AD_Table_ID=? AND Record_ID IN (").append(m_matchInv.getReversal_ID()).append(")")
|
||||
.append(" AND Record_ID <> ?")
|
||||
.append(" AND C_AcctSchema_ID=?")
|
||||
.append(" AND Account_ID=?")
|
||||
.append(" AND PostingType='A'");
|
||||
}
|
||||
|
||||
BigDecimal acctDifference = null; // gain is negative
|
||||
// For Match Invoice
|
||||
valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
|
||||
MMatchInv.Table_ID, get_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
|
||||
if (valuesInv != null)
|
||||
{
|
||||
BigDecimal totalAmtSourceDr = (BigDecimal) valuesInv.get(0);
|
||||
if (totalAmtSourceDr == null)
|
||||
totalAmtSourceDr = Env.ZERO;
|
||||
BigDecimal totalAmtAcctDr = (BigDecimal) valuesInv.get(1);
|
||||
if (totalAmtAcctDr == null)
|
||||
totalAmtAcctDr = Env.ZERO;
|
||||
BigDecimal totalAmtSourceCr = (BigDecimal) valuesInv.get(2);
|
||||
if (totalAmtSourceCr == null)
|
||||
totalAmtSourceCr = Env.ZERO;
|
||||
BigDecimal totalAmtAcctCr = (BigDecimal) valuesInv.get(3);
|
||||
if (totalAmtAcctCr == null)
|
||||
totalAmtAcctCr = Env.ZERO;
|
||||
|
||||
if (m_matchInv.getReversal_ID() == 0)
|
||||
{
|
||||
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceCr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
|
||||
}
|
||||
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceDr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
|
||||
acctDifference = totalAmtAcctCr;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceCr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
|
||||
acctDifference = totalAmtAcctDr.negate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StringBuilder description = new StringBuilder("Invoice=(").append(invoice.getC_Currency_ID()).append(")").append(invoiceSource).append("/").append(invoiceAccounted)
|
||||
.append(" - MatchInv=(").append(getC_Currency_ID()).append(")").append(matchInvSource).append("/").append(matchInvAccounted);
|
||||
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
|
||||
//
|
||||
|
||||
// Full Payment in currency
|
||||
if (acctDifference == null && matchInvSource.compareTo(invoiceSource) == 0)
|
||||
BigDecimal acctDifference = null;
|
||||
// Full MR in currency
|
||||
if (matchInvSource.compareTo(invoiceSource) == 0)
|
||||
{
|
||||
acctDifference = matchInvAccounted.subtract(invoiceAccounted.abs()); // gain is negative
|
||||
acctDifference = matchInvAccounted.abs().subtract(invoiceAccounted.abs()); // gain is negative
|
||||
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
|
||||
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
|
||||
description.append(" - ").append(d2);
|
||||
}
|
||||
else // partial or MC
|
||||
{
|
||||
BigDecimal matchInvAccounted0 = MConversionRate.convert(getCtx(),
|
||||
matchInvSource, invoice.getC_Currency_ID(),
|
||||
as.getC_Currency_ID(), invoice.getDateAcct(),
|
||||
invoice.getC_ConversionType_ID(), invoice.getAD_Client_ID(), invoice.getAD_Org_ID());
|
||||
acctDifference = matchInvAccounted0.abs().subtract(matchInvAccounted.abs());
|
||||
// ignore Tolerance
|
||||
if (acctDifference.abs().compareTo(TOLERANCE) < 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);
|
||||
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
|
||||
description.append(" - ").append(d2);
|
||||
}
|
||||
|
||||
if (acctDifference == null || acctDifference.signum() == 0)
|
||||
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());
|
||||
//
|
||||
|
@ -1233,32 +1234,409 @@ public class Doc_MatchInv extends Doc
|
|||
FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference.negate());
|
||||
fl.setDescription(description.toString());
|
||||
updateFactLine(fl);
|
||||
|
||||
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID()) {
|
||||
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(), as.getC_Currency_ID(), acctDifference);
|
||||
} else {
|
||||
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference);
|
||||
}
|
||||
ArrayList<FactLine> factLineList = htFactLineInv.get(invoice.get_ID());
|
||||
if (factLineList == null)
|
||||
factLineList = new ArrayList<FactLine>();
|
||||
factLineList.add(fl);
|
||||
htFactLineInv.put(invoice.get_ID(), factLineList);
|
||||
|
||||
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference);
|
||||
fl.setDescription(description.toString());
|
||||
updateFactLine(fl);
|
||||
invGainLossFactLines.add(fl);
|
||||
}
|
||||
else
|
||||
{
|
||||
FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference);
|
||||
fl.setDescription(description.toString());
|
||||
updateFactLine(fl);
|
||||
ArrayList<FactLine> factLineList = htFactLineInv.get(invoice.get_ID());
|
||||
if (factLineList == null)
|
||||
factLineList = new ArrayList<FactLine>();
|
||||
factLineList.add(fl);
|
||||
htFactLineInv.put(invoice.get_ID(), factLineList);
|
||||
|
||||
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID()) {
|
||||
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(), as.getC_Currency_ID(), acctDifference.negate());
|
||||
} 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());
|
||||
fl.setDescription(description.toString());
|
||||
updateFactLine(fl);
|
||||
invGainLossFactLines.add(fl);
|
||||
}
|
||||
return null;
|
||||
} // createInvoiceGainLoss
|
||||
|
||||
private String createInvoiceRoundingCorrection(MAcctSchema as, Fact fact, MAccount acct,
|
||||
ArrayList<FactLine> invGainLossFactLines, ArrayList<MInvoice> invList, HashMap<Integer, ArrayList<FactLine>> htFactLineInv)
|
||||
{
|
||||
// C_Invoice_ID and the total source amount from C_Invoice accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htInvSource = new HashMap<Integer, BigDecimal>();
|
||||
// C_Invoice_ID and the total accounted amount from C_Invoice accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htInvAccounted = new HashMap<Integer, BigDecimal>();
|
||||
for (MInvoice invoice : invList)
|
||||
{
|
||||
StringBuilder sql = new StringBuilder()
|
||||
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
|
||||
.append(" FROM Fact_Acct ")
|
||||
.append("WHERE AD_Table_ID=? AND Record_ID=?")
|
||||
.append(" AND C_AcctSchema_ID=?")
|
||||
.append(" AND Account_ID=?")
|
||||
.append(" AND PostingType='A'");
|
||||
|
||||
// For Invoice
|
||||
List<Object> valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
|
||||
MInvoice.Table_ID, invoice.getC_Invoice_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
|
||||
if (valuesInv != null) {
|
||||
BigDecimal invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr
|
||||
BigDecimal invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr
|
||||
if (invoiceSource.signum() == 0 && invoiceAccounted.signum() == 0) {
|
||||
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr
|
||||
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
|
||||
}
|
||||
htInvSource.put(invoice.getC_Invoice_ID(), invoiceSource);
|
||||
htInvAccounted.put(invoice.getC_Invoice_ID(), invoiceAccounted);
|
||||
}
|
||||
}
|
||||
|
||||
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
|
||||
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
|
||||
|
||||
// C_Invoice_ID and the total source DR amount from the current M_MatchInv accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htTotalAmtSourceDr = new HashMap<Integer, BigDecimal>();
|
||||
// C_Invoice_ID and the total accounted DR amount from the current M_MatchInv accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htTotalAmtAcctDr = new HashMap<Integer, BigDecimal>();
|
||||
// C_Invoice_ID and the total source CR amount from the current M_MatchInv accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htTotalAmtSourceCr = new HashMap<Integer, BigDecimal>();
|
||||
// C_Invoice_ID and the total accounted CR amount from the current M_MatchInv accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htTotalAmtAcctCr = new HashMap<Integer, BigDecimal>();
|
||||
for (Integer C_Invoice_ID : htFactLineInv.keySet())
|
||||
{
|
||||
ArrayList<FactLine> factLineList = htFactLineInv.get(C_Invoice_ID);
|
||||
for (FactLine factLine : factLineList)
|
||||
{
|
||||
if (factLine.getAccount_ID() == acct.getAccount_ID())
|
||||
{
|
||||
BigDecimal totalAmtSourceDr = htTotalAmtSourceDr.get(C_Invoice_ID);
|
||||
if (totalAmtSourceDr == null)
|
||||
totalAmtSourceDr = Env.ZERO;
|
||||
BigDecimal totalAmtAcctDr = htTotalAmtAcctDr.get(C_Invoice_ID);
|
||||
if (totalAmtAcctDr == null)
|
||||
totalAmtAcctDr = Env.ZERO;
|
||||
BigDecimal totalAmtSourceCr = htTotalAmtSourceCr.get(C_Invoice_ID);
|
||||
if (totalAmtSourceCr == null)
|
||||
totalAmtSourceCr = Env.ZERO;
|
||||
BigDecimal totalAmtAcctCr = htTotalAmtAcctCr.get(C_Invoice_ID);
|
||||
if (totalAmtAcctCr == null)
|
||||
totalAmtAcctCr = Env.ZERO;
|
||||
|
||||
totalAmtSourceDr = totalAmtSourceDr.add(factLine.getAmtSourceDr());
|
||||
totalAmtAcctDr = totalAmtAcctDr.add(factLine.getAmtAcctDr());
|
||||
totalAmtSourceCr = totalAmtSourceCr.add(factLine.getAmtSourceCr());
|
||||
totalAmtAcctCr = totalAmtAcctCr.add(factLine.getAmtAcctCr());
|
||||
|
||||
htTotalAmtSourceDr.put(C_Invoice_ID, totalAmtSourceDr);
|
||||
htTotalAmtAcctDr.put(C_Invoice_ID, totalAmtAcctDr);
|
||||
htTotalAmtSourceCr.put(C_Invoice_ID, totalAmtSourceCr);
|
||||
htTotalAmtAcctCr.put(C_Invoice_ID, totalAmtAcctCr);
|
||||
}
|
||||
else if (factLine.getAccount_ID() == gain.getAccount_ID() || factLine.getAccount_ID() == loss.getAccount_ID())
|
||||
{
|
||||
if (!invGainLossFactLines.contains(factLine))
|
||||
continue;
|
||||
|
||||
BigDecimal totalAmtSourceDr = htTotalAmtSourceDr.get(C_Invoice_ID);
|
||||
if (totalAmtSourceDr == null)
|
||||
totalAmtSourceDr = Env.ZERO;
|
||||
BigDecimal totalAmtSourceCr = htTotalAmtSourceCr.get(C_Invoice_ID);
|
||||
if (totalAmtSourceCr == null)
|
||||
totalAmtSourceCr = Env.ZERO;
|
||||
|
||||
totalAmtSourceDr = totalAmtSourceDr.subtract(factLine.getAmtSourceCr());
|
||||
totalAmtSourceCr = totalAmtSourceCr.subtract(factLine.getAmtSourceDr());
|
||||
|
||||
htTotalAmtSourceDr.put(C_Invoice_ID, totalAmtSourceDr);
|
||||
htTotalAmtSourceCr.put(C_Invoice_ID, totalAmtSourceCr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// C_Invoice_ID and the total source amount from M_MatchInv accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htMatchInvSource = new HashMap<Integer, BigDecimal>();
|
||||
// C_Invoice_ID and the total accounted amount from M_MatchInv accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htMatchInvAccounted = new HashMap<Integer, BigDecimal>();
|
||||
// C_Invoice_ID and the total source amount from M_MatchInv accounting fact lines
|
||||
HashMap<Integer, BigDecimal> htMatchInvAcctDiff = new HashMap<Integer, BigDecimal>();
|
||||
for (MInvoice invoice : invList)
|
||||
{
|
||||
BigDecimal matchInvSource = Env.ZERO;
|
||||
BigDecimal matchInvAccounted = Env.ZERO;
|
||||
|
||||
BigDecimal totalAmtSourceDr = htTotalAmtSourceDr.get(invoice.getC_Invoice_ID());
|
||||
if (totalAmtSourceDr == null)
|
||||
totalAmtSourceDr = Env.ZERO;
|
||||
BigDecimal totalAmtAcctDr = htTotalAmtAcctDr.get(invoice.getC_Invoice_ID());
|
||||
if (totalAmtAcctDr == null)
|
||||
totalAmtAcctDr = Env.ZERO;
|
||||
BigDecimal totalAmtSourceCr = htTotalAmtSourceCr.get(invoice.getC_Invoice_ID());
|
||||
if (totalAmtSourceCr == null)
|
||||
totalAmtSourceCr = Env.ZERO;
|
||||
BigDecimal totalAmtAcctCr = htTotalAmtAcctCr.get(invoice.getC_Invoice_ID());
|
||||
if (totalAmtAcctCr == null)
|
||||
totalAmtAcctCr = Env.ZERO;
|
||||
|
||||
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceCr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
|
||||
}
|
||||
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceDr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceDr).subtract(totalAmtSourceCr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceCr).subtract(totalAmtSourceDr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_matchInv.getReversal_ID() == 0)
|
||||
{
|
||||
MMatchInv[] matchInvs = MMatchInv.getInvoice(getCtx(), invoice.get_ID(), getTrxName());
|
||||
|
||||
ArrayList<Integer> skipMatchInvIdList = new ArrayList<Integer>();
|
||||
skipMatchInvIdList.add(m_matchInv.get_ID());
|
||||
for (MMatchInv matchInv : matchInvs)
|
||||
{
|
||||
if (matchInv.getReversal_ID() > 0)
|
||||
skipMatchInvIdList.add(matchInv.get_ID());
|
||||
}
|
||||
|
||||
for (MMatchInv matchInv : matchInvs)
|
||||
{
|
||||
if (matchInv.get_ID() == m_matchInv.get_ID())
|
||||
continue;
|
||||
|
||||
if (skipMatchInvIdList.contains(matchInv.get_ID()))
|
||||
continue;
|
||||
|
||||
StringBuilder sql = new StringBuilder()
|
||||
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
|
||||
.append(" FROM Fact_Acct ")
|
||||
.append("WHERE AD_Table_ID=? AND (Record_ID=? OR Record_ID=?)") // match inv
|
||||
.append(" AND C_AcctSchema_ID=?")
|
||||
.append(" AND PostingType='A'")
|
||||
.append(" AND Account_ID=?");
|
||||
|
||||
if (matchInv.getRef_MatchInv_ID() > 0)
|
||||
{
|
||||
if (invoice.isCreditMemo() && matchInv.getQty().compareTo(BigDecimal.ZERO) < 0)
|
||||
sql.append(" AND Qty > 0");
|
||||
else
|
||||
sql.append(" AND Qty < 0");
|
||||
}
|
||||
|
||||
// For Match Inv
|
||||
List<Object> valuesMatchInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
|
||||
MMatchInv.Table_ID, matchInv.get_ID(), matchInv.getRef_MatchInv_ID() > 0 ? matchInv.getRef_MatchInv_ID() : -1, as.getC_AcctSchema_ID(), acct.getAccount_ID());
|
||||
if (valuesMatchInv != null) {
|
||||
totalAmtSourceDr = (BigDecimal) valuesMatchInv.get(0);
|
||||
if (totalAmtSourceDr == null)
|
||||
totalAmtSourceDr = Env.ZERO;
|
||||
totalAmtAcctDr = (BigDecimal) valuesMatchInv.get(1);
|
||||
if (totalAmtAcctDr == null)
|
||||
totalAmtAcctDr = Env.ZERO;
|
||||
totalAmtSourceCr = (BigDecimal) valuesMatchInv.get(2);
|
||||
if (totalAmtSourceCr == null)
|
||||
totalAmtSourceCr = Env.ZERO;
|
||||
totalAmtAcctCr = (BigDecimal) valuesMatchInv.get(3);
|
||||
if (totalAmtAcctCr == null)
|
||||
totalAmtAcctCr = Env.ZERO;
|
||||
|
||||
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceCr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
|
||||
}
|
||||
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceDr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceDr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceCr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sql = new StringBuilder()
|
||||
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
|
||||
.append(" FROM Fact_Acct ")
|
||||
.append("WHERE AD_Table_ID=? AND (Record_ID=? OR Record_ID=?)") // match inv
|
||||
.append(" AND C_AcctSchema_ID=?")
|
||||
.append(" AND PostingType='A'")
|
||||
.append(" AND (Account_ID=? OR Account_ID=? OR Account_ID=?)")
|
||||
.append(" AND Description LIKE 'Invoice%'");
|
||||
|
||||
// For Match Inv
|
||||
valuesMatchInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
|
||||
MMatchInv.Table_ID, matchInv.get_ID(), matchInv.getRef_MatchInv_ID() > 0 ? matchInv.getRef_MatchInv_ID() : -1, as.getC_AcctSchema_ID(),
|
||||
gain.getAccount_ID(), loss.getAccount_ID(), as.getCurrencyBalancing_Acct().getAccount_ID());
|
||||
if (valuesMatchInv != null) {
|
||||
totalAmtSourceDr = (BigDecimal) valuesMatchInv.get(0);
|
||||
if (totalAmtSourceDr == null)
|
||||
totalAmtSourceDr = Env.ZERO;
|
||||
totalAmtAcctDr = (BigDecimal) valuesMatchInv.get(1);
|
||||
if (totalAmtAcctDr == null)
|
||||
totalAmtAcctDr = Env.ZERO;
|
||||
totalAmtSourceCr = (BigDecimal) valuesMatchInv.get(2);
|
||||
if (totalAmtSourceCr == null)
|
||||
totalAmtSourceCr = Env.ZERO;
|
||||
totalAmtAcctCr = (BigDecimal) valuesMatchInv.get(3);
|
||||
if (totalAmtAcctCr == null)
|
||||
totalAmtAcctCr = Env.ZERO;
|
||||
|
||||
matchInvAccounted = matchInvAccounted.subtract(totalAmtAcctDr).subtract(totalAmtAcctCr);
|
||||
}
|
||||
}
|
||||
|
||||
htMatchInvSource.put(invoice.getC_Invoice_ID(), matchInvSource);
|
||||
htMatchInvAccounted.put(invoice.getC_Invoice_ID(), matchInvAccounted);
|
||||
}
|
||||
else
|
||||
{
|
||||
BigDecimal acctDifference = Env.ZERO;
|
||||
StringBuilder sql = new StringBuilder()
|
||||
.append("SELECT SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtSourceCr), SUM(AmtAcctCr)")
|
||||
.append(" FROM Fact_Acct ")
|
||||
.append("WHERE AD_Table_ID=? AND Record_ID IN (").append(m_matchInv.getReversal_ID()).append(")")
|
||||
.append(" AND Record_ID <> ?")
|
||||
.append(" AND C_AcctSchema_ID=?")
|
||||
.append(" AND PostingType='A'")
|
||||
.append(" AND Account_ID=?");
|
||||
|
||||
// For Match Inv
|
||||
List<Object> valuesMatchInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
|
||||
MMatchInv.Table_ID, get_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
|
||||
if (valuesMatchInv != null) {
|
||||
totalAmtSourceDr = (BigDecimal) valuesMatchInv.get(0);
|
||||
if (totalAmtSourceDr == null)
|
||||
totalAmtSourceDr = Env.ZERO;
|
||||
totalAmtAcctDr = (BigDecimal) valuesMatchInv.get(1);
|
||||
if (totalAmtAcctDr == null)
|
||||
totalAmtAcctDr = Env.ZERO;
|
||||
totalAmtSourceCr = (BigDecimal) valuesMatchInv.get(2);
|
||||
if (totalAmtSourceCr == null)
|
||||
totalAmtSourceCr = Env.ZERO;
|
||||
totalAmtAcctCr = (BigDecimal) valuesMatchInv.get(3);
|
||||
if (totalAmtAcctCr == null)
|
||||
totalAmtAcctCr = Env.ZERO;
|
||||
|
||||
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceDr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
|
||||
acctDifference = totalAmtAcctCr.negate();
|
||||
}
|
||||
else
|
||||
{
|
||||
matchInvSource = matchInvSource.add(totalAmtSourceCr);
|
||||
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
|
||||
acctDifference = totalAmtAcctDr;
|
||||
}
|
||||
}
|
||||
|
||||
htMatchInvSource.put(invoice.getC_Invoice_ID(), matchInvSource);
|
||||
htMatchInvAccounted.put(invoice.getC_Invoice_ID(), matchInvAccounted);
|
||||
htMatchInvAcctDiff.put(invoice.getC_Invoice_ID(), acctDifference);
|
||||
}
|
||||
}
|
||||
|
||||
for (MInvoice invoice : invList)
|
||||
{
|
||||
BigDecimal invSource = htInvSource.get(invoice.getC_Invoice_ID());
|
||||
if (invSource == null)
|
||||
invSource = Env.ZERO;
|
||||
BigDecimal invAccounted = htInvAccounted.get(invoice.getC_Invoice_ID());
|
||||
if (invAccounted == null)
|
||||
invAccounted = Env.ZERO;
|
||||
BigDecimal matchInvSource = htMatchInvSource.get(invoice.getC_Invoice_ID());
|
||||
if (matchInvSource == null)
|
||||
matchInvSource = Env.ZERO;
|
||||
BigDecimal matchInvAccounted = htMatchInvAccounted.get(invoice.getC_Invoice_ID());
|
||||
if (matchInvAccounted == null)
|
||||
matchInvAccounted = Env.ZERO;
|
||||
BigDecimal acctDifference = htMatchInvAcctDiff.get(invoice.getC_Invoice_ID());
|
||||
|
||||
StringBuilder description = new StringBuilder("Invoice=(").append(getC_Currency_ID()).append(")").append(invSource).append("/").append(invAccounted)
|
||||
.append(" - Match Invoice=(").append(getC_Currency_ID()).append(")").append(matchInvSource).append("/").append(matchInvAccounted);
|
||||
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
|
||||
if (acctDifference == null && matchInvSource.abs().compareTo(invSource.abs()) == 0)
|
||||
{
|
||||
acctDifference = invAccounted.abs().subtract(matchInvAccounted.abs()); // gain is negative
|
||||
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
|
||||
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
|
||||
description.append(" - ").append(d2);
|
||||
}
|
||||
|
||||
if (acctDifference == null || acctDifference.signum() == 0)
|
||||
{
|
||||
log.fine("No Difference");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (acctDifference.abs().compareTo(TOLERANCE) > 0)
|
||||
{
|
||||
log.fine("acctDifference="+acctDifference);
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
if (invoice.isSOTrx())
|
||||
{
|
||||
FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference);
|
||||
fl.setDescription(description.toString());
|
||||
updateFactLine(fl);
|
||||
|
||||
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID())
|
||||
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(), as.getC_Currency_ID(), acctDifference.negate());
|
||||
else
|
||||
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference.negate());
|
||||
fl.setDescription(description.toString());
|
||||
updateFactLine(fl);
|
||||
}
|
||||
else
|
||||
{
|
||||
FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference.negate());
|
||||
fl.setDescription(description.toString());
|
||||
updateFactLine(fl);
|
||||
|
||||
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID())
|
||||
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(), as.getC_Currency_ID(), acctDifference);
|
||||
else
|
||||
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference);
|
||||
fl.setDescription(description.toString());
|
||||
updateFactLine(fl);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String createReceiptGainLoss(MAcctSchema as, Fact fact, MAccount acct,
|
||||
MInOut receipt, BigDecimal matchInvSource, BigDecimal matchInvAccounted)
|
||||
{
|
||||
|
|
|
@ -339,4 +339,185 @@ public class MatchInvTest extends AbstractTestCase {
|
|||
|
||||
rollback();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the matched invoice posting for credit memo
|
||||
* PO Qty=10 > IV Qty=10 > MR Qty=9 > CM Qty=1
|
||||
*/
|
||||
public void testCreditMemoPosting() {
|
||||
MBPartner bpartner = MBPartner.get(Env.getCtx(), 114); // Tree Farm Inc.
|
||||
MProduct product = MProduct.get(Env.getCtx(), 124); // Elm Tree
|
||||
|
||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||
order.setBPartner(bpartner);
|
||||
order.setIsSOTrx(false);
|
||||
order.setC_DocTypeTarget_ID();
|
||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||
order.setDocAction(DocAction.ACTION_Complete);
|
||||
order.saveEx();
|
||||
|
||||
MOrderLine orderLine = new MOrderLine(order);
|
||||
orderLine.setLine(10);
|
||||
orderLine.setProduct(product);
|
||||
orderLine.setQty(BigDecimal.TEN);
|
||||
orderLine.saveEx();
|
||||
|
||||
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||
order.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||
|
||||
MInvoice invoice = new MInvoice(Env.getCtx(), 0, getTrxName());
|
||||
invoice.setOrder(order);
|
||||
invoice.setDateAcct(order.getDateOrdered());
|
||||
invoice.setSalesRep_ID(order.getSalesRep_ID());
|
||||
invoice.setC_BPartner_ID(order.getBill_BPartner_ID());
|
||||
invoice.setC_BPartner_Location_ID(order.getBill_Location_ID());
|
||||
invoice.setAD_User_ID(order.getBill_User_ID());
|
||||
invoice.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_APInvoice);
|
||||
invoice.setDocStatus(DocAction.STATUS_Drafted);
|
||||
invoice.setDocAction(DocAction.ACTION_Complete);
|
||||
invoice.saveEx();
|
||||
|
||||
MInvoiceLine invoiceLine = new MInvoiceLine(invoice);
|
||||
invoiceLine.setC_OrderLine_ID(orderLine.get_ID());
|
||||
invoiceLine.setLine(10);
|
||||
invoiceLine.setProduct(product);
|
||||
invoiceLine.setQty(BigDecimal.TEN);
|
||||
invoiceLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete);
|
||||
invoice.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus());
|
||||
|
||||
if (!invoice.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), invoice.getAD_Client_ID(), MInvoice.Table_ID, invoice.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
invoice.load(getTrxName());
|
||||
assertTrue(invoice.isPosted());
|
||||
|
||||
MInOut receipt = new MInOut(order, 122, order.getDateOrdered()); // MM Receipt
|
||||
receipt.saveEx();
|
||||
|
||||
MInOutLine receiptLine = new MInOutLine(receipt);
|
||||
receiptLine.setC_OrderLine_ID(orderLine.get_ID());
|
||||
receiptLine.setLine(10);
|
||||
receiptLine.setProduct(product);
|
||||
receiptLine.setQty(new BigDecimal(9));
|
||||
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
|
||||
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
||||
receiptLine.setM_Locator_ID(M_Locator_ID);
|
||||
receiptLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
|
||||
receipt.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
|
||||
|
||||
if (!receipt.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), receipt.getAD_Client_ID(), MInOut.Table_ID, receipt.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
receipt.load(getTrxName());
|
||||
assertTrue(receipt.isPosted());
|
||||
|
||||
int C_AcctSchema_ID = MClientInfo.get(Env.getCtx()).getC_AcctSchema1_ID();
|
||||
MAcctSchema as = MAcctSchema.get(Env.getCtx(), C_AcctSchema_ID);
|
||||
MMatchInv[] miList = MMatchInv.getInvoiceLine(Env.getCtx(), invoiceLine.get_ID(), getTrxName());
|
||||
for (MMatchInv mi : miList) {
|
||||
if (!mi.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), mi.getAD_Client_ID(), MMatchInv.Table_ID, mi.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
mi.load(getTrxName());
|
||||
assertTrue(mi.isPosted());
|
||||
|
||||
Doc doc = DocManager.getDocument(as, MMatchInv.Table_ID, mi.get_ID(), getTrxName());
|
||||
doc.setC_BPartner_ID(mi.getC_InvoiceLine().getC_Invoice().getC_BPartner_ID());
|
||||
MAccount acctNIR = doc.getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as);
|
||||
|
||||
ProductCost pc = new ProductCost (Env.getCtx(), mi.getM_Product_ID(), mi.getM_AttributeSetInstance_ID(), getTrxName());
|
||||
MAccount acctInvClr = pc.getAccount(ProductCost.ACCTTYPE_P_InventoryClearing, as);
|
||||
|
||||
String whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MMatchInv.Table_ID
|
||||
+ " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + mi.get_ID()
|
||||
+ " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + C_AcctSchema_ID;
|
||||
int[] ids = MFactAcct.getAllIDs(MFactAcct.Table_Name, whereClause, getTrxName());
|
||||
for (int id : ids) {
|
||||
MFactAcct fa = new MFactAcct(Env.getCtx(), id, getTrxName());
|
||||
if (fa.getAccount_ID() == acctNIR.getAccount_ID())
|
||||
assertTrue(fa.getAmtAcctDr().compareTo(Env.ZERO) >= 0);
|
||||
else if (fa.getAccount_ID() == acctInvClr.getAccount_ID())
|
||||
assertTrue(fa.getAmtAcctCr().compareTo(Env.ZERO) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
MInvoice creditMemo = new MInvoice(Env.getCtx(), 0, getTrxName());
|
||||
creditMemo.setOrder(order);
|
||||
creditMemo.setDateAcct(order.getDateOrdered());
|
||||
creditMemo.setSalesRep_ID(order.getSalesRep_ID());
|
||||
creditMemo.setC_BPartner_ID(order.getBill_BPartner_ID());
|
||||
creditMemo.setC_BPartner_Location_ID(order.getBill_Location_ID());
|
||||
creditMemo.setAD_User_ID(order.getBill_User_ID());
|
||||
creditMemo.setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_APCreditMemo);
|
||||
creditMemo.setDocStatus(DocAction.STATUS_Drafted);
|
||||
creditMemo.setDocAction(DocAction.ACTION_Complete);
|
||||
creditMemo.saveEx();
|
||||
|
||||
MInvoiceLine creditMemoLine = new MInvoiceLine(creditMemo);
|
||||
creditMemoLine.setC_OrderLine_ID(orderLine.get_ID());
|
||||
creditMemoLine.setLine(10);
|
||||
creditMemoLine.setProduct(product);
|
||||
creditMemoLine.setQty(BigDecimal.ONE);
|
||||
creditMemoLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(creditMemo, DocAction.ACTION_Complete);
|
||||
creditMemo.load(getTrxName());
|
||||
assertFalse(info.isError());
|
||||
assertEquals(DocAction.STATUS_Completed, creditMemo.getDocStatus());
|
||||
|
||||
if (!creditMemo.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), creditMemo.getAD_Client_ID(), MInvoice.Table_ID, creditMemo.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
creditMemo.load(getTrxName());
|
||||
assertTrue(creditMemo.isPosted());
|
||||
|
||||
miList = MMatchInv.getInvoiceLine(Env.getCtx(), creditMemoLine.get_ID(), getTrxName());
|
||||
for (MMatchInv mi : miList) {
|
||||
if (!mi.isPosted()) {
|
||||
String error = DocumentEngine.postImmediate(Env.getCtx(), mi.getAD_Client_ID(), MMatchInv.Table_ID, mi.get_ID(), false, getTrxName());
|
||||
assertTrue(error == null);
|
||||
}
|
||||
mi.load(getTrxName());
|
||||
assertTrue(mi.isPosted());
|
||||
|
||||
ProductCost pc = new ProductCost (Env.getCtx(), mi.getM_Product_ID(), mi.getM_AttributeSetInstance_ID(), getTrxName());
|
||||
MAccount acctInvClr = pc.getAccount(ProductCost.ACCTTYPE_P_InventoryClearing, as);
|
||||
|
||||
BigDecimal amtAcctDrInvClr = BigDecimal.ZERO;
|
||||
BigDecimal amtAcctCrInvClr = BigDecimal.ZERO;
|
||||
String whereClause = MFactAcct.COLUMNNAME_AD_Table_ID + "=" + MMatchInv.Table_ID
|
||||
+ " AND " + MFactAcct.COLUMNNAME_Record_ID + "=" + mi.get_ID()
|
||||
+ " AND " + MFactAcct.COLUMNNAME_C_AcctSchema_ID + "=" + C_AcctSchema_ID;
|
||||
int[] ids = MFactAcct.getAllIDs(MFactAcct.Table_Name, whereClause, getTrxName());
|
||||
for (int id : ids) {
|
||||
MFactAcct fa = new MFactAcct(Env.getCtx(), id, getTrxName());
|
||||
if (fa.getAccount_ID() == acctInvClr.getAccount_ID() && fa.getQty().compareTo(BigDecimal.ZERO) < 0) {
|
||||
assertTrue(fa.getAmtAcctCr().compareTo(Env.ZERO) >= 0);
|
||||
amtAcctCrInvClr = amtAcctCrInvClr.add(fa.getAmtAcctCr());
|
||||
}
|
||||
else if (fa.getAccount_ID() == acctInvClr.getAccount_ID() && fa.getQty().compareTo(BigDecimal.ZERO) > 0) {
|
||||
assertTrue(fa.getAmtAcctDr().compareTo(Env.ZERO) >= 0);
|
||||
amtAcctDrInvClr = amtAcctDrInvClr.add(fa.getAmtAcctDr());
|
||||
}
|
||||
}
|
||||
assertTrue(amtAcctDrInvClr.compareTo(amtAcctCrInvClr) == 0);
|
||||
}
|
||||
|
||||
rollback();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue