Implemented FR [ 1696228 ] ModelValidator for BeforePost and AfterPost

Moved lots of sources and packages to base as discussed in forums
This commit is contained in:
Carlos Ruiz 2007-05-09 11:08:52 +00:00
parent 0cd4cb4b9e
commit 39c44b6373
878 changed files with 11541 additions and 12 deletions

View File

@ -21,7 +21,7 @@
<pathelement path="${classpath}"/> <pathelement path="${classpath}"/>
<pathelement location="../tools/lib/j2ee.jar" /> <pathelement location="../tools/lib/j2ee.jar" />
<pathelement location="../JasperReports/CompiereJasper.jar" /> <pathelement location="../JasperReports/CompiereJasper.jar" />
<pathelement location="../dbPort/dbPort.jar" /> <pathelement location="../base/Base.jar" />
</path> </path>
<target name="compile"> <target name="compile">

View File

@ -22,6 +22,9 @@
<path id="project.class.path"> <path id="project.class.path">
<pathelement path="${classpath}"/> <pathelement path="${classpath}"/>
<pathelement path="${jar.path}/CCTools.jar"/> <pathelement path="${jar.path}/CCTools.jar"/>
<pathelement path="${jar.path}/oracle.jar"/>
<pathelement path="${jar.path}/postgresql.jar"/>
<pathelement path="${jar.path}/jboss.jar"/>
<pathelement path="../dbPort/dbPort.jar"/> <pathelement path="../dbPort/dbPort.jar"/>
<pathelement path="../looks/CLooks.jar"/> <pathelement path="../looks/CLooks.jar"/>
<pathelement path="../print/Print.jar"/> <pathelement path="../print/Print.jar"/>
@ -52,7 +55,7 @@
<target name="compile" depends="makedir"> <target name="compile" depends="makedir">
<!-- compile the java code from ${src} into ${build.dir} --> <!-- compile the java code from ${src} into ${build.dir} -->
<javac srcdir="${src}" destdir="${build.dir}" deprecation="on" debug="on"> <javac fork="true" srcdir="${src}" destdir="${build.dir}" deprecation="on" debug="on" memoryinitialsize="512m" memorymaximumsize="512m">
<classpath refid="project.class.path"/> <classpath refid="project.class.path"/>
</javac> </javac>
<!-- copy all image & sound files from src to the build directory --> <!-- copy all image & sound files from src to the build directory -->

View File

Before

Width:  |  Height:  |  Size: 972 B

After

Width:  |  Height:  |  Size: 972 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1013 B

After

Width:  |  Height:  |  Size: 1013 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 688 B

View File

Before

Width:  |  Height:  |  Size: 689 B

After

Width:  |  Height:  |  Size: 689 B

View File

Before

Width:  |  Height:  |  Size: 908 B

After

Width:  |  Height:  |  Size: 908 B

View File

Before

Width:  |  Height:  |  Size: 901 B

After

Width:  |  Height:  |  Size: 901 B

View File

Before

Width:  |  Height:  |  Size: 908 B

After

Width:  |  Height:  |  Size: 908 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,142 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import org.compiere.util.*;
/**
* Allocation Line
*
* @author Jorg Janke
* @version $Id: DocLine_Allocation.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $
*/
public class DocLine_Allocation extends DocLine
{
/**
* DocLine_Allocation
* @param line allocation line
* @param doc header
*/
public DocLine_Allocation (MAllocationLine line, Doc doc)
{
super (line, doc);
m_C_Payment_ID = line.getC_Payment_ID();
m_C_CashLine_ID = line.getC_CashLine_ID();
m_C_Invoice_ID = line.getC_Invoice_ID();
m_C_Order_ID = line.getC_Order_ID();
//
setAmount(line.getAmount());
m_DiscountAmt = line.getDiscountAmt();
m_WriteOffAmt = line.getWriteOffAmt();
m_OverUnderAmt = line.getOverUnderAmt();
} // DocLine_Allocation
private int m_C_Invoice_ID;
private int m_C_Payment_ID;
private int m_C_CashLine_ID;
private int m_C_Order_ID;
private BigDecimal m_DiscountAmt;
private BigDecimal m_WriteOffAmt;
private BigDecimal m_OverUnderAmt;
/**
* Get Invoice C_Currency_ID
* @return 0 if no invoice -1 if not found
*/
public int getInvoiceC_Currency_ID()
{
if (m_C_Invoice_ID == 0)
return 0;
String sql = "SELECT C_Currency_ID "
+ "FROM C_Invoice "
+ "WHERE C_Invoice_ID=?";
return DB.getSQLValue(null, sql, m_C_Invoice_ID);
} // getInvoiceC_Currency_ID
/**
* String Representation
* @return info
*/
public String toString ()
{
StringBuffer sb = new StringBuffer ("DocLine_Allocation[");
sb.append(get_ID())
.append(",Amt=").append(getAmtSource())
.append(",Discount=").append(getDiscountAmt())
.append(",WriteOff=").append(getWriteOffAmt())
.append(",OverUnderAmt=").append(getOverUnderAmt())
.append(" - C_Payment_ID=").append(m_C_Payment_ID)
.append(",C_CashLine_ID=").append(m_C_CashLine_ID)
.append(",C_Invoice_ID=").append(m_C_Invoice_ID)
.append("]");
return sb.toString ();
} // toString
/**
* @return Returns the c_Order_ID.
*/
public int getC_Order_ID ()
{
return m_C_Order_ID;
}
/**
* @return Returns the discountAmt.
*/
public BigDecimal getDiscountAmt ()
{
return m_DiscountAmt;
}
/**
* @return Returns the overUnderAmt.
*/
public BigDecimal getOverUnderAmt ()
{
return m_OverUnderAmt;
}
/**
* @return Returns the writeOffAmt.
*/
public BigDecimal getWriteOffAmt ()
{
return m_WriteOffAmt;
}
/**
* @return Returns the c_CashLine_ID.
*/
public int getC_CashLine_ID ()
{
return m_C_CashLine_ID;
}
/**
* @return Returns the c_Invoice_ID.
*/
public int getC_Invoice_ID ()
{
return m_C_Invoice_ID;
}
/**
* @return Returns the c_Payment_ID.
*/
public int getC_Payment_ID ()
{
return m_C_Payment_ID;
}
} // DocLine_Allocation

View File

@ -0,0 +1,122 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import org.compiere.util.*;
//import org.compiere.model.*;
/**
* Bank Statement Line
*
* @author Jorg Janke
* @version $Id: DocLine_Bank.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $
*/
public class DocLine_Bank extends DocLine
{
/**
* Constructor
* @param line statement line
* @param doc header
*/
public DocLine_Bank (MBankStatementLine line, Doc_Bank doc)
{
super (line, doc);
m_C_Payment_ID = line.getC_Payment_ID();
m_IsReversal = line.isReversal();
//
m_StmtAmt = line.getStmtAmt();
m_InterestAmt = line.getInterestAmt();
m_TrxAmt = line.getTrxAmt();
//
setDateDoc(line.getValutaDate());
setC_BPartner_ID(line.getC_BPartner_ID());
} // DocLine_Bank
/** Reversal Flag */
private boolean m_IsReversal = false;
/** Payment */
private int m_C_Payment_ID = 0;
private BigDecimal m_TrxAmt = Env.ZERO;
private BigDecimal m_StmtAmt = Env.ZERO;
private BigDecimal m_InterestAmt = Env.ZERO;
/**
* Get Payment
* @return C_Paymnet_ID
*/
public int getC_Payment_ID()
{
return m_C_Payment_ID;
} // getC_Payment_ID
/**
* Get AD_Org_ID
* @param payment if true get Org from payment
* @return org
*/
public int getAD_Org_ID (boolean payment)
{
if (payment && getC_Payment_ID() != 0)
{
String sql = "SELECT AD_Org_ID FROM C_Payment WHERE C_Payment_ID=?";
int id = DB.getSQLValue(null, sql, getC_Payment_ID());
if (id > 0)
return id;
}
return super.getAD_Org_ID();
} // getAD_Org_ID
/**
* Is Reversal
* @return true if reversal
*/
public boolean isReversal()
{
return m_IsReversal;
} // isReversal
/**
* Get Interest
* @return InterestAmount
*/
public BigDecimal getInterestAmt()
{
return m_InterestAmt;
} // getInterestAmt
/**
* Get Statement
* @return Starement Amount
*/
public BigDecimal getStmtAmt()
{
return m_StmtAmt;
} // getStrmtAmt
/**
* Get Transaction
* @return transaction amount
*/
public BigDecimal getTrxAmt()
{
return m_TrxAmt;
} // getTrxAmt
} // DocLine_Bank

View File

@ -0,0 +1,138 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import org.compiere.util.*;
/**
* Cash Journal Line
*
* @author Jorg Janke
* @version $Id: DocLine_Cash.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class DocLine_Cash extends DocLine
{
/**
* Constructor
* @param line cash line
* @param doc header
*/
public DocLine_Cash (MCashLine line, Doc_Cash doc)
{
super (line, doc);
m_CashType = line.getCashType();
m_C_BankAccount_ID = line.getC_BankAccount_ID();
m_C_Invoice_ID = line.getC_Invoice_ID();
//
if (m_C_Invoice_ID != 0)
{
MInvoice invoice = MInvoice.get(line.getCtx(), m_C_Invoice_ID);
setC_BPartner_ID(invoice.getC_BPartner_ID());
}
//
m_Amount = line.getAmount();
m_DiscountAmt = line.getDiscountAmt();
m_WriteOffAmt = line.getWriteOffAmt();
setAmount(m_Amount);
} // DocLine_Cash
/** Cash Type */
private String m_CashType = "";
// AD_Reference_ID=217
/** Charge - C */
public static final String CASHTYPE_CHARGE = "C";
/** Difference - D */
public static final String CASHTYPE_DIFFERENCE = "D";
/** Expense - E */
public static final String CASHTYPE_EXPENSE = "E";
/** Onvoice - I */
public static final String CASHTYPE_INVOICE = "I";
/** Receipt - R */
public static final String CASHTYPE_RECEIPT = "R";
/** Transfer - T */
public static final String CASHTYPE_TRANSFER = "T";
// References
private int m_C_BankAccount_ID = 0;
private int m_C_Invoice_ID = 0;
// Amounts
private BigDecimal m_Amount = Env.ZERO;
private BigDecimal m_DiscountAmt = Env.ZERO;
private BigDecimal m_WriteOffAmt = Env.ZERO;
/**
* Get Cash Type
* @return cash type
*/
public String getCashType()
{
return m_CashType;
} // getCashType
/**
* Get Bank Account
* @return Bank Account
*/
public int getC_BankAccount_ID()
{
return m_C_BankAccount_ID;
} // getC_BankAccount_ID
/**
* Get Invoice
* @return C_Invoice_ID
*/
public int getC_Invoice_ID()
{
return m_C_Invoice_ID;
} // getC_Invoice_ID
/**
* Get Amount
* @return Payment Amount
*/
public BigDecimal getAmount()
{
return m_Amount;
}
/**
* Get Discount
* @return Discount Amount
*/
public BigDecimal getDiscountAmt()
{
return m_DiscountAmt;
}
/**
* Get WriteOff
* @return Write-Off Amount
*/
public BigDecimal getWriteOffAmt()
{
return m_WriteOffAmt;
}
} // DocLine_Cash

View File

@ -0,0 +1,240 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import java.util.logging.*;
import org.compiere.util.*;
/**
* Document Tax Line
*
* @author Jorg Janke
* @version $Id: DocTax.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public final class DocTax
{
/**
* Create Tax
* @param C_Tax_ID tax
* @param name name
* @param rate rate
* @param taxBaseAmt tax base amount
* @param amount amount
* @param salesTax sales tax flag
*/
public DocTax (int C_Tax_ID, String name, BigDecimal rate,
BigDecimal taxBaseAmt, BigDecimal amount, boolean salesTax)
{
m_C_Tax_ID = C_Tax_ID;
m_name = name;
m_rate = rate;
m_amount = amount;
m_salesTax = salesTax;
} // DocTax
/** Tax ID */
private int m_C_Tax_ID = 0;
/** Amount */
private BigDecimal m_amount = null;
/** Tax Rate */
private BigDecimal m_rate = null;
/** Name */
private String m_name = null;
/** Base Tax Amt */
private BigDecimal m_taxBaseAmt = null;
/** Included Tax */
private BigDecimal m_includedTax = Env.ZERO;
/** Sales Tax */
private boolean m_salesTax = false;
/** Logger */
private static CLogger log = CLogger.getCLogger(DocTax.class);
/** Tax Due Acct */
public static final int ACCTTYPE_TaxDue = 0;
/** Tax Liability */
public static final int ACCTTYPE_TaxLiability = 1;
/** Tax Credit */
public static final int ACCTTYPE_TaxCredit = 2;
/** Tax Receivables */
public static final int ACCTTYPE_TaxReceivables = 3;
/** Tax Expense */
public static final int ACCTTYPE_TaxExpense = 4;
/**
* Get Account
* @param AcctType see ACCTTYPE_*
* @param as account schema
* @return Account
*/
public MAccount getAccount (int AcctType, MAcctSchema as)
{
if (AcctType < 0 || AcctType > 4)
return null;
//
String sql = "SELECT T_Due_Acct, T_Liability_Acct, T_Credit_Acct, T_Receivables_Acct, T_Expense_Acct "
+ "FROM C_Tax_Acct WHERE C_Tax_ID=? AND C_AcctSchema_ID=?";
int validCombination_ID = 0;
try
{
PreparedStatement pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(1, m_C_Tax_ID);
pstmt.setInt(2, as.getC_AcctSchema_ID());
ResultSet rs = pstmt.executeQuery();
if (rs.next())
validCombination_ID = rs.getInt(AcctType+1); // 1..5
rs.close();
pstmt.close();
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
}
if (validCombination_ID == 0)
return null;
return MAccount.get(as.getCtx(), validCombination_ID);
} // getAccount
/**
* Get Amount
* @return gross amount
*/
public BigDecimal getAmount()
{
return m_amount;
}
/**
* Get Base Amount
* @return net amount
*/
public BigDecimal getTaxBaseAmt()
{
return m_taxBaseAmt;
}
/**
* Get Rate
* @return tax rate in percent
*/
public BigDecimal getRate()
{
return m_rate;
}
/**
* Get Name of Tax
* @return name
*/
public String getName()
{
return m_name;
}
/**
* Get C_Tax_ID
* @return tax id
*/
public int getC_Tax_ID()
{
return m_C_Tax_ID;
} // getC_Tax_ID
/**
* Get Description (Tax Name and Base Amount)
* @return tax anme and base amount
*/
public String getDescription()
{
return m_name + " " + m_taxBaseAmt.toString();
} // getDescription
/**
* Add to Included Tax
* @param amt amount
*/
public void addIncludedTax (BigDecimal amt)
{
m_includedTax = m_includedTax.add(amt);
} // addIncludedTax
/**
* Get Included Tax
* @return tax amount
*/
public BigDecimal getIncludedTax()
{
return m_includedTax;
} // getIncludedTax
/**
* Get Included Tax Difference
* @return tax ampunt - included amount
*/
public BigDecimal getIncludedTaxDifference()
{
return m_amount.subtract(m_includedTax);
} // getIncludedTaxDifference
/**
* Included Tax differs from tax amount
* @return true if difference
*/
public boolean isIncludedTaxDifference()
{
return Env.ZERO.compareTo(getIncludedTaxDifference()) != 0;
} // isIncludedTaxDifference
/**
* Get AP Tax Type
* @return AP tax type (Credit or Expense)
*/
public int getAPTaxType()
{
if (isSalesTax())
return ACCTTYPE_TaxExpense;
return ACCTTYPE_TaxCredit;
} // getAPTaxAcctType
/**
* Is Sales Tax
* @return sales tax
*/
public boolean isSalesTax()
{
return m_salesTax;
} // isSalesTax
/**
* Return String representation
* @return tax anme and base amount
*/
public String toString()
{
StringBuffer sb = new StringBuffer("Tax=(");
sb.append(m_name);
sb.append(" Amt=").append(m_amount);
sb.append(")");
return sb.toString();
} // toString
} // DocTax

View File

