From c8d858836f80bfd5fd5bd8b075ef9f4f1a5162d7 Mon Sep 17 00:00:00 2001 From: hengsin Date: Mon, 2 Mar 2020 13:08:19 +0800 Subject: [PATCH] IDEMPIERE-4127 GL Inventory Clearing - Minor rounding variances --- .../org/compiere/acct/Doc_AllocationHdr.java | 486 +++++++++++------- .../src/org/compiere/acct/Doc_MatchInv.java | 117 +++-- .../src/org/compiere/model/MInOut.java | 6 +- 3 files changed, 383 insertions(+), 226 deletions(-) diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java b/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java index a0d7c79943..999d6be5c9 100644 --- a/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java +++ b/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java @@ -21,6 +21,7 @@ import java.math.RoundingMode; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; +import java.util.Hashtable; import java.util.List; import java.util.logging.Level; @@ -75,8 +76,8 @@ public class Doc_AllocationHdr extends Doc private static final BigDecimal TOLERANCE = BigDecimal.valueOf(0.02); /** Facts */ private ArrayList m_facts = null; - BigDecimal gainLossAmt =Env.ZERO; - private BigDecimal cmGainLossAmt=Env.ZERO; + private Hashtable htGainLossAmtByInv = new Hashtable(); + private Hashtable htGainLossAmtByCM = new Hashtable(); private ArrayList gainLossFactList; @@ -741,18 +742,32 @@ public class Doc_AllocationHdr extends Doc .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 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 (invoice.isSOTrx()) { - invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr - invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr - } else { - invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr - invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr + if (invoice.getReversal_ID() == 0 || invoice.get_ID() < invoice.getReversal_ID()) + { + if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) { + invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr + invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr + } 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()); } // Full Payment in currency - if (allocationSource.compareTo(invoiceSource) == 0) + if (allocationSource.abs().compareTo(invoiceSource.abs()) == 0) { 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 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) cmGainLossAmt = cmGainLossAmt.add(acctDifference); else 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); fl.setDescription(description.toString()); @@ -1049,112 +1072,164 @@ public class Doc_AllocationHdr extends Doc * @param payment payment * @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; ResultSet rs = null; // Invoice AR/AP - BigDecimal totalInvoiceSource = BigDecimal.ZERO; - BigDecimal totalInvoiceAccounted = BigDecimal.ZERO; - boolean isCMReversal =false ; - MInvoice invoice = null; - MPayment payment = null; ArrayList invList = new ArrayList(); + ArrayList payList = new ArrayList(); + Hashtable htInvAllocLine = new Hashtable(); for (int i = 0; i < p_lines.length; i++) { + MInvoice invoice = null; + MPayment payment = null; DocLine_Allocation line = (DocLine_Allocation)p_lines[i]; 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; - // to cater for invoice reverse-accrual. - if (invoice.isSOTrx() && !invoice.isCreditMemo()) - isDebit = true; - else if (!invoice.isSOTrx() && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) - isDebit = true; - else if (invoice.isSOTrx() && invoice.isCreditMemo() && invoice.getReversal_ID() == 0) - 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()) - { - 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; - } + invoice = new MInvoice (getCtx(), line.getC_Invoice_ID(), getTrxName()); + if (!invList.contains(invoice)) + invList.add(invoice); + htInvAllocLine.put(invoice.getC_Invoice_ID(), line.get_ID()); + } + if (line.getC_Payment_ID() != 0) + { + payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName()); + if (!payList.contains(payment)) + payList.add(payment); } } - BigDecimal allocInvoiceSource = BigDecimal.ZERO; - BigDecimal allocInvoiceAccounted = BigDecimal.ZERO; - MAllocationLine allocationLine = null; - FactLine[] factlines = fact.getLines(); - boolean isExcludeCMGainLoss = false; - for (FactLine factLine : factlines) { - if (bpAcct != null) { - if (factLine.getAccount_ID() == bpAcct.getAccount_ID() ) + + Hashtable htInvSource = new Hashtable(); + Hashtable htInvAccounted = new Hashtable(); + for (MInvoice invoice : invList) + { + boolean isDebit = false; + // to cater for invoice reverse-accrual. + 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 htAllocInvSource = new Hashtable(); + Hashtable htAllocInvAccounted = new Hashtable(); + Hashtable htIsExcludeCMGainLoss = new Hashtable(); + Hashtable htIsCMReversal = new Hashtable(); + 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()); + MInvoice invoice = null; + MPayment payment = null; if (allocationLine != null) + { 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 (factLine.getC_Currency_ID() != as.getC_Currency_ID()) - allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceCr()); + if (factLine.getC_Currency_ID() != as.getC_Currency_ID()) + { + if (!invoice.isCreditMemo()) + allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceCr()); + else + allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); + } if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo()) 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()); if (!invoice.getDateAcct().equals(getDateAcct())) - isCMReversal =true; + isCMReversal = true; } if (invoice!=null) { - if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) { + if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) + { allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs()); cmGainLossAmt = Env.ZERO; } - if (gainLossFactList.contains(factLine)) { + if (gainLossFactList.contains(factLine)) + { isExcludeCMGainLoss = true; } } @@ -1164,8 +1239,8 @@ public class Doc_AllocationHdr extends Doc allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); } - - } else + } + else { if (as.getC_Currency_ID() != factLine.getC_Currency_ID()) allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); @@ -1173,58 +1248,100 @@ public class Doc_AllocationHdr extends Doc 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.getAmtAcctCr()); // this is to cater for reverse-accrual. 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()); cmGainLossAmt = Env.ZERO; } - if (gainLossFactList.contains(factLine)) { + if (gainLossFactList.contains(factLine)) + { 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); } } } - - - 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) + + for (MInvoice invoice : invList) { - if (isExcludeCMGainLoss) - allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt); - if (payment != null && payment.getReversal_ID() > 0 ) - allocInvoiceAccounted = allocInvoiceAccounted.subtract(gainLossAmt); - else - allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt); - if (isCMReversal) - acctDifference = totalInvoiceAccounted.subtract(allocInvoiceAccounted.abs()); - else - acctDifference = allocInvoiceAccounted.subtract(totalInvoiceAccounted.abs()); // gain is positive for receipt + BigDecimal invoiceSource = htInvSource.get(invoice.getC_Invoice_ID()); + if (invoiceSource == null) + invoiceSource = Env.ZERO; + BigDecimal invoiceAccounted = htInvAccounted.get(invoice.getC_Invoice_ID()); + if (invoiceAccounted == null) + invoiceAccounted = Env.ZERO; + BigDecimal allocInvoiceSource = htAllocInvSource.get(invoice.getC_Invoice_ID()); + if (allocInvoiceSource == null) + allocInvoiceSource = Env.ZERO; + 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); - 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) + 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(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() ? "SUM(AmtSourceCr), SUM(AmtAcctCr), SUM(AmtAcctDr)" // so : "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(" AND C_AcctSchema_ID=?") .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; rs = null; try @@ -1242,15 +1360,17 @@ public class Doc_AllocationHdr extends Doc pstmt.setInt(2, alloc.get_ID()); pstmt.setInt(3, as.getC_AcctSchema_ID()); pstmt.setInt(4, bpAcct.getAccount_ID()); + pstmt.setInt(5, alloc.get_ID()); + pstmt.setInt(6, invoice.getC_Invoice_ID()); rs = pstmt.executeQuery(); if (rs.next()) { BigDecimal allocateSource = rs.getBigDecimal(1); BigDecimal allocateAccounted = rs.getBigDecimal(2); BigDecimal allocateCredit = rs.getBigDecimal(3); - allocInvoiceSource =allocInvoiceSource.add(allocateSource != null ? allocateSource: BigDecimal.ZERO); - allocInvoiceAccounted =allocInvoiceAccounted.add(allocateAccounted != null ? allocateAccounted : BigDecimal.ZERO); - allocInvoiceAccounted= allocInvoiceAccounted.subtract(allocateCredit != null ? allocateCredit : BigDecimal.ZERO); + allocInvoiceSource = allocInvoiceSource.add(allocateSource != null ? allocateSource: BigDecimal.ZERO); + allocInvoiceAccounted = allocInvoiceAccounted.add(allocateAccounted != null ? allocateAccounted : 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); } - finally { + finally + { DB.close(rs, pstmt); 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 - 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()) + + if (acctDifference.signum() == 0) { - 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) fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference); else fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference); fl.setDescription(description.toString()); + fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); 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()); - } else + 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()); - } } - }else + fl.setDescription(description.toString()); + fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); + } + else { FactLine fl = null; if (!isBPartnerAdjust) fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate()); else fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference.negate()); - fl.setDescription(description.toString()); + fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); + 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); - } else { - fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference); + 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()); + fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); } } + } return null; } // createInvoiceRounding diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_MatchInv.java b/org.adempiere.base/src/org/compiere/acct/Doc_MatchInv.java index bb1354956f..4ac78b8885 100644 --- a/org.adempiere.base/src/org/compiere/acct/Doc_MatchInv.java +++ b/org.adempiere.base/src/org/compiere/acct/Doc_MatchInv.java @@ -763,6 +763,21 @@ public class Doc_MatchInv extends Doc 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) { cr.setC_Activity_ID(m_invoiceLine.getC_Activity_ID()); @@ -880,7 +895,7 @@ public class Doc_MatchInv extends Doc 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 " + "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) totalAmtAcctCr = Env.ZERO; - if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) + if (m_matchInv.getReversal_ID() == 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); + 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 { @@ -955,13 +983,13 @@ public class Doc_MatchInv extends Doc { matchInvSource = matchInvSource.add(totalAmtSourceDr); matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr); - acctDifference = totalAmtAcctCr.negate(); + acctDifference = totalAmtAcctCr; } else { matchInvSource = matchInvSource.add(totalAmtSourceCr); 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) 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 " + "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) totalAmtAcctCr = Env.ZERO; - if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) + if (m_matchInv.getReversal_ID() == 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 (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID()) + if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) { - 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); - } + 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 { - 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.negate(); - } + 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.negate();; + } + else + { + matchInvSource = matchInvSource.add(totalAmtSourceCr); + matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr); + acctDifference = totalAmtAcctDr; } } } diff --git a/org.adempiere.base/src/org/compiere/model/MInOut.java b/org.adempiere.base/src/org/compiere/model/MInOut.java index cb76ded2c3..6b97cc497f 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOut.java +++ b/org.adempiere.base/src/org/compiere/model/MInOut.java @@ -1616,10 +1616,10 @@ public class MInOut extends X_M_InOut implements DocAction } if (!po.isPosted()) 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); - } } // Update PO with ASI if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0