From 132cc4036c3031671182a8b16aef811b71760264 Mon Sep 17 00:00:00 2001 From: hengsin Date: Wed, 25 Mar 2020 10:33:49 +0800 Subject: [PATCH] IDEMPIERE-4200 AR Payment Allocation: Incorrect Currency Balancing Postings --- .../org/compiere/acct/Doc_AllocationHdr.java | 1342 ++++++++++------- 1 file changed, 765 insertions(+), 577 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 077146c359..9b656af07c 100644 --- a/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java +++ b/org.adempiere.base/src/org/compiere/acct/Doc_AllocationHdr.java @@ -37,7 +37,6 @@ import org.compiere.model.MInvoice; import org.compiere.model.MInvoiceLine; import org.compiere.model.MOrder; import org.compiere.model.MPayment; -import org.compiere.model.MPeriod; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; @@ -76,10 +75,9 @@ public class Doc_AllocationHdr extends Doc private static final BigDecimal TOLERANCE = BigDecimal.valueOf(0.02); /** Facts */ private ArrayList m_facts = null; - private Hashtable htGainLossAmtByInv = new Hashtable(); - private Hashtable htGainLossAmtByCM = new Hashtable(); - private ArrayList gainLossFactList; - + + private ArrayList invGainLossFactLines = null; + private ArrayList payGainLossFactLines = null; /** * Load Specific Document Details @@ -173,17 +171,14 @@ public class Doc_AllocationHdr extends Doc public ArrayList createFacts (MAcctSchema as) { m_facts = new ArrayList(); + invGainLossFactLines = new ArrayList(); + payGainLossFactLines = new ArrayList(); // create Fact Header Fact fact = new Fact(this, as, Fact.POST_Actual); Fact factForRGL = new Fact(this, as, Fact.POST_Actual); // dummy fact (not posted) to calculate Realized Gain & Loss boolean isInterOrg = isInterOrg(as); - BigDecimal paymentSelectAmt = Env.ZERO; - BigDecimal totalAllocationSource = Env.ZERO; - MPayment payment = null; - int lineID = 0; MAccount bpAcct = null; // Liability/Receivables - gainLossFactList = new ArrayList(); for (int i = 0; i < p_lines.length; i++) { @@ -210,11 +205,15 @@ public class Doc_AllocationHdr extends Doc FactLine fl = null; FactLine flForRGL = null; // + MPayment payment = null; if (line.getC_Payment_ID() != 0) payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName()); MInvoice invoice = null; if (line.getC_Invoice_ID() != 0) invoice = new MInvoice (getCtx(), line.getC_Invoice_ID(), getTrxName()); + + BigDecimal allocPayAccounted = Env.ZERO; + BigDecimal allocPaySource = Env.ZERO; // No Invoice if (invoice == null) @@ -233,6 +232,7 @@ public class Doc_AllocationHdr extends Doc getC_Currency_ID(), line.getAmtSource(), null); if (fl != null && payment != null) fl.setAD_Org_ID(payment.getAD_Org_ID()); + allocPayAccounted = allocPayAccounted.add(fl.getAcctBalance()); } else { @@ -275,9 +275,9 @@ public class Doc_AllocationHdr extends Doc if (fl != null && payment != null) fl.setAD_Org_ID(payment.getAD_Org_ID()); if (payment.getReversal_ID() > 0 ) - paymentSelectAmt= paymentSelectAmt.add(fl.getAcctBalance().negate()); + allocPayAccounted = allocPayAccounted.add(fl.getAcctBalance().negate()); else - paymentSelectAmt= paymentSelectAmt.add(fl.getAcctBalance()); + allocPayAccounted = allocPayAccounted.add(fl.getAcctBalance()); } else if (line.getC_CashLine_ID() != 0) { @@ -408,7 +408,7 @@ public class Doc_AllocationHdr extends Doc getC_Currency_ID(), null, line.getAmtSource().negate()); if (fl != null && payment != null) fl.setAD_Org_ID(payment.getAD_Org_ID()); - paymentSelectAmt= paymentSelectAmt.add(fl.getAcctBalance().negate()); + allocPayAccounted = allocPayAccounted.add(fl.getAcctBalance().negate()); } else if (isUsingClearing && line.getC_CashLine_ID() != 0) // Avoid usage of clearing accounts { @@ -446,29 +446,31 @@ public class Doc_AllocationHdr extends Doc && (getC_Currency_ID() != as.getC_Currency_ID() // payment allocation in foreign currency || getC_Currency_ID() != line.getInvoiceC_Currency_ID())) // allocation <> invoice currency { - p_Error = createRealizedGainLoss (line, as, fact, bpAcct, invoice, + p_Error = createInvoiceGainLoss (line, as, fact, bpAcct, invoice, allocationSource, allocationAccounted); if (p_Error != null) return null; - } - totalAllocationSource = totalAllocationSource.add(line.getAmtSource()); - lineID = line.get_ID(); + } + + allocPaySource = allocPaySource.add(line.getAmtSource()); + if (payment != null && getC_Currency_ID() != as.getC_Currency_ID()) + { + p_Error = createPaymentGainLoss (line, as, fact, getPaymentAcct(as, payment.get_ID()), payment, + allocPaySource, allocPayAccounted); + if (p_Error != null) + return null; + } } // for all lines - - // rounding correction - if (payment != null && getC_Currency_ID() != as.getC_Currency_ID() ) // payment allocation in foreign currency - { - p_Error = createPaymentGainLoss (as, fact, getPaymentAcct(as, payment.get_ID()), payment, - totalAllocationSource, paymentSelectAmt, lineID); - if (p_Error != null) - return null; - } + // rounding adjustment if (getC_Currency_ID() != as.getC_Currency_ID()) { - p_Error = createInvoiceRounding (as, fact, bpAcct); + p_Error = createInvoiceRoundingCorrection (as, fact, bpAcct); if (p_Error != null) return null; + p_Error = createPaymentRoundingCorrection (as, fact); + if (p_Error != null) + return null; } // FR [ 1840016 ] Avoid usage of clearing accounts - subject to C_AcctSchema.IsPostIfClearingEqual @@ -730,145 +732,12 @@ public class Doc_AllocationHdr extends Doc * @param allocationSource source amt * @param allocationAccounted acct amt * @return Error Message or null if OK + * */ private String createRealizedGainLoss (DocLine line, MAcctSchema as, Fact fact, MAccount acct, MInvoice invoice, BigDecimal allocationSource, BigDecimal allocationAccounted) { - BigDecimal invoiceSource = null; - BigDecimal invoiceAccounted = null; - // - 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 valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), - MInvoice.Table_ID, invoice.getC_Invoice_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID()); - if (valuesInv != null) { - 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 - } - } - } - - // Requires that Invoice is Posted - if (invoiceSource == null || invoiceAccounted == null) - return "Gain/Loss - Invoice not posted yet"; - // - StringBuilder description = new StringBuilder("Invoice=(").append(invoice.getC_Currency_ID()).append(")").append(invoiceSource).append("/").append(invoiceAccounted) - .append(" - Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource).append("/").append(allocationAccounted); - if (log.isLoggable(Level.FINE)) log.fine(description.toString()); - // Allocation not Invoice Currency - if (getC_Currency_ID() != invoice.getC_Currency_ID()) - { - BigDecimal allocationSourceNew = MConversionRate.convert(getCtx(), - allocationSource, getC_Currency_ID(), - invoice.getC_Currency_ID(), getDateAcct(), - invoice.getC_ConversionType_ID(), invoice.getAD_Client_ID(), invoice.getAD_Org_ID()); - if (allocationSourceNew == null) - return "Gain/Loss - No Conversion from Allocation->Invoice"; - StringBuilder d2 = new StringBuilder("Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource) - .append("->(").append(invoice.getC_Currency_ID()).append(")").append(allocationSourceNew); - if (log.isLoggable(Level.FINE)) log.fine(d2.toString()); - description.append(" - ").append(d2); - allocationSource = allocationSourceNew; - } - - BigDecimal acctDifference = null; // gain is negative - //reversal entry - if (allocationSource.signum() > 0 ) - { - acctDifference = invoiceAccounted.subtract(allocationAccounted.abs()); - } - // Full Payment in currency - if (allocationSource.abs().compareTo(invoiceSource.abs()) == 0) - { - acctDifference = invoiceAccounted.subtract(allocationAccounted.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 - { - // percent of total payment - double multiplier = allocationSource.doubleValue() / invoiceSource.doubleValue(); - // Reduce Orig Invoice Accounted - invoiceAccounted = invoiceAccounted.multiply(BigDecimal.valueOf(multiplier)); - // Difference based on percentage of Orig Invoice - acctDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative - // 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).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()); - 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() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) - { - FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference); - fl.setDescription(description.toString()); - fl = fact.createLine (line, acct, as.getC_Currency_ID(), acctDifference.negate()); - gainLossFactList.add(fl); - } - else - { - FactLine fl = fact.createLine (line, acct, - as.getC_Currency_ID(), acctDifference); - gainLossFactList.add(fl); - fl = fact.createLine (line, loss, gain, - as.getC_Currency_ID(), acctDifference.negate()); - fl.setDescription(description.toString()); - - } - return null; + return createInvoiceGainLoss(line, as, fact, acct, invoice, allocationSource, allocationAccounted); } // createRealizedGainLoss @@ -944,19 +813,139 @@ public class Doc_AllocationHdr extends Doc } // createTaxCorrection /************************************************************************** - * Create Rounding Correction. + * Create Realized Gain & Loss. + * Compares the Accounted Amount of the Invoice to the + * Accounted Amount of the Allocation + * @param line Allocation line + * @param as accounting schema + * @param fact fact + * @param acct account + * @param invoice invoice + * @param allocationSource source amt + * @param allocationAccounted acct amt + * @return Error Message or null if OK + */ + private String createInvoiceGainLoss (DocLine line, MAcctSchema as, Fact fact, MAccount acct, + MInvoice invoice, BigDecimal allocationSource, BigDecimal allocationAccounted) + { + BigDecimal invoiceSource = null; + BigDecimal invoiceAccounted = null; + // + 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 valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), + MInvoice.Table_ID, invoice.getC_Invoice_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID()); + if (valuesInv != null) { + 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 + } + } + } + + // Requires that Invoice is Posted + if (invoiceSource == null || invoiceAccounted == null) + return "Gain/Loss - Invoice not posted yet"; + // + StringBuilder description = new StringBuilder("Invoice=(").append(invoice.getC_Currency_ID()).append(")").append(invoiceSource).append("/").append(invoiceAccounted) + .append(" - Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource).append("/").append(allocationAccounted); + if (log.isLoggable(Level.FINE)) log.fine(description.toString()); + + BigDecimal acctDifference = null; // gain is negative + // Full Payment in currency + if (allocationSource.abs().compareTo(invoiceSource.abs()) == 0) + { + acctDifference = invoiceAccounted.abs().subtract(allocationAccounted.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 allocationAccounted0 = MConversionRate.convert(getCtx(), + allocationSource, getC_Currency_ID(), + as.getC_Currency_ID(), invoice.getDateAcct(), + invoice.getC_ConversionType_ID(), invoice.getAD_Client_ID(), invoice.getAD_Org_ID()); + acctDifference = allocationAccounted0.abs().subtract(allocationAccounted.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.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 ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) + { + FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference); + fl.setDescription(description.toString()); + invGainLossFactLines.add(fl); + fl = fact.createLine (line, acct, as.getC_Currency_ID(), acctDifference.negate()); + fl.setDescription(description.toString()); + } + else + { + FactLine fl = fact.createLine (line, acct, as.getC_Currency_ID(), acctDifference); + fl.setDescription(description.toString()); + fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference.negate()); + fl.setDescription(description.toString()); + invGainLossFactLines.add(fl); + } + return null; + } + + /************************************************************************** + * Create Realized Gain & Loss. * Compares the Accounted Amount of the Payment to the * Accounted Amount of the Allocation + * @param line Allocation line * @param as accounting schema * @param fact fact * @param acct account * @param payment payment - * @param paymentSource source amt - * @param paymentAccounted acct amt + * @param allocationSource source amt + * @param allocationAccounted acct amt * @return Error Message or null if OK */ - private String createPaymentGainLoss (MAcctSchema as, Fact fact, MAccount acct, - MPayment payment, BigDecimal allocationSource, BigDecimal totalAllocationAccounted, int lineID) + private String createPaymentGainLoss (DocLine line, MAcctSchema as, Fact fact, MAccount acct, + MPayment payment, BigDecimal allocationSource, BigDecimal allocationAccounted) { BigDecimal paymentSource = null; BigDecimal paymentAccounted = null; @@ -986,43 +975,25 @@ public class Doc_AllocationHdr extends Doc return null; //"Gain/Loss - Payment not posted yet"; // StringBuilder description = new StringBuilder("Payment=(").append(payment.getC_Currency_ID()).append(")").append(paymentSource).append("/").append(paymentAccounted) - .append(" - Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource).append("/").append(totalAllocationAccounted); + .append(" - Allocation=(").append(getC_Currency_ID()).append(")").append(allocationSource).append("/").append(allocationAccounted); if (log.isLoggable(Level.FINE)) log.fine(description.toString()); - boolean isSameSourceDiffPeriod = false; BigDecimal acctDifference = null; // gain is negative // Full Payment in currency if (allocationSource.abs().compareTo(paymentSource.abs()) == 0) { - acctDifference = totalAllocationAccounted.abs().subtract(paymentAccounted.abs()); // gain is negative + acctDifference = allocationAccounted.abs().subtract(paymentAccounted.abs()); // gain is negative StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference); if (log.isLoggable(Level.FINE)) log.fine(d2.toString()); description.append(" - ").append(d2); - - // Different period - if (MPeriod.getC_Period_ID(getCtx(), payment.getDateAcct(), payment.getAD_Org_ID()) != - MPeriod.getC_Period_ID(getCtx(), getDateAcct(), getAD_Org_ID())) - { - BigDecimal allocationAccounted0 = MConversionRate.convert(getCtx(), - allocationSource, getC_Currency_ID(), - as.getC_Currency_ID(), payment.getDateAcct(), - payment.getC_ConversionType_ID(), payment.getAD_Client_ID(), payment.getAD_Org_ID()); - BigDecimal paymentAccounted0 = MConversionRate.convert(getCtx(), - paymentSource, getC_Currency_ID(), - as.getC_Currency_ID(), getDateAcct(), - getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID()); - isSameSourceDiffPeriod = allocationAccounted0.abs().compareTo(paymentAccounted.abs()) == 0 && - paymentAccounted0.abs().compareTo(totalAllocationAccounted.abs()) == 0; - } } else { - // percent of total payment - double multiplier = allocationSource.doubleValue() / paymentSource.doubleValue(); - // Reduce Orig Payment Accounted - paymentAccounted = paymentAccounted.multiply(BigDecimal.valueOf(multiplier)); - // Difference based on percentage of Orig Payment - acctDifference = totalAllocationAccounted.abs().subtract(paymentAccounted.abs()); // gain is negative + BigDecimal allocationAccounted0 = MConversionRate.convert(getCtx(), + allocationSource, getC_Currency_ID(), + as.getC_Currency_ID(), payment.getDateAcct(), + payment.getC_ConversionType_ID(), payment.getAD_Client_ID(), payment.getAD_Org_ID()); + acctDifference = allocationAccounted.abs().subtract(allocationAccounted0.abs()); // ignore Tolerance if (acctDifference.abs().compareTo(TOLERANCE) < 0) acctDifference = Env.ZERO; @@ -1030,30 +1001,9 @@ public class Doc_AllocationHdr extends Doc 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); + StringBuilder d2 = new StringBuilder("(partial) = ").append(acctDifference); if (log.isLoggable(Level.FINE)) log.fine(d2.toString()); description.append(" - ").append(d2); - - // Different period - if (MPeriod.getC_Period_ID(getCtx(), payment.getDateAcct(), payment.getAD_Org_ID()) != - MPeriod.getC_Period_ID(getCtx(), getDateAcct(), getAD_Org_ID())) - { - if (paymentAccounted.scale() > precision) - paymentAccounted = paymentAccounted.setScale(precision, RoundingMode.HALF_UP); - paymentSource = paymentSource.multiply(BigDecimal.valueOf(multiplier)); - if (paymentSource.scale() > precision) - paymentSource = paymentSource.setScale(precision, RoundingMode.HALF_UP); - BigDecimal allocationAccounted0 = MConversionRate.convert(getCtx(), - allocationSource, getC_Currency_ID(), - as.getC_Currency_ID(), payment.getDateAcct(), - payment.getC_ConversionType_ID(), payment.getAD_Client_ID(), payment.getAD_Org_ID()); - BigDecimal paymentAccounted0 = MConversionRate.convert(getCtx(), - paymentSource, getC_Currency_ID(), - as.getC_Currency_ID(), getDateAcct(), - getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID()); - isSameSourceDiffPeriod = allocationAccounted0.abs().compareTo(paymentAccounted.abs()) == 0 && - paymentAccounted0.abs().compareTo(totalAllocationAccounted.abs()) == 0; - } } if (acctDifference == null || acctDifference.signum() == 0) @@ -1065,38 +1015,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()); // - if (payment.isReceipt()) + if ((payment.isReceipt() && payment.getPayAmt().signum() >= 0) || (!payment.isReceipt() && payment.getPayAmt().signum() < 0)) { - FactLine fl = fact.createLine (null, acct,as.getC_Currency_ID(), acctDifference.negate()); + FactLine fl = fact.createLine (line, acct, as.getC_Currency_ID(), acctDifference.negate()); fl.setDescription(description.toString()); - fl.setLine_ID(lineID); - if (!fact.isAcctBalanced()) - { - if (!isSameSourceDiffPeriod && as.isCurrencyBalancing() && as.getC_Currency_ID() != payment.getC_Currency_ID() ) - { - fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference); - } else - { - fl = fact.createLine (null, loss, gain,as.getC_Currency_ID(), acctDifference); - - } - } + fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference); + fl.setDescription(description.toString()); + payGainLossFactLines.add(fl); } else { - FactLine fl = fact.createLine (null, acct,as.getC_Currency_ID(), acctDifference); + FactLine fl = fact.createLine (line, acct, as.getC_Currency_ID(), acctDifference); fl.setDescription(description.toString()); - fl.setLine_ID(lineID); - if (!fact.isAcctBalanced()) - { - if (!isSameSourceDiffPeriod && as.isCurrencyBalancing() && as.getC_Currency_ID() != payment.getC_Currency_ID() ) - { - fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate()); - } else { - fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference.negate()); - } - } - + fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference.negate()); + fl.setDescription(description.toString()); + payGainLossFactLines.add(fl); } return null; } @@ -1107,22 +1040,16 @@ public class Doc_AllocationHdr extends Doc * Accounted Amount of the AR/AP Allocation * @param as accounting schema * @param fact fact - * @param bpAcct account - * @param payment payment + * @param acct account * @return Error Message or null if OK */ - private String createInvoiceRounding(MAcctSchema as, Fact fact, MAccount bpAcct) + private String createInvoiceRoundingCorrection (MAcctSchema as, Fact fact, MAccount acct) { - PreparedStatement pstmt = null; - ResultSet rs = null; - // Invoice AR/AP 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) { @@ -1131,390 +1058,651 @@ public class Doc_AllocationHdr extends Doc 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); - } } 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 + 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=?") // Invoice + .append("WHERE AD_Table_ID=? AND Record_ID=?") .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()) + .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(), acct.getAccount_ID()); + if (valuesInv != null) { + BigDecimal invoiceSource = null; + BigDecimal invoiceAccounted = null; + if (invoice.getReversal_ID() == 0 || invoice.get_ID() < invoice.getReversal_ID()) { - BigDecimal invoiceSource = rs.getBigDecimal(1); - BigDecimal invoiceAccounted = rs.getBigDecimal(2); - htInvSource.put(invoice.getC_Invoice_ID(), invoiceSource); - htInvAccounted.put(invoice.getC_Invoice_ID(), invoiceAccounted); - } + 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 + } + } + htInvSource.put(invoice.getC_Invoice_ID(), invoiceSource); + htInvAccounted.put(invoice.getC_Invoice_ID(), invoiceAccounted); } - catch (Exception e) + } + + MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct()); + MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct()); + + Hashtable htTotalAmtSourceDr = new Hashtable(); + Hashtable htTotalAmtAcctDr = new Hashtable(); + Hashtable htTotalAmtSourceCr = new Hashtable(); + Hashtable htTotalAmtAcctCr = new Hashtable(); + FactLine[] factlines = fact.getLines(); + for (FactLine factLine : factlines) + { + if (factLine.getLine_ID() > 0) { - throw new RuntimeException(e.getLocalizedMessage(), e); + MAllocationLine allocationLine = new MAllocationLine(getCtx(), factLine.getLine_ID(), getTrxName()); + if (allocationLine.getC_Invoice_ID() > 0) + { + if (factLine.getAccount_ID() == acct.getAccount_ID()) + { + BigDecimal totalAmtSourceDr = htTotalAmtSourceDr.get(allocationLine.getC_Invoice_ID()); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + BigDecimal totalAmtAcctDr = htTotalAmtAcctDr.get(allocationLine.getC_Invoice_ID()); + if (totalAmtAcctDr == null) + totalAmtAcctDr = Env.ZERO; + BigDecimal totalAmtSourceCr = htTotalAmtSourceCr.get(allocationLine.getC_Invoice_ID()); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + BigDecimal totalAmtAcctCr = htTotalAmtAcctCr.get(allocationLine.getC_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(allocationLine.getC_Invoice_ID(), totalAmtSourceDr); + htTotalAmtAcctDr.put(allocationLine.getC_Invoice_ID(), totalAmtAcctDr); + htTotalAmtSourceCr.put(allocationLine.getC_Invoice_ID(), totalAmtSourceCr); + htTotalAmtAcctCr.put(allocationLine.getC_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(allocationLine.getC_Invoice_ID()); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + BigDecimal totalAmtSourceCr = htTotalAmtSourceCr.get(allocationLine.getC_Invoice_ID()); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + + totalAmtSourceDr = totalAmtSourceDr.subtract(factLine.getAmtSourceCr()); + totalAmtSourceCr = totalAmtSourceCr.subtract(factLine.getAmtSourceDr()); + + htTotalAmtSourceDr.put(allocationLine.getC_Invoice_ID(), totalAmtSourceDr); + htTotalAmtSourceCr.put(allocationLine.getC_Invoice_ID(), totalAmtSourceCr); + } + } } - 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()); - } + for (MInvoice invoice : invList) + { + BigDecimal allocateSource = Env.ZERO; + BigDecimal allocateAccounted = Env.ZERO; - 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()) + 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) + { + allocateSource = allocateSource.add(totalAmtSourceCr); + allocateAccounted = allocateAccounted.add(totalAmtAcctCr); + } + else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0) + { + allocateSource = allocateSource.add(totalAmtSourceDr); + allocateAccounted = allocateAccounted.add(totalAmtAcctDr); + } + else + { + if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0) + { + allocateSource = allocateSource.add(totalAmtSourceDr); + allocateAccounted = allocateAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr); + } + else + { + allocateSource = allocateSource.add(totalAmtSourceCr); + allocateAccounted = allocateAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr); + } + } + + MAllocationHdr[] allocations = MAllocationHdr.getOfInvoice(getCtx(), invoice.get_ID(), getTrxName()); + for (MAllocationHdr alloc : allocations) + { + if (alloc.get_ID() == get_ID()) + continue; + + BigDecimal currencyAdjustment = 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=?") // allocation + .append(" AND C_AcctSchema_ID=?") + .append(" AND PostingType='A'") + .append(" AND Account_ID=?") + .append(" AND Line_ID IN (SELECT C_AllocationLine_ID FROM C_AllocationLine WHERE C_AllocationHdr_ID=? AND C_Invoice_ID=?)"); + + // For Allocation + List valuesAlloc = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), + MAllocationHdr.Table_ID, alloc.get_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID(), alloc.get_ID(), invoice.getC_Invoice_ID()); + if (valuesAlloc != null) { + totalAmtSourceDr = (BigDecimal) valuesAlloc.get(0); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + totalAmtAcctDr = (BigDecimal) valuesAlloc.get(1); + if (totalAmtAcctDr == null) + totalAmtAcctDr = Env.ZERO; + totalAmtSourceCr = (BigDecimal) valuesAlloc.get(2); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + totalAmtAcctCr = (BigDecimal) valuesAlloc.get(3); + if (totalAmtAcctCr == null) + totalAmtAcctCr = Env.ZERO; + + if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) { - 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) - { - allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); - if (!invoice.getDateAcct().equals(getDateAcct())) - isCMReversal = true; - } - if (invoice!=null) - { - if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) - { - allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs()); - cmGainLossAmt = Env.ZERO; - } - if (gainLossFactList.contains(factLine)) - { - isExcludeCMGainLoss = true; - } - } - - if (payment != null && payment.getReversal_ID() > 0 && !gainLossFactList.contains(factLine)) - { - allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); - allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); - } + allocateSource = allocateSource.add(totalAmtSourceCr); + allocateAccounted = allocateAccounted.add(totalAmtAcctCr); + } + else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0) + { + allocateSource = allocateSource.add(totalAmtSourceDr); + allocateAccounted = allocateAccounted.add(totalAmtAcctDr); } else { - if (as.getC_Currency_ID() != factLine.getC_Currency_ID()) - allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); - - if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo()) - allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); - - if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0) + if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0) { - allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr()); - // this is to cater for reverse-accrual. - if (!invoice.getDateAcct().equals(getDateAcct())) - isCMReversal = true; + allocateSource = allocateSource.add(totalAmtSourceDr); + allocateAccounted = allocateAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr); + currencyAdjustment = currencyAdjustment.add(totalAmtAcctCr); } - - if (invoice != null) + else { - if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0) - { - allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs()); - cmGainLossAmt = Env.ZERO; - } - if (gainLossFactList.contains(factLine)) - { - isExcludeCMGainLoss = true; - } + allocateSource = allocateSource.add(totalAmtSourceCr); + allocateAccounted = allocateAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr); + currencyAdjustment = currencyAdjustment.add(totalAmtAcctDr); } - } - 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); + } + } + + 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=?") // allocation + .append(" AND C_AcctSchema_ID=?") + .append(" AND PostingType='A'") + .append(" AND (Account_ID=? OR Account_ID=? OR Account_ID=?)") + .append(" AND Line_ID IN (SELECT C_AllocationLine_ID FROM C_AllocationLine WHERE C_AllocationHdr_ID=? AND C_Invoice_ID=?)"); + + // For Allocation + valuesAlloc = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), + MAllocationHdr.Table_ID, alloc.get_ID(), as.getC_AcctSchema_ID(), + gain.getAccount_ID(), loss.getAccount_ID(), as.getCurrencyBalancing_Acct().getAccount_ID(), + alloc.get_ID(), invoice.getC_Invoice_ID()); + if (valuesAlloc != null) { + totalAmtSourceDr = (BigDecimal) valuesAlloc.get(0); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + totalAmtAcctDr = (BigDecimal) valuesAlloc.get(1); + if (totalAmtAcctDr == null) + totalAmtAcctDr = Env.ZERO; + totalAmtSourceCr = (BigDecimal) valuesAlloc.get(2); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + totalAmtAcctCr = (BigDecimal) valuesAlloc.get(3); + if (totalAmtAcctCr == null) + totalAmtAcctCr = Env.ZERO; + + allocateSource = allocateSource.subtract(totalAmtSourceDr).subtract(totalAmtSourceCr).add(currencyAdjustment); } } + + htAllocInvSource.put(invoice.getC_Invoice_ID(), allocateSource); + htAllocInvAccounted.put(invoice.getC_Invoice_ID(), allocateAccounted); } for (MInvoice invoice : invList) { - 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; + 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 allocInvSource = htAllocInvSource.get(invoice.getC_Invoice_ID()); + if (allocInvSource == null) + allocInvSource = Env.ZERO; + BigDecimal allocInvAccounted = htAllocInvAccounted.get(invoice.getC_Invoice_ID()); + if (allocInvAccounted == null) + allocInvAccounted = Env.ZERO; - BigDecimal acctDifference = null; // gain is negative - // - StringBuilder description = new StringBuilder("Invoice=(").append(getC_Currency_ID()).append(")").append(allocInvoiceSource).append("/").append(allocInvoiceAccounted); + StringBuilder description = new StringBuilder("Invoice=(").append(getC_Currency_ID()).append(")").append(invSource).append("/").append(invAccounted) + .append(" - Allocation=(").append(getC_Currency_ID()).append(")").append(allocInvSource).append("/").append(allocInvAccounted); if (log.isLoggable(Level.FINE)) log.fine(description.toString()); - boolean isBPartnerAdjust = true; - if (allocInvoiceSource.abs().compareTo(invoiceSource.abs()) == 0) + BigDecimal acctDifference = null; + if (allocInvSource.abs().compareTo(invSource.abs()) == 0) { - 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 - + acctDifference = allocInvAccounted.abs().subtract(invAccounted.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 - { - 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 - .append(" FROM Fact_Acct ") - .append("WHERE AD_Table_ID=? AND Record_ID=?") // allocation - .append(" AND C_AcctSchema_ID=?") - .append(" AND PostingType='A'") - .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 - { - pstmt = DB.prepareStatement(sql.toString(), getTrxName()); - pstmt.setInt(1, MAllocationHdr.Table_ID); - 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); - } - - } - catch (Exception e) - { - throw new RuntimeException(e.getLocalizedMessage(), e); - } - 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); } - - if (acctDifference.signum() == 0) + + if (acctDifference == null || 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) + Integer C_AllocationLine_ID = htInvAllocLine.get(invoice.getC_Invoice_ID()); + if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) { - Integer C_AllocationLine_ID = htInvAllocLine.get(invoice.getC_Invoice_ID()); - if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) + FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference); + fl.setDescription(description.toString()); + fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); + if (!fact.isAcctBalanced()) { - 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); + 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()); 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()) - { - 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()); - fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); - } - else + } + } + else + { + FactLine fl = fact.createLine (null, acct, as.getC_Currency_ID(), acctDifference.negate()); + fl.setDescription(description.toString()); + fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); + if (!fact.isAcctBalanced()) { - FactLine fl = null; - if (!isBPartnerAdjust) - fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate()); + 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, 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()) - { - 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 = 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 - + + /************************************************************************** + * Create Rounding Correction. + * Compares the Accounted Amount of the Payment to the + * Accounted Amount of the Allocation + * @param as accounting schema + * @param fact fact + * @return Error Message or null if OK + */ + private String createPaymentRoundingCorrection (MAcctSchema as, Fact fact) + { + ArrayList payList = new ArrayList(); + Hashtable htPayAllocLine = new Hashtable(); + for (int i = 0; i < p_lines.length; i++) + { + MPayment payment = null; + DocLine_Allocation line = (DocLine_Allocation) p_lines[i]; + if (line.getC_Payment_ID() != 0) + { + payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName()); + if (!payList.contains(payment)) + payList.add(payment); + htPayAllocLine.put(payment.getC_Payment_ID(), line.get_ID()); + } + } + + Hashtable htPayAcct = new Hashtable(); + Hashtable htPaySource = new Hashtable(); + Hashtable htPayAccounted = new Hashtable(); + for (MPayment payment : payList) + { + htPayAcct.put(payment.getC_Payment_ID(), getPaymentAcct(as, payment.getC_Payment_ID())); + + 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 Payment + List valuesPay = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), + MPayment.Table_ID, payment.getC_Payment_ID(), as.getC_AcctSchema_ID(), htPayAcct.get(payment.getC_Payment_ID()).getAccount_ID()); + if (valuesPay != null) { + BigDecimal paymentSource = (BigDecimal) valuesPay.get(0); // AmtSourceDr + BigDecimal paymentAccounted = (BigDecimal) valuesPay.get(1); // AmtAcctDr + if (paymentSource.signum() == 0 && paymentAccounted.signum() == 0) { + paymentSource = (BigDecimal) valuesPay.get(2); // AmtSourceCr + paymentAccounted = (BigDecimal) valuesPay.get(3); // AmtAcctCr + } + htPaySource.put(payment.getC_Payment_ID(), paymentSource); + htPayAccounted.put(payment.getC_Payment_ID(), paymentAccounted); + } + } + + MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct()); + MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct()); + + Hashtable htTotalAmtSourceDr = new Hashtable(); + Hashtable htTotalAmtAcctDr = new Hashtable(); + Hashtable htTotalAmtSourceCr = new Hashtable(); + Hashtable htTotalAmtAcctCr = new Hashtable(); + FactLine[] factlines = fact.getLines(); + for (FactLine factLine : factlines) + { + if (factLine.getLine_ID() > 0) + { + MAllocationLine allocationLine = new MAllocationLine(getCtx(), factLine.getLine_ID(), getTrxName()); + if (allocationLine.getC_Payment_ID() > 0) + { + if (factLine.getAccount_ID() == htPayAcct.get(allocationLine.getC_Payment_ID()).getAccount_ID()) + { + BigDecimal totalAmtSourceDr = htTotalAmtSourceDr.get(allocationLine.getC_Payment_ID()); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + BigDecimal totalAmtAcctDr = htTotalAmtAcctDr.get(allocationLine.getC_Payment_ID()); + if (totalAmtAcctDr == null) + totalAmtAcctDr = Env.ZERO; + BigDecimal totalAmtSourceCr = htTotalAmtSourceCr.get(allocationLine.getC_Payment_ID()); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + BigDecimal totalAmtAcctCr = htTotalAmtAcctCr.get(allocationLine.getC_Payment_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(allocationLine.getC_Payment_ID(), totalAmtSourceDr); + htTotalAmtAcctDr.put(allocationLine.getC_Payment_ID(), totalAmtAcctDr); + htTotalAmtSourceCr.put(allocationLine.getC_Payment_ID(), totalAmtSourceCr); + htTotalAmtAcctCr.put(allocationLine.getC_Payment_ID(), totalAmtAcctCr); + } + else if (factLine.getAccount_ID() == gain.getAccount_ID() || factLine.getAccount_ID() == loss.getAccount_ID()) + { + if (!payGainLossFactLines.contains(factLine)) + continue; + + BigDecimal totalAmtSourceDr = htTotalAmtSourceDr.get(allocationLine.getC_Payment_ID()); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + BigDecimal totalAmtSourceCr = htTotalAmtSourceCr.get(allocationLine.getC_Payment_ID()); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + + totalAmtSourceDr = totalAmtSourceDr.subtract(factLine.getAmtSourceCr()); + totalAmtSourceCr = totalAmtSourceCr.subtract(factLine.getAmtSourceDr()); + + htTotalAmtSourceDr.put(allocationLine.getC_Payment_ID(), totalAmtSourceDr); + htTotalAmtSourceCr.put(allocationLine.getC_Payment_ID(), totalAmtSourceCr); + } + } + } + } + + Hashtable htAllocPaySource = new Hashtable(); + Hashtable htAllocPayAccounted = new Hashtable(); + for (MPayment payment : payList) + { + BigDecimal allocateSource = Env.ZERO; + BigDecimal allocateAccounted = Env.ZERO; + + BigDecimal totalAmtSourceDr = htTotalAmtSourceDr.get(payment.getC_Payment_ID()); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + BigDecimal totalAmtAcctDr = htTotalAmtAcctDr.get(payment.getC_Payment_ID()); + if (totalAmtAcctDr == null) + totalAmtAcctDr = Env.ZERO; + BigDecimal totalAmtSourceCr = htTotalAmtSourceCr.get(payment.getC_Payment_ID()); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + BigDecimal totalAmtAcctCr = htTotalAmtAcctCr.get(payment.getC_Payment_ID()); + if (totalAmtAcctCr == null) + totalAmtAcctCr = Env.ZERO; + + if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) + { + allocateSource = allocateSource.add(totalAmtSourceCr); + allocateAccounted = allocateAccounted.add(totalAmtAcctCr); + } + else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0) + { + allocateSource = allocateSource.add(totalAmtSourceDr); + allocateAccounted = allocateAccounted.add(totalAmtAcctDr); + } + else + { + if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0) + { + allocateSource = allocateSource.add(totalAmtSourceDr); + allocateAccounted = allocateAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr); + } + else + { + allocateSource = allocateSource.add(totalAmtSourceCr); + allocateAccounted = allocateAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr); + } + } + + MAllocationHdr[] allocations = MAllocationHdr.getOfPayment(getCtx(), payment.get_ID(), getTrxName()); + for (MAllocationHdr alloc : allocations) + { + if (alloc.get_ID() == get_ID()) + continue; + + BigDecimal currencyAdjustment = 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=?") // allocation + .append(" AND C_AcctSchema_ID=?") + .append(" AND PostingType='A'") + .append(" AND Account_ID=?") + .append(" AND Line_ID IN (SELECT C_AllocationLine_ID FROM C_AllocationLine WHERE C_AllocationHdr_ID=? AND C_Payment_ID=?)"); + + // For Allocation + List valuesAlloc = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), + MAllocationHdr.Table_ID, alloc.get_ID(), as.getC_AcctSchema_ID(), htPayAcct.get(payment.getC_Payment_ID()).getAccount_ID(), alloc.get_ID(), payment.getC_Payment_ID()); + if (valuesAlloc != null) { + totalAmtSourceDr = (BigDecimal) valuesAlloc.get(0); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + totalAmtAcctDr = (BigDecimal) valuesAlloc.get(1); + if (totalAmtAcctDr == null) + totalAmtAcctDr = Env.ZERO; + totalAmtSourceCr = (BigDecimal) valuesAlloc.get(2); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + totalAmtAcctCr = (BigDecimal) valuesAlloc.get(3); + if (totalAmtAcctCr == null) + totalAmtAcctCr = Env.ZERO; + + if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) + { + allocateSource = allocateSource.add(totalAmtSourceCr); + allocateAccounted = allocateAccounted.add(totalAmtAcctCr); + } + else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0) + { + allocateSource = allocateSource.add(totalAmtSourceDr); + allocateAccounted = allocateAccounted.add(totalAmtAcctDr); + } + else + { + if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0) + { + allocateSource = allocateSource.add(totalAmtSourceDr); + allocateAccounted = allocateAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr); + currencyAdjustment = currencyAdjustment.add(totalAmtAcctCr); + } + else + { + allocateSource = allocateSource.add(totalAmtSourceCr); + allocateAccounted = allocateAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr); + currencyAdjustment = currencyAdjustment.add(totalAmtAcctDr); + } + } + } + + 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=?") // allocation + .append(" AND C_AcctSchema_ID=?") + .append(" AND PostingType='A'") + .append(" AND (Account_ID=? OR Account_ID=? OR Account_ID=?)") + .append(" AND Line_ID IN (SELECT C_AllocationLine_ID FROM C_AllocationLine WHERE C_AllocationHdr_ID=? AND C_Payment_ID=?)"); + + // For Allocation + valuesAlloc = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), + MAllocationHdr.Table_ID, alloc.get_ID(), as.getC_AcctSchema_ID(), + gain.getAccount_ID(), loss.getAccount_ID(), as.getCurrencyBalancing_Acct().getAccount_ID(), + alloc.get_ID(), payment.getC_Payment_ID()); + if (valuesAlloc != null) { + totalAmtSourceDr = (BigDecimal) valuesAlloc.get(0); + if (totalAmtSourceDr == null) + totalAmtSourceDr = Env.ZERO; + totalAmtAcctDr = (BigDecimal) valuesAlloc.get(1); + if (totalAmtAcctDr == null) + totalAmtAcctDr = Env.ZERO; + totalAmtSourceCr = (BigDecimal) valuesAlloc.get(2); + if (totalAmtSourceCr == null) + totalAmtSourceCr = Env.ZERO; + totalAmtAcctCr = (BigDecimal) valuesAlloc.get(3); + if (totalAmtAcctCr == null) + totalAmtAcctCr = Env.ZERO; + + allocateSource = allocateSource.subtract(totalAmtSourceDr).subtract(totalAmtSourceCr).add(currencyAdjustment); + if (as.isCurrencyBalancing() && as.getC_Currency_ID() != payment.getC_Currency_ID()) + ; + else + allocateAccounted = allocateAccounted.add(currencyAdjustment); + } + } + + htAllocPaySource.put(payment.getC_Payment_ID(), allocateSource); + htAllocPayAccounted.put(payment.getC_Payment_ID(), allocateAccounted); + } + + for (MPayment payment : payList) + { + BigDecimal paySource = htPaySource.get(payment.getC_Payment_ID()); + if (paySource == null) + paySource = Env.ZERO; + BigDecimal payAccounted = htPayAccounted.get(payment.getC_Payment_ID()); + if (payAccounted == null) + payAccounted = Env.ZERO; + BigDecimal allocPaySource = htAllocPaySource.get(payment.getC_Payment_ID()); + if (allocPaySource == null) + allocPaySource = Env.ZERO; + BigDecimal allocPayAccounted = htAllocPayAccounted.get(payment.getC_Payment_ID()); + if (allocPayAccounted == null) + allocPayAccounted = Env.ZERO; + + StringBuilder description = new StringBuilder("Payment=(").append(getC_Currency_ID()).append(")").append(paySource).append("/").append(payAccounted) + .append(" - Allocation=(").append(getC_Currency_ID()).append(")").append(allocPaySource).append("/").append(allocPayAccounted); + if (log.isLoggable(Level.FINE)) log.fine(description.toString()); + BigDecimal acctDifference = null; + if (allocPaySource.abs().compareTo(paySource.abs()) == 0) + { + acctDifference = allocPayAccounted.abs().subtract(payAccounted.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"); + return null; + } + + // + Integer C_AllocationLine_ID = htPayAllocLine.get(payment.getC_Payment_ID()); + if ((payment.isReceipt() && payment.getPayAmt().signum() >= 0) || (!payment.isReceipt() && payment.getPayAmt().signum() < 0)) + { + FactLine fl = fact.createLine (null, htPayAcct.get(payment.getC_Payment_ID()), 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() != payment.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()); + fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); + } + } + else + { + FactLine fl = fact.createLine (null, htPayAcct.get(payment.getC_Payment_ID()), 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() != payment.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()); + fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID); + } + } + } + return null; + } } // Doc_Allocation /**