@ -0,0 +1,895 @@
/******************************************************************************
* 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. *
* 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 Allocation Documents.
* <pre>
* Table: C_AllocationHdr
* Document Types: CMA
* </pre>
* @author Jorg Janke
* @version $Id: Doc_Allocation.java,v 1.6 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Allocation extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_Allocation (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MAllocationHdr.class, rs, DOCTYPE_Allocation, trxName);
} // Doc_Allocation
/** Tolearance G&L */
private static final BigDecimal TOLERANCE = new BigDecimal (0.02);
/** Facts */
private ArrayList<Fact> m_facts = null;
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
MAllocationHdr alloc = (MAllocationHdr)getPO();
setDateDoc(alloc.getDateTrx());
// Contained Objects
p_lines = loadLines(alloc);
return null;
} // loadDocumentDetails
/**
* Load Invoice Line
* @param alloc header
* @return DocLine Array
*/
private DocLine[] loadLines(MAllocationHdr alloc)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
MAllocationLine[] lines = alloc.getLines(false);
for (int i = 0; i < lines.length; i++)
{
MAllocationLine line = lines[i];
DocLine_Allocation docLine = new DocLine_Allocation(line, this);
// Get Payment Conversion Rate
if (line.getC_Payment_ID() != 0)
{
MPayment payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName());
int C_ConversionType_ID = payment.getC_ConversionType_ID();
docLine.setC_ConversionType_ID(C_ConversionType_ID);
}
//
log.fine(docLine.toString());
list.add (docLine);
}
// Return Array
DocLine[] dls = new DocLine[list.size()];
list.toArray(dls);
return dls;
} // loadLines
/**************************************************************************
* 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 = Env.ZERO;
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* CMA.
* <pre>
* AR_Invoice_Payment
* UnAllocatedCash DR
* or C_Prepayment
* DiscountExp DR
* WriteOff DR
* Receivables CR
* AR_Invoice_Cash
* CashTransfer DR
* DiscountExp DR
* WriteOff DR
* Receivables CR
*
* AP_Invoice_Payment
* Liability DR
* DiscountRev CR
* WriteOff CR
* PaymentSelect CR
* or V_Prepayment
* AP_Invoice_Cash
* Liability DR
* DiscountRev CR
* WriteOff CR
* CashTransfer CR
* CashBankTransfer
* -
* ==============================
* Realized Gain & Loss
* AR/AP DR CR
* Realized G/L DR CR
*
*
* </pre>
* Tax needs to be corrected for discount & write-off;
* Currency gain & loss is realized here.
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
m_facts = new ArrayList<Fact>();
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
for (int i = 0; i < p_lines.length; i++)
{
DocLine_Allocation line = (DocLine_Allocation)p_lines[i];
setC_BPartner_ID(line.getC_BPartner_ID());
// CashBankTransfer - all references null and Discount/WriteOff = 0
if (line.getC_Payment_ID() != 0
&& line.getC_Invoice_ID() == 0 && line.getC_Order_ID() == 0
&& line.getC_CashLine_ID() == 0 && line.getC_BPartner_ID() == 0
&& Env.ZERO.compareTo(line.getDiscountAmt()) == 0
&& Env.ZERO.compareTo(line.getWriteOffAmt()) == 0)
continue;
// Receivables/Liability Amt
BigDecimal allocationSource = line.getAmtSource()
.add(line.getDiscountAmt())
.add(line.getWriteOffAmt());
//Modified Lines by Armen
//Old:
//BigDecimal allocationAccounted = null; // AR/AP balance corrected
BigDecimal allocationAccounted = Env.ZERO; // AR/AP balance corrected
//End of Modified Lines
FactLine fl = null;
MAccount bpAcct = null; // Liability/Receivables
//
MPayment payment = null;
if (line.getC_Payment_ID() != 0)
payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName());
MInvoice invoice = null;
if (line.getC_Invoice_ID() != 0)
invoice = new MInvoice (getCtx(), line.getC_Invoice_ID(), null);
// No Invoice
if (invoice == null)
{
// Payment Only
if (line.getC_Invoice_ID() == 0 && line.getC_Payment_ID() != 0)
{
fl = fact.createLine (line, getPaymentAcct(as, line.getC_Payment_ID()),
getC_Currency_ID(), line.getAmtSource(), null);
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
}
else
{
p_Error = "Cannot determine SO/PO";
log.log(Level.SEVERE, p_Error);
return null;
}
}
// Sales Invoice
else if (invoice.isSOTrx())
{
// Payment/Cash DR
if (line.getC_Payment_ID() != 0)
{
fl = fact.createLine (line, getPaymentAcct(as, line.getC_Payment_ID()),
getC_Currency_ID(), line.getAmtSource(), null);
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
}
else if (line.getC_CashLine_ID() != 0)
{
fl = fact.createLine (line, getCashAcct(as, line.getC_CashLine_ID()),
getC_Currency_ID(), line.getAmtSource(), null);
MCashLine cashLine = new MCashLine (getCtx(), line.getC_CashLine_ID(), getTrxName());
if (fl != null && cashLine.get_ID() != 0)
fl.setAD_Org_ID(cashLine.getAD_Org_ID());
}
// Discount DR
if (Env.ZERO.compareTo(line.getDiscountAmt()) != 0)
{
fl = fact.createLine (line, getAccount(Doc.ACCTTYPE_DiscountExp, as),
getC_Currency_ID(), line.getDiscountAmt(), null);
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
}
// Write off DR
if (Env.ZERO.compareTo(line.getWriteOffAmt()) != 0)
{
fl = fact.createLine (line, getAccount(Doc.ACCTTYPE_WriteOff, as),
getC_Currency_ID(), line.getWriteOffAmt(), null);
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
}
// AR Invoice Amount CR
if (as.isAccrual())
{
bpAcct = getAccount(Doc.ACCTTYPE_C_Receivable, as);
fl = fact.createLine (line, bpAcct,
getC_Currency_ID(), null, allocationSource); // payment currency
if (fl != null)
allocationAccounted = fl.getAcctBalance().negate();
if (fl != null && invoice != null)
fl.setAD_Org_ID(invoice.getAD_Org_ID());
}
else // Cash Based
{
allocationAccounted = createCashBasedAcct (as, fact,
invoice, allocationSource);
}
}
// Purchase Invoice
else
{
allocationSource = allocationSource.negate(); // allocation is negative
// AP Invoice Amount DR
if (as.isAccrual())
{
bpAcct = getAccount(Doc.ACCTTYPE_V_Liability, as);
fl = fact.createLine (line, bpAcct,
getC_Currency_ID(), allocationSource, null); // payment currency
if (fl != null)
allocationAccounted = fl.getAcctBalance();
if (fl != null && invoice != null)
fl.setAD_Org_ID(invoice.getAD_Org_ID());
}
else // Cash Based
{
allocationAccounted = createCashBasedAcct (as, fact,
invoice, allocationSource);
}
// Discount CR
if (Env.ZERO.compareTo(line.getDiscountAmt()) != 0)
{
fl = fact.createLine (line, getAccount(Doc.ACCTTYPE_DiscountRev, as),
getC_Currency_ID(), null, line.getDiscountAmt().negate());
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
}
// Write off CR
if (Env.ZERO.compareTo(line.getWriteOffAmt()) != 0)
{
fl = fact.createLine (line, getAccount(Doc.ACCTTYPE_WriteOff, as),
getC_Currency_ID(), null, line.getWriteOffAmt().negate());
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
}
// Payment/Cash CR
if (line.getC_Payment_ID() != 0)
{
fl = fact.createLine (line, getPaymentAcct(as, line.getC_Payment_ID()),
getC_Currency_ID(), null, line.getAmtSource().negate());
if (fl != null && payment != null)
fl.setAD_Org_ID(payment.getAD_Org_ID());
}
else if (line.getC_CashLine_ID() != 0)
{
fl = fact.createLine (line, getCashAcct(as, line.getC_CashLine_ID()),
getC_Currency_ID(), null, line.getAmtSource().negate());
MCashLine cashLine = new MCashLine (getCtx(), line.getC_CashLine_ID(), getTrxName());
if (fl != null && cashLine.get_ID() != 0)
fl.setAD_Org_ID(cashLine.getAD_Org_ID());
}
}
// VAT Tax Correction
if (invoice != null && as.isTaxCorrection())
{
BigDecimal taxCorrectionAmt = Env.ZERO;
if (as.isTaxCorrectionDiscount())
taxCorrectionAmt = line.getDiscountAmt();
if (as.isTaxCorrectionWriteOff())
taxCorrectionAmt = taxCorrectionAmt.add(line.getWriteOffAmt());
//
if (taxCorrectionAmt.signum() != 0)
{
if (!createTaxCorrection(as, fact, line,
getAccount(invoice.isSOTrx() ? Doc.ACCTTYPE_DiscountExp : Doc.ACCTTYPE_DiscountRev, as),
getAccount(Doc.ACCTTYPE_WriteOff, as)))
{
p_Error = "Cannot create Tax correction";
return null;
}
}
}
// Realized Gain & Loss
if (invoice != null
&& (getC_Currency_ID() != as.getC_Currency_ID() // payment allocation in foreign currency
|| getC_Currency_ID() != line.getInvoiceC_Currency_ID())) // allocation <> invoice currency
{
p_Error = createRealizedGainLoss (as, fact, bpAcct, invoice,
allocationSource, allocationAccounted);
if (p_Error != null)
return null;
}
} // for all lines
// reset line info
setC_BPartner_ID(0);
//
m_facts.add(fact);
return m_facts;
} // createFact
/**
* Create Cash Based Acct
* @param as accounting schema
* @param fact fact
* @param invoice invoice
* @param allocationSource allocation amount (incl discount, writeoff)
* @return Accounted Amt
*/
private BigDecimal createCashBasedAcct (MAcctSchema as, Fact fact, MInvoice invoice,
BigDecimal allocationSource)
{
BigDecimal allocationAccounted = Env.ZERO;
// Multiplier
double percent = invoice.getGrandTotal().doubleValue() / allocationSource.doubleValue();
if (percent > 0.99 && percent < 1.01)
percent = 1.0;
log.config("Multiplier=" + percent + " - GrandTotal=" + invoice.getGrandTotal()
+ " - Allocation Source=" + allocationSource);
// Get Invoice Postings
Doc_Invoice docInvoice = (Doc_Invoice)Doc.get(new MAcctSchema[]{as},
MInvoice.Table_ID, invoice.getC_Invoice_ID(), getTrxName());
docInvoice.loadDocumentDetails();
allocationAccounted = docInvoice.createFactCash(as, fact, new BigDecimal(percent));
log.config("Allocation Accounted=" + allocationAccounted);
// Cash Based Commitment Release
if (as.isCreateCommitment() && !invoice.isSOTrx())
{
MInvoiceLine[] lines = invoice.getLines();
for (int i = 0; i < lines.length; i++)
{
Fact factC = Doc_Order.getCommitmentRelease(as, this,
lines[i].getQtyInvoiced(), lines[i].getC_InvoiceLine_ID(), new BigDecimal(percent));
if (factC == null)
return null;
m_facts.add(factC);
}
} // Commitment
return allocationAccounted;
} // createCashBasedAcct
/**
* Get Payment (Unallocated Payment or Payment Selection) Acct of Bank Account
* @param as accounting schema
* @param C_Payment_ID payment
* @return acct
*/
private MAccount getPaymentAcct (MAcctSchema as, int C_Payment_ID)
{
setC_BankAccount_ID(0);
// Doc.ACCTTYPE_UnallocatedCash (AR) or C_Prepayment
// or Doc.ACCTTYPE_PaymentSelect (AP) or V_Prepayment
int accountType = Doc.ACCTTYPE_UnallocatedCash;
//
String sql = "SELECT p.C_BankAccount_ID, d.DocBaseType, p.IsReceipt, p.IsPrepayment "
+ "FROM C_Payment p INNER JOIN C_DocType d ON (p.C_DocType_ID=d.C_DocType_ID) "
+ "WHERE C_Payment_ID=?";
PreparedStatement pstmt = null;
try
{
pstmt = DB.prepareStatement (sql, getTrxName());
pstmt.setInt (1, C_Payment_ID);
ResultSet rs = pstmt.executeQuery ();
if (rs.next ())
{
setC_BankAccount_ID(rs.getInt(1));
if (DOCTYPE_APPayment.equals(rs.getString(2)))
accountType = Doc.ACCTTYPE_PaymentSelect;
// Prepayment
if ("Y".equals(rs.getString(4))) // Prepayment
{
if ("Y".equals(rs.getString(3))) // Receipt
accountType = Doc.ACCTTYPE_C_Prepayment;
else
accountType = Doc.ACCTTYPE_V_Prepayment;
}
}
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;
}
//
if (getC_BankAccount_ID() <= 0)
{
log.log(Level.SEVERE, "NONE for C_Payment_ID=" + C_Payment_ID);
return null;
}
return getAccount (accountType, as);
} // getPaymentAcct
/**
* Get Cash (Transfer) Acct of CashBook
* @param as accounting schema
* @param C_CashLine_ID
* @return acct
*/
private MAccount getCashAcct (MAcctSchema as, int C_CashLine_ID)
{
String sql = "SELECT c.C_CashBook_ID "
+ "FROM C_Cash c, C_CashLine cl "
+ "WHERE c.C_Cash_ID=cl.C_Cash_ID AND cl.C_CashLine_ID=?";
setC_CashBook_ID(DB.getSQLValue(null, sql, C_CashLine_ID));
if (getC_CashBook_ID() <= 0)
{
log.log(Level.SEVERE, "NONE for C_CashLine_ID=" + C_CashLine_ID);
return null;
}
return getAccount(Doc.ACCTTYPE_CashTransfer, as);
} // getCashAcct
/**************************************************************************
* Create Realized Gain & Loss.
* Compares the Accounted Amount of the Invoice to the
* Accounted Amount of the Allocation
* @param as accounting schema
* @param fact fact
* @param acct account
* @param invoice invoice
* @param allocationSource source amt
* @param allocationAccounted acct amt
* @return Error Message or null if OK
*/
private String createRealizedGainLoss (MAcctSchema as, Fact fact, MAccount acct,
MInvoice invoice, BigDecimal allocationSource, BigDecimal allocationAccounted)
{
BigDecimal invoiceSource = null;
BigDecimal invoiceAccounted = null;
//
String sql = "SELECT "
+ (invoice.isSOTrx()
? "SUM(AmtSourceDr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceCr), SUM(AmtAcctCr)") // po
+ " FROM Fact_Acct "
+ "WHERE AD_Table_ID=318 AND Record_ID=?" // Invoice
+ " AND C_AcctSchema_ID=?"
+ " AND PostingType='A'";
//AND C_Currency_ID=102
PreparedStatement pstmt = null;
try
{
pstmt = DB.prepareStatement(sql, getTrxName());
pstmt.setInt(1, invoice.getC_Invoice_ID());
pstmt.setInt(2, as.getC_AcctSchema_ID());
ResultSet rs = pstmt.executeQuery();
if (rs.next())
{
invoiceSource = rs.getBigDecimal(1);
invoiceAccounted = rs.getBigDecimal(2);
}
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;
}
// Requires that Invoice is Posted
if (invoiceSource == null || invoiceAccounted == null)
return "Gain/Loss - Invoice not posted yet";
//
String description = "Invoice=(" + invoice.getC_Currency_ID() + ")" + invoiceSource + "/" + invoiceAccounted
+ " - Allocation=(" + getC_Currency_ID() + ")" + allocationSource + "/" + allocationAccounted;
log.fine(description);
// Allocation not Invoice Currency
if (getC_Currency_ID() != invoice.getC_Currency_ID())
{
BigDecimal allocationSourceNew = MConversionRate.convert(getCtx(),
allocationSource, getC_Currency_ID(),
invoice.getC_Currency_ID(), getDateAcct(),
invoice.getC_ConversionType_ID(), invoice.getAD_Client_ID(), invoice.getAD_Org_ID());
if (allocationSourceNew == null)
return "Gain/Loss - No Conversion from Allocation->Invoice";
String d2 = "Allocation=(" + getC_Currency_ID() + ")" + allocationSource
+ "->(" + invoice.getC_Currency_ID() + ")" + allocationSourceNew;
log.fine(d2);
description += " - " + d2;
allocationSource = allocationSourceNew;
}
BigDecimal acctDifference = null; // gain is negative
// Full Payment in currency
if (allocationSource.compareTo(invoiceSource) == 0)
{
acctDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative
String d2 = "(full) = " + acctDifference;
log.fine(d2);
description += " - " + d2;
}
else // partial or MC
{
// percent of total payment
double multiplier = allocationSource.doubleValue() / invoiceSource.doubleValue();
// Reduce Orig Invoice Accounted
invoiceAccounted = invoiceAccounted.multiply(new BigDecimal(multiplier));
// Difference based on percentage of Orig Invoice
acctDifference = invoiceAccounted.subtract(allocationAccounted); // gain is negative
// ignore Tolerance
if (acctDifference.abs().compareTo(TOLERANCE) < 0)
acctDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (acctDifference.scale() > precision)
acctDifference = acctDifference.setScale(precision, BigDecimal.ROUND_HALF_UP);
String d2 = "(partial) = " + acctDifference + " - Multiplier=" + multiplier;
log.fine(d2);
description += " - " + d2;
}
if (acctDifference.signum() == 0)
{
log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (invoice.isSOTrx())
{
FactLine fl = fact.createLine (null, loss, gain,
as.getC_Currency_ID(), acctDifference);
fl.setDescription(description);
fact.createLine (null, acct,
as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description);
}
else
{
fact.createLine (null, acct,
as.getC_Currency_ID(), acctDifference);
FactLine fl = fact.createLine (null, loss, gain,
as.getC_Currency_ID(), acctDifference.negate());
}
return null;
} // createRealizedGainLoss
/**************************************************************************
* Create Tax Correction.
* Requirement: Adjust the tax amount, if you did not receive the full
* amount of the invoice (payment discount, write-off).
* Applies to many countries with VAT.
* Example:
* Invoice: Net $100 + Tax1 $15 + Tax2 $5 = Total $120
* Payment: $115 (i.e. $5 underpayment)
* Tax Adjustment = Tax1 = 0.63 (15/120*5) Tax2 = 0.21 (5/120/5)
*
* @param as accounting schema
* @param fact fact
* @param line Allocation line
* @param DiscountAccount discount acct
* @param WriteOffAccoint write off acct
* @return true if created
*/
private boolean createTaxCorrection (MAcctSchema as, Fact fact,
DocLine_Allocation line,
MAccount DiscountAccount, MAccount WriteOffAccoint)
{
log.info (line.toString());
BigDecimal discount = Env.ZERO;
if (as.isTaxCorrectionDiscount())
discount = line.getDiscountAmt();
BigDecimal writeOff = Env.ZERO;
if (as.isTaxCorrectionWriteOff())
writeOff = line.getWriteOffAmt();
Doc_AllocationTax tax = new Doc_AllocationTax (
DiscountAccount, discount, WriteOffAccoint, writeOff);
// Get Source Amounts with account
String sql = "SELECT * "
+ "FROM Fact_Acct "
+ "WHERE AD_Table_ID=318 AND Record_ID=?" // Invoice
+ " AND C_AcctSchema_ID=?"
+ " AND Line_ID IS NULL"; // header lines like tax or total
PreparedStatement pstmt = null;
try
{
pstmt = DB.prepareStatement(sql, getTrxName());
pstmt.setInt(1, line.getC_Invoice_ID());
pstmt.setInt(2, as.getC_AcctSchema_ID());
ResultSet rs = pstmt.executeQuery();
while (rs.next())
tax.addInvoiceFact (new MFactAcct(getCtx(), rs, fact.get_TrxName()));
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;
}
// Invoice Not posted
if (tax.getLineCount() == 0)
{
log.warning ("Invoice not posted yet - " + line);
return false;
}
// size = 1 if no tax
if (tax.getLineCount() < 2)
return true;
return tax.createEntries (as, fact, line);
} // createTaxCorrection
} // Doc_Allocation
/**
* Allocation Document Tax Handing
*
* @author Jorg Janke
* @version $Id: Doc_Allocation.java,v 1.6 2006/07/30 00:53:33 jjanke Exp $
*/
class Doc_AllocationTax
{
/**
* Allocation Tax Adjustment
* @param DiscountAccount discount acct
* @param DiscountAmt discount amt
* @param WriteOffAccount write off acct
* @param WriteOffAmt write off amt
*/
public Doc_AllocationTax (MAccount DiscountAccount, BigDecimal DiscountAmt,
MAccount WriteOffAccount, BigDecimal WriteOffAmt)
{
m_DiscountAccount = DiscountAccount;
m_DiscountAmt = DiscountAmt;
m_WriteOffAccount = WriteOffAccount;
m_WriteOffAmt = WriteOffAmt;
} // Doc_AllocationTax
private CLogger log = CLogger.getCLogger(getClass());
private MAccount m_DiscountAccount;
private BigDecimal m_DiscountAmt;
private MAccount m_WriteOffAccount;
private BigDecimal m_WriteOffAmt;
private ArrayList<MFactAcct> m_facts = new ArrayList<MFactAcct>();
private int m_totalIndex = 0;
/**
* Add Invoice Fact Line
* @param fact fact line
*/
public void addInvoiceFact (MFactAcct fact)
{
m_facts.add(fact);
} // addInvoiceLine
/**
* Get Line Count
* @return number of lines
*/
public int getLineCount()
{
return m_facts.size();
} // getLineCount
/**
* Create Accounting Entries
* @param as account schema
* @param fact fact to add lines
* @param line line
* @return true if created
*/
public boolean createEntries (MAcctSchema as, Fact fact, DocLine line)
{
// get total index (the Receivables/Liabilities line)
BigDecimal total = Env.ZERO;
for (int i = 0; i < m_facts.size(); i++)
{
MFactAcct factAcct = (MFactAcct)m_facts.get(i);
if (factAcct.getAmtSourceDr().compareTo(total) > 0)
{
total = factAcct.getAmtSourceDr();
m_totalIndex = i;
}
if (factAcct.getAmtSourceCr().compareTo(total) > 0)
{
total = factAcct.getAmtSourceCr();
m_totalIndex = i;
}
}
MFactAcct factAcct = (MFactAcct)m_facts.get(m_totalIndex);
log.info ("Total Invoice = " + total + " - " + factAcct);
int precision = as.getStdPrecision();
for (int i = 0; i < m_facts.size(); i++)
{
// No Tax Line
if (i == m_totalIndex)
continue;
factAcct = (MFactAcct)m_facts.get(i);
log.info (i + ": " + factAcct);
// Create Tax Account
MAccount taxAcct = factAcct.getMAccount();
if (taxAcct == null || taxAcct.get_ID() == 0)
{
log.severe ("Tax Account not found/created");
return false;
}
// Discount Amount
if (m_DiscountAmt.signum() != 0)
{
// Original Tax is DR - need to correct it CR
if (Env.ZERO.compareTo(factAcct.getAmtSourceDr()) != 0)
{
BigDecimal amount = calcAmount(factAcct.getAmtSourceDr(),
total, m_DiscountAmt, precision);
if (amount.signum() != 0)
{
fact.createLine (line, m_DiscountAccount,
as.getC_Currency_ID(), amount, null);
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), null, amount);
}
}
// Original Tax is CR - need to correct it DR
else
{
BigDecimal amount = calcAmount(factAcct.getAmtSourceCr(),
total, m_DiscountAmt, precision);
if (amount.signum() != 0)
{
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), amount, null);
fact.createLine (line, m_DiscountAccount,
as.getC_Currency_ID(), null, amount);
}
}
} // Discount
// WriteOff Amount
if (m_WriteOffAmt.signum() != 0)
{
// Original Tax is DR - need to correct it CR
if (Env.ZERO.compareTo(factAcct.getAmtSourceDr()) != 0)
{
BigDecimal amount = calcAmount(factAcct.getAmtSourceDr(),
total, m_WriteOffAmt, precision);
if (amount.signum() != 0)
{
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), amount, null);
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), null, amount);
}
}
// Original Tax is CR - need to correct it DR
else
{
BigDecimal amount = calcAmount(factAcct.getAmtSourceCr(),
total, m_WriteOffAmt, precision);
if (amount.signum() != 0)
{
fact.createLine (line, taxAcct,
as.getC_Currency_ID(), amount, null);
fact.createLine (line, m_WriteOffAccount,
as.getC_Currency_ID(), null, amount);
}
}
} // WriteOff
} // for all lines
return true;
} // createEntries
/**
* Calc Amount tax / (total-tax) * amt
* @param tax tax
* @param total total
* @param amt reduction amt
* @param precision precision
* @return tax / total * amt
*/
private BigDecimal calcAmount (BigDecimal tax, BigDecimal total, BigDecimal amt, int precision)
{
log.fine("Amt=" + amt + " - Total=" + total + ", Tax=" + tax);
if (tax.signum() == 0
|| total.signum() == 0
|| amt.signum() == 0)
return Env.ZERO;
//
BigDecimal devisor = total.subtract(tax);
BigDecimal multiplier = tax.divide(devisor, 10, BigDecimal.ROUND_HALF_UP);
BigDecimal retValue = multiplier.multiply(amt);
if (retValue.scale() > precision)
retValue = retValue.setScale(precision, BigDecimal.ROUND_HALF_UP);
log.fine(retValue + " (Mult=" + multiplier + "(Prec=" + precision + ")");
return retValue;
} // calcAmount
} // Doc_AllocationTax

