/******************************************************************************
* 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.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.DBException;
import org.adempiere.exceptions.PeriodClosedException;
import org.compiere.acct.Doc;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.TimeUtil;
import org.compiere.util.Util;
/**
* Cost Detail Model
*
* @author Jorg Janke
* @author Armen Rizal, Goodwill Consulting
*
BF: 2431123 Return Trx changes weighted average cost
* BF: 1568752 Average invoice costing: landed costs incorrectly applied
* @author Armen Rizal and Bayu Cahya
* BF [ 2129781 ] Cost Detail not created properly for multi acc schema
* @author Teo Sarca
* BF [ 2847648 ] Manufacture and shipment cost errors
* https://sourceforge.net/p/adempiere/libero/237/
* @author red1 FR: [ 2214883 ] Remove SQL code and Replace for Query
* @version $Id: MCostDetail.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
*
*/
public class MCostDetail extends X_M_CostDetail
{
private static final long serialVersionUID = -7909571771846993407L;
protected static final String INOUTLINE_DOCBASETYPE_SQL =
"SELECT c.DocBaseType From M_InOut io " +
"INNER JOIN M_InOutLine iol ON io.M_InOut_ID=iol.M_InOut_ID " +
"INNER JOIN C_DocType c ON io.C_DocType_ID=c.C_DocType_ID " +
"WHERE iol.M_InOutLine_ID=?";
/**
* Create New Cost Detail record for Purchase Orders.
* Called from Doc_MatchPO.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param C_OrderLine_ID order
* @param M_CostElement_ID optional cost element for Freight
* @param Amt amt total amount
* @param Qty qty
* @param Description optional description
* @param trxName transaction
* @return true if created
* @deprecated
*/
@Deprecated
public static boolean createOrder (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int C_OrderLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, String trxName)
{
return createOrder (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, C_OrderLine_ID, M_CostElement_ID,
Amt, Qty, Description, null, 0, trxName);
}
/**
* Create New Cost Detail record for Purchase Orders.
* Called from Doc_MatchPO.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param C_OrderLine_ID order
* @param M_CostElement_ID optional cost element for Freight
* @param Amt amt total amount
* @param Qty qty
* @param Description optional description
* @param DateAcct account date
* @param Ref_CostDetail_ID reference cost detail
* @param trxName transaction
* @return true if created
*/
public static boolean createOrder (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int C_OrderLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, Timestamp DateAcct, int Ref_CostDetail_ID, String trxName)
{
MCostDetail cd = getOrder (as, M_Product_ID, M_AttributeSetInstance_ID, C_OrderLine_ID, M_CostElement_ID, DateAcct, trxName);
if (cd != null && !cd.isDelta() && Ref_CostDetail_ID > 0)
cd.setIsBackDate(true);
//
if (cd == null) // createNew
{
cd = new MCostDetail (as, AD_Org_ID,
M_Product_ID, M_AttributeSetInstance_ID,
M_CostElement_ID,
Amt, Qty, Description, DateAcct, Ref_CostDetail_ID, trxName);
cd.setC_OrderLine_ID (C_OrderLine_ID);
}
else
{
if (cd.isProcessed())
{
// set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty
cd.setDeltaAmt(Amt.subtract(cd.getAmt()));
cd.setDeltaQty(Qty.subtract(cd.getQty()));
}
else
{
cd.setDeltaAmt(BigDecimal.ZERO);
cd.setDeltaQty(BigDecimal.ZERO);
cd.setAmt(Amt);
cd.setQty(Qty);
}
if (cd.isDelta())
{
cd.setProcessed(false);
cd.setAmt(Amt);
cd.setQty(Qty);
}
else if (cd.isProcessed())
return true; // nothing to do
}
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
ok = cd.process();
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("(" + ok + ") " + cd);
return ok;
} // createOrder
/**
* Create New Cost Detail record for AP Invoices.
* Called from Doc_Invoice - for Invoice Adjustments.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param C_InvoiceLine_ID invoice
* @param M_CostElement_ID optional cost element for Freight
* @param Amt amt
* @param Qty qty
* @param Description optional description
* @param trxName transaction
* @return true if created
* @deprecated
*/
@Deprecated
public static boolean createInvoice (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int C_InvoiceLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, String trxName)
{
return createInvoice (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, C_InvoiceLine_ID, M_CostElement_ID,
Amt, Qty, Description, null, 0, trxName);
}
/**
* Create New Cost Detail record for AP Invoices.
* Called from Doc_Invoice - for Invoice Adjustments.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param C_InvoiceLine_ID invoice
* @param M_CostElement_ID optional cost element for Freight
* @param Amt amt
* @param Qty qty
* @param Description optional description
* @param DateAcct account date
* @param Ref_CostDetail_ID reference cost detail
* @param trxName transaction
* @return true if created
*/
public static boolean createInvoice (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int C_InvoiceLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, Timestamp DateAcct, int Ref_CostDetail_ID, String trxName)
{
MCostDetail cd = getInvoice (as, M_Product_ID, M_AttributeSetInstance_ID, C_InvoiceLine_ID, M_CostElement_ID, DateAcct, trxName);
if (cd != null && !cd.isDelta() && Ref_CostDetail_ID > 0)
cd.setIsBackDate(true);
//
if (cd == null) // createNew
{
cd = new MCostDetail (as, AD_Org_ID,
M_Product_ID, M_AttributeSetInstance_ID,
M_CostElement_ID,
Amt, Qty, Description, DateAcct, Ref_CostDetail_ID, trxName);
cd.setC_InvoiceLine_ID (C_InvoiceLine_ID);
}
else
{
if (cd.isProcessed())
{
// set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty
cd.setDeltaAmt(Amt.subtract(cd.getAmt()));
cd.setDeltaQty(Qty.subtract(cd.getQty()));
}
else
{
cd.setDeltaAmt(BigDecimal.ZERO);
cd.setDeltaQty(BigDecimal.ZERO);
cd.setAmt(Amt);
cd.setQty(Qty);
}
if (cd.isDelta())
{
cd.setProcessed(false);
cd.setAmt(Amt);
cd.setQty(Qty);
}
else if (cd.isProcessed())
return true; // nothing to do
}
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
ok = cd.process();
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("(" + ok + ") " + cd);
return ok;
} // createInvoice
/**
* Create New Cost Detail record for SO Shipments.
* Called from Doc_MInOut - for SO Shipments.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_InOutLine_ID shipment
* @param M_CostElement_ID optional cost element for Freight
* @param Amt amt
* @param Qty qty
* @param Description optional description
* @param IsSOTrx sales order
* @param trxName transaction
* @return true if no error
* @deprecated
*/
@Deprecated
public static boolean createShipment (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_InOutLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, boolean IsSOTrx, String trxName)
{
return createShipment (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, M_InOutLine_ID, M_CostElement_ID,
Amt, Qty, Description, IsSOTrx, null, 0, trxName);
}
/**
* Create New Cost Detail record for SO Shipments.
* Called from Doc_MInOut - for SO Shipments.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_InOutLine_ID shipment
* @param M_CostElement_ID optional cost element for Freight
* @param Amt amt
* @param Qty qty
* @param Description optional description
* @param IsSOTrx sales order
* @param DateAcct account date
* @param Ref_CostDetail_ID reference cost detail
* @param trxName transaction
* @return true if no error
*/
public static boolean createShipment (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_InOutLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, boolean IsSOTrx, Timestamp DateAcct, int Ref_CostDetail_ID, String trxName)
{
MCostDetail cd = getShipment (as, M_Product_ID, M_AttributeSetInstance_ID, M_InOutLine_ID, M_CostElement_ID, trxName);
//
if (cd == null) // createNew
{
cd = new MCostDetail (as, AD_Org_ID,
M_Product_ID, M_AttributeSetInstance_ID,
M_CostElement_ID,
Amt, Qty, Description, DateAcct, Ref_CostDetail_ID, trxName);
cd.setM_InOutLine_ID(M_InOutLine_ID);
cd.setIsSOTrx(IsSOTrx);
}
else
{
if (cd.isProcessed())
{
// set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty
cd.setDeltaAmt(Amt.subtract(cd.getAmt()));
cd.setDeltaQty(Qty.subtract(cd.getQty()));
}
else
{
cd.setDeltaAmt(BigDecimal.ZERO);
cd.setDeltaQty(BigDecimal.ZERO);
cd.setAmt(Amt);
cd.setQty(Qty);
}
if (cd.isDelta())
{
cd.setProcessed(false);
cd.setAmt(Amt);
cd.setQty(Qty);
}
else if (cd.isProcessed())
return true; // nothing to do
}
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
ok = cd.process();
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("(" + ok + ") " + cd);
return ok;
} // createShipment
/**
* Create New Cost Detail record for Physical Inventory.
* Called from Doc_Inventory.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_InventoryLine_ID order
* @param M_CostElement_ID optional cost element
* @param Amt amt total amount
* @param Qty qty
* @param Description optional description
* @param trxName transaction
* @return true if no error
* @deprecated
*/
@Deprecated
public static boolean createInventory (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_InventoryLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, String trxName)
{
return createInventory (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, M_InventoryLine_ID, M_CostElement_ID,
Amt, Qty, Description, null, 0, trxName);
}
/**
* Create New Cost Detail record for Physical Inventory.
* Called from Doc_Inventory.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_InventoryLine_ID order
* @param M_CostElement_ID optional cost element
* @param Amt amt total amount
* @param Qty qty
* @param Description optional description
* @param DateAcct account date
* @param Ref_CostDetail_ID reference cost detail
* @param trxName transaction
* @return true if no error
*/
public static boolean createInventory (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_InventoryLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, Timestamp DateAcct, int Ref_CostDetail_ID, String trxName)
{
MCostDetail cd = getInventory (as, M_Product_ID, M_AttributeSetInstance_ID, M_InventoryLine_ID, M_CostElement_ID, trxName);
//
if (cd == null) // createNew
{
cd = new MCostDetail (as, AD_Org_ID,
M_Product_ID, M_AttributeSetInstance_ID,
M_CostElement_ID,
Amt, Qty, Description, DateAcct, Ref_CostDetail_ID, trxName);
cd.setM_InventoryLine_ID(M_InventoryLine_ID);
}
else
{
if (cd.isProcessed())
{
// set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty
cd.setDeltaAmt(Amt.subtract(cd.getAmt()));
cd.setDeltaQty(Qty.subtract(cd.getQty()));
}
else
{
cd.setDeltaAmt(BigDecimal.ZERO);
cd.setDeltaQty(BigDecimal.ZERO);
cd.setAmt(Amt);
cd.setQty(Qty);
}
if (cd.isDelta())
{
cd.setProcessed(false);
cd.setAmt(Amt);
cd.setQty(Qty);
}
else if (cd.isProcessed())
return true; // nothing to do
}
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
ok = cd.process();
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("(" + ok + ") " + cd);
return ok;
} // createInventory
/**
* Create New Cost Detail record for Inventory Movements.
* Called from Doc_Movement.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_MovementLine_ID movement
* @param M_CostElement_ID optional cost element for Freight
* @param Amt amt total amount
* @param Qty qty
* @param from if true the from (reduction)
* @param Description optional description
* @param trxName transaction
* @return true if no error
* @deprecated
*/
@Deprecated
public static boolean createMovement (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_MovementLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty, boolean from,
String Description, String trxName)
{
return createMovement (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, M_MovementLine_ID, M_CostElement_ID,
Amt, Qty, from, Description, null, 0, trxName);
}
/**
* Create New Cost Detail record for Inventory Movements.
* Called from Doc_Movement.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_MovementLine_ID movement
* @param M_CostElement_ID optional cost element for Freight
* @param Amt amt total amount
* @param Qty qty
* @param from if true the from (reduction)
* @param Description optional description
* @param DateAcct account date
* @param Ref_CostDetail_ID reference cost detail
* @param trxName transaction
* @return true if no error
*/
public static boolean createMovement (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_MovementLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty, boolean from,
String Description, Timestamp DateAcct, int Ref_CostDetail_ID, String trxName)
{
MCostDetail cd = getMovement (as, M_Product_ID, M_AttributeSetInstance_ID, M_MovementLine_ID, M_CostElement_ID, from, trxName);
//
if (cd == null) // createNew
{
cd = new MCostDetail (as, AD_Org_ID,
M_Product_ID, M_AttributeSetInstance_ID,
M_CostElement_ID,
Amt, Qty, Description, DateAcct, Ref_CostDetail_ID, trxName);
cd.setM_MovementLine_ID (M_MovementLine_ID);
cd.setIsSOTrx(from);
}
else
{
if (cd.isProcessed())
{
// set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty
cd.setDeltaAmt(Amt.subtract(cd.getAmt()));
cd.setDeltaQty(Qty.subtract(cd.getQty()));
}
else
{
cd.setDeltaAmt(BigDecimal.ZERO);
cd.setDeltaQty(BigDecimal.ZERO);
cd.setAmt(Amt);
cd.setQty(Qty);
}
if (cd.isDelta())
{
cd.setProcessed(false);
cd.setAmt(Amt);
cd.setQty(Qty);
}
else if (cd.isProcessed())
return true; // nothing to do
}
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
ok = cd.process();
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("(" + ok + ") " + cd);
return ok;
} // createMovement
/**
* Create New Cost Detail record for Production.
* Called from Doc_Production.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_ProductionLine_ID production line
* @param M_CostElement_ID optional cost element
* @param Amt amt total amount
* @param Qty qty
* @param Description optional description
* @param trxName transaction
* @return true if no error
* @deprecated
*/
@Deprecated
public static boolean createProduction (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_ProductionLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, String trxName)
{
return createProduction (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, M_ProductionLine_ID, M_CostElement_ID,
Amt, Qty, Description, null, 0, trxName);
}
/**
* Create New Cost Detail record for Production.
* Called from Doc_Production.
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_ProductionLine_ID production line
* @param M_CostElement_ID optional cost element
* @param Amt amt total amount
* @param Qty qty
* @param Description optional description
* @param DateAcct account date
* @param Ref_CostDetail_ID reference cost detail
* @param trxName transaction
* @return true if no error
*/
public static boolean createProduction (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_ProductionLine_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, Timestamp DateAcct, int Ref_CostDetail_ID, String trxName)
{
MCostDetail cd = getProduction (as, M_Product_ID, M_AttributeSetInstance_ID, M_ProductionLine_ID, M_CostElement_ID, trxName);
//
if (cd == null) // createNew
{
cd = new MCostDetail (as, AD_Org_ID,
M_Product_ID, M_AttributeSetInstance_ID,
M_CostElement_ID,
Amt, Qty, Description, DateAcct, Ref_CostDetail_ID, trxName);
cd.setM_ProductionLine_ID(M_ProductionLine_ID);
}
else
{
if (cd.isProcessed())
{
// set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty
cd.setDeltaAmt(Amt.subtract(cd.getAmt()));
cd.setDeltaQty(Qty.subtract(cd.getQty()));
}
else
{
cd.setDeltaAmt(BigDecimal.ZERO);
cd.setDeltaQty(BigDecimal.ZERO);
cd.setAmt(Amt);
cd.setQty(Qty);
}
if (cd.isDelta())
{
cd.setProcessed(false);
cd.setAmt(Amt);
cd.setQty(Qty);
}
else if (cd.isProcessed())
return true; // nothing to do
}
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
ok = cd.process();
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("(" + ok + ") " + cd);
return ok;
} // createProduction
/**
* Create cost detail record for Match Invoice (M_MatchInv).
* @param as
* @param AD_Org_ID
* @param M_Product_ID
* @param M_AttributeSetInstance_ID
* @param M_MatchInv_ID
* @param M_CostElement_ID
* @param Amt
* @param Qty
* @param Description
* @param trxName
* @return true if no error
* @deprecated
*/
@Deprecated
public static boolean createMatchInvoice (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_MatchInv_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, String trxName)
{
return createMatchInvoice (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, M_MatchInv_ID, M_CostElement_ID,
Amt, Qty, Description, null, 0, trxName);
}
/**
* Create cost detail record for Match Invoice (M_MatchInv).
* @param as
* @param AD_Org_ID
* @param M_Product_ID
* @param M_AttributeSetInstance_ID
* @param M_MatchInv_ID
* @param M_CostElement_ID
* @param Amt
* @param Qty
* @param Description
* @param DateAcct account date
* @param Ref_CostDetail_ID reference cost detail
* @param trxName
* @return true if no error
*/
public static boolean createMatchInvoice (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_MatchInv_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, Timestamp DateAcct, int Ref_CostDetail_ID, String trxName)
{
MCostDetail cd = getMatchInvoice (as, M_Product_ID, M_AttributeSetInstance_ID, M_MatchInv_ID, M_CostElement_ID, trxName);
//
if (cd == null) // createNew
{
cd = new MCostDetail (as, AD_Org_ID,
M_Product_ID, M_AttributeSetInstance_ID,
M_CostElement_ID,
Amt, Qty, Description, DateAcct, Ref_CostDetail_ID, trxName);
cd.setM_MatchInv_ID(M_MatchInv_ID);
}
else
{
if (cd.isProcessed())
{
cd.setDeltaAmt(Amt.subtract(cd.getAmt()));
cd.setDeltaQty(Qty.subtract(cd.getQty()));
}
else
{
cd.setDeltaAmt(BigDecimal.ZERO);
cd.setDeltaQty(BigDecimal.ZERO);
cd.setAmt(Amt);
cd.setQty(Qty);
}
if (cd.isDelta())
{
cd.setProcessed(false);
cd.setAmt(Amt);
cd.setQty(Qty);
}
else if (cd.isProcessed())
return true; // nothing to do
}
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
ok = cd.process();
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("(" + ok + ") " + cd);
return ok;
} // createMatchInvoice
/**
* Create Cost Detail for Project Issue (C_ProjectIssue).
* Called from Doc_ProjectIssue
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param C_ProjectIssue_ID project issue line
* @param M_CostElement_ID optional cost element
* @param Amt amt total amount
* @param Qty qty
* @param Description optional description
* @param trxName transaction
* @return true if no error
* @deprecated
*/
@Deprecated
public static boolean createProjectIssue (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int C_ProjectIssue_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, String trxName)
{
return createProjectIssue (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, C_ProjectIssue_ID, M_CostElement_ID,
Amt, Qty, Description, null, 0, trxName);
}
/**
* Create Cost Detail for Project Issue (C_ProjectIssue).
* Called from Doc_ProjectIssue
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param C_ProjectIssue_ID project issue line
* @param M_CostElement_ID optional cost element
* @param Amt amt total amount
* @param Qty qty
* @param Description optional description
* @param DateAcct account date
* @param Ref_CostDetail_ID reference cost detail
* @param trxName transaction
* @return true if no error
*/
public static boolean createProjectIssue (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int C_ProjectIssue_ID, int M_CostElement_ID,
BigDecimal Amt, BigDecimal Qty,
String Description, Timestamp DateAcct, int Ref_CostDetail_ID, String trxName)
{
MCostDetail cd = getProjectIssue (as, M_Product_ID, M_AttributeSetInstance_ID, C_ProjectIssue_ID, M_CostElement_ID, trxName);
//
if (cd == null) // createNew
{
cd = new MCostDetail (as, AD_Org_ID,
M_Product_ID, M_AttributeSetInstance_ID,
M_CostElement_ID,
Amt, Qty, Description, DateAcct, Ref_CostDetail_ID, trxName);
cd.setC_ProjectIssue_ID(C_ProjectIssue_ID);
}
else
{
if (cd.isProcessed())
{
cd.setDeltaAmt(Amt.subtract(cd.getAmt()));
cd.setDeltaQty(Qty.subtract(cd.getQty()));
}
else
{
cd.setDeltaAmt(BigDecimal.ZERO);
cd.setDeltaQty(BigDecimal.ZERO);
cd.setAmt(Amt);
cd.setQty(Qty);
}
if (cd.isDelta())
{
cd.setProcessed(false);
cd.setAmt(Amt);
cd.setQty(Qty);
}
else if (cd.isProcessed())
return true; // nothing to do
}
boolean ok = cd.save();
if (ok && !cd.isProcessed())
{
ok = cd.process();
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("(" + ok + ") " + cd);
return ok;
} // createProjectIssue
public static MCostDetail getOrder (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int C_OrderLine_ID, int M_CostElement_ID, Timestamp DateAcct, String trxName) {
MCostDetail cd = get (as.getCtx(), "C_OrderLine_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID
+" AND TRUNC(DateAcct)="+DB.TO_DATE(DateAcct, true),
C_OrderLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
if (cd == null) {
cd = get (as.getCtx(), "C_OrderLine_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID,
C_OrderLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
if (cd != null && !cd.isDelta())
cd = null;
}
return cd;
}
public static MCostDetail getInvoice (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int C_InvoiceLine_ID, int M_CostElement_ID, Timestamp DateAcct, String trxName) {
MCostDetail cd = get (as.getCtx(), "C_InvoiceLine_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID+" AND M_Product_ID="+M_Product_ID
+" AND TRUNC(DateAcct)="+DB.TO_DATE(DateAcct, true),
C_InvoiceLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
if (cd == null) {
cd = get (as.getCtx(), "C_InvoiceLine_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID+" AND M_Product_ID="+M_Product_ID,
C_InvoiceLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
if (cd != null && !cd.isDelta())
cd = null;
}
return cd;
}
public static MCostDetail getShipment (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int M_InOutLine_ID, int M_CostElement_ID, String trxName) {
return get (as.getCtx(), "M_InOutLine_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID,
M_InOutLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
}
public static MCostDetail getInventory (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int M_InventoryLine_ID, int M_CostElement_ID, String trxName) {
return get (as.getCtx(), "M_InventoryLine_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID+" AND M_Product_ID="+M_Product_ID,
M_InventoryLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
}
public static MCostDetail getMovement (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int M_MovementLine_ID, int M_CostElement_ID, boolean from, String trxName) {
StringBuilder msget = new StringBuilder( "M_MovementLine_ID=? AND IsSOTrx=")
.append((from ? "'Y'" : "'N'")).append(" AND Coalesce(M_CostElement_ID,0)=").append(M_CostElement_ID);
return get (as.getCtx(),msget.toString(),
M_MovementLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
}
public static MCostDetail getProduction (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int M_ProductionLine_ID, String trxName) {
return get (as.getCtx(), "M_ProductionLine_ID=?",
M_ProductionLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
}
public static MCostDetail getProduction (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int M_ProductionLine_ID, int M_CostElement_ID, String trxName) {
return get (as.getCtx(), "M_ProductionLine_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID,
M_ProductionLine_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
}
public static MCostDetail getMatchInvoice (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int M_MatchInv_ID, int M_CostElement_ID, String trxName) {
return get (as.getCtx(), "M_MatchInv_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID,
M_MatchInv_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
}
public static MCostDetail getProjectIssue (MAcctSchema as, int M_Product_ID, int M_AttributeSetInstance_ID,
int C_ProjectIssue_ID, int M_CostElement_ID, String trxName) {
return get (as.getCtx(), "C_ProjectIssue_ID=? AND Coalesce(M_CostElement_ID,0)="+M_CostElement_ID,
C_ProjectIssue_ID, M_AttributeSetInstance_ID, as.getC_AcctSchema_ID(), trxName);
}
/**
* Get Cost Detail
* @param ctx context
* @param whereClause where clause
* @param ID 1st parameter
* @param M_AttributeSetInstance_ID ASI
* @param trxName trx
* @return cost detail
* @deprecated
*/
@Deprecated
public static MCostDetail get (Properties ctx, String whereClause,
int ID, int M_AttributeSetInstance_ID, String trxName)
{
StringBuilder sql = new StringBuilder("SELECT * FROM M_CostDetail WHERE ").append(whereClause);
MClientInfo clientInfo = MClientInfo.get(ctx);
MAcctSchema primary = clientInfo.getMAcctSchema1();
int C_AcctSchema_ID = primary != null ? primary.getC_AcctSchema_ID() : 0;
if (C_AcctSchema_ID > 0)
{
sql.append(" AND C_AcctSchema_ID=?");
}
MCostDetail retValue = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement (sql.toString(), null);
pstmt.setInt (1, ID);
pstmt.setInt (2, M_AttributeSetInstance_ID);
if (C_AcctSchema_ID > 0)
{
pstmt.setInt (3, C_AcctSchema_ID);
}
rs = pstmt.executeQuery ();
if (rs.next ())
retValue = new MCostDetail (ctx, rs, trxName);
}
catch (Exception e)
{
s_log.log (Level.SEVERE, sql + " - " + ID, e);
}
finally
{
DB.close(rs, pstmt);
}
return retValue;
}
/**
* Get Cost Detail
* @param ctx context
* @param whereClause where clause for record id (1st parameter)
* @param ID record id (1st parameter)
* @param M_AttributeSetInstance_ID ASI (2nd parameter)
* @param C_AcctSchema_ID accounting schema (3rd parameter)
* @param trxName trx
* @return cost detail
*/
public static MCostDetail get (Properties ctx, String whereClause,
int ID, int M_AttributeSetInstance_ID, int C_AcctSchema_ID, String trxName)
{
StringBuilder localWhereClause = new StringBuilder(whereClause)
.append(" AND M_AttributeSetInstance_ID=?")
.append(" AND C_AcctSchema_ID=?");
MCostDetail retValue = new Query(ctx,I_M_CostDetail.Table_Name,localWhereClause.toString(),trxName)
.setParameters(ID,M_AttributeSetInstance_ID,C_AcctSchema_ID)
.first();
return retValue;
} // get
/**
* Get Cost Detail Records
* @param ctx context
* @param whereClause where clause for record id (1st parameter)
* @param ID record id (1st parameter)
* @param M_AttributeSetInstance_ID ASI (2nd parameter)
* @param C_AcctSchema_ID accounting schema (3rd parameter)
* @param trxName trx
* @return list of cost detail record
*/
public static List list (Properties ctx, String whereClause,
int ID, int M_AttributeSetInstance_ID, int C_AcctSchema_ID, String trxName)
{
StringBuilder localWhereClause = new StringBuilder(whereClause)
.append(" AND M_AttributeSetInstance_ID=?")
.append(" AND C_AcctSchema_ID=?");
List retValue = new Query(ctx,I_M_CostDetail.Table_Name,localWhereClause.toString(),trxName)
.setParameters(ID,M_AttributeSetInstance_ID,C_AcctSchema_ID)
.list();
return retValue;
} // get
/**
* Process Cost Details for product
* @param product product
* @param trxName transaction
* @return true if no error
*/
public static boolean processProduct (MProduct product, String trxName)
{
final String whereClause = I_M_CostDetail.Table_Name + "." + I_M_CostDetail.COLUMNNAME_M_Product_ID + "=?"
+ " AND " + I_M_CostDetail.Table_Name + "." + I_M_CostDetail.COLUMNNAME_Processed + "=?";
int counterOK = 0;
int counterError = 0;
List list = new Query(product.getCtx(),I_M_CostDetail.Table_Name,whereClause,trxName)
.addJoinClause(" LEFT JOIN M_CostDetail refcd ON (refcd.M_CostDetail_ID=M_CostDetail.Ref_CostDetail_ID) ")
.setParameters(product.getM_Product_ID(),false)
.setOrderBy("M_CostDetail.C_AcctSchema_ID, M_CostDetail.M_CostElement_ID, M_CostDetail.AD_Org_ID, M_CostDetail.M_AttributeSetInstance_ID, M_CostDetail.DateAcct, "
+ "CASE WHEN COALESCE(refcd.DateAcct,M_CostDetail.DateAcct) = M_CostDetail.DateAcct THEN COALESCE(M_CostDetail.Ref_CostDetail_ID,M_CostDetail.M_CostDetail_ID) ELSE M_CostDetail.M_CostDetail_ID END, "
+ "M_CostDetail.M_CostDetail_ID")
.list();
for (MCostDetail cd : list) {
if (cd.process()) // saves
counterOK++;
else
counterError++;
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("OK=" + counterOK + ", Errors=" + counterError);
return counterError == 0;
} // processProduct
/**
* Process Cost Details for product
* @param as accounting schema
* @param product product
* @param dateAcct account date
* @param trxName transaction
* @return true if no error
*/
public static boolean processProduct(MAcctSchema as, MProduct product, Timestamp dateAcct, String trxName)
{
if (dateAcct == null)
dateAcct = TimeUtil.getDay(System.currentTimeMillis());
final String whereClause = I_M_CostDetail.Table_Name + "." + I_M_CostDetail.COLUMNNAME_C_AcctSchema_ID + "=?"
+ " AND " + I_M_CostDetail.Table_Name + "." + I_M_CostDetail.COLUMNNAME_M_Product_ID + "=?"
+ " AND " + I_M_CostDetail.Table_Name + "." + I_M_CostDetail.COLUMNNAME_DateAcct + "<=?"
+ " AND " + I_M_CostDetail.Table_Name + "." + I_M_CostDetail.COLUMNNAME_Processed + "=?";
int counterOK = 0;
int counterError = 0;
List list = new Query(product.getCtx(),I_M_CostDetail.Table_Name,whereClause,trxName)
.addJoinClause(" LEFT JOIN M_CostDetail refcd ON (refcd.M_CostDetail_ID=M_CostDetail.Ref_CostDetail_ID) ")
.setParameters(as.getC_AcctSchema_ID(), product.getM_Product_ID(), dateAcct, false)
.setOrderBy("M_CostDetail.M_CostElement_ID, M_CostDetail.AD_Org_ID, M_CostDetail.M_AttributeSetInstance_ID, M_CostDetail.DateAcct, "
+ "CASE WHEN COALESCE(refcd.DateAcct,M_CostDetail.DateAcct) = M_CostDetail.DateAcct THEN COALESCE(M_CostDetail.Ref_CostDetail_ID,M_CostDetail.M_CostDetail_ID) ELSE M_CostDetail.M_CostDetail_ID END, "
+ "M_CostDetail.M_CostDetail_ID")
.list();
for (MCostDetail cd : list) {
if (cd.process()) // saves
counterOK++;
else
counterError++;
}
if (s_log.isLoggable(Level.CONFIG)) s_log.config("OK=" + counterOK + ", Errors=" + counterError);
return counterError == 0;
} // processProduct
/** Logger */
private static CLogger s_log = CLogger.getCLogger (MCostDetail.class);
/**
* UUID based Constructor
* @param ctx Context
* @param M_CostDetail_UU UUID key
* @param trxName Transaction
*/
public MCostDetail(Properties ctx, String M_CostDetail_UU, String trxName) {
super(ctx, M_CostDetail_UU, trxName);
if (Util.isEmpty(M_CostDetail_UU))
setInitialDefaults();
}
/**
* Standard Constructor
* @param ctx context
* @param M_CostDetail_ID id
* @param trxName trx
*/
public MCostDetail (Properties ctx, int M_CostDetail_ID, String trxName)
{
super (ctx, M_CostDetail_ID, trxName);
if (M_CostDetail_ID == 0)
setInitialDefaults();
} // MCostDetail
/**
* Set the initial defaults for a new record
*/
private void setInitialDefaults() {
setM_AttributeSetInstance_ID (0);
setProcessed (false);
setAmt (Env.ZERO);
setQty (Env.ZERO);
setIsSOTrx (false);
setDeltaAmt (Env.ZERO);
setDeltaQty (Env.ZERO);
}
/**
* Load Constructor
* @param ctx context
* @param rs result set
* @param trxName trx
*/
public MCostDetail (Properties ctx, ResultSet rs, String trxName)
{
super (ctx, rs, trxName);
} // MCostDetail
/**
* New Constructor
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_CostElement_ID optional cost element for Freight
* @param amt Amount
* @param qty Quantity
* @param description optional description
* @param trxName transaction
* @deprecated
*/
@Deprecated
public MCostDetail (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_CostElement_ID, BigDecimal amt, BigDecimal qty,
String description, String trxName)
{
this (as, AD_Org_ID, M_Product_ID, M_AttributeSetInstance_ID, M_CostElement_ID, amt, qty, description, null, 0, trxName);
}
/**
* New Constructor
* @param as accounting schema
* @param AD_Org_ID org
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param M_CostElement_ID optional cost element for Freight
* @param amt Amount
* @param qty Quantity
* @param description optional description
* @param dateAcct account date
* @param Ref_CostDetail_ID referenced cost detail
* @param trxName transaction
*/
public MCostDetail (MAcctSchema as, int AD_Org_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
int M_CostElement_ID, BigDecimal amt, BigDecimal qty,
String description, Timestamp dateAcct, int Ref_CostDetail_ID, String trxName)
{
this (as.getCtx(), 0, trxName);
setClientOrg(as.getAD_Client_ID(), AD_Org_ID);
setC_AcctSchema_ID (as.getC_AcctSchema_ID());
setM_Product_ID (M_Product_ID);
setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID);
//
setM_CostElement_ID(M_CostElement_ID);
setAmt (amt);
setQty (qty);
setDescription(description);
setDateAcct(dateAcct);
if (Ref_CostDetail_ID > 0)
setRef_CostDetail_ID(Ref_CostDetail_ID);
} // MCostDetail
/**
* Set Amt
* @param Amt amt
*/
@Override
public void setAmt (BigDecimal Amt)
{
if (isProcessed())
throw new IllegalStateException("Cannot change Amt - processed");
if (Amt == null)
super.setAmt (Env.ZERO);
else
super.setAmt (Amt);
} // setAmt
/**
* Set Qty
* @param Qty qty
*/
@Override
public void setQty (BigDecimal Qty)
{
if (isProcessed())
throw new IllegalStateException("Cannot change Qty - processed");
if (Qty == null)
super.setQty (Env.ZERO);
else
super.setQty (Qty);
} // setQty
/**
* Is Order
* @return true if has order line
*/
public boolean isOrder()
{
return getC_OrderLine_ID() != 0;
} // isOrder
/**
* Is Invoice
* @return true if has invoice line
*/
public boolean isInvoice()
{
return getC_InvoiceLine_ID() != 0;
} // isInvoice
/**
* Is Shipment
* @return true if has sales order shipment line
*/
public boolean isShipment()
{
return isSOTrx() && getM_InOutLine_ID() != 0;
} // isShipment
/**
* @return true if shipment line belongs to return to vendor (vendor RMA)
*/
public boolean isVendorRMA()
{
if (!isSOTrx() && getM_InOutLine_ID() > 0)
{
String docBaseType = DB.getSQLValueString((String)null,
INOUTLINE_DOCBASETYPE_SQL, getM_InOutLine_ID());
return Doc.DOCTYPE_MatShipment.equals(docBaseType);
}
return false;
}
/**
* Is this a Delta Record (previously processed)?
* @return true if delta is not null
*/
public boolean isDelta()
{
return !(getDeltaAmt().signum() == 0
&& getDeltaQty().signum() == 0);
} // isDelta
@Override
protected boolean beforeSave(boolean newRecord) {
if (newRecord) {
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
Timestamp dateAcct = getDateAcct();
if (dateAcct == null)
{
setDateAcct(today);
setIsBackDate(false);
}
else
{
int Ref_CostDetail_ID = getRef_CostDetail_ID();
if (Ref_CostDetail_ID > 0)
{
setDateAcct(dateAcct);
setIsBackDate(true);
}
else
{
final String sql = "SELECT MAX(DateAcct) FROM M_CostDetail WHERE M_Product_ID=? AND Processed='Y'";
Timestamp MaxDateAcct = DB.getSQLValueTS(get_TrxName(), sql, getM_Product_ID());
if (MaxDateAcct != null && MaxDateAcct.after(today))
today = MaxDateAcct;
setDateAcct(dateAcct);
setIsBackDate(dateAcct.before(today));
}
}
} else {
if (is_ValueChanged(COLUMNNAME_DateAcct))
{
log.saveError("Error", Msg.getMsg(getCtx(), "CannotChangeAccountDate"));
return false;
}
}
return super.beforeSave(newRecord);
}
@Override
protected boolean beforeDelete ()
{
return !isProcessed();
} // beforeDelete
/**
* String Representation
* @return info
*/
@Override
public String toString ()
{
StringBuilder sb = new StringBuilder ("MCostDetail[");
sb.append (get_ID());
if (getC_OrderLine_ID() != 0)
sb.append (",C_OrderLine_ID=").append (getC_OrderLine_ID());
if (getM_InOutLine_ID() != 0)
sb.append (",M_InOutLine_ID=").append (getM_InOutLine_ID());
if (getC_InvoiceLine_ID() != 0)
sb.append (",C_InvoiceLine_ID=").append (getC_InvoiceLine_ID());
if (getC_ProjectIssue_ID() != 0)
sb.append (",C_ProjectIssue_ID=").append (getC_ProjectIssue_ID());
if (getM_MovementLine_ID() != 0)
sb.append (",M_MovementLine_ID=").append (getM_MovementLine_ID());
if (getM_InventoryLine_ID() != 0)
sb.append (",M_InventoryLine_ID=").append (getM_InventoryLine_ID());
if (getM_ProductionLine_ID() != 0)
sb.append (",M_ProductionLine_ID=").append (getM_ProductionLine_ID());
sb.append(",Amt=").append(getAmt())
.append(",Qty=").append(getQty());
if (isDelta())
sb.append(",DeltaAmt=").append(getDeltaAmt())
.append(",DeltaQty=").append(getDeltaQty());
sb.append ("]");
return sb.toString ();
} // toString
/**
* Process Cost Detail Record.
* The record is saved if processed.
* @return true if processed
*/
public synchronized boolean process()
{
if (isProcessed())
{
log.info("Already processed");
return true;
}
boolean ok = false;
// get costing level for product
MAcctSchema as = MAcctSchema.get(getCtx(), getC_AcctSchema_ID());
MProduct product = new MProduct(getCtx(), getM_Product_ID(), get_TrxName());
String CostingLevel = product.getCostingLevel(as);
// Org Element
int Org_ID = getAD_Org_ID();
int M_ASI_ID = getM_AttributeSetInstance_ID();
if (MAcctSchema.COSTINGLEVEL_Client.equals(CostingLevel))
{
Org_ID = 0;
M_ASI_ID = 0;
}
else if (MAcctSchema.COSTINGLEVEL_Organization.equals(CostingLevel))
M_ASI_ID = 0;
else if (MAcctSchema.COSTINGLEVEL_BatchLot.equals(CostingLevel))
Org_ID = 0;
// Create Material Cost elements
if (getM_CostElement_ID() == 0)
{
MCostElement[] ces = MCostElement.getCostingMethods(this);
for (int i = 0; i < ces.length; i++)
{
MCostElement ce = ces[i];
if (ce.isAverageInvoice() || ce.isAveragePO() || ce.isLifo() || ce.isFifo())
{
if (!product.isStocked())
continue;
}
ok = process (as, product, ce, Org_ID, M_ASI_ID);
if (!ok)
break;
}
} // Material Cost elements
else
{
MCostElement ce = MCostElement.get(getCtx(), getM_CostElement_ID());
if (ce.getCostingMethod() == null)
{
MCostElement[] ces = MCostElement.getCostingMethods(this);
for (MCostElement costingElement : ces)
{
if (costingElement.isAverageInvoice() || costingElement.isAveragePO() || costingElement.isLifo() || costingElement.isFifo())
{
if (!product.isStocked())
continue;
}
ok = process (as, product, costingElement, Org_ID, M_ASI_ID);
if (!ok)
break;
}
}
else
{
if (ce.isAverageInvoice() || ce.isAveragePO() || ce.isLifo() || ce.isFifo())
{
if (product.isStocked())
ok = process (as, product, ce, Org_ID, M_ASI_ID);
}
else
{
ok = process (as, product, ce, Org_ID, M_ASI_ID);
}
}
}
// Save it
if (ok)
{
setDeltaAmt(null);
setDeltaQty(null);
setProcessed(true);
ok = save();
}
if (log.isLoggable(Level.INFO)) log.info(ok + " - " + toString());
return ok;
} // process
/**
* Process cost detail record
* @param as accounting schema
* @param product product
* @param ce cost element
* @param Org_ID org - corrected for costing level
* @param M_ASI_ID - asi corrected for costing level
* @return true if cost ok
*/
protected boolean process (MAcctSchema as, MProduct product, MCostElement ce,
int Org_ID, int M_ASI_ID)
{
//handle compatibility issue between average invoice and average po
String costingMethod = product.getCostingMethod(as);
if (X_M_Cost.COSTINGMETHOD_AverageInvoice.equals(costingMethod)) {
if (ce.isAveragePO())
return true;
} else if (X_M_Cost.COSTINGMETHOD_AveragePO.equals(costingMethod)) {
if (ce.isAverageInvoice())
return true;
}
MCost cost = MCost.get(product, M_ASI_ID, as, Org_ID, ce.getM_CostElement_ID(), get_TrxName());
ICostInfo costInfo = MCost.getCostInfo(product.getCtx(), product.getAD_Client_ID(), Org_ID, product.getM_Product_ID(),
as.getM_CostType_ID(), as.getC_AcctSchema_ID(), ce.getM_CostElement_ID(), M_ASI_ID, getDateAcct(), this, get_TrxName());
if (costInfo != null)
{
cost.setCurrentQty(costInfo.getCurrentQty());
cost.setCurrentCostPrice(costInfo.getCurrentCostPrice());
cost.setCumulatedQty(costInfo.getCumulatedQty());
cost.setCumulatedAmt(costInfo.getCumulatedAmt());
}
DB.getDatabase().forUpdate(cost, 120);
//save history for m_cost
MCostHistory history = new MCostHistory(this, cost, ce);
// MZ Goodwill
// used deltaQty and deltaAmt if exist
BigDecimal qty = Env.ZERO;
BigDecimal amt = Env.ZERO;
if (isDelta())
{
qty = getDeltaQty();
amt = getDeltaAmt();
}
else
{
qty = getQty();
amt = getAmt();
}
// end MZ
//determine whether this is cost only adjustment entry
boolean costAdjustment = false;
if (this.getM_CostElement_ID() > 0 && this.getM_CostElement_ID() != ce.getM_CostElement_ID())
{
MCostElement thisCostElement = MCostElement.get(getCtx(), getM_CostElement_ID());
if (thisCostElement.getCostingMethod() == null && ce.getCostingMethod() != null)
{
qty = BigDecimal.ZERO;
costAdjustment = true;
}
}
int precision = as.getCostingPrecision();
BigDecimal price = amt;
if (qty.signum() != 0)
price = amt.divide(qty, precision, RoundingMode.HALF_UP);
// *** Purchase Order Detail Record ***
if (getC_OrderLine_ID() != 0)
{
boolean isReturnTrx = qty.signum() < 0;
if (ce.isAveragePO())
{
cost.setWeightedAverage(amt, qty);
if (log.isLoggable(Level.FINER)) log.finer("PO - AveragePO - " + cost);
}
else if (ce.isLastPOPrice() && !costAdjustment)
{
if(!isReturnTrx)
{
if (qty.signum() != 0)
cost.setCurrentCostPrice(price);
else
{
BigDecimal cCosts = cost.getCurrentCostPrice().add(amt);
cost.setCurrentCostPrice(cCosts);
}
}
cost.add(amt, qty);
if (log.isLoggable(Level.FINER)) log.finer("PO - LastPO - " + cost);
}
else if (ce.isStandardCosting() && !costAdjustment)
{
// Update cost record only if it is zero
if (cost.getCurrentCostPrice().signum() == 0
&& cost.getCurrentCostPriceLL().signum() == 0)
{
cost.setCurrentCostPrice(price);
if (cost.getCurrentCostPrice().signum() == 0)
{
cost.setCurrentCostPrice(MCost.getSeedCosts(product, M_ASI_ID,
as, Org_ID, ce.getCostingMethod(), getC_OrderLine_ID()));
}
if (log.isLoggable(Level.FINEST)) log.finest("PO - Standard - CurrentCostPrice(seed)="+cost.getCurrentCostPrice()+", price="+price);
}
cost.add(amt, qty);
if (log.isLoggable(Level.FINER)) log.finer("PO - Standard - " + cost);
}
else if (ce.isUserDefined())
{
// Interface
if (log.isLoggable(Level.FINER)) log.finer("PO - UserDef - " + cost);
}
else if (!ce.isCostingMethod())
{
if (log.isLoggable(Level.FINER)) log.finer("PO - " + ce + " - " + cost);
}
}
// *** AP Invoice Detail Record ***
else if (getC_InvoiceLine_ID() != 0)
{
boolean isReturnTrx = qty.signum() < 0;
if (ce.isAverageInvoice())
{
cost.setWeightedAverage(amt, qty);
if (log.isLoggable(Level.FINER)) log.finer("Inv - AverageInv - " + cost);
}
else if (ce.isAveragePO() && costAdjustment)
{
cost.setWeightedAverage(amt, qty);
}
else if (ce.isFifo()
|| ce.isLifo())
{
// Real ASI - costing level Org
MCostQueue cq = MCostQueue.get(product, getM_AttributeSetInstance_ID(),
as, Org_ID, ce.getM_CostElement_ID(), get_TrxName());
cq.setCosts(amt, qty, precision);
cq.saveEx();
// Get Costs - costing level Org/ASI
MCostQueue[] cQueue = MCostQueue.getQueue(product, M_ASI_ID,
as, Org_ID, ce, get_TrxName());
if (cQueue != null && cQueue.length > 0)
cost.setCurrentCostPrice(cQueue[0].getCurrentCostPrice());
cost.add(amt, qty);
if (log.isLoggable(Level.FINER)) log.finer("Inv - FiFo/LiFo - " + cost);
}
else if (ce.isLastInvoice() && !costAdjustment)
{
if (!isReturnTrx)
{
if (qty.signum() != 0)
cost.setCurrentCostPrice(price);
else
{
BigDecimal cCosts = cost.getCurrentCostPrice().add(amt);
cost.setCurrentCostPrice(cCosts);
}
}
cost.add(amt, qty);
if (log.isLoggable(Level.FINER)) log.finer("Inv - LastInv - " + cost);
}
else if (ce.isStandardCosting() && !costAdjustment)
{
// Update cost record only if it is zero
if (cost.getCurrentCostPrice().signum() == 0
&& cost.getCurrentCostPriceLL().signum() == 0)
{
cost.setCurrentCostPrice(price);
// seed initial price
if (cost.getCurrentCostPrice().signum() == 0)
{
cost.setCurrentCostPrice(MCost.getSeedCosts(product, M_ASI_ID,
as, Org_ID, ce.getCostingMethod(), getC_OrderLine_ID()));
if (log.isLoggable(Level.FINEST)) log.finest("Inv - Standard - CurrentCostPrice(seed)="+cost.getCurrentCostPrice()+", price="+price);
}
cost.add(amt, qty);
}
if (log.isLoggable(Level.FINER)) log.finer("Inv - Standard - " + cost);
}
else if (ce.isUserDefined())
{
// Interface
cost.add(amt, qty);
if (log.isLoggable(Level.FINER)) log.finer("Inv - UserDef - " + cost);
}
}
else if (getM_InOutLine_ID() != 0 && costAdjustment)
{
if (ce.isAverageInvoice())
{
cost.setWeightedAverage(amt, qty);
}
}
// *** Qty Adjustment Detail Record ***
else if (getM_InOutLine_ID() != 0 // AR Shipment Detail Record
|| getM_MovementLine_ID() != 0
|| getM_InventoryLine_ID() != 0
|| getM_ProductionLine_ID() != 0
|| getC_ProjectIssue_ID() != 0
|| getPP_Cost_Collector_ID() != 0)
{
boolean addition = qty.signum() > 0;
boolean adjustment = getM_InventoryLine_ID() > 0 && qty.signum() == 0 && amt.signum() != 0;
boolean isVendorRMA = isVendorRMA();
//
if (ce.isAverageInvoice())
{
if (!isVendorRMA)
{
if (adjustment)
{
costingMethod = getM_InventoryLine().getM_Inventory().getCostingMethod();
if (MCostElement.COSTINGMETHOD_AverageInvoice.equals(costingMethod))
{
if (cost.getCurrentQty().signum() == 0 && qty.signum() == 0) {
// IDEMPIERE-2057 - this is a cost adjustment when there is no qty - setting the initial cost
cost.setWeightedAverageInitial(amt);
} else {
cost.setWeightedAverage(amt.multiply(cost.getCurrentQty()), qty);
}
}
}
else if (addition)
{
cost.setWeightedAverage(amt, qty);
//shouldn't accumulate reversal of customer shipment qty and amt
if (isShipment())
{
cost.setCumulatedQty(history.getOldCQty());
cost.setCumulatedAmt(history.getOldCAmt());
}
}
else
cost.setCurrentQty(cost.getCurrentQty().add(qty));
if (log.isLoggable(Level.FINER)) log.finer("QtyAdjust - AverageInv - " + cost);
}
}
else if (ce.isAveragePO())
{
if (adjustment)
{
costingMethod = getM_InventoryLine().getM_Inventory().getCostingMethod();
if (MCostElement.COSTINGMETHOD_AveragePO.equals(costingMethod))
{
if (cost.getCurrentQty().signum() == 0 && qty.signum() == 0) {
// IDEMPIERE-2057 - this is a cost adjustment when there is no qty - setting the initial cost
cost.setWeightedAverageInitial(amt);
} else {
cost.setWeightedAverage(amt.multiply(cost.getCurrentQty()), qty);
}
}
}
else if (addition)
{
cost.setWeightedAverage(amt, qty);
//shouldn't accumulate reversal of customer shipment qty and amt
if (isShipment() && !isVendorRMA())
{
cost.setCumulatedQty(history.getOldCQty());
cost.setCumulatedAmt(history.getOldCAmt());
}
}
else
{
if (isVendorRMA)
{
cost.setWeightedAverage(amt, qty);
}
else
{
cost.setCurrentQty(cost.getCurrentQty().add(qty));
}
}
if (log.isLoggable(Level.FINER)) log.finer("QtyAdjust - AveragePO - " + cost);
}
else if (ce.isFifo() || ce.isLifo())
{
if (!isVendorRMA && !adjustment)
{
if (addition)
{
// Real ASI - costing level Org
MCostQueue cq = MCostQueue.get(product, getM_AttributeSetInstance_ID(),
as, Org_ID, ce.getM_CostElement_ID(), get_TrxName());
cq.setCosts(amt, qty, precision);
cq.saveEx();
}
else
{
// Adjust Queue - costing level Org/ASI
MCostQueue.adjustQty(product, M_ASI_ID,
as, Org_ID, ce, qty.negate(), get_TrxName());
}
// Get Costs - costing level Org/ASI
MCostQueue[] cQueue = MCostQueue.getQueue(product, M_ASI_ID,
as, Org_ID, ce, get_TrxName());
if (cQueue != null && cQueue.length > 0)
cost.setCurrentCostPrice(cQueue[0].getCurrentCostPrice());
cost.setCurrentQty(cost.getCurrentQty().add(qty));
if (log.isLoggable(Level.FINER)) log.finer("QtyAdjust - FiFo/Lifo - " + cost);
}
}
else if (ce.isLastInvoice() && !isVendorRMA && !adjustment)
{
cost.setCurrentQty(cost.getCurrentQty().add(qty));
if (log.isLoggable(Level.FINER)) log.finer("QtyAdjust - LastInv - " + cost);
}
else if (ce.isLastPOPrice() && !isVendorRMA && !adjustment)
{
cost.setCurrentQty(cost.getCurrentQty().add(qty));
if (log.isLoggable(Level.FINER)) log.finer("QtyAdjust - LastPO - " + cost);
}
else if (ce.isStandardCosting() && !isVendorRMA)
{
if (adjustment)
{
costingMethod = getM_InventoryLine().getM_Inventory().getCostingMethod();
if (MCostElement.COSTINGMETHOD_StandardCosting.equals(costingMethod))
{
cost.add(amt.multiply(cost.getCurrentQty()), qty);
cost.setCurrentCostPrice(cost.getCurrentCostPrice().add(amt));
}
}
else if (addition)
{
MProductionLine productionLine = getM_ProductionLine_ID() > 0 ? new MProductionLine(getCtx(), getM_ProductionLine_ID(), get_TrxName()) : null;
if (productionLine != null && productionLine.getProductionReversalId() > 0)
cost.setCurrentQty(cost.getCurrentQty().add(qty));
else
cost.add(amt, qty);
// Initial
if (cost.getCurrentCostPrice().signum() == 0
&& cost.getCurrentCostPriceLL().signum() == 0
&& cost.is_new())
{
cost.setCurrentCostPrice(price);
if (log.isLoggable(Level.FINEST)) log.finest("QtyAdjust - Standard - CurrentCostPrice="+price);
}
}
else
{
cost.setCurrentQty(cost.getCurrentQty().add(qty));
}
if (log.isLoggable(Level.FINER)) log.finer("QtyAdjust - Standard - " + cost);
}
else if (ce.isUserDefined() && !isVendorRMA && !adjustment)
{
// Interface
if (addition)
cost.add(amt, qty);
else
cost.setCurrentQty(cost.getCurrentQty().add(qty));
if (log.isLoggable(Level.FINER)) log.finer("QtyAdjust - UserDef - " + cost);
}
else if (!ce.isCostingMethod())
{
//Should not happen
if (log.isLoggable(Level.FINER)) log.finer("QtyAdjust - ?none? - " + cost);
}
else if (ce.isStandardCosting() && isVendorRMA)
{
cost.add(amt, qty);
}
else
log.warning("QtyAdjust - " + ce + " - " + cost);
}
else if (getM_MatchInv_ID() > 0)
{
if (ce.isAveragePO())
{
cost.setWeightedAverage(amt, qty);
}
}
else // unknown or no id
{
log.warning("Unknown Type: " + toString());
return false;
}
//Should only update cost detail with value from as costing method
if(as.getCostingMethod().equals(ce.getCostingMethod())) {
setCurrentCostPrice(cost.getCurrentCostPrice());
setCurrentQty(cost.getCurrentQty());
setCumulatedAmt(cost.getCumulatedAmt());
setCumulatedQty(cost.getCumulatedQty());
}
//update history
history.setNewQty(cost.getCurrentQty());
history.setNewCostPrice(cost.getCurrentCostPrice());
history.setNewCAmt(cost.getCumulatedAmt());
history.setNewCQty(cost.getCumulatedQty());
//save history if there are movement of qty or costprice
//save history if the costing method is average po or average invoice
if (history.getNewQty().compareTo(history.getOldQty()) != 0
|| history.getNewCostPrice().compareTo(history.getOldCostPrice()) != 0
|| (ce.isAveragePO() || ce.isAverageInvoice()))
{
if (!history.save())
return false;
}
return cost.save();
} // process
/**
* Period Closed Check for Documents after the Back-Date Transaction
* @param AD_Client_ID Client of the back-date transaction
* @param C_AcctSchema_ID Accounting schema of the back-date transaction
* @param M_Product_ID Product of the back-date transaction
* @param M_CostDetail_ID Cost detail of the back-date transaction
* @param DateAcct Account date of the back-date transaction
* @param trxName Transaction name
*/
public static void periodClosedCheckForDocsAfterBackDateTrx(int AD_Client_ID, int C_AcctSchema_ID, int M_Product_ID,
int M_CostDetail_ID, Timestamp DateAcct, String trxName) {
List repostedRecordIds = new ArrayList();
StringBuilder selectSql = new StringBuilder();
selectSql.append("SELECT mpo.M_MatchPO_ID, il.C_Invoice_ID, iol.M_InOut_ID, mi.M_MatchInv_ID, invl.M_Inventory_ID, ");
selectSql.append("ml.M_Movement_ID, pl.M_Production_ID, pi.C_ProjectIssue_ID ");
selectSql.append("FROM M_CostDetail cd ");
selectSql.append("LEFT JOIN M_CostDetail refcd ON (refcd.M_CostDetail_ID=cd.Ref_CostDetail_ID) ");
selectSql.append("LEFT JOIN M_MatchPO mpo ON (mpo.C_OrderLine_ID = cd.C_OrderLine_ID) ");
selectSql.append("LEFT JOIN C_InvoiceLine il ON (il.C_InvoiceLine_ID = cd.C_InvoiceLine_ID) ");
selectSql.append("LEFT JOIN M_InOutLine iol ON (iol.M_InOutLine_ID = cd.M_InOutLine_ID) ");
selectSql.append("LEFT JOIN M_MatchInv mi ON (mi.M_MatchInv_ID = cd.M_MatchInv_ID) ");
selectSql.append("LEFT JOIN M_InventoryLine invl ON (invl.M_InventoryLine_ID = cd.M_InventoryLine_ID) ");
selectSql.append("LEFT JOIN M_MovementLine ml ON (ml.M_MovementLine_ID = cd.M_MovementLine_ID) ");
selectSql.append("LEFT JOIN M_ProductionLine pl ON (pl.M_ProductionLine_ID = cd.M_ProductionLine_ID) ");
selectSql.append("LEFT JOIN C_ProjectIssue pi ON (pi.C_ProjectIssue_ID = cd.C_ProjectIssue_ID) ");
selectSql.append("WHERE cd.AD_Client_ID=? ");
selectSql.append("AND cd.C_AcctSchema_ID=? ");
selectSql.append("AND cd.M_Product_ID=? ");
selectSql.append("AND (cd.DateAcct, COALESCE(cd.Ref_CostDetail_ID,cd.M_CostDetail_ID), cd.M_CostDetail_ID) > (");
selectSql.append(" SELECT cd.DateAcct, ");
selectSql.append(" CASE WHEN COALESCE(refcd.DateAcct,cd.DateAcct) = cd.DateAcct ");
selectSql.append(" THEN COALESCE(cd.Ref_CostDetail_ID,cd.M_CostDetail_ID) ELSE cd.M_CostDetail_ID END, ");
selectSql.append(" cd.M_CostDetail_ID ");
selectSql.append(" FROM M_CostDetail cd ");
selectSql.append(" LEFT JOIN M_CostDetail refcd ON (refcd.M_CostDetail_ID=cd.Ref_CostDetail_ID) ");
selectSql.append(" WHERE cd.M_CostDetail_ID=? ");
selectSql.append(") ");
selectSql.append("AND cd.DateAcct >= ? ");
selectSql.append("AND cd.Processed='Y' ");
selectSql.append("ORDER BY cd.DateAcct, ");
selectSql.append("CASE WHEN COALESCE(refcd.DateAcct,cd.DateAcct) = cd.DateAcct ");
selectSql.append("THEN COALESCE(cd.Ref_CostDetail_ID,cd.M_CostDetail_ID) ELSE cd.M_CostDetail_ID END, ");
selectSql.append("cd.M_CostDetail_ID ");
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(selectSql.toString(), trxName);
DB.setParameters(pstmt, new Object[] {AD_Client_ID, C_AcctSchema_ID, M_Product_ID, M_CostDetail_ID, DateAcct});
rs = pstmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
while (rs.next()) {
int tableID = 0;
int recordID = 0;
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
String key = rsmd.getColumnName(i);
Object value = rs.getObject(i);
if (value == null || !(value instanceof Number))
continue;
MTable docTable = MTable.get(Env.getCtx(), key.substring(0, key.length()-3));
if (docTable == null)
continue;
tableID = docTable.getAD_Table_ID();
recordID = ((Number) value).intValue();
break;
}
if (tableID == 0 || recordID == 0)
continue;
Timestamp dateAcct = MCostDetail.getDateAcct(tableID, recordID, trxName);
if (dateAcct == null)
continue;
MTable table = MTable.get(Env.getCtx(), tableID);
PO po = table.getPO(recordID, trxName);
int index = po.get_ColumnIndex("C_DocType_ID");
String docBaseType = null;
if (index < 0) {
if (tableID == MMatchInv.Table_ID) {
docBaseType = MDocType.DOCBASETYPE_MatchInvoice;
} else if (tableID == MMatchPO.Table_ID) {
docBaseType = MDocType.DOCBASETYPE_MatchPO;
} else if (tableID == MProjectIssue.Table_ID) {
docBaseType = MDocType.DOCBASETYPE_ProjectIssue;
} else {
continue;
}
} else {
int C_DocType_ID = 0;
Object objts = po.get_Value(index);
if (objts != null && objts instanceof Number) {
C_DocType_ID = ((Number) objts).intValue();
}
MDocType dt = MDocType.get(Env.getCtx(), C_DocType_ID);
docBaseType = dt.getDocBaseType();
}
if (docBaseType == null)
continue;
String repostedRecordId = tableID + "_" + recordID;
if (repostedRecordIds.contains(repostedRecordId))
continue;
repostedRecordIds.add(repostedRecordId);
if (!MPeriod.isOpen(Env.getCtx(), dateAcct, docBaseType, po.getAD_Org_ID(), true)) {
throw new PeriodClosedException(dateAcct, docBaseType);
}
if (tableID == MInvoice.Table_ID) {
MMatchInv[] miList = MMatchInv.getInvoice(Env.getCtx(), recordID, trxName);
for (MMatchInv mi : miList) {
repostedRecordId = MMatchInv.Table_ID + "_" + mi.get_ID();
if (repostedRecordIds.contains(repostedRecordId))
continue;
repostedRecordIds.add(repostedRecordId);
dateAcct = mi.getDateAcct();
docBaseType = MDocType.DOCBASETYPE_MatchInvoice;
if (!MPeriod.isOpen(Env.getCtx(), dateAcct, docBaseType, mi.getAD_Org_ID(), true)) {
throw new PeriodClosedException(dateAcct, docBaseType);
}
}
}
}
}
catch (SQLException e)
{
throw new DBException(e, selectSql.toString());
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
}
/**
* Get Account Date
* @param tableID Transaction table
* @param recordID Record ID of this document
* @param trxName Transaction name
* @return accounting date
*/
public static Timestamp getDateAcct(int tableID, int recordID, String trxName) {
MTable table = MTable.get(Env.getCtx(), tableID);
PO po = table.getPO(recordID, trxName);
int index = -1;
if (tableID == MInventory.Table_ID
|| tableID == MMovement.Table_ID
|| tableID == MProduction.Table_ID
|| tableID == MProjectIssue.Table_ID) {
index = po.get_ColumnIndex("MovementDate");
} else if (tableID == MMatchPO.Table_ID
|| tableID == MInvoice.Table_ID
|| tableID == MInOut.Table_ID
|| tableID == MMatchInv.Table_ID) {
index = po.get_ColumnIndex("DateAcct");
}
if (index < 0)
return null;
Timestamp dateAcct = null;
Object objts = po.get_Value(index);
if (objts != null && objts instanceof Timestamp) {
dateAcct = (Timestamp) objts;
}
return dateAcct;
}
} // MCostDetail