diff --git a/base/src/org/compiere/model/MInvoice.java b/base/src/org/compiere/model/MInvoice.java index 8174982e07..f0630e6ec4 100644 --- a/base/src/org/compiere/model/MInvoice.java +++ b/base/src/org/compiere/model/MInvoice.java @@ -1,1929 +1,1918 @@ -/****************************************************************************** - * 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.model; - -import java.io.File; -import java.math.BigDecimal; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Properties; -import java.util.logging.Level; - -import org.compiere.print.ReportEngine; -import org.compiere.process.DocAction; -import org.compiere.process.DocumentEngine; -import org.compiere.report.MReportTree; -import org.compiere.util.CCache; -import org.compiere.util.CLogger; -import org.compiere.util.DB; -import org.compiere.util.Env; -import org.compiere.util.Msg; -import org.eevolution.model.MPPProductBOM; -import org.eevolution.model.MPPProductBOMLine; - - -/** - * Invoice Model. - * Please do not set DocStatus and C_DocType_ID directly. - * They are set in the process() method. - * Use DocAction and C_DocTypeTarget_ID instead. - * - * @author Jorg Janke - * @version $Id: MInvoice.java,v 1.2 2006/07/30 00:51:02 jjanke Exp $ - * @author victor.perez@e-evolution.com - * @see http://sourceforge.net/tracker/?func=detail&atid=879335&aid=1948157&group_id=176962 - * Modifications: Added RMA functionality (Ashley Ramdass) - */ -public class MInvoice extends X_C_Invoice implements DocAction -{ - private static final long serialVersionUID = 1L; - - /** - * Get Payments Of BPartner - * @param ctx context - * @param C_BPartner_ID id - * @param trxName transaction - * @return array - */ - public static MInvoice[] getOfBPartner (Properties ctx, int C_BPartner_ID, String trxName) - { - ArrayList list = new ArrayList(); - String sql = "SELECT * FROM C_Invoice WHERE C_BPartner_ID=?"; - PreparedStatement pstmt = null; - try - { - pstmt = DB.prepareStatement(sql, trxName); - pstmt.setInt(1, C_BPartner_ID); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) - list.add(new MInvoice(ctx,rs, trxName)); - 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; - } - - // - MInvoice[] retValue = new MInvoice[list.size()]; - list.toArray(retValue); - return retValue; - } // getOfBPartner - - /** - * Create new Invoice by copying - * @param from invoice - * @param dateDoc date of the document date - * @param C_DocTypeTarget_ID target doc type - * @param isSOTrx sales order - * @param counter create counter links - * @param trxName trx - * @param setOrder set Order links - * @return Invoice - */ - public static MInvoice copyFrom (MInvoice from, Timestamp dateDoc, - int C_DocTypeTarget_ID, boolean isSOTrx, boolean counter, - String trxName, boolean setOrder) - { - MInvoice to = new MInvoice (from.getCtx(), 0, null); - to.set_TrxName(trxName); - PO.copyValues (from, to, from.getAD_Client_ID(), from.getAD_Org_ID()); - to.set_ValueNoCheck ("C_Invoice_ID", I_ZERO); - to.set_ValueNoCheck ("DocumentNo", null); - // - to.setDocStatus (DOCSTATUS_Drafted); // Draft - to.setDocAction(DOCACTION_Complete); - // - to.setC_DocType_ID(0); - to.setC_DocTypeTarget_ID (C_DocTypeTarget_ID); - to.setIsSOTrx(isSOTrx); - // - to.setDateInvoiced (dateDoc); - to.setDateAcct (dateDoc); - to.setDatePrinted(null); - to.setIsPrinted (false); - // - to.setIsApproved (false); - to.setC_Payment_ID(0); - to.setC_CashLine_ID(0); - to.setIsPaid (false); - to.setIsInDispute(false); - // - // Amounts are updated by trigger when adding lines - to.setGrandTotal(Env.ZERO); - to.setTotalLines(Env.ZERO); - // - to.setIsTransferred (false); - to.setPosted (false); - to.setProcessed (false); - //[ 1633721 ] Reverse Documents- Processing=Y - to.setProcessing(false); - // delete references - to.setIsSelfService(false); - if (!setOrder) - to.setC_Order_ID(0); - if (counter) - { - to.setRef_Invoice_ID(from.getC_Invoice_ID()); - // Try to find Order link - if (from.getC_Order_ID() != 0) - { - MOrder peer = new MOrder (from.getCtx(), from.getC_Order_ID(), from.get_TrxName()); - if (peer.getRef_Order_ID() != 0) - to.setC_Order_ID(peer.getRef_Order_ID()); - } - } - else - to.setRef_Invoice_ID(0); - - if (!to.save(trxName)) - throw new IllegalStateException("Could not create Invoice"); - if (counter) - from.setRef_Invoice_ID(to.getC_Invoice_ID()); - - // Lines - if (to.copyLinesFrom(from, counter, setOrder) == 0) - throw new IllegalStateException("Could not create Invoice Lines"); - - return to; - } // copyFrom - - /** - * Get PDF File Name - * @param documentDir directory - * @param C_Invoice_ID invoice - * @return file name - */ - public static String getPDFFileName (String documentDir, int C_Invoice_ID) - { - StringBuffer sb = new StringBuffer (documentDir); - if (sb.length() == 0) - sb.append("."); - if (!sb.toString().endsWith(File.separator)) - sb.append(File.separator); - sb.append("C_Invoice_ID_") - .append(C_Invoice_ID) - .append(".pdf"); - return sb.toString(); - } // getPDFFileName - - - /** - * Get MInvoice from Cache - * @param ctx context - * @param C_Invoice_ID id - * @return MInvoice - */ - public static MInvoice get (Properties ctx, int C_Invoice_ID) - { - Integer key = new Integer (C_Invoice_ID); - MInvoice retValue = (MInvoice) s_cache.get (key); - if (retValue != null) - return retValue; - retValue = new MInvoice (ctx, C_Invoice_ID, null); - if (retValue.get_ID () != 0) - s_cache.put (key, retValue); - return retValue; - } // get - - /** Cache */ - private static CCache s_cache = new CCache("C_Invoice", 20, 2); // 2 minutes - - - /************************************************************************** - * Invoice Constructor - * @param ctx context - * @param C_Invoice_ID invoice or 0 for new - * @param trxName trx name - */ - public MInvoice (Properties ctx, int C_Invoice_ID, String trxName) - { - super (ctx, C_Invoice_ID, trxName); - if (C_Invoice_ID == 0) - { - setDocStatus (DOCSTATUS_Drafted); // Draft - setDocAction (DOCACTION_Complete); - // - setPaymentRule(PAYMENTRULE_OnCredit); // Payment Terms - - setDateInvoiced (new Timestamp (System.currentTimeMillis ())); - setDateAcct (new Timestamp (System.currentTimeMillis ())); - // - setChargeAmt (Env.ZERO); - setTotalLines (Env.ZERO); - setGrandTotal (Env.ZERO); - // - setIsSOTrx (true); - setIsTaxIncluded (false); - setIsApproved (false); - setIsDiscountPrinted (false); - setIsPaid (false); - setSendEMail (false); - setIsPrinted (false); - setIsTransferred (false); - setIsSelfService(false); - setIsPayScheduleValid(false); - setIsInDispute(false); - setPosted(false); - super.setProcessed (false); - setProcessing(false); - } - } // MInvoice - - /** - * Load Constructor - * @param ctx context - * @param rs result set record - * @param trxName transaction - */ - public MInvoice (Properties ctx, ResultSet rs, String trxName) - { - super(ctx, rs, trxName); - } // MInvoice - - /** - * Create Invoice from Order - * @param order order - * @param C_DocTypeTarget_ID target document type - * @param invoiceDate date or null - */ - public MInvoice (MOrder order, int C_DocTypeTarget_ID, Timestamp invoiceDate) - { - this (order.getCtx(), 0, order.get_TrxName()); - setClientOrg(order); - setOrder(order); // set base settings - // - if (C_DocTypeTarget_ID == 0) - C_DocTypeTarget_ID = DB.getSQLValue(null, - "SELECT C_DocTypeInvoice_ID FROM C_DocType WHERE C_DocType_ID=?", - order.getC_DocType_ID()); - setC_DocTypeTarget_ID(C_DocTypeTarget_ID); - if (invoiceDate != null) - setDateInvoiced(invoiceDate); - setDateAcct(getDateInvoiced()); - // - setSalesRep_ID(order.getSalesRep_ID()); - // - setC_BPartner_ID(order.getBill_BPartner_ID()); - setC_BPartner_Location_ID(order.getBill_Location_ID()); - setAD_User_ID(order.getBill_User_ID()); - } // MInvoice - - /** - * Create Invoice from Shipment - * @param ship shipment - * @param invoiceDate date or null - */ - public MInvoice (MInOut ship, Timestamp invoiceDate) - { - this (ship.getCtx(), 0, ship.get_TrxName()); - setClientOrg(ship); - setShipment(ship); // set base settings - // - setC_DocTypeTarget_ID(); - if (invoiceDate != null) - setDateInvoiced(invoiceDate); - setDateAcct(getDateInvoiced()); - // - setSalesRep_ID(ship.getSalesRep_ID()); - setAD_User_ID(ship.getAD_User_ID()); - } // MInvoice - - /** - * Create Invoice from Batch Line - * @param batch batch - * @param line batch line - */ - public MInvoice (MInvoiceBatch batch, MInvoiceBatchLine line) - { - this (line.getCtx(), 0, line.get_TrxName()); - setClientOrg(line); - setDocumentNo(line.getDocumentNo()); - // - setIsSOTrx(batch.isSOTrx()); - MBPartner bp = new MBPartner (line.getCtx(), line.getC_BPartner_ID(), line.get_TrxName()); - setBPartner(bp); // defaults - // - setIsTaxIncluded(line.isTaxIncluded()); - // May conflict with default price list - setC_Currency_ID(batch.getC_Currency_ID()); - setC_ConversionType_ID(batch.getC_ConversionType_ID()); - // - // setPaymentRule(order.getPaymentRule()); - // setC_PaymentTerm_ID(order.getC_PaymentTerm_ID()); - // setPOReference(""); - setDescription(batch.getDescription()); - // setDateOrdered(order.getDateOrdered()); - // - setAD_OrgTrx_ID(line.getAD_OrgTrx_ID()); - setC_Project_ID(line.getC_Project_ID()); - // setC_Campaign_ID(line.getC_Campaign_ID()); - setC_Activity_ID(line.getC_Activity_ID()); - setUser1_ID(line.getUser1_ID()); - setUser2_ID(line.getUser2_ID()); - // - setC_DocTypeTarget_ID(line.getC_DocType_ID()); - setDateInvoiced(line.getDateInvoiced()); - setDateAcct(line.getDateAcct()); - // - setSalesRep_ID(batch.getSalesRep_ID()); - // - setC_BPartner_ID(line.getC_BPartner_ID()); - setC_BPartner_Location_ID(line.getC_BPartner_Location_ID()); - setAD_User_ID(line.getAD_User_ID()); - } // MInvoice - - /** Open Amount */ - private BigDecimal m_openAmt = null; - - /** Invoice Lines */ - private MInvoiceLine[] m_lines; - /** Invoice Taxes */ - private MInvoiceTax[] m_taxes; - /** Logger */ - private static CLogger s_log = CLogger.getCLogger(MInvoice.class); - - /** - * Overwrite Client/Org if required - * @param AD_Client_ID client - * @param AD_Org_ID org - */ - public void setClientOrg (int AD_Client_ID, int AD_Org_ID) - { - super.setClientOrg(AD_Client_ID, AD_Org_ID); - } // setClientOrg - - /** - * Set Business Partner Defaults & Details - * @param bp business partner - */ - public void setBPartner (MBPartner bp) - { - if (bp == null) - return; - - setC_BPartner_ID(bp.getC_BPartner_ID()); - // Set Defaults - int ii = 0; - if (isSOTrx()) - ii = bp.getC_PaymentTerm_ID(); - else - ii = bp.getPO_PaymentTerm_ID(); - if (ii != 0) - setC_PaymentTerm_ID(ii); - // - if (isSOTrx()) - ii = bp.getM_PriceList_ID(); - else - ii = bp.getPO_PriceList_ID(); - if (ii != 0) - setM_PriceList_ID(ii); - // - String ss = bp.getPaymentRule(); - if (ss != null) - setPaymentRule(ss); - - - // Set Locations - MBPartnerLocation[] locs = bp.getLocations(false); - if (locs != null) - { - for (int i = 0; i < locs.length; i++) - { - if ((locs[i].isBillTo() && isSOTrx()) - || (locs[i].isPayFrom() && !isSOTrx())) - setC_BPartner_Location_ID(locs[i].getC_BPartner_Location_ID()); - } - // set to first - if (getC_BPartner_Location_ID() == 0 && locs.length > 0) - setC_BPartner_Location_ID(locs[0].getC_BPartner_Location_ID()); - } - if (getC_BPartner_Location_ID() == 0) - log.log(Level.SEVERE, "Has no To Address: " + bp); - - // Set Contact - MUser[] contacts = bp.getContacts(false); - if (contacts != null && contacts.length > 0) // get first User - setAD_User_ID(contacts[0].getAD_User_ID()); - } // setBPartner - - /** - * Set Order References - * @param order order - */ - public void setOrder (MOrder order) - { - if (order == null) - return; - - setC_Order_ID(order.getC_Order_ID()); - setIsSOTrx(order.isSOTrx()); - setIsDiscountPrinted(order.isDiscountPrinted()); - setIsSelfService(order.isSelfService()); - setSendEMail(order.isSendEMail()); - // - setM_PriceList_ID(order.getM_PriceList_ID()); - setIsTaxIncluded(order.isTaxIncluded()); - setC_Currency_ID(order.getC_Currency_ID()); - setC_ConversionType_ID(order.getC_ConversionType_ID()); - // - setPaymentRule(order.getPaymentRule()); - setC_PaymentTerm_ID(order.getC_PaymentTerm_ID()); - setPOReference(order.getPOReference()); - setDescription(order.getDescription()); - setDateOrdered(order.getDateOrdered()); - // - setAD_OrgTrx_ID(order.getAD_OrgTrx_ID()); - setC_Project_ID(order.getC_Project_ID()); - setC_Campaign_ID(order.getC_Campaign_ID()); - setC_Activity_ID(order.getC_Activity_ID()); - setUser1_ID(order.getUser1_ID()); - setUser2_ID(order.getUser2_ID()); - } // setOrder - - /** - * Set Shipment References - * @param ship shipment - */ - public void setShipment (MInOut ship) - { - if (ship == null) - return; - - setIsSOTrx(ship.isSOTrx()); - // - MBPartner bp = new MBPartner (getCtx(), ship.getC_BPartner_ID(), null); - setBPartner (bp); - // - setSendEMail(ship.isSendEMail()); - // - setPOReference(ship.getPOReference()); - setDescription(ship.getDescription()); - setDateOrdered(ship.getDateOrdered()); - // - setAD_OrgTrx_ID(ship.getAD_OrgTrx_ID()); - setC_Project_ID(ship.getC_Project_ID()); - setC_Campaign_ID(ship.getC_Campaign_ID()); - setC_Activity_ID(ship.getC_Activity_ID()); - setUser1_ID(ship.getUser1_ID()); - setUser2_ID(ship.getUser2_ID()); - // - if (ship.getC_Order_ID() != 0) - { - setC_Order_ID(ship.getC_Order_ID()); - MOrder order = new MOrder (getCtx(), ship.getC_Order_ID(), get_TrxName()); - setIsDiscountPrinted(order.isDiscountPrinted()); - setM_PriceList_ID(order.getM_PriceList_ID()); - setIsTaxIncluded(order.isTaxIncluded()); - setC_Currency_ID(order.getC_Currency_ID()); - setC_ConversionType_ID(order.getC_ConversionType_ID()); - setPaymentRule(order.getPaymentRule()); - setC_PaymentTerm_ID(order.getC_PaymentTerm_ID()); - // - MDocType dt = MDocType.get(getCtx(), order.getC_DocType_ID()); - if (dt.getC_DocTypeInvoice_ID() != 0) - setC_DocTypeTarget_ID(dt.getC_DocTypeInvoice_ID()); - // Overwrite Invoice Address - setC_BPartner_Location_ID(order.getBill_Location_ID()); - } - // Check if Shipment/Receipt is based on RMA - if (ship.getM_RMA_ID() != 0) - { - MRMA rma = new MRMA(getCtx(), ship.getM_RMA_ID(), get_TrxName()); - MOrder rmaOrder = rma.getOriginalOrder(); - setM_RMA_ID(ship.getM_RMA_ID()); - setIsSOTrx(rma.isSOTrx()); - setM_PriceList_ID(rmaOrder.getM_PriceList_ID()); - setIsTaxIncluded(rmaOrder.isTaxIncluded()); - setC_Currency_ID(rmaOrder.getC_Currency_ID()); - setC_ConversionType_ID(rmaOrder.getC_ConversionType_ID()); - setPaymentRule(rmaOrder.getPaymentRule()); - setC_PaymentTerm_ID(rmaOrder.getC_PaymentTerm_ID()); - - // Retrieves the invoice DocType - MDocType dt = MDocType.get(getCtx(), rma.getC_DocType_ID()); - if (dt.getC_DocTypeInvoice_ID() != 0) - { - setC_DocTypeTarget_ID(dt.getC_DocTypeInvoice_ID()); - } - setC_BPartner_Location_ID(rmaOrder.getBill_Location_ID()); - } - - } // setShipment - - /** - * Set Target Document Type - * @param DocBaseType doc type MDocType.DOCBASETYPE_ - */ - public void setC_DocTypeTarget_ID (String DocBaseType) - { - String sql = "SELECT C_DocType_ID FROM C_DocType " - + "WHERE AD_Client_ID=? AND DocBaseType=?" - + " AND IsActive='Y' " - + "ORDER BY IsDefault DESC"; - int C_DocType_ID = DB.getSQLValue(null, sql, getAD_Client_ID(), DocBaseType); - if (C_DocType_ID <= 0) - log.log(Level.SEVERE, "Not found for AC_Client_ID=" - + getAD_Client_ID() + " - " + DocBaseType); - else - { - log.fine(DocBaseType); - setC_DocTypeTarget_ID (C_DocType_ID); - boolean isSOTrx = MDocType.DOCBASETYPE_ARInvoice.equals(DocBaseType) - || MDocType.DOCBASETYPE_ARCreditMemo.equals(DocBaseType); - setIsSOTrx (isSOTrx); - } - } // setC_DocTypeTarget_ID - - /** - * Set Target Document Type. - * Based on SO flag AP/AP Invoice - */ - public void setC_DocTypeTarget_ID () - { - if (getC_DocTypeTarget_ID() > 0) - return; - if (isSOTrx()) - setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_ARInvoice); - else - setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_APInvoice); - } // setC_DocTypeTarget_ID - - - /** - * Get Grand Total - * @param creditMemoAdjusted adjusted for CM (negative) - * @return grand total - */ - public BigDecimal getGrandTotal (boolean creditMemoAdjusted) - { - if (!creditMemoAdjusted) - return super.getGrandTotal(); - // - BigDecimal amt = getGrandTotal(); - if (isCreditMemo()) - return amt.negate(); - return amt; - } // getGrandTotal - - - /** - * Get Invoice Lines of Invoice - * @param whereClause starting with AND - * @return lines - */ - private MInvoiceLine[] getLines (String whereClause) - { - ArrayList list = new ArrayList(); - String sql = "SELECT * FROM C_InvoiceLine WHERE C_Invoice_ID=? "; - if (whereClause != null) - sql += whereClause; - sql += " ORDER BY Line"; - PreparedStatement pstmt = null; - try - { - pstmt = DB.prepareStatement(sql, get_TrxName()); - pstmt.setInt(1, getC_Invoice_ID()); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) - { - MInvoiceLine il = new MInvoiceLine(getCtx(), rs, get_TrxName()); - il.setInvoice(this); - list.add(il); - } - rs.close(); - pstmt.close(); - pstmt = null; - } - catch (Exception e) - { - log.log(Level.SEVERE, "getLines", e); - } - finally - { - try - { - if (pstmt != null) - pstmt.close (); - } - catch (Exception e) - {} - pstmt = null; - } - - // - MInvoiceLine[] lines = new MInvoiceLine[list.size()]; - list.toArray(lines); - return lines; - } // getLines - - /** - * Get Invoice Lines - * @param requery - * @return lines - */ - public MInvoiceLine[] getLines (boolean requery) - { - if (m_lines == null || m_lines.length == 0 || requery) - m_lines = getLines(null); - set_TrxName(m_lines, get_TrxName()); - return m_lines; - } // getLines - - /** - * Get Lines of Invoice - * @return lines - */ - public MInvoiceLine[] getLines() - { - return getLines(false); - } // getLines - - - /** - * Renumber Lines - * @param step start and step - */ - public void renumberLines (int step) - { - int number = step; - MInvoiceLine[] lines = getLines(false); - for (int i = 0; i < lines.length; i++) - { - MInvoiceLine line = lines[i]; - line.setLine(number); - line.save(); - number += step; - } - m_lines = null; - } // renumberLines - - /** - * Copy Lines From other Invoice. - * @param otherInvoice invoice - * @param counter create counter links - * @param setOrder set order links - * @return number of lines copied - */ - public int copyLinesFrom (MInvoice otherInvoice, boolean counter, boolean setOrder) - { - if (isProcessed() || isPosted() || otherInvoice == null) - return 0; - MInvoiceLine[] fromLines = otherInvoice.getLines(false); - int count = 0; - for (int i = 0; i < fromLines.length; i++) - { - MInvoiceLine line = new MInvoiceLine (getCtx(), 0, get_TrxName()); - MInvoiceLine fromLine = fromLines[i]; - if (counter) // header - PO.copyValues (fromLine, line, getAD_Client_ID(), getAD_Org_ID()); - else - PO.copyValues (fromLine, line, fromLine.getAD_Client_ID(), fromLine.getAD_Org_ID()); - line.setC_Invoice_ID(getC_Invoice_ID()); - line.setInvoice(this); - line.set_ValueNoCheck ("C_InvoiceLine_ID", I_ZERO); // new - // Reset - if (!setOrder) - line.setC_OrderLine_ID(0); - line.setRef_InvoiceLine_ID(0); - line.setM_InOutLine_ID(0); - line.setA_Asset_ID(0); - line.setM_AttributeSetInstance_ID(0); - line.setS_ResourceAssignment_ID(0); - // New Tax - if (getC_BPartner_ID() != otherInvoice.getC_BPartner_ID()) - line.setTax(); // recalculate - // - if (counter) - { - line.setRef_InvoiceLine_ID(fromLine.getC_InvoiceLine_ID()); - if (fromLine.getC_OrderLine_ID() != 0) - { - MOrderLine peer = new MOrderLine (getCtx(), fromLine.getC_OrderLine_ID(), get_TrxName()); - if (peer.getRef_OrderLine_ID() != 0) - line.setC_OrderLine_ID(peer.getRef_OrderLine_ID()); - } - line.setM_InOutLine_ID(0); - if (fromLine.getM_InOutLine_ID() != 0) - { - MInOutLine peer = new MInOutLine (getCtx(), fromLine.getM_InOutLine_ID(), get_TrxName()); - if (peer.getRef_InOutLine_ID() != 0) - line.setM_InOutLine_ID(peer.getRef_InOutLine_ID()); - } - } - // - line.setProcessed(false); - if (line.save(get_TrxName())) - count++; - // Cross Link - if (counter) - { - fromLine.setRef_InvoiceLine_ID(line.getC_InvoiceLine_ID()); - fromLine.save(get_TrxName()); - } - - // MZ Goodwill - // copy the landed cost - line.copyLandedCostFrom(fromLine); - line.allocateLandedCosts(); - // end MZ - } - if (fromLines.length != count) - log.log(Level.SEVERE, "Line difference - From=" + fromLines.length + " <> Saved=" + count); - return count; - } // copyLinesFrom - - /** Reversal Flag */ - private boolean m_reversal = false; - - /** - * Set Reversal - * @param reversal reversal - */ - private void setReversal(boolean reversal) - { - m_reversal = reversal; - } // setReversal - /** - * Is Reversal - * @return reversal - */ - public boolean isReversal() - { - return m_reversal; - } // isReversal - - /** - * Get Taxes - * @param requery requery - * @return array of taxes - */ - public MInvoiceTax[] getTaxes (boolean requery) - { - if (m_taxes != null && !requery) - return m_taxes; - String sql = "SELECT * FROM C_InvoiceTax WHERE C_Invoice_ID=?"; - ArrayList list = new ArrayList(); - PreparedStatement pstmt = null; - try - { - pstmt = DB.prepareStatement (sql, get_TrxName()); - pstmt.setInt (1, getC_Invoice_ID()); - ResultSet rs = pstmt.executeQuery (); - while (rs.next ()) - list.add(new MInvoiceTax(getCtx(), rs, get_TrxName())); - rs.close (); - pstmt.close (); - pstmt = null; - } - catch (Exception e) - { - log.log(Level.SEVERE, "getTaxes", e); - } - try - { - if (pstmt != null) - pstmt.close (); - pstmt = null; - } - catch (Exception e) - { - pstmt = null; - } - - m_taxes = new MInvoiceTax[list.size ()]; - list.toArray (m_taxes); - return m_taxes; - } // getTaxes - - /** - * Add to Description - * @param description text - */ - public void addDescription (String description) - { - String desc = getDescription(); - if (desc == null) - setDescription(description); - else - setDescription(desc + " | " + description); - } // addDescription - - /** - * Is it a Credit Memo? - * @return true if CM - */ - public boolean isCreditMemo() - { - MDocType dt = MDocType.get(getCtx(), - getC_DocType_ID()==0 ? getC_DocTypeTarget_ID() : getC_DocType_ID()); - return MDocType.DOCBASETYPE_APCreditMemo.equals(dt.getDocBaseType()) - || MDocType.DOCBASETYPE_ARCreditMemo.equals(dt.getDocBaseType()); - } // isCreditMemo - - /** - * Set Processed. - * Propergate to Lines/Taxes - * @param processed processed - */ - public void setProcessed (boolean processed) - { - super.setProcessed (processed); - if (get_ID() == 0) - return; - String set = "SET Processed='" - + (processed ? "Y" : "N") - + "' WHERE C_Invoice_ID=" + getC_Invoice_ID(); - int noLine = DB.executeUpdate("UPDATE C_InvoiceLine " + set, get_TrxName()); - int noTax = DB.executeUpdate("UPDATE C_InvoiceTax " + set, get_TrxName()); - m_lines = null; - m_taxes = null; - log.fine(processed + " - Lines=" + noLine + ", Tax=" + noTax); - } // setProcessed - - /** - * Validate Invoice Pay Schedule - * @return pay schedule is valid - */ - public boolean validatePaySchedule() - { - MInvoicePaySchedule[] schedule = MInvoicePaySchedule.getInvoicePaySchedule - (getCtx(), getC_Invoice_ID(), 0, get_TrxName()); - log.fine("#" + schedule.length); - if (schedule.length == 0) - { - setIsPayScheduleValid(false); - return false; - } - // Add up due amounts - BigDecimal total = Env.ZERO; - for (int i = 0; i < schedule.length; i++) - { - schedule[i].setParent(this); - BigDecimal due = schedule[i].getDueAmt(); - if (due != null) - total = total.add(due); - } - boolean valid = getGrandTotal().compareTo(total) == 0; - setIsPayScheduleValid(valid); - - // Update Schedule Lines - for (int i = 0; i < schedule.length; i++) - { - if (schedule[i].isValid() != valid) - { - schedule[i].setIsValid(valid); - schedule[i].save(get_TrxName()); - } - } - return valid; - } // validatePaySchedule - - - /************************************************************************** - * Before Save - * @param newRecord new - * @return true - */ - protected boolean beforeSave (boolean newRecord) - { - log.fine(""); - // No Partner Info - set Template - if (getC_BPartner_ID() == 0) - setBPartner(MBPartner.getTemplate(getCtx(), getAD_Client_ID())); - if (getC_BPartner_Location_ID() == 0) - setBPartner(new MBPartner(getCtx(), getC_BPartner_ID(), null)); - - // Price List - if (getM_PriceList_ID() == 0) - { - int ii = Env.getContextAsInt(getCtx(), "#M_PriceList_ID"); - if (ii != 0) - setM_PriceList_ID(ii); - else - { - String sql = "SELECT M_PriceList_ID FROM M_PriceList WHERE AD_Client_ID=? AND IsDefault='Y'"; - ii = DB.getSQLValue (null, sql, getAD_Client_ID()); - if (ii != 0) - setM_PriceList_ID (ii); - } - } - - // Currency - if (getC_Currency_ID() == 0) - { - String sql = "SELECT C_Currency_ID FROM M_PriceList WHERE M_PriceList_ID=?"; - int ii = DB.getSQLValue (null, sql, getM_PriceList_ID()); - if (ii != 0) - setC_Currency_ID (ii); - else - setC_Currency_ID(Env.getContextAsInt(getCtx(), "#C_Currency_ID")); - } - - // Sales Rep - if (getSalesRep_ID() == 0) - { - int ii = Env.getContextAsInt(getCtx(), "#SalesRep_ID"); - if (ii != 0) - setSalesRep_ID (ii); - } - - // Document Type - if (getC_DocType_ID() == 0) - setC_DocType_ID (0); // make sure it's set to 0 - if (getC_DocTypeTarget_ID() == 0) - setC_DocTypeTarget_ID(isSOTrx() ? MDocType.DOCBASETYPE_ARInvoice : MDocType.DOCBASETYPE_APInvoice); - - // Payment Term - if (getC_PaymentTerm_ID() == 0) - { - int ii = Env.getContextAsInt(getCtx(), "#C_PaymentTerm_ID"); - if (ii != 0) - setC_PaymentTerm_ID (ii); - else - { - String sql = "SELECT C_PaymentTerm_ID FROM C_PaymentTerm WHERE AD_Client_ID=? AND IsDefault='Y'"; - ii = DB.getSQLValue(null, sql, getAD_Client_ID()); - if (ii != 0) - setC_PaymentTerm_ID (ii); - } - } - return true; - } // beforeSave - - /** - * Before Delete - * @return true if it can be deleted - */ - protected boolean beforeDelete () - { - if (getC_Order_ID() != 0) - { - log.saveError("Error", Msg.getMsg(getCtx(), "CannotDelete")); - return false; - } - return true; - } // beforeDelete - - /** - * String Representation - * @return info - */ - public String toString () - { - StringBuffer sb = new StringBuffer ("MInvoice[") - .append(get_ID()).append("-").append(getDocumentNo()) - .append(",GrandTotal=").append(getGrandTotal()); - if (m_lines != null) - sb.append(" (#").append(m_lines.length).append(")"); - sb.append ("]"); - return sb.toString (); - } // toString - - /** - * Get Document Info - * @return document info (untranslated) - */ - public String getDocumentInfo() - { - MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); - return dt.getName() + " " + getDocumentNo(); - } // getDocumentInfo - - - /** - * After Save - * @param newRecord new - * @param success success - * @return success - */ - protected boolean afterSave (boolean newRecord, boolean success) - { - if (!success || newRecord) - return success; - - if (is_ValueChanged("AD_Org_ID")) - { - String sql = "UPDATE C_InvoiceLine ol" - + " SET AD_Org_ID =" - + "(SELECT AD_Org_ID" - + " FROM C_Invoice o WHERE ol.C_Invoice_ID=o.C_Invoice_ID) " - + "WHERE C_Invoice_ID=" + getC_Invoice_ID(); - int no = DB.executeUpdate(sql, get_TrxName()); - log.fine("Lines -> #" + no); - } - return true; - } // afterSave - - - /** - * Set Price List (and Currency) when valid - * @param M_PriceList_ID price list - */ - public void setM_PriceList_ID (int M_PriceList_ID) - { - String sql = "SELECT M_PriceList_ID, C_Currency_ID " - + "FROM M_PriceList WHERE M_PriceList_ID=?"; - PreparedStatement pstmt = null; - try - { - pstmt = DB.prepareStatement(sql, null); - pstmt.setInt(1, M_PriceList_ID); - ResultSet rs = pstmt.executeQuery(); - if (rs.next()) - { - super.setM_PriceList_ID (rs.getInt(1)); - setC_Currency_ID (rs.getInt(2)); - } - rs.close(); - pstmt.close(); - pstmt = null; - } - catch (Exception e) - { - log.log(Level.SEVERE, "setM_PriceList_ID", e); - } - finally - { - try - { - if (pstmt != null) - pstmt.close (); - } - catch (Exception e) - {} - pstmt = null; - } - } // setM_PriceList_ID - - - /** - * Get Allocated Amt in Invoice Currency - * @return pos/neg amount or null - */ - public BigDecimal getAllocatedAmt () - { - BigDecimal retValue = null; - String sql = "SELECT SUM(currencyConvert(al.Amount+al.DiscountAmt+al.WriteOffAmt," - + "ah.C_Currency_ID, i.C_Currency_ID,ah.DateTrx,COALESCE(i.C_ConversionType_ID,0), al.AD_Client_ID,al.AD_Org_ID)) " - + "FROM C_AllocationLine al" - + " INNER JOIN C_AllocationHdr ah ON (al.C_AllocationHdr_ID=ah.C_AllocationHdr_ID)" - + " INNER JOIN C_Invoice i ON (al.C_Invoice_ID=i.C_Invoice_ID) " - + "WHERE al.C_Invoice_ID=?" - + " AND ah.IsActive='Y' AND al.IsActive='Y'"; - PreparedStatement pstmt = null; - ResultSet rs = null; - try - { - pstmt = DB.prepareStatement(sql, get_TrxName()); - pstmt.setInt(1, getC_Invoice_ID()); - rs = pstmt.executeQuery(); - if (rs.next()) - retValue = rs.getBigDecimal(1); - rs.close(); - pstmt.close(); - pstmt = null; - } - catch (Exception e) - { - log.log(Level.SEVERE, sql, e); - } - finally - { - DB.close(rs, pstmt); - rs = null; pstmt = null; - } - // log.fine("getAllocatedAmt - " + retValue); - // ? ROUND(NVL(v_AllocatedAmt,0), 2); - return retValue; - } // getAllocatedAmt - - /** - * Test Allocation (and set paid flag) - * @return true if updated - */ - public boolean testAllocation() - { - boolean change = false; - - if ( isProcessed() ) { - BigDecimal alloc = getAllocatedAmt(); // absolute - if (alloc == null) - alloc = Env.ZERO; - BigDecimal total = getGrandTotal(); - if (!isSOTrx()) - total = total.negate(); - if (isCreditMemo()) - total = total.negate(); - boolean test = total.compareTo(alloc) == 0; - change = test != isPaid(); - if (change) - setIsPaid(test); - log.fine("Paid=" + test - + " (" + alloc + "=" + total + ")"); - } - - return change; - } // testAllocation - - /** - * Set Paid Flag for invoices - * @param ctx context - * @param C_BPartner_ID if 0 all - * @param trxName transaction - */ - public static void setIsPaid (Properties ctx, int C_BPartner_ID, String trxName) - { - int counter = 0; - String sql = "SELECT * FROM C_Invoice " - + "WHERE IsPaid='N' AND DocStatus IN ('CO','CL')"; - if (C_BPartner_ID > 1) - sql += " AND C_BPartner_ID=?"; - else - sql += " AND AD_Client_ID=" + Env.getAD_Client_ID(ctx); - PreparedStatement pstmt = null; - try - { - pstmt = DB.prepareStatement (sql, trxName); - if (C_BPartner_ID > 1) - pstmt.setInt (1, C_BPartner_ID); - ResultSet rs = pstmt.executeQuery (); - while (rs.next ()) - { - MInvoice invoice = new MInvoice(ctx, rs, trxName); - if (invoice.testAllocation()) - if (invoice.save()) - counter++; - } - 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; - } - s_log.config("#" + counter); - /**/ - } // setIsPaid - - /** - * Get Open Amount. - * Used by web interface - * @return Open Amt - */ - public BigDecimal getOpenAmt () - { - return getOpenAmt (true, null); - } // getOpenAmt - - /** - * Get Open Amount - * @param creditMemoAdjusted adjusted for CM (negative) - * @param paymentDate ignored Payment Date - * @return Open Amt - */ - public BigDecimal getOpenAmt (boolean creditMemoAdjusted, Timestamp paymentDate) - { - if (isPaid()) - return Env.ZERO; - // - if (m_openAmt == null) - { - m_openAmt = getGrandTotal(); - if (paymentDate != null) - { - // Payment Discount - // Payment Schedule - } - BigDecimal allocated = getAllocatedAmt(); - if (allocated != null) - { - allocated = allocated.abs(); // is absolute - m_openAmt = m_openAmt.subtract(allocated); - } - } - // - if (!creditMemoAdjusted) - return m_openAmt; - if (isCreditMemo()) - return m_openAmt.negate(); - return m_openAmt; - } // getOpenAmt - - - /** - * Get Document Status - * @return Document Status Clear Text - */ - public String getDocStatusName() - { - return MRefList.getListName(getCtx(), 131, getDocStatus()); - } // getDocStatusName - - - /************************************************************************** - * Create PDF - * @return File or null - */ - public File createPDF () - { - try - { - File temp = File.createTempFile(get_TableName()+get_ID()+"_", ".pdf"); - return createPDF (temp); - } - catch (Exception e) - { - log.severe("Could not create PDF - " + e.getMessage()); - } - return null; - } // getPDF - - /** - * Create PDF file - * @param file output file - * @return file if success - */ - public File createPDF (File file) - { - ReportEngine re = ReportEngine.get (getCtx(), ReportEngine.INVOICE, getC_Invoice_ID(), get_TrxName()); - if (re == null) - return null; - return re.getPDF(file); - } // createPDF - - /** - * Get PDF File Name - * @param documentDir directory - * @return file name - */ - public String getPDFFileName (String documentDir) - { - return getPDFFileName (documentDir, getC_Invoice_ID()); - } // getPDFFileName - - /** - * Get ISO Code of Currency - * @return Currency ISO - */ - public String getCurrencyISO() - { - return MCurrency.getISO_Code (getCtx(), getC_Currency_ID()); - } // getCurrencyISO - - /** - * Get Currency Precision - * @return precision - */ - public int getPrecision() - { - return MCurrency.getStdPrecision(getCtx(), getC_Currency_ID()); - } // getPrecision - - - /************************************************************************** - * Process document - * @param processAction document action - * @return true if performed - */ - public boolean processIt (String processAction) - { - m_processMsg = null; - DocumentEngine engine = new DocumentEngine (this, getDocStatus()); - return engine.processIt (processAction, getDocAction()); - } // process - - /** Process Message */ - private String m_processMsg = null; - /** Just Prepared Flag */ - private boolean m_justPrepared = false; - - /** - * Unlock Document. - * @return true if success - */ - public boolean unlockIt() - { - log.info("unlockIt - " + toString()); - setProcessing(false); - return true; - } // unlockIt - - /** - * Invalidate Document - * @return true if success - */ - public boolean invalidateIt() - { - log.info("invalidateIt - " + toString()); - setDocAction(DOCACTION_Prepare); - return true; - } // invalidateIt - - /** - * Prepare Document - * @return new status (In Progress or Invalid) - */ - public String prepareIt() - { - log.info(toString()); - m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE); - if (m_processMsg != null) - return DocAction.STATUS_Invalid; - MDocType dt = MDocType.get(getCtx(), getC_DocTypeTarget_ID()); - - // Std Period open? - if (!MPeriod.isOpen(getCtx(), getDateAcct(), dt.getDocBaseType())) - { - m_processMsg = "@PeriodClosed@"; - return DocAction.STATUS_Invalid; - } - // Lines - MInvoiceLine[] lines = getLines(true); - if (lines.length == 0) - { - m_processMsg = "@NoLines@"; - return DocAction.STATUS_Invalid; - } - // No Cash Book - if (PAYMENTRULE_Cash.equals(getPaymentRule()) - && MCashBook.get(getCtx(), getAD_Org_ID(), getC_Currency_ID()) == null) - { - m_processMsg = "@NoCashBook@"; - return DocAction.STATUS_Invalid; - } - - // Convert/Check DocType - if (getC_DocType_ID() != getC_DocTypeTarget_ID() ) - setC_DocType_ID(getC_DocTypeTarget_ID()); - if (getC_DocType_ID() == 0) - { - m_processMsg = "No Document Type"; - return DocAction.STATUS_Invalid; - } - - explodeBOM(); - if (!calculateTaxTotal()) // setTotals - { - m_processMsg = "Error calculating Tax"; - return DocAction.STATUS_Invalid; - } - - createPaySchedule(); - - // Credit Status - if (isSOTrx() && !isReversal()) - { - MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), null); - if (MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus())) - { - m_processMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@=" - + bp.getTotalOpenBalance() - + ", @SO_CreditLimit@=" + bp.getSO_CreditLimit(); - return DocAction.STATUS_Invalid; - } - } - - // Landed Costs - if (!isSOTrx()) - { - for (int i = 0; i < lines.length; i++) - { - MInvoiceLine line = lines[i]; - String error = line.allocateLandedCosts(); - if (error != null && error.length() > 0) - { - m_processMsg = error; - return DocAction.STATUS_Invalid; - } - } - } - - m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE); - if (m_processMsg != null) - return DocAction.STATUS_Invalid; - - // Add up Amounts - m_justPrepared = true; - if (!DOCACTION_Complete.equals(getDocAction())) - setDocAction(DOCACTION_Complete); - return DocAction.STATUS_InProgress; - } // prepareIt - - /** - * Explode non stocked BOM. - */ - private void explodeBOM () - { - String where = "AND IsActive='Y' AND EXISTS " - + "(SELECT * FROM M_Product p WHERE C_InvoiceLine.M_Product_ID=p.M_Product_ID" - + " AND p.IsBOM='Y' AND p.IsVerified='Y' AND p.IsStocked='N')"; - // - String sql = "SELECT COUNT(*) FROM C_InvoiceLine " - + "WHERE C_Invoice_ID=? " + where; - int count = DB.getSQLValue(get_TrxName(), sql, getC_Invoice_ID()); - while (count != 0) - { - renumberLines (100); - - // Order Lines with non-stocked BOMs - MInvoiceLine[] lines = getLines (where); - for (int i = 0; i < lines.length; i++) - { - MInvoiceLine line = lines[i]; - MProduct product = MProduct.get (getCtx(), line.getM_Product_ID()); - log.fine(product.getName()); - // New Lines - int lineNo = line.getLine (); - - //find default BOM with valid dates and to this product - MPPProductBOM bom = MPPProductBOM.get(product, getAD_Org_ID(),getDateInvoiced(), get_TrxName()); - if(bom != null) - { - MPPProductBOMLine[] bomlines = bom.getLines(getDateInvoiced()); - for (int j = 0; j < bomlines.length; j++) - { - MPPProductBOMLine bomline = bomlines[j]; - MInvoiceLine newLine = new MInvoiceLine (this); - newLine.setLine (++lineNo); - newLine.setM_Product_ID (bomline.getM_Product_ID ()); - newLine.setC_UOM_ID (bomline.getC_UOM_ID ()); - newLine.setQty (line.getQtyInvoiced().multiply( - bomline.getQtyBOM ())); // Invoiced/Entered - if (bomline.getDescription () != null) - newLine.setDescription (bomline.getDescription ()); - // - newLine.setPrice (); - newLine.save (get_TrxName()); - } - } - - /*MProductBOM[] boms = MProductBOM.getBOMLines (product); - for (int j = 0; j < boms.length; j++) - { - MProductBOM bom = boms[j]; - MInvoiceLine newLine = new MInvoiceLine (this); - newLine.setLine (++lineNo); - newLine.setM_Product_ID (bom.getProduct().getM_Product_ID(), - bom.getProduct().getC_UOM_ID()); - newLine.setQty (line.getQtyInvoiced().multiply( - bom.getBOMQty ())); // Invoiced/Entered - if (bom.getDescription () != null) - newLine.setDescription (bom.getDescription ()); - // - newLine.setPrice (); - newLine.save (get_TrxName()); - }*/ - - // Convert into Comment Line - line.setM_Product_ID (0); - line.setM_AttributeSetInstance_ID (0); - line.setPriceEntered (Env.ZERO); - line.setPriceActual (Env.ZERO); - line.setPriceLimit (Env.ZERO); - line.setPriceList (Env.ZERO); - line.setLineNetAmt (Env.ZERO); - // - String description = product.getName (); - if (product.getDescription () != null) - description += " " + product.getDescription (); - if (line.getDescription () != null) - description += " " + line.getDescription (); - line.setDescription (description); - line.save (get_TrxName()); - } // for all lines with BOM - - m_lines = null; - count = DB.getSQLValue (get_TrxName(), sql, getC_Invoice_ID ()); - renumberLines (10); - } // while count != 0 - } // explodeBOM - - /** - * Calculate Tax and Total - * @return true if calculated - */ - private boolean calculateTaxTotal() - { - log.fine(""); - // Delete Taxes - DB.executeUpdate("DELETE C_InvoiceTax WHERE C_Invoice_ID=" + getC_Invoice_ID(), get_TrxName()); - m_taxes = null; - - // Lines - BigDecimal totalLines = Env.ZERO; - ArrayList taxList = new ArrayList(); - MInvoiceLine[] lines = getLines(false); - for (int i = 0; i < lines.length; i++) - { - MInvoiceLine line = lines[i]; - /** Sync ownership for SO - if (isSOTrx() && line.getAD_Org_ID() != getAD_Org_ID()) - { - line.setAD_Org_ID(getAD_Org_ID()); - line.save(); - } **/ - Integer taxID = new Integer(line.getC_Tax_ID()); - if (!taxList.contains(taxID)) - { - MInvoiceTax iTax = MInvoiceTax.get (line, getPrecision(), - false, get_TrxName()); // current Tax - if (iTax != null) - { - iTax.setIsTaxIncluded(isTaxIncluded()); - if (!iTax.calculateTaxFromLines()) - return false; - if (!iTax.save()) - return false; - taxList.add(taxID); - } - } - totalLines = totalLines.add(line.getLineNetAmt()); - } - - // Taxes - BigDecimal grandTotal = totalLines; - MInvoiceTax[] taxes = getTaxes(true); - for (int i = 0; i < taxes.length; i++) - { - MInvoiceTax iTax = taxes[i]; - MTax tax = iTax.getTax(); - if (tax.isSummary()) - { - MTax[] cTaxes = tax.getChildTaxes(false); // Multiple taxes - for (int j = 0; j < cTaxes.length; j++) - { - MTax cTax = cTaxes[j]; - BigDecimal taxAmt = cTax.calculateTax(iTax.getTaxBaseAmt(), isTaxIncluded(), getPrecision()); - // - MInvoiceTax newITax = new MInvoiceTax(getCtx(), 0, get_TrxName()); - newITax.setClientOrg(this); - newITax.setC_Invoice_ID(getC_Invoice_ID()); - newITax.setC_Tax_ID(cTax.getC_Tax_ID()); - newITax.setPrecision(getPrecision()); - newITax.setIsTaxIncluded(isTaxIncluded()); - newITax.setTaxBaseAmt(iTax.getTaxBaseAmt()); - newITax.setTaxAmt(taxAmt); - if (!newITax.save(get_TrxName())) - return false; - // - if (!isTaxIncluded()) - grandTotal = grandTotal.add(taxAmt); - } - if (!iTax.delete(true, get_TrxName())) - return false; - } - else - { - if (!isTaxIncluded()) - grandTotal = grandTotal.add(iTax.getTaxAmt()); - } - } - // - setTotalLines(totalLines); - setGrandTotal(grandTotal); - return true; - } // calculateTaxTotal - - - /** - * (Re) Create Pay Schedule - * @return true if valid schedule - */ - private boolean createPaySchedule() - { - if (getC_PaymentTerm_ID() == 0) - return false; - MPaymentTerm pt = new MPaymentTerm(getCtx(), getC_PaymentTerm_ID(), null); - log.fine(pt.toString()); - return pt.apply(this); // calls validate pay schedule - } // createPaySchedule - - - /** - * Approve Document - * @return true if success - */ - public boolean approveIt() - { - log.info(toString()); - setIsApproved(true); - return true; - } // approveIt - - /** - * Reject Approval - * @return true if success - */ - public boolean rejectIt() - { - log.info(toString()); - setIsApproved(false); - return true; - } // rejectIt - - /** - * Complete Document - * @return new status (Complete, In Progress, Invalid, Waiting ..) - */ - public String completeIt() - { - // Re-Check - if (!m_justPrepared) - { - String status = prepareIt(); - if (!DocAction.STATUS_InProgress.equals(status)) - return status; - } - - m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_COMPLETE); - if (m_processMsg != null) - return DocAction.STATUS_Invalid; - - // Implicit Approval - if (!isApproved()) - approveIt(); - log.info(toString()); - StringBuffer info = new StringBuffer(); - - /* - // Create Cash - if (PAYMENTRULE_Cash.equals(getPaymentRule())) - { - // Modifications for POSterita - // - // MCash cash = MCash.get (getCtx(), getAD_Org_ID(), - // getDateInvoiced(), getC_Currency_ID(), get_TrxName()); - - MCash cash; - - int posId = Env.getContextAsInt(getCtx(),Env.POS_ID); - - if (posId != 0) - { - MPOS pos = new MPOS(getCtx(),posId,get_TrxName()); - int cashBookId = pos.getC_CashBook_ID(); - cash = MCash.get(getCtx(),cashBookId,getDateInvoiced(),get_TrxName()); - } - else - { - cash = MCash.get (getCtx(), getAD_Org_ID(), - getDateInvoiced(), getC_Currency_ID(), get_TrxName()); - } - - // End Posterita Modifications - - if (cash == null || cash.get_ID() == 0) - { - m_processMsg = "@NoCashBook@"; - return DocAction.STATUS_Invalid; - } - MCashLine cl = new MCashLine (cash); - cl.setInvoice(this); - if (!cl.save(get_TrxName())) - { - m_processMsg = "Could not save Cash Journal Line"; - return DocAction.STATUS_Invalid; - } - info.append("@C_Cash_ID@: " + cash.getName() + " #" + cl.getLine()); - setC_CashLine_ID(cl.getC_CashLine_ID()); - } // CashBook - */ - - // Update Order & Match - int matchInv = 0; - int matchPO = 0; - MInvoiceLine[] lines = getLines(false); - for (int i = 0; i < lines.length; i++) - { - MInvoiceLine line = lines[i]; - - // Update Order Line - MOrderLine ol = null; - if (line.getC_OrderLine_ID() != 0) - { - if (isSOTrx() - || line.getM_Product_ID() == 0) - { - ol = new MOrderLine (getCtx(), line.getC_OrderLine_ID(), get_TrxName()); - if (line.getQtyInvoiced() != null) - ol.setQtyInvoiced(ol.getQtyInvoiced().add(line.getQtyInvoiced())); - if (!ol.save(get_TrxName())) - { - m_processMsg = "Could not update Order Line"; - return DocAction.STATUS_Invalid; - } - } - // Order Invoiced Qty updated via Matching Inv-PO - else if (!isSOTrx() - && line.getM_Product_ID() != 0 - && !isReversal()) - { - // MatchPO is created also from MInOut when Invoice exists before Shipment - BigDecimal matchQty = line.getQtyInvoiced(); - MMatchPO po = MMatchPO.create (line, null, - getDateInvoiced(), matchQty); - if (!po.save(get_TrxName())) - { - m_processMsg = "Could not create PO Matching"; - return DocAction.STATUS_Invalid; - } - else - matchPO++; - } - } - - // Matching - Inv-Shipment - if (!isSOTrx() - && line.getM_InOutLine_ID() != 0 - && line.getM_Product_ID() != 0 - && !isReversal()) - { - MInOutLine receiptLine = new MInOutLine (getCtx(),line.getM_InOutLine_ID(), get_TrxName()); - BigDecimal matchQty = line.getQtyInvoiced(); - - if (receiptLine.getMovementQty().compareTo(matchQty) < 0) - matchQty = receiptLine.getMovementQty(); - - MMatchInv inv = new MMatchInv(line, getDateInvoiced(), matchQty); - if (!inv.save(get_TrxName())) - { - m_processMsg = CLogger.retrieveErrorString("Could not create Invoice Matching"); - return DocAction.STATUS_Invalid; - } - else - matchInv++; +/****************************************************************************** + * 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.model; + +import java.io.File; +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Properties; +import java.util.logging.Level; + +import org.compiere.print.ReportEngine; +import org.compiere.process.DocAction; +import org.compiere.process.DocumentEngine; +import org.compiere.report.MReportTree; +import org.compiere.util.CCache; +import org.compiere.util.CLogger; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.Msg; +import org.eevolution.model.MPPProductBOM; +import org.eevolution.model.MPPProductBOMLine; + + +/** + * Invoice Model. + * Please do not set DocStatus and C_DocType_ID directly. + * They are set in the process() method. + * Use DocAction and C_DocTypeTarget_ID instead. + * + * @author Jorg Janke + * @version $Id: MInvoice.java,v 1.2 2006/07/30 00:51:02 jjanke Exp $ + * @author victor.perez@e-evolution.com + * @see http://sourceforge.net/tracker/?func=detail&atid=879335&aid=1948157&group_id=176962 + * Modifications: Added RMA functionality (Ashley Ramdass) + */ +public class MInvoice extends X_C_Invoice implements DocAction +{ + private static final long serialVersionUID = 1L; + + /** + * Get Payments Of BPartner + * @param ctx context + * @param C_BPartner_ID id + * @param trxName transaction + * @return array + */ + public static MInvoice[] getOfBPartner (Properties ctx, int C_BPartner_ID, String trxName) + { + ArrayList list = new ArrayList(); + String sql = "SELECT * FROM C_Invoice WHERE C_BPartner_ID=?"; + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement(sql, trxName); + pstmt.setInt(1, C_BPartner_ID); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + list.add(new MInvoice(ctx,rs, trxName)); + 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; + } + + // + MInvoice[] retValue = new MInvoice[list.size()]; + list.toArray(retValue); + return retValue; + } // getOfBPartner + + /** + * Create new Invoice by copying + * @param from invoice + * @param dateDoc date of the document date + * @param C_DocTypeTarget_ID target doc type + * @param isSOTrx sales order + * @param counter create counter links + * @param trxName trx + * @param setOrder set Order links + * @return Invoice + */ + public static MInvoice copyFrom (MInvoice from, Timestamp dateDoc, + int C_DocTypeTarget_ID, boolean isSOTrx, boolean counter, + String trxName, boolean setOrder) + { + MInvoice to = new MInvoice (from.getCtx(), 0, null); + to.set_TrxName(trxName); + PO.copyValues (from, to, from.getAD_Client_ID(), from.getAD_Org_ID()); + to.set_ValueNoCheck ("C_Invoice_ID", I_ZERO); + to.set_ValueNoCheck ("DocumentNo", null); + // + to.setDocStatus (DOCSTATUS_Drafted); // Draft + to.setDocAction(DOCACTION_Complete); + // + to.setC_DocType_ID(0); + to.setC_DocTypeTarget_ID (C_DocTypeTarget_ID); + to.setIsSOTrx(isSOTrx); + // + to.setDateInvoiced (dateDoc); + to.setDateAcct (dateDoc); + to.setDatePrinted(null); + to.setIsPrinted (false); + // + to.setIsApproved (false); + to.setC_Payment_ID(0); + to.setC_CashLine_ID(0); + to.setIsPaid (false); + to.setIsInDispute(false); + // + // Amounts are updated by trigger when adding lines + to.setGrandTotal(Env.ZERO); + to.setTotalLines(Env.ZERO); + // + to.setIsTransferred (false); + to.setPosted (false); + to.setProcessed (false); + //[ 1633721 ] Reverse Documents- Processing=Y + to.setProcessing(false); + // delete references + to.setIsSelfService(false); + if (!setOrder) + to.setC_Order_ID(0); + if (counter) + { + to.setRef_Invoice_ID(from.getC_Invoice_ID()); + // Try to find Order link + if (from.getC_Order_ID() != 0) + { + MOrder peer = new MOrder (from.getCtx(), from.getC_Order_ID(), from.get_TrxName()); + if (peer.getRef_Order_ID() != 0) + to.setC_Order_ID(peer.getRef_Order_ID()); + } + } + else + to.setRef_Invoice_ID(0); + + if (!to.save(trxName)) + throw new IllegalStateException("Could not create Invoice"); + if (counter) + from.setRef_Invoice_ID(to.getC_Invoice_ID()); + + // Lines + if (to.copyLinesFrom(from, counter, setOrder) == 0) + throw new IllegalStateException("Could not create Invoice Lines"); + + return to; + } // copyFrom + + /** + * Get PDF File Name + * @param documentDir directory + * @param C_Invoice_ID invoice + * @return file name + */ + public static String getPDFFileName (String documentDir, int C_Invoice_ID) + { + StringBuffer sb = new StringBuffer (documentDir); + if (sb.length() == 0) + sb.append("."); + if (!sb.toString().endsWith(File.separator)) + sb.append(File.separator); + sb.append("C_Invoice_ID_") + .append(C_Invoice_ID) + .append(".pdf"); + return sb.toString(); + } // getPDFFileName + + + /** + * Get MInvoice from Cache + * @param ctx context + * @param C_Invoice_ID id + * @return MInvoice + */ + public static MInvoice get (Properties ctx, int C_Invoice_ID) + { + Integer key = new Integer (C_Invoice_ID); + MInvoice retValue = (MInvoice) s_cache.get (key); + if (retValue != null) + return retValue; + retValue = new MInvoice (ctx, C_Invoice_ID, null); + if (retValue.get_ID () != 0) + s_cache.put (key, retValue); + return retValue; + } // get + + /** Cache */ + private static CCache s_cache = new CCache("C_Invoice", 20, 2); // 2 minutes + + + /************************************************************************** + * Invoice Constructor + * @param ctx context + * @param C_Invoice_ID invoice or 0 for new + * @param trxName trx name + */ + public MInvoice (Properties ctx, int C_Invoice_ID, String trxName) + { + super (ctx, C_Invoice_ID, trxName); + if (C_Invoice_ID == 0) + { + setDocStatus (DOCSTATUS_Drafted); // Draft + setDocAction (DOCACTION_Complete); + // + setPaymentRule(PAYMENTRULE_OnCredit); // Payment Terms + + setDateInvoiced (new Timestamp (System.currentTimeMillis ())); + setDateAcct (new Timestamp (System.currentTimeMillis ())); + // + setChargeAmt (Env.ZERO); + setTotalLines (Env.ZERO); + setGrandTotal (Env.ZERO); + // + setIsSOTrx (true); + setIsTaxIncluded (false); + setIsApproved (false); + setIsDiscountPrinted (false); + setIsPaid (false); + setSendEMail (false); + setIsPrinted (false); + setIsTransferred (false); + setIsSelfService(false); + setIsPayScheduleValid(false); + setIsInDispute(false); + setPosted(false); + super.setProcessed (false); + setProcessing(false); + } + } // MInvoice + + /** + * Load Constructor + * @param ctx context + * @param rs result set record + * @param trxName transaction + */ + public MInvoice (Properties ctx, ResultSet rs, String trxName) + { + super(ctx, rs, trxName); + } // MInvoice + + /** + * Create Invoice from Order + * @param order order + * @param C_DocTypeTarget_ID target document type + * @param invoiceDate date or null + */ + public MInvoice (MOrder order, int C_DocTypeTarget_ID, Timestamp invoiceDate) + { + this (order.getCtx(), 0, order.get_TrxName()); + setClientOrg(order); + setOrder(order); // set base settings + // + if (C_DocTypeTarget_ID == 0) + C_DocTypeTarget_ID = DB.getSQLValue(null, + "SELECT C_DocTypeInvoice_ID FROM C_DocType WHERE C_DocType_ID=?", + order.getC_DocType_ID()); + setC_DocTypeTarget_ID(C_DocTypeTarget_ID); + if (invoiceDate != null) + setDateInvoiced(invoiceDate); + setDateAcct(getDateInvoiced()); + // + setSalesRep_ID(order.getSalesRep_ID()); + // + setC_BPartner_ID(order.getBill_BPartner_ID()); + setC_BPartner_Location_ID(order.getBill_Location_ID()); + setAD_User_ID(order.getBill_User_ID()); + } // MInvoice + + /** + * Create Invoice from Shipment + * @param ship shipment + * @param invoiceDate date or null + */ + public MInvoice (MInOut ship, Timestamp invoiceDate) + { + this (ship.getCtx(), 0, ship.get_TrxName()); + setClientOrg(ship); + setShipment(ship); // set base settings + // + setC_DocTypeTarget_ID(); + if (invoiceDate != null) + setDateInvoiced(invoiceDate); + setDateAcct(getDateInvoiced()); + // + setSalesRep_ID(ship.getSalesRep_ID()); + setAD_User_ID(ship.getAD_User_ID()); + } // MInvoice + + /** + * Create Invoice from Batch Line + * @param batch batch + * @param line batch line + */ + public MInvoice (MInvoiceBatch batch, MInvoiceBatchLine line) + { + this (line.getCtx(), 0, line.get_TrxName()); + setClientOrg(line); + setDocumentNo(line.getDocumentNo()); + // + setIsSOTrx(batch.isSOTrx()); + MBPartner bp = new MBPartner (line.getCtx(), line.getC_BPartner_ID(), line.get_TrxName()); + setBPartner(bp); // defaults + // + setIsTaxIncluded(line.isTaxIncluded()); + // May conflict with default price list + setC_Currency_ID(batch.getC_Currency_ID()); + setC_ConversionType_ID(batch.getC_ConversionType_ID()); + // + // setPaymentRule(order.getPaymentRule()); + // setC_PaymentTerm_ID(order.getC_PaymentTerm_ID()); + // setPOReference(""); + setDescription(batch.getDescription()); + // setDateOrdered(order.getDateOrdered()); + // + setAD_OrgTrx_ID(line.getAD_OrgTrx_ID()); + setC_Project_ID(line.getC_Project_ID()); + // setC_Campaign_ID(line.getC_Campaign_ID()); + setC_Activity_ID(line.getC_Activity_ID()); + setUser1_ID(line.getUser1_ID()); + setUser2_ID(line.getUser2_ID()); + // + setC_DocTypeTarget_ID(line.getC_DocType_ID()); + setDateInvoiced(line.getDateInvoiced()); + setDateAcct(line.getDateAcct()); + // + setSalesRep_ID(batch.getSalesRep_ID()); + // + setC_BPartner_ID(line.getC_BPartner_ID()); + setC_BPartner_Location_ID(line.getC_BPartner_Location_ID()); + setAD_User_ID(line.getAD_User_ID()); + } // MInvoice + + /** Open Amount */ + private BigDecimal m_openAmt = null; + + /** Invoice Lines */ + private MInvoiceLine[] m_lines; + /** Invoice Taxes */ + private MInvoiceTax[] m_taxes; + /** Logger */ + private static CLogger s_log = CLogger.getCLogger(MInvoice.class); + + /** + * Overwrite Client/Org if required + * @param AD_Client_ID client + * @param AD_Org_ID org + */ + public void setClientOrg (int AD_Client_ID, int AD_Org_ID) + { + super.setClientOrg(AD_Client_ID, AD_Org_ID); + } // setClientOrg + + /** + * Set Business Partner Defaults & Details + * @param bp business partner + */ + public void setBPartner (MBPartner bp) + { + if (bp == null) + return; + + setC_BPartner_ID(bp.getC_BPartner_ID()); + // Set Defaults + int ii = 0; + if (isSOTrx()) + ii = bp.getC_PaymentTerm_ID(); + else + ii = bp.getPO_PaymentTerm_ID(); + if (ii != 0) + setC_PaymentTerm_ID(ii); + // + if (isSOTrx()) + ii = bp.getM_PriceList_ID(); + else + ii = bp.getPO_PriceList_ID(); + if (ii != 0) + setM_PriceList_ID(ii); + // + String ss = bp.getPaymentRule(); + if (ss != null) + setPaymentRule(ss); + + + // Set Locations + MBPartnerLocation[] locs = bp.getLocations(false); + if (locs != null) + { + for (int i = 0; i < locs.length; i++) + { + if ((locs[i].isBillTo() && isSOTrx()) + || (locs[i].isPayFrom() && !isSOTrx())) + setC_BPartner_Location_ID(locs[i].getC_BPartner_Location_ID()); + } + // set to first + if (getC_BPartner_Location_ID() == 0 && locs.length > 0) + setC_BPartner_Location_ID(locs[0].getC_BPartner_Location_ID()); + } + if (getC_BPartner_Location_ID() == 0) + log.log(Level.SEVERE, "Has no To Address: " + bp); + + // Set Contact + MUser[] contacts = bp.getContacts(false); + if (contacts != null && contacts.length > 0) // get first User + setAD_User_ID(contacts[0].getAD_User_ID()); + } // setBPartner + + /** + * Set Order References + * @param order order + */ + public void setOrder (MOrder order) + { + if (order == null) + return; + + setC_Order_ID(order.getC_Order_ID()); + setIsSOTrx(order.isSOTrx()); + setIsDiscountPrinted(order.isDiscountPrinted()); + setIsSelfService(order.isSelfService()); + setSendEMail(order.isSendEMail()); + // + setM_PriceList_ID(order.getM_PriceList_ID()); + setIsTaxIncluded(order.isTaxIncluded()); + setC_Currency_ID(order.getC_Currency_ID()); + setC_ConversionType_ID(order.getC_ConversionType_ID()); + // + setPaymentRule(order.getPaymentRule()); + setC_PaymentTerm_ID(order.getC_PaymentTerm_ID()); + setPOReference(order.getPOReference()); + setDescription(order.getDescription()); + setDateOrdered(order.getDateOrdered()); + // + setAD_OrgTrx_ID(order.getAD_OrgTrx_ID()); + setC_Project_ID(order.getC_Project_ID()); + setC_Campaign_ID(order.getC_Campaign_ID()); + setC_Activity_ID(order.getC_Activity_ID()); + setUser1_ID(order.getUser1_ID()); + setUser2_ID(order.getUser2_ID()); + } // setOrder + + /** + * Set Shipment References + * @param ship shipment + */ + public void setShipment (MInOut ship) + { + if (ship == null) + return; + + setIsSOTrx(ship.isSOTrx()); + // + MBPartner bp = new MBPartner (getCtx(), ship.getC_BPartner_ID(), null); + setBPartner (bp); + // + setSendEMail(ship.isSendEMail()); + // + setPOReference(ship.getPOReference()); + setDescription(ship.getDescription()); + setDateOrdered(ship.getDateOrdered()); + // + setAD_OrgTrx_ID(ship.getAD_OrgTrx_ID()); + setC_Project_ID(ship.getC_Project_ID()); + setC_Campaign_ID(ship.getC_Campaign_ID()); + setC_Activity_ID(ship.getC_Activity_ID()); + setUser1_ID(ship.getUser1_ID()); + setUser2_ID(ship.getUser2_ID()); + // + if (ship.getC_Order_ID() != 0) + { + setC_Order_ID(ship.getC_Order_ID()); + MOrder order = new MOrder (getCtx(), ship.getC_Order_ID(), get_TrxName()); + setIsDiscountPrinted(order.isDiscountPrinted()); + setM_PriceList_ID(order.getM_PriceList_ID()); + setIsTaxIncluded(order.isTaxIncluded()); + setC_Currency_ID(order.getC_Currency_ID()); + setC_ConversionType_ID(order.getC_ConversionType_ID()); + setPaymentRule(order.getPaymentRule()); + setC_PaymentTerm_ID(order.getC_PaymentTerm_ID()); + // + MDocType dt = MDocType.get(getCtx(), order.getC_DocType_ID()); + if (dt.getC_DocTypeInvoice_ID() != 0) + setC_DocTypeTarget_ID(dt.getC_DocTypeInvoice_ID()); + // Overwrite Invoice Address + setC_BPartner_Location_ID(order.getBill_Location_ID()); + } + // Check if Shipment/Receipt is based on RMA + if (ship.getM_RMA_ID() != 0) + { + MRMA rma = new MRMA(getCtx(), ship.getM_RMA_ID(), get_TrxName()); + MOrder rmaOrder = rma.getOriginalOrder(); + setM_RMA_ID(ship.getM_RMA_ID()); + setIsSOTrx(rma.isSOTrx()); + setM_PriceList_ID(rmaOrder.getM_PriceList_ID()); + setIsTaxIncluded(rmaOrder.isTaxIncluded()); + setC_Currency_ID(rmaOrder.getC_Currency_ID()); + setC_ConversionType_ID(rmaOrder.getC_ConversionType_ID()); + setPaymentRule(rmaOrder.getPaymentRule()); + setC_PaymentTerm_ID(rmaOrder.getC_PaymentTerm_ID()); + + // Retrieves the invoice DocType + MDocType dt = MDocType.get(getCtx(), rma.getC_DocType_ID()); + if (dt.getC_DocTypeInvoice_ID() != 0) + { + setC_DocTypeTarget_ID(dt.getC_DocTypeInvoice_ID()); + } + setC_BPartner_Location_ID(rmaOrder.getBill_Location_ID()); + } + + } // setShipment + + /** + * Set Target Document Type + * @param DocBaseType doc type MDocType.DOCBASETYPE_ + */ + public void setC_DocTypeTarget_ID (String DocBaseType) + { + String sql = "SELECT C_DocType_ID FROM C_DocType " + + "WHERE AD_Client_ID=? AND DocBaseType=?" + + " AND IsActive='Y' " + + "ORDER BY IsDefault DESC"; + int C_DocType_ID = DB.getSQLValue(null, sql, getAD_Client_ID(), DocBaseType); + if (C_DocType_ID <= 0) + log.log(Level.SEVERE, "Not found for AC_Client_ID=" + + getAD_Client_ID() + " - " + DocBaseType); + else + { + log.fine(DocBaseType); + setC_DocTypeTarget_ID (C_DocType_ID); + boolean isSOTrx = MDocType.DOCBASETYPE_ARInvoice.equals(DocBaseType) + || MDocType.DOCBASETYPE_ARCreditMemo.equals(DocBaseType); + setIsSOTrx (isSOTrx); + } + } // setC_DocTypeTarget_ID + + /** + * Set Target Document Type. + * Based on SO flag AP/AP Invoice + */ + public void setC_DocTypeTarget_ID () + { + if (getC_DocTypeTarget_ID() > 0) + return; + if (isSOTrx()) + setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_ARInvoice); + else + setC_DocTypeTarget_ID(MDocType.DOCBASETYPE_APInvoice); + } // setC_DocTypeTarget_ID + + + /** + * Get Grand Total + * @param creditMemoAdjusted adjusted for CM (negative) + * @return grand total + */ + public BigDecimal getGrandTotal (boolean creditMemoAdjusted) + { + if (!creditMemoAdjusted) + return super.getGrandTotal(); + // + BigDecimal amt = getGrandTotal(); + if (isCreditMemo()) + return amt.negate(); + return amt; + } // getGrandTotal + + + /** + * Get Invoice Lines of Invoice + * @param whereClause starting with AND + * @return lines + */ + private MInvoiceLine[] getLines (String whereClause) + { + ArrayList list = new ArrayList(); + String sql = "SELECT * FROM C_InvoiceLine WHERE C_Invoice_ID=? "; + if (whereClause != null) + sql += whereClause; + sql += " ORDER BY Line"; + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, getC_Invoice_ID()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + { + MInvoiceLine il = new MInvoiceLine(getCtx(), rs, get_TrxName()); + il.setInvoice(this); + list.add(il); + } + rs.close(); + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + log.log(Level.SEVERE, "getLines", e); + } + finally + { + try + { + if (pstmt != null) + pstmt.close (); + } + catch (Exception e) + {} + pstmt = null; + } + + // + MInvoiceLine[] lines = new MInvoiceLine[list.size()]; + list.toArray(lines); + return lines; + } // getLines + + /** + * Get Invoice Lines + * @param requery + * @return lines + */ + public MInvoiceLine[] getLines (boolean requery) + { + if (m_lines == null || m_lines.length == 0 || requery) + m_lines = getLines(null); + set_TrxName(m_lines, get_TrxName()); + return m_lines; + } // getLines + + /** + * Get Lines of Invoice + * @return lines + */ + public MInvoiceLine[] getLines() + { + return getLines(false); + } // getLines + + + /** + * Renumber Lines + * @param step start and step + */ + public void renumberLines (int step) + { + int number = step; + MInvoiceLine[] lines = getLines(false); + for (int i = 0; i < lines.length; i++) + { + MInvoiceLine line = lines[i]; + line.setLine(number); + line.save(); + number += step; + } + m_lines = null; + } // renumberLines + + /** + * Copy Lines From other Invoice. + * @param otherInvoice invoice + * @param counter create counter links + * @param setOrder set order links + * @return number of lines copied + */ + public int copyLinesFrom (MInvoice otherInvoice, boolean counter, boolean setOrder) + { + if (isProcessed() || isPosted() || otherInvoice == null) + return 0; + MInvoiceLine[] fromLines = otherInvoice.getLines(false); + int count = 0; + for (int i = 0; i < fromLines.length; i++) + { + MInvoiceLine line = new MInvoiceLine (getCtx(), 0, get_TrxName()); + MInvoiceLine fromLine = fromLines[i]; + if (counter) // header + PO.copyValues (fromLine, line, getAD_Client_ID(), getAD_Org_ID()); + else + PO.copyValues (fromLine, line, fromLine.getAD_Client_ID(), fromLine.getAD_Org_ID()); + line.setC_Invoice_ID(getC_Invoice_ID()); + line.setInvoice(this); + line.set_ValueNoCheck ("C_InvoiceLine_ID", I_ZERO); // new + // Reset + if (!setOrder) + line.setC_OrderLine_ID(0); + line.setRef_InvoiceLine_ID(0); + line.setM_InOutLine_ID(0); + line.setA_Asset_ID(0); + line.setM_AttributeSetInstance_ID(0); + line.setS_ResourceAssignment_ID(0); + // New Tax + if (getC_BPartner_ID() != otherInvoice.getC_BPartner_ID()) + line.setTax(); // recalculate + // + if (counter) + { + line.setRef_InvoiceLine_ID(fromLine.getC_InvoiceLine_ID()); + if (fromLine.getC_OrderLine_ID() != 0) + { + MOrderLine peer = new MOrderLine (getCtx(), fromLine.getC_OrderLine_ID(), get_TrxName()); + if (peer.getRef_OrderLine_ID() != 0) + line.setC_OrderLine_ID(peer.getRef_OrderLine_ID()); + } + line.setM_InOutLine_ID(0); + if (fromLine.getM_InOutLine_ID() != 0) + { + MInOutLine peer = new MInOutLine (getCtx(), fromLine.getM_InOutLine_ID(), get_TrxName()); + if (peer.getRef_InOutLine_ID() != 0) + line.setM_InOutLine_ID(peer.getRef_InOutLine_ID()); + } + } + // + line.setProcessed(false); + if (line.save(get_TrxName())) + count++; + // Cross Link + if (counter) + { + fromLine.setRef_InvoiceLine_ID(line.getC_InvoiceLine_ID()); + fromLine.save(get_TrxName()); + } + + // MZ Goodwill + // copy the landed cost + line.copyLandedCostFrom(fromLine); + line.allocateLandedCosts(); + // end MZ + } + if (fromLines.length != count) + log.log(Level.SEVERE, "Line difference - From=" + fromLines.length + " <> Saved=" + count); + return count; + } // copyLinesFrom + + /** Reversal Flag */ + private boolean m_reversal = false; + + /** + * Set Reversal + * @param reversal reversal + */ + private void setReversal(boolean reversal) + { + m_reversal = reversal; + } // setReversal + /** + * Is Reversal + * @return reversal + */ + public boolean isReversal() + { + return m_reversal; + } // isReversal + + /** + * Get Taxes + * @param requery requery + * @return array of taxes + */ + public MInvoiceTax[] getTaxes (boolean requery) + { + if (m_taxes != null && !requery) + return m_taxes; + String sql = "SELECT * FROM C_InvoiceTax WHERE C_Invoice_ID=?"; + ArrayList list = new ArrayList(); + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement (sql, get_TrxName()); + pstmt.setInt (1, getC_Invoice_ID()); + ResultSet rs = pstmt.executeQuery (); + while (rs.next ()) + list.add(new MInvoiceTax(getCtx(), rs, get_TrxName())); + rs.close (); + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + log.log(Level.SEVERE, "getTaxes", e); + } + try + { + if (pstmt != null) + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + + m_taxes = new MInvoiceTax[list.size ()]; + list.toArray (m_taxes); + return m_taxes; + } // getTaxes + + /** + * Add to Description + * @param description text + */ + public void addDescription (String description) + { + String desc = getDescription(); + if (desc == null) + setDescription(description); + else + setDescription(desc + " | " + description); + } // addDescription + + /** + * Is it a Credit Memo? + * @return true if CM + */ + public boolean isCreditMemo() + { + MDocType dt = MDocType.get(getCtx(), + getC_DocType_ID()==0 ? getC_DocTypeTarget_ID() : getC_DocType_ID()); + return MDocType.DOCBASETYPE_APCreditMemo.equals(dt.getDocBaseType()) + || MDocType.DOCBASETYPE_ARCreditMemo.equals(dt.getDocBaseType()); + } // isCreditMemo + + /** + * Set Processed. + * Propergate to Lines/Taxes + * @param processed processed + */ + public void setProcessed (boolean processed) + { + super.setProcessed (processed); + if (get_ID() == 0) + return; + String set = "SET Processed='" + + (processed ? "Y" : "N") + + "' WHERE C_Invoice_ID=" + getC_Invoice_ID(); + int noLine = DB.executeUpdate("UPDATE C_InvoiceLine " + set, get_TrxName()); + int noTax = DB.executeUpdate("UPDATE C_InvoiceTax " + set, get_TrxName()); + m_lines = null; + m_taxes = null; + log.fine(processed + " - Lines=" + noLine + ", Tax=" + noTax); + } // setProcessed + + /** + * Validate Invoice Pay Schedule + * @return pay schedule is valid + */ + public boolean validatePaySchedule() + { + MInvoicePaySchedule[] schedule = MInvoicePaySchedule.getInvoicePaySchedule + (getCtx(), getC_Invoice_ID(), 0, get_TrxName()); + log.fine("#" + schedule.length); + if (schedule.length == 0) + { + setIsPayScheduleValid(false); + return false; + } + // Add up due amounts + BigDecimal total = Env.ZERO; + for (int i = 0; i < schedule.length; i++) + { + schedule[i].setParent(this); + BigDecimal due = schedule[i].getDueAmt(); + if (due != null) + total = total.add(due); + } + boolean valid = getGrandTotal().compareTo(total) == 0; + setIsPayScheduleValid(valid); + + // Update Schedule Lines + for (int i = 0; i < schedule.length; i++) + { + if (schedule[i].isValid() != valid) + { + schedule[i].setIsValid(valid); + schedule[i].save(get_TrxName()); + } + } + return valid; + } // validatePaySchedule + + + /************************************************************************** + * Before Save + * @param newRecord new + * @return true + */ + protected boolean beforeSave (boolean newRecord) + { + log.fine(""); + // No Partner Info - set Template + if (getC_BPartner_ID() == 0) + setBPartner(MBPartner.getTemplate(getCtx(), getAD_Client_ID())); + if (getC_BPartner_Location_ID() == 0) + setBPartner(new MBPartner(getCtx(), getC_BPartner_ID(), null)); + + // Price List + if (getM_PriceList_ID() == 0) + { + int ii = Env.getContextAsInt(getCtx(), "#M_PriceList_ID"); + if (ii != 0) + setM_PriceList_ID(ii); + else + { + String sql = "SELECT M_PriceList_ID FROM M_PriceList WHERE AD_Client_ID=? AND IsDefault='Y'"; + ii = DB.getSQLValue (null, sql, getAD_Client_ID()); + if (ii != 0) + setM_PriceList_ID (ii); + } + } + + // Currency + if (getC_Currency_ID() == 0) + { + String sql = "SELECT C_Currency_ID FROM M_PriceList WHERE M_PriceList_ID=?"; + int ii = DB.getSQLValue (null, sql, getM_PriceList_ID()); + if (ii != 0) + setC_Currency_ID (ii); + else + setC_Currency_ID(Env.getContextAsInt(getCtx(), "#C_Currency_ID")); + } + + // Sales Rep + if (getSalesRep_ID() == 0) + { + int ii = Env.getContextAsInt(getCtx(), "#SalesRep_ID"); + if (ii != 0) + setSalesRep_ID (ii); + } + + // Document Type + if (getC_DocType_ID() == 0) + setC_DocType_ID (0); // make sure it's set to 0 + if (getC_DocTypeTarget_ID() == 0) + setC_DocTypeTarget_ID(isSOTrx() ? MDocType.DOCBASETYPE_ARInvoice : MDocType.DOCBASETYPE_APInvoice); + + // Payment Term + if (getC_PaymentTerm_ID() == 0) + { + int ii = Env.getContextAsInt(getCtx(), "#C_PaymentTerm_ID"); + if (ii != 0) + setC_PaymentTerm_ID (ii); + else + { + String sql = "SELECT C_PaymentTerm_ID FROM C_PaymentTerm WHERE AD_Client_ID=? AND IsDefault='Y'"; + ii = DB.getSQLValue(null, sql, getAD_Client_ID()); + if (ii != 0) + setC_PaymentTerm_ID (ii); + } + } + return true; + } // beforeSave + + /** + * Before Delete + * @return true if it can be deleted + */ + protected boolean beforeDelete () + { + if (getC_Order_ID() != 0) + { + log.saveError("Error", Msg.getMsg(getCtx(), "CannotDelete")); + return false; + } + return true; + } // beforeDelete + + /** + * String Representation + * @return info + */ + public String toString () + { + StringBuffer sb = new StringBuffer ("MInvoice[") + .append(get_ID()).append("-").append(getDocumentNo()) + .append(",GrandTotal=").append(getGrandTotal()); + if (m_lines != null) + sb.append(" (#").append(m_lines.length).append(")"); + sb.append ("]"); + return sb.toString (); + } // toString + + /** + * Get Document Info + * @return document info (untranslated) + */ + public String getDocumentInfo() + { + MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); + return dt.getName() + " " + getDocumentNo(); + } // getDocumentInfo + + + /** + * After Save + * @param newRecord new + * @param success success + * @return success + */ + protected boolean afterSave (boolean newRecord, boolean success) + { + if (!success || newRecord) + return success; + + if (is_ValueChanged("AD_Org_ID")) + { + String sql = "UPDATE C_InvoiceLine ol" + + " SET AD_Org_ID =" + + "(SELECT AD_Org_ID" + + " FROM C_Invoice o WHERE ol.C_Invoice_ID=o.C_Invoice_ID) " + + "WHERE C_Invoice_ID=" + getC_Invoice_ID(); + int no = DB.executeUpdate(sql, get_TrxName()); + log.fine("Lines -> #" + no); + } + return true; + } // afterSave + + + /** + * Set Price List (and Currency) when valid + * @param M_PriceList_ID price list + */ + public void setM_PriceList_ID (int M_PriceList_ID) + { + String sql = "SELECT M_PriceList_ID, C_Currency_ID " + + "FROM M_PriceList WHERE M_PriceList_ID=?"; + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement(sql, null); + pstmt.setInt(1, M_PriceList_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + super.setM_PriceList_ID (rs.getInt(1)); + setC_Currency_ID (rs.getInt(2)); + } + rs.close(); + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + log.log(Level.SEVERE, "setM_PriceList_ID", e); + } + finally + { + try + { + if (pstmt != null) + pstmt.close (); + } + catch (Exception e) + {} + pstmt = null; + } + } // setM_PriceList_ID + + + /** + * Get Allocated Amt in Invoice Currency + * @return pos/neg amount or null + */ + public BigDecimal getAllocatedAmt () + { + BigDecimal retValue = null; + String sql = "SELECT SUM(currencyConvert(al.Amount+al.DiscountAmt+al.WriteOffAmt," + + "ah.C_Currency_ID, i.C_Currency_ID,ah.DateTrx,COALESCE(i.C_ConversionType_ID,0), al.AD_Client_ID,al.AD_Org_ID)) " + + "FROM C_AllocationLine al" + + " INNER JOIN C_AllocationHdr ah ON (al.C_AllocationHdr_ID=ah.C_AllocationHdr_ID)" + + " INNER JOIN C_Invoice i ON (al.C_Invoice_ID=i.C_Invoice_ID) " + + "WHERE al.C_Invoice_ID=?" + + " AND ah.IsActive='Y' AND al.IsActive='Y'"; + PreparedStatement pstmt = null; + ResultSet rs = null; + try + { + pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, getC_Invoice_ID()); + rs = pstmt.executeQuery(); + if (rs.next()) + retValue = rs.getBigDecimal(1); + rs.close(); + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + log.log(Level.SEVERE, sql, e); + } + finally + { + DB.close(rs, pstmt); + rs = null; pstmt = null; + } + // log.fine("getAllocatedAmt - " + retValue); + // ? ROUND(NVL(v_AllocatedAmt,0), 2); + return retValue; + } // getAllocatedAmt + + /** + * Test Allocation (and set paid flag) + * @return true if updated + */ + public boolean testAllocation() + { + boolean change = false; + + if ( isProcessed() ) { + BigDecimal alloc = getAllocatedAmt(); // absolute + if (alloc == null) + alloc = Env.ZERO; + BigDecimal total = getGrandTotal(); + if (!isSOTrx()) + total = total.negate(); + if (isCreditMemo()) + total = total.negate(); + boolean test = total.compareTo(alloc) == 0; + change = test != isPaid(); + if (change) + setIsPaid(test); + log.fine("Paid=" + test + + " (" + alloc + "=" + total + ")"); + } + + return change; + } // testAllocation + + /** + * Set Paid Flag for invoices + * @param ctx context + * @param C_BPartner_ID if 0 all + * @param trxName transaction + */ + public static void setIsPaid (Properties ctx, int C_BPartner_ID, String trxName) + { + int counter = 0; + String sql = "SELECT * FROM C_Invoice " + + "WHERE IsPaid='N' AND DocStatus IN ('CO','CL')"; + if (C_BPartner_ID > 1) + sql += " AND C_BPartner_ID=?"; + else + sql += " AND AD_Client_ID=" + Env.getAD_Client_ID(ctx); + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement (sql, trxName); + if (C_BPartner_ID > 1) + pstmt.setInt (1, C_BPartner_ID); + ResultSet rs = pstmt.executeQuery (); + while (rs.next ()) + { + MInvoice invoice = new MInvoice(ctx, rs, trxName); + if (invoice.testAllocation()) + if (invoice.save()) + counter++; + } + 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; + } + s_log.config("#" + counter); + /**/ + } // setIsPaid + + /** + * Get Open Amount. + * Used by web interface + * @return Open Amt + */ + public BigDecimal getOpenAmt () + { + return getOpenAmt (true, null); + } // getOpenAmt + + /** + * Get Open Amount + * @param creditMemoAdjusted adjusted for CM (negative) + * @param paymentDate ignored Payment Date + * @return Open Amt + */ + public BigDecimal getOpenAmt (boolean creditMemoAdjusted, Timestamp paymentDate) + { + if (isPaid()) + return Env.ZERO; + // + if (m_openAmt == null) + { + m_openAmt = getGrandTotal(); + if (paymentDate != null) + { + // Payment Discount + // Payment Schedule + } + BigDecimal allocated = getAllocatedAmt(); + if (allocated != null) + { + allocated = allocated.abs(); // is absolute + m_openAmt = m_openAmt.subtract(allocated); + } + } + // + if (!creditMemoAdjusted) + return m_openAmt; + if (isCreditMemo()) + return m_openAmt.negate(); + return m_openAmt; + } // getOpenAmt + + + /** + * Get Document Status + * @return Document Status Clear Text + */ + public String getDocStatusName() + { + return MRefList.getListName(getCtx(), 131, getDocStatus()); + } // getDocStatusName + + + /************************************************************************** + * Create PDF + * @return File or null + */ + public File createPDF () + { + try + { + File temp = File.createTempFile(get_TableName()+get_ID()+"_", ".pdf"); + return createPDF (temp); + } + catch (Exception e) + { + log.severe("Could not create PDF - " + e.getMessage()); + } + return null; + } // getPDF + + /** + * Create PDF file + * @param file output file + * @return file if success + */ + public File createPDF (File file) + { + ReportEngine re = ReportEngine.get (getCtx(), ReportEngine.INVOICE, getC_Invoice_ID(), get_TrxName()); + if (re == null) + return null; + return re.getPDF(file); + } // createPDF + + /** + * Get PDF File Name + * @param documentDir directory + * @return file name + */ + public String getPDFFileName (String documentDir) + { + return getPDFFileName (documentDir, getC_Invoice_ID()); + } // getPDFFileName + + /** + * Get ISO Code of Currency + * @return Currency ISO + */ + public String getCurrencyISO() + { + return MCurrency.getISO_Code (getCtx(), getC_Currency_ID()); + } // getCurrencyISO + + /** + * Get Currency Precision + * @return precision + */ + public int getPrecision() + { + return MCurrency.getStdPrecision(getCtx(), getC_Currency_ID()); + } // getPrecision + + + /************************************************************************** + * Process document + * @param processAction document action + * @return true if performed + */ + public boolean processIt (String processAction) + { + m_processMsg = null; + DocumentEngine engine = new DocumentEngine (this, getDocStatus()); + return engine.processIt (processAction, getDocAction()); + } // process + + /** Process Message */ + private String m_processMsg = null; + /** Just Prepared Flag */ + private boolean m_justPrepared = false; + + /** + * Unlock Document. + * @return true if success + */ + public boolean unlockIt() + { + log.info("unlockIt - " + toString()); + setProcessing(false); + return true; + } // unlockIt + + /** + * Invalidate Document + * @return true if success + */ + public boolean invalidateIt() + { + log.info("invalidateIt - " + toString()); + setDocAction(DOCACTION_Prepare); + return true; + } // invalidateIt + + /** + * Prepare Document + * @return new status (In Progress or Invalid) + */ + public String prepareIt() + { + log.info(toString()); + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE); + if (m_processMsg != null) + return DocAction.STATUS_Invalid; + MDocType dt = MDocType.get(getCtx(), getC_DocTypeTarget_ID()); + + // Std Period open? + if (!MPeriod.isOpen(getCtx(), getDateAcct(), dt.getDocBaseType())) + { + m_processMsg = "@PeriodClosed@"; + return DocAction.STATUS_Invalid; + } + // Lines + MInvoiceLine[] lines = getLines(true); + if (lines.length == 0) + { + m_processMsg = "@NoLines@"; + return DocAction.STATUS_Invalid; + } + // No Cash Book + if (PAYMENTRULE_Cash.equals(getPaymentRule()) + && MCashBook.get(getCtx(), getAD_Org_ID(), getC_Currency_ID()) == null) + { + m_processMsg = "@NoCashBook@"; + return DocAction.STATUS_Invalid; + } + + // Convert/Check DocType + if (getC_DocType_ID() != getC_DocTypeTarget_ID() ) + setC_DocType_ID(getC_DocTypeTarget_ID()); + if (getC_DocType_ID() == 0) + { + m_processMsg = "No Document Type"; + return DocAction.STATUS_Invalid; + } + + explodeBOM(); + if (!calculateTaxTotal()) // setTotals + { + m_processMsg = "Error calculating Tax"; + return DocAction.STATUS_Invalid; + } + + createPaySchedule(); + + // Credit Status + if (isSOTrx() && !isReversal()) + { + MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), null); + if (MBPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus())) + { + m_processMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@=" + + bp.getTotalOpenBalance() + + ", @SO_CreditLimit@=" + bp.getSO_CreditLimit(); + return DocAction.STATUS_Invalid; + } + } + + // Landed Costs + if (!isSOTrx()) + { + for (int i = 0; i < lines.length; i++) + { + MInvoiceLine line = lines[i]; + String error = line.allocateLandedCosts(); + if (error != null && error.length() > 0) + { + m_processMsg = error; + return DocAction.STATUS_Invalid; + } + } + } + + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE); + if (m_processMsg != null) + return DocAction.STATUS_Invalid; + + // Add up Amounts + m_justPrepared = true; + if (!DOCACTION_Complete.equals(getDocAction())) + setDocAction(DOCACTION_Complete); + return DocAction.STATUS_InProgress; + } // prepareIt + + /** + * Explode non stocked BOM. + */ + private void explodeBOM () + { + String where = "AND IsActive='Y' AND EXISTS " + + "(SELECT * FROM M_Product p WHERE C_InvoiceLine.M_Product_ID=p.M_Product_ID" + + " AND p.IsBOM='Y' AND p.IsVerified='Y' AND p.IsStocked='N')"; + // + String sql = "SELECT COUNT(*) FROM C_InvoiceLine " + + "WHERE C_Invoice_ID=? " + where; + int count = DB.getSQLValue(get_TrxName(), sql, getC_Invoice_ID()); + while (count != 0) + { + renumberLines (100); + + // Order Lines with non-stocked BOMs + MInvoiceLine[] lines = getLines (where); + for (int i = 0; i < lines.length; i++) + { + MInvoiceLine line = lines[i]; + MProduct product = MProduct.get (getCtx(), line.getM_Product_ID()); + log.fine(product.getName()); + // New Lines + int lineNo = line.getLine (); + + //find default BOM with valid dates and to this product + MPPProductBOM bom = MPPProductBOM.get(product, getAD_Org_ID(),getDateInvoiced(), get_TrxName()); + if(bom != null) + { + MPPProductBOMLine[] bomlines = bom.getLines(getDateInvoiced()); + for (int j = 0; j < bomlines.length; j++) + { + MPPProductBOMLine bomline = bomlines[j]; + MInvoiceLine newLine = new MInvoiceLine (this); + newLine.setLine (++lineNo); + newLine.setM_Product_ID (bomline.getM_Product_ID ()); + newLine.setC_UOM_ID (bomline.getC_UOM_ID ()); + newLine.setQty (line.getQtyInvoiced().multiply( + bomline.getQtyBOM ())); // Invoiced/Entered + if (bomline.getDescription () != null) + newLine.setDescription (bomline.getDescription ()); + // + newLine.setPrice (); + newLine.save (get_TrxName()); + } + } + + /*MProductBOM[] boms = MProductBOM.getBOMLines (product); + for (int j = 0; j < boms.length; j++) + { + MProductBOM bom = boms[j]; + MInvoiceLine newLine = new MInvoiceLine (this); + newLine.setLine (++lineNo); + newLine.setM_Product_ID (bom.getProduct().getM_Product_ID(), + bom.getProduct().getC_UOM_ID()); + newLine.setQty (line.getQtyInvoiced().multiply( + bom.getBOMQty ())); // Invoiced/Entered + if (bom.getDescription () != null) + newLine.setDescription (bom.getDescription ()); + // + newLine.setPrice (); + newLine.save (get_TrxName()); + }*/ + + // Convert into Comment Line + line.setM_Product_ID (0); + line.setM_AttributeSetInstance_ID (0); + line.setPriceEntered (Env.ZERO); + line.setPriceActual (Env.ZERO); + line.setPriceLimit (Env.ZERO); + line.setPriceList (Env.ZERO); + line.setLineNetAmt (Env.ZERO); + // + String description = product.getName (); + if (product.getDescription () != null) + description += " " + product.getDescription (); + if (line.getDescription () != null) + description += " " + line.getDescription (); + line.setDescription (description); + line.save (get_TrxName()); + } // for all lines with BOM + + m_lines = null; + count = DB.getSQLValue (get_TrxName(), sql, getC_Invoice_ID ()); + renumberLines (10); + } // while count != 0 + } // explodeBOM + + /** + * Calculate Tax and Total + * @return true if calculated + */ + public boolean calculateTaxTotal() + { + log.fine(""); + // Delete Taxes + DB.executeUpdateEx("DELETE C_InvoiceTax WHERE C_Invoice_ID=" + getC_Invoice_ID(), get_TrxName()); + m_taxes = null; + + // Lines + BigDecimal totalLines = Env.ZERO; + ArrayList taxList = new ArrayList(); + MInvoiceLine[] lines = getLines(false); + for (int i = 0; i < lines.length; i++) + { + MInvoiceLine line = lines[i]; + if (!taxList.contains(line.getC_Tax_ID())) + { + MInvoiceTax iTax = MInvoiceTax.get (line, getPrecision(), false, get_TrxName()); // current Tax + if (iTax != null) + { + iTax.setIsTaxIncluded(isTaxIncluded()); + if (!iTax.calculateTaxFromLines()) + return false; + iTax.saveEx(); + taxList.add(line.getC_Tax_ID()); + } + } + totalLines = totalLines.add(line.getLineNetAmt()); + } + + // Taxes + BigDecimal grandTotal = totalLines; + MInvoiceTax[] taxes = getTaxes(true); + for (int i = 0; i < taxes.length; i++) + { + MInvoiceTax iTax = taxes[i]; + MTax tax = iTax.getTax(); + if (tax.isSummary()) + { + MTax[] cTaxes = tax.getChildTaxes(false); // Multiple taxes + for (int j = 0; j < cTaxes.length; j++) + { + MTax cTax = cTaxes[j]; + BigDecimal taxAmt = cTax.calculateTax(iTax.getTaxBaseAmt(), isTaxIncluded(), getPrecision()); + // + MInvoiceTax newITax = new MInvoiceTax(getCtx(), 0, get_TrxName()); + newITax.setClientOrg(this); + newITax.setC_Invoice_ID(getC_Invoice_ID()); + newITax.setC_Tax_ID(cTax.getC_Tax_ID()); + newITax.setPrecision(getPrecision()); + newITax.setIsTaxIncluded(isTaxIncluded()); + newITax.setTaxBaseAmt(iTax.getTaxBaseAmt()); + newITax.setTaxAmt(taxAmt); + newITax.saveEx(get_TrxName()); + // + if (!isTaxIncluded()) + grandTotal = grandTotal.add(taxAmt); + } + iTax.deleteEx(true, get_TrxName()); + } + else + { + if (!isTaxIncluded()) + grandTotal = grandTotal.add(iTax.getTaxAmt()); + } + } + // + setTotalLines(totalLines); + setGrandTotal(grandTotal); + return true; + } // calculateTaxTotal + + + /** + * (Re) Create Pay Schedule + * @return true if valid schedule + */ + private boolean createPaySchedule() + { + if (getC_PaymentTerm_ID() == 0) + return false; + MPaymentTerm pt = new MPaymentTerm(getCtx(), getC_PaymentTerm_ID(), null); + log.fine(pt.toString()); + return pt.apply(this); // calls validate pay schedule + } // createPaySchedule + + + /** + * Approve Document + * @return true if success + */ + public boolean approveIt() + { + log.info(toString()); + setIsApproved(true); + return true; + } // approveIt + + /** + * Reject Approval + * @return true if success + */ + public boolean rejectIt() + { + log.info(toString()); + setIsApproved(false); + return true; + } // rejectIt + + /** + * Complete Document + * @return new status (Complete, In Progress, Invalid, Waiting ..) + */ + public String completeIt() + { + // Re-Check + if (!m_justPrepared) + { + String status = prepareIt(); + if (!DocAction.STATUS_InProgress.equals(status)) + return status; + } + + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_COMPLETE); + if (m_processMsg != null) + return DocAction.STATUS_Invalid; + + // Implicit Approval + if (!isApproved()) + approveIt(); + log.info(toString()); + StringBuffer info = new StringBuffer(); + + /* + // Create Cash + if (PAYMENTRULE_Cash.equals(getPaymentRule())) + { + // Modifications for POSterita + // + // MCash cash = MCash.get (getCtx(), getAD_Org_ID(), + // getDateInvoiced(), getC_Currency_ID(), get_TrxName()); + + MCash cash; + + int posId = Env.getContextAsInt(getCtx(),Env.POS_ID); + + if (posId != 0) + { + MPOS pos = new MPOS(getCtx(),posId,get_TrxName()); + int cashBookId = pos.getC_CashBook_ID(); + cash = MCash.get(getCtx(),cashBookId,getDateInvoiced(),get_TrxName()); + } + else + { + cash = MCash.get (getCtx(), getAD_Org_ID(), + getDateInvoiced(), getC_Currency_ID(), get_TrxName()); + } + + // End Posterita Modifications + + if (cash == null || cash.get_ID() == 0) + { + m_processMsg = "@NoCashBook@"; + return DocAction.STATUS_Invalid; + } + MCashLine cl = new MCashLine (cash); + cl.setInvoice(this); + if (!cl.save(get_TrxName())) + { + m_processMsg = "Could not save Cash Journal Line"; + return DocAction.STATUS_Invalid; + } + info.append("@C_Cash_ID@: " + cash.getName() + " #" + cl.getLine()); + setC_CashLine_ID(cl.getC_CashLine_ID()); + } // CashBook + */ + + // Update Order & Match + int matchInv = 0; + int matchPO = 0; + MInvoiceLine[] lines = getLines(false); + for (int i = 0; i < lines.length; i++) + { + MInvoiceLine line = lines[i]; + + // Update Order Line + MOrderLine ol = null; + if (line.getC_OrderLine_ID() != 0) + { + if (isSOTrx() + || line.getM_Product_ID() == 0) + { + ol = new MOrderLine (getCtx(), line.getC_OrderLine_ID(), get_TrxName()); + if (line.getQtyInvoiced() != null) + ol.setQtyInvoiced(ol.getQtyInvoiced().add(line.getQtyInvoiced())); + if (!ol.save(get_TrxName())) + { + m_processMsg = "Could not update Order Line"; + return DocAction.STATUS_Invalid; + } + } + // Order Invoiced Qty updated via Matching Inv-PO + else if (!isSOTrx() + && line.getM_Product_ID() != 0 + && !isReversal()) + { + // MatchPO is created also from MInOut when Invoice exists before Shipment + BigDecimal matchQty = line.getQtyInvoiced(); + MMatchPO po = MMatchPO.create (line, null, + getDateInvoiced(), matchQty); + if (!po.save(get_TrxName())) + { + m_processMsg = "Could not create PO Matching"; + return DocAction.STATUS_Invalid; + } + else + matchPO++; + } + } + + // Matching - Inv-Shipment + if (!isSOTrx() + && line.getM_InOutLine_ID() != 0 + && line.getM_Product_ID() != 0 + && !isReversal()) + { + MInOutLine receiptLine = new MInOutLine (getCtx(),line.getM_InOutLine_ID(), get_TrxName()); + BigDecimal matchQty = line.getQtyInvoiced(); + + if (receiptLine.getMovementQty().compareTo(matchQty) < 0) + matchQty = receiptLine.getMovementQty(); + + MMatchInv inv = new MMatchInv(line, getDateInvoiced(), matchQty); + if (!inv.save(get_TrxName())) + { + m_processMsg = CLogger.retrieveErrorString("Could not create Invoice Matching"); + return DocAction.STATUS_Invalid; + } + else + matchInv++; // Elaine 2008/6/20 String err = createMatchInvCostDetail(inv, line, receiptLine); if(err != null && err.length() > 0) return err; // - } - } // for all lines - if (matchInv > 0) - info.append(" @M_MatchInv_ID@#").append(matchInv).append(" "); - if (matchPO > 0) - info.append(" @M_MatchPO_ID@#").append(matchPO).append(" "); - - - - // Update BP Statistics - MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName()); - // Update total revenue and balance / credit limit (reversed on AllocationLine.processIt) - BigDecimal invAmt = MConversionRate.convertBase(getCtx(), getGrandTotal(true), // CM adjusted - getC_Currency_ID(), getDateAcct(), getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID()); - if (invAmt == null) - { - m_processMsg = "Could not convert C_Currency_ID=" + getC_Currency_ID() - + " to base C_Currency_ID=" + MClient.get(Env.getCtx()).getC_Currency_ID(); - return DocAction.STATUS_Invalid; - } - // Total Balance - BigDecimal newBalance = bp.getTotalOpenBalance(false); - if (newBalance == null) - newBalance = Env.ZERO; - if (isSOTrx()) - { - newBalance = newBalance.add(invAmt); - // - if (bp.getFirstSale() == null) - bp.setFirstSale(getDateInvoiced()); - BigDecimal newLifeAmt = bp.getActualLifeTimeValue(); - if (newLifeAmt == null) - newLifeAmt = invAmt; - else - newLifeAmt = newLifeAmt.add(invAmt); - BigDecimal newCreditAmt = bp.getSO_CreditUsed(); - if (newCreditAmt == null) - newCreditAmt = invAmt; - else - newCreditAmt = newCreditAmt.add(invAmt); - // - log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt - + ") BP Life=" + bp.getActualLifeTimeValue() + "->" + newLifeAmt - + ", Credit=" + bp.getSO_CreditUsed() + "->" + newCreditAmt - + ", Balance=" + bp.getTotalOpenBalance(false) + " -> " + newBalance); - bp.setActualLifeTimeValue(newLifeAmt); - bp.setSO_CreditUsed(newCreditAmt); - } // SO - else - { - newBalance = newBalance.subtract(invAmt); - log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt - + ") Balance=" + bp.getTotalOpenBalance(false) + " -> " + newBalance); - } - bp.setTotalOpenBalance(newBalance); - bp.setSOCreditStatus(); - if (!bp.save(get_TrxName())) - { - m_processMsg = "Could not update Business Partner"; - return DocAction.STATUS_Invalid; - } - - // User - Last Result/Contact - if (getAD_User_ID() != 0) - { - MUser user = new MUser (getCtx(), getAD_User_ID(), get_TrxName()); - user.setLastContact(new Timestamp(System.currentTimeMillis())); - user.setLastResult(Msg.translate(getCtx(), "C_Invoice_ID") + ": " + getDocumentNo()); - if (!user.save(get_TrxName())) - { - m_processMsg = "Could not update Business Partner User"; - return DocAction.STATUS_Invalid; - } - } // user - - // Update Project - if (isSOTrx() && getC_Project_ID() != 0) - { - MProject project = new MProject (getCtx(), getC_Project_ID(), get_TrxName()); - BigDecimal amt = getGrandTotal(true); - int C_CurrencyTo_ID = project.getC_Currency_ID(); - if (C_CurrencyTo_ID != getC_Currency_ID()) - amt = MConversionRate.convert(getCtx(), amt, getC_Currency_ID(), C_CurrencyTo_ID, - getDateAcct(), 0, getAD_Client_ID(), getAD_Org_ID()); - if (amt == null) - { - m_processMsg = "Could not convert C_Currency_ID=" + getC_Currency_ID() - + " to Project C_Currency_ID=" + C_CurrencyTo_ID; - return DocAction.STATUS_Invalid; - } - BigDecimal newAmt = project.getInvoicedAmt(); - if (newAmt == null) - newAmt = amt; - else - newAmt = newAmt.add(amt); - log.fine("GrandTotal=" + getGrandTotal(true) + "(" + amt - + ") Project " + project.getName() - + " - Invoiced=" + project.getInvoicedAmt() + "->" + newAmt); - project.setInvoicedAmt(newAmt); - if (!project.save(get_TrxName())) - { - m_processMsg = "Could not update Project"; - return DocAction.STATUS_Invalid; - } - } // project - - // User Validation - String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE); - if (valid != null) - { - m_processMsg = valid; - return DocAction.STATUS_Invalid; - } - - // Set the definite document number after completed (if needed) - setDefiniteDocumentNo(); - - // Counter Documents - MInvoice counter = createCounterDoc(); - if (counter != null) - info.append(" - @CounterDoc@: @C_Invoice_ID@=").append(counter.getDocumentNo()); - - m_processMsg = info.toString().trim(); - setProcessed(true); - setDocAction(DOCACTION_Close); - return DocAction.STATUS_Completed; - } // completeIt + } + } // for all lines + if (matchInv > 0) + info.append(" @M_MatchInv_ID@#").append(matchInv).append(" "); + if (matchPO > 0) + info.append(" @M_MatchPO_ID@#").append(matchPO).append(" "); + + + + // Update BP Statistics + MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName()); + // Update total revenue and balance / credit limit (reversed on AllocationLine.processIt) + BigDecimal invAmt = MConversionRate.convertBase(getCtx(), getGrandTotal(true), // CM adjusted + getC_Currency_ID(), getDateAcct(), getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID()); + if (invAmt == null) + { + m_processMsg = "Could not convert C_Currency_ID=" + getC_Currency_ID() + + " to base C_Currency_ID=" + MClient.get(Env.getCtx()).getC_Currency_ID(); + return DocAction.STATUS_Invalid; + } + // Total Balance + BigDecimal newBalance = bp.getTotalOpenBalance(false); + if (newBalance == null) + newBalance = Env.ZERO; + if (isSOTrx()) + { + newBalance = newBalance.add(invAmt); + // + if (bp.getFirstSale() == null) + bp.setFirstSale(getDateInvoiced()); + BigDecimal newLifeAmt = bp.getActualLifeTimeValue(); + if (newLifeAmt == null) + newLifeAmt = invAmt; + else + newLifeAmt = newLifeAmt.add(invAmt); + BigDecimal newCreditAmt = bp.getSO_CreditUsed(); + if (newCreditAmt == null) + newCreditAmt = invAmt; + else + newCreditAmt = newCreditAmt.add(invAmt); + // + log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt + + ") BP Life=" + bp.getActualLifeTimeValue() + "->" + newLifeAmt + + ", Credit=" + bp.getSO_CreditUsed() + "->" + newCreditAmt + + ", Balance=" + bp.getTotalOpenBalance(false) + " -> " + newBalance); + bp.setActualLifeTimeValue(newLifeAmt); + bp.setSO_CreditUsed(newCreditAmt); + } // SO + else + { + newBalance = newBalance.subtract(invAmt); + log.fine("GrandTotal=" + getGrandTotal(true) + "(" + invAmt + + ") Balance=" + bp.getTotalOpenBalance(false) + " -> " + newBalance); + } + bp.setTotalOpenBalance(newBalance); + bp.setSOCreditStatus(); + if (!bp.save(get_TrxName())) + { + m_processMsg = "Could not update Business Partner"; + return DocAction.STATUS_Invalid; + } + + // User - Last Result/Contact + if (getAD_User_ID() != 0) + { + MUser user = new MUser (getCtx(), getAD_User_ID(), get_TrxName()); + user.setLastContact(new Timestamp(System.currentTimeMillis())); + user.setLastResult(Msg.translate(getCtx(), "C_Invoice_ID") + ": " + getDocumentNo()); + if (!user.save(get_TrxName())) + { + m_processMsg = "Could not update Business Partner User"; + return DocAction.STATUS_Invalid; + } + } // user + + // Update Project + if (isSOTrx() && getC_Project_ID() != 0) + { + MProject project = new MProject (getCtx(), getC_Project_ID(), get_TrxName()); + BigDecimal amt = getGrandTotal(true); + int C_CurrencyTo_ID = project.getC_Currency_ID(); + if (C_CurrencyTo_ID != getC_Currency_ID()) + amt = MConversionRate.convert(getCtx(), amt, getC_Currency_ID(), C_CurrencyTo_ID, + getDateAcct(), 0, getAD_Client_ID(), getAD_Org_ID()); + if (amt == null) + { + m_processMsg = "Could not convert C_Currency_ID=" + getC_Currency_ID() + + " to Project C_Currency_ID=" + C_CurrencyTo_ID; + return DocAction.STATUS_Invalid; + } + BigDecimal newAmt = project.getInvoicedAmt(); + if (newAmt == null) + newAmt = amt; + else + newAmt = newAmt.add(amt); + log.fine("GrandTotal=" + getGrandTotal(true) + "(" + amt + + ") Project " + project.getName() + + " - Invoiced=" + project.getInvoicedAmt() + "->" + newAmt); + project.setInvoicedAmt(newAmt); + if (!project.save(get_TrxName())) + { + m_processMsg = "Could not update Project"; + return DocAction.STATUS_Invalid; + } + } // project + + // User Validation + String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE); + if (valid != null) + { + m_processMsg = valid; + return DocAction.STATUS_Invalid; + } + + // Set the definite document number after completed (if needed) + setDefiniteDocumentNo(); + + // Counter Documents + MInvoice counter = createCounterDoc(); + if (counter != null) + info.append(" - @CounterDoc@: @C_Invoice_ID@=").append(counter.getDocumentNo()); + + m_processMsg = info.toString().trim(); + setProcessed(true); + setDocAction(DOCACTION_Close); + return DocAction.STATUS_Completed; + } // completeIt // Elaine 2008/6/20 private String createMatchInvCostDetail(MMatchInv inv, MInvoiceLine m_invoiceLine, MInOutLine m_receiptLine) @@ -1956,52 +1945,52 @@ public class MInvoice extends X_C_Invoice implements DocAction .abs(); if (multiplier.compareTo(Env.ONE) != 0) LineNetAmt = LineNetAmt.multiply(multiplier); - - // Source from Doc_MatchInv.createFacts(MAcctSchema) - // Cost Detail Record - data from Expense/IncClearing (CR) record - // MZ Goodwill - // Create Cost Detail Matched Invoice using Total Amount and Total Qty based on InvoiceLine - MMatchInv[] mInv = MMatchInv.getInvoiceLine(getCtx(), m_invoiceLine.getC_InvoiceLine_ID(), inv.get_TrxName()); - BigDecimal tQty = Env.ZERO; - BigDecimal tAmt = Env.ZERO; - for (int i = 0 ; i < mInv.length ; i++) - { - if (mInv[i].isPosted() && mInv[i].getM_MatchInv_ID() != get_ID()) - { - tQty = tQty.add(mInv[i].getQty()); - multiplier = mInv[i].getQty() - .divide(m_invoiceLine.getQtyInvoiced(), 12, BigDecimal.ROUND_HALF_UP).abs(); - tAmt = tAmt.add(m_invoiceLine.getLineNetAmt().multiply(multiplier)); - } - } + + // Source from Doc_MatchInv.createFacts(MAcctSchema) + // Cost Detail Record - data from Expense/IncClearing (CR) record + // MZ Goodwill + // Create Cost Detail Matched Invoice using Total Amount and Total Qty based on InvoiceLine + MMatchInv[] mInv = MMatchInv.getInvoiceLine(getCtx(), m_invoiceLine.getC_InvoiceLine_ID(), inv.get_TrxName()); + BigDecimal tQty = Env.ZERO; + BigDecimal tAmt = Env.ZERO; + for (int i = 0 ; i < mInv.length ; i++) + { + if (mInv[i].isPosted() && mInv[i].getM_MatchInv_ID() != get_ID()) + { + tQty = tQty.add(mInv[i].getQty()); + multiplier = mInv[i].getQty() + .divide(m_invoiceLine.getQtyInvoiced(), 12, BigDecimal.ROUND_HALF_UP).abs(); + tAmt = tAmt.add(m_invoiceLine.getLineNetAmt().multiply(multiplier)); + } + } - // Different currency - MInvoice invoice = m_invoiceLine.getParent(); - if (as.getC_Currency_ID() != invoice.getC_Currency_ID()) - { - tAmt = MConversionRate.convert(getCtx(), tAmt, - invoice.getC_Currency_ID(), as.getC_Currency_ID(), - invoice.getDateAcct(), invoice.getC_ConversionType_ID(), - invoice.getAD_Client_ID(), invoice.getAD_Org_ID()); - if (tAmt == null) - { - return "AP Invoice not convertible - " + as.getName(); - } - } - - tAmt = tAmt.add(LineNetAmt); //Invoice Price - // set Qty to negative value when MovementType is Vendor Returns - MInOut receipt = m_receiptLine.getParent(); - if (receipt.getMovementType().equals(MInOut.MOVEMENTTYPE_VendorReturns)) - tQty = tQty.add(inv.getQty().negate()); // Qty is set to negative value - else - tQty = tQty.add(inv.getQty()); + // Different currency + MInvoice invoice = m_invoiceLine.getParent(); + if (as.getC_Currency_ID() != invoice.getC_Currency_ID()) + { + tAmt = MConversionRate.convert(getCtx(), tAmt, + invoice.getC_Currency_ID(), as.getC_Currency_ID(), + invoice.getDateAcct(), invoice.getC_ConversionType_ID(), + invoice.getAD_Client_ID(), invoice.getAD_Org_ID()); + if (tAmt == null) + { + return "AP Invoice not convertible - " + as.getName(); + } + } - // Set Total Amount and Total Quantity from Matched Invoice - MCostDetail.createInvoice(as, getAD_Org_ID(), - inv.getM_Product_ID(), inv.getM_AttributeSetInstance_ID(), - m_invoiceLine.getC_InvoiceLine_ID(), 0, // No cost element - tAmt, tQty, getDescription(), inv.get_TrxName()); + tAmt = tAmt.add(LineNetAmt); //Invoice Price + // set Qty to negative value when MovementType is Vendor Returns + MInOut receipt = m_receiptLine.getParent(); + if (receipt.getMovementType().equals(MInOut.MOVEMENTTYPE_VendorReturns)) + tQty = tQty.add(inv.getQty().negate()); // Qty is set to negative value + else + tQty = tQty.add(inv.getQty()); + + // Set Total Amount and Total Quantity from Matched Invoice + MCostDetail.createInvoice(as, getAD_Org_ID(), + inv.getM_Product_ID(), inv.getM_AttributeSetInstance_ID(), + m_invoiceLine.getC_InvoiceLine_ID(), 0, // No cost element + tAmt, tQty, getDescription(), inv.get_TrxName()); // end MZ // end } @@ -2009,513 +1998,513 @@ public class MInvoice extends X_C_Invoice implements DocAction return ""; } // - - /** - * Set the definite document number after completed - */ - private void setDefiniteDocumentNo() { - MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); - if (dt.isOverwriteDateOnComplete()) { - setDateInvoiced(new Timestamp (System.currentTimeMillis())); - } - if (dt.isOverwriteSeqOnComplete()) { - String value = DB.getDocumentNo(getC_DocType_ID(), get_TrxName(), true, this); - if (value != null) - setDocumentNo(value); - } - } - - /** - * Create Counter Document - * @return counter invoice - */ - private MInvoice createCounterDoc() - { - // Is this a counter doc ? - if (getRef_Invoice_ID() != 0) - return null; - - // Org Must be linked to BPartner - MOrg org = MOrg.get(getCtx(), getAD_Org_ID()); - int counterC_BPartner_ID = org.getLinkedC_BPartner_ID(get_TrxName()); - if (counterC_BPartner_ID == 0) - return null; - // Business Partner needs to be linked to Org - MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), null); - int counterAD_Org_ID = bp.getAD_OrgBP_ID_Int(); - if (counterAD_Org_ID == 0) - return null; - - MBPartner counterBP = new MBPartner (getCtx(), counterC_BPartner_ID, null); - MOrgInfo counterOrgInfo = MOrgInfo.get(getCtx(), counterAD_Org_ID); - log.info("Counter BP=" + counterBP.getName()); - - // Document Type - int C_DocTypeTarget_ID = 0; - MDocTypeCounter counterDT = MDocTypeCounter.getCounterDocType(getCtx(), getC_DocType_ID()); - if (counterDT != null) - { - log.fine(counterDT.toString()); - if (!counterDT.isCreateCounter() || !counterDT.isValid()) - return null; - C_DocTypeTarget_ID = counterDT.getCounter_C_DocType_ID(); - } - else // indirect - { - C_DocTypeTarget_ID = MDocTypeCounter.getCounterDocType_ID(getCtx(), getC_DocType_ID()); - log.fine("Indirect C_DocTypeTarget_ID=" + C_DocTypeTarget_ID); - if (C_DocTypeTarget_ID <= 0) - return null; - } - - // Deep Copy - MInvoice counter = copyFrom(this, getDateInvoiced(), - C_DocTypeTarget_ID, !isSOTrx(), true, get_TrxName(), true); - // - counter.setAD_Org_ID(counterAD_Org_ID); - // counter.setM_Warehouse_ID(counterOrgInfo.getM_Warehouse_ID()); - // - counter.setBPartner(counterBP); - // Refernces (Should not be required - counter.setSalesRep_ID(getSalesRep_ID()); - counter.save(get_TrxName()); - - // Update copied lines - MInvoiceLine[] counterLines = counter.getLines(true); - for (int i = 0; i < counterLines.length; i++) - { - MInvoiceLine counterLine = counterLines[i]; - counterLine.setClientOrg(counter); - counterLine.setInvoice(counter); // copies header values (BP, etc.) - counterLine.setPrice(); - counterLine.setTax(); - // - counterLine.save(get_TrxName()); - } - - log.fine(counter.toString()); - - // Document Action - if (counterDT != null) - { - if (counterDT.getDocAction() != null) - { - counter.setDocAction(counterDT.getDocAction()); - counter.processIt(counterDT.getDocAction()); - counter.save(get_TrxName()); - } - } - return counter; - } // createCounterDoc - - /** - * Void Document. - * @return true if success - */ - public boolean voidIt() - { - log.info(toString()); - // Before Void - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID); - if (m_processMsg != null) - return false; - - if (DOCSTATUS_Closed.equals(getDocStatus()) - || DOCSTATUS_Reversed.equals(getDocStatus()) - || DOCSTATUS_Voided.equals(getDocStatus())) - { - m_processMsg = "Document Closed: " + getDocStatus(); - setDocAction(DOCACTION_None); - return false; - } - - // Not Processed - if (DOCSTATUS_Drafted.equals(getDocStatus()) - || DOCSTATUS_Invalid.equals(getDocStatus()) - || DOCSTATUS_InProgress.equals(getDocStatus()) - || DOCSTATUS_Approved.equals(getDocStatus()) - || DOCSTATUS_NotApproved.equals(getDocStatus()) ) - { - // Set lines to 0 - MInvoiceLine[] lines = getLines(false); - for (int i = 0; i < lines.length; i++) - { - MInvoiceLine line = lines[i]; - BigDecimal old = line.getQtyInvoiced(); - if (old.compareTo(Env.ZERO) != 0) - { - line.setQty(Env.ZERO); - line.setTaxAmt(Env.ZERO); - line.setLineNetAmt(Env.ZERO); - line.setLineTotalAmt(Env.ZERO); - line.addDescription(Msg.getMsg(getCtx(), "Voided") + " (" + old + ")"); - // Unlink Shipment - if (line.getM_InOutLine_ID() != 0) - { - MInOutLine ioLine = new MInOutLine(getCtx(), line.getM_InOutLine_ID(), get_TrxName()); - ioLine.setIsInvoiced(false); - ioLine.save(get_TrxName()); - line.setM_InOutLine_ID(0); - } - line.save(get_TrxName()); - } - } - addDescription(Msg.getMsg(getCtx(), "Voided")); - setIsPaid(true); - setC_Payment_ID(0); - } - else - { - return reverseCorrectIt(); - } - - // After Void - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_VOID); - if (m_processMsg != null) - return false; - - setProcessed(true); - setDocAction(DOCACTION_None); - return true; - } // voidIt - - /** - * Close Document. - * @return true if success - */ - public boolean closeIt() - { - log.info(toString()); - // Before Close - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_CLOSE); - if (m_processMsg != null) - return false; - - // After Close - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_CLOSE); - if (m_processMsg != null) - return false; - - setProcessed(true); - setDocAction(DOCACTION_None); - return true; - } // closeIt - - /** - * Reverse Correction - same date - * @return true if success - */ - public boolean reverseCorrectIt() - { - log.info(toString()); - // Before reverseCorrect - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSECORRECT); - if (m_processMsg != null) - return false; - - MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); - if (!MPeriod.isOpen(getCtx(), getDateAcct(), dt.getDocBaseType())) - { - m_processMsg = "@PeriodClosed@"; - return false; - } - // - MAllocationHdr[] allocations = MAllocationHdr.getOfInvoice(getCtx(), - getC_Invoice_ID(), get_TrxName()); - for (int i = 0; i < allocations.length; i++) - { - allocations[i].setDocAction(DocAction.ACTION_Reverse_Correct); - allocations[i].reverseCorrectIt(); - allocations[i].save(get_TrxName()); - } - // Reverse/Delete Matching - if (!isSOTrx()) - { - MMatchInv[] mInv = MMatchInv.getInvoice(getCtx(), getC_Invoice_ID(), get_TrxName()); - for (int i = 0; i < mInv.length; i++) - mInv[i].delete(true); - MMatchPO[] mPO = MMatchPO.getInvoice(getCtx(), getC_Invoice_ID(), get_TrxName()); - for (int i = 0; i < mPO.length; i++) - { - if (mPO[i].getM_InOutLine_ID() == 0) - mPO[i].delete(true); - else - { - mPO[i].setC_InvoiceLine_ID(null); - mPO[i].save(get_TrxName()); - } - } - } - // - load(get_TrxName()); // reload allocation reversal info - - // Deep Copy - MInvoice reversal = copyFrom (this, getDateInvoiced(), - getC_DocType_ID(), isSOTrx(), false, get_TrxName(), true); - if (reversal == null) - { - m_processMsg = "Could not create Invoice Reversal"; - return false; - } - reversal.setReversal(true); - - // Reverse Line Qty - MInvoiceLine[] rLines = reversal.getLines(false); - for (int i = 0; i < rLines.length; i++) - { - MInvoiceLine rLine = rLines[i]; - rLine.setQtyEntered(rLine.getQtyEntered().negate()); - rLine.setQtyInvoiced(rLine.getQtyInvoiced().negate()); - rLine.setLineNetAmt(rLine.getLineNetAmt().negate()); - if (rLine.getTaxAmt() != null && rLine.getTaxAmt().compareTo(Env.ZERO) != 0) - rLine.setTaxAmt(rLine.getTaxAmt().negate()); - if (rLine.getLineTotalAmt() != null && rLine.getLineTotalAmt().compareTo(Env.ZERO) != 0) - rLine.setLineTotalAmt(rLine.getLineTotalAmt().negate()); - if (!rLine.save(get_TrxName())) - { - m_processMsg = "Could not correct Invoice Reversal Line"; - return false; - } - } - reversal.setC_Order_ID(getC_Order_ID()); - reversal.addDescription("{->" + getDocumentNo() + ")"); - // - if (!reversal.processIt(DocAction.ACTION_Complete)) - { - m_processMsg = "Reversal ERROR: " + reversal.getProcessMsg(); - return false; - } - reversal.setC_Payment_ID(0); - //FR1948157 - reversal.setReversal_ID(getC_Invoice_ID()); - reversal.setIsPaid(true); - reversal.closeIt(); - reversal.setProcessing (false); - reversal.setDocStatus(DOCSTATUS_Reversed); - reversal.setDocAction(DOCACTION_None); - reversal.save(get_TrxName()); - m_processMsg = reversal.getDocumentNo(); - // - addDescription("(" + reversal.getDocumentNo() + "<-)"); - - // Clean up Reversed (this) - MInvoiceLine[] iLines = getLines(false); - for (int i = 0; i < iLines.length; i++) - { - MInvoiceLine iLine = iLines[i]; - if (iLine.getM_InOutLine_ID() != 0) - { - MInOutLine ioLine = new MInOutLine(getCtx(), iLine.getM_InOutLine_ID(), get_TrxName()); - ioLine.setIsInvoiced(false); - ioLine.save(get_TrxName()); - // Reconsiliation - iLine.setM_InOutLine_ID(0); - iLine.save(get_TrxName()); - } - //AZ Goodwill - if (!isSOTrx()) - { - deleteMatchInvCostDetail(iLine); - } - } - setProcessed(true); - //FR1948157 - setReversal_ID(reversal.getC_Invoice_ID()); - setDocStatus(DOCSTATUS_Reversed); // may come from void - setDocAction(DOCACTION_None); - setC_Payment_ID(0); - setIsPaid(true); - - // Create Allocation - MAllocationHdr alloc = new MAllocationHdr(getCtx(), false, getDateAcct(), - getC_Currency_ID(), - Msg.translate(getCtx(), "C_Invoice_ID") + ": " + getDocumentNo() + "/" + reversal.getDocumentNo(), - get_TrxName()); - alloc.setAD_Org_ID(getAD_Org_ID()); - if (alloc.save()) - { - // Amount - BigDecimal gt = getGrandTotal(true); - if (!isSOTrx()) - gt = gt.negate(); - // Orig Line - MAllocationLine aLine = new MAllocationLine (alloc, gt, - Env.ZERO, Env.ZERO, Env.ZERO); - aLine.setC_Invoice_ID(getC_Invoice_ID()); - aLine.save(); - // Reversal Line - MAllocationLine rLine = new MAllocationLine (alloc, gt.negate(), - Env.ZERO, Env.ZERO, Env.ZERO); - rLine.setC_Invoice_ID(reversal.getC_Invoice_ID()); - rLine.save(); - // Process It - if (alloc.processIt(DocAction.ACTION_Complete)) - alloc.save(); - } - - // After reverseCorrect - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSECORRECT); - if (m_processMsg != null) - return false; - - return true; - } // reverseCorrectIt - - /** - * Reverse Accrual - none - * @return false - */ - public boolean reverseAccrualIt() - { - log.info(toString()); - // Before reverseAccrual - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSEACCRUAL); - if (m_processMsg != null) - return false; - - // After reverseAccrual - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSEACCRUAL); - if (m_processMsg != null) - return false; - - return false; - } // reverseAccrualIt - - /** - * Re-activate - * @return false - */ - public boolean reActivateIt() - { - log.info(toString()); - // Before reActivate - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REACTIVATE); - if (m_processMsg != null) - return false; - - // After reActivate - m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REACTIVATE); - if (m_processMsg != null) - return false; - - - return false; - } // reActivateIt - - - /************************************************************************* - * Get Summary - * @return Summary of Document - */ - public String getSummary() - { - StringBuffer sb = new StringBuffer(); - sb.append(getDocumentNo()); - // : Grand Total = 123.00 (#1) - sb.append(": "). - append(Msg.translate(getCtx(),"GrandTotal")).append("=").append(getGrandTotal()) - .append(" (#").append(getLines(false).length).append(")"); - // - Description - if (getDescription() != null && getDescription().length() > 0) - sb.append(" - ").append(getDescription()); - return sb.toString(); - } // getSummary - - /** - * Get Process Message - * @return clear text error message - */ - public String getProcessMsg() - { - return m_processMsg; - } // getProcessMsg - - /** - * Get Document Owner (Responsible) - * @return AD_User_ID - */ - public int getDoc_User_ID() - { - return getSalesRep_ID(); - } // getDoc_User_ID - - /** - * Get Document Approval Amount - * @return amount - */ - public BigDecimal getApprovalAmt() - { - return getGrandTotal(); - } // getApprovalAmt - - /** - * - * @param rma - */ - public void setRMA(MRMA rma) - { - setM_RMA_ID(rma.getM_RMA_ID()); - setAD_Org_ID(rma.getAD_Org_ID()); - setDescription(rma.getDescription()); - setC_BPartner_ID(rma.getC_BPartner_ID()); - setSalesRep_ID(rma.getSalesRep_ID()); - - setGrandTotal(rma.getAmt()); - setIsSOTrx(rma.isSOTrx()); - setTotalLines(rma.getAmt()); - - MInvoice originalInvoice = rma.getOriginalInvoice(); - - if (originalInvoice == null) - { - throw new IllegalStateException("Not invoiced - RMA: " + rma.getDocumentNo()); - } - - setC_BPartner_Location_ID(originalInvoice.getC_BPartner_Location_ID()); - setAD_User_ID(originalInvoice.getAD_User_ID()); - setC_Currency_ID(originalInvoice.getC_Currency_ID()); - setIsTaxIncluded(originalInvoice.isTaxIncluded()); - setM_PriceList_ID(originalInvoice.getM_PriceList_ID()); - setC_Project_ID(originalInvoice.getC_Project_ID()); - setC_Activity_ID(originalInvoice.getC_Activity_ID()); - setC_Campaign_ID(originalInvoice.getC_Campaign_ID()); - setUser1_ID(originalInvoice.getUser1_ID()); - setUser2_ID(originalInvoice.getUser2_ID()); - } - - //AZ Goodwill - private String deleteMatchInvCostDetail(MInvoiceLine line) - { - // Get Account Schemas to delete MCostDetail - MAcctSchema[] acctschemas = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID()); - for(int asn = 0; asn < acctschemas.length; asn++) - { - MAcctSchema as = acctschemas[asn]; - - boolean skip = false; - if (as.getAD_OrgOnly_ID() != 0) - { - if (as.getOnlyOrgs() == null) - as.setOnlyOrgs(MReportTree.getChildIDs(getCtx(), - 0, MAcctSchemaElement.ELEMENTTYPE_Organization, - as.getAD_OrgOnly_ID())); - skip = as.isSkipOrg(getAD_Org_ID()); - } - if (skip) - continue; - - // update/delete Cost Detail and recalculate Current Cost - MCostDetail cd = MCostDetail.get (getCtx(), "C_InvoiceLine_ID=?", - line.getC_InvoiceLine_ID(), line.getM_AttributeSetInstance_ID(), - as.getC_AcctSchema_ID(), get_TrxName()); - if (cd != null) - { - cd.setProcessed(false); - cd.delete(true); - } - } - - return ""; - } - -} // MInvoice + + /** + * Set the definite document number after completed + */ + private void setDefiniteDocumentNo() { + MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); + if (dt.isOverwriteDateOnComplete()) { + setDateInvoiced(new Timestamp (System.currentTimeMillis())); + } + if (dt.isOverwriteSeqOnComplete()) { + String value = DB.getDocumentNo(getC_DocType_ID(), get_TrxName(), true, this); + if (value != null) + setDocumentNo(value); + } + } + + /** + * Create Counter Document + * @return counter invoice + */ + private MInvoice createCounterDoc() + { + // Is this a counter doc ? + if (getRef_Invoice_ID() != 0) + return null; + + // Org Must be linked to BPartner + MOrg org = MOrg.get(getCtx(), getAD_Org_ID()); + int counterC_BPartner_ID = org.getLinkedC_BPartner_ID(get_TrxName()); + if (counterC_BPartner_ID == 0) + return null; + // Business Partner needs to be linked to Org + MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), null); + int counterAD_Org_ID = bp.getAD_OrgBP_ID_Int(); + if (counterAD_Org_ID == 0) + return null; + + MBPartner counterBP = new MBPartner (getCtx(), counterC_BPartner_ID, null); + MOrgInfo counterOrgInfo = MOrgInfo.get(getCtx(), counterAD_Org_ID); + log.info("Counter BP=" + counterBP.getName()); + + // Document Type + int C_DocTypeTarget_ID = 0; + MDocTypeCounter counterDT = MDocTypeCounter.getCounterDocType(getCtx(), getC_DocType_ID()); + if (counterDT != null) + { + log.fine(counterDT.toString()); + if (!counterDT.isCreateCounter() || !counterDT.isValid()) + return null; + C_DocTypeTarget_ID = counterDT.getCounter_C_DocType_ID(); + } + else // indirect + { + C_DocTypeTarget_ID = MDocTypeCounter.getCounterDocType_ID(getCtx(), getC_DocType_ID()); + log.fine("Indirect C_DocTypeTarget_ID=" + C_DocTypeTarget_ID); + if (C_DocTypeTarget_ID <= 0) + return null; + } + + // Deep Copy + MInvoice counter = copyFrom(this, getDateInvoiced(), + C_DocTypeTarget_ID, !isSOTrx(), true, get_TrxName(), true); + // + counter.setAD_Org_ID(counterAD_Org_ID); + // counter.setM_Warehouse_ID(counterOrgInfo.getM_Warehouse_ID()); + // + counter.setBPartner(counterBP); + // Refernces (Should not be required + counter.setSalesRep_ID(getSalesRep_ID()); + counter.save(get_TrxName()); + + // Update copied lines + MInvoiceLine[] counterLines = counter.getLines(true); + for (int i = 0; i < counterLines.length; i++) + { + MInvoiceLine counterLine = counterLines[i]; + counterLine.setClientOrg(counter); + counterLine.setInvoice(counter); // copies header values (BP, etc.) + counterLine.setPrice(); + counterLine.setTax(); + // + counterLine.save(get_TrxName()); + } + + log.fine(counter.toString()); + + // Document Action + if (counterDT != null) + { + if (counterDT.getDocAction() != null) + { + counter.setDocAction(counterDT.getDocAction()); + counter.processIt(counterDT.getDocAction()); + counter.save(get_TrxName()); + } + } + return counter; + } // createCounterDoc + + /** + * Void Document. + * @return true if success + */ + public boolean voidIt() + { + log.info(toString()); + // Before Void + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID); + if (m_processMsg != null) + return false; + + if (DOCSTATUS_Closed.equals(getDocStatus()) + || DOCSTATUS_Reversed.equals(getDocStatus()) + || DOCSTATUS_Voided.equals(getDocStatus())) + { + m_processMsg = "Document Closed: " + getDocStatus(); + setDocAction(DOCACTION_None); + return false; + } + + // Not Processed + if (DOCSTATUS_Drafted.equals(getDocStatus()) + || DOCSTATUS_Invalid.equals(getDocStatus()) + || DOCSTATUS_InProgress.equals(getDocStatus()) + || DOCSTATUS_Approved.equals(getDocStatus()) + || DOCSTATUS_NotApproved.equals(getDocStatus()) ) + { + // Set lines to 0 + MInvoiceLine[] lines = getLines(false); + for (int i = 0; i < lines.length; i++) + { + MInvoiceLine line = lines[i]; + BigDecimal old = line.getQtyInvoiced(); + if (old.compareTo(Env.ZERO) != 0) + { + line.setQty(Env.ZERO); + line.setTaxAmt(Env.ZERO); + line.setLineNetAmt(Env.ZERO); + line.setLineTotalAmt(Env.ZERO); + line.addDescription(Msg.getMsg(getCtx(), "Voided") + " (" + old + ")"); + // Unlink Shipment + if (line.getM_InOutLine_ID() != 0) + { + MInOutLine ioLine = new MInOutLine(getCtx(), line.getM_InOutLine_ID(), get_TrxName()); + ioLine.setIsInvoiced(false); + ioLine.save(get_TrxName()); + line.setM_InOutLine_ID(0); + } + line.save(get_TrxName()); + } + } + addDescription(Msg.getMsg(getCtx(), "Voided")); + setIsPaid(true); + setC_Payment_ID(0); + } + else + { + return reverseCorrectIt(); + } + + // After Void + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_VOID); + if (m_processMsg != null) + return false; + + setProcessed(true); + setDocAction(DOCACTION_None); + return true; + } // voidIt + + /** + * Close Document. + * @return true if success + */ + public boolean closeIt() + { + log.info(toString()); + // Before Close + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_CLOSE); + if (m_processMsg != null) + return false; + + // After Close + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_CLOSE); + if (m_processMsg != null) + return false; + + setProcessed(true); + setDocAction(DOCACTION_None); + return true; + } // closeIt + + /** + * Reverse Correction - same date + * @return true if success + */ + public boolean reverseCorrectIt() + { + log.info(toString()); + // Before reverseCorrect + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSECORRECT); + if (m_processMsg != null) + return false; + + MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); + if (!MPeriod.isOpen(getCtx(), getDateAcct(), dt.getDocBaseType())) + { + m_processMsg = "@PeriodClosed@"; + return false; + } + // + MAllocationHdr[] allocations = MAllocationHdr.getOfInvoice(getCtx(), + getC_Invoice_ID(), get_TrxName()); + for (int i = 0; i < allocations.length; i++) + { + allocations[i].setDocAction(DocAction.ACTION_Reverse_Correct); + allocations[i].reverseCorrectIt(); + allocations[i].save(get_TrxName()); + } + // Reverse/Delete Matching + if (!isSOTrx()) + { + MMatchInv[] mInv = MMatchInv.getInvoice(getCtx(), getC_Invoice_ID(), get_TrxName()); + for (int i = 0; i < mInv.length; i++) + mInv[i].delete(true); + MMatchPO[] mPO = MMatchPO.getInvoice(getCtx(), getC_Invoice_ID(), get_TrxName()); + for (int i = 0; i < mPO.length; i++) + { + if (mPO[i].getM_InOutLine_ID() == 0) + mPO[i].delete(true); + else + { + mPO[i].setC_InvoiceLine_ID(null); + mPO[i].save(get_TrxName()); + } + } + } + // + load(get_TrxName()); // reload allocation reversal info + + // Deep Copy + MInvoice reversal = copyFrom (this, getDateInvoiced(), + getC_DocType_ID(), isSOTrx(), false, get_TrxName(), true); + if (reversal == null) + { + m_processMsg = "Could not create Invoice Reversal"; + return false; + } + reversal.setReversal(true); + + // Reverse Line Qty + MInvoiceLine[] rLines = reversal.getLines(false); + for (int i = 0; i < rLines.length; i++) + { + MInvoiceLine rLine = rLines[i]; + rLine.setQtyEntered(rLine.getQtyEntered().negate()); + rLine.setQtyInvoiced(rLine.getQtyInvoiced().negate()); + rLine.setLineNetAmt(rLine.getLineNetAmt().negate()); + if (rLine.getTaxAmt() != null && rLine.getTaxAmt().compareTo(Env.ZERO) != 0) + rLine.setTaxAmt(rLine.getTaxAmt().negate()); + if (rLine.getLineTotalAmt() != null && rLine.getLineTotalAmt().compareTo(Env.ZERO) != 0) + rLine.setLineTotalAmt(rLine.getLineTotalAmt().negate()); + if (!rLine.save(get_TrxName())) + { + m_processMsg = "Could not correct Invoice Reversal Line"; + return false; + } + } + reversal.setC_Order_ID(getC_Order_ID()); + reversal.addDescription("{->" + getDocumentNo() + ")"); + // + if (!reversal.processIt(DocAction.ACTION_Complete)) + { + m_processMsg = "Reversal ERROR: " + reversal.getProcessMsg(); + return false; + } + reversal.setC_Payment_ID(0); + //FR1948157 + reversal.setReversal_ID(getC_Invoice_ID()); + reversal.setIsPaid(true); + reversal.closeIt(); + reversal.setProcessing (false); + reversal.setDocStatus(DOCSTATUS_Reversed); + reversal.setDocAction(DOCACTION_None); + reversal.save(get_TrxName()); + m_processMsg = reversal.getDocumentNo(); + // + addDescription("(" + reversal.getDocumentNo() + "<-)"); + + // Clean up Reversed (this) + MInvoiceLine[] iLines = getLines(false); + for (int i = 0; i < iLines.length; i++) + { + MInvoiceLine iLine = iLines[i]; + if (iLine.getM_InOutLine_ID() != 0) + { + MInOutLine ioLine = new MInOutLine(getCtx(), iLine.getM_InOutLine_ID(), get_TrxName()); + ioLine.setIsInvoiced(false); + ioLine.save(get_TrxName()); + // Reconsiliation + iLine.setM_InOutLine_ID(0); + iLine.save(get_TrxName()); + } + //AZ Goodwill + if (!isSOTrx()) + { + deleteMatchInvCostDetail(iLine); + } + } + setProcessed(true); + //FR1948157 + setReversal_ID(reversal.getC_Invoice_ID()); + setDocStatus(DOCSTATUS_Reversed); // may come from void + setDocAction(DOCACTION_None); + setC_Payment_ID(0); + setIsPaid(true); + + // Create Allocation + MAllocationHdr alloc = new MAllocationHdr(getCtx(), false, getDateAcct(), + getC_Currency_ID(), + Msg.translate(getCtx(), "C_Invoice_ID") + ": " + getDocumentNo() + "/" + reversal.getDocumentNo(), + get_TrxName()); + alloc.setAD_Org_ID(getAD_Org_ID()); + if (alloc.save()) + { + // Amount + BigDecimal gt = getGrandTotal(true); + if (!isSOTrx()) + gt = gt.negate(); + // Orig Line + MAllocationLine aLine = new MAllocationLine (alloc, gt, + Env.ZERO, Env.ZERO, Env.ZERO); + aLine.setC_Invoice_ID(getC_Invoice_ID()); + aLine.save(); + // Reversal Line + MAllocationLine rLine = new MAllocationLine (alloc, gt.negate(), + Env.ZERO, Env.ZERO, Env.ZERO); + rLine.setC_Invoice_ID(reversal.getC_Invoice_ID()); + rLine.save(); + // Process It + if (alloc.processIt(DocAction.ACTION_Complete)) + alloc.save(); + } + + // After reverseCorrect + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSECORRECT); + if (m_processMsg != null) + return false; + + return true; + } // reverseCorrectIt + + /** + * Reverse Accrual - none + * @return false + */ + public boolean reverseAccrualIt() + { + log.info(toString()); + // Before reverseAccrual + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSEACCRUAL); + if (m_processMsg != null) + return false; + + // After reverseAccrual + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSEACCRUAL); + if (m_processMsg != null) + return false; + + return false; + } // reverseAccrualIt + + /** + * Re-activate + * @return false + */ + public boolean reActivateIt() + { + log.info(toString()); + // Before reActivate + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REACTIVATE); + if (m_processMsg != null) + return false; + + // After reActivate + m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REACTIVATE); + if (m_processMsg != null) + return false; + + + return false; + } // reActivateIt + + + /************************************************************************* + * Get Summary + * @return Summary of Document + */ + public String getSummary() + { + StringBuffer sb = new StringBuffer(); + sb.append(getDocumentNo()); + // : Grand Total = 123.00 (#1) + sb.append(": "). + append(Msg.translate(getCtx(),"GrandTotal")).append("=").append(getGrandTotal()) + .append(" (#").append(getLines(false).length).append(")"); + // - Description + if (getDescription() != null && getDescription().length() > 0) + sb.append(" - ").append(getDescription()); + return sb.toString(); + } // getSummary + + /** + * Get Process Message + * @return clear text error message + */ + public String getProcessMsg() + { + return m_processMsg; + } // getProcessMsg + + /** + * Get Document Owner (Responsible) + * @return AD_User_ID + */ + public int getDoc_User_ID() + { + return getSalesRep_ID(); + } // getDoc_User_ID + + /** + * Get Document Approval Amount + * @return amount + */ + public BigDecimal getApprovalAmt() + { + return getGrandTotal(); + } // getApprovalAmt + + /** + * + * @param rma + */ + public void setRMA(MRMA rma) + { + setM_RMA_ID(rma.getM_RMA_ID()); + setAD_Org_ID(rma.getAD_Org_ID()); + setDescription(rma.getDescription()); + setC_BPartner_ID(rma.getC_BPartner_ID()); + setSalesRep_ID(rma.getSalesRep_ID()); + + setGrandTotal(rma.getAmt()); + setIsSOTrx(rma.isSOTrx()); + setTotalLines(rma.getAmt()); + + MInvoice originalInvoice = rma.getOriginalInvoice(); + + if (originalInvoice == null) + { + throw new IllegalStateException("Not invoiced - RMA: " + rma.getDocumentNo()); + } + + setC_BPartner_Location_ID(originalInvoice.getC_BPartner_Location_ID()); + setAD_User_ID(originalInvoice.getAD_User_ID()); + setC_Currency_ID(originalInvoice.getC_Currency_ID()); + setIsTaxIncluded(originalInvoice.isTaxIncluded()); + setM_PriceList_ID(originalInvoice.getM_PriceList_ID()); + setC_Project_ID(originalInvoice.getC_Project_ID()); + setC_Activity_ID(originalInvoice.getC_Activity_ID()); + setC_Campaign_ID(originalInvoice.getC_Campaign_ID()); + setUser1_ID(originalInvoice.getUser1_ID()); + setUser2_ID(originalInvoice.getUser2_ID()); + } + + //AZ Goodwill + private String deleteMatchInvCostDetail(MInvoiceLine line) + { + // Get Account Schemas to delete MCostDetail + MAcctSchema[] acctschemas = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID()); + for(int asn = 0; asn < acctschemas.length; asn++) + { + MAcctSchema as = acctschemas[asn]; + + boolean skip = false; + if (as.getAD_OrgOnly_ID() != 0) + { + if (as.getOnlyOrgs() == null) + as.setOnlyOrgs(MReportTree.getChildIDs(getCtx(), + 0, MAcctSchemaElement.ELEMENTTYPE_Organization, + as.getAD_OrgOnly_ID())); + skip = as.isSkipOrg(getAD_Org_ID()); + } + if (skip) + continue; + + // update/delete Cost Detail and recalculate Current Cost + MCostDetail cd = MCostDetail.get (getCtx(), "C_InvoiceLine_ID=?", + line.getC_InvoiceLine_ID(), line.getM_AttributeSetInstance_ID(), + as.getC_AcctSchema_ID(), get_TrxName()); + if (cd != null) + { + cd.setProcessed(false); + cd.delete(true); + } + } + + return ""; + } + +} // MInvoice diff --git a/base/src/org/eevolution/process/InvoiceCalculateTax.java b/base/src/org/eevolution/process/InvoiceCalculateTax.java index 7c2a59fa00..f941fe8d40 100644 --- a/base/src/org/eevolution/process/InvoiceCalculateTax.java +++ b/base/src/org/eevolution/process/InvoiceCalculateTax.java @@ -17,249 +17,53 @@ package org.eevolution.process; -import java.util.ArrayList; -import java.util.Properties; -import java.math.BigDecimal; - - -import org.compiere.model.*; +import org.compiere.model.MBPartner; +import org.compiere.model.MInvoice; import org.compiere.process.ProcessInfoParameter; import org.compiere.process.SvrProcess; -import org.compiere.util.DB; -import org.compiere.util.Env; -import org.compiere.util.*; /** - * Invoice Calculate Tax let re calculate Tax Invoice - * - * @author Victor Perez + * Invoice Calculate Tax let re calculate Tax Invoice + * @author Victor Perez + * @author Teo Sarca, www.arhipac.ro */ -public class InvoiceCalculateTax extends SvrProcess { - - - private static final Properties ctx = Env.getCtx(); - - //private static final String AD_Client_ID = ctx.getProperty("#AD_Client_ID"); - //private static final String AD_Org_ID = ctx.getProperty("#AD_Org_ID"); - int p_C_Invoice_ID = 0; - private MInvoiceTax[] m_taxes; - /** - * Financial Report Constructor - */ - public InvoiceCalculateTax() - { - super(); - log.info(" "); - } // FinBalance +public class InvoiceCalculateTax extends SvrProcess +{ + private int p_C_Invoice_ID = 0; - - /** - * Prepare - e.g., get Parameters. - */ + @Override protected void prepare() { - - ProcessInfoParameter[] para = getParameter(); - for (int i = 0; i < para.length; i++) - { - String name = para[i].getParameterName(); - if (para[i].getParameter() == null) - ; - else if (name.equals("C_Invoice_ID")) - p_C_Invoice_ID = para[i].getParameterAsInt(); - } - + for (ProcessInfoParameter para : getParameter()) + { + String name = para.getParameterName(); + if (para.getParameter() == null) + { + ; + } + else if (name.equals("C_Invoice_ID")) + { + p_C_Invoice_ID = para.getParameterAsInt(); + } + } + } // prepare - /** - * Perform process. - * @return Message (clear text) - * @throws Exception if not successful - */ - protected String doIt() throws Exception { - - calculateTaxTotal(p_C_Invoice_ID); + @Override + protected String doIt() throws Exception + { + MInvoice invoice = new MInvoice(getCtx(), p_C_Invoice_ID, get_TrxName()); + invoice.calculateTaxTotal(); + invoice.saveEx(); + // + // Update balance + MBPartner bp = new MBPartner (getCtx(), invoice.getC_BPartner_ID(), get_TrxName()); + bp.setTotalOpenBalance(); + bp.setSOCreditStatus(); + bp.saveEx(); + // return "@ProcessOK@"; } // doIt - - /** - * Calculate Tax and Total - * @return true if calculated - */ - private boolean calculateTaxTotal(int C_Invoice_ID) - { - Trx trx = Trx.get("retax", true); - - MInvoice inv = new MInvoice(Env.getCtx(),C_Invoice_ID,trx.getTrxName()); - updateBalance(inv, -1 , trx.getTrxName()); - log.fine(""); - // Delete Taxes - DB.executeUpdate("DELETE C_InvoiceTax WHERE C_Invoice_ID=" + inv.getC_Invoice_ID(), trx.getTrxName()); - m_taxes = null; - - // Lines - BigDecimal totalLines = Env.ZERO; - ArrayList taxList = new ArrayList(); - MInvoiceLine[] lines = inv.getLines(false); - for (int i = 0; i < lines.length; i++) - { - MInvoiceLine line = lines[i]; - /** Sync ownership for SO - if (isSOTrx() && line.getAD_Org_ID() != getAD_Org_ID()) - { - line.setAD_Org_ID(getAD_Org_ID()); - line.save(); - } **/ - Integer taxID = new Integer(line.getC_Tax_ID()); - if (!taxList.contains(taxID)) - { - MInvoiceTax iTax = MInvoiceTax.get (line, inv.getPrecision(), - false, trx.getTrxName()); // current Tax - if (iTax != null) - { - iTax.setIsTaxIncluded(inv.isTaxIncluded()); - iTax.setAD_Org_ID(inv.getAD_Org_ID()); - if (!iTax.calculateTaxFromLines()) - return false; - if (!iTax.save()) - return false; - taxList.add(taxID); - } - } - totalLines = totalLines.add(line.getLineNetAmt()); - } - - // Taxes - BigDecimal grandTotal = totalLines; - MInvoiceTax[] taxes = inv.getTaxes(true); - for (int i = 0; i < taxes.length; i++) - { - MInvoiceTax iTax = taxes[i]; - //MTax tax = iTax.getTax(); - MTax tax = MTax.get(Env.getCtx(), iTax.getC_Tax_ID()); - - if (tax.isSummary()) - { - MTax[] cTaxes = tax.getChildTaxes(false); // Multiple taxes - for (int j = 0; j < cTaxes.length; j++) - { - MTax cTax = cTaxes[j]; - BigDecimal taxAmt = cTax.calculateTax(iTax.getTaxBaseAmt(), inv.isTaxIncluded(), inv.getPrecision()); - // - MInvoiceTax newITax = new MInvoiceTax(Env.getCtx(), 0, trx.getTrxName()); - //newITax.setClientOrg(this); - newITax.setC_Invoice_ID(inv.getC_Invoice_ID()); - newITax.setC_Tax_ID(cTax.getC_Tax_ID()); - //newITax.setPrecision(inv.getPrecision()); - newITax.setIsTaxIncluded(inv.isTaxIncluded()); - newITax.setTaxBaseAmt(iTax.getTaxBaseAmt()); - newITax.setTaxAmt(taxAmt); - newITax.setAD_Org_ID(inv.getAD_Org_ID()); - if (!newITax.save()) - return false; - // - if (!inv.isTaxIncluded()) - grandTotal = grandTotal.add(taxAmt); - } - if (!iTax.delete(true, trx.getTrxName())) - return false; - } - else - { - if (!inv.isTaxIncluded()) - grandTotal = grandTotal.add(iTax.getTaxAmt()); - } - } - // - inv.setTotalLines(totalLines); - inv.setGrandTotal(grandTotal); - if(!inv.save()) - { - return false; - } - updateBalance(inv, 1 , trx.getTrxName()); - trx.commit(); - - return true; - - } // calculateTaxTotal - - private boolean updateBalance(MInvoice i , int factor , String trx_name) - { - - // Update BP Statistics - MBPartner bp = new MBPartner (Env.getCtx(), i.getC_BPartner_ID(), trx_name); - // Update total revenue and balance / credit limit (reversed on AllocationLine.processIt) - BigDecimal invAmt = MConversionRate.convertBase(Env.getCtx(), i.getGrandTotal(true).multiply(new BigDecimal(factor)), // CM adjusted - i.getC_Currency_ID(), i.getDateAcct(), i.getC_ConversionType_ID(), getAD_Client_ID(), i.getAD_Org_ID()); - if (invAmt == null) - { - return false; - } - // Total Balance - BigDecimal newBalance = bp.getTotalOpenBalance(false); - if (newBalance == null) - newBalance = Env.ZERO; - if (i.isSOTrx()) - { - newBalance = newBalance.add(invAmt); - // - if (bp.getFirstSale() == null) - bp.setFirstSale(i.getDateInvoiced()); - BigDecimal newLifeAmt = bp.getActualLifeTimeValue(); - if (newLifeAmt == null) - newLifeAmt = invAmt; - else - newLifeAmt = newLifeAmt.add(invAmt); - BigDecimal newCreditAmt = bp.getSO_CreditUsed(); - if (newCreditAmt == null) - newCreditAmt = invAmt; - else - newCreditAmt = newCreditAmt.add(invAmt); - // - log.fine("GrandTotal=" + i.getGrandTotal(true) + "(" + invAmt - + ") BP Life=" + bp.getActualLifeTimeValue() + "->" + newLifeAmt - + ", Credit=" + bp.getSO_CreditUsed() + "->" + newCreditAmt - + ", Balance=" + bp.getTotalOpenBalance(false) + " -> " + newBalance); - bp.setActualLifeTimeValue(newLifeAmt); - bp.setSO_CreditUsed(newCreditAmt); - } // SO - else - { - newBalance = newBalance.subtract(invAmt); - log.fine("GrandTotal=" + i.getGrandTotal(true) + "(" + invAmt - + ") Balance=" + bp.getTotalOpenBalance(false) + " -> " + newBalance); - } - bp.setTotalOpenBalance(newBalance); - bp.setSOCreditStatus(); - if (!bp.save()) - { - return false; - } - return true; - } - - - /************************************************************************** - * Test - * @param args ignored - */ - public static void main(String[] args) - { - org.compiere.Adempiere.startup(true); - InvoiceCalculateTax cs = new InvoiceCalculateTax(); - try - { - cs.doIt(); - } - catch (Exception e) - { - System.out.println("Error" + e.getMessage()); - } - - } // main - - }