View File

@ -0,0 +1,223 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import org.compiere.util.*;
/**
* Post Invoice Documents.
* <pre>
* Table: C_BankStatement (392)
* Document Types: CMB
* </pre>
* @author Jorg Janke
* @version $Id: Doc_Bank.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Bank extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_Bank (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MBankStatement.class, rs, DOCTYPE_BankStatement, trxName);
} // Doc_Bank
/** Bank Account */
private int m_C_BankAccount_ID = 0;
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
MBankStatement bs = (MBankStatement)getPO();
setDateDoc(bs.getStatementDate());
setDateAcct(bs.getStatementDate()); // Overwritten on Line Level
m_C_BankAccount_ID = bs.getC_BankAccount_ID();
// Amounts
setAmount(AMTTYPE_Gross, bs.getStatementDifference());
// Set Bank Account Info (Currency)
MBankAccount ba = MBankAccount.get (getCtx(), m_C_BankAccount_ID);
setC_Currency_ID (ba.getC_Currency_ID());
// Contained Objects
p_lines = loadLines(bs);
log.fine("Lines=" + p_lines.length);
return null;
} // loadDocumentDetails
/**
* Load Invoice Line.
* @param bs bank statement
* 4 amounts
* AMTTYPE_Payment
* AMTTYPE_Statement2
* AMTTYPE_Charge
* AMTTYPE_Interest
* @return DocLine Array
*/
private DocLine[] loadLines(MBankStatement bs)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
MBankStatementLine[] lines = bs.getLines(false);
for (int i = 0; i < lines.length; i++)
{
MBankStatementLine line = lines[i];
DocLine_Bank docLine = new DocLine_Bank(line, this);
// Set Date Acct
if (i == 0)
setDateAcct(line.getDateAcct());
MPeriod period = MPeriod.get(getCtx(), line.getDateAcct());
if (period != null && period.isOpen(DOCTYPE_BankStatement))
docLine.setC_Period_ID(period.getC_Period_ID());
//
list.add(docLine);
}
// Return Array
DocLine[] dls = new DocLine[list.size()];
list.toArray(dls);
return dls;
} // loadLines
/**************************************************************************
* Get Source Currency Balance - subtracts line amounts from total - no rounding
* @return positive amount, if total invoice is bigger than lines
*/
public BigDecimal getBalance()
{
BigDecimal retValue = Env.ZERO;
StringBuffer sb = new StringBuffer (" [");
// Total
retValue = retValue.add(getAmount(Doc.AMTTYPE_Gross));
sb.append(getAmount(Doc.AMTTYPE_Gross));
// - Lines
for (int i = 0; i < p_lines.length; i++)
{
BigDecimal lineBalance = ((DocLine_Bank)p_lines[i]).getStmtAmt();
retValue = retValue.subtract(lineBalance);
sb.append("-").append(lineBalance);
}
sb.append("]");
//
log.fine(toString() + " Balance=" + retValue + sb.toString());
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* CMB.
* <pre>
* BankAsset DR CR (Statement)
* BankInTransit DR CR (Payment)
* Charge DR (Charge)
* Interest DR CR (Interest)
* </pre>
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
// Header -- there may be different currency amounts
FactLine fl = null;
int AD_Org_ID = getBank_Org_ID(); // Bank Account Org
// Lines
for (int i = 0; i < p_lines.length; i++)
{
DocLine_Bank line = (DocLine_Bank)p_lines[i];
int C_BPartner_ID = line.getC_BPartner_ID();
// BankAsset DR CR (Statement)
fl = fact.createLine(line,
getAccount(Doc.ACCTTYPE_BankAsset, as),
line.getC_Currency_ID(), line.getStmtAmt());
if (fl != null && AD_Org_ID != 0)
fl.setAD_Org_ID(AD_Org_ID);
if (fl != null && C_BPartner_ID != 0)
fl.setC_BPartner_ID(C_BPartner_ID);
// BankInTransit DR CR (Payment)
fl = fact.createLine(line,
getAccount(Doc.ACCTTYPE_BankInTransit, as),
line.getC_Currency_ID(), line.getTrxAmt().negate());
if (fl != null)
{
if (C_BPartner_ID != 0)
fl.setC_BPartner_ID(C_BPartner_ID);
if (AD_Org_ID != 0)
fl.setAD_Org_ID(AD_Org_ID);
else
fl.setAD_Org_ID(line.getAD_Org_ID(true)); // from payment
}
// Charge DR (Charge)
fl = fact.createLine(line,
line.getChargeAccount(as, line.getChargeAmt().negate()),
line.getC_Currency_ID(), line.getChargeAmt().negate(), null);
if (fl != null && C_BPartner_ID != 0)
fl.setC_BPartner_ID(C_BPartner_ID);
// Interest DR CR (Interest)
if (line.getInterestAmt().signum() < 0)
fl = fact.createLine(line,
getAccount(Doc.ACCTTYPE_InterestExp, as), getAccount(Doc.ACCTTYPE_InterestExp, as),
line.getC_Currency_ID(), line.getInterestAmt().negate());
else
fl = fact.createLine(line,
getAccount(Doc.ACCTTYPE_InterestRev, as), getAccount(Doc.ACCTTYPE_InterestRev, as),
line.getC_Currency_ID(), line.getInterestAmt().negate());
if (fl != null && C_BPartner_ID != 0)
fl.setC_BPartner_ID(C_BPartner_ID);
//
// fact.createTaxCorrection();
}
//
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
} // createFact
/**
* Get AD_Org_ID from Bank Account
* @return AD_Org_ID or 0
*/
private int getBank_Org_ID ()
{
if (m_C_BankAccount_ID == 0)
return 0;
//
MBankAccount ba = MBankAccount.get(getCtx(), m_C_BankAccount_ID);
return ba.getAD_Org_ID();
} // getBank_Org_ID
} // Doc_Bank

View File

@ -0,0 +1,254 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import java.util.logging.*;
import org.compiere.util.*;
/**
* Post Invoice Documents.
* <pre>
* Table: C_Cash (407)
* Document Types: CMC
* </pre>
* @author Jorg Janke
* @version $Id: Doc_Cash.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Cash extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_Cash (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super(ass, MCash.class, rs, DOCTYPE_CashJournal, trxName);
} // Doc_Cash
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
MCash cash = (MCash)getPO();
setDateDoc(cash.getStatementDate());
// Amounts
setAmount(Doc.AMTTYPE_Gross, cash.getStatementDifference());
// Set CashBook Org & Currency
MCashBook cb = MCashBook.get(getCtx(), cash.getC_CashBook_ID());
setC_CashBook_ID(cb.getC_CashBook_ID());
setC_Currency_ID(cb.getC_Currency_ID());
// Contained Objects
p_lines = loadLines(cash, cb);
log.fine("Lines=" + p_lines.length);
return null;
} // loadDocumentDetails
/**
* Load Cash Line
* @param cash journal
* @param cb cash book
* @return DocLine Array
*/
private DocLine[] loadLines(MCash cash, MCashBook cb)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
MCashLine[] lines = cash.getLines(false);
for (int i = 0; i < lines.length; i++)
{
MCashLine line = lines[i];
DocLine_Cash docLine = new DocLine_Cash (line, this);
//
list.add(docLine);
}
// Return Array
DocLine[] dls = new DocLine[list.size()];
list.toArray(dls);
return dls;
} // loadLines
/**************************************************************************
* Get Source Currency Balance - subtracts line amounts from total - no rounding
* @return positive amount, if total invoice is bigger than lines
*/
public BigDecimal getBalance()
{
BigDecimal retValue = Env.ZERO;
StringBuffer sb = new StringBuffer (" [");
// Total
retValue = retValue.add(getAmount(Doc.AMTTYPE_Gross));
sb.append(getAmount(Doc.AMTTYPE_Gross));
// - Lines
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("]");
//
log.fine(toString() + " Balance=" + retValue + sb.toString());
// return retValue;
return Env.ZERO; // Lines are balanced
} // getBalance
/**
* Create Facts (the accounting logic) for
* CMC.
* <pre>
* Expense
* CashExpense DR
* CashAsset CR
* Receipt
* CashAsset DR
* CashReceipt CR
* Charge
* Charge DR
* CashAsset CR
* Difference
* CashDifference DR
* CashAsset CR
* Invoice
* CashAsset DR
* CashTransfer CR
* Transfer
* BankInTransit DR
* CashAsset CR
* </pre>
* @param as account schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
// Need to have CashBook
if (getC_CashBook_ID() == 0)
{
p_Error = "C_CashBook_ID not set";
log.log(Level.SEVERE, p_Error);
return null;
}
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
// Header posting amt as Invoices and Transfer could be differenet currency
// CashAsset Total
BigDecimal assetAmt = Env.ZERO;
// Lines
for (int i = 0; i < p_lines.length; i++)
{
DocLine_Cash line = (DocLine_Cash)p_lines[i];
String CashType = line.getCashType();
if (CashType.equals(DocLine_Cash.CASHTYPE_EXPENSE))
{ // amount is negative
// CashExpense DR
// CashAsset CR
fact.createLine(line, getAccount(Doc.ACCTTYPE_CashExpense, as),
getC_Currency_ID(), line.getAmount().negate(), null);
// fact.createLine(line, getAccount(Doc.ACCTTYPE_CashAsset, as),
// p_vo.C_Currency_ID, null, line.getAmount().negate());
assetAmt = assetAmt.subtract(line.getAmount().negate());
}
else if (CashType.equals(DocLine_Cash.CASHTYPE_RECEIPT))
{ // amount is positive
// CashAsset DR
// CashReceipt CR
// fact.createLine(line, getAccount(Doc.ACCTTYPE_CashAsset, as),
// p_vo.C_Currency_ID, line.getAmount(), null);
assetAmt = assetAmt.add(line.getAmount());
fact.createLine(line, getAccount(Doc.ACCTTYPE_CashReceipt, as),
getC_Currency_ID(), null, line.getAmount());
}
else if (CashType.equals(DocLine_Cash.CASHTYPE_CHARGE))
{ // amount is negative
// Charge DR
// CashAsset CR
fact.createLine(line, line.getChargeAccount(as, getAmount()),
getC_Currency_ID(), line.getAmount().negate(), null);
// fact.createLine(line, getAccount(Doc.ACCTTYPE_CashAsset, as),
// p_vo.C_Currency_ID, null, line.getAmount().negate());
assetAmt = assetAmt.subtract(line.getAmount().negate());
}
else if (CashType.equals(DocLine_Cash.CASHTYPE_DIFFERENCE))
{ // amount is pos/neg
// CashDifference DR
// CashAsset CR
fact.createLine(line, getAccount(Doc.ACCTTYPE_CashDifference, as),
getC_Currency_ID(), line.getAmount().negate());
// fact.createLine(line, getAccount(Doc.ACCTTYPE_CashAsset, as),
// p_vo.C_Currency_ID, line.getAmount());
assetAmt = assetAmt.add(line.getAmount());
}
else if (CashType.equals(DocLine_Cash.CASHTYPE_INVOICE))
{ // amount is pos/neg
// CashAsset DR dr -- Invoice is in Invoice Currency !
// CashTransfer cr CR
if (line.getC_Currency_ID() == getC_Currency_ID())
assetAmt = assetAmt.add (line.getAmount());
else
fact.createLine(line,
getAccount(Doc.ACCTTYPE_CashAsset, as),
line.getC_Currency_ID(), line.getAmount());
fact.createLine(line,
getAccount(Doc.ACCTTYPE_CashTransfer, as),
line.getC_Currency_ID(), line.getAmount().negate());
}
else if (CashType.equals(DocLine_Cash.CASHTYPE_TRANSFER))
{ // amount is pos/neg
// BankInTransit DR dr -- Transfer is in Bank Account Currency
// CashAsset dr CR
int temp = getC_BankAccount_ID();
setC_BankAccount_ID (line.getC_BankAccount_ID());
fact.createLine(line,
getAccount(Doc.ACCTTYPE_BankInTransit, as),
line.getC_Currency_ID(), line.getAmount().negate());
setC_BankAccount_ID(temp);
if (line.getC_Currency_ID() == getC_Currency_ID())
assetAmt = assetAmt.add (line.getAmount());
else
fact.createLine(line,
getAccount(Doc.ACCTTYPE_CashAsset, as),
line.getC_Currency_ID(), line.getAmount());
}
} // lines
// Cash Asset
fact.createLine(null, getAccount(Doc.ACCTTYPE_CashAsset, as),
getC_Currency_ID(), assetAmt);
//
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
} // createFact
} // Doc_Cash

View File

@ -0,0 +1,168 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import java.util.logging.*;
import org.compiere.util.*;
/**
* Post Invoice Documents.
* <pre>
* Table: GL_Journal (224)
* Document Types: GLJ
* </pre>
* @author Jorg Janke
* @version $Id: Doc_GLJournal.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_GLJournal extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_GLJournal (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super(ass, MJournal.class, rs, null, trxName);
} // Foc_GL_Journal
/** Posting Type */
private String m_PostingType = null;
private int m_C_AcctSchema_ID = 0;
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
MJournal journal = (MJournal)getPO();
m_PostingType = journal.getPostingType();
m_C_AcctSchema_ID = journal.getC_AcctSchema_ID();
// Contained Objects
p_lines = loadLines(journal);
log.fine("Lines=" + p_lines.length);
return null;
} // loadDocumentDetails
/**
* Load Invoice Line
* @param journal journal
* @return DocLine Array
*/
private DocLine[] loadLines(MJournal journal)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
MJournalLine[] lines = journal.getLines(false);
for (int i = 0; i < lines.length; i++)
{
MJournalLine line = lines[i];
DocLine docLine = new DocLine (line, this);
// -- Source Amounts
docLine.setAmount (line.getAmtSourceDr(), line.getAmtSourceCr());
// -- Converted Amounts
docLine.setConvertedAmt (m_C_AcctSchema_ID, line.getAmtAcctDr(), line.getAmtAcctCr());
// -- Account
MAccount account = line.getAccount();
docLine.setAccount (account);
// -- Organization of Line was set to Org of Account
list.add(docLine);
}
// Return Array
int size = list.size();
DocLine[] dls = new DocLine[size];
list.toArray(dls);
return dls;
} // loadLines
/**************************************************************************
* 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 = Env.ZERO;
StringBuffer sb = new StringBuffer (" [");
// Lines
for (int i = 0; i < p_lines.length; i++)
{
retValue = retValue.add(p_lines[i].getAmtSource());
sb.append("+").append(p_lines[i].getAmtSource());
}
sb.append("]");
//
log.fine(toString() + " Balance=" + retValue + sb.toString());
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* GLJ.
* (only for the accounting scheme, it was created)
* <pre>
* account DR CR
* </pre>
* @param as acct schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
ArrayList<Fact> facts = new ArrayList<Fact>();
// Other Acct Schema
if (as.getC_AcctSchema_ID() != m_C_AcctSchema_ID)
return facts;
// create Fact Header
Fact fact = new Fact (this, as, m_PostingType);
// GLJ
if (getDocumentType().equals(DOCTYPE_GLJournal))
{
// account DR CR
for (int i = 0; i < p_lines.length; i++)
{
if (p_lines[i].getC_AcctSchema_ID () == as.getC_AcctSchema_ID ())
{
FactLine line = fact.createLine (p_lines[i],
p_lines[i].getAccount (),
getC_Currency_ID(),
p_lines[i].getAmtSourceDr (),
p_lines[i].getAmtSourceCr ());
}
} // for all lines
}
else
{
p_Error = "DocumentType unknown: " + getDocumentType();
log.log(Level.SEVERE, p_Error);
fact = null;
}
//
facts.add(fact);
return facts;
} // createFact
} // Doc_GLJournal

View File

@ -0,0 +1,305 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import java.util.logging.*;
import org.compiere.util.*;
/**
* Post Shipment/Receipt Documents.
* <pre>
* Table: M_InOut (319)
* Document Types: MMS, MMR
* </pre>
* @author Jorg Janke
* @version $Id: Doc_InOut.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_InOut extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
public Doc_InOut (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MInOut.class, rs, null, trxName);
} // DocInOut
/**
* Load Document Details
* @return error message or null
*/
protected String loadDocumentDetails()
{
setC_Currency_ID(NO_CURRENCY);
MInOut inout = (MInOut)getPO();
setDateDoc (inout.getMovementDate());
// Contained Objects
p_lines = loadLines(inout);
log.fine("Lines=" + p_lines.length);
return null;
} // loadDocumentDetails
/**
* Load InOut Line
* @param inout shipment/receipt
* @return DocLine Array
*/
private DocLine[] loadLines(MInOut inout)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
MInOutLine[] lines = inout.getLines(false);
for (int i = 0; i < lines.length; i++)
{
MInOutLine line = lines[i];
if (line.isDescription()
|| line.getM_Product_ID() == 0
|| line.getMovementQty().signum() == 0)
{
log.finer("Ignored: " + line);
continue;
}
DocLine docLine = new DocLine (line, this);
BigDecimal Qty = line.getMovementQty();
docLine.setQty (Qty, getDocumentType().equals(DOCTYPE_MatShipment)); // sets Trx and Storage Qty
//
log.fine(docLine.toString());
list.add (docLine);
}
// Return Array
DocLine[] dls = new DocLine[list.size()];
list.toArray(dls);
return dls;
} // loadLines
/**
* Get Balance
* @return Zero (always balanced)
*/
public BigDecimal getBalance()
{
BigDecimal retValue = Env.ZERO;
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* MMS, MMR.
* <pre>
* Shipment
* CoGS (RevOrg) DR
* Inventory CR
* Shipment of Project Issue
* CoGS DR
* Project CR
* Receipt
* Inventory DR
* NotInvoicedReceipt CR
* </pre>
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
setC_Currency_ID (as.getC_Currency_ID());
// Line pointers
FactLine dr = null;
FactLine cr = null;
// *** Sales - Shipment
if (getDocumentType().equals(DOCTYPE_MatShipment))
{
for (int i = 0; i < p_lines.length; i++)
{
DocLine line = p_lines[i];
BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), true);
if (costs == null || costs.signum() == 0) // zero costs OK
{
MProduct product = line.getProduct();
if (product.isStocked())
{
p_Error = "No Costs for " + line.getProduct().getName();
log.log(Level.WARNING, p_Error);
return null;
}
else // ignore service
continue;
}
// CoGS DR
dr = fact.createLine(line,
line.getAccount(ProductCost.ACCTTYPE_P_Cogs, as),
as.getC_Currency_ID(), costs, null);
if (dr == null)
{
p_Error = "FactLine DR not created: " + line;
log.log(Level.WARNING, p_Error);
return null;
}
dr.setM_Locator_ID(line.getM_Locator_ID());
dr.setLocationFromLocator(line.getM_Locator_ID(), true); // from Loc
dr.setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc
dr.setAD_Org_ID(line.getOrder_Org_ID()); // Revenue X-Org
dr.setQty(line.getQty().negate());
// Inventory CR
cr = fact.createLine(line,
line.getAccount(ProductCost.ACCTTYPE_P_Asset, as),
as.getC_Currency_ID(), null, costs);
if (cr == null)
{
p_Error = "FactLine CR not created: " + line;
log.log(Level.WARNING, p_Error);
return null;
}
cr.setM_Locator_ID(line.getM_Locator_ID());
cr.setLocationFromLocator(line.getM_Locator_ID(), true); // from Loc
cr.setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc
//
if (line.getM_Product_ID() != 0)
{
MCostDetail.createShipment(as, line.getAD_Org_ID(),
line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
line.get_ID(), 0,
costs, line.getQty(),
line.getDescription(), true, getTrxName());
}
} // for all lines
updateProductInfo(as.getC_AcctSchema_ID()); // only for SO!
} // Shipment
// *** Purchasing - Receipt
else if (getDocumentType().equals(DOCTYPE_MatReceipt))
{
for (int i = 0; i < p_lines.length; i++)
{
DocLine line = p_lines[i];
BigDecimal costs = null;
MProduct product = line.getProduct();
//get costing method for product
String costingMethod = as.getCostingMethod();
MProductCategoryAcct pca = MProductCategoryAcct.get(getCtx(),
product.getM_Product_Category_ID(), as.getC_AcctSchema_ID(), getTrxName());
if (pca.getCostingMethod() != null)
costingMethod = pca.getCostingMethod();
if (MAcctSchema.COSTINGMETHOD_AveragePO.equals(costingMethod) ||
MAcctSchema.COSTINGMETHOD_LastPOPrice.equals(costingMethod) )
{
int C_OrderLine_ID = line.getC_OrderLine_ID();
MOrderLine orderLine = new MOrderLine (getCtx(), C_OrderLine_ID, getTrxName());
costs = orderLine.getPriceCost();
if (costs == null || costs.signum() == 0)
costs = orderLine.getPriceActual();
costs = costs.multiply(line.getQty());
}
else
{
costs = line.getProductCosts(as, line.getAD_Org_ID(), false); // current costs
}
if (costs == null || costs.signum() == 0)
{
p_Error = "Resubmit - No Costs for " + product.getName();
log.log(Level.WARNING, p_Error);
return null;
}
// Inventory/Asset DR
MAccount assets = line.getAccount(ProductCost.ACCTTYPE_P_Asset, as);
if (product.isService())
assets = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as);
dr = fact.createLine(line, assets,
as.getC_Currency_ID(), costs, null);
if (dr == null)
{
p_Error = "DR not created: " + line;
log.log(Level.WARNING, p_Error);
return null;
}
dr.setM_Locator_ID(line.getM_Locator_ID());
dr.setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc
dr.setLocationFromLocator(line.getM_Locator_ID(), false); // to Loc
// NotInvoicedReceipt CR
cr = fact.createLine(line,
getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as),
as.getC_Currency_ID(), null, costs);
if (cr == null)
{
p_Error = "CR not created: " + line;
log.log(Level.WARNING, p_Error);
return null;
}
cr.setM_Locator_ID(line.getM_Locator_ID());
cr.setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc
cr.setLocationFromLocator(line.getM_Locator_ID(), false); // to Loc
cr.setQty(line.getQty().negate());
}
} // Receipt
else
{
p_Error = "DocumentType unknown: " + getDocumentType();
log.log(Level.SEVERE, p_Error);
return null;
}
//
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
} // createFact
/**
* Update Sales Order Costing Product Info (old).
* Purchase side handeled in Invoice Matching.
* <br>
* decrease average cumulatives
* @param C_AcctSchema_ID accounting schema
* @deprecated old costing
*/
private void updateProductInfo (int C_AcctSchema_ID)
{
log.fine("M_InOut_ID=" + get_ID());
// Old Model
StringBuffer sql = new StringBuffer(
//FYRACLE add pc. everywhere
"UPDATE M_Product_Costing pc "
+ "SET (CostAverageCumQty, CostAverageCumAmt)="
+ "(SELECT pc.CostAverageCumQty - SUM(il.MovementQty),"
+ " pc.CostAverageCumAmt - SUM(il.MovementQty*pc.CurrentCostPrice) "
+ "FROM M_InOutLine il "
+ "WHERE pc.M_Product_ID=il.M_Product_ID"
+ " AND il.M_InOut_ID=").append(get_ID()).append(") ")
.append("WHERE EXISTS (SELECT * "
+ "FROM M_InOutLine il "
+ "WHERE pc.M_Product_ID=il.M_Product_ID"
+ " AND il.M_InOut_ID=").append(get_ID()).append(")");
int no = DB.executeUpdate(sql.toString(), getTrxName());
log.fine("M_Product_Costing - Updated=" + no);
//
} // updateProductInfo
} // Doc_InOut

