From 64eca30fca22de811c6f7d48f48dd5cb796b0a0b Mon Sep 17 00:00:00 2001 From: vpj-cd Date: Thu, 7 Dec 2006 03:25:49 +0000 Subject: [PATCH] Adempiere 3.1.2 --- .../main/server/org/compiere/acct/Doc.java | 16 + .../server/org/compiere/acct/DocLine.java | 17 + .../server/org/compiere/acct/Doc_Order.java | 1146 +++++----- .../main/server/org/compiere/acct/Fact.java | 1645 +++++++------- .../server/org/compiere/acct/FactLine.java | 1905 +++++++++-------- .../compiere/ldap/LdapConnectionHandler.java | 154 +- .../server/org/compiere/ldap/LdapMessage.java | 432 ++-- .../org/compiere/ldap/LdapProcessor.java | 48 +- .../org/compiere/ldap/LdapProcessorModel.java | 158 -- .../server/org/compiere/ldap/LdapResult.java | 400 ++-- .../org/compiere/server/AdempiereServer.java | 652 +++--- .../compiere/server/AdempiereServerMgr.java | 16 +- serverRoot/src/web/adempiere.jnlp | 2 +- 13 files changed, 3453 insertions(+), 3138 deletions(-) delete mode 100644 serverRoot/src/main/server/org/compiere/ldap/LdapProcessorModel.java diff --git a/serverRoot/src/main/server/org/compiere/acct/Doc.java b/serverRoot/src/main/server/org/compiere/acct/Doc.java index 569b5317f1..8ea0923e94 100644 --- a/serverRoot/src/main/server/org/compiere/acct/Doc.java +++ b/serverRoot/src/main/server/org/compiere/acct/Doc.java @@ -2135,6 +2135,22 @@ public abstract class Doc } return 0; } // getUser2_ID + + /** + * Get User Defined value + * @return User defined + */ + public int getValue (String ColumnName) + { + int index = p_po.get_ColumnIndex(ColumnName); + if (index != -1) + { + Integer ii = (Integer)p_po.get_Value(index); + if (ii != null) + return ii.intValue(); + } + return 0; + } // getValue /*************************************************************************/ diff --git a/serverRoot/src/main/server/org/compiere/acct/DocLine.java b/serverRoot/src/main/server/org/compiere/acct/DocLine.java index ff6ecd0fc7..81240c176a 100644 --- a/serverRoot/src/main/server/org/compiere/acct/DocLine.java +++ b/serverRoot/src/main/server/org/compiere/acct/DocLine.java @@ -994,6 +994,23 @@ public class DocLine } return 0; } // getUser2_ID + + /** + * Get User Defined Column + * @param ColumnName column name + * @return user defined column value + */ + public int getValue(String ColumnName) + { + int index = p_po.get_ColumnIndex(ColumnName); + if (index != -1) + { + Integer ii = (Integer)p_po.get_Value(index); + if (ii != null) + return ii.intValue(); + } + return 0; + } // getValue /** * String representation diff --git a/serverRoot/src/main/server/org/compiere/acct/Doc_Order.java b/serverRoot/src/main/server/org/compiere/acct/Doc_Order.java index 13e728a7a0..64028957a8 100644 --- a/serverRoot/src/main/server/org/compiere/acct/Doc_Order.java +++ b/serverRoot/src/main/server/org/compiere/acct/Doc_Order.java @@ -3,90 +3,90 @@ * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * - * by the Free Software Foundation. This program is distributed in the hope * - * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * - * For the text or an alternative of this public license, you may reach us * - * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * - * or via info@compiere.org or http://www.compiere.org/license.html * - *****************************************************************************/ -package org.compiere.acct; - -import java.math.*; -import java.sql.*; -import java.util.*; -import java.util.logging.*; -import org.compiere.model.*; -import org.compiere.util.*; - -/** - * Post Order Documents. - *
- *  Table:              C_Order (259)
- *  Document Types:     SOO, POO
- *  
- * @author Jorg Janke - * @version $Id: Doc_Order.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $ - */ -public class Doc_Order extends Doc -{ - /** - * Constructor - * @param ass accounting schemata - * @param rs record - * @param trxName trx - */ - protected Doc_Order (MAcctSchema[] ass, ResultSet rs, String trxName) - { - super (ass, MOrder.class, rs, null, trxName); - } // Doc_Order - - /** Contained Optional Tax Lines */ - private DocTax[] m_taxes = null; - /** Requisitions */ - private DocLine[] m_requisitions = null; - /** Order Currency Precision */ - private int m_precision = -1; - - /** - * Load Specific Document Details - * @return error message or null - */ - protected String loadDocumentDetails () - { - MOrder order = (MOrder)getPO(); - setDateDoc(order.getDateOrdered()); - setIsTaxIncluded(order.isTaxIncluded()); - // Amounts - setAmount(AMTTYPE_Gross, order.getGrandTotal()); - setAmount(AMTTYPE_Net, order.getTotalLines()); - setAmount(AMTTYPE_Charge, order.getChargeAmt()); - - // Contained Objects - m_taxes = loadTaxes(); - p_lines = loadLines(order); - // log.fine( "Lines=" + p_lines.length + ", Taxes=" + m_taxes.length); - return null; - } // loadDocumentDetails - - - /** - * Load Invoice Line - * @param order order - * @return DocLine Array - */ - private DocLine[] loadLines(MOrder order) - { - ArrayList list = new ArrayList(); - MOrderLine[] lines = order.getLines(); - for (int i = 0; i < lines.length; i++) - { - MOrderLine line = lines[i]; - DocLine docLine = new DocLine (line, this); + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.compiere.acct; + +import java.math.*; +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * Post Order Documents. + *
+ *  Table:              C_Order (259)
+ *  Document Types:     SOO, POO
+ *  
+ * @author Jorg Janke + * @version $Id: Doc_Order.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $ + */ +public class Doc_Order extends Doc +{ + /** + * Constructor + * @param ass accounting schemata + * @param rs record + * @param trxName trx + */ + protected Doc_Order (MAcctSchema[] ass, ResultSet rs, String trxName) + { + super (ass, MOrder.class, rs, null, trxName); + } // Doc_Order + + /** Contained Optional Tax Lines */ + private DocTax[] m_taxes = null; + /** Requisitions */ + private DocLine[] m_requisitions = null; + /** Order Currency Precision */ + private int m_precision = -1; + + /** + * Load Specific Document Details + * @return error message or null + */ + protected String loadDocumentDetails () + { + MOrder order = (MOrder)getPO(); + setDateDoc(order.getDateOrdered()); + setIsTaxIncluded(order.isTaxIncluded()); + // Amounts + setAmount(AMTTYPE_Gross, order.getGrandTotal()); + setAmount(AMTTYPE_Net, order.getTotalLines()); + setAmount(AMTTYPE_Charge, order.getChargeAmt()); + + // Contained Objects + m_taxes = loadTaxes(); + p_lines = loadLines(order); + // log.fine( "Lines=" + p_lines.length + ", Taxes=" + m_taxes.length); + return null; + } // loadDocumentDetails + + + /** + * Load Invoice Line + * @param order order + * @return DocLine Array + */ + private DocLine[] loadLines(MOrder order) + { + ArrayList list = new ArrayList(); + MOrderLine[] lines = order.getLines(); + for (int i = 0; i < lines.length; i++) + { + MOrderLine line = lines[i]; + DocLine docLine = new DocLine (line, this); BigDecimal Qty = line.getQtyOrdered(); docLine.setQty(Qty, order.isSOTrx()); // @@ -94,517 +94,519 @@ public class Doc_Order extends Doc BigDecimal PriceCost = null; if (getDocumentType().equals(DOCTYPE_POrder)) // PO PriceCost = line.getPriceCost(); - BigDecimal LineNetAmt = null; - if (PriceCost != null && PriceCost.signum() != 0) - LineNetAmt = Qty.multiply(PriceCost); - else - LineNetAmt = line.getLineNetAmt(); - docLine.setAmount (LineNetAmt); // DR - BigDecimal PriceList = line.getPriceList(); - int C_Tax_ID = docLine.getC_Tax_ID(); - // Correct included Tax - if (isTaxIncluded() && C_Tax_ID != 0) - { - MTax tax = MTax.get(getCtx(), C_Tax_ID); - if (!tax.isZeroTax()) - { - BigDecimal LineNetAmtTax = tax.calculateTax(LineNetAmt, true, getStdPrecision()); - log.fine("LineNetAmt=" + LineNetAmt + " - Tax=" + LineNetAmtTax); - LineNetAmt = LineNetAmt.subtract(LineNetAmtTax); - for (int t = 0; t < m_taxes.length; t++) - { - if (m_taxes[t].getC_Tax_ID() == C_Tax_ID) - { - m_taxes[t].addIncludedTax(LineNetAmtTax); - break; - } - } - BigDecimal PriceListTax = tax.calculateTax(PriceList, true, getStdPrecision()); - PriceList = PriceList.subtract(PriceListTax); - } - } // correct included Tax - - docLine.setAmount (LineNetAmt, PriceList, Qty); - list.add(docLine); - } - - // Return Array - DocLine[] dl = new DocLine[list.size()]; - list.toArray(dl); - return dl; - } // loadLines - - - /** - * Load Requisitions - * @return requisition lines of Order - */ - private DocLine[] loadRequisitions () - { - MOrder order = (MOrder)getPO(); - MOrderLine[] oLines = order.getLines(); - HashMap qtys = new HashMap(); - for (int i = 0; i < oLines.length; i++) - { - MOrderLine line = oLines[i]; - qtys.put(new Integer(line.getC_OrderLine_ID()), line.getQtyOrdered()); - } - // - ArrayList list = new ArrayList(); - String sql = "SELECT * FROM M_RequisitionLine rl " - + "WHERE EXISTS (SELECT * FROM C_Order o " - + " INNER JOIN C_OrderLine ol ON (o.C_Order_ID=ol.C_Order_ID) " - + "WHERE ol.C_OrderLine_ID=rl.C_OrderLine_ID" - + " AND o.C_Order_ID=?) " - + "ORDER BY rl.C_OrderLine_ID"; - PreparedStatement pstmt = null; - try - { - pstmt = DB.prepareStatement (sql, null); - pstmt.setInt (1, order.getC_Order_ID()); - ResultSet rs = pstmt.executeQuery (); - while (rs.next ()) - { - MRequisitionLine line = new MRequisitionLine (getCtx(), rs, null); - DocLine docLine = new DocLine (line, this); - // Quantity - not more then OrderLine - // Issue: Split of Requisition to multiple POs & different price - Integer key = new Integer(line.getC_OrderLine_ID()); - BigDecimal maxQty = qtys.get(key); - BigDecimal Qty = line.getQty().max(maxQty); - if (Qty.signum() == 0) - continue; - docLine.setQty (Qty, false); - qtys.put(key, maxQty.subtract(Qty)); - // - BigDecimal PriceActual = line.getPriceActual(); - BigDecimal LineNetAmt = line.getLineNetAmt(); - if (line.getQty().compareTo(Qty) != 0) - LineNetAmt = PriceActual.multiply(Qty); - docLine.setAmount (LineNetAmt); // DR - list.add (docLine); - } - rs.close (); - pstmt.close (); - pstmt = null; - } - catch (Exception e) - { - log.log (Level.SEVERE, sql, e); - } - try - { - if (pstmt != null) - pstmt.close (); - pstmt = null; - } - catch (Exception e) - { - pstmt = null; - } - - // Return Array - DocLine[] dls = new DocLine[list.size ()]; - list.toArray (dls); - return dls; - } // loadRequisitions - - - /** - * Get Currency Precision - * @return precision - */ - private int getStdPrecision() - { - if (m_precision == -1) - m_precision = MCurrency.getStdPrecision(getCtx(), getC_Currency_ID()); - return m_precision; - } // getPrecision - - /** - * Load Invoice Taxes - * @return DocTax Array - */ - private DocTax[] loadTaxes() - { - ArrayList list = new ArrayList(); - String sql = "SELECT it.C_Tax_ID, t.Name, t.Rate, it.TaxBaseAmt, it.TaxAmt, t.IsSalesTax " - + "FROM C_Tax t, C_OrderTax it " - + "WHERE t.C_Tax_ID=it.C_Tax_ID AND it.C_Order_ID=?"; - try - { - PreparedStatement pstmt = DB.prepareStatement(sql, getTrxName()); - pstmt.setInt(1, get_ID()); - ResultSet rs = pstmt.executeQuery(); - // - while (rs.next()) - { - int C_Tax_ID = rs.getInt(1); - String name = rs.getString(2); - BigDecimal rate = rs.getBigDecimal(3); - BigDecimal taxBaseAmt = rs.getBigDecimal(4); - BigDecimal amount = rs.getBigDecimal(5); - boolean salesTax = "Y".equals(rs.getString(6)); - // - DocTax taxLine = new DocTax(C_Tax_ID, name, rate, - taxBaseAmt, amount, salesTax); - list.add(taxLine); - } - // - rs.close(); - pstmt.close(); - } - catch (SQLException e) - { - log.log(Level.SEVERE, sql, e); - } - - // Return Array - DocTax[] tl = new DocTax[list.size()]; - list.toArray(tl); - return tl; - } // loadTaxes - - - /************************************************************************** - * Get Source Currency Balance - subtracts line and tax amounts from total - no rounding - * @return positive amount, if total invoice is bigger than lines - */ - public BigDecimal getBalance() - { - BigDecimal retValue = new BigDecimal(0.0); - StringBuffer sb = new StringBuffer (" ["); - // Total - retValue = retValue.add(getAmount(Doc.AMTTYPE_Gross)); - sb.append(getAmount(Doc.AMTTYPE_Gross)); - // - Header Charge - retValue = retValue.subtract(getAmount(Doc.AMTTYPE_Charge)); - sb.append("-").append(getAmount(Doc.AMTTYPE_Charge)); - // - Tax - if (m_taxes != null) - { - for (int i = 0; i < m_taxes.length; i++) - { - retValue = retValue.subtract(m_taxes[i].getAmount()); - sb.append("-").append(m_taxes[i].getAmount()); - } - } - // - Lines - if (p_lines != null) - { - for (int i = 0; i < p_lines.length; i++) - { - retValue = retValue.subtract(p_lines[i].getAmtSource()); - sb.append("-").append(p_lines[i].getAmtSource()); - } - sb.append("]"); - } - // - if (retValue.signum() != 0 // Sum of Cost(vs. Price) in lines may not add up - && getDocumentType().equals(DOCTYPE_POrder)) // PO - { - log.fine(toString() + " Balance=" + retValue + sb.toString() + " (ignored)"); - retValue = Env.ZERO; - } - else - log.fine(toString() + " Balance=" + retValue + sb.toString()); - return retValue; - } // getBalance - - - /************************************************************************* - * Create Facts (the accounting logic) for - * SOO, POO. - *
-	 *  Reservation (release)
-	 * 		Expense			DR
-	 * 		Offset					CR
-	 *  Commitment
-	 *  (to be released by Invoice Matching)
-	 * 		Expense					CR
-	 * 		Offset			DR
-	 *  
- * @param as accounting schema - * @return Fact - */ - public ArrayList createFacts (MAcctSchema as) - { - ArrayList facts = new ArrayList(); - // Purchase Order - if (getDocumentType().equals(DOCTYPE_POrder)) - { + BigDecimal LineNetAmt = null; + if (PriceCost != null && PriceCost.signum() != 0) + LineNetAmt = Qty.multiply(PriceCost); + else + LineNetAmt = line.getLineNetAmt(); + docLine.setAmount (LineNetAmt); // DR + BigDecimal PriceList = line.getPriceList(); + int C_Tax_ID = docLine.getC_Tax_ID(); + // Correct included Tax + if (isTaxIncluded() && C_Tax_ID != 0) + { + MTax tax = MTax.get(getCtx(), C_Tax_ID); + if (!tax.isZeroTax()) + { + BigDecimal LineNetAmtTax = tax.calculateTax(LineNetAmt, true, getStdPrecision()); + log.fine("LineNetAmt=" + LineNetAmt + " - Tax=" + LineNetAmtTax); + LineNetAmt = LineNetAmt.subtract(LineNetAmtTax); + for (int t = 0; t < m_taxes.length; t++) + { + if (m_taxes[t].getC_Tax_ID() == C_Tax_ID) + { + m_taxes[t].addIncludedTax(LineNetAmtTax); + break; + } + } + BigDecimal PriceListTax = tax.calculateTax(PriceList, true, getStdPrecision()); + PriceList = PriceList.subtract(PriceListTax); + } + } // correct included Tax + + docLine.setAmount (LineNetAmt, PriceList, Qty); + list.add(docLine); + } + + // Return Array + DocLine[] dl = new DocLine[list.size()]; + list.toArray(dl); + return dl; + } // loadLines + + + /** + * Load Requisitions + * @return requisition lines of Order + */ + private DocLine[] loadRequisitions () + { + MOrder order = (MOrder)getPO(); + MOrderLine[] oLines = order.getLines(); + HashMap qtys = new HashMap(); + for (int i = 0; i < oLines.length; i++) + { + MOrderLine line = oLines[i]; + qtys.put(new Integer(line.getC_OrderLine_ID()), line.getQtyOrdered()); + } + // + ArrayList list = new ArrayList(); + String sql = "SELECT * FROM M_RequisitionLine rl " + + "WHERE EXISTS (SELECT * FROM C_Order o " + + " INNER JOIN C_OrderLine ol ON (o.C_Order_ID=ol.C_Order_ID) " + + "WHERE ol.C_OrderLine_ID=rl.C_OrderLine_ID" + + " AND o.C_Order_ID=?) " + + "ORDER BY rl.C_OrderLine_ID"; + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement (sql, null); + pstmt.setInt (1, order.getC_Order_ID()); + ResultSet rs = pstmt.executeQuery (); + while (rs.next ()) + { + MRequisitionLine line = new MRequisitionLine (getCtx(), rs, null); + DocLine docLine = new DocLine (line, this); + // Quantity - not more then OrderLine + // Issue: Split of Requisition to multiple POs & different price + Integer key = new Integer(line.getC_OrderLine_ID()); + BigDecimal maxQty = qtys.get(key); + BigDecimal Qty = line.getQty().max(maxQty); + if (Qty.signum() == 0) + continue; + docLine.setQty (Qty, false); + qtys.put(key, maxQty.subtract(Qty)); + // + BigDecimal PriceActual = line.getPriceActual(); + BigDecimal LineNetAmt = line.getLineNetAmt(); + if (line.getQty().compareTo(Qty) != 0) + LineNetAmt = PriceActual.multiply(Qty); + docLine.setAmount (LineNetAmt); // DR + list.add (docLine); + } + rs.close (); + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + log.log (Level.SEVERE, sql, e); + } + try + { + if (pstmt != null) + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + + // Return Array + DocLine[] dls = new DocLine[list.size ()]; + list.toArray (dls); + return dls; + } // loadRequisitions + + + /** + * Get Currency Precision + * @return precision + */ + private int getStdPrecision() + { + if (m_precision == -1) + m_precision = MCurrency.getStdPrecision(getCtx(), getC_Currency_ID()); + return m_precision; + } // getPrecision + + /** + * Load Invoice Taxes + * @return DocTax Array + */ + private DocTax[] loadTaxes() + { + ArrayList list = new ArrayList(); + String sql = "SELECT it.C_Tax_ID, t.Name, t.Rate, it.TaxBaseAmt, it.TaxAmt, t.IsSalesTax " + + "FROM C_Tax t, C_OrderTax it " + + "WHERE t.C_Tax_ID=it.C_Tax_ID AND it.C_Order_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, getTrxName()); + pstmt.setInt(1, get_ID()); + ResultSet rs = pstmt.executeQuery(); + // + while (rs.next()) + { + int C_Tax_ID = rs.getInt(1); + String name = rs.getString(2); + BigDecimal rate = rs.getBigDecimal(3); + BigDecimal taxBaseAmt = rs.getBigDecimal(4); + BigDecimal amount = rs.getBigDecimal(5); + boolean salesTax = "Y".equals(rs.getString(6)); + // + DocTax taxLine = new DocTax(C_Tax_ID, name, rate, + taxBaseAmt, amount, salesTax); + list.add(taxLine); + } + // + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + } + + // Return Array + DocTax[] tl = new DocTax[list.size()]; + list.toArray(tl); + return tl; + } // loadTaxes + + + /************************************************************************** + * Get Source Currency Balance - subtracts line and tax amounts from total - no rounding + * @return positive amount, if total invoice is bigger than lines + */ + public BigDecimal getBalance() + { + BigDecimal retValue = new BigDecimal(0.0); + StringBuffer sb = new StringBuffer (" ["); + // Total + retValue = retValue.add(getAmount(Doc.AMTTYPE_Gross)); + sb.append(getAmount(Doc.AMTTYPE_Gross)); + // - Header Charge + retValue = retValue.subtract(getAmount(Doc.AMTTYPE_Charge)); + sb.append("-").append(getAmount(Doc.AMTTYPE_Charge)); + // - Tax + if (m_taxes != null) + { + for (int i = 0; i < m_taxes.length; i++) + { + retValue = retValue.subtract(m_taxes[i].getAmount()); + sb.append("-").append(m_taxes[i].getAmount()); + } + } + // - Lines + if (p_lines != null) + { + for (int i = 0; i < p_lines.length; i++) + { + retValue = retValue.subtract(p_lines[i].getAmtSource()); + sb.append("-").append(p_lines[i].getAmtSource()); + } + sb.append("]"); + } + // + if (retValue.signum() != 0 // Sum of Cost(vs. Price) in lines may not add up + && getDocumentType().equals(DOCTYPE_POrder)) // PO + { + log.fine(toString() + " Balance=" + retValue + sb.toString() + " (ignored)"); + retValue = Env.ZERO; + } + else + log.fine(toString() + " Balance=" + retValue + sb.toString()); + return retValue; + } // getBalance + + + /************************************************************************* + * Create Facts (the accounting logic) for + * SOO, POO. + *
+	 *  Reservation (release)
+	 * 		Expense			DR
+	 * 		Offset					CR
+	 *  Commitment
+	 *  (to be released by Invoice Matching)
+	 * 		Expense					CR
+	 * 		Offset			DR
+	 *  
+ * @param as accounting schema + * @return Fact + */ + public ArrayList createFacts (MAcctSchema as) + { + ArrayList facts = new ArrayList(); + // Purchase Order + if (getDocumentType().equals(DOCTYPE_POrder)) + { updateProductPO(as); updateProductInfo(as.getC_AcctSchema_ID()); BigDecimal grossAmt = getAmount(Doc.AMTTYPE_Gross); // Commitment + FactLine fl = null; if (as.isCreateCommitment()) { Fact fact = new Fact(this, as, Fact.POST_Commitment); - BigDecimal total = Env.ZERO; - for (int i = 0; i < p_lines.length; i++) - { - DocLine line = p_lines[i]; - BigDecimal cost = line.getAmtSource(); - total = total.add(cost); + BigDecimal total = Env.ZERO; + for (int i = 0; i < p_lines.length; i++) + { + DocLine line = p_lines[i]; + BigDecimal cost = line.getAmtSource(); + total = total.add(cost); // Account MAccount expense = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as); - FactLine fl = fact.createLine (line, expense, + fl = fact.createLine (line, expense, getC_Currency_ID(), cost, null); } // Offset - MAccount offset = getAccount(ACCTTYPE_CommitmentOffset, as); - if (offset == null) - { - p_Error = "@NotFound@ @CommitmentOffset_Acct@"; - log.log(Level.SEVERE, p_Error); - return null; - } - fact.createLine (null, offset, - getC_Currency_ID(), null, total); - // - facts.add(fact); - } - - // Reverse Reservation - if (as.isCreateReservation()) - { - Fact fact = new Fact(this, as, Fact.POST_Reservation); - BigDecimal total = Env.ZERO; - if (m_requisitions == null) - m_requisitions = loadRequisitions(); - for (int i = 0; i < m_requisitions.length; i++) - { - DocLine line = m_requisitions[i]; - BigDecimal cost = line.getAmtSource(); - total = total.add(cost); + MAccount offset = getAccount(ACCTTYPE_CommitmentOffset, as); + if (offset == null) + { + p_Error = "@NotFound@ @CommitmentOffset_Acct@"; + log.log(Level.SEVERE, p_Error); + return null; + } + fact.createLine (null, offset, + getC_Currency_ID(), null, total); + // + facts.add(fact); + } + + // Reverse Reservation + if (as.isCreateReservation()) + { + Fact fact = new Fact(this, as, Fact.POST_Reservation); + BigDecimal total = Env.ZERO; + if (m_requisitions == null) + m_requisitions = loadRequisitions(); + for (int i = 0; i < m_requisitions.length; i++) + { + DocLine line = m_requisitions[i]; + BigDecimal cost = line.getAmtSource(); + total = total.add(cost); // Account MAccount expense = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as); - FactLine fl = fact.createLine (line, expense, + fl = fact.createLine (line, expense, getC_Currency_ID(), null, cost); } // Offset - MAccount offset = getAccount(ACCTTYPE_CommitmentOffset, as); - if (offset == null) - { - p_Error = "@NotFound@ @CommitmentOffset_Acct@"; - log.log(Level.SEVERE, p_Error); - return null; - } - fact.createLine (null, offset, - getC_Currency_ID(), total, null); - // - facts.add(fact); - } // reservations - } - // SO - return facts; - } // createFact - - - /** - * Update ProductPO PriceLastPO - * @param as accounting schema - */ - private void updateProductPO(MAcctSchema as) - { - MClientInfo ci = MClientInfo.get(getCtx(), as.getAD_Client_ID()); - if (ci.getC_AcctSchema1_ID() != as.getC_AcctSchema_ID()) - return; - - StringBuffer sql = new StringBuffer ( - "UPDATE M_Product_PO po " - + "SET PriceLastPO = (SELECT currencyConvert(ol.PriceActual,ol.C_Currency_ID,po.C_Currency_ID,o.DateOrdered,o.C_ConversionType_ID,o.AD_Client_ID,o.AD_Org_ID) " - + "FROM C_Order o, C_OrderLine ol " - + "WHERE o.C_Order_ID=ol.C_Order_ID" - + " AND po.M_Product_ID=ol.M_Product_ID AND po.C_BPartner_ID=o.C_BPartner_ID" - + " AND ROWNUM=1 AND o.C_Order_ID=").append(get_ID()).append(") ") - .append("WHERE EXISTS (SELECT * " - + "FROM C_Order o, C_OrderLine ol " - + "WHERE o.C_Order_ID=ol.C_Order_ID" - + " AND po.M_Product_ID=ol.M_Product_ID AND po.C_BPartner_ID=o.C_BPartner_ID" - + " AND o.C_Order_ID=").append(get_ID()).append(")"); - int no = DB.executeUpdate(sql.toString(), getTrxName()); - log.fine("Updated=" + no); - } // updateProductPO - - - /** - * Get Commitments - * @param doc document - * @param maxQty Qty invoiced/matched - * @param C_InvoiceLine_ID invoice line - * @return commitments (order lines) - */ - protected static DocLine[] getCommitments(Doc doc, BigDecimal maxQty, int C_InvoiceLine_ID) - { - int precision = -1; - // - ArrayList list = new ArrayList(); - String sql = "SELECT * FROM C_OrderLine ol " - + "WHERE EXISTS " - + "(SELECT * FROM C_InvoiceLine il " - + "WHERE il.C_OrderLine_ID=ol.C_OrderLine_ID" - + " AND il.C_InvoiceLine_ID=?)" - + " OR EXISTS " - + "(SELECT * FROM M_MatchPO po " - + "WHERE po.C_OrderLine_ID=ol.C_OrderLine_ID" - + " AND po.C_InvoiceLine_ID=?)"; - PreparedStatement pstmt = null; - try - { - pstmt = DB.prepareStatement (sql, null); - pstmt.setInt (1, C_InvoiceLine_ID); - pstmt.setInt (2, C_InvoiceLine_ID); - ResultSet rs = pstmt.executeQuery (); - while (rs.next ()) - { - if (maxQty.signum() == 0) - continue; - MOrderLine line = new MOrderLine (doc.getCtx(), rs, null); - DocLine docLine = new DocLine (line, doc); - // Currency - if (precision == -1) - { - doc.setC_Currency_ID(docLine.getC_Currency_ID()); - precision = MCurrency.getStdPrecision(doc.getCtx(), docLine.getC_Currency_ID()); - } - // Qty - BigDecimal Qty = line.getQtyOrdered().max(maxQty); - docLine.setQty(Qty, false); - // - BigDecimal PriceActual = line.getPriceActual(); - BigDecimal PriceCost = line.getPriceCost(); - BigDecimal LineNetAmt = null; - if (PriceCost != null && PriceCost.signum() != 0) - LineNetAmt = Qty.multiply(PriceCost); - else if (Qty.equals(maxQty)) - LineNetAmt = line.getLineNetAmt(); - else - LineNetAmt = Qty.multiply(PriceActual); - maxQty = maxQty.subtract(Qty); - - docLine.setAmount (LineNetAmt); // DR - BigDecimal PriceList = line.getPriceList(); - int C_Tax_ID = docLine.getC_Tax_ID(); - // Correct included Tax - if (C_Tax_ID != 0 && line.getParent().isTaxIncluded()) - { - MTax tax = MTax.get(doc.getCtx(), C_Tax_ID); - if (!tax.isZeroTax()) - { - BigDecimal LineNetAmtTax = tax.calculateTax(LineNetAmt, true, precision); - s_log.fine("LineNetAmt=" + LineNetAmt + " - Tax=" + LineNetAmtTax); - LineNetAmt = LineNetAmt.subtract(LineNetAmtTax); - BigDecimal PriceListTax = tax.calculateTax(PriceList, true, precision); - PriceList = PriceList.subtract(PriceListTax); - } - } // correct included Tax - - docLine.setAmount (LineNetAmt, PriceList, Qty); - list.add(docLine); - } - rs.close (); - pstmt.close (); - pstmt = null; - } - catch (Exception e) - { - s_log.log (Level.SEVERE, sql, e); - } - try - { - if (pstmt != null) - pstmt.close (); - pstmt = null; - } - catch (Exception e) - { - pstmt = null; - } - - // Return Array - DocLine[] dl = new DocLine[list.size()]; - list.toArray(dl); - return dl; - } // getCommitments - - /** - * Get Commitment Release. - * Called from MatchInv for accrual and Allocation for Cash Based - * @param as accounting schema - * @param doc doc - * @param Qty qty invoiced/matched - * @param C_InvoiceLine_ID line - * @param multiplier 1 for accrual - * @return Fact - */ - protected static Fact getCommitmentRelease(MAcctSchema as, Doc doc, - BigDecimal Qty, int C_InvoiceLine_ID, BigDecimal multiplier) - { - Fact fact = new Fact(doc, as, Fact.POST_Commitment); - DocLine[] commitments = Doc_Order.getCommitments(doc, Qty, + MAccount offset = getAccount(ACCTTYPE_CommitmentOffset, as); + if (offset == null) + { + p_Error = "@NotFound@ @CommitmentOffset_Acct@"; + log.log(Level.SEVERE, p_Error); + return null; + } + fact.createLine (null, offset, + getC_Currency_ID(), total, null); + // + facts.add(fact); + } // reservations + } + // SO + return facts; + } // createFact + + + /** + * Update ProductPO PriceLastPO + * @param as accounting schema + */ + private void updateProductPO(MAcctSchema as) + { + MClientInfo ci = MClientInfo.get(getCtx(), as.getAD_Client_ID()); + if (ci.getC_AcctSchema1_ID() != as.getC_AcctSchema_ID()) + return; + + StringBuffer sql = new StringBuffer ( + "UPDATE M_Product_PO po " + + "SET PriceLastPO = (SELECT currencyConvert(ol.PriceActual,ol.C_Currency_ID,po.C_Currency_ID,o.DateOrdered,o.C_ConversionType_ID,o.AD_Client_ID,o.AD_Org_ID) " + + "FROM C_Order o, C_OrderLine ol " + + "WHERE o.C_Order_ID=ol.C_Order_ID" + + " AND po.M_Product_ID=ol.M_Product_ID AND po.C_BPartner_ID=o.C_BPartner_ID" + + " AND ROWNUM=1 AND o.C_Order_ID=").append(get_ID()).append(") ") + .append("WHERE EXISTS (SELECT * " + + "FROM C_Order o, C_OrderLine ol " + + "WHERE o.C_Order_ID=ol.C_Order_ID" + + " AND po.M_Product_ID=ol.M_Product_ID AND po.C_BPartner_ID=o.C_BPartner_ID" + + " AND o.C_Order_ID=").append(get_ID()).append(")"); + int no = DB.executeUpdate(sql.toString(), getTrxName()); + log.fine("Updated=" + no); + } // updateProductPO + + + /** + * Get Commitments + * @param doc document + * @param maxQty Qty invoiced/matched + * @param C_InvoiceLine_ID invoice line + * @return commitments (order lines) + */ + protected static DocLine[] getCommitments(Doc doc, BigDecimal maxQty, int C_InvoiceLine_ID) + { + int precision = -1; + // + ArrayList list = new ArrayList(); + String sql = "SELECT * FROM C_OrderLine ol " + + "WHERE EXISTS " + + "(SELECT * FROM C_InvoiceLine il " + + "WHERE il.C_OrderLine_ID=ol.C_OrderLine_ID" + + " AND il.C_InvoiceLine_ID=?)" + + " OR EXISTS " + + "(SELECT * FROM M_MatchPO po " + + "WHERE po.C_OrderLine_ID=ol.C_OrderLine_ID" + + " AND po.C_InvoiceLine_ID=?)"; + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement (sql, null); + pstmt.setInt (1, C_InvoiceLine_ID); + pstmt.setInt (2, C_InvoiceLine_ID); + ResultSet rs = pstmt.executeQuery (); + while (rs.next ()) + { + if (maxQty.signum() == 0) + continue; + MOrderLine line = new MOrderLine (doc.getCtx(), rs, null); + DocLine docLine = new DocLine (line, doc); + // Currency + if (precision == -1) + { + doc.setC_Currency_ID(docLine.getC_Currency_ID()); + precision = MCurrency.getStdPrecision(doc.getCtx(), docLine.getC_Currency_ID()); + } + // Qty + BigDecimal Qty = line.getQtyOrdered().max(maxQty); + docLine.setQty(Qty, false); + // + BigDecimal PriceActual = line.getPriceActual(); + BigDecimal PriceCost = line.getPriceCost(); + BigDecimal LineNetAmt = null; + if (PriceCost != null && PriceCost.signum() != 0) + LineNetAmt = Qty.multiply(PriceCost); + else if (Qty.equals(maxQty)) + LineNetAmt = line.getLineNetAmt(); + else + LineNetAmt = Qty.multiply(PriceActual); + maxQty = maxQty.subtract(Qty); + + docLine.setAmount (LineNetAmt); // DR + BigDecimal PriceList = line.getPriceList(); + int C_Tax_ID = docLine.getC_Tax_ID(); + // Correct included Tax + if (C_Tax_ID != 0 && line.getParent().isTaxIncluded()) + { + MTax tax = MTax.get(doc.getCtx(), C_Tax_ID); + if (!tax.isZeroTax()) + { + BigDecimal LineNetAmtTax = tax.calculateTax(LineNetAmt, true, precision); + s_log.fine("LineNetAmt=" + LineNetAmt + " - Tax=" + LineNetAmtTax); + LineNetAmt = LineNetAmt.subtract(LineNetAmtTax); + BigDecimal PriceListTax = tax.calculateTax(PriceList, true, precision); + PriceList = PriceList.subtract(PriceListTax); + } + } // correct included Tax + + docLine.setAmount (LineNetAmt, PriceList, Qty); + list.add(docLine); + } + rs.close (); + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + s_log.log (Level.SEVERE, sql, e); + } + try + { + if (pstmt != null) + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + + // Return Array + DocLine[] dl = new DocLine[list.size()]; + list.toArray(dl); + return dl; + } // getCommitments + + /** + * Get Commitment Release. + * Called from MatchInv for accrual and Allocation for Cash Based + * @param as accounting schema + * @param doc doc + * @param Qty qty invoiced/matched + * @param C_InvoiceLine_ID line + * @param multiplier 1 for accrual + * @return Fact + */ + protected static Fact getCommitmentRelease(MAcctSchema as, Doc doc, + BigDecimal Qty, int C_InvoiceLine_ID, BigDecimal multiplier) + { + Fact fact = new Fact(doc, as, Fact.POST_Commitment); + DocLine[] commitments = Doc_Order.getCommitments(doc, Qty, C_InvoiceLine_ID); BigDecimal total = Env.ZERO; + FactLine fl = null; int C_Currency_ID = -1; for (int i = 0; i < commitments.length; i++) { - DocLine line = commitments[i]; - if (C_Currency_ID == -1) - C_Currency_ID = line.getC_Currency_ID(); - else if (C_Currency_ID != line.getC_Currency_ID()) - { - doc.p_Error = "Different Currencies of Order Lines"; - s_log.log(Level.SEVERE, doc.p_Error); - return null; - } - BigDecimal cost = line.getAmtSource().multiply(multiplier); - total = total.add(cost); + DocLine line = commitments[i]; + if (C_Currency_ID == -1) + C_Currency_ID = line.getC_Currency_ID(); + else if (C_Currency_ID != line.getC_Currency_ID()) + { + doc.p_Error = "Different Currencies of Order Lines"; + s_log.log(Level.SEVERE, doc.p_Error); + return null; + } + BigDecimal cost = line.getAmtSource().multiply(multiplier); + total = total.add(cost); // Account MAccount expense = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as); - FactLine fl = fact.createLine (line, expense, + fl = fact.createLine (line, expense, C_Currency_ID, null, cost); } // Offset - MAccount offset = doc.getAccount(ACCTTYPE_CommitmentOffset, as); - if (offset == null) - { - doc.p_Error = "@NotFound@ @CommitmentOffset_Acct@"; - s_log.log(Level.SEVERE, doc.p_Error); - return null; - } - fact.createLine (null, offset, - C_Currency_ID, total, null); - return fact; - } // getCommitmentRelease - - - /************************************************************************** - * Update Product Info (old) - * - Costing (PriceLastPO) - * - PO (PriceLastPO) - * @param C_AcctSchema_ID accounting schema - * @deprecated old costing - */ - private void updateProductInfo (int C_AcctSchema_ID) - { - log.fine("C_Order_ID=" + get_ID()); - - /** @todo Last.. would need to compare document/last updated date - * would need to maintain LastPriceUpdateDate on _PO and _Costing */ - - // update Product Costing - // requires existence of currency conversion !! - // if there are multiple lines of the same product last price uses first - StringBuffer sql = new StringBuffer ( - "UPDATE M_Product_Costing pc " - + "SET PriceLastPO = " - + "(SELECT currencyConvert(ol.PriceActual,ol.C_Currency_ID,a.C_Currency_ID,o.DateOrdered,o.C_ConversionType_ID,o.AD_Client_ID,o.AD_Org_ID) " + MAccount offset = doc.getAccount(ACCTTYPE_CommitmentOffset, as); + if (offset == null) + { + doc.p_Error = "@NotFound@ @CommitmentOffset_Acct@"; + s_log.log(Level.SEVERE, doc.p_Error); + return null; + } + fact.createLine (null, offset, + C_Currency_ID, total, null); + return fact; + } // getCommitmentRelease + + + /************************************************************************** + * Update Product Info (old) + * - Costing (PriceLastPO) + * - PO (PriceLastPO) + * @param C_AcctSchema_ID accounting schema + * @deprecated old costing + */ + private void updateProductInfo (int C_AcctSchema_ID) + { + log.fine("C_Order_ID=" + get_ID()); + + /** @todo Last.. would need to compare document/last updated date + * would need to maintain LastPriceUpdateDate on _PO and _Costing */ + + // update Product Costing + // requires existence of currency conversion !! + // if there are multiple lines of the same product last price uses first + StringBuffer sql = new StringBuffer ( + "UPDATE M_Product_Costing pc " + + "SET PriceLastPO = " + + "(SELECT currencyConvert(ol.PriceActual,ol.C_Currency_ID,a.C_Currency_ID,o.DateOrdered,o.C_ConversionType_ID,o.AD_Client_ID,o.AD_Org_ID) " + "FROM C_Order o, C_OrderLine ol, C_AcctSchema a " + "WHERE o.C_Order_ID=ol.C_Order_ID" + " AND pc.M_Product_ID=ol.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID" @@ -613,13 +615,13 @@ public class Doc_Order extends Doc + " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND o.C_Order_ID=") .append(get_ID()).append(") ") .append("WHERE EXISTS (SELECT * " - + "FROM C_Order o, C_OrderLine ol, C_AcctSchema a " - + "WHERE o.C_Order_ID=ol.C_Order_ID" - + " AND pc.M_Product_ID=ol.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID" - + " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND o.C_Order_ID=") - .append(get_ID()).append(")"); - int no = DB.executeUpdate(sql.toString(), getTrxName()); - log.fine("M_Product_Costing - Updated=" + no); - } // updateProductInfo - -} // Doc_Order + + "FROM C_Order o, C_OrderLine ol, C_AcctSchema a " + + "WHERE o.C_Order_ID=ol.C_Order_ID" + + " AND pc.M_Product_ID=ol.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID" + + " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND o.C_Order_ID=") + .append(get_ID()).append(")"); + int no = DB.executeUpdate(sql.toString(), getTrxName()); + log.fine("M_Product_Costing - Updated=" + no); + } // updateProductInfo + +} // Doc_Order diff --git a/serverRoot/src/main/server/org/compiere/acct/Fact.java b/serverRoot/src/main/server/org/compiere/acct/Fact.java index fbf8f092da..5760bbf486 100644 --- a/serverRoot/src/main/server/org/compiere/acct/Fact.java +++ b/serverRoot/src/main/server/org/compiere/acct/Fact.java @@ -3,59 +3,59 @@ * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * - * by the Free Software Foundation. This program is distributed in the hope * - * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * - * For the text or an alternative of this public license, you may reach us * - * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * - * or via info@compiere.org or http://www.compiere.org/license.html * - *****************************************************************************/ -package org.compiere.acct; - -import java.math.*; -import java.util.*; -import org.compiere.model.*; -import org.compiere.util.*; - -/** - * Accounting Fact - * - * @author Jorg Janke - * @version $Id: Fact.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $ - */ -public final class Fact -{ - /** - * Constructor - * @param document pointer to document - * @param acctSchema Account Schema to create accounts - * @param defaultPostingType the default Posting type (actual,..) for this posting - */ - public Fact (Doc document, MAcctSchema acctSchema, String defaultPostingType) - { - m_doc = document; - m_acctSchema = acctSchema; - m_postingType = defaultPostingType; - // - log.config(toString()); - } // Fact - - - /** Log */ - private CLogger log = CLogger.getCLogger(getClass()); - - /** Document */ - private Doc m_doc = null; - /** Accounting Schema */ - private MAcctSchema m_acctSchema = null; - /** Transaction */ - private String m_trxName; - - /** Posting Type */ + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.compiere.acct; + +import java.math.*; +import java.util.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * Accounting Fact + * + * @author Jorg Janke + * @version $Id: Fact.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $ + */ +public final class Fact +{ + /** + * Constructor + * @param document pointer to document + * @param acctSchema Account Schema to create accounts + * @param defaultPostingType the default Posting type (actual,..) for this posting + */ + public Fact (Doc document, MAcctSchema acctSchema, String defaultPostingType) + { + m_doc = document; + m_acctSchema = acctSchema; + m_postingType = defaultPostingType; + // + log.config(toString()); + } // Fact + + + /** Log */ + private CLogger log = CLogger.getCLogger(getClass()); + + /** Document */ + private Doc m_doc = null; + /** Accounting Schema */ + private MAcctSchema m_acctSchema = null; + /** Transaction */ + private String m_trxName; + + /** Posting Type */ private String m_postingType = null; /** Actual Balance Type */ @@ -69,253 +69,253 @@ public final class Fact /** Is Converted */ - private boolean m_converted = false; - - /** Lines */ - private ArrayList m_lines = new ArrayList(); - - - /** - * Dispose - */ - public void dispose() - { - m_lines.clear(); - m_lines = null; - } // dispose - - /** - * Create and convert Fact Line. - * Used to create a DR and/or CR entry - * - * @param docLine the document line or null - * @param account if null, line is not created - * @param C_Currency_ID the currency - * @param debitAmt debit amount, can be null - * @param creditAmt credit amount, can be null - * @return Fact Line - */ - public FactLine createLine (DocLine docLine, MAccount account, - int C_Currency_ID, BigDecimal debitAmt, BigDecimal creditAmt) - { - // log.fine("createLine - " + account + " - Dr=" + debitAmt + ", Cr=" + creditAmt); - - // Data Check - if (account == null) - { - log.info("No account for " + docLine - + ": Amt=" + debitAmt + "/" + creditAmt - + " - " + toString()); - return null; - } - // - FactLine line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), - m_doc.get_ID(), - docLine == null ? 0 : docLine.get_ID(), m_trxName); - // Set Info & Account - line.setDocumentInfo(m_doc, docLine); - line.setPostingType(m_postingType); - line.setAccount(m_acctSchema, account); - - // Amounts - one needs to not zero - if (!line.setAmtSource(C_Currency_ID, debitAmt, creditAmt)) - { - if (docLine == null || docLine.getQty() == null || docLine.getQty().signum() == 0) - { - log.fine("Both amounts & qty = 0/Null - " + docLine - + " - " + toString()); - return null; - } - log.fine("Both amounts = 0/Null, Qty=" + docLine.getQty() + " - " + docLine - + " - " + toString()); - } - // Convert - line.convert(); - // Optionally overwrite Acct Amount - if (docLine != null - && (docLine.getAmtAcctDr() != null || docLine.getAmtAcctCr() != null)) - line.setAmtAcct(docLine.getAmtAcctDr(), docLine.getAmtAcctCr()); - // - log.fine(line.toString()); - add(line); - return line; - } // createLine - - /** - * Add Fact Line - * @param line fact line - */ - void add (FactLine line) - { - m_lines.add(line); - } // add - - /** - * Create and convert Fact Line. - * Used to create either a DR or CR entry - * - * @param docLine Document Line or null - * @param accountDr Account to be used if Amt is DR balance - * @param accountCr Account to be used if Amt is CR balance - * @param C_Currency_ID Currency - * @param Amt if negative Cr else Dr - * @return FactLine - */ - public FactLine createLine (DocLine docLine, MAccount accountDr, MAccount accountCr, - int C_Currency_ID, BigDecimal Amt) - { - if (Amt.signum() < 0) - return createLine (docLine, accountCr, C_Currency_ID, null, Amt.abs()); - else - return createLine (docLine, accountDr, C_Currency_ID, Amt, null); - } // createLine - - /** - * Create and convert Fact Line. - * Used to create either a DR or CR entry - * - * @param docLine Document line or null - * @param account Account to be used - * @param C_Currency_ID Currency - * @param Amt if negative Cr else Dr - * @return FactLine - */ - public FactLine createLine (DocLine docLine, MAccount account, - int C_Currency_ID, BigDecimal Amt) - { - if (Amt.signum() < 0) - return createLine (docLine, account, C_Currency_ID, null, Amt.abs()); - else - return createLine (docLine, account, C_Currency_ID, Amt, null); - } // createLine - - /** - * Is Posting Type - * @param PostingType - see POST_* - * @return true if document is posting type - */ - public boolean isPostingType (String PostingType) - { - return m_postingType.equals(PostingType); - } // isPostingType - - /** - * Is converted - * @return true if converted - */ - public boolean isConverted() - { - return m_converted; - } // isConverted - - /** - * Get AcctSchema - * @return AcctSchema - */ - public MAcctSchema getAcctSchema() - { - return m_acctSchema; - } // getAcctSchema - - - /************************************************************************** - * Are the lines Source Balanced - * @return true if source lines balanced - */ - public boolean isSourceBalanced() - { - // No lines -> balanded - if (m_lines.size() == 0) - return true; - BigDecimal balance = getSourceBalance(); - boolean retValue = balance.signum() == 0; - if (retValue) - log.finer(toString()); - else - log.warning ("NO - Diff=" + balance + " - " + toString()); - return retValue; - } // isSourceBalanced - - /** - * Return Source Balance - * @return source balance - */ - protected BigDecimal getSourceBalance() - { - BigDecimal result = Env.ZERO; - for (int i = 0; i < m_lines.size(); i++) - { - FactLine line = (FactLine)m_lines.get(i); - result = result.add (line.getSourceBalance()); - } - // log.fine("getSourceBalance - " + result.toString()); - return result; - } // getSourceBalance - - /** - * Create Source Line for Suspense Balancing. - * Only if Suspense Balancing is enabled and not a multi-currency document - * (double check as otherwise the rule should not have fired) - * If not balanced create balancing entry in currency of the document - * @return FactLine - */ - public FactLine balanceSource() - { - if (!m_acctSchema.isSuspenseBalancing() || m_doc.isMultiCurrency()) - return null; - BigDecimal diff = getSourceBalance(); - log.finer("Diff=" + diff); - - // new line - FactLine line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), - m_doc.get_ID(), 0, m_trxName); - line.setDocumentInfo(m_doc, null); - line.setPostingType(m_postingType); - - // Amount - if (diff.signum() < 0) // negative balance => DR - line.setAmtSource(m_doc.getC_Currency_ID(), diff.abs(), Env.ZERO); - else // positive balance => CR - line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, diff); - - // Account - line.setAccount(m_acctSchema, m_acctSchema.getSuspenseBalancing_Acct()); - - // Convert - line.convert(); - // - log.fine(line.toString()); - m_lines.add(line); - return line; - } // balancingSource - - - /************************************************************************** - * Are all segments balanced - * @return true if segments are balanced - */ - public boolean isSegmentBalanced() - { - if (m_lines.size() == 0) - return true; - - MAcctSchemaElement[] elements = m_acctSchema.getAcctSchemaElements(); - // check all balancing segments - for (int i = 0; i < elements.length; i++) - { - MAcctSchemaElement ase = elements[i]; - if (ase.isBalanced() && !isSegmentBalanced (ase.getElementType())) - return false; - } - return true; - } // isSegmentBalanced - - /** - * Is Source Segment balanced. - * @param segmentType - see AcctSchemaElement.SEGMENT_* - * Implemented only for Org - * Other sensible candidates are Project, User1/2 - * @return true if segments are balanced + private boolean m_converted = false; + + /** Lines */ + private ArrayList m_lines = new ArrayList(); + + + /** + * Dispose + */ + public void dispose() + { + m_lines.clear(); + m_lines = null; + } // dispose + + /** + * Create and convert Fact Line. + * Used to create a DR and/or CR entry + * + * @param docLine the document line or null + * @param account if null, line is not created + * @param C_Currency_ID the currency + * @param debitAmt debit amount, can be null + * @param creditAmt credit amount, can be null + * @return Fact Line + */ + public FactLine createLine (DocLine docLine, MAccount account, + int C_Currency_ID, BigDecimal debitAmt, BigDecimal creditAmt) + { + // log.fine("createLine - " + account + " - Dr=" + debitAmt + ", Cr=" + creditAmt); + + // Data Check + if (account == null) + { + log.info("No account for " + docLine + + ": Amt=" + debitAmt + "/" + creditAmt + + " - " + toString()); + return null; + } + // + FactLine line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), + m_doc.get_ID(), + docLine == null ? 0 : docLine.get_ID(), m_trxName); + // Set Info & Account + line.setDocumentInfo(m_doc, docLine); + line.setPostingType(m_postingType); + line.setAccount(m_acctSchema, account); + + // Amounts - one needs to not zero + if (!line.setAmtSource(C_Currency_ID, debitAmt, creditAmt)) + { + if (docLine == null || docLine.getQty() == null || docLine.getQty().signum() == 0) + { + log.fine("Both amounts & qty = 0/Null - " + docLine + + " - " + toString()); + return null; + } + log.fine("Both amounts = 0/Null, Qty=" + docLine.getQty() + " - " + docLine + + " - " + toString()); + } + // Convert + line.convert(); + // Optionally overwrite Acct Amount + if (docLine != null + && (docLine.getAmtAcctDr() != null || docLine.getAmtAcctCr() != null)) + line.setAmtAcct(docLine.getAmtAcctDr(), docLine.getAmtAcctCr()); + // + log.fine(line.toString()); + add(line); + return line; + } // createLine + + /** + * Add Fact Line + * @param line fact line + */ + void add (FactLine line) + { + m_lines.add(line); + } // add + + /** + * Create and convert Fact Line. + * Used to create either a DR or CR entry + * + * @param docLine Document Line or null + * @param accountDr Account to be used if Amt is DR balance + * @param accountCr Account to be used if Amt is CR balance + * @param C_Currency_ID Currency + * @param Amt if negative Cr else Dr + * @return FactLine + */ + public FactLine createLine (DocLine docLine, MAccount accountDr, MAccount accountCr, + int C_Currency_ID, BigDecimal Amt) + { + if (Amt.signum() < 0) + return createLine (docLine, accountCr, C_Currency_ID, null, Amt.abs()); + else + return createLine (docLine, accountDr, C_Currency_ID, Amt, null); + } // createLine + + /** + * Create and convert Fact Line. + * Used to create either a DR or CR entry + * + * @param docLine Document line or null + * @param account Account to be used + * @param C_Currency_ID Currency + * @param Amt if negative Cr else Dr + * @return FactLine + */ + public FactLine createLine (DocLine docLine, MAccount account, + int C_Currency_ID, BigDecimal Amt) + { + if (Amt.signum() < 0) + return createLine (docLine, account, C_Currency_ID, null, Amt.abs()); + else + return createLine (docLine, account, C_Currency_ID, Amt, null); + } // createLine + + /** + * Is Posting Type + * @param PostingType - see POST_* + * @return true if document is posting type + */ + public boolean isPostingType (String PostingType) + { + return m_postingType.equals(PostingType); + } // isPostingType + + /** + * Is converted + * @return true if converted + */ + public boolean isConverted() + { + return m_converted; + } // isConverted + + /** + * Get AcctSchema + * @return AcctSchema + */ + public MAcctSchema getAcctSchema() + { + return m_acctSchema; + } // getAcctSchema + + + /************************************************************************** + * Are the lines Source Balanced + * @return true if source lines balanced + */ + public boolean isSourceBalanced() + { + // No lines -> balanded + if (m_lines.size() == 0) + return true; + BigDecimal balance = getSourceBalance(); + boolean retValue = balance.signum() == 0; + if (retValue) + log.finer(toString()); + else + log.warning ("NO - Diff=" + balance + " - " + toString()); + return retValue; + } // isSourceBalanced + + /** + * Return Source Balance + * @return source balance + */ + protected BigDecimal getSourceBalance() + { + BigDecimal result = Env.ZERO; + for (int i = 0; i < m_lines.size(); i++) + { + FactLine line = (FactLine)m_lines.get(i); + result = result.add (line.getSourceBalance()); + } + // log.fine("getSourceBalance - " + result.toString()); + return result; + } // getSourceBalance + + /** + * Create Source Line for Suspense Balancing. + * Only if Suspense Balancing is enabled and not a multi-currency document + * (double check as otherwise the rule should not have fired) + * If not balanced create balancing entry in currency of the document + * @return FactLine + */ + public FactLine balanceSource() + { + if (!m_acctSchema.isSuspenseBalancing() || m_doc.isMultiCurrency()) + return null; + BigDecimal diff = getSourceBalance(); + log.finer("Diff=" + diff); + + // new line + FactLine line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), + m_doc.get_ID(), 0, m_trxName); + line.setDocumentInfo(m_doc, null); + line.setPostingType(m_postingType); + + // Amount + if (diff.signum() < 0) // negative balance => DR + line.setAmtSource(m_doc.getC_Currency_ID(), diff.abs(), Env.ZERO); + else // positive balance => CR + line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, diff); + + // Account + line.setAccount(m_acctSchema, m_acctSchema.getSuspenseBalancing_Acct()); + + // Convert + line.convert(); + // + log.fine(line.toString()); + m_lines.add(line); + return line; + } // balancingSource + + + /************************************************************************** + * Are all segments balanced + * @return true if segments are balanced + */ + public boolean isSegmentBalanced() + { + if (m_lines.size() == 0) + return true; + + MAcctSchemaElement[] elements = m_acctSchema.getAcctSchemaElements(); + // check all balancing segments + for (int i = 0; i < elements.length; i++) + { + MAcctSchemaElement ase = elements[i]; + if (ase.isBalanced() && !isSegmentBalanced (ase.getElementType())) + return false; + } + return true; + } // isSegmentBalanced + + /** + * Is Source Segment balanced. + * @param segmentType - see AcctSchemaElement.SEGMENT_* + * Implemented only for Org + * Other sensible candidates are Project, User1/2 + * @return true if segments are balanced */ public boolean isSegmentBalanced (String segmentType) { @@ -323,66 +323,66 @@ public final class Fact { HashMap map = new HashMap(); // Add up values by key - for (int i = 0; i < m_lines.size(); i++) - { - FactLine line = (FactLine)m_lines.get(i); - Integer key = new Integer(line.getAD_Org_ID()); - BigDecimal bal = line.getSourceBalance(); - BigDecimal oldBal = (BigDecimal)map.get(key); - if (oldBal != null) - bal = bal.add(oldBal); - map.put(key, bal); - // System.out.println("Add Key=" + key + ", Bal=" + bal + " <- " + line); - } - // check if all keys are zero - Iterator values = map.values().iterator(); - while (values.hasNext()) - { - BigDecimal bal = (BigDecimal)values.next(); - if (bal.signum() != 0) - { - map.clear(); - log.warning ("(" + segmentType + ") NO - " + toString() + ", Balance=" + bal); - return false; - } - } - map.clear(); - log.finer("(" + segmentType + ") - " + toString()); - return true; - } - log.finer("(" + segmentType + ") (not checked) - " + toString()); - return true; - } // isSegmentBalanced - - /** - * Balance all segments. - * - For all balancing segments - * - For all segment values - * - If balance <> 0 create dueTo/dueFrom line - * overwriting the segment value - */ - public void balanceSegments() - { - MAcctSchemaElement[] elements = m_acctSchema.getAcctSchemaElements(); - // check all balancing segments - for (int i = 0; i < elements.length; i++) - { - MAcctSchemaElement ase = elements[i]; - if (ase.isBalanced()) - balanceSegment (ase.getElementType()); - } - } // balanceSegments - - /** - * Balance Source Segment - * @param elementType segment element type - */ - private void balanceSegment (String elementType) - { - // no lines -> balanced - if (m_lines.size() == 0) - return; - + for (int i = 0; i < m_lines.size(); i++) + { + FactLine line = (FactLine)m_lines.get(i); + Integer key = new Integer(line.getAD_Org_ID()); + BigDecimal bal = line.getSourceBalance(); + BigDecimal oldBal = (BigDecimal)map.get(key); + if (oldBal != null) + bal = bal.add(oldBal); + map.put(key, bal); + // System.out.println("Add Key=" + key + ", Bal=" + bal + " <- " + line); + } + // check if all keys are zero + Iterator values = map.values().iterator(); + while (values.hasNext()) + { + BigDecimal bal = (BigDecimal)values.next(); + if (bal.signum() != 0) + { + map.clear(); + log.warning ("(" + segmentType + ") NO - " + toString() + ", Balance=" + bal); + return false; + } + } + map.clear(); + log.finer("(" + segmentType + ") - " + toString()); + return true; + } + log.finer("(" + segmentType + ") (not checked) - " + toString()); + return true; + } // isSegmentBalanced + + /** + * Balance all segments. + * - For all balancing segments + * - For all segment values + * - If balance <> 0 create dueTo/dueFrom line + * overwriting the segment value + */ + public void balanceSegments() + { + MAcctSchemaElement[] elements = m_acctSchema.getAcctSchemaElements(); + // check all balancing segments + for (int i = 0; i < elements.length; i++) + { + MAcctSchemaElement ase = elements[i]; + if (ase.isBalanced()) + balanceSegment (ase.getElementType()); + } + } // balanceSegments + + /** + * Balance Source Segment + * @param elementType segment element type + */ + private void balanceSegment (String elementType) + { + // no lines -> balanced + if (m_lines.size() == 0) + return; + log.fine ("(" + elementType + ") - " + toString()); // Org @@ -390,471 +390,472 @@ public final class Fact { HashMap map = new HashMap(); // Add up values by key - for (int i = 0; i < m_lines.size(); i++) - { - FactLine line = (FactLine)m_lines.get(i); - Integer key = new Integer(line.getAD_Org_ID()); - // BigDecimal balance = line.getSourceBalance(); - Balance oldBalance = (Balance)map.get(key); - if (oldBalance == null) - { - oldBalance = new Balance (line.getAmtSourceDr(), line.getAmtSourceCr()); - map.put(key, oldBalance); - } - else - oldBalance.add(line.getAmtSourceDr(), line.getAmtSourceCr()); - // log.info ("Key=" + key + ", Balance=" + balance + " - " + line); - } - - // Create entry for non-zero element - Iterator keys = map.keySet().iterator(); - while (keys.hasNext()) - { - Integer key = (Integer)keys.next(); - Balance difference = (Balance)map.get(key); - log.info (elementType + "=" + key + ", " + difference); - // - if (!difference.isZeroBalance()) - { - // Create Balancing Entry - FactLine line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), - m_doc.get_ID(), 0, m_trxName); - line.setDocumentInfo(m_doc, null); - line.setPostingType(m_postingType); - // Amount & Account - if (difference.getBalance().signum() < 0) - { - if (difference.isReversal()) - { - line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, difference.getPostBalance()); - line.setAccount(m_acctSchema, m_acctSchema.getDueTo_Acct(elementType)); - } - else - { - line.setAmtSource(m_doc.getC_Currency_ID(), difference.getPostBalance(), Env.ZERO); - line.setAccount(m_acctSchema, m_acctSchema.getDueFrom_Acct(elementType)); - } - } - else - { - if (difference.isReversal()) - { - line.setAmtSource(m_doc.getC_Currency_ID(), difference.getPostBalance(), Env.ZERO); - line.setAccount(m_acctSchema, m_acctSchema.getDueFrom_Acct(elementType)); - } - else - { - line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, difference.getPostBalance()); - line.setAccount(m_acctSchema, m_acctSchema.getDueTo_Acct(elementType)); - } - } - line.convert(); - line.setAD_Org_ID(key.intValue()); - // - m_lines.add(line); - log.fine("(" + elementType + ") - " + line); - } - } - map.clear(); - } - } // balanceSegment - - - /************************************************************************** - * Are the lines Accounting Balanced - * @return true if accounting lines are balanced - */ - public boolean isAcctBalanced() - { - // no lines -> balanced - if (m_lines.size() == 0) - return true; - BigDecimal balance = getAcctBalance(); - boolean retValue = balance.signum() == 0; - if (retValue) - log.finer(toString()); - else - log.warning("NO - Diff=" + balance + " - " + toString()); - return retValue; - } // isAcctBalanced - - /** - * Return Accounting Balance - * @return true if accounting lines are balanced - */ - protected BigDecimal getAcctBalance() - { - BigDecimal result = Env.ZERO; - for (int i = 0; i < m_lines.size(); i++) - { - FactLine line = (FactLine)m_lines.get(i); - result = result.add(line.getAcctBalance()); - } - // log.fine(result.toString()); - return result; - } // getAcctBalance - - /** - * Balance Accounting Currency. - * If the accounting currency is not balanced, - * if Currency balancing is enabled - * create a new line using the currency balancing account with zero source balance - * or - * adjust the line with the largest balance sheet account - * or if no balance sheet account exist, the line with the largest amount - * @return FactLine - */ - public FactLine balanceAccounting() - { - BigDecimal diff = getAcctBalance(); // DR-CR - log.fine("Balance=" + diff - + ", CurrBal=" + m_acctSchema.isCurrencyBalancing() - + " - " + toString()); - FactLine line = null; - - BigDecimal BSamount = Env.ZERO; - FactLine BSline = null; - BigDecimal PLamount = Env.ZERO; - FactLine PLline = null; - - // Find line biggest BalanceSheet or P&L line - for (int i = 0; i < m_lines.size(); i++) - { - FactLine l = (FactLine)m_lines.get(i); - BigDecimal amt = l.getAcctBalance().abs(); - if (l.isBalanceSheet() && amt.compareTo(BSamount) > 0) - { - BSamount = amt; - BSline = l; - } - else if (!l.isBalanceSheet() && amt.compareTo(PLamount) > 0) - { - PLamount = amt; - PLline = l; - } - } - - // Create Currency Balancing Entry - if (m_acctSchema.isCurrencyBalancing()) - { - line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), - m_doc.get_ID(), 0, m_trxName); - line.setDocumentInfo (m_doc, null); - line.setPostingType (m_postingType); - line.setAccount (m_acctSchema, m_acctSchema.getCurrencyBalancing_Acct()); - - // Amount - line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, Env.ZERO); - line.convert(); - // Accounted - BigDecimal drAmt = Env.ZERO; - BigDecimal crAmt = Env.ZERO; - boolean isDR = diff.signum() < 0; - BigDecimal difference = diff.abs(); - if (isDR) - drAmt = difference; - else - crAmt = difference; - // Switch sides - boolean switchIt = BSline != null - && ((BSline.isDrSourceBalance() && isDR) - || (!BSline.isDrSourceBalance() && !isDR)); - if (switchIt) - { - drAmt = Env.ZERO; - crAmt = Env.ZERO; - if (isDR) - crAmt = difference.negate(); - else - drAmt = difference.negate(); - } - line.setAmtAcct(drAmt, crAmt); - log.fine(line.toString()); - m_lines.add(line); - } - else // Adjust biggest (Balance Sheet) line amount - { - if (BSline != null) - line = BSline; - else - line = PLline; - if (line == null) - log.severe ("No Line found"); - else - { - log.fine("Adjusting Amt=" + diff + "; Line=" + line); - line.currencyCorrect(diff); - log.fine(line.toString()); - } - } // correct biggest amount - - return line; - } // balanceAccounting - - /** - * Check Accounts of Fact Lines - * @return true if success - */ - public boolean checkAccounts() - { - // no lines -> nothing to distribute - if (m_lines.size() == 0) - return true; - - // For all fact lines - for (int i = 0; i < m_lines.size(); i++) - { - FactLine line = (FactLine)m_lines.get(i); - MAccount account = line.getAccount(); - if (account == null) - { - log.warning("No Account for " + line); - return false; - } - MElementValue ev = account.getAccount(); - if (ev == null) - { - log.warning("No Element Value for " + account - + ": " + line); - return false; - } - if (ev.isSummary()) - { - log.warning("Cannot post to Summary Account " + ev - + ": " + line); - return false; - } - if (!ev.isActive()) - { - log.warning("Cannot post to Inactive Account " + ev - + ": " + line); - return false; - } - - } // for all lines - - return true; - } // checkAccounts - - /** - * GL Distribution of Fact Lines - * @return true if success - */ - public boolean distribute() - { - // no lines -> nothing to distribute - if (m_lines.size() == 0) - return true; - - ArrayList newLines = new ArrayList(); - // For all fact lines - for (int i = 0; i < m_lines.size(); i++) - { - FactLine dLine = (FactLine)m_lines.get(i); - MDistribution[] distributions = MDistribution.get (dLine.getAccount(), - m_postingType, m_doc.getC_DocType_ID()); - // No Distribution for this line - if (distributions == null || distributions.length == 0) - continue; - // Just the first - if (distributions.length > 1) - log.warning("More then one Distributiion for " + dLine.getAccount()); - MDistribution distribution = distributions[0]; - // Add Reversal - FactLine reversal = dLine.reverse(distribution.getName()); - log.info("Reversal=" + reversal); - newLines.add(reversal); // saved in postCommit - // Prepare - distribution.distribute(dLine.getAccount(), dLine.getSourceBalance(), dLine.getC_Currency_ID()); - MDistributionLine[] lines = distribution.getLines(false); - for (int j = 0; j < lines.length; j++) - { - MDistributionLine dl = lines[j]; - if (!dl.isActive() || dl.getAmt().signum() == 0) - continue; - FactLine factLine = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), - m_doc.get_ID(), 0, m_trxName); - // Set Info & Account - factLine.setDocumentInfo(m_doc, dLine.getDocLine()); - factLine.setAccount(m_acctSchema, dl.getAccount()); - factLine.setPostingType(m_postingType); - if (dl.isOverwriteOrg()) // set Org explicitly - factLine.setAD_Org_ID(dl.getOrg_ID()); - // - if (dl.getAmt().signum() < 0) - factLine.setAmtSource(dLine.getC_Currency_ID(), null, dl.getAmt().abs()); - else - factLine.setAmtSource(dLine.getC_Currency_ID(), dl.getAmt(), null); - // Convert - factLine.convert(); - // - String description = distribution.getName() + " #" + dl.getLine(); - if (dl.getDescription() != null) - description += " - " + dl.getDescription(); - factLine.addDescription(description); - // - log.info(factLine.toString()); - newLines.add(factLine); - } - } // for all lines - - // Add Lines - for (int i = 0; i < newLines.size(); i++) - m_lines.add(newLines.get(i)); - - return true; - } // distribute - - - /************************************************************************** - * String representation - * @return String - */ - public String toString() - { - StringBuffer sb = new StringBuffer("Fact["); - sb.append(m_doc.toString()); - sb.append(",").append(m_acctSchema.toString()); - sb.append(",PostType=").append(m_postingType); - sb.append("]"); - return sb.toString(); - } // toString - - /** - * Get Lines - * @return FactLine Array - */ - public FactLine[] getLines() - { - FactLine[] temp = new FactLine[m_lines.size()]; - m_lines.toArray(temp); - return temp; - } // getLines - - /** - * Save Fact - * @param trxName transaction - * @return true if all lines were saved - */ - public boolean save (String trxName) - { - // save Lines - for (int i = 0; i < m_lines.size(); i++) - { - FactLine fl = (FactLine)m_lines.get(i); - // log.fine("save - " + fl); - if (!fl.save(trxName)) // abort on first error - return false; - } - return true; - } // commit - - /** - * Get Transaction - * @return trx - */ - public String get_TrxName() - { - return m_trxName; - } // getTrxName - - /** + for (int i = 0; i < m_lines.size(); i++) + { + FactLine line = (FactLine)m_lines.get(i); + Integer key = new Integer(line.getAD_Org_ID()); + // BigDecimal balance = line.getSourceBalance(); + Balance oldBalance = (Balance)map.get(key); + if (oldBalance == null) + { + oldBalance = new Balance (line.getAmtSourceDr(), line.getAmtSourceCr()); + map.put(key, oldBalance); + } + else + oldBalance.add(line.getAmtSourceDr(), line.getAmtSourceCr()); + // log.info ("Key=" + key + ", Balance=" + balance + " - " + line); + } + + // Create entry for non-zero element + Iterator keys = map.keySet().iterator(); + while (keys.hasNext()) + { + Integer key = (Integer)keys.next(); + Balance difference = (Balance)map.get(key); + log.info (elementType + "=" + key + ", " + difference); + // + if (!difference.isZeroBalance()) + { + // Create Balancing Entry + FactLine line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), + m_doc.get_ID(), 0, m_trxName); + line.setDocumentInfo(m_doc, null); + line.setPostingType(m_postingType); + // Amount & Account + if (difference.getBalance().signum() < 0) + { + if (difference.isReversal()) + { + line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, difference.getPostBalance()); + line.setAccount(m_acctSchema, m_acctSchema.getDueTo_Acct(elementType)); + } + else + { + line.setAmtSource(m_doc.getC_Currency_ID(), difference.getPostBalance(), Env.ZERO); + line.setAccount(m_acctSchema, m_acctSchema.getDueFrom_Acct(elementType)); + } + } + else + { + if (difference.isReversal()) + { + line.setAmtSource(m_doc.getC_Currency_ID(), difference.getPostBalance(), Env.ZERO); + line.setAccount(m_acctSchema, m_acctSchema.getDueFrom_Acct(elementType)); + } + else + { + line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, difference.getPostBalance()); + line.setAccount(m_acctSchema, m_acctSchema.getDueTo_Acct(elementType)); + } + } + line.convert(); + line.setAD_Org_ID(key.intValue()); + // + m_lines.add(line); + log.fine("(" + elementType + ") - " + line); + } + } + map.clear(); + } + } // balanceSegment + + + /************************************************************************** + * Are the lines Accounting Balanced + * @return true if accounting lines are balanced + */ + public boolean isAcctBalanced() + { + // no lines -> balanced + if (m_lines.size() == 0) + return true; + BigDecimal balance = getAcctBalance(); + boolean retValue = balance.signum() == 0; + if (retValue) + log.finer(toString()); + else + log.warning("NO - Diff=" + balance + " - " + toString()); + return retValue; + } // isAcctBalanced + + /** + * Return Accounting Balance + * @return true if accounting lines are balanced + */ + protected BigDecimal getAcctBalance() + { + BigDecimal result = Env.ZERO; + for (int i = 0; i < m_lines.size(); i++) + { + FactLine line = (FactLine)m_lines.get(i); + result = result.add(line.getAcctBalance()); + } + // log.fine(result.toString()); + return result; + } // getAcctBalance + + /** + * Balance Accounting Currency. + * If the accounting currency is not balanced, + * if Currency balancing is enabled + * create a new line using the currency balancing account with zero source balance + * or + * adjust the line with the largest balance sheet account + * or if no balance sheet account exist, the line with the largest amount + * @return FactLine + */ + public FactLine balanceAccounting() + { + BigDecimal diff = getAcctBalance(); // DR-CR + log.fine("Balance=" + diff + + ", CurrBal=" + m_acctSchema.isCurrencyBalancing() + + " - " + toString()); + FactLine line = null; + + BigDecimal BSamount = Env.ZERO; + FactLine BSline = null; + BigDecimal PLamount = Env.ZERO; + FactLine PLline = null; + + // Find line biggest BalanceSheet or P&L line + for (int i = 0; i < m_lines.size(); i++) + { + FactLine l = (FactLine)m_lines.get(i); + BigDecimal amt = l.getAcctBalance().abs(); + if (l.isBalanceSheet() && amt.compareTo(BSamount) > 0) + { + BSamount = amt; + BSline = l; + } + else if (!l.isBalanceSheet() && amt.compareTo(PLamount) > 0) + { + PLamount = amt; + PLline = l; + } + } + + // Create Currency Balancing Entry + if (m_acctSchema.isCurrencyBalancing()) + { + line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), + m_doc.get_ID(), 0, m_trxName); + line.setDocumentInfo (m_doc, null); + line.setPostingType (m_postingType); + line.setAccount (m_acctSchema, m_acctSchema.getCurrencyBalancing_Acct()); + + // Amount + line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, Env.ZERO); + line.convert(); + // Accounted + BigDecimal drAmt = Env.ZERO; + BigDecimal crAmt = Env.ZERO; + boolean isDR = diff.signum() < 0; + BigDecimal difference = diff.abs(); + if (isDR) + drAmt = difference; + else + crAmt = difference; + // Switch sides + boolean switchIt = BSline != null + && ((BSline.isDrSourceBalance() && isDR) + || (!BSline.isDrSourceBalance() && !isDR)); + if (switchIt) + { + drAmt = Env.ZERO; + crAmt = Env.ZERO; + if (isDR) + crAmt = difference.negate(); + else + drAmt = difference.negate(); + } + line.setAmtAcct(drAmt, crAmt); + log.fine(line.toString()); + m_lines.add(line); + } + else // Adjust biggest (Balance Sheet) line amount + { + if (BSline != null) + line = BSline; + else + line = PLline; + if (line == null) + log.severe ("No Line found"); + else + { + log.fine("Adjusting Amt=" + diff + "; Line=" + line); + line.currencyCorrect(diff); + log.fine(line.toString()); + } + } // correct biggest amount + + return line; + } // balanceAccounting + + /** + * Check Accounts of Fact Lines + * @return true if success + */ + public boolean checkAccounts() + { + // no lines -> nothing to distribute + if (m_lines.size() == 0) + return true; + + // For all fact lines + for (int i = 0; i < m_lines.size(); i++) + { + FactLine line = (FactLine)m_lines.get(i); + MAccount account = line.getAccount(); + if (account == null) + { + log.warning("No Account for " + line); + return false; + } + MElementValue ev = account.getAccount(); + if (ev == null) + { + log.warning("No Element Value for " + account + + ": " + line); + return false; + } + if (ev.isSummary()) + { + log.warning("Cannot post to Summary Account " + ev + + ": " + line); + return false; + } + if (!ev.isActive()) + { + log.warning("Cannot post to Inactive Account " + ev + + ": " + line); + return false; + } + + } // for all lines + + return true; + } // checkAccounts + + /** + * GL Distribution of Fact Lines + * @return true if success + */ + public boolean distribute() + { + // no lines -> nothing to distribute + if (m_lines.size() == 0) + return true; + + ArrayList newLines = new ArrayList(); + // For all fact lines + for (int i = 0; i < m_lines.size(); i++) + { + FactLine dLine = (FactLine)m_lines.get(i); + MDistribution[] distributions = MDistribution.get (dLine.getAccount(), + m_postingType, m_doc.getC_DocType_ID()); + // No Distribution for this line + if (distributions == null || distributions.length == 0) + continue; + // Just the first + if (distributions.length > 1) + log.warning("More then one Distributiion for " + dLine.getAccount()); + MDistribution distribution = distributions[0]; + // Add Reversal + FactLine reversal = dLine.reverse(distribution.getName()); + log.info("Reversal=" + reversal); + newLines.add(reversal); // saved in postCommit + // Prepare + distribution.distribute(dLine.getAccount(), dLine.getSourceBalance(), dLine.getC_Currency_ID()); + MDistributionLine[] lines = distribution.getLines(false); + for (int j = 0; j < lines.length; j++) + { + MDistributionLine dl = lines[j]; + if (!dl.isActive() || dl.getAmt().signum() == 0) + continue; + FactLine factLine = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(), + m_doc.get_ID(), 0, m_trxName); + // Set Info & Account + factLine.setDocumentInfo(m_doc, dLine.getDocLine()); + factLine.setAccount(m_acctSchema, dl.getAccount()); + factLine.setPostingType(m_postingType); + if (dl.isOverwriteOrg()) // set Org explicitly + factLine.setAD_Org_ID(dl.getOrg_ID()); + // + if (dl.getAmt().signum() < 0) + factLine.setAmtSource(dLine.getC_Currency_ID(), null, dl.getAmt().abs()); + else + factLine.setAmtSource(dLine.getC_Currency_ID(), dl.getAmt(), null); + // Convert + factLine.convert(); + // + String description = distribution.getName() + " #" + dl.getLine(); + if (dl.getDescription() != null) + description += " - " + dl.getDescription(); + factLine.addDescription(description); + // + log.info(factLine.toString()); + newLines.add(factLine); + } + } // for all lines + + // Add Lines + for (int i = 0; i < newLines.size(); i++) + m_lines.add(newLines.get(i)); + + return true; + } // distribute + + + /************************************************************************** + * String representation + * @return String + */ + public String toString() + { + StringBuffer sb = new StringBuffer("Fact["); + sb.append(m_doc.toString()); + sb.append(",").append(m_acctSchema.toString()); + sb.append(",PostType=").append(m_postingType); + sb.append("]"); + return sb.toString(); + } // toString + + /** + * Get Lines + * @return FactLine Array + */ + public FactLine[] getLines() + { + FactLine[] temp = new FactLine[m_lines.size()]; + m_lines.toArray(temp); + return temp; + } // getLines + + /** + * Save Fact + * @param trxName transaction + * @return true if all lines were saved + */ + public boolean save (String trxName) + { + // save Lines + for (int i = 0; i < m_lines.size(); i++) + { + FactLine fl = (FactLine)m_lines.get(i); + // log.fine("save - " + fl); + if (!fl.save(trxName)) // abort on first error + return false; + } + return true; + } // commit + + /** + * Get Transaction + * @return trx + */ + public String get_TrxName() + { + return m_trxName; + } // getTrxName + + /** * Set Transaction name * @param trxName */ + @SuppressWarnings("unused") private void set_TrxName(String trxName) { m_trxName = trxName; - } // set_TrxName - - /** - * Fact Balance Utility - * - * @author Jorg Janke - * @version $Id: Fact.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $ - */ - public class Balance - { - /** - * New Balance - * @param dr DR - * @param cr CR - */ - public Balance (BigDecimal dr, BigDecimal cr) - { - DR = dr; - CR = cr; - } - - /** DR Amount */ - public BigDecimal DR = Env.ZERO; - /** CR Amount */ - public BigDecimal CR = Env.ZERO; - - /** - * Add - * @param dr DR - * @param cr CR - */ - public void add (BigDecimal dr, BigDecimal cr) - { - DR = DR.add(dr); - CR = CR.add(cr); - } - - /** - * Get Balance - * @return balance - */ - public BigDecimal getBalance() - { - return DR.subtract(CR); - } // getBalance - - /** - * Get Post Balance - * @return absolute balance - negative if reversal - */ - public BigDecimal getPostBalance() - { - BigDecimal bd = getBalance().abs(); - if (isReversal()) - return bd.negate(); - return bd; - } // getPostBalance - - /** - * Zero Balance - * @return true if 0 - */ - public boolean isZeroBalance() - { - return getBalance().signum() == 0; - } // isZeroBalance - - /** - * Reversal - * @return true if both DR/CR are negative or zero - */ - public boolean isReversal() - { - return DR.signum() <= 0 && CR.signum() <= 0; - } // isReversal - - /** - * String Representation - * @return info - */ - public String toString () - { - StringBuffer sb = new StringBuffer ("Balance["); - sb.append ("DR=").append(DR) - .append ("-CR=").append(CR) - .append(" = ").append(getBalance()) - .append ("]"); - return sb.toString (); - } // toString - - } // Balance - -} // Fact + } // set_TrxName + + /** + * Fact Balance Utility + * + * @author Jorg Janke + * @version $Id: Fact.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $ + */ + public class Balance + { + /** + * New Balance + * @param dr DR + * @param cr CR + */ + public Balance (BigDecimal dr, BigDecimal cr) + { + DR = dr; + CR = cr; + } + + /** DR Amount */ + public BigDecimal DR = Env.ZERO; + /** CR Amount */ + public BigDecimal CR = Env.ZERO; + + /** + * Add + * @param dr DR + * @param cr CR + */ + public void add (BigDecimal dr, BigDecimal cr) + { + DR = DR.add(dr); + CR = CR.add(cr); + } + + /** + * Get Balance + * @return balance + */ + public BigDecimal getBalance() + { + return DR.subtract(CR); + } // getBalance + + /** + * Get Post Balance + * @return absolute balance - negative if reversal + */ + public BigDecimal getPostBalance() + { + BigDecimal bd = getBalance().abs(); + if (isReversal()) + return bd.negate(); + return bd; + } // getPostBalance + + /** + * Zero Balance + * @return true if 0 + */ + public boolean isZeroBalance() + { + return getBalance().signum() == 0; + } // isZeroBalance + + /** + * Reversal + * @return true if both DR/CR are negative or zero + */ + public boolean isReversal() + { + return DR.signum() <= 0 && CR.signum() <= 0; + } // isReversal + + /** + * String Representation + * @return info + */ + public String toString () + { + StringBuffer sb = new StringBuffer ("Balance["); + sb.append ("DR=").append(DR) + .append ("-CR=").append(CR) + .append(" = ").append(getBalance()) + .append ("]"); + return sb.toString (); + } // toString + + } // Balance + +} // Fact diff --git a/serverRoot/src/main/server/org/compiere/acct/FactLine.java b/serverRoot/src/main/server/org/compiere/acct/FactLine.java index 343364b561..f009b4366e 100644 --- a/serverRoot/src/main/server/org/compiere/acct/FactLine.java +++ b/serverRoot/src/main/server/org/compiere/acct/FactLine.java @@ -3,947 +3,988 @@ * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * - * by the Free Software Foundation. This program is distributed in the hope * - * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * - * For the text or an alternative of this public license, you may reach us * - * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * - * or via info@compiere.org or http://www.compiere.org/license.html * - *****************************************************************************/ -package org.compiere.acct; - -import java.math.*; -import java.sql.*; -import java.util.*; -import java.util.logging.*; -import org.compiere.model.*; -import org.compiere.util.*; - -/** - * Accounting Fact Entry. - * - * @author Jorg Janke - * @version $Id: FactLine.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $ - */ -public final class FactLine extends X_Fact_Acct -{ - /** - * Constructor - * @param ctx context - * @param AD_Table_ID - Table of Document Source - * @param Record_ID - Record of document - * @param Line_ID - Optional line id - * @param trxName transaction - */ - public FactLine (Properties ctx, int AD_Table_ID, int Record_ID, int Line_ID, String trxName) - { - super(ctx, 0, trxName); - setAD_Client_ID(0); // do not derive - setAD_Org_ID(0); // do not derive - // - setAmtAcctCr (Env.ZERO); - setAmtAcctDr (Env.ZERO); - setAmtSourceCr (Env.ZERO); - setAmtSourceDr (Env.ZERO); - // Log.trace(this,Log.l1_User, "FactLine " + AD_Table_ID + ":" + Record_ID); - setAD_Table_ID (AD_Table_ID); - setRecord_ID (Record_ID); - setLine_ID (Line_ID); - } // FactLine - - /** Account */ - private MAccount m_acct = null; - /** Accounting Schema */ - private MAcctSchema m_acctSchema = null; - /** Document Header */ - private Doc m_doc = null; - /** Document Line */ - private DocLine m_docLine = null; - - /** - * Create Reversal (negate DR/CR) of the line - * @param description new description - * @return reversal line - */ - public FactLine reverse (String description) - { - FactLine reversal = new FactLine (getCtx(), getAD_Table_ID(), getRecord_ID(), getLine_ID(), get_TrxName()); - reversal.setClientOrg(this); // needs to be set explicitly - reversal.setDocumentInfo(m_doc, m_docLine); - reversal.setAccount(m_acctSchema, m_acct); - reversal.setPostingType(getPostingType()); - // - reversal.setAmtSource(getC_Currency_ID(), getAmtSourceDr().negate(), getAmtSourceCr().negate()); - reversal.convert(); - reversal.setDescription(description); - return reversal; - } // reverse - - /** - * Create Accrual (flip CR/DR) of the line - * @param description new description - * @return accrual line - */ - public FactLine accrue (String description) - { - FactLine accrual = new FactLine (getCtx(), getAD_Table_ID(), getRecord_ID(), getLine_ID(), get_TrxName()); - accrual.setClientOrg(this); // needs to be set explicitly - accrual.setDocumentInfo(m_doc, m_docLine); - accrual.setAccount(m_acctSchema, m_acct); - accrual.setPostingType(getPostingType()); - // - accrual.setAmtSource(getC_Currency_ID(), getAmtSourceCr(), getAmtSourceDr()); - accrual.convert(); - accrual.setDescription(description); - return accrual; - } // reverse - - /** - * Set Account Info - * @param acctSchema account schema - * @param acct account - */ - public void setAccount (MAcctSchema acctSchema, MAccount acct) - { - m_acctSchema = acctSchema; - setC_AcctSchema_ID (acctSchema.getC_AcctSchema_ID()); - // - m_acct = acct; - if (getAD_Client_ID() == 0) + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.compiere.acct; + +import java.math.*; +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * Accounting Fact Entry. + * + * @author Jorg Janke + * @version $Id: FactLine.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $ + */ +public final class FactLine extends X_Fact_Acct +{ + /** + * Constructor + * @param ctx context + * @param AD_Table_ID - Table of Document Source + * @param Record_ID - Record of document + * @param Line_ID - Optional line id + * @param trxName transaction + */ + public FactLine (Properties ctx, int AD_Table_ID, int Record_ID, int Line_ID, String trxName) + { + super(ctx, 0, trxName); + setAD_Client_ID(0); // do not derive + setAD_Org_ID(0); // do not derive + // + setAmtAcctCr (Env.ZERO); + setAmtAcctDr (Env.ZERO); + setAmtSourceCr (Env.ZERO); + setAmtSourceDr (Env.ZERO); + // Log.trace(this,Log.l1_User, "FactLine " + AD_Table_ID + ":" + Record_ID); + setAD_Table_ID (AD_Table_ID); + setRecord_ID (Record_ID); + setLine_ID (Line_ID); + } // FactLine + + /** Account */ + private MAccount m_acct = null; + /** Accounting Schema */ + private MAcctSchema m_acctSchema = null; + /** Document Header */ + private Doc m_doc = null; + /** Document Line */ + private DocLine m_docLine = null; + + /** + * Create Reversal (negate DR/CR) of the line + * @param description new description + * @return reversal line + */ + public FactLine reverse (String description) + { + FactLine reversal = new FactLine (getCtx(), getAD_Table_ID(), getRecord_ID(), getLine_ID(), get_TrxName()); + reversal.setClientOrg(this); // needs to be set explicitly + reversal.setDocumentInfo(m_doc, m_docLine); + reversal.setAccount(m_acctSchema, m_acct); + reversal.setPostingType(getPostingType()); + // + reversal.setAmtSource(getC_Currency_ID(), getAmtSourceDr().negate(), getAmtSourceCr().negate()); + reversal.convert(); + reversal.setDescription(description); + return reversal; + } // reverse + + /** + * Create Accrual (flip CR/DR) of the line + * @param description new description + * @return accrual line + */ + public FactLine accrue (String description) + { + FactLine accrual = new FactLine (getCtx(), getAD_Table_ID(), getRecord_ID(), getLine_ID(), get_TrxName()); + accrual.setClientOrg(this); // needs to be set explicitly + accrual.setDocumentInfo(m_doc, m_docLine); + accrual.setAccount(m_acctSchema, m_acct); + accrual.setPostingType(getPostingType()); + // + accrual.setAmtSource(getC_Currency_ID(), getAmtSourceCr(), getAmtSourceDr()); + accrual.convert(); + accrual.setDescription(description); + return accrual; + } // reverse + + /** + * Set Account Info + * @param acctSchema account schema + * @param acct account + */ + public void setAccount (MAcctSchema acctSchema, MAccount acct) + { + m_acctSchema = acctSchema; + setC_AcctSchema_ID (acctSchema.getC_AcctSchema_ID()); + // + m_acct = acct; + if (getAD_Client_ID() == 0) setAD_Client_ID(m_acct.getAD_Client_ID()); setAccount_ID (m_acct.getAccount_ID()); setC_SubAcct_ID(m_acct.getC_SubAcct_ID()); + + // User Defined References + MAcctSchemaElement ud1 = m_acctSchema.getAcctSchemaElement( + X_C_AcctSchema_Element.ELEMENTTYPE_UserElement1); + if (ud1 != null) + { + String ColumnName1 = ud1.getDisplayColumnName(); + if (ColumnName1 != null) + { + int ID1 = 0; + if (m_docLine != null) + ID1 = m_docLine.getValue(ColumnName1); + if (ID1 == 0) + { + if (m_doc == null) + throw new IllegalArgumentException("Document not set yet"); + ID1 = m_doc.getValue(ColumnName1); + } + if (ID1 != 0) + setUserElement1_ID(ID1); + } + } + MAcctSchemaElement ud2 = m_acctSchema.getAcctSchemaElement( + X_C_AcctSchema_Element.ELEMENTTYPE_UserElement2); + if (ud2 != null) + { + String ColumnName2 = ud2.getDisplayColumnName(); + if (ColumnName2 != null) + { + int ID2 = 0; + if (m_docLine != null) + ID2 = m_docLine.getValue(ColumnName2); + if (ID2 == 0) + { + if (m_doc == null) + throw new IllegalArgumentException("Document not set yet"); + ID2 = m_doc.getValue(ColumnName2); + } + if (ID2 != 0) + setUserElement2_ID(ID2); + } + } } // setAccount /** - * Set Source Amounts - * @param C_Currency_ID currency - * @param AmtSourceDr source amount dr - * @param AmtSourceCr source amount cr - * @return true, if any if the amount is not zero - */ - public boolean setAmtSource (int C_Currency_ID, BigDecimal AmtSourceDr, BigDecimal AmtSourceCr) - { - setC_Currency_ID (C_Currency_ID); - if (AmtSourceDr != null) - setAmtSourceDr (AmtSourceDr); - if (AmtSourceCr != null) - setAmtSourceCr (AmtSourceCr); - // one needs to be non zero - if (getAmtSourceDr().equals(Env.ZERO) && getAmtSourceCr().equals(Env.ZERO)) - return false; - // Currency Precision - int precision = MCurrency.getStdPrecision(getCtx(), C_Currency_ID); - if (AmtSourceDr != null && AmtSourceDr.scale() > precision) - { - BigDecimal AmtSourceDr1 = AmtSourceDr.setScale(precision, BigDecimal.ROUND_HALF_UP); - log.warning("Source DR Precision " + AmtSourceDr + " -> " + AmtSourceDr1); - setAmtSourceDr(AmtSourceDr1); - } - if (AmtSourceCr != null && AmtSourceCr.scale() > precision) - { - BigDecimal AmtSourceCr1 = AmtSourceCr.setScale(precision, BigDecimal.ROUND_HALF_UP); - log.warning("Source CR Precision " + AmtSourceCr + " -> " + AmtSourceCr1); - setAmtSourceCr(AmtSourceCr1); - } - return true; - } // setAmtSource - - /** - * Set Accounted Amounts (alternative: call convert) - * @param AmtAcctDr acct amount dr - * @param AmtAcctCr acct amount cr - */ - public void setAmtAcct(BigDecimal AmtAcctDr, BigDecimal AmtAcctCr) - { - setAmtAcctDr (AmtAcctDr); - setAmtAcctCr (AmtAcctCr); - } // setAmtAcct - - /** - * Set Document Info - * @param doc document - * @param docLine doc line - */ - public void setDocumentInfo(Doc doc, DocLine docLine) - { - m_doc = doc; - m_docLine = docLine; - // reset - setAD_Org_ID(0); - setC_SalesRegion_ID(0); - // Client - if (getAD_Client_ID() == 0) - setAD_Client_ID (m_doc.getAD_Client_ID()); - // Date Trx - setDateTrx (m_doc.getDateDoc()); - if (m_docLine != null && m_docLine.getDateDoc() != null) - setDateTrx (m_docLine.getDateDoc()); - // Date Acct - setDateAcct (m_doc.getDateAcct()); - if (m_docLine != null && m_docLine.getDateAcct() != null) - setDateAcct (m_docLine.getDateAcct()); - // Period, Tax - if (m_docLine != null && m_docLine.getC_Period_ID() != 0) - setC_Period_ID(m_docLine.getC_Period_ID()); - else - setC_Period_ID (m_doc.getC_Period_ID()); - if (m_docLine != null) - setC_Tax_ID (m_docLine.getC_Tax_ID()); - // Description - StringBuffer description = new StringBuffer(m_doc.getDocumentNo()); - if (m_docLine != null) - { - description.append(" #").append(m_docLine.getLine()); - if (m_docLine.getDescription() != null) - description.append(" (").append(m_docLine.getDescription()).append(")"); - else if (m_doc.getDescription() != null && m_doc.getDescription().length() > 0) - description.append(" (").append(m_doc.getDescription()).append(")"); - } - else if (m_doc.getDescription() != null && m_doc.getDescription().length() > 0) - description.append(" (").append(m_doc.getDescription()).append(")"); - setDescription(description.toString()); - // Journal Info - setGL_Budget_ID (m_doc.getGL_Budget_ID()); - setGL_Category_ID (m_doc.getGL_Category_ID()); - - // Product - if (m_docLine != null) - setM_Product_ID (m_docLine.getM_Product_ID()); - if (getM_Product_ID() == 0) - setM_Product_ID (m_doc.getM_Product_ID()); - // UOM - if (m_docLine != null) - setC_UOM_ID (m_docLine.getC_UOM_ID()); - // Qty - if (get_Value("Qty") == null) // not previously set - { - setQty (m_doc.getQty()); // neg = outgoing - if (m_docLine != null) - setQty (m_docLine.getQty()); - } - - // Loc From (maybe set earlier) - if (getC_LocFrom_ID() == 0 && m_docLine != null) - setC_LocFrom_ID (m_docLine.getC_LocFrom_ID()); - if (getC_LocFrom_ID() == 0) - setC_LocFrom_ID (m_doc.getC_LocFrom_ID()); - // Loc To (maybe set earlier) - if (getC_LocTo_ID() == 0 && m_docLine != null) - setC_LocTo_ID (m_docLine.getC_LocTo_ID()); - if (getC_LocTo_ID() == 0) - setC_LocTo_ID (m_doc.getC_LocTo_ID()); - // BPartner - if (m_docLine != null) - setC_BPartner_ID (m_docLine.getC_BPartner_ID()); - if (getC_BPartner_ID() == 0) - setC_BPartner_ID (m_doc.getC_BPartner_ID()); - // Sales Region from BPLocation/Sales Rep - // Trx Org - if (m_docLine != null) - setAD_OrgTrx_ID (m_docLine.getAD_OrgTrx_ID()); - if (getAD_OrgTrx_ID() == 0) - setAD_OrgTrx_ID (m_doc.getAD_OrgTrx_ID()); - // Project - if (m_docLine != null) - setC_Project_ID (m_docLine.getC_Project_ID()); - if (getC_Project_ID() == 0) - setC_Project_ID (m_doc.getC_Project_ID()); - // Campaign - if (m_docLine != null) - setC_Campaign_ID (m_docLine.getC_Campaign_ID()); - if (getC_Campaign_ID() == 0) - setC_Campaign_ID (m_doc.getC_Campaign_ID()); - // Activity - if (m_docLine != null) - setC_Activity_ID (m_docLine.getC_Activity_ID()); - if (getC_Activity_ID() == 0) - setC_Activity_ID (m_doc.getC_Activity_ID()); - // User List 1 - if (m_docLine != null) - setUser1_ID (m_docLine.getUser1_ID()); - if (getUser1_ID() == 0) - setUser1_ID (m_doc.getUser1_ID()); - // User List 2 - if (m_docLine != null) + * Set Source Amounts + * @param C_Currency_ID currency + * @param AmtSourceDr source amount dr + * @param AmtSourceCr source amount cr + * @return true, if any if the amount is not zero + */ + public boolean setAmtSource (int C_Currency_ID, BigDecimal AmtSourceDr, BigDecimal AmtSourceCr) + { + setC_Currency_ID (C_Currency_ID); + if (AmtSourceDr != null) + setAmtSourceDr (AmtSourceDr); + if (AmtSourceCr != null) + setAmtSourceCr (AmtSourceCr); + // one needs to be non zero + if (getAmtSourceDr().equals(Env.ZERO) && getAmtSourceCr().equals(Env.ZERO)) + return false; + // Currency Precision + int precision = MCurrency.getStdPrecision(getCtx(), C_Currency_ID); + if (AmtSourceDr != null && AmtSourceDr.scale() > precision) + { + BigDecimal AmtSourceDr1 = AmtSourceDr.setScale(precision, BigDecimal.ROUND_HALF_UP); + log.warning("Source DR Precision " + AmtSourceDr + " -> " + AmtSourceDr1); + setAmtSourceDr(AmtSourceDr1); + } + if (AmtSourceCr != null && AmtSourceCr.scale() > precision) + { + BigDecimal AmtSourceCr1 = AmtSourceCr.setScale(precision, BigDecimal.ROUND_HALF_UP); + log.warning("Source CR Precision " + AmtSourceCr + " -> " + AmtSourceCr1); + setAmtSourceCr(AmtSourceCr1); + } + return true; + } // setAmtSource + + /** + * Set Accounted Amounts (alternative: call convert) + * @param AmtAcctDr acct amount dr + * @param AmtAcctCr acct amount cr + */ + public void setAmtAcct(BigDecimal AmtAcctDr, BigDecimal AmtAcctCr) + { + setAmtAcctDr (AmtAcctDr); + setAmtAcctCr (AmtAcctCr); + } // setAmtAcct + + /** + * Set Document Info + * @param doc document + * @param docLine doc line + */ + public void setDocumentInfo(Doc doc, DocLine docLine) + { + m_doc = doc; + m_docLine = docLine; + // reset + setAD_Org_ID(0); + setC_SalesRegion_ID(0); + // Client + if (getAD_Client_ID() == 0) + setAD_Client_ID (m_doc.getAD_Client_ID()); + // Date Trx + setDateTrx (m_doc.getDateDoc()); + if (m_docLine != null && m_docLine.getDateDoc() != null) + setDateTrx (m_docLine.getDateDoc()); + // Date Acct + setDateAcct (m_doc.getDateAcct()); + if (m_docLine != null && m_docLine.getDateAcct() != null) + setDateAcct (m_docLine.getDateAcct()); + // Period, Tax + if (m_docLine != null && m_docLine.getC_Period_ID() != 0) + setC_Period_ID(m_docLine.getC_Period_ID()); + else + setC_Period_ID (m_doc.getC_Period_ID()); + if (m_docLine != null) + setC_Tax_ID (m_docLine.getC_Tax_ID()); + // Description + StringBuffer description = new StringBuffer(m_doc.getDocumentNo()); + if (m_docLine != null) + { + description.append(" #").append(m_docLine.getLine()); + if (m_docLine.getDescription() != null) + description.append(" (").append(m_docLine.getDescription()).append(")"); + else if (m_doc.getDescription() != null && m_doc.getDescription().length() > 0) + description.append(" (").append(m_doc.getDescription()).append(")"); + } + else if (m_doc.getDescription() != null && m_doc.getDescription().length() > 0) + description.append(" (").append(m_doc.getDescription()).append(")"); + setDescription(description.toString()); + // Journal Info + setGL_Budget_ID (m_doc.getGL_Budget_ID()); + setGL_Category_ID (m_doc.getGL_Category_ID()); + + // Product + if (m_docLine != null) + setM_Product_ID (m_docLine.getM_Product_ID()); + if (getM_Product_ID() == 0) + setM_Product_ID (m_doc.getM_Product_ID()); + // UOM + if (m_docLine != null) + setC_UOM_ID (m_docLine.getC_UOM_ID()); + // Qty + if (get_Value("Qty") == null) // not previously set + { + setQty (m_doc.getQty()); // neg = outgoing + if (m_docLine != null) + setQty (m_docLine.getQty()); + } + + // Loc From (maybe set earlier) + if (getC_LocFrom_ID() == 0 && m_docLine != null) + setC_LocFrom_ID (m_docLine.getC_LocFrom_ID()); + if (getC_LocFrom_ID() == 0) + setC_LocFrom_ID (m_doc.getC_LocFrom_ID()); + // Loc To (maybe set earlier) + if (getC_LocTo_ID() == 0 && m_docLine != null) + setC_LocTo_ID (m_docLine.getC_LocTo_ID()); + if (getC_LocTo_ID() == 0) + setC_LocTo_ID (m_doc.getC_LocTo_ID()); + // BPartner + if (m_docLine != null) + setC_BPartner_ID (m_docLine.getC_BPartner_ID()); + if (getC_BPartner_ID() == 0) + setC_BPartner_ID (m_doc.getC_BPartner_ID()); + // Sales Region from BPLocation/Sales Rep + // Trx Org + if (m_docLine != null) + setAD_OrgTrx_ID (m_docLine.getAD_OrgTrx_ID()); + if (getAD_OrgTrx_ID() == 0) + setAD_OrgTrx_ID (m_doc.getAD_OrgTrx_ID()); + // Project + if (m_docLine != null) + setC_Project_ID (m_docLine.getC_Project_ID()); + if (getC_Project_ID() == 0) + setC_Project_ID (m_doc.getC_Project_ID()); + // Campaign + if (m_docLine != null) + setC_Campaign_ID (m_docLine.getC_Campaign_ID()); + if (getC_Campaign_ID() == 0) + setC_Campaign_ID (m_doc.getC_Campaign_ID()); + // Activity + if (m_docLine != null) + setC_Activity_ID (m_docLine.getC_Activity_ID()); + if (getC_Activity_ID() == 0) + setC_Activity_ID (m_doc.getC_Activity_ID()); + // User List 1 + if (m_docLine != null) + setUser1_ID (m_docLine.getUser1_ID()); + if (getUser1_ID() == 0) + setUser1_ID (m_doc.getUser1_ID()); + // User List 2 + if (m_docLine != null) setUser2_ID (m_docLine.getUser2_ID()); if (getUser2_ID() == 0) setUser2_ID (m_doc.getUser2_ID()); - // User Defined - + // References in setAccount } // setDocumentInfo /** - * Get Document Line - * @return doc line - */ - protected DocLine getDocLine() - { - return m_docLine; - } // getDocLine - - /** - * Set Description - * @param description description - */ - public void addDescription (String description) - { - String original = getDescription(); - if (original == null || original.trim().length() == 0) - super.setDescription(description); - else - super.setDescription(original + " - " + description); - } // addDescription - - /** - * Set Warehouse Locator. - * - will overwrite Organization - - * @param M_Locator_ID locator - */ - public void setM_Locator_ID (int M_Locator_ID) - { - super.setM_Locator_ID (M_Locator_ID); - setAD_Org_ID(0); // reset - } // setM_Locator_ID - - - /************************************************************************** - * Set Location - * @param C_Location_ID location - * @param isFrom from - */ - public void setLocation (int C_Location_ID, boolean isFrom) - { - if (isFrom) - setC_LocFrom_ID (C_Location_ID); - else - setC_LocTo_ID (C_Location_ID); - } // setLocator - - /** - * Set Location from Locator - * @param M_Locator_ID locator - * @param isFrom from - */ - public void setLocationFromLocator (int M_Locator_ID, boolean isFrom) - { - if (M_Locator_ID == 0) - return; - int C_Location_ID = 0; - String sql = "SELECT w.C_Location_ID FROM M_Warehouse w, M_Locator l " - + "WHERE w.M_Warehouse_ID=l.M_Warehouse_ID AND l.M_Locator_ID=?"; - try - { - PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); - pstmt.setInt(1, M_Locator_ID); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - C_Location_ID = rs.getInt(1); - rs.close(); - pstmt.close(); - } - catch (SQLException e) - { - log.log(Level.SEVERE, sql, e); - return; - } - if (C_Location_ID != 0) - setLocation (C_Location_ID, isFrom); - } // setLocationFromLocator - - /** - * Set Location from Busoness Partner Location - * @param C_BPartner_Location_ID bp location - * @param isFrom from - */ - public void setLocationFromBPartner (int C_BPartner_Location_ID, boolean isFrom) - { - if (C_BPartner_Location_ID == 0) - return; - int C_Location_ID = 0; - String sql = "SELECT C_Location_ID FROM C_BPartner_Location WHERE C_BPartner_Location_ID=?"; - try - { - PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); - pstmt.setInt(1, C_BPartner_Location_ID); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - C_Location_ID = rs.getInt(1); - rs.close(); - pstmt.close(); - } - catch (SQLException e) - { - log.log(Level.SEVERE, sql, e); - return; - } - if (C_Location_ID != 0) - setLocation (C_Location_ID, isFrom); - } // setLocationFromBPartner - - /** - * Set Location from Organization - * @param AD_Org_ID org - * @param isFrom from - */ - public void setLocationFromOrg (int AD_Org_ID, boolean isFrom) - { - if (AD_Org_ID == 0) - return; - int C_Location_ID = 0; - String sql = "SELECT C_Location_ID FROM AD_OrgInfo WHERE AD_Org_ID=?"; - try - { - PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); - pstmt.setInt(1, AD_Org_ID); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - C_Location_ID = rs.getInt(1); - rs.close(); - pstmt.close(); - } - catch (SQLException e) - { - log.log(Level.SEVERE, sql, e); - return; - } - if (C_Location_ID != 0) - setLocation (C_Location_ID, isFrom); - } // setLocationFromOrg - - - /************************************************************************** - * Returns Source Balance of line - * @return source balance - */ - public BigDecimal getSourceBalance() - { - if (getAmtSourceDr() == null) - setAmtSourceDr (Env.ZERO); - if (getAmtSourceCr() == null) - setAmtSourceCr (Env.ZERO); - // - return getAmtSourceDr().subtract(getAmtSourceCr()); - } // getSourceBalance - - /** - * Is Debit Source Balance - * @return true if DR source balance - */ - public boolean isDrSourceBalance() - { - return getSourceBalance().signum() != -1; - } // isDrSourceBalance - - /** - * Get Accounted Balance - * @return accounting balance - */ - public BigDecimal getAcctBalance() - { - if (getAmtAcctDr() == null) - setAmtAcctDr (Env.ZERO); - if (getAmtAcctCr() == null) - setAmtAcctCr (Env.ZERO); - return getAmtAcctDr().subtract(getAmtAcctCr()); - } // getAcctBalance - - /** - * Is Account on Balance Sheet - * @return true if account is a balance sheet account - */ - public boolean isBalanceSheet() - { - return m_acct.isBalanceSheet(); - } // isBalanceSheet - - /** - * Currect Accounting Amount. - *
-	 *  Example:    1       -1      1       -1
-	 *  Old         100/0   100/0   0/100   0/100
-	 *  New         99/0    101/0   0/99    0/101
-	 *  
- * @param deltaAmount delta amount - */ - public void currencyCorrect (BigDecimal deltaAmount) - { - boolean negative = deltaAmount.compareTo(Env.ZERO) < 0; - boolean adjustDr = getAmtAcctDr().abs().compareTo(getAmtAcctCr().abs()) > 0; - - log.fine(deltaAmount.toString() - + "; Old-AcctDr=" + getAmtAcctDr() + ",AcctCr=" + getAmtAcctCr() - + "; Negative=" + negative + "; AdjustDr=" + adjustDr); - - if (adjustDr) - if (negative) - setAmtAcctDr (getAmtAcctDr().subtract(deltaAmount)); - else - setAmtAcctDr (getAmtAcctDr().subtract(deltaAmount)); - else - if (negative) - setAmtAcctCr (getAmtAcctCr().add(deltaAmount)); - else - setAmtAcctCr (getAmtAcctCr().add(deltaAmount)); - - log.fine("New-AcctDr=" + getAmtAcctDr() + ",AcctCr=" + getAmtAcctCr()); - } // currencyCorrect - - /** - * Convert to Accounted Currency - * @return true if converted - */ - public boolean convert () - { - // Document has no currency - if (getC_Currency_ID() == Doc.NO_CURRENCY) - setC_Currency_ID (m_acctSchema.getC_Currency_ID()); - - if (m_acctSchema.getC_Currency_ID() == getC_Currency_ID()) - { - setAmtAcctDr (getAmtSourceDr()); - setAmtAcctCr (getAmtSourceCr()); - return true; - } - // Get Conversion Type from Line or Header - int C_ConversionType_ID = 0; - int AD_Org_ID = 0; - if (m_docLine != null) // get from line - { - C_ConversionType_ID = m_docLine.getC_ConversionType_ID(); - AD_Org_ID = m_docLine.getAD_Org_ID(); - } - if (C_ConversionType_ID == 0) // get from header - { - if (m_doc == null) - { - log.severe ("No Document VO"); - return false; - } - C_ConversionType_ID = m_doc.getC_ConversionType_ID(); - if (AD_Org_ID == 0) - AD_Org_ID = m_doc.getAD_Org_ID(); - } - setAmtAcctDr (MConversionRate.convert (getCtx(), - getAmtSourceDr(), getC_Currency_ID(), m_acctSchema.getC_Currency_ID(), - getDateAcct(), C_ConversionType_ID, m_doc.getAD_Client_ID(), AD_Org_ID)); - if (getAmtAcctDr() == null) - return false; - setAmtAcctCr (MConversionRate.convert (getCtx(), - getAmtSourceCr(), getC_Currency_ID(), m_acctSchema.getC_Currency_ID(), - getDateAcct(), C_ConversionType_ID, m_doc.getAD_Client_ID(), AD_Org_ID)); - return true; - } // convert - - /** - * Get Account - * @return account - */ - public MAccount getAccount() - { - return m_acct; - } // getAccount - - /** - * To String - * @return String - */ - public String toString() - { - StringBuffer sb = new StringBuffer("FactLine=["); - sb.append(getAD_Table_ID()).append(":").append(getRecord_ID()) - .append(",").append(m_acct) - .append(",Cur=").append(getC_Currency_ID()) - .append(", DR=").append(getAmtSourceDr()).append("|").append(getAmtAcctDr()) - .append(", CR=").append(getAmtSourceCr()).append("|").append(getAmtAcctCr()) - .append("]"); - return sb.toString(); - } // toString - - - /** - * Get AD_Org_ID (balancing segment). - * (if not set directly - from document line, document, account, locator) - *

- * Note that Locator needs to be set before - otherwise - * segment balancing might produce the wrong results - * @return AD_Org_ID - */ - public int getAD_Org_ID() - { - if (super.getAD_Org_ID() != 0) // set earlier - return super.getAD_Org_ID(); - // Prio 1 - get from locator - if exist - if (getM_Locator_ID() != 0) - { - String sql = "SELECT AD_Org_ID FROM M_Locator WHERE M_Locator_ID=? AND AD_Client_ID=?"; - try - { - PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); - pstmt.setInt(1, getM_Locator_ID()); - pstmt.setInt(2, getAD_Client_ID()); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - { - setAD_Org_ID (rs.getInt(1)); - log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (1 from M_Locator_ID=" + getM_Locator_ID() + ")"); - } - else - log.log(Level.SEVERE, "AD_Org_ID - Did not find M_Locator_ID=" + getM_Locator_ID()); - rs.close(); - pstmt.close(); - } - catch (SQLException e) - { - log.log(Level.SEVERE, sql, e); - } - } // M_Locator_ID != 0 - - // Prio 2 - get from doc line - if exists (document context overwrites) - if (m_docLine != null && super.getAD_Org_ID() == 0) - { - setAD_Org_ID (m_docLine.getAD_Org_ID()); - log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (2 from DocumentLine)"); - } - // Prio 3 - get from doc - if not GL - if (m_doc != null && super.getAD_Org_ID() == 0) - { - if (Doc.DOCTYPE_GLJournal.equals (m_doc.getDocumentType())) - { - setAD_Org_ID (m_acct.getAD_Org_ID()); // inter-company GL - log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (3 from Acct)"); - } - else - { - setAD_Org_ID (m_doc.getAD_Org_ID()); - log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (3 from Document)"); - } - } - // Prio 4 - get from account - if not GL - if (m_doc != null && super.getAD_Org_ID() == 0) - { - if (Doc.DOCTYPE_GLJournal.equals (m_doc.getDocumentType())) - { - setAD_Org_ID (m_doc.getAD_Org_ID()); - log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (4 from Document)"); - } - else - { - setAD_Org_ID (m_acct.getAD_Org_ID()); - log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (4 from Acct)"); - } - } - return super.getAD_Org_ID(); - } // setAD_Org_ID - - - /** - * Get/derive Sales Region - * @return Sales Region - */ - public int getC_SalesRegion_ID () - { - if (super.getC_SalesRegion_ID() != 0) - return super.getC_SalesRegion_ID(); - // - if (m_docLine != null) - setC_SalesRegion_ID (m_docLine.getC_SalesRegion_ID()); - if (m_doc != null) - { - if (super.getC_SalesRegion_ID() == 0) - setC_SalesRegion_ID (m_doc.getC_SalesRegion_ID()); - if (super.getC_SalesRegion_ID() == 0 && m_doc.getBP_C_SalesRegion_ID() > 0) - setC_SalesRegion_ID (m_doc.getBP_C_SalesRegion_ID()); - // derive SalesRegion if AcctSegment - if (super.getC_SalesRegion_ID() == 0 - && m_doc.getC_BPartner_Location_ID() != 0 - && m_doc.getBP_C_SalesRegion_ID() == -1) // never tried - // && m_acctSchema.isAcctSchemaElement(MAcctSchemaElement.ELEMENTTYPE_SalesRegion)) - { - String sql = "SELECT COALESCE(C_SalesRegion_ID,0) FROM C_BPartner_Location WHERE C_BPartner_Location_ID=?"; - setC_SalesRegion_ID (DB.getSQLValue(null, - sql, m_doc.getC_BPartner_Location_ID())); - if (super.getC_SalesRegion_ID() != 0) // save in VO - { - m_doc.setBP_C_SalesRegion_ID(super.getC_SalesRegion_ID()); - log.fine("C_SalesRegion_ID=" + super.getC_SalesRegion_ID() + " (from BPL)" ); - } - else // From Sales Rep of Document -> Sales Region - { - sql = "SELECT COALESCE(MAX(C_SalesRegion_ID),0) FROM C_SalesRegion WHERE SalesRep_ID=?"; - setC_SalesRegion_ID (DB.getSQLValue(null, - sql, m_doc.getSalesRep_ID())); - if (super.getC_SalesRegion_ID() != 0) // save in VO - { - m_doc.setBP_C_SalesRegion_ID(super.getC_SalesRegion_ID()); - log.fine("C_SalesRegion_ID=" + super.getC_SalesRegion_ID() + " (from SR)" ); - } - else - m_doc.setBP_C_SalesRegion_ID(-2); // don't try again - } - } - if (m_acct != null && super.getC_SalesRegion_ID() == 0) - setC_SalesRegion_ID (m_acct.getC_SalesRegion_ID()); - } - // - // log.fine("C_SalesRegion_ID=" + super.getC_SalesRegion_ID() - // + ", C_BPartner_Location_ID=" + m_docVO.C_BPartner_Location_ID - // + ", BP_C_SalesRegion_ID=" + m_docVO.BP_C_SalesRegion_ID - // + ", SR=" + m_acctSchema.isAcctSchemaElement(MAcctSchemaElement.ELEMENTTYPE_SalesRegion)); - return super.getC_SalesRegion_ID(); - } // getC_SalesRegion_ID - - - /** - * Before Save - * @param newRecord new - * @return true - */ - protected boolean beforeSave (boolean newRecord) - { - if (newRecord) - { - log.fine(toString()); - // - getAD_Org_ID(); - getC_SalesRegion_ID(); - // Set Default Account Info - if (getM_Product_ID() == 0) - setM_Product_ID (m_acct.getM_Product_ID()); - if (getC_LocFrom_ID() == 0) - setC_LocFrom_ID (m_acct.getC_LocFrom_ID()); - if (getC_LocTo_ID() == 0) - setC_LocTo_ID (m_acct.getC_LocTo_ID()); - if (getC_BPartner_ID() == 0) - setC_BPartner_ID (m_acct.getC_BPartner_ID()); - if (getAD_OrgTrx_ID() == 0) - setAD_OrgTrx_ID (m_acct.getAD_OrgTrx_ID()); - if (getC_Project_ID() == 0) - setC_Project_ID (m_acct.getC_Project_ID()); - if (getC_Campaign_ID() == 0) - setC_Campaign_ID (m_acct.getC_Campaign_ID()); - if (getC_Activity_ID() == 0) - setC_Activity_ID (m_acct.getC_Activity_ID()); - if (getUser1_ID() == 0) - setUser1_ID (m_acct.getUser1_ID()); - if (getUser2_ID() == 0) - setUser2_ID (m_acct.getUser2_ID()); - - // Revenue Recognition for AR Invoices - if (m_doc.getDocumentType().equals(Doc.DOCTYPE_ARInvoice) - && m_docLine != null - && m_docLine.getC_RevenueRecognition_ID() != 0) - { - int AD_User_ID = 0; - setAccount_ID ( - createRevenueRecognition ( - m_docLine.getC_RevenueRecognition_ID(), m_docLine.get_ID(), - getAD_Client_ID(), getAD_Org_ID(), AD_User_ID, - getAccount_ID(), getC_SubAcct_ID(), - getM_Product_ID(), getC_BPartner_ID(), getAD_OrgTrx_ID(), - getC_LocFrom_ID(), getC_LocTo_ID(), - getC_SalesRegion_ID(), getC_Project_ID(), - getC_Campaign_ID(), getC_Activity_ID(), - getUser1_ID(), getUser2_ID(), - getUserElement1_ID(), getUserElement2_ID()) - ); - } - } - return true; - } // beforeSave - - - /************************************************************************** - * Revenue Recognition. - * Called from FactLine.save - *

- * Create Revenue recognition plan and return Unearned Revenue account - * to be used instead of Revenue Account. If not found, it returns - * the revenue account. - * - * @param C_RevenueRecognition_ID revenue recognition - * @param C_InvoiceLine_ID invoice line - * @param AD_Client_ID client - * @param AD_Org_ID org - * @param AD_User_ID user - * @param Account_ID of Revenue Account - * @param C_SubAcct_ID sub account - * @param M_Product_ID product - * @param C_BPartner_ID bpartner - * @param AD_OrgTrx_ID trx org - * @param C_LocFrom_ID loc from - * @param C_LocTo_ID loc to - * @param C_SRegion_ID sales region - * @param C_Project_ID project - * @param C_Campaign_ID campaign - * @param C_Activity_ID activity - * @param User1_ID user1 - * @param User2_ID user2 - * @param UserElement1_ID user element 1 - * @param UserElement2_ID user element 2 - * @return Account_ID for Unearned Revenue or Revenue Account if not found - */ - private int createRevenueRecognition ( - int C_RevenueRecognition_ID, int C_InvoiceLine_ID, - int AD_Client_ID, int AD_Org_ID, int AD_User_ID, - int Account_ID, int C_SubAcct_ID, - int M_Product_ID, int C_BPartner_ID, int AD_OrgTrx_ID, - int C_LocFrom_ID, int C_LocTo_ID, int C_SRegion_ID, int C_Project_ID, - int C_Campaign_ID, int C_Activity_ID, - int User1_ID, int User2_ID, int UserElement1_ID, int UserElement2_ID) - { - log.fine("From Accout_ID=" + Account_ID); - // get VC for P_Revenue (from Product) - MAccount revenue = MAccount.get(getCtx(), - AD_Client_ID, AD_Org_ID, getC_AcctSchema_ID(), Account_ID, C_SubAcct_ID, - M_Product_ID, C_BPartner_ID, AD_OrgTrx_ID, C_LocFrom_ID, C_LocTo_ID, C_SRegion_ID, - C_Project_ID, C_Campaign_ID, C_Activity_ID, - User1_ID, User2_ID, UserElement1_ID, UserElement2_ID); - if (revenue != null && revenue.get_ID() == 0) - revenue.save(); - if (revenue == null || revenue.get_ID() == 0) - { - log.severe ("Revenue_Acct not found"); - return Account_ID; - } - int P_Revenue_Acct = revenue.get_ID(); - - // get Unearned Revenue Acct from BPartner Group - int UnearnedRevenue_Acct = 0; - int new_Account_ID = 0; - String sql = "SELECT ga.UnearnedRevenue_Acct, vc.Account_ID " - + "FROM C_BP_Group_Acct ga, C_BPartner p, C_ValidCombination vc " - + "WHERE ga.C_BP_Group_ID=p.C_BP_Group_ID" - + " AND ga.UnearnedRevenue_Acct=vc.C_ValidCombination_ID" - + " AND ga.C_AcctSchema_ID=? AND p.C_BPartner_ID=?"; - try - { - PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); - pstmt.setInt(1, getC_AcctSchema_ID()); - pstmt.setInt(2, C_BPartner_ID); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - { - UnearnedRevenue_Acct = rs.getInt(1); - new_Account_ID = rs.getInt(2); - } - rs.close(); - pstmt.close(); - } - catch (SQLException e) - { - log.log(Level.SEVERE, sql, e); - } - if (new_Account_ID == 0) - { - log.severe ("UnearnedRevenue_Acct not found"); - return Account_ID; - } - - MRevenueRecognitionPlan plan = new MRevenueRecognitionPlan(getCtx(), 0, null); - plan.setC_RevenueRecognition_ID (C_RevenueRecognition_ID); - plan.setC_AcctSchema_ID (getC_AcctSchema_ID()); - plan.setC_InvoiceLine_ID (C_InvoiceLine_ID); - plan.setUnEarnedRevenue_Acct (UnearnedRevenue_Acct); - plan.setP_Revenue_Acct (P_Revenue_Acct); - plan.setC_Currency_ID (getC_Currency_ID()); - plan.setTotalAmt (getAcctBalance()); - if (!plan.save(get_TrxName())) - { - log.severe ("Plan NOT created"); - return Account_ID; - } - log.fine("From Acctount_ID=" + Account_ID + " to " + new_Account_ID - + " - Plan from UnearnedRevenue_Acct=" + UnearnedRevenue_Acct + " to Revenue_Acct=" + P_Revenue_Acct); - return new_Account_ID; - } // createRevenueRecognition - - - /************************************************************************** - * Update Line with reversed Original Amount in Accounting Currency. - * Also copies original dimensions like Project, etc. - * Called from Doc_MatchInv - * @param AD_Table_ID table - * @param Record_ID record - * @param Line_ID line - * @param multiplier targetQty/documentQty - * @return true if success - */ - public boolean updateReverseLine (int AD_Table_ID, int Record_ID, int Line_ID, - BigDecimal multiplier) - { - boolean success = false; - - String sql = "SELECT * " - + "FROM Fact_Acct " - + "WHERE C_AcctSchema_ID=? AND AD_Table_ID=? AND Record_ID=?" - + " AND Line_ID=? AND Account_ID=?"; - try - { - PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); - pstmt.setInt(1, getC_AcctSchema_ID()); - pstmt.setInt(2, AD_Table_ID); - pstmt.setInt(3, Record_ID); - pstmt.setInt(4, Line_ID); - pstmt.setInt(5, m_acct.getAccount_ID()); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - { - MFactAcct fact = new MFactAcct(getCtx(), rs, get_TrxName()); - // Accounted Amounts - reverse - BigDecimal dr = fact.getAmtAcctDr(); - BigDecimal cr = fact.getAmtAcctCr(); - setAmtAcctDr (cr.multiply(multiplier)); - setAmtAcctCr (dr.multiply(multiplier)); - // Source Amounts - setAmtSourceDr (getAmtAcctDr()); - setAmtSourceCr (getAmtAcctCr()); - // - success = true; - log.fine(new StringBuffer("(Table=").append(AD_Table_ID) - .append(",Record_ID=").append(Record_ID) - .append(",Line=").append(Record_ID) - .append(", Account=").append(m_acct) - .append(",dr=").append(dr).append(",cr=").append(cr) - .append(") - DR=").append(getAmtSourceDr()).append("|").append(getAmtAcctDr()) - .append(", CR=").append(getAmtSourceCr()).append("|").append(getAmtAcctCr()) - .toString()); - // Dimensions - setAD_OrgTrx_ID(fact.getAD_OrgTrx_ID()); - setC_Project_ID (fact.getC_Project_ID()); - setC_Activity_ID(fact.getC_Activity_ID()); - setC_Campaign_ID(fact.getC_Campaign_ID()); - setC_SalesRegion_ID(fact.getC_SalesRegion_ID()); - setC_LocFrom_ID(fact.getC_LocFrom_ID()); - setC_LocTo_ID(fact.getC_LocTo_ID()); - setM_Product_ID(fact.getM_Product_ID()); - setM_Locator_ID(fact.getM_Locator_ID()); - setUser1_ID(fact.getUser1_ID()); - setUser2_ID(fact.getUser2_ID()); - setC_UOM_ID(fact.getC_UOM_ID()); - setC_Tax_ID(fact.getC_Tax_ID()); - // Org for cross charge - setAD_Org_ID (fact.getAD_Org_ID()); - } - else - log.warning(new StringBuffer("Not Found (try later) ") - .append(",C_AcctSchema_ID=").append(getC_AcctSchema_ID()) - .append(", AD_Table_ID=").append(AD_Table_ID) - .append(",Record_ID=").append(Record_ID) - .append(",Line_ID=").append(Line_ID) - .append(", Account_ID=").append(m_acct.getAccount_ID()).toString()); - rs.close(); - pstmt.close(); - } - catch (SQLException e) - { - log.log(Level.SEVERE, sql, e); - } - return success; - } // updateReverseLine - -} // FactLine + * Get Document Line + * @return doc line + */ + protected DocLine getDocLine() + { + return m_docLine; + } // getDocLine + + /** + * Set Description + * @param description description + */ + public void addDescription (String description) + { + String original = getDescription(); + if (original == null || original.trim().length() == 0) + super.setDescription(description); + else + super.setDescription(original + " - " + description); + } // addDescription + + /** + * Set Warehouse Locator. + * - will overwrite Organization - + * @param M_Locator_ID locator + */ + public void setM_Locator_ID (int M_Locator_ID) + { + super.setM_Locator_ID (M_Locator_ID); + setAD_Org_ID(0); // reset + } // setM_Locator_ID + + + /************************************************************************** + * Set Location + * @param C_Location_ID location + * @param isFrom from + */ + public void setLocation (int C_Location_ID, boolean isFrom) + { + if (isFrom) + setC_LocFrom_ID (C_Location_ID); + else + setC_LocTo_ID (C_Location_ID); + } // setLocator + + /** + * Set Location from Locator + * @param M_Locator_ID locator + * @param isFrom from + */ + public void setLocationFromLocator (int M_Locator_ID, boolean isFrom) + { + if (M_Locator_ID == 0) + return; + int C_Location_ID = 0; + String sql = "SELECT w.C_Location_ID FROM M_Warehouse w, M_Locator l " + + "WHERE w.M_Warehouse_ID=l.M_Warehouse_ID AND l.M_Locator_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, M_Locator_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + C_Location_ID = rs.getInt(1); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + return; + } + if (C_Location_ID != 0) + setLocation (C_Location_ID, isFrom); + } // setLocationFromLocator + + /** + * Set Location from Busoness Partner Location + * @param C_BPartner_Location_ID bp location + * @param isFrom from + */ + public void setLocationFromBPartner (int C_BPartner_Location_ID, boolean isFrom) + { + if (C_BPartner_Location_ID == 0) + return; + int C_Location_ID = 0; + String sql = "SELECT C_Location_ID FROM C_BPartner_Location WHERE C_BPartner_Location_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, C_BPartner_Location_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + C_Location_ID = rs.getInt(1); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + return; + } + if (C_Location_ID != 0) + setLocation (C_Location_ID, isFrom); + } // setLocationFromBPartner + + /** + * Set Location from Organization + * @param AD_Org_ID org + * @param isFrom from + */ + public void setLocationFromOrg (int AD_Org_ID, boolean isFrom) + { + if (AD_Org_ID == 0) + return; + int C_Location_ID = 0; + String sql = "SELECT C_Location_ID FROM AD_OrgInfo WHERE AD_Org_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, AD_Org_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + C_Location_ID = rs.getInt(1); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + return; + } + if (C_Location_ID != 0) + setLocation (C_Location_ID, isFrom); + } // setLocationFromOrg + + + /************************************************************************** + * Returns Source Balance of line + * @return source balance + */ + public BigDecimal getSourceBalance() + { + if (getAmtSourceDr() == null) + setAmtSourceDr (Env.ZERO); + if (getAmtSourceCr() == null) + setAmtSourceCr (Env.ZERO); + // + return getAmtSourceDr().subtract(getAmtSourceCr()); + } // getSourceBalance + + /** + * Is Debit Source Balance + * @return true if DR source balance + */ + public boolean isDrSourceBalance() + { + return getSourceBalance().signum() != -1; + } // isDrSourceBalance + + /** + * Get Accounted Balance + * @return accounting balance + */ + public BigDecimal getAcctBalance() + { + if (getAmtAcctDr() == null) + setAmtAcctDr (Env.ZERO); + if (getAmtAcctCr() == null) + setAmtAcctCr (Env.ZERO); + return getAmtAcctDr().subtract(getAmtAcctCr()); + } // getAcctBalance + + /** + * Is Account on Balance Sheet + * @return true if account is a balance sheet account + */ + public boolean isBalanceSheet() + { + return m_acct.isBalanceSheet(); + } // isBalanceSheet + + /** + * Currect Accounting Amount. + *

+	 *  Example:    1       -1      1       -1
+	 *  Old         100/0   100/0   0/100   0/100
+	 *  New         99/0    101/0   0/99    0/101
+	 *  
+ * @param deltaAmount delta amount + */ + public void currencyCorrect (BigDecimal deltaAmount) + { + boolean negative = deltaAmount.compareTo(Env.ZERO) < 0; + boolean adjustDr = getAmtAcctDr().abs().compareTo(getAmtAcctCr().abs()) > 0; + + log.fine(deltaAmount.toString() + + "; Old-AcctDr=" + getAmtAcctDr() + ",AcctCr=" + getAmtAcctCr() + + "; Negative=" + negative + "; AdjustDr=" + adjustDr); + + if (adjustDr) + if (negative) + setAmtAcctDr (getAmtAcctDr().subtract(deltaAmount)); + else + setAmtAcctDr (getAmtAcctDr().subtract(deltaAmount)); + else + if (negative) + setAmtAcctCr (getAmtAcctCr().add(deltaAmount)); + else + setAmtAcctCr (getAmtAcctCr().add(deltaAmount)); + + log.fine("New-AcctDr=" + getAmtAcctDr() + ",AcctCr=" + getAmtAcctCr()); + } // currencyCorrect + + /** + * Convert to Accounted Currency + * @return true if converted + */ + public boolean convert () + { + // Document has no currency + if (getC_Currency_ID() == Doc.NO_CURRENCY) + setC_Currency_ID (m_acctSchema.getC_Currency_ID()); + + if (m_acctSchema.getC_Currency_ID() == getC_Currency_ID()) + { + setAmtAcctDr (getAmtSourceDr()); + setAmtAcctCr (getAmtSourceCr()); + return true; + } + // Get Conversion Type from Line or Header + int C_ConversionType_ID = 0; + int AD_Org_ID = 0; + if (m_docLine != null) // get from line + { + C_ConversionType_ID = m_docLine.getC_ConversionType_ID(); + AD_Org_ID = m_docLine.getAD_Org_ID(); + } + if (C_ConversionType_ID == 0) // get from header + { + if (m_doc == null) + { + log.severe ("No Document VO"); + return false; + } + C_ConversionType_ID = m_doc.getC_ConversionType_ID(); + if (AD_Org_ID == 0) + AD_Org_ID = m_doc.getAD_Org_ID(); + } + setAmtAcctDr (MConversionRate.convert (getCtx(), + getAmtSourceDr(), getC_Currency_ID(), m_acctSchema.getC_Currency_ID(), + getDateAcct(), C_ConversionType_ID, m_doc.getAD_Client_ID(), AD_Org_ID)); + if (getAmtAcctDr() == null) + return false; + setAmtAcctCr (MConversionRate.convert (getCtx(), + getAmtSourceCr(), getC_Currency_ID(), m_acctSchema.getC_Currency_ID(), + getDateAcct(), C_ConversionType_ID, m_doc.getAD_Client_ID(), AD_Org_ID)); + return true; + } // convert + + /** + * Get Account + * @return account + */ + public MAccount getAccount() + { + return m_acct; + } // getAccount + + /** + * To String + * @return String + */ + public String toString() + { + StringBuffer sb = new StringBuffer("FactLine=["); + sb.append(getAD_Table_ID()).append(":").append(getRecord_ID()) + .append(",").append(m_acct) + .append(",Cur=").append(getC_Currency_ID()) + .append(", DR=").append(getAmtSourceDr()).append("|").append(getAmtAcctDr()) + .append(", CR=").append(getAmtSourceCr()).append("|").append(getAmtAcctCr()) + .append("]"); + return sb.toString(); + } // toString + + + /** + * Get AD_Org_ID (balancing segment). + * (if not set directly - from document line, document, account, locator) + *

+ * Note that Locator needs to be set before - otherwise + * segment balancing might produce the wrong results + * @return AD_Org_ID + */ + public int getAD_Org_ID() + { + if (super.getAD_Org_ID() != 0) // set earlier + return super.getAD_Org_ID(); + // Prio 1 - get from locator - if exist + if (getM_Locator_ID() != 0) + { + String sql = "SELECT AD_Org_ID FROM M_Locator WHERE M_Locator_ID=? AND AD_Client_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, getM_Locator_ID()); + pstmt.setInt(2, getAD_Client_ID()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + setAD_Org_ID (rs.getInt(1)); + log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (1 from M_Locator_ID=" + getM_Locator_ID() + ")"); + } + else + log.log(Level.SEVERE, "AD_Org_ID - Did not find M_Locator_ID=" + getM_Locator_ID()); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + } + } // M_Locator_ID != 0 + + // Prio 2 - get from doc line - if exists (document context overwrites) + if (m_docLine != null && super.getAD_Org_ID() == 0) + { + setAD_Org_ID (m_docLine.getAD_Org_ID()); + log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (2 from DocumentLine)"); + } + // Prio 3 - get from doc - if not GL + if (m_doc != null && super.getAD_Org_ID() == 0) + { + if (Doc.DOCTYPE_GLJournal.equals (m_doc.getDocumentType())) + { + setAD_Org_ID (m_acct.getAD_Org_ID()); // inter-company GL + log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (3 from Acct)"); + } + else + { + setAD_Org_ID (m_doc.getAD_Org_ID()); + log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (3 from Document)"); + } + } + // Prio 4 - get from account - if not GL + if (m_doc != null && super.getAD_Org_ID() == 0) + { + if (Doc.DOCTYPE_GLJournal.equals (m_doc.getDocumentType())) + { + setAD_Org_ID (m_doc.getAD_Org_ID()); + log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (4 from Document)"); + } + else + { + setAD_Org_ID (m_acct.getAD_Org_ID()); + log.finer("AD_Org_ID=" + super.getAD_Org_ID() + " (4 from Acct)"); + } + } + return super.getAD_Org_ID(); + } // setAD_Org_ID + + + /** + * Get/derive Sales Region + * @return Sales Region + */ + public int getC_SalesRegion_ID () + { + if (super.getC_SalesRegion_ID() != 0) + return super.getC_SalesRegion_ID(); + // + if (m_docLine != null) + setC_SalesRegion_ID (m_docLine.getC_SalesRegion_ID()); + if (m_doc != null) + { + if (super.getC_SalesRegion_ID() == 0) + setC_SalesRegion_ID (m_doc.getC_SalesRegion_ID()); + if (super.getC_SalesRegion_ID() == 0 && m_doc.getBP_C_SalesRegion_ID() > 0) + setC_SalesRegion_ID (m_doc.getBP_C_SalesRegion_ID()); + // derive SalesRegion if AcctSegment + if (super.getC_SalesRegion_ID() == 0 + && m_doc.getC_BPartner_Location_ID() != 0 + && m_doc.getBP_C_SalesRegion_ID() == -1) // never tried + // && m_acctSchema.isAcctSchemaElement(MAcctSchemaElement.ELEMENTTYPE_SalesRegion)) + { + String sql = "SELECT COALESCE(C_SalesRegion_ID,0) FROM C_BPartner_Location WHERE C_BPartner_Location_ID=?"; + setC_SalesRegion_ID (DB.getSQLValue(null, + sql, m_doc.getC_BPartner_Location_ID())); + if (super.getC_SalesRegion_ID() != 0) // save in VO + { + m_doc.setBP_C_SalesRegion_ID(super.getC_SalesRegion_ID()); + log.fine("C_SalesRegion_ID=" + super.getC_SalesRegion_ID() + " (from BPL)" ); + } + else // From Sales Rep of Document -> Sales Region + { + sql = "SELECT COALESCE(MAX(C_SalesRegion_ID),0) FROM C_SalesRegion WHERE SalesRep_ID=?"; + setC_SalesRegion_ID (DB.getSQLValue(null, + sql, m_doc.getSalesRep_ID())); + if (super.getC_SalesRegion_ID() != 0) // save in VO + { + m_doc.setBP_C_SalesRegion_ID(super.getC_SalesRegion_ID()); + log.fine("C_SalesRegion_ID=" + super.getC_SalesRegion_ID() + " (from SR)" ); + } + else + m_doc.setBP_C_SalesRegion_ID(-2); // don't try again + } + } + if (m_acct != null && super.getC_SalesRegion_ID() == 0) + setC_SalesRegion_ID (m_acct.getC_SalesRegion_ID()); + } + // + // log.fine("C_SalesRegion_ID=" + super.getC_SalesRegion_ID() + // + ", C_BPartner_Location_ID=" + m_docVO.C_BPartner_Location_ID + // + ", BP_C_SalesRegion_ID=" + m_docVO.BP_C_SalesRegion_ID + // + ", SR=" + m_acctSchema.isAcctSchemaElement(MAcctSchemaElement.ELEMENTTYPE_SalesRegion)); + return super.getC_SalesRegion_ID(); + } // getC_SalesRegion_ID + + + /** + * Before Save + * @param newRecord new + * @return true + */ + protected boolean beforeSave (boolean newRecord) + { + if (newRecord) + { + log.fine(toString()); + // + getAD_Org_ID(); + getC_SalesRegion_ID(); + // Set Default Account Info + if (getM_Product_ID() == 0) + setM_Product_ID (m_acct.getM_Product_ID()); + if (getC_LocFrom_ID() == 0) + setC_LocFrom_ID (m_acct.getC_LocFrom_ID()); + if (getC_LocTo_ID() == 0) + setC_LocTo_ID (m_acct.getC_LocTo_ID()); + if (getC_BPartner_ID() == 0) + setC_BPartner_ID (m_acct.getC_BPartner_ID()); + if (getAD_OrgTrx_ID() == 0) + setAD_OrgTrx_ID (m_acct.getAD_OrgTrx_ID()); + if (getC_Project_ID() == 0) + setC_Project_ID (m_acct.getC_Project_ID()); + if (getC_Campaign_ID() == 0) + setC_Campaign_ID (m_acct.getC_Campaign_ID()); + if (getC_Activity_ID() == 0) + setC_Activity_ID (m_acct.getC_Activity_ID()); + if (getUser1_ID() == 0) + setUser1_ID (m_acct.getUser1_ID()); + if (getUser2_ID() == 0) + setUser2_ID (m_acct.getUser2_ID()); + + // Revenue Recognition for AR Invoices + if (m_doc.getDocumentType().equals(Doc.DOCTYPE_ARInvoice) + && m_docLine != null + && m_docLine.getC_RevenueRecognition_ID() != 0) + { + int AD_User_ID = 0; + setAccount_ID ( + createRevenueRecognition ( + m_docLine.getC_RevenueRecognition_ID(), m_docLine.get_ID(), + getAD_Client_ID(), getAD_Org_ID(), AD_User_ID, + getAccount_ID(), getC_SubAcct_ID(), + getM_Product_ID(), getC_BPartner_ID(), getAD_OrgTrx_ID(), + getC_LocFrom_ID(), getC_LocTo_ID(), + getC_SalesRegion_ID(), getC_Project_ID(), + getC_Campaign_ID(), getC_Activity_ID(), + getUser1_ID(), getUser2_ID(), + getUserElement1_ID(), getUserElement2_ID()) + ); + } + } + return true; + } // beforeSave + + + /************************************************************************** + * Revenue Recognition. + * Called from FactLine.save + *

+ * Create Revenue recognition plan and return Unearned Revenue account + * to be used instead of Revenue Account. If not found, it returns + * the revenue account. + * + * @param C_RevenueRecognition_ID revenue recognition + * @param C_InvoiceLine_ID invoice line + * @param AD_Client_ID client + * @param AD_Org_ID org + * @param AD_User_ID user + * @param Account_ID of Revenue Account + * @param C_SubAcct_ID sub account + * @param M_Product_ID product + * @param C_BPartner_ID bpartner + * @param AD_OrgTrx_ID trx org + * @param C_LocFrom_ID loc from + * @param C_LocTo_ID loc to + * @param C_SRegion_ID sales region + * @param C_Project_ID project + * @param C_Campaign_ID campaign + * @param C_Activity_ID activity + * @param User1_ID user1 + * @param User2_ID user2 + * @param UserElement1_ID user element 1 + * @param UserElement2_ID user element 2 + * @return Account_ID for Unearned Revenue or Revenue Account if not found + */ + private int createRevenueRecognition ( + int C_RevenueRecognition_ID, int C_InvoiceLine_ID, + int AD_Client_ID, int AD_Org_ID, int AD_User_ID, + int Account_ID, int C_SubAcct_ID, + int M_Product_ID, int C_BPartner_ID, int AD_OrgTrx_ID, + int C_LocFrom_ID, int C_LocTo_ID, int C_SRegion_ID, int C_Project_ID, + int C_Campaign_ID, int C_Activity_ID, + int User1_ID, int User2_ID, int UserElement1_ID, int UserElement2_ID) + { + log.fine("From Accout_ID=" + Account_ID); + // get VC for P_Revenue (from Product) + MAccount revenue = MAccount.get(getCtx(), + AD_Client_ID, AD_Org_ID, getC_AcctSchema_ID(), Account_ID, C_SubAcct_ID, + M_Product_ID, C_BPartner_ID, AD_OrgTrx_ID, C_LocFrom_ID, C_LocTo_ID, C_SRegion_ID, + C_Project_ID, C_Campaign_ID, C_Activity_ID, + User1_ID, User2_ID, UserElement1_ID, UserElement2_ID); + if (revenue != null && revenue.get_ID() == 0) + revenue.save(); + if (revenue == null || revenue.get_ID() == 0) + { + log.severe ("Revenue_Acct not found"); + return Account_ID; + } + int P_Revenue_Acct = revenue.get_ID(); + + // get Unearned Revenue Acct from BPartner Group + int UnearnedRevenue_Acct = 0; + int new_Account_ID = 0; + String sql = "SELECT ga.UnearnedRevenue_Acct, vc.Account_ID " + + "FROM C_BP_Group_Acct ga, C_BPartner p, C_ValidCombination vc " + + "WHERE ga.C_BP_Group_ID=p.C_BP_Group_ID" + + " AND ga.UnearnedRevenue_Acct=vc.C_ValidCombination_ID" + + " AND ga.C_AcctSchema_ID=? AND p.C_BPartner_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, getC_AcctSchema_ID()); + pstmt.setInt(2, C_BPartner_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + UnearnedRevenue_Acct = rs.getInt(1); + new_Account_ID = rs.getInt(2); + } + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + } + if (new_Account_ID == 0) + { + log.severe ("UnearnedRevenue_Acct not found"); + return Account_ID; + } + + MRevenueRecognitionPlan plan = new MRevenueRecognitionPlan(getCtx(), 0, null); + plan.setC_RevenueRecognition_ID (C_RevenueRecognition_ID); + plan.setC_AcctSchema_ID (getC_AcctSchema_ID()); + plan.setC_InvoiceLine_ID (C_InvoiceLine_ID); + plan.setUnEarnedRevenue_Acct (UnearnedRevenue_Acct); + plan.setP_Revenue_Acct (P_Revenue_Acct); + plan.setC_Currency_ID (getC_Currency_ID()); + plan.setTotalAmt (getAcctBalance()); + if (!plan.save(get_TrxName())) + { + log.severe ("Plan NOT created"); + return Account_ID; + } + log.fine("From Acctount_ID=" + Account_ID + " to " + new_Account_ID + + " - Plan from UnearnedRevenue_Acct=" + UnearnedRevenue_Acct + " to Revenue_Acct=" + P_Revenue_Acct); + return new_Account_ID; + } // createRevenueRecognition + + + /************************************************************************** + * Update Line with reversed Original Amount in Accounting Currency. + * Also copies original dimensions like Project, etc. + * Called from Doc_MatchInv + * @param AD_Table_ID table + * @param Record_ID record + * @param Line_ID line + * @param multiplier targetQty/documentQty + * @return true if success + */ + public boolean updateReverseLine (int AD_Table_ID, int Record_ID, int Line_ID, + BigDecimal multiplier) + { + boolean success = false; + + String sql = "SELECT * " + + "FROM Fact_Acct " + + "WHERE C_AcctSchema_ID=? AND AD_Table_ID=? AND Record_ID=?" + + " AND Line_ID=? AND Account_ID=?"; + try + { + PreparedStatement pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, getC_AcctSchema_ID()); + pstmt.setInt(2, AD_Table_ID); + pstmt.setInt(3, Record_ID); + pstmt.setInt(4, Line_ID); + pstmt.setInt(5, m_acct.getAccount_ID()); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + MFactAcct fact = new MFactAcct(getCtx(), rs, get_TrxName()); + // Accounted Amounts - reverse + BigDecimal dr = fact.getAmtAcctDr(); + BigDecimal cr = fact.getAmtAcctCr(); + setAmtAcctDr (cr.multiply(multiplier)); + setAmtAcctCr (dr.multiply(multiplier)); + // Source Amounts + setAmtSourceDr (getAmtAcctDr()); + setAmtSourceCr (getAmtAcctCr()); + // + success = true; + log.fine(new StringBuffer("(Table=").append(AD_Table_ID) + .append(",Record_ID=").append(Record_ID) + .append(",Line=").append(Record_ID) + .append(", Account=").append(m_acct) + .append(",dr=").append(dr).append(",cr=").append(cr) + .append(") - DR=").append(getAmtSourceDr()).append("|").append(getAmtAcctDr()) + .append(", CR=").append(getAmtSourceCr()).append("|").append(getAmtAcctCr()) + .toString()); + // Dimensions + setAD_OrgTrx_ID(fact.getAD_OrgTrx_ID()); + setC_Project_ID (fact.getC_Project_ID()); + setC_Activity_ID(fact.getC_Activity_ID()); + setC_Campaign_ID(fact.getC_Campaign_ID()); + setC_SalesRegion_ID(fact.getC_SalesRegion_ID()); + setC_LocFrom_ID(fact.getC_LocFrom_ID()); + setC_LocTo_ID(fact.getC_LocTo_ID()); + setM_Product_ID(fact.getM_Product_ID()); + setM_Locator_ID(fact.getM_Locator_ID()); + setUser1_ID(fact.getUser1_ID()); + setUser2_ID(fact.getUser2_ID()); + setC_UOM_ID(fact.getC_UOM_ID()); + setC_Tax_ID(fact.getC_Tax_ID()); + // Org for cross charge + setAD_Org_ID (fact.getAD_Org_ID()); + } + else + log.warning(new StringBuffer("Not Found (try later) ") + .append(",C_AcctSchema_ID=").append(getC_AcctSchema_ID()) + .append(", AD_Table_ID=").append(AD_Table_ID) + .append(",Record_ID=").append(Record_ID) + .append(",Line_ID=").append(Line_ID) + .append(", Account_ID=").append(m_acct.getAccount_ID()).toString()); + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.log(Level.SEVERE, sql, e); + } + return success; + } // updateReverseLine + +} // FactLine diff --git a/serverRoot/src/main/server/org/compiere/ldap/LdapConnectionHandler.java b/serverRoot/src/main/server/org/compiere/ldap/LdapConnectionHandler.java index 532c7062da..94525a0aa8 100644 --- a/serverRoot/src/main/server/org/compiere/ldap/LdapConnectionHandler.java +++ b/serverRoot/src/main/server/org/compiere/ldap/LdapConnectionHandler.java @@ -10,21 +10,50 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * You may reach us at: ComPiere, Inc. - http://www.adempiere.org/license.html - * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@adempiere.org + * You may reach us at: ComPiere, Inc. - http://www.compiere.org/license.html + * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@compiere.org *****************************************************************************/ package org.compiere.ldap; -import java.io.*; -import java.net.*; -import java.util.logging.*; -import org.compiere.ldap.*; -import org.compiere.util.*; -import com.sun.jndi.ldap.*; - -/** - * LDAP Connection Handler - * +import java.io.*; +import java.net.*; +import java.util.Hashtable; +import java.util.logging.*; + +import javax.naming.AuthenticationException; +import javax.naming.Context; +import javax.naming.ldap.InitialLdapContext; + +import org.compiere.model.*; +import org.compiere.util.*; + +/** + * LDAP Connection Handler + * + * Only "simple" authentication and the following protocol are supported: + * bind + * unbind + * search + * The following distinguished name are supported: + * o - organization + * ou - organization unit + * cn - common name + * Due to some of the ldap client might not unbind and close the connection, + * whenever error occurs and authenticate done, we will close the connection. + * + * Basically, tested with two type of ldap authentication, java client and + * apache ldap support. + * For the apache support, here's the tested definition: + * AuthType Basic + * AuthLDAPAuthoritative on + * AuthLDAPEnabled on + * AuthLDAPURL ldap://:/o=,ou=?uid?sub + * The protocol for the apache ldap: + * - bind to server + * - search for the object name with user input userid + * - bind again with returned object name and password + * The protocol for the java client, please refer to the sample code in main(). + * * @author Jorg Janke * @version $Id: LdapConnectionHandler.java,v 1.1 2006/10/09 00:23:16 jjanke Exp $ */ @@ -33,13 +62,15 @@ public class LdapConnectionHandler extends Thread /** * Ldap Connection Handler * @param socket server socket - */ - public LdapConnectionHandler(Socket socket) - { - try - { - m_socket = socket; - m_socket.setTcpNoDelay(true); // should not be required + * @param model model + */ + public LdapConnectionHandler(Socket socket, MLdapProcessor model) + { + try + { + m_socket = socket; + m_socket.setTcpNoDelay(true); // should not be required + m_model = model; } catch (Exception e) { @@ -49,6 +80,8 @@ public class LdapConnectionHandler extends Thread /** Socket */ private Socket m_socket = null; + /** Ldap Model */ + private MLdapProcessor m_model = null; /** Logger */ private static CLogger log = CLogger.getCLogger (LdapConnectionHandler.class); @@ -63,6 +96,9 @@ public class LdapConnectionHandler extends Thread if (m_socket == null || m_socket.isClosed()) return; + LdapMessage msg = new LdapMessage(); + MLdapUser ldapUser = new MLdapUser(); + LdapResult result = new LdapResult(); boolean activeSession = true; while (activeSession) { @@ -72,21 +108,31 @@ public class LdapConnectionHandler extends Thread byte[] buffer = new byte[512]; int length = in.read(buffer, 0, 512); - LdapMessage msg = new LdapMessage (buffer, length); - if (msg.getOperation() == LdapMessage.UNBIND_REQUEST) - { - activeSession = false; - out.close(); - } - else - { - LdapResult result = new LdapResult (); - byte[] bytes = result.bindResponse(); - // - out.write(bytes); - out.flush(); - } - } + // Decode the input message buffer + result.reset(msg, ldapUser); + msg.reset(result); + msg.decode(buffer, length); + if (msg.getOperation() == LdapMessage.UNBIND_REQUEST) + { + out.close(); + break; + } + + // Not unbind, so we can create a response + byte[] bytes = result.getResult(m_model); + + // Send the response back + out.write(bytes); + out.flush(); + + // If there's error or successfully authenticated the user, + // close the connection to avoid too many open connection + if (result.getDone()) + { + out.close(); + break; + } + } // while(activeSession) } catch (IOException e) { @@ -115,4 +161,42 @@ public class LdapConnectionHandler extends Thread return sb.toString (); } // toString -} // LdapConnectionHandler + /** + * Test using the java client. + * Ldap v3 won't need to do any bind, search, bind anymore. + * When new InitialLdapContext() is called, it will bind with the + * dn and password, the ldap server should be authenticate with it. + * + * @param args + */ + public static void main(String[] args) + { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + // ldap://dc.compiere.org + env.put(Context.PROVIDER_URL, "ldap://10.104.139.160:389"); + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + // Compiere server only support cn/o/ou, and cn should be the user id. + // Only one entry for cn. + env.put(Context.SECURITY_PRINCIPAL, "cn=cboss@compiere.org,o=GardenWorld,ou=LawnCare"); + env.put(Context.SECURITY_CREDENTIALS, "carlboss"); + + try + { + // Create the initial context + new InitialLdapContext(env, null); + // If not successfully authenticated, exception should be thrown + System.out.println("Successfully authenticated ..."); + } + catch (AuthenticationException e) + { + e.printStackTrace(); + return; + } + catch (Exception e) + { + e.printStackTrace(); + return; + } + } // main() +} // LdapConnectionHandler diff --git a/serverRoot/src/main/server/org/compiere/ldap/LdapMessage.java b/serverRoot/src/main/server/org/compiere/ldap/LdapMessage.java index e3e0c26e0f..c2003a0715 100644 --- a/serverRoot/src/main/server/org/compiere/ldap/LdapMessage.java +++ b/serverRoot/src/main/server/org/compiere/ldap/LdapMessage.java @@ -10,12 +10,13 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * You may reach us at: ComPiere, Inc. - http://www.adempiere.org/license.html - * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@adempiere.org + * You may reach us at: ComPiere, Inc. - http://www.compiere.org/license.html + * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@compiere.org *****************************************************************************/ package org.compiere.ldap; -import java.util.logging.*; +import java.util.logging.*; + import org.compiere.util.*; import com.sun.jndi.ldap.*; @@ -27,138 +28,235 @@ import com.sun.jndi.ldap.*; */ public class LdapMessage { - /** - * Ldap Message - * @param data BER data - * @param length Ber data length - */ - public LdapMessage (byte[] data, int length) - { - try - { - decode(data, length); - } - catch (Exception e) - { - log.log(Level.SEVERE, data.toString(), e); - } - } // LdapMessage - - /** - LDAPMessage ::= SEQUENCE { - messageID MessageID, - protocolOp CHOICE { - bindRequest BindRequest, - bindResponse BindResponse, - unbindRequest UnbindRequest, - searchRequest SearchRequest, - searchResEntry SearchResultEntry, - searchResDone SearchResultDone, - searchResRef SearchResultReference, - modifyRequest ModifyRequest, - modifyResponse ModifyResponse, - addRequest AddRequest, - addResponse AddResponse, - delRequest DelRequest, - delResponse DelResponse, - modDNRequest ModifyDNRequest, - modDNResponse ModifyDNResponse, - compareRequest CompareRequest, - compareResponse CompareResponse, - abandonRequest AbandonRequest, - extendedReq ExtendedRequest, - extendedResp ExtendedResponse }, - controls [0] Controls OPTIONAL } - **/ - - static public final int BIND_REQUEST = 0; - static public final int BIND_RESPONSE = 1; - static public final int UNBIND_REQUEST = 2; - static public final int SEARCH_REQUEST = 3; - static public final int SEARCH_RESENTRY = 4; - static public final int SEARCH_RESDONE = 5; - static public final int MODIFY_REQUEST = 6; - static public final int MODIFY_RESPONSE = 7; - static public final int ADD_REQUEST = 8; - static public final int ADD_RESPONSE = 9; - static public final int DEL_REQUEST = 10; - static public final int DEL_RESPONSE = 11; - static public final int MODDN_REQUEST = 12; - static public final int MODDN_RESPONSE = 13; - static public final int COMPARE_REQUEST = 14; - static public final int COMPARE_RESPONSE = 15; - static public final int ABANDON_REQUEST = 16; - static public final int EXTENDED_REQUEST = 17; - static public final int EXTENDED_RESPONSE = 18; - - static public final int[] PROTOCOL_OP = { - BIND_REQUEST, BIND_RESPONSE, UNBIND_REQUEST, - SEARCH_REQUEST, SEARCH_RESENTRY, SEARCH_RESDONE, - MODIFY_REQUEST, MODIFY_RESPONSE, ADD_REQUEST, ADD_RESPONSE, - DEL_REQUEST, DEL_RESPONSE, MODDN_REQUEST, MODDN_RESPONSE, - COMPARE_REQUEST, COMPARE_RESPONSE, ABANDON_REQUEST, - EXTENDED_REQUEST, EXTENDED_RESPONSE}; - - - /** Logger */ - private static CLogger log = CLogger.getCLogger (LdapMessage.class); - /** Protocol Operation */ - private int m_protocolOp = -1; - - - /** - * Decode Message - * @param data data - * @param length length - * @throws Exception - */ - private void decode (byte[] data, int length) throws Exception - { - BerDecoder decoder = new BerDecoder(data, 0, length); - int left = decoder.bytesLeft(); - int pos = decoder.getParsePosition(); - // - int seq = decoder.parseSeq(null); - left = decoder.bytesLeft(); - pos = decoder.getParsePosition(); - // - int messageID = decoder.parseInt(); - left = decoder.bytesLeft(); - pos = decoder.getParsePosition(); - // - int peek = decoder.peekByte(); - m_protocolOp = decoder.parseSeq(PROTOCOL_OP); - m_protocolOp -= Ber.ASN_APPLICATION; - if (m_protocolOp - Ber.ASN_CONSTRUCTOR >= 0) - m_protocolOp -= Ber.ASN_CONSTRUCTOR; - left = decoder.bytesLeft(); - pos = decoder.getParsePosition(); - // - // Payload - if (m_protocolOp == BIND_REQUEST) - { - int version = decoder.parseInt(); - left = decoder.bytesLeft(); - pos = decoder.getParsePosition(); - // - byte[] dn = decoder.parseOctetString(Ber.ASN_OCTET_STR, null); - left = decoder.bytesLeft(); - pos = decoder.getParsePosition(); - // - byte[] authentification = decoder.parseOctetString(Ber.ASN_CONTEXT, null); - left = decoder.bytesLeft(); - pos = decoder.getParsePosition(); - // - log.info("#" + messageID + ": bind - version=" + version + ", dn=" + new String(dn) - + ", auth=" + new String (authentification)); - } - else if (m_protocolOp == UNBIND_REQUEST) - log.info("#" + messageID + ": unbind"); - else - { - log.warning("#" + messageID + ": Unknown Op + " + m_protocolOp); - } - } // decode + static public final int BIND_REQUEST = 96; + static public final int BIND_RESPONSE = 97; + static public final int UNBIND_REQUEST = 98; + static public final int SEARCH_REQUEST = 99; + static public final int SEARCH_REP_ENTRY = 100; + static public final int SEARCH_RES_RESULT = 101; + + static public final int SIMPLE_AUTHENTICATION = 128; + + static public final int FILTER_AND = 160; + static public final int FILTER_OR = 161; + static public final int FILTER_NOT = 162; + static public final int FILTER_EQUALITYMATCH = 163; + + static public final int SEQUENCE = 48; + + /** Decoder */ + private BerDecoder decoder = null; + /** Logger */ + private static CLogger log = CLogger.getCLogger (LdapMessage.class); + /** Protocol Operation */ + private int m_protocolOp = -1; + /** Message Id needed for the reply message */ + private int msgId; + /** Distinguished name */ + private String dn = null; + /** Organization */ + private String org = null; + /** Organization unit */ + private String orgUnit = null; + /** User Id */ + private String userId = null; + /** Password */ + private String passwd = null; + /** base Object */ + private String baseObj = null; + /** LdapResult object to hold if there's any error during parsing */ + private LdapResult result = null; + + /** + * Ldap Message + */ + public LdapMessage() + { + } // LdapMessage + + /* + * Reset all the attributes + */ + public void reset(LdapResult result) + { + this.result = result; + decoder = null; + m_protocolOp = -1; + msgId = -1; + dn = null; + org = null; + orgUnit = null; + userId = null; + passwd = null; + baseObj = null; + + } // reset() + + /** + * Decode Message + * @param data input buffer + * @param length buffer size + */ + public void decode(byte[] data, int length) + { + try + { + // Create the decoder + decoder = new BerDecoder(data, 0, length); + } + catch (Exception e) + { + log.log(Level.SEVERE, data.toString(), e); + return; + } + + try + { + // Parse the message envelope + decoder.parseSeq(null); + + // Parse message Id + msgId = decoder.parseInt(); + + // Parse the operation protocol + m_protocolOp = decoder.parseSeq(null); + + // + // Payload + if (m_protocolOp == BIND_REQUEST) + handleBind(); + else if (m_protocolOp == UNBIND_REQUEST) + log.info("#" + msgId + ": unbind"); + else if (m_protocolOp == SEARCH_REQUEST) + handleSearch(); + else // Only supoort BIND, UNBIND and SEARCH + { + result.setErrorNo(LdapResult.LDAP_PROTOCOL_ERROR); + result.setErrorString(": Unsupported Request"); + log.warning("#" + msgId + ": Unknown Op + " + m_protocolOp); + } + } + catch (Exception ex) + { + result.setErrorNo(LdapResult.LDAP_PROTOCOL_ERROR); + log.log(Level.SEVERE, "", ex); + } + } // decode + + /* + * Encode the search request message + */ + private void handleSearch() + { + try + { + // Parse the base Object + baseObj = decoder.parseString(true); + parseDN(baseObj); + + decoder.parseEnumeration(); // scope + decoder.parseEnumeration(); // derefAliases + decoder.parseInt(); // sizeLimit + decoder.parseInt(); // timeLimit + decoder.parseBoolean(); // typeOnly + + boolean equalityFilter = false; + while (true) + { + int filter = decoder.parseSeq(null); //Filter + if (filter == FILTER_EQUALITYMATCH) + { + decoder.parseString(true); + userId = decoder.parseString(true); + equalityFilter = true; + break; + } + else if (filter == FILTER_AND) + decoder.parseStringWithTag(135, true, null); + else if (filter == SEQUENCE) + break; + } // while true + + if (!equalityFilter) // Didn't find the it + { + result.setErrorNo(LdapResult.LDAP_PROTOCOL_ERROR); + result.setErrorString("Can't can't Filter - EqualityMatch"); + } + } + catch (Exception ex) + { + log.log(Level.SEVERE, "", ex); + } + } // handleSearch() + + /* + * Encode the bind request message + */ + private void handleBind() + { + try + { + // Parse LDAP version; only support v3 + int version = decoder.parseInt(); + if (version != 3) + { + result.setErrorNo(LdapResult.LDAP_PROTOCOL_ERROR); + result.setErrorString("Unsupported LDAP version"); + log.info("#" + msgId + ": unsupported LDAP version - " + version); + return; + } + + // Parse DN + dn = decoder.parseString(true); + + // Peek on AuthenticationChoice; only support simple authentication + int auth = decoder.peekByte(); + if (auth != SIMPLE_AUTHENTICATION) // 0x80 - simple authentication + { + result.setErrorNo(LdapResult.LDAP_AUTH_METHOD_NOT_SUPPORTED); + log.info("#" + msgId + ": unsupported authentication method - " + auth); + return; + } + + // It is simple authentication, get the authentication string + passwd = decoder.parseStringWithTag(SIMPLE_AUTHENTICATION, true, null); + if (passwd != null && passwd.length() > 0) + { + parseDN(dn); + if (userId == null || userId.length() <= 0) + { + result.setErrorNo(LdapResult.LDAP_NO_SUCH_OBJECT); + result.setErrorString(": \"cn\" not defined"); + log.info("#" + msgId + ": \"cn\" not defined"); + return; + } + } + + // Log the information + log.info("#" + msgId + ": bind - version=" + version + ", userId=" + userId); + } + catch (Exception ex) + { + log.log(Level.SEVERE, "", ex); + } + } // handleBind() + + /* + * Parse the DN to find user id, organization and organization unit + */ + private void parseDN(String dName) + { + String[] dnArray = dName.split(","); + for (int i = 0; i < dnArray.length; i++) + { + if (dnArray[i].startsWith("cn=")) + userId = dnArray[i].split("=")[1]; + else if (dnArray[i].startsWith("o=")) + org = dnArray[i].split("=")[1]; + else if (dnArray[i].startsWith("ou=")) + orgUnit = dnArray[i].split("=")[1]; + } + } // parseDN() /** * Get Operation Code @@ -169,4 +267,66 @@ public class LdapMessage return m_protocolOp; } // getOperation -} // LdapMessage + /** + * Get message id + * @return msgId + */ + public int getMsgId() + { + return msgId; + } // getMsgId() + + /** + * Get DN + * @return dn + */ + public String getDN() + { + return dn; + } // getDN() + + /** + * Get User Id + * @return userId + */ + public String getUserId() + { + return userId; + } // getUserId() + + /** + * Get User passwod + * @return passwd + */ + public String getUserPasswd() + { + return passwd; + } // getUserPasswd() + + /** + * Get base object + * @return baseObj + */ + public String getBaseObj() + { + return baseObj; + } // getBaseObj() + + /** + * Get organization + * @return org + */ + public String getOrg() + { + return org; + } // getOrg() + + /** + * Get organization unit + * @return orgUnit + */ + public String getOrgUnit() + { + return orgUnit; + } // getOrgUnit() +} // LdapMessage diff --git a/serverRoot/src/main/server/org/compiere/ldap/LdapProcessor.java b/serverRoot/src/main/server/org/compiere/ldap/LdapProcessor.java index 13a181595a..8906c45976 100644 --- a/serverRoot/src/main/server/org/compiere/ldap/LdapProcessor.java +++ b/serverRoot/src/main/server/org/compiere/ldap/LdapProcessor.java @@ -10,8 +10,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * You may reach us at: ComPiere, Inc. - http://www.adempiere.org/license.html - * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@adempiere.org + * You may reach us at: ComPiere, Inc. - http://www.compiere.org/license.html + * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@compiere.org *****************************************************************************/ package org.compiere.ldap; @@ -19,9 +19,7 @@ import java.net.*; import java.sql.*; import java.util.*; import java.util.logging.*; -import javax.naming.ldap.*; import org.compiere.*; -import org.compiere.ldap.*; import org.compiere.model.*; import org.compiere.server.*; import org.compiere.util.*; @@ -38,19 +36,16 @@ public class LdapProcessor extends AdempiereServer * Ldap Processor (Server) * @param model Ldap Model */ - public LdapProcessor (LdapProcessorModel model) + public LdapProcessor (MLdapProcessor model) { super (model, 300); m_model = model; - init(); } // LdapProcessor /** The Concrete Model */ - private LdapProcessorModel m_model = null; + private MLdapProcessor m_model = null; /** Last Summary */ private StringBuffer m_summary = new StringBuffer(); - /** Client info */ - private MClient m_client = null; /** Server Socket */ private ServerSocket m_serverSocket = null; /** Counter */ @@ -87,7 +82,8 @@ public class LdapProcessor extends AdempiereServer { Socket socket = m_serverSocket.accept(); // waits for connection log.log(Level.FINE, "Connection on Port=" + m_model.getLdapPort()); - LdapConnectionHandler handler = new LdapConnectionHandler (socket); + LdapConnectionHandler handler = + new LdapConnectionHandler (socket, m_model); handler.start(); m_counter++; } @@ -98,24 +94,19 @@ public class LdapProcessor extends AdempiereServer m_summary.append(e.toString()); } + m_summary.append ("; ") + .append (m_model.getInfo()); + + int no = m_model.deleteLog(); + m_summary.append("; Logs deleted=").append(no); + // + MLdapProcessorLog pLog = new MLdapProcessorLog(m_model, m_summary.toString()); + pLog.setReference("#" + String.valueOf(p_runCount) + + " - " + TimeUtil.formatElapsed(new Timestamp(p_startWork))); + pLog.save(); + } // doWork - /** - * Initialize - */ - private void init() - { - try - { - InitialLdapContext lctx = new InitialLdapContext(); - // lctx.setRequestControls(critModCtls); - // lctx.modifyAttributes(name, mods); - Control[] respCtls = lctx.getResponseControls(); - } - catch (Exception e) - { - } - } // /** * Get Server Info @@ -124,7 +115,8 @@ public class LdapProcessor extends AdempiereServer public String getServerInfo() { return "#" + p_runCount + " - Last=" + m_summary.toString() - + "; Counter=" + m_counter; + + "; Counter=" + m_counter + + "; " + m_model.getInfo(); } // getServerInfo /** @@ -134,7 +126,7 @@ public class LdapProcessor extends AdempiereServer public static void main(String[] args) { Adempiere.startup(true); - new LdapProcessor(new LdapProcessorModel(new Properties())).doWork(); + new LdapProcessor(new MLdapProcessor(new Properties(), 0, null)).doWork(); } // main } // LdapProcessor diff --git a/serverRoot/src/main/server/org/compiere/ldap/LdapProcessorModel.java b/serverRoot/src/main/server/org/compiere/ldap/LdapProcessorModel.java deleted file mode 100644 index b2b04e7a4a..0000000000 --- a/serverRoot/src/main/server/org/compiere/ldap/LdapProcessorModel.java +++ /dev/null @@ -1,158 +0,0 @@ -/****************************************************************************** - * Product: Adempiere ERP & CRM Smart Business Solution - * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. - * This program is free software; you can redistribute it and/or modify it - * under the terms version 2 of the GNU General Public License as published - * by the Free Software Foundation. This program is distributed in the hope - * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * You may reach us at: ComPiere, Inc. - http://www.adempiere.org/license.html - * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@adempiere.org - *****************************************************************************/ -package org.compiere.ldap; - -import java.sql.*; -import java.util.*; -import org.compiere.model.*; - -/** - * Interim LDAP Server Model - * - * @author Jorg Janke - * @version $Id: LdapProcessorModel.java,v 1.1 2006/10/09 00:23:16 jjanke Exp $ - */ -public class LdapProcessorModel implements AdempiereProcessor -{ - /** - * Ldap Processor Model - * @param ctx context - */ - public LdapProcessorModel (Properties ctx) - { - m_ctx = ctx; - } - // Properties - private Properties m_ctx = null; - - private Timestamp m_dateNextRun; - private Timestamp m_dateLastRun; - - - public int getLdapPort() - { - return 389; - } - - - - /** - * String Representation - * @return info - */ - public String toString() - { - StringBuffer sb = new StringBuffer (getName()); - sb.append (";Port=").append (getLdapPort()); - return sb.toString (); - } // toString - - - - - /************************************************************************** - * getAD_Client_ID - * @see org.compiere.model.AdempiereProcessor#getAD_Client_ID() - * @return 0 - */ - public int getAD_Client_ID() - { - return 0; - } - /** - * getName - * @see org.compiere.model.AdempiereProcessor#getName() - * @return name - */ - public String getName() - { - return "Adempiere LDAP Server"; - } - /** - * getDescription - * @see org.compiere.model.AdempiereProcessor#getDescription() - * @return - - */ - public String getDescription() - { - return "-"; - } - /** - * Get Ctx - * @return context - */ - public Properties getCtx() - { - return m_ctx; - } - /** - * GetFrequencyType - * @see org.compiere.model.AdempiereProcessor#getFrequencyType() - * @return min - */ - public String getFrequencyType() - { - return MRequestProcessor.FREQUENCYTYPE_Minute; - } - /** - * getFrequency - * @see org.compiere.model.AdempiereProcessor#getFrequency() - * @return 1 - */ - public int getFrequency() - { - return 1; - } - - /** - * Get Unique Server ID - * @return id - */ - public String getServerID() - { - return "Ldap"; - } - - public Timestamp getDateNextRun(boolean requery) - { - return m_dateNextRun; - } - - public void setDateNextRun(Timestamp dateNextWork) - { - m_dateNextRun = dateNextWork; - } - - public Timestamp getDateLastRun() - { - return m_dateLastRun; - } - - public void setDateLastRun(Timestamp dateLastRun) - { - m_dateLastRun = dateLastRun; - } - - public boolean save() - { - return true; - } - - public AdempiereProcessorLog[] getLogs() - { - return new AdempiereProcessorLog[0]; - } -} diff --git a/serverRoot/src/main/server/org/compiere/ldap/LdapResult.java b/serverRoot/src/main/server/org/compiere/ldap/LdapResult.java index 7c459ed878..00b3be5000 100644 --- a/serverRoot/src/main/server/org/compiere/ldap/LdapResult.java +++ b/serverRoot/src/main/server/org/compiere/ldap/LdapResult.java @@ -10,15 +10,15 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * You may reach us at: ComPiere, Inc. - http://www.adempiere.org/license.html - * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@adempiere.org + * You may reach us at: ComPiere, Inc. - http://www.compiere.org/license.html + * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@compiere.org *****************************************************************************/ package org.compiere.ldap; -import java.io.*; import java.util.logging.*; +import org.compiere.model.*; import org.compiere.util.*; -import com.sun.jndi.ldap.*; +import com.sun.jndi.ldap.BerEncoder; /** * Ldap Wire Response @@ -28,120 +28,278 @@ import com.sun.jndi.ldap.*; */ public class LdapResult { - - public LdapResult() - { - super (); - } // LdapResult - - /** - LDAPResult ::= SEQUENCE { - resultCode ENUMERATED { - success (0), - operationsError (1), - protocolError (2), - timeLimitExceeded (3), - sizeLimitExceeded (4), - compareFalse (5), - compareTrue (6), - - authMethodNotSupported (7), - strongAuthRequired (8), - -- 9 reserved -- - referral (10), -- new - adminLimitExceeded (11), -- new - unavailableCriticalExtension (12), -- new - confidentialityRequired (13), -- new - saslBindInProgress (14), -- new - noSuchAttribute (16), - undefinedAttributeType (17), - inappropriateMatching (18), - constraintViolation (19), - attributeOrValueExists (20), - invalidAttributeSyntax (21), - noSuchObject (32), - aliasProblem (33), - invalidDNSyntax (34), - -- 35 reserved for undefined isLeaf -- - aliasDereferencingProblem (36), - -- 37-47 unused -- - inappropriateAuthentication (48), - invalidCredentials (49), - insufficientAccessRights (50), - busy (51), - unavailable (52), - unwillingToPerform (53), - loopDetect (54), - -- 55-63 unused -- - namingViolation (64), - objectClassViolation (65), - notAllowedOnNonLeaf (66), - notAllowedOnRDN (67), - entryAlreadyExists (68), - objectClassModsProhibited (69), - -- 70 reserved for CLDAP -- - affectsMultipleDSAs (71), -- new - -- 72-79 unused -- - other (80) }, - -- 81-90 reserved for APIs -- - matchedDN LDAPDN, - errorMessage LDAPString, - referral [3] Referral OPTIONAL } - **/ - - /** Encoder */ - private BerEncoder m_encoder = new BerEncoder(); - /** Logger */ - private static CLogger log = CLogger.getCLogger (LdapResult.class); - - /** - * Bind Response - * @return reponse - */ - public byte[] bindResponse() - { - try - { -/** - m_encoder.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR); - for (int i = 0; i < sortKeys.length; i++) { - ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR); - ber.encodeString(sortKeys[i].getAttributeID(), true); // v3 - if ((matchingRule = sortKeys[i].getMatchingRuleID()) != null) { - ber.encodeString(matchingRule, (Ber.ASN_CONTEXT | 0), true); - } - if (! sortKeys[i].isAscending()) { - ber.encodeBoolean(true, (Ber.ASN_CONTEXT | 1)); - } - ber.endSeq(); - } -*/ - // payload - m_encoder.beginSeq(Ber.ASN_APPLICATION | LdapMessage.BIND_RESPONSE); - // Response - m_encoder.encodeInt(0); // success - m_encoder.encodeOctetString("cn=testCN".getBytes(), 0); // matched DN - m_encoder.encodeOctetString("".getBytes(), 0); // error mag - // referral - // sasl - // - m_encoder.endSeq(); - log.info("Success"); - } - catch (Exception e) - { - log.log(Level.SEVERE, "", e); - } - return getResult(); - } // bindResponse - - /** - * Get BER Result as byte array - * @return byte array - */ - public byte[] getResult() - { - return m_encoder.getTrimmedBuf(); - } // getResult - -} // LdapResult + /** LdapMesssage */ + private LdapMessage ldapMsg = null; + /** Encoder */ + private BerEncoder m_encoder = null; + /** Logger */ + private static CLogger log = CLogger.getCLogger (LdapResult.class); + /** Error number */ + private int errNo = LDAP_SUCCESS; + /** Error String */ + private String errStr = ""; + /** LdapUser */ + private MLdapUser ldapUser = null; + /** disconnect to client */ + private boolean disconnect = false; + + public LdapResult () + { + } // LdapResult + + /* + * Reset the attributes + */ + public void reset(LdapMessage ldapMsg, MLdapUser ldapUser) + { + this.ldapMsg = ldapMsg; + m_encoder = new BerEncoder(); + errNo = LDAP_SUCCESS; + errStr = ""; + this.ldapUser = ldapUser; + } // reset() + + /** + * Get the response according to the request message + * @param model model + * @return reponse + */ + public byte[] getResult(MLdapProcessor model) + { + if (errNo != LDAP_SUCCESS) + { + generateResult("", + ((ldapMsg.getOperation()==LdapMessage.BIND_REQUEST)? + LdapMessage.BIND_RESPONSE:LdapMessage.SEARCH_RES_RESULT), + errNo, ldapErrorMessage[errNo] + errStr); + m_encoder.getTrimmedBuf(); + } + + try + { + String usrId = ldapMsg.getUserId(); + String o = ldapMsg.getOrg(); + String ou = ldapMsg.getOrgUnit(); + + // Adding the Application 1 Sequence + if (ldapMsg.getOperation() == LdapMessage.BIND_REQUEST) + { + String pwd = ldapMsg.getUserPasswd(); + if (pwd == null || pwd.length() <= 0) + { + // 1st anonymous bind + generateResult(ldapMsg.getDN(), LdapMessage.BIND_RESPONSE, + LDAP_SUCCESS, null); + log.info("Success"); + return m_encoder.getTrimmedBuf(); + } + + // Authenticate with Compiere data + if (ldapUser.getUserId() == null) + { // Try to authenticate on the 1st bind, must be java client + ldapUser.reset(); + model.authenticate(ldapUser, usrId, o, ou); + if (ldapUser.getErrorMsg() != null) + { // Failed to authenticated with compiere + errNo = LDAP_NO_SUCH_OBJECT; + generateResult(ldapMsg.getBaseObj(), LdapMessage.SEARCH_RES_RESULT, + LDAP_NO_SUCH_OBJECT, + ldapErrorMessage[LDAP_NO_SUCH_OBJECT] + ldapUser.getErrorMsg()); + log.info("Failed"); + return m_encoder.getTrimmedBuf(); + } + } + + // Check to see if the input passwd is match to the one + // in compiere database + if (usrId.compareTo(ldapUser.getUserId()) == 0 && + pwd.compareTo(ldapUser.getPassword()) == 0) + { // Successfully authenticated + generateResult("", LdapMessage.BIND_RESPONSE, + LDAP_SUCCESS, null); + // Close the connection to client since most of the client + // application might cache the connection but we can't afford + // to have too many such client connection + disconnect = true; + log.info("Success"); + } + else + { // Unsuccessfully authenticated + errNo = LDAP_INAPPROPRIATE_AUTHENTICATION; + generateResult("", LdapMessage.BIND_RESPONSE, + LDAP_INAPPROPRIATE_AUTHENTICATION, + ldapErrorMessage[LDAP_INAPPROPRIATE_AUTHENTICATION]); + log.info("Failed : " + ldapErrorMessage[LDAP_INAPPROPRIATE_AUTHENTICATION]); + } + } + else if (ldapMsg.getOperation() == LdapMessage.SEARCH_REQUEST) + { + // Authenticate with compiere database + ldapUser.reset(); + model.authenticate(ldapUser, usrId, o, ou); + if (ldapUser.getErrorMsg() != null) + { + errNo = LDAP_NO_SUCH_OBJECT; + generateResult(ldapMsg.getBaseObj(), LdapMessage.SEARCH_RES_RESULT, + LDAP_NO_SUCH_OBJECT, + ldapErrorMessage[LDAP_NO_SUCH_OBJECT] + ldapUser.getErrorMsg()); + log.info("Failed"); + return m_encoder.getTrimmedBuf(); + } + + m_encoder.beginSeq(48); // Hard coded here for Envelope header + m_encoder.encodeInt(ldapMsg.getMsgId()); + m_encoder.beginSeq(LdapMessage.SEARCH_REP_ENTRY); // Application 4 + m_encoder.encodeString("cn="+ldapMsg.getUserId(), true); // this should be object name + // not going to put in any attributes for this + m_encoder.beginSeq(48); + m_encoder.endSeq(); + m_encoder.endSeq(); + m_encoder.endSeq(); + + // SearchResultDone Application 5 for bind + // Result 0 = success + // No error message + generateResult(ldapMsg.getBaseObj(), LdapMessage.SEARCH_RES_RESULT, + LDAP_SUCCESS, null); + log.info("Success"); + } + + return m_encoder.getTrimmedBuf(); + } + catch (Exception e) + { + log.log(Level.SEVERE, "", e); + } + + return m_encoder.getTrimmedBuf(); + } // bindResponse + + /** + * Generate LDAPResult + * @param dn Distinguished Name + * @param resultProtocol Result protocol/operation code + * @param resultCode Result code + * @param errMsg Error Message + * @return reponse + */ + private void generateResult(String dn, int resultProtocol, + int resultCode, String errMsg) + { + try + { + m_encoder.beginSeq(48); // Hard coded here for Envelope header + m_encoder.encodeInt(ldapMsg.getMsgId()); + m_encoder.beginSeq(resultProtocol); + m_encoder.encodeInt(resultCode, 10); // Enumeration - 10 + // Adding LDAPDN + m_encoder.encodeString(dn, true); + // Adding error message + m_encoder.encodeString((errMsg == null)?"":errMsg, true); + m_encoder.endSeq(); + m_encoder.endSeq(); + } + catch (Exception ex) + { + log.log(Level.SEVERE, "", ex); + } + } // generateResult() + + /* + * Should it be close the connection with client + */ + public boolean getDone() + { + if (errNo != LDAP_SUCCESS) + return true; + return disconnect; + } // getDone() + + /** + * Set the error No + * @param errNo Error Number + */ + public void setErrorNo(int errNo) + { + this.errNo = errNo; + } // setErrorNo() + + /** + * Get the error No + * @return errNo Error Number + */ + public int getErrorNo() + { + return errNo; + } // getErrorNo() + + /** + * Set the error String + * @param errStr Error String + */ + public void setErrorString(String errStr) + { + this.errStr = errStr; + } // setErrorStr() + + static final int LDAP_SUCCESS = 0; + static final int LDAP_OPERATIONS_ERROR = 1; + static final int LDAP_PROTOCOL_ERROR = 2; + static final int LDAP_TIME_LIMIT_EXCEEDED = 3; + static final int LDAP_SIZE_LIMIT_EXCEEDED = 4; + static final int LDAP_COMPARE_FALSE = 5; + static final int LDAP_COMPARE_TRUE = 6; + static final int LDAP_AUTH_METHOD_NOT_SUPPORTED = 7; + static final int LDAP_STRONG_AUTH_REQUIRED = 8; + static final int LDAP_PARTIAL_RESULTS = 9; + static final int LDAP_REFERRAL = 10; + static final int LDAP_ADMIN_LIMIT_EXCEEDED = 11; + static final int LDAP_UNAVAILABLE_CRITICAL_EXTENSION = 12; + static final int LDAP_CONFIDENTIALITY_REQUIRED = 13; + static final int LDAP_SASL_BIND_IN_PROGRESS = 14; + static final int LDAP_NO_SUCH_ATTRIBUTE = 16; + static final int LDAP_UNDEFINED_ATTRIBUTE_TYPE = 17; + static final int LDAP_INAPPROPRIATE_MATCHING = 18; + static final int LDAP_CONSTRAINT_VIOLATION = 19; + static final int LDAP_ATTRIBUTE_OR_VALUE_EXISTS = 20; + static final int LDAP_INVALID_ATTRIBUTE_SYNTAX = 21; + static final int LDAP_NO_SUCH_OBJECT = 32; + static final int LDAP_ALIAS_PROBLEM = 33; + static final int LDAP_INVALID_DN_SYNTAX = 34; + static final int LDAP_IS_LEAF = 35; + static final int LDAP_ALIAS_DEREFERENCING_PROBLEM = 36; + static final int LDAP_INAPPROPRIATE_AUTHENTICATION = 48; + static final int LDAP_INVALID_CREDENTIALS = 49; + static final int LDAP_INSUFFICIENT_ACCESS_RIGHTS = 50; + static final int LDAP_BUSY = 51; + static final int LDAP_UNAVAILABLE = 52; + static final int LDAP_UNWILLING_TO_PERFORM = 53; + static final int LDAP_LOOP_DETECT = 54; + static final int LDAP_NAMING_VIOLATION = 64; + static final int LDAP_OBJECT_CLASS_VIOLATION = 65; + static final int LDAP_NOT_ALLOWED_ON_NON_LEAF = 66; + static final int LDAP_NOT_ALLOWED_ON_RDN = 67; + static final int LDAP_ENTRY_ALREADY_EXISTS = 68; + static final int LDAP_OBJECT_CLASS_MODS_PROHIBITED = 69; + static final int LDAP_AFFECTS_MULTIPLE_DSAS = 71; + static final int LDAP_OTHER = 80; + static final String ldapErrorMessage[] = { + "Success", "Operations Error", "Protocol Error", "Timelimit Exceeded", + "Sizelimit Exceeded", "Compare False", "Compare True", + "Authentication Method Not Supported", "Strong Authentication Required", null, + "Referral", "Administrative Limit Exceeded", "Unavailable Critical Extension", + "Confidentiality Required", "SASL Bind In Progress", null, "No Such Attribute", + "Undefined Attribute Type", "Inappropriate Matching", "Constraint Violation", + "Attribute Or Value Exists", "Invalid Attribute Syntax", null, null, null, + null, null, null, null, null,null, null, "No Such Object", "Alias Problem", + "Invalid DN Syntax", null, "Alias Dereferencing Problem", null, null, null, + null, null, null, null, null, null, null, null, "Inappropriate Authentication", + "Invalid Credentials", "Insufficient Access Rights", "Busy", "Unavailable", + "Unwilling To Perform", "Loop Detect", null, null, null, null, null, + null, null, null, null, "Naming Violation", "Object Class Violation", + "Not Allowed On Non-leaf", "Not Allowed On RDN", "Entry Already Exists", + "Object Class Modifications Prohibited", null, "Affects Multiple DSAs", null, + null, null, null, null, null, null, null,"Other", null, null, null, null, + null, null, null, null, null,null + }; +} // LdapResult diff --git a/serverRoot/src/main/server/org/compiere/server/AdempiereServer.java b/serverRoot/src/main/server/org/compiere/server/AdempiereServer.java index 4dde40ed9c..0472f50efb 100644 --- a/serverRoot/src/main/server/org/compiere/server/AdempiereServer.java +++ b/serverRoot/src/main/server/org/compiere/server/AdempiereServer.java @@ -3,25 +3,25 @@ * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * - * by the Free Software Foundation. This program is distributed in the hope * - * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * - * For the text or an alternative of this public license, you may reach us * - * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * - * or via info@compiere.org or http://www.compiere.org/license.html * - *****************************************************************************/ -package org.compiere.server; - -import java.sql.*; -import java.util.*; -import java.util.logging.*; -import org.compiere.ldap.*; -import org.compiere.model.*; -import org.compiere.util.*; + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.compiere.server; + +import java.sql.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.ldap.*; +import org.compiere.model.*; +import org.compiere.util.*; import org.compiere.wf.*; /** @@ -41,23 +41,23 @@ public abstract class AdempiereServer extends Thread { if (model instanceof MRequestProcessor) return new RequestProcessor ((MRequestProcessor)model); - if (model instanceof MWorkflowProcessor) - return new WorkflowProcessor ((MWorkflowProcessor)model); - if (model instanceof MAcctProcessor) - return new AcctProcessor ((MAcctProcessor)model); - if (model instanceof MAlertProcessor) + if (model instanceof MWorkflowProcessor) + return new WorkflowProcessor ((MWorkflowProcessor)model); + if (model instanceof MAcctProcessor) + return new AcctProcessor ((MAcctProcessor)model); + if (model instanceof MAlertProcessor) return new AlertProcessor ((MAlertProcessor)model); if (model instanceof MScheduler) return new Scheduler ((MScheduler)model); - if (model instanceof LdapProcessorModel) - return new LdapProcessor((LdapProcessorModel)model); + if (model instanceof MLdapProcessor) + return new LdapProcessor((MLdapProcessor)model); // throw new IllegalArgumentException("Unknown Processor"); } // create - - - /************************************************************************** - * Server Base Class + + + /************************************************************************** + * Server Base Class * @param model model * @param initialNap delay time running in sec */ @@ -67,11 +67,11 @@ public abstract class AdempiereServer extends Thread p_model = model; m_ctx = new Properties(model.getCtx()); if (p_system == null) - p_system = MSystem.get(m_ctx); - p_client = MClient.get(m_ctx); - Env.setContext(m_ctx, "#AD_Client_ID", p_client.getAD_Client_ID()); - m_initialNap = initialNap; - // log.info(model.getName() + " - " + getThreadGroup()); + p_system = MSystem.get(m_ctx); + p_client = MClient.get(m_ctx); + Env.setContext(m_ctx, "#AD_Client_ID", p_client.getAD_Client_ID()); + m_initialNap = initialNap; + // log.info(model.getName() + " - " + getThreadGroup()); } // ServerBase /** The Processor Model */ @@ -79,221 +79,221 @@ public abstract class AdempiereServer extends Thread /** Initial nap is seconds */ private int m_initialNap = 0; - /** Miliseconds to sleep - 10 Min default */ - private long m_sleepMS = 600000; - /** Sleeping */ - private volatile boolean m_sleeping = false; - /** Server start time */ - private long m_start = 0; - /** Number of Work executions */ - protected int p_runCount = 0; - /** Tine start of work */ - protected long p_startWork = 0; - /** Number MS of last Run */ - private long m_runLastMS = 0; - /** Number of MS total */ - private long m_runTotalMS = 0; - /** When to run next */ - private long m_nextWork = 0; - - /** Logger */ - protected CLogger log = CLogger.getCLogger(getClass()); - /** Context */ - private Properties m_ctx = null; - /** System */ - protected static MSystem p_system = null; - /** Client */ - protected MClient p_client = null; - - /** - * Get Server Context - * @return context - */ - public Properties getCtx() - { - return m_ctx; - } // getCtx - - /** - * @return Returns the sleepMS. - */ - public long getSleepMS () - { - return m_sleepMS; - } // getSleepMS - - - /** - * Sleep for set time - * @return true if not interrupted - */ - public boolean sleep() - { - if (isInterrupted()) - { - log.info (getName() + ": interrupted"); - return false; - } - log.fine(getName() + ": sleeping " + TimeUtil.formatElapsed(m_sleepMS)); - m_sleeping = true; - try - { - sleep (m_sleepMS); - } - catch (InterruptedException e) - { - log.info (getName() + ": interrupted"); - m_sleeping = false; - return false; - } - m_sleeping = false; - return true; - } // sleep - - /** - * Run Now - */ - public void runNow() - { - log.info(getName()); - p_startWork = System.currentTimeMillis(); - doWork(); - long now = System.currentTimeMillis(); - // --------------- - - p_runCount++; - m_runLastMS = now - p_startWork; - m_runTotalMS += m_runLastMS; - // - p_model.setDateLastRun(new Timestamp(now)); - p_model.save(); - // - log.fine(getName() + ": " + getStatistics()); - } // runNow - - /************************************************************************** - * Run async - */ - public void run () - { - try - { - log.fine(getName() + ": pre-nap - " + m_initialNap); - sleep (m_initialNap * 1000); - } - catch (InterruptedException e) - { - log.log(Level.SEVERE, getName() + ": pre-nap interrupted", e); - return; - } - - m_start = System.currentTimeMillis(); - while (true) - { - if (m_nextWork == 0) - { - Timestamp dateNextRun = getDateNextRun(true); - if (dateNextRun != null) - m_nextWork = dateNextRun.getTime(); - } - long now = System.currentTimeMillis(); - if (m_nextWork > now) - { - m_sleepMS = m_nextWork - now; - if (!sleep ()) - break; - } - if (isInterrupted()) - { - log.info (getName() + ": interrupted"); - break; - } - - // --------------- - p_startWork = System.currentTimeMillis(); - doWork(); - now = System.currentTimeMillis(); - // --------------- - - p_runCount++; - m_runLastMS = now - p_startWork; - m_runTotalMS += m_runLastMS; - // - m_sleepMS = calculateSleep(); - m_nextWork = now + m_sleepMS; - // - p_model.setDateLastRun(new Timestamp(now)); - p_model.setDateNextRun(new Timestamp(m_nextWork)); - p_model.save(); - // - log.fine(getName() + ": " + getStatistics()); - if (!sleep()) - break; - } - m_start = 0; - } // run - - /** - * Get Run Statistics - * @return Statistic info - */ - public String getStatistics() - { - return "Run #" + p_runCount - + " - Last=" + TimeUtil.formatElapsed(m_runLastMS) - + " - Total=" + TimeUtil.formatElapsed(m_runTotalMS) - + " - Next " + TimeUtil.formatElapsed(m_nextWork - System.currentTimeMillis()); - } // getStatistics - - /** - * Do the actual Work - */ - protected abstract void doWork(); - - /** - * Get Server Info - * @return info - */ - public abstract String getServerInfo(); - - /** - * Get Unique ID - * @return Unique ID - */ - public String getServerID() - { - return p_model.getServerID(); - } // getServerID - - /** - * Get the date Next run - * @param requery requery database - * @return date next run - */ - public Timestamp getDateNextRun (boolean requery) - { - return p_model.getDateNextRun(requery); - } // getDateNextRun - - /** - * Get the date Last run - * @return date lext run - */ - public Timestamp getDateLastRun () - { - return p_model.getDateLastRun(); - } // getDateLastRun - - /** - * Get Description - * @return Description - */ - public String getDescription() - { - return p_model.getDescription(); - } // getDescription - - /** + /** Miliseconds to sleep - 10 Min default */ + private long m_sleepMS = 600000; + /** Sleeping */ + private volatile boolean m_sleeping = false; + /** Server start time */ + private long m_start = 0; + /** Number of Work executions */ + protected int p_runCount = 0; + /** Tine start of work */ + protected long p_startWork = 0; + /** Number MS of last Run */ + private long m_runLastMS = 0; + /** Number of MS total */ + private long m_runTotalMS = 0; + /** When to run next */ + private long m_nextWork = 0; + + /** Logger */ + protected CLogger log = CLogger.getCLogger(getClass()); + /** Context */ + private Properties m_ctx = null; + /** System */ + protected static MSystem p_system = null; + /** Client */ + protected MClient p_client = null; + + /** + * Get Server Context + * @return context + */ + public Properties getCtx() + { + return m_ctx; + } // getCtx + + /** + * @return Returns the sleepMS. + */ + public long getSleepMS () + { + return m_sleepMS; + } // getSleepMS + + + /** + * Sleep for set time + * @return true if not interrupted + */ + public boolean sleep() + { + if (isInterrupted()) + { + log.info (getName() + ": interrupted"); + return false; + } + log.fine(getName() + ": sleeping " + TimeUtil.formatElapsed(m_sleepMS)); + m_sleeping = true; + try + { + sleep (m_sleepMS); + } + catch (InterruptedException e) + { + log.info (getName() + ": interrupted"); + m_sleeping = false; + return false; + } + m_sleeping = false; + return true; + } // sleep + + /** + * Run Now + */ + public void runNow() + { + log.info(getName()); + p_startWork = System.currentTimeMillis(); + doWork(); + long now = System.currentTimeMillis(); + // --------------- + + p_runCount++; + m_runLastMS = now - p_startWork; + m_runTotalMS += m_runLastMS; + // + p_model.setDateLastRun(new Timestamp(now)); + p_model.save(); + // + log.fine(getName() + ": " + getStatistics()); + } // runNow + + /************************************************************************** + * Run async + */ + public void run () + { + try + { + log.fine(getName() + ": pre-nap - " + m_initialNap); + sleep (m_initialNap * 1000); + } + catch (InterruptedException e) + { + log.log(Level.SEVERE, getName() + ": pre-nap interrupted", e); + return; + } + + m_start = System.currentTimeMillis(); + while (true) + { + if (m_nextWork == 0) + { + Timestamp dateNextRun = getDateNextRun(true); + if (dateNextRun != null) + m_nextWork = dateNextRun.getTime(); + } + long now = System.currentTimeMillis(); + if (m_nextWork > now) + { + m_sleepMS = m_nextWork - now; + if (!sleep ()) + break; + } + if (isInterrupted()) + { + log.info (getName() + ": interrupted"); + break; + } + + // --------------- + p_startWork = System.currentTimeMillis(); + doWork(); + now = System.currentTimeMillis(); + // --------------- + + p_runCount++; + m_runLastMS = now - p_startWork; + m_runTotalMS += m_runLastMS; + // + m_sleepMS = calculateSleep(); + m_nextWork = now + m_sleepMS; + // + p_model.setDateLastRun(new Timestamp(now)); + p_model.setDateNextRun(new Timestamp(m_nextWork)); + p_model.save(); + // + log.fine(getName() + ": " + getStatistics()); + if (!sleep()) + break; + } + m_start = 0; + } // run + + /** + * Get Run Statistics + * @return Statistic info + */ + public String getStatistics() + { + return "Run #" + p_runCount + + " - Last=" + TimeUtil.formatElapsed(m_runLastMS) + + " - Total=" + TimeUtil.formatElapsed(m_runTotalMS) + + " - Next " + TimeUtil.formatElapsed(m_nextWork - System.currentTimeMillis()); + } // getStatistics + + /** + * Do the actual Work + */ + protected abstract void doWork(); + + /** + * Get Server Info + * @return info + */ + public abstract String getServerInfo(); + + /** + * Get Unique ID + * @return Unique ID + */ + public String getServerID() + { + return p_model.getServerID(); + } // getServerID + + /** + * Get the date Next run + * @param requery requery database + * @return date next run + */ + public Timestamp getDateNextRun (boolean requery) + { + return p_model.getDateNextRun(requery); + } // getDateNextRun + + /** + * Get the date Last run + * @return date lext run + */ + public Timestamp getDateLastRun () + { + return p_model.getDateLastRun(); + } // getDateLastRun + + /** + * Get Description + * @return Description + */ + public String getDescription() + { + return p_model.getDescription(); + } // getDescription + + /** * Get Model * @return Model */ @@ -301,82 +301,82 @@ public abstract class AdempiereServer extends Thread { return p_model; } // getModel - - /** - * Calculate Sleep ms - * @return miliseconds - */ - private long calculateSleep () - { - String frequencyType = p_model.getFrequencyType(); - int frequency = p_model.getFrequency(); - if (frequency < 1) - frequency = 1; - // - long typeSec = 600; // 10 minutes - if (frequencyType == null) - typeSec = 300; // 5 minutes - else if (X_R_RequestProcessor.FREQUENCYTYPE_Minute.equals(frequencyType)) - typeSec = 60; - else if (X_R_RequestProcessor.FREQUENCYTYPE_Hour.equals(frequencyType)) - typeSec = 3600; - else if (X_R_RequestProcessor.FREQUENCYTYPE_Day.equals(frequencyType)) - typeSec = 86400; - // - return typeSec * 1000 * frequency; // ms - } // calculateSleep - - /** - * Is Sleeping - * @return sleeping - */ - public boolean isSleeping() - { - return m_sleeping; - } // isSleeping - - /** - * String Representation - * @return info - */ - public String toString () - { - StringBuffer sb = new StringBuffer (getName()) - .append (",Prio=").append(getPriority()) - .append (",").append (getThreadGroup()) - .append (",Alive=").append(isAlive()) - .append (",Sleeping=").append(m_sleeping) - .append (",Last=").append(getDateLastRun()); - if (m_sleeping) - sb.append (",Next=").append(getDateNextRun(false)); - return sb.toString (); - } // toString - - /** - * Get Seconds Alive - * @return seconds alive - */ - public int getSecondsAlive() - { - if (m_start == 0) - return 0; - long now = System.currentTimeMillis(); - long ms = (now-m_start) / 1000; - return (int)ms; - } // getSecondsAlive - - /** - * Get Start Time - * @return start time - */ - public Timestamp getStartTime() - { - if (m_start == 0) - return null; - return new Timestamp (m_start); - } // getStartTime - - /** + + /** + * Calculate Sleep ms + * @return miliseconds + */ + private long calculateSleep () + { + String frequencyType = p_model.getFrequencyType(); + int frequency = p_model.getFrequency(); + if (frequency < 1) + frequency = 1; + // + long typeSec = 600; // 10 minutes + if (frequencyType == null) + typeSec = 300; // 5 minutes + else if (X_R_RequestProcessor.FREQUENCYTYPE_Minute.equals(frequencyType)) + typeSec = 60; + else if (X_R_RequestProcessor.FREQUENCYTYPE_Hour.equals(frequencyType)) + typeSec = 3600; + else if (X_R_RequestProcessor.FREQUENCYTYPE_Day.equals(frequencyType)) + typeSec = 86400; + // + return typeSec * 1000 * frequency; // ms + } // calculateSleep + + /** + * Is Sleeping + * @return sleeping + */ + public boolean isSleeping() + { + return m_sleeping; + } // isSleeping + + /** + * String Representation + * @return info + */ + public String toString () + { + StringBuffer sb = new StringBuffer (getName()) + .append (",Prio=").append(getPriority()) + .append (",").append (getThreadGroup()) + .append (",Alive=").append(isAlive()) + .append (",Sleeping=").append(m_sleeping) + .append (",Last=").append(getDateLastRun()); + if (m_sleeping) + sb.append (",Next=").append(getDateNextRun(false)); + return sb.toString (); + } // toString + + /** + * Get Seconds Alive + * @return seconds alive + */ + public int getSecondsAlive() + { + if (m_start == 0) + return 0; + long now = System.currentTimeMillis(); + long ms = (now-m_start) / 1000; + return (int)ms; + } // getSecondsAlive + + /** + * Get Start Time + * @return start time + */ + public Timestamp getStartTime() + { + if (m_start == 0) + return null; + return new Timestamp (m_start); + } // getStartTime + + /** * Get Processor Logs * @return logs */ diff --git a/serverRoot/src/main/server/org/compiere/server/AdempiereServerMgr.java b/serverRoot/src/main/server/org/compiere/server/AdempiereServerMgr.java index 5285c1cdd6..d79098a82d 100644 --- a/serverRoot/src/main/server/org/compiere/server/AdempiereServerMgr.java +++ b/serverRoot/src/main/server/org/compiere/server/AdempiereServerMgr.java @@ -20,7 +20,6 @@ import java.sql.*; import java.util.*; import java.util.logging.*; import org.compiere.*; -import org.compiere.ldap.*; import org.compiere.model.*; import org.compiere.util.*; import org.compiere.wf.*; @@ -148,12 +147,15 @@ public class AdempiereServerMgr m_servers.add(server); } // LDAP - LdapProcessorModel lp = new LdapProcessorModel(m_ctx); - AdempiereServer server = AdempiereServer.create(lp); - server.start(); - server.setPriority(Thread.NORM_PRIORITY-2); - m_servers.add(server); - + MLdapProcessor[] ldapModels = MLdapProcessor.getActive(m_ctx); + for (int i = 0; i < ldapModels.length; i++) + { + MLdapProcessor lp = ldapModels[i]; + AdempiereServer server = AdempiereServer.create(lp); + server.start(); + server.setPriority(Thread.NORM_PRIORITY-1); + m_servers.add(server); + } log.fine("#" + noServers); return startAll(); diff --git a/serverRoot/src/web/adempiere.jnlp b/serverRoot/src/web/adempiere.jnlp index 858d1e54d3..053593f80e 100644 --- a/serverRoot/src/web/adempiere.jnlp +++ b/serverRoot/src/web/adempiere.jnlp @@ -3,7 +3,7 @@ codebase = "$$context/adempiereHome" href = "$$context/adempiere.jnlp"> - Adempiere Client 3.1.1 $$context + Adempiere Client 3.1.2 $$context ComPiere, Inc.