/******************************************************************************
* 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.sql.ResultSet;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
import org.idempiere.cache.ImmutableIntPOCache;
import org.idempiere.cache.ImmutablePOSupport;
/**
* Cost Element Model
* @author Jorg Janke
* @version $Id: MCostElement.java,v 1.2 2006/07/30 00:58:04 jjanke Exp $
*
* @author Teo Sarca, www.arhipac.ro
*
BF [ 2664529 ] More then one Labor/Burden//Overhead is not allowed
* BF [ 2667470 ] MCostElement.getMaterialCostElement should check only material
* @author red1
* FR: [ 2214883 ] Remove SQL code and Replace for Query -- JUnit tested
*/
public class MCostElement extends X_M_CostElement implements ImmutablePOSupport
{
/**
* generated serial id
*/
private static final long serialVersionUID = 4914952212171251715L;
/**
* Get Material Cost Element or create it
* @param po parent
* @param CostingMethod costing method
* @return cost element
*/
public static MCostElement getMaterialCostElement (PO po, String CostingMethod)
{
if (CostingMethod == null || CostingMethod.length() == 0)
{
s_log.severe("No CostingMethod");
return null;
}
//
final String whereClause = "AD_Client_ID=? AND CostingMethod=? AND CostElementType=?";
MCostElement retValue = new Query(po.getCtx(), Table_Name, whereClause, po.get_TrxName())
.setParameters(po.getAD_Client_ID(), CostingMethod, COSTELEMENTTYPE_Material)
.setOrderBy("AD_Org_ID")
.firstOnly();
if (retValue != null)
return retValue;
// Create New
retValue = new MCostElement (po.getCtx(), 0, po.get_TrxName());
retValue.setClientOrg(po.getAD_Client_ID(), 0);
String name = MRefList.getListName(po.getCtx(), COSTINGMETHOD_AD_Reference_ID, CostingMethod);
if (name == null || name.length() == 0)
name = CostingMethod;
retValue.setName(name);
retValue.setCostElementType(COSTELEMENTTYPE_Material);
retValue.setCostingMethod(CostingMethod);
retValue.saveEx();
//
return retValue;
} // getMaterialCostElement
/**
* Get first Material Cost Element for a costing method.
* @param ctx context
* @param CostingMethod costing method
* @return Cost Element or null
*/
public static MCostElement getMaterialCostElement(Properties ctx, String CostingMethod)
{
final String whereClause = "AD_Client_ID=? AND CostingMethod=? AND CostElementType=?";
List list = new Query(ctx, I_M_CostElement.Table_Name, whereClause, null)
.setParameters(Env.getAD_Client_ID(ctx),CostingMethod,COSTELEMENTTYPE_Material)
.setOrderBy(I_M_CostElement.COLUMNNAME_AD_Org_ID)
.list();
MCostElement retValue = null;
if (list.size() > 0)
retValue = list.get(0);
if (list.size() > 1)
if (s_log.isLoggable(Level.INFO)) s_log.info("More then one Material Cost Element for CostingMethod=" + CostingMethod);
return retValue;
} // getMaterialCostElement
/**
* Get first Material Cost Element for a costing method
* @param ctx context
* @param CostingMethod costing method
* @return Cost Element or null
*/
public static MCostElement getMaterialCostElement(Properties ctx, String CostingMethod, int AD_Org_ID)
{
final String whereClause = "AD_Client_ID=? AND CostingMethod=? AND CostElementType=? AND AD_Org_ID In (0, ?)";
List list = new Query(ctx, I_M_CostElement.Table_Name, whereClause, null)
.setParameters(Env.getAD_Client_ID(ctx),CostingMethod,COSTELEMENTTYPE_Material,AD_Org_ID)
.setOrderBy(I_M_CostElement.COLUMNNAME_AD_Org_ID + " Desc")
.list();
MCostElement retValue = null;
if (list.size() > 0)
retValue = list.get(0);
if (list.size() > 1)
if (s_log.isLoggable(Level.INFO)) s_log.info("More then one Material Cost Element for CostingMethod=" + CostingMethod);
return retValue;
} // getMaterialCostElement
/**
* Get active Material Cost Element (associated with costing method) for client
* @param po parent
* @return cost element list
*/
public static List getCostElementsWithCostingMethods (PO po)
{
final String whereClause = "AD_Client_ID=? AND CostingMethod IS NOT NULL";
return new Query(po.getCtx(),MCostElement.Table_Name,whereClause,po.get_TrxName())
.setParameters(po.getAD_Client_ID())
.setOnlyActiveRecords(true)
.list();
} // getCostElementCostingMethod
/**
* Get active Material Cost Element (associated with costing method) for client
* @param po parent
* @return cost element array
*/
public static MCostElement[] getCostingMethods (PO po)
{
final String whereClause ="AD_Client_ID=? AND CostElementType=? AND CostingMethod IS NOT NULL";
List list = new Query(po.getCtx(), I_M_CostElement.Table_Name, whereClause, po.get_TrxName())
.setParameters(po.getAD_Client_ID(),COSTELEMENTTYPE_Material)
.setOnlyActiveRecords(true)
.list();
//
MCostElement[] retValue = new MCostElement[list.size ()];
list.toArray (retValue);
return retValue;
} // getMaterialCostElement
/**
* Get active non Material Cost Element (i.e costing method is null) for client
* @param po parent
* @return cost element array
*/
public static MCostElement[] getNonCostingMethods (PO po)
{
final String whereClause = "AD_Client_ID=? AND CostingMethod IS NULL";
Listlist = new Query(po.getCtx(),I_M_CostElement.Table_Name, whereClause, po.get_TrxName())
.setParameters(po.getAD_Client_ID())
.setOnlyActiveRecords(true)
.list();
//
MCostElement[] retValue = new MCostElement[list.size ()];
list.toArray (retValue);
return retValue;
} // getMaterialCostElement
// end MZ
/**
* Get Cost Element from Cache (immutable)
* @param M_CostElement_ID id
* @return Cost Element
*/
public static MCostElement get (int M_CostElement_ID)
{
return get(Env.getCtx(), M_CostElement_ID);
}
/**
* Get Cost Element from Cache (immutable)
* @param ctx context
* @param M_CostElement_ID id
* @return Cost Element
*/
public static MCostElement get (Properties ctx, int M_CostElement_ID)
{
Integer key = Integer.valueOf(M_CostElement_ID);
MCostElement retValue = s_cache.get (ctx, key, e -> new MCostElement(ctx, e));
if (retValue != null)
return retValue;
retValue = new MCostElement (ctx, M_CostElement_ID, (String)null);
if (retValue.get_ID () == M_CostElement_ID)
{
s_cache.put (key, retValue, e -> new MCostElement(Env.getCtx(), e));
return retValue;
}
return null;
} // get
/**
* Get updateable copy of MCostElement from cache
* @param ctx
* @param M_CostElement_ID
* @param trxName
* @return MCostElement
*/
public static MCostElement getCopy(Properties ctx, int M_CostElement_ID, String trxName)
{
MCostElement ce = get(M_CostElement_ID);
if (ce != null)
ce = new MCostElement(ctx, ce, trxName);
return ce;
}
/**
* Get All Cost Elements for current AD_Client_ID
* @param ctx context
* @param trxName transaction
* @return array cost elements
*/
public static MCostElement[] getElements (Properties ctx, String trxName)
{
int AD_Org_ID = 0; // Org is always ZERO - see beforeSave
final String whereClause = "AD_Client_ID = ? AND AD_Org_ID=?";
List list = new Query(ctx, Table_Name, whereClause, trxName)
.setParameters(Env.getAD_Client_ID(ctx),AD_Org_ID)
.list();
MCostElement[] retValue = new MCostElement[list.size()];
list.toArray(retValue);
return retValue;
}
/**
* Get All active Cost Elements for current AD_Client_ID
* @param ctx context
* @param CostingMethod
* @return cost element list
**/
public static List getByCostingMethod (Properties ctx, String CostingMethod)
{
final String whereClause = "AD_Client_ID = ? AND CostingMethod=?";
return new Query(ctx, Table_Name, whereClause, null)
.setOnlyActiveRecords(true)
.setParameters(Env.getAD_Client_ID(ctx),CostingMethod)
.list();
}
/** Cache */
protected static ImmutableIntPOCache s_cache = new ImmutableIntPOCache(Table_Name, 20);
/** Logger */
private static CLogger s_log = CLogger.getCLogger (MCostElement.class);
/**
* UUID based Constructor
* @param ctx Context
* @param M_CostElement_UU UUID key
* @param trxName Transaction
*/
public MCostElement(Properties ctx, String M_CostElement_UU, String trxName) {
super(ctx, M_CostElement_UU, trxName);
if (Util.isEmpty(M_CostElement_UU))
setInitialDefaults();
}
/**
* Standard Constructor
* @param ctx context
* @param M_CostElement_ID id
* @param trxName trx
*/
public MCostElement (Properties ctx, int M_CostElement_ID, String trxName)
{
super (ctx, M_CostElement_ID, trxName);
if (M_CostElement_ID == 0)
setInitialDefaults();
} // MCostElement
/**
* Set the initial defaults for a new record
*/
private void setInitialDefaults() {
setCostElementType (COSTELEMENTTYPE_Material);
setIsCalculated (false);
}
/**
* Load Constructor
* @param ctx context
* @param rs result set
* @param trxName trx
*/
public MCostElement (Properties ctx, ResultSet rs, String trxName)
{
super (ctx, rs, trxName);
} // MCostElement
/**
* Copy constructor
* @param copy
*/
public MCostElement(MCostElement copy)
{
this(Env.getCtx(), copy);
}
/**
* Copy constructor
* @param ctx
* @param copy
*/
public MCostElement(Properties ctx, MCostElement copy)
{
this(ctx, copy, (String) null);
}
/**
* Copy constructor
* @param ctx
* @param copy
* @param trxName
*/
public MCostElement(Properties ctx, MCostElement copy, String trxName)
{
this(ctx, 0, trxName);
copyPO(copy);
}
@Override
protected boolean beforeSave (boolean newRecord)
{
// For material and outside processing cost element type, CostingMethod must be unique
if (
( COSTELEMENTTYPE_Material.equals(getCostElementType())
|| COSTELEMENTTYPE_OutsideProcessing.equals(getCostElementType())
)
&& (newRecord || is_ValueChanged(COLUMNNAME_CostingMethod)))
{
String sql = "SELECT COALESCE(MAX(M_CostElement_ID),0) FROM M_CostElement "
+ "WHERE AD_Client_ID=? AND CostingMethod=? AND CostElementType=?";
int id = DB.getSQLValue(get_TrxName(), sql, getAD_Client_ID(), getCostingMethod() , getCostElementType());
if (id > 0 && id != get_ID())
{
log.saveError("AlreadyExists", Msg.getElement(getCtx(), "CostingMethod"));
return false;
}
}
if (getAD_Org_ID() != 0)
setAD_Org_ID(0);
return true;
} // beforeSave
@Override
protected boolean beforeDelete ()
{
String cm = getCostingMethod();
if (cm == null
|| !COSTELEMENTTYPE_Material.equals(getCostElementType()))
return true;
// Disallow delete if costing method is use by accounting schema
MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID());
for (int i = 0; i < ass.length; i++)
{
if (ass[i].getCostingMethod().equals(getCostingMethod()))
{
log.saveError("CannotDeleteUsed", Msg.getElement(getCtx(), "C_AcctSchema_ID")
+ " - " + ass[i].getName());
return false;
}
}
// Disallow delete if costing method is use by product category accounting
int M_Product_Category_ID = 0;
final String whereClause ="AD_Client_ID=? AND CostingMethod=?";
MProductCategoryAcct retValue = new Query(getCtx(), I_M_Product_Category_Acct.Table_Name, whereClause, null)
.setParameters(getAD_Client_ID(), getCostingMethod())
.first();
if (retValue != null)
M_Product_Category_ID = retValue.getM_Product_Category_ID();
if (M_Product_Category_ID != 0)
{
log.saveError("CannotDeleteUsed", Msg.getElement(getCtx(), "M_Product_Category_ID")
+ " (ID=" + M_Product_Category_ID + ")");
return false;
}
return true;
} // beforeDelete
/**
* Is this a Costing Method
* @return true if cost element is of type material and costing method is not null
*/
public boolean isCostingMethod()
{
return COSTELEMENTTYPE_Material.equals(getCostElementType())
&& getCostingMethod() != null;
} // isCostingMethod
/**
* Is Avg Invoice Costing Method
* @return true if costing method is AverageInvoice
*/
public boolean isAverageInvoice()
{
String cm = getCostingMethod();
return cm != null
&& cm.equals(COSTINGMETHOD_AverageInvoice)
&& COSTELEMENTTYPE_Material.equals(getCostElementType());
} // isAverageInvoice
/**
* Is Avg PO Costing Method
* @return true if costing method is AveragePO
*/
public boolean isAveragePO()
{
String cm = getCostingMethod();
return cm != null
&& cm.equals(COSTINGMETHOD_AveragePO)
&& COSTELEMENTTYPE_Material.equals(getCostElementType());
} // isAveragePO
/**
* Is FiFo Costing Method
* @return true if costing method is Fifo
*/
public boolean isFifo()
{
String cm = getCostingMethod();
return cm != null
&& cm.equals(COSTINGMETHOD_Fifo)
&& COSTELEMENTTYPE_Material.equals(getCostElementType());
} // isFifo
/**
* Is Last Invoice Costing Method
* @return true if costing method is LastInvoice
*/
public boolean isLastInvoice()
{
String cm = getCostingMethod();
return cm != null
&& cm.equals(COSTINGMETHOD_LastInvoice)
&& COSTELEMENTTYPE_Material.equals(getCostElementType());
} // isLastInvoice
/**
* Is Last PO Costing Method
* @return true if costing method is LastPOPrice
*/
public boolean isLastPOPrice()
{
String cm = getCostingMethod();
return cm != null
&& cm.equals(COSTINGMETHOD_LastPOPrice)
&& COSTELEMENTTYPE_Material.equals(getCostElementType());
} // isLastPOPrice
/**
* Is LiFo Costing Method
* @return true if costing method is Lifo
*/
public boolean isLifo()
{
String cm = getCostingMethod();
return cm != null
&& cm.equals(COSTINGMETHOD_Lifo)
&& COSTELEMENTTYPE_Material.equals(getCostElementType());
} // isLiFo
/**
* Is Std Costing Method
* @return true if costing method is StandardCosting
*/
public boolean isStandardCosting()
{
String cm = getCostingMethod();
return cm != null
&& cm.equals(COSTINGMETHOD_StandardCosting)
&& COSTELEMENTTYPE_Material.equals(getCostElementType());
} // isStandardCosting
/**
* Is User Costing Method
* @return true if costing method is User Defined
*/
public boolean isUserDefined()
{
String cm = getCostingMethod();
return cm != null
&& cm.equals(COSTINGMETHOD_UserDefined)
&& COSTELEMENTTYPE_Material.equals(getCostElementType());
} // isAveragePO
/**
* String Representation
* @return info
*/
@Override
public String toString ()
{
StringBuilder sb = new StringBuilder ("MCostElement[");
sb.append (get_ID ())
.append ("-").append (getName())
.append(",Type=").append(getCostElementType())
.append(",Method=").append(getCostingMethod())
.append ("]");
return sb.toString ();
} // toString
@Override
public MCostElement markImmutable() {
if (is_Immutable())
return this;
makeImmutable();
return this;
}
} // MCostElement