View File

@ -0,0 +1,179 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import org.compiere.util.*;
/**
* Post Inventory Documents.
* <pre>
* Table: M_Inventory (321)
* Document Types: MMI
* </pre>
* @author Jorg Janke
* @version $Id: Doc_Inventory.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Inventory extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
public Doc_Inventory (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MInventory.class, rs, DOCTYPE_MatInventory, trxName);
} // Doc_Inventory
/**
* Load Document Details
* @return error message or null
*/
protected String loadDocumentDetails()
{
setC_Currency_ID (NO_CURRENCY);
MInventory inventory = (MInventory)getPO();
setDateDoc (inventory.getMovementDate());
setDateAcct(inventory.getMovementDate());
// Contained Objects
p_lines = loadLines(inventory);
log.fine("Lines=" + p_lines.length);
return null;
} // loadDocumentDetails
/**
* Load Invoice Line
* @param inventory inventory
* @return DocLine Array
*/
private DocLine[] loadLines(MInventory inventory)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
MInventoryLine[] lines = inventory.getLines(false);
for (int i = 0; i < lines.length; i++)
{
MInventoryLine line = lines[i];
// nothing to post
if (line.getQtyBook().compareTo(line.getQtyCount()) == 0
&& line.getQtyInternalUse().signum() == 0)
continue;
//
DocLine docLine = new DocLine (line, this);
BigDecimal Qty = line.getQtyInternalUse();
if (Qty.signum() != 0)
Qty = Qty.negate(); // Internal Use entered positive
else
{
BigDecimal QtyBook = line.getQtyBook();
BigDecimal QtyCount = line.getQtyCount();
Qty = QtyCount.subtract(QtyBook);
}
docLine.setQty (Qty, false); // -5 => -5
//
log.fine(docLine.toString());
list.add (docLine);
}
// Return Array
DocLine[] dls = new DocLine[list.size()];
list.toArray(dls);
return dls;
} // loadLines
/**
* Get Balance
* @return Zero (always balanced)
*/
public BigDecimal getBalance()
{
BigDecimal retValue = Env.ZERO;
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* MMI.
* <pre>
* Inventory
* Inventory DR CR
* InventoryDiff DR CR (or Charge)
* </pre>
* @param as account schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
setC_Currency_ID(as.getC_Currency_ID());
// Line pointers
FactLine dr = null;
FactLine cr = null;
for (int i = 0; i < p_lines.length; i++)
{
DocLine line = p_lines[i];
BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), false);
if (costs == null || costs.signum() == 0)
{
p_Error = "No Costs for " + line.getProduct().getName();
return null;
}
// Inventory DR CR
dr = fact.createLine(line,
line.getAccount(ProductCost.ACCTTYPE_P_Asset, as),
as.getC_Currency_ID(), costs);
// may be zero difference - no line created.
if (dr == null)
continue;
dr.setM_Locator_ID(line.getM_Locator_ID());
// InventoryDiff DR CR
// or Charge
MAccount invDiff = line.getChargeAccount(as, costs.negate());
if (invDiff == null)
invDiff = getAccount(Doc.ACCTTYPE_InvDifferences, as);
cr = fact.createLine(line, invDiff,
as.getC_Currency_ID(), costs.negate());
if (cr == null)
continue;
cr.setM_Locator_ID(line.getM_Locator_ID());
cr.setQty(line.getQty().negate());
if (line.getC_Charge_ID() != 0) // explicit overwrite for charge
cr.setAD_Org_ID(line.getAD_Org_ID());
// Cost Detail
MCostDetail.createInventory(as, line.getAD_Org_ID(),
line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
line.get_ID(), 0,
costs, line.getQty(),
line.getDescription(), getTrxName());
}
//
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
} // createFact
} // Doc_Inventory

View File

@ -0,0 +1,967 @@
/******************************************************************************
* 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. *
* 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 Invoice Documents.
* <pre>
* Table: C_Invoice (318)
* Document Types: ARI, ARC, ARF, API, APC
* </pre>
* @author Jorg Janke
* @version $Id: Doc_Invoice.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Invoice extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_Invoice(MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MInvoice.class, rs, null, trxName);
} // Doc_Invoice
/** Contained Optional Tax Lines */
private DocTax[] m_taxes = null;
/** Currency Precision */
private int m_precision = -1;
/** All lines are Service */
private boolean m_allLinesService = true;
/** All lines are product item */
private boolean m_allLinesItem = true;
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
MInvoice invoice = (MInvoice)getPO();
setDateDoc(invoice.getDateInvoiced());
setIsTaxIncluded(invoice.isTaxIncluded());
// Amounts
setAmount(Doc.AMTTYPE_Gross, invoice.getGrandTotal());
setAmount(Doc.AMTTYPE_Net, invoice.getTotalLines());
setAmount(Doc.AMTTYPE_Charge, invoice.getChargeAmt());
// Contained Objects
m_taxes = loadTaxes();
p_lines = loadLines(invoice);
log.fine("Lines=" + p_lines.length + ", Taxes=" + m_taxes.length);
return null;
} // loadDocumentDetails
/**
* Load Invoice Taxes
* @return DocTax Array
*/
private DocTax[] loadTaxes()
{
ArrayList<DocTax> list = new ArrayList<DocTax>();
String sql = "SELECT it.C_Tax_ID, t.Name, t.Rate, it.TaxBaseAmt, it.TaxAmt, t.IsSalesTax "
+ "FROM C_Tax t, C_InvoiceTax it "
+ "WHERE t.C_Tax_ID=it.C_Tax_ID AND it.C_Invoice_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);
log.fine(taxLine.toString());
list.add(taxLine);
}
//
rs.close();
pstmt.close();
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
return null;
}
// Return Array
DocTax[] tl = new DocTax[list.size()];
list.toArray(tl);
return tl;
} // loadTaxes
/**
* Load Invoice Line
* @param invoice invoice
* @return DocLine Array
*/
private DocLine[] loadLines (MInvoice invoice)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
//
MInvoiceLine[] lines = invoice.getLines(false);
for (int i = 0; i < lines.length; i++)
{
MInvoiceLine line = lines[i];
if (line.isDescription())
continue;
DocLine docLine = new DocLine(line, this);
// Qty
BigDecimal Qty = line.getQtyInvoiced();
boolean cm = getDocumentType().equals(DOCTYPE_ARCredit)
|| getDocumentType().equals(DOCTYPE_APCredit);
docLine.setQty(cm ? Qty.negate() : Qty, invoice.isSOTrx());
//
BigDecimal LineNetAmt = line.getLineNetAmt();
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, getStdPercision());
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, getStdPercision());
PriceList = PriceList.subtract(PriceListTax);
}
} // correct included Tax
docLine.setAmount (LineNetAmt, PriceList, Qty); // qty for discount calc
if (docLine.isItem())
m_allLinesService = false;
else
m_allLinesItem = false;
//
log.fine(docLine.toString());
list.add(docLine);
}
// Convert to Array
DocLine[] dls = new DocLine[list.size()];
list.toArray(dls);
// Included Tax - make sure that no difference
if (isTaxIncluded())
{
for (int i = 0; i < m_taxes.length; i++)
{
if (m_taxes[i].isIncludedTaxDifference())
{
BigDecimal diff = m_taxes[i].getIncludedTaxDifference();
for (int j = 0; j < dls.length; j++)
{
if (dls[j].getC_Tax_ID() == m_taxes[i].getC_Tax_ID())
{
dls[j].setLineNetAmtDifference(diff);
break;
}
} // for all lines
} // tax difference
} // for all taxes
} // Included Tax difference
// Return Array
return dls;
} // loadLines
/**
* Get Currency Percision
* @return precision
*/
private int getStdPercision()
{
if (m_precision == -1)
m_precision = MCurrency.getStdPrecision(getCtx(), getC_Currency_ID());
return m_precision;
} // getPrecision
/**************************************************************************
* 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 = Env.ZERO;
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
for (int i = 0; i < m_taxes.length; i++)
{
retValue = retValue.subtract(m_taxes[i].getAmount());
sb.append("-").append(m_taxes[i].getAmount());
}
// - Lines
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("]");
//
log.fine(toString() + " Balance=" + retValue + sb.toString());
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* ARI, ARC, ARF, API, APC.
* <pre>
* ARI, ARF
* Receivables DR
* Charge CR
* TaxDue CR
* Revenue CR
*
* ARC
* Receivables CR
* Charge DR
* TaxDue DR
* Revenue RR
*
* API
* Payables CR
* Charge DR
* TaxCredit DR
* Expense DR
*
* APC
* Payables DR
* Charge CR
* TaxCredit CR
* Expense CR
* </pre>
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
//
ArrayList<Fact> facts = new ArrayList<Fact>();
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
// Cash based accounting
if (!as.isAccrual())
return facts;
// ** ARI, ARF
if (getDocumentType().equals(DOCTYPE_ARInvoice)
|| getDocumentType().equals(DOCTYPE_ARProForma))
{
BigDecimal grossAmt = getAmount(Doc.AMTTYPE_Gross);
BigDecimal serviceAmt = Env.ZERO;
// Header Charge CR
BigDecimal amt = getAmount(Doc.AMTTYPE_Charge);
if (amt != null && amt.signum() != 0)
fact.createLine(null, getAccount(Doc.ACCTTYPE_Charge, as),
getC_Currency_ID(), null, amt);
// TaxDue CR
for (int i = 0; i < m_taxes.length; i++)
{
amt = m_taxes[i].getAmount();
if (amt != null && amt.signum() != 0)
{
FactLine tl = fact.createLine(null, m_taxes[i].getAccount(DocTax.ACCTTYPE_TaxDue, as),
getC_Currency_ID(), null, amt);
if (tl != null)
tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID());
}
}
// Revenue CR
for (int i = 0; i < p_lines.length; i++)
{
amt = p_lines[i].getAmtSource();
BigDecimal dAmt = null;
if (as.isTradeDiscountPosted())
{
BigDecimal discount = p_lines[i].getDiscount();
if (discount != null && discount.signum() != 0)
{
amt = amt.add(discount);
dAmt = discount;
}
}
fact.createLine (p_lines[i],
p_lines[i].getAccount(ProductCost.ACCTTYPE_P_Revenue, as),
getC_Currency_ID(), dAmt, amt);
if (!p_lines[i].isItem())
{
grossAmt = grossAmt.subtract(amt);
serviceAmt = serviceAmt.add(amt);
}
}
// Set Locations
FactLine[] fLines = fact.getLines();
for (int i = 0; i < fLines.length; i++)
{
if (fLines[i] != null)
{
fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), true); // from Loc
fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc
}
}
// Receivables DR
int receivables_ID = getValidCombination_ID(Doc.ACCTTYPE_C_Receivable, as);
int receivablesServices_ID = getValidCombination_ID (Doc.ACCTTYPE_C_Receivable_Services, as);
if (m_allLinesItem || !as.isPostServices()
|| receivables_ID == receivablesServices_ID)
{
grossAmt = getAmount(Doc.AMTTYPE_Gross);
serviceAmt = Env.ZERO;
}
else if (m_allLinesService)
{
serviceAmt = getAmount(Doc.AMTTYPE_Gross);
grossAmt = Env.ZERO;
}
if (grossAmt.signum() != 0)
fact.createLine(null, MAccount.get(getCtx(), receivables_ID),
getC_Currency_ID(), grossAmt, null);
if (serviceAmt.signum() != 0)
fact.createLine(null, MAccount.get(getCtx(), receivablesServices_ID),
getC_Currency_ID(), serviceAmt, null);
}
// ARC
else if (getDocumentType().equals(DOCTYPE_ARCredit))
{
BigDecimal grossAmt = getAmount(Doc.AMTTYPE_Gross);
BigDecimal serviceAmt = Env.ZERO;
// Header Charge DR
BigDecimal amt = getAmount(Doc.AMTTYPE_Charge);
if (amt != null && amt.signum() != 0)
fact.createLine(null, getAccount(Doc.ACCTTYPE_Charge, as),
getC_Currency_ID(), amt, null);
// TaxDue DR
for (int i = 0; i < m_taxes.length; i++)
{
amt = m_taxes[i].getAmount();
if (amt != null && amt.signum() != 0)
{
FactLine tl = fact.createLine(null, m_taxes[i].getAccount(DocTax.ACCTTYPE_TaxDue, as),
getC_Currency_ID(), amt, null);
if (tl != null)
tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID());
}
}
// Revenue CR
for (int i = 0; i < p_lines.length; i++)
{
amt = p_lines[i].getAmtSource();
BigDecimal dAmt = null;
if (as.isTradeDiscountPosted())
{
BigDecimal discount = p_lines[i].getDiscount();
if (discount != null && discount.signum() != 0)
{
amt = amt.add(discount);
dAmt = discount;
}
}
fact.createLine (p_lines[i],
p_lines[i].getAccount (ProductCost.ACCTTYPE_P_Revenue, as),
getC_Currency_ID(), amt, dAmt);
if (!p_lines[i].isItem())
{
grossAmt = grossAmt.subtract(amt);
serviceAmt = serviceAmt.add(amt);
}
}
// Set Locations
FactLine[] fLines = fact.getLines();
for (int i = 0; i < fLines.length; i++)
{
if (fLines[i] != null)
{
fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), true); // from Loc
fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc
}
}
// Receivables CR
int receivables_ID = getValidCombination_ID (Doc.ACCTTYPE_C_Receivable, as);
int receivablesServices_ID = getValidCombination_ID (Doc.ACCTTYPE_C_Receivable_Services, as);
if (m_allLinesItem || !as.isPostServices()
|| receivables_ID == receivablesServices_ID)
{
grossAmt = getAmount(Doc.AMTTYPE_Gross);
serviceAmt = Env.ZERO;
}
else if (m_allLinesService)
{
serviceAmt = getAmount(Doc.AMTTYPE_Gross);
grossAmt = Env.ZERO;
}
if (grossAmt.signum() != 0)
fact.createLine(null, MAccount.get(getCtx(), receivables_ID),
getC_Currency_ID(), null, grossAmt);
if (serviceAmt.signum() != 0)
fact.createLine(null, MAccount.get(getCtx(), receivablesServices_ID),
getC_Currency_ID(), null, serviceAmt);
}
// ** API
else if (getDocumentType().equals(DOCTYPE_APInvoice))
{
BigDecimal grossAmt = getAmount(Doc.AMTTYPE_Gross);
BigDecimal serviceAmt = Env.ZERO;
// Charge DR
fact.createLine(null, getAccount(Doc.ACCTTYPE_Charge, as),
getC_Currency_ID(), getAmount(Doc.AMTTYPE_Charge), null);
// TaxCredit DR
for (int i = 0; i < m_taxes.length; i++)
{
FactLine tl = fact.createLine(null, m_taxes[i].getAccount(m_taxes[i].getAPTaxType(), as),
getC_Currency_ID(), m_taxes[i].getAmount(), null);
if (tl != null)
tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID());
}
// Expense DR
for (int i = 0; i < p_lines.length; i++)
{
DocLine line = p_lines[i];
boolean landedCost = landedCost(as, fact, line, true);
if (landedCost && as.isExplicitCostAdjustment())
{
fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
getC_Currency_ID(), line.getAmtSource(), null);
//
FactLine fl = fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
getC_Currency_ID(), null, line.getAmtSource());
String desc = line.getDescription();
if (desc == null)
desc = "100%";
else
desc += " 100%";
fl.setDescription(desc);
}
if (!landedCost)
{
MAccount expense = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as);
if (line.isItem())
expense = line.getAccount (ProductCost.ACCTTYPE_P_InventoryClearing, as);
BigDecimal amt = line.getAmtSource();
BigDecimal dAmt = null;
if (as.isTradeDiscountPosted() && !line.isItem())
{
BigDecimal discount = line.getDiscount();
if (discount != null && discount.signum() != 0)
{
amt = amt.add(discount);
dAmt = discount;
}
}
fact.createLine (line, expense,
getC_Currency_ID(), amt, dAmt);
if (!line.isItem())
{
grossAmt = grossAmt.subtract(amt);
serviceAmt = serviceAmt.add(amt);
}
//
if (line.getM_Product_ID() != 0
&& line.getProduct().isService()) // otherwise Inv Matching
MCostDetail.createInvoice(as, line.getAD_Org_ID(),
line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
line.get_ID(), 0, // No Cost Element
line.getAmtSource(), line.getQty(),
line.getDescription(), getTrxName());
}
}
// Set Locations
FactLine[] fLines = fact.getLines();
for (int i = 0; i < fLines.length; i++)
{
if (fLines[i] != null)
{
fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc
fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), false); // to Loc
}
}
// Liability CR
int payables_ID = getValidCombination_ID (Doc.ACCTTYPE_V_Liability, as);
int payablesServices_ID = getValidCombination_ID (Doc.ACCTTYPE_V_Liability_Services, as);
if (m_allLinesItem || !as.isPostServices()
|| payables_ID == payablesServices_ID)
{
grossAmt = getAmount(Doc.AMTTYPE_Gross);
serviceAmt = Env.ZERO;
}
else if (m_allLinesService)
{
serviceAmt = getAmount(Doc.AMTTYPE_Gross);
grossAmt = Env.ZERO;
}
if (grossAmt.signum() != 0)
fact.createLine(null, MAccount.get(getCtx(), payables_ID),
getC_Currency_ID(), null, grossAmt);
if (serviceAmt.signum() != 0)
fact.createLine(null, MAccount.get(getCtx(), payablesServices_ID),
getC_Currency_ID(), null, serviceAmt);
//
updateProductPO(as); // Only API
updateProductInfo (as.getC_AcctSchema_ID()); // only API
}
// APC
else if (getDocumentType().equals(DOCTYPE_APCredit))
{
BigDecimal grossAmt = getAmount(Doc.AMTTYPE_Gross);
BigDecimal serviceAmt = Env.ZERO;
// Charge CR
fact.createLine (null, getAccount(Doc.ACCTTYPE_Charge, as),
getC_Currency_ID(), null, getAmount(Doc.AMTTYPE_Charge));
// TaxCredit CR
for (int i = 0; i < m_taxes.length; i++)
{
FactLine tl = fact.createLine (null, m_taxes[i].getAccount(m_taxes[i].getAPTaxType(), as),
getC_Currency_ID(), null, m_taxes[i].getAmount());
if (tl != null)
tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID());
}
// Expense CR
for (int i = 0; i < p_lines.length; i++)
{
DocLine line = p_lines[i];
boolean landedCost = landedCost(as, fact, line, false);
if (landedCost && as.isExplicitCostAdjustment())
{
fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
getC_Currency_ID(), null, line.getAmtSource());
//
FactLine fl = fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
getC_Currency_ID(), line.getAmtSource(), null);
String desc = line.getDescription();
if (desc == null)
desc = "100%";
else
desc += " 100%";
fl.setDescription(desc);
}
if (!landedCost)
{
MAccount expense = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as);
if (line.isItem())
expense = line.getAccount (ProductCost.ACCTTYPE_P_InventoryClearing, as);
BigDecimal amt = line.getAmtSource();
BigDecimal dAmt = null;
if (as.isTradeDiscountPosted() && !line.isItem())
{
BigDecimal discount = line.getDiscount();
if (discount != null && discount.signum() != 0)
{
amt = amt.add(discount);
dAmt = discount;
}
}
fact.createLine (line, expense,
getC_Currency_ID(), dAmt, amt);
if (!line.isItem())
{
grossAmt = grossAmt.subtract(amt);
serviceAmt = serviceAmt.add(amt);
}
//
if (line.getM_Product_ID() != 0
&& line.getProduct().isService()) // otherwise Inv Matching
MCostDetail.createInvoice(as, line.getAD_Org_ID(),
line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
line.get_ID(), 0, // No Cost Element
line.getAmtSource().negate(), line.getQty(),
line.getDescription(), getTrxName());
}
}
// Set Locations
FactLine[] fLines = fact.getLines();
for (int i = 0; i < fLines.length; i++)
{
if (fLines[i] != null)
{
fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc
fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), false); // to Loc
}
}
// Liability DR
int payables_ID = getValidCombination_ID (Doc.ACCTTYPE_V_Liability, as);
int payablesServices_ID = getValidCombination_ID (Doc.ACCTTYPE_V_Liability_Services, as);
if (m_allLinesItem || !as.isPostServices()
|| payables_ID == payablesServices_ID)
{
grossAmt = getAmount(Doc.AMTTYPE_Gross);
serviceAmt = Env.ZERO;
}
else if (m_allLinesService)
{
serviceAmt = getAmount(Doc.AMTTYPE_Gross);
grossAmt = Env.ZERO;
}
if (grossAmt.signum() != 0)
fact.createLine(null, MAccount.get(getCtx(), payables_ID),
getC_Currency_ID(), grossAmt, null);
if (serviceAmt.signum() != 0)
fact.createLine(null, MAccount.get(getCtx(), payablesServices_ID),
getC_Currency_ID(), serviceAmt, null);
}
else
{
p_Error = "DocumentType unknown: " + getDocumentType();
log.log(Level.SEVERE, p_Error);
fact = null;
}
//
facts.add(fact);
return facts;
} // createFact
/**
* Create Fact Cash Based (i.e. only revenue/expense)
* @param as accounting schema
* @param fact fact to add lines to
* @param multiplier source amount multiplier
* @return accounted amount
*/
public BigDecimal createFactCash (MAcctSchema as, Fact fact, BigDecimal multiplier)
{
boolean creditMemo = getDocumentType().equals(DOCTYPE_ARCredit)
|| getDocumentType().equals(DOCTYPE_APCredit);
boolean payables = getDocumentType().equals(DOCTYPE_APInvoice)
|| getDocumentType().equals(DOCTYPE_APCredit);
BigDecimal acctAmt = Env.ZERO;
FactLine fl = null;
// Revenue/Cost
for (int i = 0; i < p_lines.length; i++)
{
DocLine line = p_lines[i];
boolean landedCost = false;
if (payables)
landedCost = landedCost(as, fact, line, false);
if (landedCost && as.isExplicitCostAdjustment())
{
fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
getC_Currency_ID(), null, line.getAmtSource());
//
fl = fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
getC_Currency_ID(), line.getAmtSource(), null);
String desc = line.getDescription();
if (desc == null)
desc = "100%";
else
desc += " 100%";
fl.setDescription(desc);
}
if (!landedCost)
{
MAccount acct = line.getAccount(
payables ? ProductCost.ACCTTYPE_P_Expense : ProductCost.ACCTTYPE_P_Revenue, as);
if (payables)
{
// if Fixed Asset
if (line.isItem())
acct = line.getAccount (ProductCost.ACCTTYPE_P_InventoryClearing, as);
}
BigDecimal amt = line.getAmtSource().multiply(multiplier);
BigDecimal amt2 = null;
if (creditMemo)
{
amt2 = amt;
amt = null;
}
if (payables) // Vendor = DR
fl = fact.createLine (line, acct,
getC_Currency_ID(), amt, amt2);
else // Customer = CR
fl = fact.createLine (line, acct,
getC_Currency_ID(), amt2, amt);
if (fl != null)
acctAmt = acctAmt.add(fl.getAcctBalance());
}
}
// Tax
for (int i = 0; i < m_taxes.length; i++)
{
BigDecimal amt = m_taxes[i].getAmount();
BigDecimal amt2 = null;
if (creditMemo)
{
amt2 = amt;
amt = null;
}
FactLine tl = null;
if (payables)
tl = fact.createLine (null, m_taxes[i].getAccount(m_taxes[i].getAPTaxType(), as),
getC_Currency_ID(), amt, amt2);
else
tl = fact.createLine (null, m_taxes[i].getAccount(DocTax.ACCTTYPE_TaxDue, as),
getC_Currency_ID(), amt2, amt);
if (tl != null)
tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID());
}
// Set Locations
FactLine[] fLines = fact.getLines();
for (int i = 0; i < fLines.length; i++)
{
if (fLines[i] != null)
{
if (payables)
{
fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc
fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), false); // to Loc
}
else
{
fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), true); // from Loc
fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc
}
}
}
return acctAmt;
} // createFactCash
/**
* Create Landed Cost accounting & Cost lines
* @param as accounting schema
* @param fact fact
* @param line document line
* @param dr DR entry (normal api)
* @return true if landed costs were created
*/
private boolean landedCost (MAcctSchema as, Fact fact, DocLine line, boolean dr)
{
int C_InvoiceLine_ID = line.get_ID();
MLandedCostAllocation[] lcas = MLandedCostAllocation.getOfInvoiceLine(
getCtx(), C_InvoiceLine_ID, getTrxName());
if (lcas.length == 0)
return false;
// Delete Old
String sql = "DELETE M_CostDetail WHERE C_InvoiceLine_ID=" + C_InvoiceLine_ID;
int no = DB.executeUpdate(sql, getTrxName());
if (no != 0)
log.config("CostDetail Deleted #" + no);
// Calculate Total Base
double totalBase = 0;
for (int i = 0; i < lcas.length; i++)
totalBase += lcas[i].getBase().doubleValue();
// Create New
MInvoiceLine il = new MInvoiceLine (getCtx(), C_InvoiceLine_ID, getTrxName());
for (int i = 0; i < lcas.length; i++)
{
MLandedCostAllocation lca = lcas[i];
if (lca.getBase().signum() == 0)
continue;
double percent = totalBase / lca.getBase().doubleValue();
String desc = il.getDescription();
if (desc == null)
desc = percent + "%";
else
desc += " - " + percent + "%";
if (line.getDescription() != null)
desc += " - " + line.getDescription();
// Accounting
ProductCost pc = new ProductCost (Env.getCtx(),
lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(), getTrxName());
BigDecimal drAmt = null;
BigDecimal crAmt = null;
if (dr)
drAmt = lca.getAmt();
else
crAmt = lca.getAmt();
FactLine fl = fact.createLine (line, pc.getAccount(ProductCost.ACCTTYPE_P_CostAdjustment, as),
getC_Currency_ID(), drAmt, crAmt);
fl.setDescription(desc);
// Cost Detail - Convert to AcctCurrency
BigDecimal allocationAmt = lca.getAmt();
if (getC_Currency_ID() != as.getC_Currency_ID())
allocationAmt = MConversionRate.convert(getCtx(), allocationAmt,
getC_Currency_ID(), as.getC_Currency_ID(),
getDateAcct(), getC_ConversionType_ID(),
getAD_Client_ID(), getAD_Org_ID());
if (allocationAmt.scale() > as.getCostingPrecision())
allocationAmt = allocationAmt.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
if (!dr)
allocationAmt = allocationAmt.negate();
MCostDetail cd = new MCostDetail (as, lca.getAD_Org_ID(),
lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(),
lca.getM_CostElement_ID(),
allocationAmt, Env.ZERO, // Qty
desc, getTrxName());
cd.setC_InvoiceLine_ID(C_InvoiceLine_ID);
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
MClient client = MClient.get(as.getCtx(), as.getAD_Client_ID());
if (client.isCostImmediate())
cd.process();
}
}
log.config("Created #" + lcas.length);
return true;
} // landedCosts
/**
* Update ProductPO PriceLastInv
* @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 PriceLastInv = "
// select
+ "(SELECT currencyConvert(il.PriceActual,i.C_Currency_ID,po.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID) "
+ "FROM C_Invoice i, C_InvoiceLine il "
+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
+ " AND po.M_Product_ID=il.M_Product_ID AND po.C_BPartner_ID=i.C_BPartner_ID");
//jz + " AND ROWNUM=1 AND i.C_Invoice_ID=").append(get_ID()).append(") ")
if (DB.isOracle()) //jz
{
sql.append(" AND ROWNUM=1 ");
}
else
{
sql.append(" AND il.C_InvoiceLine_ID = (SELECT MIN(il1.C_InvoiceLine_ID) "
+ "FROM C_Invoice i1, C_InvoiceLine il1 "
+ "WHERE i1.C_Invoice_ID=il1.C_Invoice_ID"
+ " AND po.M_Product_ID=il1.M_Product_ID AND po.C_BPartner_ID=i1.C_BPartner_ID")
.append(" AND i1.C_Invoice_ID=").append(get_ID()).append(") ");
}
sql.append(" AND i.C_Invoice_ID=").append(get_ID()).append(") ")
// update
.append("WHERE EXISTS (SELECT * "
+ "FROM C_Invoice i, C_InvoiceLine il "
+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
+ " AND po.M_Product_ID=il.M_Product_ID AND po.C_BPartner_ID=i.C_BPartner_ID"
+ " AND i.C_Invoice_ID=").append(get_ID()).append(")");
int no = DB.executeUpdate(sql.toString(), getTrxName());
log.fine("Updated=" + no);
} // updateProductPO
/**
* Update Product Info (old).
* - Costing (PriceLastInv)
* - PO (PriceLastInv)
* @param C_AcctSchema_ID accounting schema
* @deprecated old costing
*/
private void updateProductInfo (int C_AcctSchema_ID)
{
log.fine("C_Invoice_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
// -> TotalInvAmt is sometimes NULL !! -> error
// begin globalqss 2005-10-19
// postgresql doesn't support LIMIT on UPDATE or DELETE statements
/*
StringBuffer sql = new StringBuffer (
"UPDATE M_Product_Costing pc "
+ "SET (PriceLastInv, TotalInvAmt,TotalInvQty) = "
// select
+ "(SELECT currencyConvert(il.PriceActual,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID),"
+ " currencyConvert(il.LineNetAmt,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID),il.QtyInvoiced "
+ "FROM C_Invoice i, C_InvoiceLine il, C_AcctSchema a "
+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
+ " AND pc.M_Product_ID=il.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
+ " AND ROWNUM=1"
+ " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND i.C_Invoice_ID=")
.append(get_ID()).append(") ")
// update
.append("WHERE EXISTS (SELECT * "
+ "FROM C_Invoice i, C_InvoiceLine il, C_AcctSchema a "
+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
+ " AND pc.M_Product_ID=il.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
+ " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND i.C_Invoice_ID=")
.append(get_ID()).append(")");
*/
// the next command is equivalent and works in postgresql and oracle
StringBuffer sql = new StringBuffer (
"UPDATE M_Product_Costing pc "
+ "SET (PriceLastInv, TotalInvAmt,TotalInvQty) = "
// select
+ "(SELECT currencyConvert(il.PriceActual,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID),"
+ " currencyConvert(il.LineNetAmt,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID),il.QtyInvoiced "
+ "FROM C_Invoice i, C_InvoiceLine il, C_AcctSchema a "
+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
+ " AND il.c_invoiceline_id = (SELECT MIN(C_InvoiceLine_ID) FROM C_InvoiceLine il2" +
" WHERE il2.M_PRODUCT_ID=il.M_PRODUCT_ID AND C_Invoice_ID=")
.append(get_ID()).append(")"
+ " AND pc.M_Product_ID=il.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
+ " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND i.C_Invoice_ID=")
.append(get_ID()).append(") ")
// update
.append("WHERE EXISTS (SELECT * "
+ "FROM C_Invoice i, C_InvoiceLine il, C_AcctSchema a "
+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
+ " AND pc.M_Product_ID=il.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
+ " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND i.C_Invoice_ID=")
.append(get_ID()).append(")");
// end globalqss 2005-10-19
int no = DB.executeUpdate(sql.toString(), getTrxName());
log.fine("M_Product_Costing - Updated=" + no);
} // updateProductInfo
} // Doc_Invoice

View File

@ -0,0 +1,327 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import org.compiere.util.*;
/**
* Post MatchInv Documents.
* <pre>
* Table: M_MatchInv (472)
* Document Types: MXI
* </pre>
* Update Costing Records
* @author Jorg Janke
* @version $Id: Doc_MatchInv.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_MatchInv extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_MatchInv (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super(ass, MMatchInv.class, rs, DOCTYPE_MatMatchInv, trxName);
} // Doc_MatchInv
/** Invoice Line */
private MInvoiceLine m_invoiceLine = null;
/** Material Receipt */
private MInOutLine m_receiptLine = null;
private ProductCost m_pc = null;
/** Commitments */
private DocLine[] m_commitments = null;
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
setC_Currency_ID (Doc.NO_CURRENCY);
MMatchInv matchInv = (MMatchInv)getPO();
setDateDoc(matchInv.getDateTrx());
setQty (matchInv.getQty());
// Invoice Info
int C_InvoiceLine_ID = matchInv.getC_InvoiceLine_ID();
m_invoiceLine = new MInvoiceLine (getCtx(), C_InvoiceLine_ID, null);
// BP for NotInvoicedReceipts
int C_BPartner_ID = m_invoiceLine.getParent().getC_BPartner_ID();
setC_BPartner_ID(C_BPartner_ID);
//
int M_InOutLine_ID = matchInv.getM_InOutLine_ID();
m_receiptLine = new MInOutLine (getCtx(), M_InOutLine_ID, null);
//
m_pc = new ProductCost (Env.getCtx(),
getM_Product_ID(), matchInv.getM_AttributeSetInstance_ID(), null);
m_pc.setQty(getQty());
return null;
} // loadDocumentDetails
/**************************************************************************
* Get Source Currency Balance - subtracts line and tax amounts from total - no rounding
* @return Zero (always balanced)
*/
public BigDecimal getBalance()
{
return Env.ZERO;
} // getBalance
/**
* Create Facts (the accounting logic) for
* MXI.
* (single line)
* <pre>
* NotInvoicedReceipts DR (Receipt Org)
* InventoryClearing CR
* InvoicePV DR CR (difference)
* Commitment
* Expense CR
* Offset DR
* </pre>
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
ArrayList<Fact> facts = new ArrayList<Fact>();
// Nothing to do
if (getM_Product_ID() == 0 // no Product
|| getQty().signum() == 0
|| m_receiptLine.getMovementQty().signum() == 0) // Qty = 0
{
log.fine("No Product/Qty - M_Product_ID=" + getM_Product_ID()
+ ",Qty=" + getQty() + ",InOutQty=" + m_receiptLine.getMovementQty());
return facts;
}
MMatchInv matchInv = (MMatchInv)getPO();
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
setC_Currency_ID (as.getC_Currency_ID());
/** Needs to be handeled in PO Matching as no Receipt info
if (m_pc.isService())
{
log.fine("Service - skipped");
return fact;
}
**/
// NotInvoicedReceipt DR
// From Receipt
BigDecimal multiplier = getQty()
.divide(m_receiptLine.getMovementQty(), 12, BigDecimal.ROUND_HALF_UP)
.abs();
FactLine dr = fact.createLine (null,
getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as),
as.getC_Currency_ID(), Env.ONE, null); // updated below
if (dr == null)
{
p_Error = "No Product Costs";
return null;
}
dr.setQty(getQty());
// dr.setM_Locator_ID(m_receiptLine.getM_Locator_ID());
// MInOut receipt = m_receiptLine.getParent();
// dr.setLocationFromBPartner(receipt.getC_BPartner_Location_ID(), true); // from Loc
// dr.setLocationFromLocator(m_receiptLine.getM_Locator_ID(), false); // to Loc
BigDecimal temp = dr.getAcctBalance();
// Set AmtAcctCr/Dr from Receipt (sets also Project)
if (!dr.updateReverseLine (MInOut.Table_ID, // Amt updated
m_receiptLine.getM_InOut_ID(), m_receiptLine.getM_InOutLine_ID(),
multiplier))
{
p_Error = "Mat.Receipt not posted yet";
return null;
}
log.fine("CR - Amt(" + temp + "->" + dr.getAcctBalance()
+ ") - " + dr.toString());
// InventoryClearing CR
// From Invoice
MAccount expense = m_pc.getAccount(ProductCost.ACCTTYPE_P_InventoryClearing, as);
if (m_pc.isService())
expense = m_pc.getAccount(ProductCost.ACCTTYPE_P_Expense, as);
BigDecimal LineNetAmt = m_invoiceLine.getLineNetAmt();
multiplier = getQty()
.divide(m_invoiceLine.getQtyInvoiced(), 12, BigDecimal.ROUND_HALF_UP)
.abs();
if (multiplier.compareTo(Env.ONE) != 0)
LineNetAmt = LineNetAmt.multiply(multiplier);
if (m_pc.isService())
LineNetAmt = dr.getAcctBalance(); // book out exact receipt amt
FactLine cr = null;
if (as.isAccrual())
{
cr = fact.createLine (null, expense,
as.getC_Currency_ID(), null, LineNetAmt); // updated below
if (cr == null)
{
log.fine("Line Net Amt=0 - M_Product_ID=" + getM_Product_ID()
+ ",Qty=" + getQty() + ",InOutQty=" + m_receiptLine.getMovementQty());
facts.add(fact);
return facts;
}
cr.setQty(getQty().negate());
temp = cr.getAcctBalance();
// Set AmtAcctCr/Dr from Invoice (sets also Project)
if (as.isAccrual() && !cr.updateReverseLine (MInvoice.Table_ID, // Amt updated
m_invoiceLine.getC_Invoice_ID(), m_invoiceLine.getC_InvoiceLine_ID(), multiplier))
{
p_Error = "Invoice not posted yet";
return null;
}
log.fine("DR - Amt(" + temp + "->" + cr.getAcctBalance()
+ ") - " + cr.toString());
}
else // Cash Acct
{
MInvoice invoice = m_invoiceLine.getParent();
if (as.getC_Currency_ID() == invoice.getC_Currency_ID())
LineNetAmt = MConversionRate.convert(getCtx(), LineNetAmt,
invoice.getC_Currency_ID(), as.getC_Currency_ID(),
invoice.getDateAcct(), invoice.getC_ConversionType_ID(),
invoice.getAD_Client_ID(), invoice.getAD_Org_ID());
cr = fact.createLine (null, expense,
as.getC_Currency_ID(), null, LineNetAmt);
cr.setQty(getQty().multiply(multiplier).negate());
}
cr.setC_Activity_ID(m_invoiceLine.getC_Activity_ID());
cr.setC_Campaign_ID(m_invoiceLine.getC_Campaign_ID());
cr.setC_Project_ID(m_invoiceLine.getC_Project_ID());
cr.setC_UOM_ID(m_invoiceLine.getC_UOM_ID());
cr.setUser1_ID(m_invoiceLine.getUser1_ID());
cr.setUser2_ID(m_invoiceLine.getUser2_ID());
// Invoice Price Variance difference
BigDecimal ipv = cr.getAcctBalance().add(dr.getAcctBalance()).negate();
if (ipv.signum() != 0)
{
FactLine pv = fact.createLine(null,
m_pc.getAccount(ProductCost.ACCTTYPE_P_IPV, as),
as.getC_Currency_ID(), ipv);
pv.setC_Activity_ID(m_invoiceLine.getC_Activity_ID());
pv.setC_Campaign_ID(m_invoiceLine.getC_Campaign_ID());
pv.setC_Project_ID(m_invoiceLine.getC_Project_ID());
pv.setC_UOM_ID(m_invoiceLine.getC_UOM_ID());
pv.setUser1_ID(m_invoiceLine.getUser1_ID());
pv.setUser2_ID(m_invoiceLine.getUser2_ID());
}
log.fine("IPV=" + ipv + "; Balance=" + fact.getSourceBalance());
// Cost Detail Record - data from Expense/IncClearing (CR) record
MCostDetail.createInvoice(as, getAD_Org_ID(),
getM_Product_ID(), matchInv.getM_AttributeSetInstance_ID(),
m_invoiceLine.getC_InvoiceLine_ID(), 0, // No cost element
cr.getAcctBalance().negate(), getQty(), // correcting
getDescription(), getTrxName());
// Update Costing
updateProductInfo(as.getC_AcctSchema_ID(),
MAcctSchema.COSTINGMETHOD_StandardCosting.equals(as.getCostingMethod()));
//
facts.add(fact);
/** Commitment release ****/
if (as.isAccrual() && as.isCreateCommitment())
{
fact = Doc_Order.getCommitmentRelease(as, this,
getQty(), m_invoiceLine.getC_InvoiceLine_ID(), Env.ONE);
if (fact == null)
return null;
facts.add(fact);
} // Commitment
return facts;
} // createFact
/**
* Update Product Info (old).
* - Costing (CostStandardCumQty, CostStandardCumAmt, CostAverageCumQty, CostAverageCumAmt)
* @param C_AcctSchema_ID accounting schema
* @param standardCosting true if std costing
* @return true if updated
* @deprecated old costing
*/
private boolean updateProductInfo (int C_AcctSchema_ID, boolean standardCosting)
{
log.fine("M_MatchInv_ID=" + get_ID());
// update Product Costing Qty/Amt
// requires existence of currency conversion !!
StringBuffer sql = new StringBuffer (
"UPDATE M_Product_Costing pc "
+ "SET (CostStandardCumQty,CostStandardCumAmt, CostAverageCumQty,CostAverageCumAmt) = "
+ "(SELECT pc.CostStandardCumQty + m.Qty,"
+ "pc.CostStandardCumAmt + currencyConvert(il.PriceActual,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*m.Qty, "
+ "pc.CostAverageCumQty + m.Qty,"
+ "pc.CostAverageCumAmt + currencyConvert(il.PriceActual,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*m.Qty "
+ "FROM M_MatchInv m"
+ " INNER JOIN C_InvoiceLine il ON (m.C_InvoiceLine_ID=il.C_InvoiceLine_ID)"
+ " INNER JOIN C_Invoice i ON (il.C_Invoice_ID=i.C_Invoice_ID),"
+ " C_AcctSchema a "
+ "WHERE pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
+ " AND pc.M_Product_ID=m.M_Product_ID"
+ " AND m.M_MatchInv_ID=").append(get_ID()).append(")"
//
+ "WHERE pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(
" AND EXISTS (SELECT * FROM M_MatchInv m "
+ "WHERE pc.M_Product_ID=m.M_Product_ID"
+ " AND m.M_MatchInv_ID=").append(get_ID()).append(")");
int no = DB.executeUpdate(sql.toString(), getTrxName());
log.fine("M_Product_Costing - Qty/Amt Updated #=" + no);
// Update Average Cost
sql = new StringBuffer (
"UPDATE M_Product_Costing "
+ "SET CostAverage = CostAverageCumAmt/DECODE(CostAverageCumQty, 0,1, CostAverageCumQty) "
+ "WHERE C_AcctSchema_ID=").append(C_AcctSchema_ID)
.append(" AND M_Product_ID=").append(getM_Product_ID());
no = DB.executeUpdate(sql.toString(), getTrxName());
log.fine("M_Product_Costing - AvgCost Updated #=" + no);
// Update Current Cost
if (!standardCosting)
{
sql = new StringBuffer (
"UPDATE M_Product_Costing "
+ "SET CurrentCostPrice = CostAverage "
+ "WHERE C_AcctSchema_ID=").append(C_AcctSchema_ID)
.append(" AND M_Product_ID=").append(getM_Product_ID());
no = DB.executeUpdate(sql.toString(), getTrxName());
log.fine("M_Product_Costing - CurrentCost Updated=" + no);
}
return true;
} // updateProductInfo
} // Doc_MatchInv

View File

@ -0,0 +1,251 @@
/******************************************************************************
* 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. *
* 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 MatchPO Documents.
* <pre>
* Table: C_MatchPO (473)
* Document Types: MXP
* </pre>
* @author Jorg Janke
* @version $Id: Doc_MatchPO.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_MatchPO extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_MatchPO (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super(ass, MMatchPO.class, rs, DOCTYPE_MatMatchPO, trxName);
} // Doc_MatchPO
private int m_C_OrderLine_ID = 0;
private MOrderLine m_oLine = null;
//
private int m_M_InOutLine_ID = 0;
private int m_C_InvoiceLine_ID = 0;
private ProductCost m_pc;
private int m_M_AttributeSetInstance_ID = 0;
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
setC_Currency_ID (Doc.NO_CURRENCY);
MMatchPO matchPO = (MMatchPO)getPO();
setDateDoc(matchPO.getDateTrx());
//
m_M_AttributeSetInstance_ID = matchPO.getM_AttributeSetInstance_ID();
setQty (matchPO.getQty());
//
m_C_OrderLine_ID = matchPO.getC_OrderLine_ID();
m_oLine = new MOrderLine (getCtx(), m_C_OrderLine_ID, getTrxName());
//
m_M_InOutLine_ID = matchPO.getM_InOutLine_ID();
m_C_InvoiceLine_ID = matchPO.getC_InvoiceLine_ID();
//
m_pc = new ProductCost (Env.getCtx(),
getM_Product_ID(), m_M_AttributeSetInstance_ID, getTrxName());
m_pc.setQty(getQty());
return null;
} // loadDocumentDetails
/**************************************************************************
* Get Source Currency Balance - subtracts line and tax amounts from total - no rounding
* @return Zero - always balanced
*/
public BigDecimal getBalance()
{
return Env.ZERO;
} // getBalance
/**
* Create Facts (the accounting logic) for
* MXP.
* <pre>
* Product PPV <difference>
* PPV_Offset <difference>
* </pre>
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
ArrayList<Fact> facts = new ArrayList<Fact>();
//
if (getM_Product_ID() == 0 // Nothing to do if no Product
|| getQty().signum() == 0
|| m_M_InOutLine_ID == 0) // No posting if not matched to Shipment
{
log.fine("No Product/Qty - M_Product_ID=" + getM_Product_ID()
+ ",Qty=" + getQty());
return facts;
}
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
setC_Currency_ID(as.getC_Currency_ID());
// Purchase Order Line
BigDecimal poCost = m_oLine.getPriceCost();
if (poCost == null || poCost.signum() == 0)
poCost = m_oLine.getPriceActual();
poCost = poCost.multiply(getQty()); // Delivered so far
// Different currency
if (m_oLine.getC_Currency_ID() != as.getC_Currency_ID())
{
MOrder order = m_oLine.getParent();
BigDecimal rate = MConversionRate.getRate(
order.getC_Currency_ID(), as.getC_Currency_ID(),
order.getDateAcct(), order.getC_ConversionType_ID(),
m_oLine.getAD_Client_ID(), m_oLine.getAD_Org_ID());
if (rate == null)
{
p_Error = "Purchase Order not convertible - " + as.getName();
return null;
}
poCost = poCost.multiply(rate);
if (poCost.scale() > as.getCostingPrecision())
poCost = poCost.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
}
// Create PO Cost Detail Record firs
MCostDetail.createOrder(as, m_oLine.getAD_Org_ID(),
getM_Product_ID(), m_M_AttributeSetInstance_ID,
m_C_OrderLine_ID, 0, // no cost element
poCost, getQty(), // Delivered
m_oLine.getDescription(), getTrxName());
// Calculate PPV for standard costing
String costingMethod = as.getCostingMethod();
MProduct product = MProduct.get(getCtx(), getM_Product_ID());
MProductCategoryAcct pca = MProductCategoryAcct.get(getCtx(),
product.getM_Product_Category_ID(), as.getC_AcctSchema_ID(), getTrxName());
if (pca.getCostingMethod() != null)
costingMethod = pca.getCostingMethod();
//get standard cost and also makesure cost for other costing method is updated
BigDecimal costs = m_pc.getProductCosts(as, getAD_Org_ID(),
MAcctSchema.COSTINGMETHOD_StandardCosting, m_C_OrderLine_ID, false); // non-zero costs
if (MAcctSchema.COSTINGMETHOD_StandardCosting.equals(costingMethod))
{
// No Costs yet - no PPV
if (costs == null || costs.signum() == 0)
{
p_Error = "Resubmit - No Costs for " + product.getName();
log.log(Level.SEVERE, p_Error);
return null;
}
// Difference
BigDecimal difference = poCost.subtract(costs);
// Nothing to post
if (difference.signum() == 0)
{
log.log(Level.FINE, "No Cost Difference for M_Product_ID=" + getM_Product_ID());
return facts;
}
// Product PPV
FactLine cr = fact.createLine(null,
m_pc.getAccount(ProductCost.ACCTTYPE_P_PPV, as),
as.getC_Currency_ID(), difference);
if (cr != null)
{
cr.setQty(getQty());
cr.setC_BPartner_ID(m_oLine.getC_BPartner_ID());
cr.setC_Activity_ID(m_oLine.getC_Activity_ID());
cr.setC_Campaign_ID(m_oLine.getC_Campaign_ID());
cr.setC_Project_ID(m_oLine.getC_Project_ID());
cr.setC_UOM_ID(m_oLine.getC_UOM_ID());
cr.setUser1_ID(m_oLine.getUser1_ID());
cr.setUser2_ID(m_oLine.getUser2_ID());
}
// PPV Offset
FactLine dr = fact.createLine(null,
getAccount(Doc.ACCTTYPE_PPVOffset, as),
as.getC_Currency_ID(), difference.negate());
if (dr != null)
{
dr.setQty(getQty().negate());
dr.setC_BPartner_ID(m_oLine.getC_BPartner_ID());
dr.setC_Activity_ID(m_oLine.getC_Activity_ID());
dr.setC_Campaign_ID(m_oLine.getC_Campaign_ID());
dr.setC_Project_ID(m_oLine.getC_Project_ID());
dr.setC_UOM_ID(m_oLine.getC_UOM_ID());
dr.setUser1_ID(m_oLine.getUser1_ID());
dr.setUser2_ID(m_oLine.getUser2_ID());
}
//
facts.add(fact);
return facts;
}
else
{
return facts;
}
} // createFact
/**
* Update Product Info (old).
* - Costing (CostStandardPOQty, CostStandardPOAmt)
* @param C_AcctSchema_ID accounting schema
* @deprecated old costing
*/
private void updateProductInfo (int C_AcctSchema_ID)
{
log.fine("M_MatchPO_ID=" + get_ID());
// update Product Costing
// requires existence of currency conversion !!
StringBuffer sql = new StringBuffer (
"UPDATE M_Product_Costing pc "
+ "SET (CostStandardPOQty,CostStandardPOAmt) = "
+ "(SELECT CostStandardPOQty + m.Qty,"
+ " CostStandardPOAmt + currencyConvert(ol.PriceActual,ol.C_Currency_ID,a.C_Currency_ID,ol.DateOrdered,null,ol.AD_Client_ID,ol.AD_Org_ID)*m.Qty "
+ "FROM M_MatchPO m, C_OrderLine ol, C_AcctSchema a "
+ "WHERE m.C_OrderLine_ID=ol.C_OrderLine_ID"
+ " AND pc.M_Product_ID=ol.M_Product_ID"
+ " AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
+ "AND m.M_MatchPO_ID=").append(get_ID()).append(") ")
.append("WHERE pc.C_AcctSchema_ID=").append(C_AcctSchema_ID)
.append(" AND pc.M_Product_ID=").append(getM_Product_ID());
int no = DB.executeUpdate(sql.toString(), getTrxName());
log.fine("M_Product_Costing - Updated=" + no);
} // updateProductInfo
} // Doc_MatchPO

View File

@ -0,0 +1,179 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import org.compiere.util.*;
/**
* Post Invoice Documents.
* <pre>
* Table: M_Movement (323)
* Document Types: MMM
* </pre>
* @author Jorg Janke
* @version $Id: Doc_Movement.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Movement extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
public Doc_Movement (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MMovement.class, rs, DOCTYPE_MatMovement, trxName);
} // Doc_Movement
/**
* Load Document Details
* @return error message or null
*/
protected String loadDocumentDetails()
{
setC_Currency_ID(NO_CURRENCY);
MMovement move = (MMovement)getPO();
setDateDoc (move.getMovementDate());
setDateAcct(move.getMovementDate());
// Contained Objects
p_lines = loadLines(move);
log.fine("Lines=" + p_lines.length);
return null;
} // loadDocumentDetails
/**
* Load Invoice Line
* @param move move
* @return document lines (DocLine_Material)
*/
private DocLine[] loadLines(MMovement move)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
MMovementLine[] lines = move.getLines(false);
for (int i = 0; i < lines.length; i++)
{
MMovementLine line = lines[i];
DocLine docLine = new DocLine (line, this);
docLine.setQty(line.getMovementQty(), false);
//
log.fine(docLine.toString());
list.add (docLine);
}
// Return Array
DocLine[] dls = new DocLine[list.size()];
list.toArray(dls);
return dls;
} // loadLines
/**
* Get Balance
* @return balance (ZERO) - always balanced
*/
public BigDecimal getBalance()
{
BigDecimal retValue = Env.ZERO;
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* MMM.
* <pre>
* Movement
* Inventory DR CR
* InventoryTo DR CR
* </pre>
* @param as account schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
setC_Currency_ID(as.getC_Currency_ID());
// Line pointers
FactLine dr = null;
FactLine cr = null;
for (int i = 0; i < p_lines.length; i++)
{
DocLine line = p_lines[i];
BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), false);
// ** Inventory DR CR
dr = fact.createLine(line,
line.getAccount(ProductCost.ACCTTYPE_P_Asset, as),
as.getC_Currency_ID(), costs.negate()); // from (-) CR
if (dr == null)
continue;
dr.setM_Locator_ID(line.getM_Locator_ID());
dr.setQty(line.getQty().negate()); // outgoing
// ** InventoryTo DR CR
cr = fact.createLine(line,
line.getAccount(ProductCost.ACCTTYPE_P_Asset, as),
as.getC_Currency_ID(), costs); // to (+) DR
if (cr == null)
continue;
cr.setM_Locator_ID(line.getM_LocatorTo_ID());
cr.setQty(line.getQty());
// Only for between-org movements
if (dr.getAD_Org_ID() != cr.getAD_Org_ID())
{
String costingLevel = as.getCostingLevel();
MProductCategoryAcct pca = MProductCategoryAcct.get(getCtx(),
line.getProduct().getM_Product_Category_ID(),
as.getC_AcctSchema_ID(), getTrxName());
if (pca.getCostingLevel() != null)
costingLevel = pca.getCostingLevel();
if (!MAcctSchema.COSTINGLEVEL_Organization.equals(costingLevel))
continue;
//
String description = line.getDescription();
if (description == null)
description = "";
// Cost Detail From
MCostDetail.createMovement(as, dr.getAD_Org_ID(), // locator org
line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
line.get_ID(), 0,
costs.negate(), line.getQty().negate(), true,
description + "(|->)", getTrxName());
// Cost Detail To
MCostDetail.createMovement(as, cr.getAD_Org_ID(), // locator org
line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
line.get_ID(), 0,
costs, line.getQty(), false,
description + "(|<-)", getTrxName());
}
}
//
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
} // createFact
} // Doc_Movement

View File

@ -0,0 +1,646 @@
/******************************************************************************
* 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. *
* 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.
* <pre>
* Table: C_Order (259)
* Document Types: SOO, POO
* </pre>
* @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<DocLine> list = new ArrayList<DocLine>();
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());
//
BigDecimal PriceActual = line.getPriceActual();
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<Integer,BigDecimal> qtys = new HashMap<Integer,BigDecimal>();
for (int i = 0; i < oLines.length; i++)
{
MOrderLine line = oLines[i];
qtys.put(new Integer(line.getC_OrderLine_ID()), line.getQtyOrdered());
}
//
ArrayList<DocLine> list = new ArrayList<DocLine>();
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<DocTax> list = new ArrayList<DocTax>();
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.
* <pre>
* Reservation (release)
* Expense DR
* Offset CR
* Commitment
* (to be released by Invoice Matching)
* Expense CR
* Offset DR
* </pre>
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
ArrayList<Fact> facts = new ArrayList<Fact>();
// 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);
// Account
MAccount expense = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as);
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);
// Account
MAccount expense = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as);
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 ");
//jz + " AND ROWNUM=1 AND o.C_Order_ID=").append(get_ID()).append(") ")
if (DB.isOracle()) //jz
{
sql.append(" AND ROWNUM=1 ");
}
else
sql.append(" AND ol.C_OrderLine_ID = (SELECT MIN(ol1.C_OrderLine_ID) "
+ "FROM C_Order o1, C_OrderLine ol1 "
+ "WHERE o1.C_Order_ID=ol1.C_Order_ID"
+ " AND po.M_Product_ID=ol1.M_Product_ID AND po.C_BPartner_ID=o1.C_BPartner_ID")
.append(" AND o1.C_Order_ID=").append(get_ID()).append(") ");
sql.append(" 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<DocLine> list = new ArrayList<DocLine>();
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);
// Account
MAccount expense = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as);
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) "
+ "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 ");
if (DB.isOracle()) //jz
{
sql.append(" AND ROWNUM=1 ");
}
else
sql.append(" AND ol.C_OrderLine_ID = (SELECT MIN(ol1.C_OrderLine_ID) "
+ "FROM C_Order o1, C_OrderLine ol1 "
+ "WHERE o1.C_Order_ID=ol1.C_Order_ID"
+ " AND pc.M_Product_ID=ol1.M_Product_ID ")
.append(" AND o1.C_Order_ID=").append(get_ID()).append(") ");
sql.append(" 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

View File

@ -0,0 +1,183 @@
/******************************************************************************
* 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. *
* 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 Invoice Documents.
* <pre>
* Table: C_Payment (335)
* Document Types ARP, APP
* </pre>
* @author Jorg Janke
* @version $Id: Doc_Payment.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Payment extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_Payment (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MPayment.class, rs, null, trxName);
} // Doc_Payment
/** Tender Type */
private String m_TenderType = null;
/** Prepayment */
private boolean m_Prepayment = false;
/** Bank Account */
private int m_C_BankAccount_ID = 0;
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
MPayment pay = (MPayment)getPO();
setDateDoc(pay.getDateTrx());
m_TenderType = pay.getTenderType();
m_Prepayment = pay.isPrepayment();
m_C_BankAccount_ID = pay.getC_BankAccount_ID();
// Amount
setAmount(Doc.AMTTYPE_Gross, pay.getPayAmt());
return null;
} // loadDocumentDetails
/**************************************************************************
* Get Source Currency Balance - always zero
* @return Zero (always balanced)
*/
public BigDecimal getBalance()
{
BigDecimal retValue = Env.ZERO;
// log.config( toString() + " Balance=" + retValue);
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* ARP, APP.
* <pre>
* ARP
* BankInTransit DR
* UnallocatedCash CR
* or Charge/C_Prepayment
* APP
* PaymentSelect DR
* or Charge/V_Prepayment
* BankInTransit CR
* CashBankTransfer
* -
* </pre>
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
// Cash Transfer
if ("X".equals(m_TenderType))
{
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
}
int AD_Org_ID = getBank_Org_ID(); // Bank Account Org
if (getDocumentType().equals(DOCTYPE_ARReceipt))
{
// Asset
FactLine fl = fact.createLine(null, getAccount(Doc.ACCTTYPE_BankInTransit, as),
getC_Currency_ID(), getAmount(), null);
if (fl != null && AD_Org_ID != 0)
fl.setAD_Org_ID(AD_Org_ID);
//
MAccount acct = null;
if (getC_Charge_ID() != 0)
acct = MCharge.getAccount(getC_Charge_ID(), as, getAmount());
else if (m_Prepayment)
acct = getAccount(Doc.ACCTTYPE_C_Prepayment, as);
else
acct = getAccount(Doc.ACCTTYPE_UnallocatedCash, as);
fl = fact.createLine(null, acct,
getC_Currency_ID(), null, getAmount());
if (fl != null && AD_Org_ID != 0
&& getC_Charge_ID() == 0) // don't overwrite charge
fl.setAD_Org_ID(AD_Org_ID);
}
// APP
else if (getDocumentType().equals(DOCTYPE_APPayment))
{
MAccount acct = null;
if (getC_Charge_ID() != 0)
acct = MCharge.getAccount(getC_Charge_ID(), as, getAmount());
else if (m_Prepayment)
acct = getAccount(Doc.ACCTTYPE_V_Prepayment, as);
else
acct = getAccount(Doc.ACCTTYPE_PaymentSelect, as);
FactLine fl = fact.createLine(null, acct,
getC_Currency_ID(), getAmount(), null);
if (fl != null && AD_Org_ID != 0
&& getC_Charge_ID() == 0) // don't overwrite charge
fl.setAD_Org_ID(AD_Org_ID);
// Asset
fl = fact.createLine(null, getAccount(Doc.ACCTTYPE_BankInTransit, as),
getC_Currency_ID(), null, getAmount());
if (fl != null && AD_Org_ID != 0)
fl.setAD_Org_ID(AD_Org_ID);
}
else
{
p_Error = "DocumentType unknown: " + getDocumentType();
log.log(Level.SEVERE, p_Error);
fact = null;
}
//
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
} // createFact
/**
* Get AD_Org_ID from Bank Account
* @return AD_Org_ID or 0
*/
private int getBank_Org_ID ()
{
if (m_C_BankAccount_ID == 0)
return 0;
//
MBankAccount ba = MBankAccount.get(getCtx(), m_C_BankAccount_ID);
return ba.getAD_Org_ID();
} // getBank_Org_ID
} // Doc_Payment

View File

@ -0,0 +1,216 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import java.util.logging.*;
import org.compiere.util.*;
/**
* Post Invoice Documents.
* <pre>
* Table: M_Production (325)
* Document Types: MMP
* </pre>
* @author Jorg Janke
* @version $Id: Doc_Production.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Production extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
public Doc_Production (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, X_M_Production.class, rs, DOCTYPE_MatProduction, trxName);
} // Doc_Production
/**
* Load Document Details
* @return error message or null
*/
protected String loadDocumentDetails()
{
setC_Currency_ID (NO_CURRENCY);
X_M_Production prod = (X_M_Production)getPO();
setDateDoc (prod.getMovementDate());
setDateAcct(prod.getMovementDate());
// Contained Objects
p_lines = loadLines(prod);
log.fine("Lines=" + p_lines.length);
return null;
} // loadDocumentDetails
/**
* Load Invoice Line
* @param prod production
* @return DoaLine Array
*/
private DocLine[] loadLines(X_M_Production prod)
{
ArrayList<DocLine> list = new ArrayList<DocLine>();
// Production
// -- ProductionPlan
// -- -- ProductionLine - the real level
String sqlPP = "SELECT * FROM M_ProductionPlan pp "
+ "WHERE pp.M_Production_ID=? "
+ "ORDER BY pp.Line";
String sqlPL = "SELECT * FROM M_ProductionLine pl "
+ "WHERE pl.M_ProductionPlan_ID=? "
+ "ORDER BY pl.Line";
try
{
PreparedStatement pstmtPP = DB.prepareStatement(sqlPP, getTrxName());
pstmtPP.setInt(1, get_ID());
ResultSet rsPP = pstmtPP.executeQuery();
//
while (rsPP.next())
{
int M_Product_ID = rsPP.getInt("M_Product_ID");
int M_ProductionPlan_ID = rsPP.getInt("M_ProductionPlan_ID");
//
try
{
PreparedStatement pstmtPL = DB.prepareStatement(sqlPL, getTrxName());
pstmtPL.setInt(1, M_ProductionPlan_ID);
ResultSet rsPL = pstmtPL.executeQuery();
while (rsPL.next())
{
X_M_ProductionLine line = new X_M_ProductionLine(getCtx(), rsPL, getTrxName());
if (line.getMovementQty().signum() == 0)
{
log.info("LineQty=0 - " + line);
continue;
}
DocLine docLine = new DocLine (line, this);
docLine.setQty (line.getMovementQty(), false);
// Identify finished BOM Product
docLine.setProductionBOM(line.getM_Product_ID() == M_Product_ID);
//
log.fine(docLine.toString());
list.add (docLine);
}
rsPL.close();
pstmtPL.close();
}
catch (Exception ee)
{
log.log(Level.SEVERE, sqlPL, ee);
}
}
rsPP.close();
pstmtPP.close();
}
catch (SQLException e)
{
log.log(Level.SEVERE, sqlPP, e);
}
// Return Array
DocLine[] dl = new DocLine[list.size()];
list.toArray(dl);
return dl;
} // loadLines
/**
* Get Balance
* @return Zero (always balanced)
*/
public BigDecimal getBalance()
{
BigDecimal retValue = Env.ZERO;
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* MMP.
* <pre>
* Production
* Inventory DR CR
* </pre>
* @param as account schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
setC_Currency_ID (as.getC_Currency_ID());
// Line pointer
FactLine fl = null;
for (int i = 0; i < p_lines.length; i++)
{
DocLine line = p_lines[i];
// Calculate Costs
BigDecimal costs = null;
if (line.isProductionBOM())
{
// Get BOM Cost - Sum of individual lines
BigDecimal bomCost = Env.ZERO;
for (int ii = 0; ii < p_lines.length; ii++)
{
DocLine line0 = p_lines[ii];
if (line0.getM_ProductionPlan_ID() != line.getM_ProductionPlan_ID())
continue;
if (!line0.isProductionBOM())
bomCost = bomCost.add(line0.getProductCosts(as, line.getAD_Org_ID(), false));
}
costs = bomCost.negate();
}
else
costs = line.getProductCosts(as, line.getAD_Org_ID(), false);
// Inventory DR CR
fl = fact.createLine(line,
line.getAccount(ProductCost.ACCTTYPE_P_Asset, as),
as.getC_Currency_ID(), costs);
if (fl == null)
{
p_Error = "No Costs for Line " + line.getLine() + " - " + line;
return null;
}
fl.setM_Locator_ID(line.getM_Locator_ID());
fl.setQty(line.getQty());
// Cost Detail
String description = line.getDescription();
if (description == null)
description = "";
if (line.isProductionBOM())
description += "(*)";
MCostDetail.createProduction(as, line.getAD_Org_ID(),
line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
line.get_ID(), 0,
costs, line.getQty(),
description, getTrxName());
}
//
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
} // createFact
} // Doc_Production

View File

@ -0,0 +1,221 @@
/******************************************************************************
* 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. *
* 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 org.compiere.model.*;
import java.util.*;
import java.util.logging.*;
import org.compiere.util.*;
/**
* Project Issue.
* Note:
* Will load the default GL Category.
* Set up a document type to set the GL Category.
*
* @author Jorg Janke
* @version $Id: Doc_ProjectIssue.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_ProjectIssue extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
public Doc_ProjectIssue (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MProjectIssue.class, rs, DOCTYPE_ProjectIssue, trxName);
} // Doc_ProjectIssue
/** Pseudo Line */
private DocLine m_line = null;
/** Issue */
private MProjectIssue m_issue = null;
/**
* Load Document Details
* @return error message or null
*/
protected String loadDocumentDetails()
{
setC_Currency_ID(NO_CURRENCY);
m_issue = (MProjectIssue)getPO();
setDateDoc (m_issue.getMovementDate());
setDateAcct(m_issue.getMovementDate());
// Pseudo Line
m_line = new DocLine (m_issue, this);
m_line.setQty (m_issue.getMovementQty(), true); // sets Trx and Storage Qty
// Pseudo Line Check
if (m_line.getM_Product_ID() == 0)
log.warning(m_line.toString() + " - No Product");
log.fine(m_line.toString());
return null;
} // loadDocumentDetails
/**
* Get DocumentNo
* @return document no
*/
public String getDocumentNo ()
{
MProject p = m_issue.getParent();
if (p != null)
return p.getValue() + " #" + m_issue.getLine();
return "(" + m_issue.get_ID() + ")";
} // getDocumentNo
/**
* Get Balance
* @return Zero (always balanced)
*/
public BigDecimal getBalance()
{
BigDecimal retValue = Env.ZERO;
return retValue;
} // getBalance
/**
* Create Facts (the accounting logic) for
* PJI
* <pre>
* Issue
* ProjectWIP DR
* Inventory CR
* </pre>
* Project Account is either Asset or WIP depending on Project Type
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
// create Fact Header
Fact fact = new Fact(this, as, Fact.POST_Actual);
setC_Currency_ID (as.getC_Currency_ID());
MProject project = new MProject (getCtx(), m_issue.getC_Project_ID(), null);
String ProjectCategory = project.getProjectCategory();
MProduct product = MProduct.get(getCtx(), m_issue.getM_Product_ID());
// Line pointers
FactLine dr = null;
FactLine cr = null;
// Issue Cost
BigDecimal cost = null;
if (m_issue.getM_InOutLine_ID() != 0)
cost = getPOCost(as);
else if (m_issue.getS_TimeExpenseLine_ID() != 0)
cost = getLaborCost(as);
if (cost == null) // standard Product Costs
cost = m_line.getProductCosts(as, getAD_Org_ID(), false);
// Project DR
int acctType = ACCTTYPE_ProjectWIP;
if (MProject.PROJECTCATEGORY_AssetProject.equals(ProjectCategory))
acctType = ACCTTYPE_ProjectAsset;
dr = fact.createLine(m_line,
getAccount(acctType, as), as.getC_Currency_ID(), cost, null);
dr.setQty(m_line.getQty().negate());
// Inventory CR
acctType = ProductCost.ACCTTYPE_P_Asset;
if (product.isService())
acctType = ProductCost.ACCTTYPE_P_Expense;
cr = fact.createLine(m_line,
m_line.getAccount(acctType, as),
as.getC_Currency_ID(), null, cost);
cr.setM_Locator_ID(m_line.getM_Locator_ID());
cr.setLocationFromLocator(m_line.getM_Locator_ID(), true); // from Loc
//
ArrayList<Fact> facts = new ArrayList<Fact>();
facts.add(fact);
return facts;
} // createFact
/**
* Get PO Costs in Currency of AcctSchema
* @param as Account Schema
* @return Unit PO Cost
*/
private BigDecimal getPOCost(MAcctSchema as)
{
BigDecimal retValue = null;
// Uses PO Date
String sql = "SELECT currencyConvert(ol.PriceActual, o.C_Currency_ID, ?, o.DateOrdered, o.C_ConversionType_ID, ?, ?) "
+ "FROM C_OrderLine ol"
+ " INNER JOIN M_InOutLine iol ON (iol.C_OrderLine_ID=ol.C_OrderLine_ID)"
+ " INNER JOIN C_Order o ON (o.C_Order_ID=ol.C_Order_ID) "
+ "WHERE iol.M_InOutLine_ID=?";
PreparedStatement pstmt = null;
try
{
pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(1, as.getC_Currency_ID());
pstmt.setInt(2, getAD_Client_ID());
pstmt.setInt(3, getAD_Org_ID());
pstmt.setInt(4, m_issue.getM_InOutLine_ID());
ResultSet rs = pstmt.executeQuery();
if (rs.next())
{
retValue = rs.getBigDecimal(1);
log.fine("POCost = " + retValue);
}
else
log.warning("Not found for M_InOutLine_ID=" + m_issue.getM_InOutLine_ID());
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 retValue;
} // getPOCost();
/**
* Get Labor Cost from Expense Report
* @param as Account Schema
* @return Unit Labor Cost
*/
private BigDecimal getLaborCost(MAcctSchema as)
{
BigDecimal retValue = null;
/** TODO Labor Cost */
return retValue;
} // getLaborCost
} // DocProjectIssue

View File

@ -0,0 +1,153 @@
/******************************************************************************
* 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. *
* 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 java.util.logging.*;
import java.sql.*;
import org.compiere.model.*;
import org.compiere.util.*;
/**
* Post Order Documents.
*
* <pre>
* Table: M_Requisition
* Document Types: POR (Requisition)
* </pre>
*
* @author Jorg Janke
* @version $Id: Doc_Requisition.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $
*/
public class Doc_Requisition extends Doc
{
/**
* Constructor
* @param ass accounting schemata
* @param rs record
* @param trxName trx
*/
protected Doc_Requisition (MAcctSchema[] ass, ResultSet rs, String trxName)
{
super (ass, MRequisition.class, rs, DOCTYPE_PurchaseRequisition, trxName);
} // Doc_Requisition
/**
* Load Specific Document Details
* @return error message or null
*/
protected String loadDocumentDetails ()
{
setC_Currency_ID(NO_CURRENCY);
MRequisition req = (MRequisition)getPO();
setDateDoc (req.getDateDoc());
setDateAcct (req.getDateDoc());
// Amounts
setAmount(AMTTYPE_Gross, req.getTotalLines());
setAmount(AMTTYPE_Net, req.getTotalLines());
// Contained Objects
p_lines = loadLines (req);
// log.fine( "Lines=" + p_lines.length + ", Taxes=" + m_taxes.length);
return null;
} // loadDocumentDetails
/**
* Load Requisition Lines
* @param req requisition
* @return DocLine Array
*/
private DocLine[] loadLines (MRequisition req)
{
ArrayList<DocLine> list = new ArrayList<DocLine> ();
MRequisitionLine[] lines = req.getLines();
for (int i = 0; i < lines.length; i++)
{
MRequisitionLine line = lines[i];
DocLine docLine = new DocLine (line, this);
BigDecimal Qty = line.getQty();
docLine.setQty (Qty, false);
BigDecimal PriceActual = line.getPriceActual();
BigDecimal LineNetAmt = line.getLineNetAmt();
docLine.setAmount (LineNetAmt); // DR
list.add (docLine);
}
// Return Array
DocLine[] dls = new DocLine[list.size ()];
list.toArray (dls);
return dls;
} // loadLines
/***************************************************************************
* 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);
return retValue;
} // getBalance
/***************************************************************************
* Create Facts (the accounting logic) for POR.
* <pre>
* Reservation
* Expense CR
* Offset DR
* </pre>
* @param as accounting schema
* @return Fact
*/
public ArrayList<Fact> createFacts (MAcctSchema as)
{
ArrayList<Fact> facts = new ArrayList<Fact>();
Fact fact = new Fact (this, as, Fact.POST_Reservation);
setC_Currency_ID(as.getC_Currency_ID());
//
BigDecimal grossAmt = getAmount (Doc.AMTTYPE_Gross);
// Commitment
if (as.isCreateReservation ())
{
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);
//
fact.createLine (line, expense, as.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);
}
return facts;
} // createFact
} // Doc_Requisition

View File

@ -0,0 +1,861 @@
/******************************************************************************
* 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. *
* 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 */
public static final String POST_Actual = MFactAcct.POSTINGTYPE_Actual;
/** Budget Balance Type */
public static final String POST_Budget = MFactAcct.POSTINGTYPE_Budget;;
/** Encumbrance Posting */
public static final String POST_Commitment = MFactAcct.POSTINGTYPE_Commitment;
/** Encumbrance Posting */
public static final String POST_Reservation = MFactAcct.POSTINGTYPE_Reservation;
/** Is Converted */
private boolean m_converted = false;
/** Lines */
private ArrayList<FactLine> m_lines = new ArrayList<FactLine>();
/**
* 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);
// Account
line.setAccount(m_acctSchema, m_acctSchema.getSuspenseBalancing_Acct());
// 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);
// 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)
{
if (segmentType.equals(MAcctSchemaElement.ELEMENTTYPE_Organization))
{
HashMap<Integer,BigDecimal> map = new HashMap<Integer,BigDecimal>();
// 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;
log.fine ("(" + elementType + ") - " + toString());
// Org
if (elementType.equals(MAcctSchemaElement.ELEMENTTYPE_Organization))
{
HashMap<Integer,Balance> map = new HashMap<Integer,Balance>();
// 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<FactLine> newLines = new ArrayList<FactLine>();
// 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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,165 @@
/******************************************************************************
* 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. *
* 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.logging.*;
import org.compiere.util.*;
/**
* Automatic Matching.
* Inv
*
* @author Jorg Janke
* @version $Id: Matcher.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $
*/
public class Matcher
{
/**
* Constructor
* @param AD_Client_ID Client
* @param trxName transaction
*/
public Matcher (int AD_Client_ID, String trxName)
{
m_AD_Client_ID = AD_Client_ID;
m_trxName = trxName;
} // Matcher
/** Client */
private int m_AD_Client_ID;
/** Transaction */
private String m_trxName = null;
/** Logger */
protected CLogger log = CLogger.getCLogger (getClass());
/**
* Matching
* <pre>
* Derive Invoice-Receipt Match from PO-Invoice and PO-Receipt
* Purchase Order (20)
* - Invoice1 (10)
* - Invoice2 (10)
* - Receipt1 (5)
* - Receipt2 (15)
*
* (a) Creates Directs
* - Invoice1 - Receipt1 (5)
* - Invoice2 - Receipt2 (10)
*
* (b) Creates Indirects
* - Invoice1 - Receipt2 (5)
* (Not imlemented)
*
*
* </pre>
* @return number of records created
*/
public int match()
{
int counter = 0;
// (a) Direct Matches
String sql = "SELECT m1.AD_Client_ID,m2.AD_Org_ID, " // 1..2
+ "m1.C_InvoiceLine_ID,m2.M_InOutLine_ID,m1.M_Product_ID, " // 3..5
+ "m1.DateTrx,m2.DateTrx, m1.Qty, m2.Qty " // 6..9
+ "FROM M_MatchPO m1, M_MatchPO m2 "
+ "WHERE m1.C_OrderLine_ID=m2.C_OrderLine_ID"
+ " AND m1.M_InOutLine_ID IS NULL"
+ " AND m2.C_InvoiceLine_ID IS NULL"
+ " AND m1.M_Product_ID=m2.M_Product_ID"
+ " AND m1.AD_Client_ID=?" // #1
// Not existing Inv Matches
+ " AND NOT EXISTS (SELECT * FROM M_MatchInv mi "
+ "WHERE mi.C_InvoiceLine_ID=m1.C_InvoiceLine_ID AND mi.M_InOutLine_ID=m2.M_InOutLine_ID)";
try
{
PreparedStatement pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(1, m_AD_Client_ID);
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
BigDecimal qty1 = rs.getBigDecimal(8);
BigDecimal qty2 = rs.getBigDecimal(9);
BigDecimal Qty = qty1.min(qty2);
if (Qty.equals(Env.ZERO))
continue;
Timestamp dateTrx1 = rs.getTimestamp(6);
Timestamp dateTrx2 = rs.getTimestamp(7);
Timestamp DateTrx = dateTrx1;
if (dateTrx1.before(dateTrx2))
DateTrx = dateTrx2;
//
int AD_Client_ID = rs.getInt(1);
int AD_Org_ID = rs.getInt(2);
int C_InvoiceLine_ID = rs.getInt(3);
int M_InOutLine_ID = rs.getInt(4);
int M_Product_ID = rs.getInt(5);
//
if (createMatchInv(AD_Client_ID, AD_Org_ID,
M_InOutLine_ID, C_InvoiceLine_ID,
M_Product_ID, DateTrx, Qty))
counter++;
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
log.log(Level.SEVERE, "match", e);
}
log.fine("Matcher.match - Client_ID=" + m_AD_Client_ID
+ ", Records created=" + counter);
return counter;
} // match
/**
* Create MatchInv record
* @param AD_Client_ID Client
* @param AD_Org_ID Org
* @param M_InOutLine_ID Receipt
* @param C_InvoiceLine_ID Invoice
* @param M_Product_ID Product
* @param DateTrx Date
* @param Qty Qty
* @return true if record created
*/
private boolean createMatchInv (int AD_Client_ID, int AD_Org_ID,
int M_InOutLine_ID, int C_InvoiceLine_ID,
int M_Product_ID, Timestamp DateTrx, BigDecimal Qty)
{
log.fine("InvLine=" + C_InvoiceLine_ID + ",Rec=" + M_InOutLine_ID + ", Qty=" + Qty + ", " + DateTrx);
// MMatchInv inv = new MMatchInv ();
int M_MatchInv_ID = DB.getNextID (AD_Client_ID, "M_MatchInv", m_trxName);
//
StringBuffer sql = new StringBuffer("INSERT INTO M_MatchInv ("
+ "M_MatchInv_ID, "
+ "AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy, "
+ "M_InOutLine_ID,C_InvoiceLine_ID, "
+ "M_Product_ID,DateTrx,Qty, "
+ "Processing,Processed,Posted) VALUES (")
.append(M_MatchInv_ID).append(", ")
.append(AD_Client_ID).append(",").append(AD_Org_ID).append(",'Y',SysDate,0,SysDate,0, ")
.append(M_InOutLine_ID).append(",").append(C_InvoiceLine_ID).append(", ")
.append(M_Product_ID).append(",").append(DB.TO_DATE(DateTrx,true)).append(",").append(Qty)
.append(", 'N','Y','N')");
int no = DB.executeUpdate(sql.toString(), m_trxName);
return no == 1;
} // createMatchInv
} // Matcher

View File

@ -0,0 +1,390 @@
/******************************************************************************
* 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. *
* 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.logging.*;
import org.compiere.model.*;
import org.compiere.util.*;
/**
* Product Costing Information.
*
* @author Jorg Janke
* @version $Id: ProductInfo.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $
*/
public class ProductInfo
{
/**
* Constructor
* @param M_Product_ID Product
* @param trxName transcation
*/
public ProductInfo (int M_Product_ID, String trxName)
{
m_trxName = trxName;
init (M_Product_ID);
} // ProductInfo
/** The Product Key */
private int m_M_Product_ID = 0;
/** Transaction */
private String m_trxName = null;
// Product Info
private int m_AD_Client_ID = 0;
private int m_AD_Org_ID = 0;
private String m_productType = null;
private String m_ProductCategory = null;
private boolean m_isBOM = false;
private boolean m_isStocked = true;
private int m_C_RevenueRecognition_ID = 0;
private int m_C_UOM_ID = 0;
private BigDecimal m_qty = Env.ZERO;
/** Logger */
protected CLogger log = CLogger.getCLogger (getClass());
/**
* Get Product Info (Service, Revenue Recognition).
* automatically called by constructor
* @param M_Product_ID Product
*/
private void init (int M_Product_ID)
{
m_M_Product_ID = M_Product_ID;
if (m_M_Product_ID == 0)
return;
String sql = "SELECT p.ProductType, pc.Value, " // 1..2
+ "p.C_RevenueRecognition_ID,p.C_UOM_ID, " // 3..4
+ "p.AD_Client_ID,p.AD_Org_ID, " // 5..6
+ "p.IsBOM, p.IsStocked " // 7..8
+ "FROM M_Product_Category pc"
+ " INNER JOIN M_Product p ON (pc.M_Product_Category_ID=p.M_Product_Category_ID) "
+ "WHERE p.M_Product_ID=?"; // #1
try
{
PreparedStatement pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(1, m_M_Product_ID);
ResultSet rs = pstmt.executeQuery();
if (rs.next())
{
m_productType = rs.getString(1);
m_ProductCategory = rs.getString(2);
m_C_RevenueRecognition_ID = rs.getInt(3);
m_C_UOM_ID = rs.getInt(4);
// reference
m_AD_Client_ID = rs.getInt(5);
m_AD_Org_ID = rs.getInt(6);
//
m_isBOM = "Y".equals(rs.getString(7));
m_isStocked = "Y".equals(rs.getString(8));
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
}
} // init
/**
* Is Product/Item
* @return true if product
*/
public boolean isProduct()
{
return MProduct.PRODUCTTYPE_Item.equals(m_productType);
} // isProduct
/**
* Is it a BOM
* @return true if BOM
*/
public boolean isBOM()
{
return m_isBOM;
} // isBOM
/**
* Is it stocked
* @return true if stocked
*/
public boolean isStocked()
{
return m_isStocked;
} // isStocked
/**
* Is Service
* @return true if service
*/
public boolean isService()
{
return MProduct.PRODUCTTYPE_Service.equals(m_productType);
} // isService
/**
* Get Product Category (Value)
* @return M_Product_Category_ID
*/
public String getProductCategory()
{
return m_ProductCategory;
} // getProductCategory
/**
* Has Revenue Recognition
* @return true if product/service has revenue recognition
*/
public boolean isRevenueRecognition()
{
return m_C_RevenueRecognition_ID != 0;
} // isRevenueRecognition
/**
* Get Revenue Recognition
* @return C_RevenueRecognition_ID
*/
public int getC_RevenueRecognition_ID()
{
return m_C_RevenueRecognition_ID;
} // getC_RevenueRecognition_ID
/**
* Quantity UOM
* @return C_UOM_ID
*/
public int getC_UOM_ID()
{
return m_C_UOM_ID;
} // getC_UOM_ID
/*************************************************************************/
/**
* Set Quantity in Storage UOM
* @param qty quantity
*/
public void setQty (BigDecimal qty)
{
m_qty = qty;
} // setQty
/**
* Set Quantity in UOM
* @param qty quantity
* @param C_UOM_ID UOM
*/
public void setQty (BigDecimal qty, int C_UOM_ID)
{
m_qty = MUOMConversion.convert (C_UOM_ID, m_C_UOM_ID, qty, true); // StdPrecision
if (qty != null && m_qty == null) // conversion error
{
log.severe ("Conversion error - set to " + qty);
m_qty = qty;
}
} // setQty
/**
* Get Qty in Storage UOM
* @return qty
*/
public BigDecimal getQty()
{
return m_qty;
} // getQty
/**
* Update/Create initial Cost Record.
* Check first for Purchase Price List,
* then Product Purchase Costs
* and then Price List
* @param as accounting schema
* @param create create record
* @return costs
*/
private BigDecimal updateCosts (MAcctSchema as, boolean create)
{
// Create Zero Record
if (create)
{
StringBuffer sql = new StringBuffer ("INSERT INTO M_Product_Costing "
+ "(M_Product_ID,C_AcctSchema_ID,"
+ " AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,"
+ " CurrentCostPrice,CostStandard,FutureCostPrice,"
+ " CostStandardPOQty,CostStandardPOAmt,CostStandardCumQty,CostStandardCumAmt,"
+ " CostAverage,CostAverageCumQty,CostAverageCumAmt,"
+ " PriceLastPO,PriceLastInv, TotalInvQty,TotalInvAmt) "
+ "VALUES (");
sql.append(m_M_Product_ID).append(",").append(as.getC_AcctSchema_ID()).append(",")
.append(m_AD_Client_ID).append(",").append(m_AD_Org_ID).append(",")
.append("'Y',SysDate,0,SysDate,0, 0,0,0, 0,0,0,0, 0,0,0, 0,0, 0,0)");
int no = DB.executeUpdate(sql.toString(), m_trxName);
if (no == 1)
log.fine("CostingCreated");
}
// Try to find non ZERO Price
String costSource = "PriceList-PO";
BigDecimal costs = getPriceList (as, true);
if (costs == null || costs.equals(Env.ZERO))
{
costSource = "PO Cost";
costs = getPOCost(as);
}
if (costs == null || costs.equals(Env.ZERO))
{
costSource = "PriceList";
costs = getPriceList (as, false);
}
// if not found use $1 (to be able to do material transactions)
if (costs == null || costs.equals(Env.ZERO))
{
costSource = "Not Found";
costs = new BigDecimal("1");
}
// update current costs
StringBuffer sql = new StringBuffer ("UPDATE M_Product_Costing ");
sql.append("SET CurrentCostPrice=").append(costs)
.append(" WHERE M_Product_ID=").append(m_M_Product_ID)
.append(" AND C_AcctSchema_ID=").append(as.getC_AcctSchema_ID());
int no = DB.executeUpdate(sql.toString(), m_trxName);
if (no == 1)
log.fine(costSource + " - " + costs);
return costs;
} // createCosts
/**
* Get PO Price from PriceList - and convert it to AcctSchema Currency
* @param as accounting schema
* @param onlyPOPriceList use only PO price list
* @return po price
*/
private BigDecimal getPriceList (MAcctSchema as, boolean onlyPOPriceList)
{
StringBuffer sql = new StringBuffer (
"SELECT pl.C_Currency_ID, pp.PriceList, pp.PriceStd, pp.PriceLimit "
+ "FROM M_PriceList pl, M_PriceList_Version plv, M_ProductPrice pp "
+ "WHERE pl.M_PriceList_ID = plv.M_PriceList_ID"
+ " AND plv.M_PriceList_Version_ID = pp.M_PriceList_Version_ID"
+ " AND pp.M_Product_ID=?");
if (onlyPOPriceList)
sql.append(" AND pl.IsSOPriceList='N'");
sql.append(" ORDER BY pl.IsSOPriceList ASC, plv.ValidFrom DESC");
int C_Currency_ID = 0;
BigDecimal PriceList = null;
BigDecimal PriceStd = null;
BigDecimal PriceLimit = null;
try
{
PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null);
pstmt.setInt(1, m_M_Product_ID);
ResultSet rs = pstmt.executeQuery();
if (rs.next())
{
C_Currency_ID = rs.getInt(1);
PriceList = rs.getBigDecimal(2);
PriceStd = rs.getBigDecimal(3);
PriceLimit = rs.getBigDecimal(4);
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql.toString(), e);
}
// nothing found
if (C_Currency_ID == 0)
return null;
BigDecimal price = PriceLimit; // best bet
if (price == null || price.equals(Env.ZERO))
price = PriceStd;
if (price == null || price.equals(Env.ZERO))
price = PriceList;
// Convert
if (price != null && !price.equals(Env.ZERO))
price = MConversionRate.convert (as.getCtx(),
price, C_Currency_ID, as.getC_Currency_ID(),
as.getAD_Client_ID(), 0);
return price;
} // getPOPrice
/**
* Get PO Cost from Purchase Info - and convert it to AcctSchema Currency
* @param as accounting schema
* @return po cost
*/
private BigDecimal getPOCost (MAcctSchema as)
{
String sql = "SELECT C_Currency_ID, PriceList,PricePO,PriceLastPO "
+ "FROM M_Product_PO WHERE M_Product_ID=? "
+ "ORDER BY IsCurrentVendor DESC";
int C_Currency_ID = 0;
BigDecimal PriceList = null;
BigDecimal PricePO = null;
BigDecimal PriceLastPO = null;
try
{
PreparedStatement pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(1, m_M_Product_ID);
ResultSet rs = pstmt.executeQuery();
if (rs.next())
{
C_Currency_ID = rs.getInt(1);
PriceList = rs.getBigDecimal(2);
PricePO = rs.getBigDecimal(3);
PriceLastPO = rs.getBigDecimal(4);
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
}
// nothing found
if (C_Currency_ID == 0)
return null;
BigDecimal cost = PriceLastPO; // best bet
if (cost == null || cost.equals(Env.ZERO))
cost = PricePO;
if (cost == null || cost.equals(Env.ZERO))
cost = PriceList;
// Convert - standard precision!! - should be costing precision
if (cost != null && !cost.equals(Env.ZERO))
cost = MConversionRate.convert (as.getCtx(),
cost, C_Currency_ID, as.getC_Currency_ID(), m_AD_Client_ID, m_AD_Org_ID);
return cost;
} // getPOCost
} // ProductInfo

View File

Before

Width:  |  Height:  |  Size: 590 B

After

Width:  |  Height:  |  Size: 590 B

View File

Before

Width:  |  Height:  |  Size: 642 B

After

Width:  |  Height:  |  Size: 642 B

Some files were not shown because too many files have changed in this diff Show More