/****************************************************************************** * 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.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Properties; import java.util.logging.Level; import org.adempiere.exceptions.NegativeInventoryDisallowedException; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Util; /** * Inventory On Hand Storage Model * * @author Jorg Janke * @version $Id: MStorageOnHand.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $ */ public class MStorageOnHand extends X_M_StorageOnHand { /** * generated serial id */ private static final long serialVersionUID = -3820729340100521329L; /** * @param ctx * @param M_Locator_ID * @param M_Product_ID * @param M_AttributeSetInstance_ID * @param trxName * @deprecated * @return MStorageOnHand */ @Deprecated public static MStorageOnHand get (Properties ctx, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID, String trxName) { return get (ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, null, trxName); } /** * Get On Hand Storage * @param ctx context * @param M_Locator_ID locator * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance * @param dateMPolicy optional DateMaterialPolicy filter * @param trxName transaction * @return existing MStorageOnHand or null */ public static MStorageOnHand get (Properties ctx, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID,Timestamp dateMPolicy, String trxName) { String sqlWhere = "M_Locator_ID=? AND M_Product_ID=? AND "; if (M_AttributeSetInstance_ID == 0) sqlWhere += "(M_AttributeSetInstance_ID=? OR M_AttributeSetInstance_ID IS NULL)"; else sqlWhere += "M_AttributeSetInstance_ID=?"; if (dateMPolicy != null) sqlWhere += " AND DateMaterialPolicy=trunc(cast(? as date))"; Query query = new Query(ctx, MStorageOnHand.Table_Name, sqlWhere, trxName); if (dateMPolicy != null) query.setParameters(M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, dateMPolicy); else query.setParameters(M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID); MStorageOnHand retValue = query.first(); if (retValue == null) { if (s_log.isLoggable(Level.FINE)) s_log.fine("Not Found - M_Locator_ID=" + M_Locator_ID + ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID); } else { if (s_log.isLoggable(Level.FINE)) s_log.fine("M_Locator_ID=" + M_Locator_ID + ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID); } return retValue; } // get /** * Get all Storages for Product with ASI and QtyOnHand != 0 * @param ctx context * @param M_Product_ID product * @param M_Locator_ID locator * @param FiFo true for fifo, false for lifo * @param trxName transaction * @return array of MStorageOnHand */ public static MStorageOnHand[] getAllWithASI (Properties ctx, int M_Product_ID, int M_Locator_ID, boolean FiFo, String trxName) { ArrayList list = new ArrayList(); String sql = "SELECT * FROM M_StorageOnHand " + "WHERE M_Product_ID=? AND M_Locator_ID=?" + " AND M_AttributeSetInstance_ID > 0 " + " AND QtyOnHand <> 0 " + "ORDER BY M_AttributeSetInstance_ID"; if (!FiFo) sql += " DESC"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement (sql, trxName); pstmt.setInt (1, M_Product_ID); pstmt.setInt (2, M_Locator_ID); rs = pstmt.executeQuery (); while (rs.next ()) list.add(new MStorageOnHand (ctx, rs, trxName)); } catch (SQLException ex) { s_log.log(Level.SEVERE, sql, ex); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } MStorageOnHand[] retValue = new MStorageOnHand[list.size()]; list.toArray(retValue); return retValue; } // getAllWithASI /** * Get all Storages for Product where QtyOnHand != 0 * @param ctx context * @param M_Product_ID product * @param M_Locator_ID locator, 0 to match all locator * @param trxName transaction * @return array of MStorageOnHand */ public static MStorageOnHand[] getAll (Properties ctx, int M_Product_ID, int M_Locator_ID, String trxName) { return getAll(ctx, M_Product_ID, M_Locator_ID, trxName, false, 0); } /** * Get all Storages for Product where QtyOnHand != 0 * @param ctx context * @param M_Product_ID product * @param M_Locator_ID locator, 0 to match all locator * @param trxName transaction * @param forUpdate true to use For Update clause * @param timeout query timeout if forUpdate is true (0 for no timeout) * @return array of MStorageOnHand */ public static MStorageOnHand[] getAll (Properties ctx, int M_Product_ID, int M_Locator_ID, String trxName, boolean forUpdate, int timeout) { return getAll(ctx, M_Product_ID, M_Locator_ID, false, true, trxName, forUpdate, timeout); } /** * Get all Storages for Product where QtyOnHand != 0 * @param ctx context * @param M_Product_ID product * @param M_Locator_ID locator, 0 to match all locator * @param locatorPriority If true, sort descending by locator Priority No * @param fifo Sort ascending(FIFO) or descending(LIFO) by date material policy, m_attributesetinstance_id * @param trxName transaction * @param forUpdate If true, acquire DB lock with FOR UPDATE clause * @param timeout query timeout if forUpdate is true (0 for no timeout) * @return array of MStorageOnHand */ public static MStorageOnHand[] getAll (Properties ctx, int M_Product_ID, int M_Locator_ID, boolean locatorPriority, boolean fifo, String trxName, boolean forUpdate, int timeout) { String sqlWhere = "M_Product_ID=? AND QtyOnHand <> 0"; if (M_Locator_ID > 0) sqlWhere = sqlWhere + " AND M_Locator_ID=? "; Query query = new Query(ctx, MStorageOnHand.Table_Name, sqlWhere, trxName); if (M_Locator_ID > 0) query.setParameters(M_Product_ID, M_Locator_ID); else query.setParameters(M_Product_ID); MProduct product = MProduct.get(ctx, M_Product_ID); StringBuilder orderBy = new StringBuilder(); if (locatorPriority) { query.addJoinClause("JOIN M_Locator locator ON (M_StorageOnHand.M_Locator_ID=locator.M_Locator_ID) "); orderBy.append("locator.PriorityNo DESC, "); } if (product.isUseGuaranteeDateForMPolicy()) { query.addJoinClause(" LEFT OUTER JOIN M_AttributeSetInstance asi ON (M_StorageOnHand.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) "); orderBy.append("asi.").append(I_M_AttributeSetInstance.COLUMNNAME_GuaranteeDate); if (!fifo) orderBy.append(" DESC"); orderBy.append(", "); orderBy.append(MStorageOnHand.Table_Name).append(".").append(MStorageOnHand.COLUMNNAME_M_AttributeSetInstance_ID); if (!fifo) orderBy.append(" DESC"); query.setOrderBy(orderBy.toString()); } else { orderBy.append(MStorageOnHand.Table_Name).append(".").append(MStorageOnHand.COLUMNNAME_DateMaterialPolicy); if (!fifo) orderBy.append(" DESC"); orderBy.append(", "); orderBy.append(MStorageOnHand.Table_Name).append(".").append(MStorageOnHand.COLUMNNAME_M_AttributeSetInstance_ID); if (!fifo) orderBy.append(" DESC"); query.setOrderBy(orderBy.toString()); } if (forUpdate) { query.setForUpdate(forUpdate); if (timeout > 0) { query.setQueryTimeout(timeout); } } List list = query.list(); MStorageOnHand[] retValue = new MStorageOnHand[list.size()]; list.toArray(retValue); return retValue; } // getAll /** * Get On Hand Storage * @param ctx context * @param M_Product_ID product * @param M_Locator_ID locator * @param M_AttributeSetInstance_ID instance * @param dateMPolicy optional DateMaterialPolicy filter * @param ignoreZeroQty if true, only get storage record with on hand != 0 * @param trxName transaction * @return array of MStorageOnHand */ public static MStorageOnHand[] getAll (Properties ctx, int M_Product_ID, int M_Locator_ID, int M_AttributeSetInstance_ID, Timestamp dateMPolicy, boolean ignoreZeroQty, String trxName) { String sqlWhere = "M_Locator_ID=? AND M_Product_ID=? AND "; if (M_AttributeSetInstance_ID == 0) sqlWhere += "(M_AttributeSetInstance_ID=? OR M_AttributeSetInstance_ID IS NULL)"; else sqlWhere += "M_AttributeSetInstance_ID=?"; if (ignoreZeroQty) sqlWhere += " AND QtyOnHand<>0 "; if (dateMPolicy != null) sqlWhere += " AND DateMaterialPolicy=trunc(cast(? as date))"; Query query = new Query(ctx, MStorageOnHand.Table_Name, sqlWhere, trxName); if (dateMPolicy != null) query.setParameters(M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, dateMPolicy); else query.setParameters(M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID); List list = query.list(); if (list == null || list.isEmpty()) { if (s_log.isLoggable(Level.FINE)) s_log.fine("Not Found - M_Locator_ID=" + M_Locator_ID + ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID); } else { if (s_log.isLoggable(Level.FINE)) s_log.fine("Found " + list.size() + " - M_Locator_ID=" + M_Locator_ID + ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID); } MStorageOnHand[] retValue = new MStorageOnHand[list.size()]; list.toArray(retValue); return retValue; } // getAll /** * Get On Hand Storage for Product across warehouses * @param ctx context * @param M_Product_ID product * @param trxName transaction * @return array of MStorageOnHand */ public static MStorageOnHand[] getOfProduct (Properties ctx, int M_Product_ID, String trxName) { String sqlWhere = "M_Product_ID=?"; List list = new Query(ctx, MStorageOnHand.Table_Name, sqlWhere, trxName) .setParameters(M_Product_ID) .list(); MStorageOnHand[] retValue = new MStorageOnHand[list.size()]; list.toArray(retValue); return retValue; } // getOfProduct /** * Get On Hand Storage for Warehouse * @param ctx context * @param M_Warehouse_ID * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance * @param M_AttributeSet_ID attribute set (NOT USED) * @param allAttributeInstances if true, all attribute set instances (NOT USED) * @param minGuaranteeDate optional minimum guarantee date filter. ignore if M_AttributeSetInstance_ID != 0 * @param FiFo first in-first-out * @param trxName transaction * @return existing - ordered by location priority (desc) and/or guarantee date * * @deprecated */ @Deprecated public static MStorageOnHand[] getWarehouse (Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, int M_AttributeSet_ID, boolean allAttributeInstances, Timestamp minGuaranteeDate, boolean FiFo, String trxName) { return getWarehouse(ctx, M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, minGuaranteeDate, FiFo, false, 0, trxName); } /** * Get On Hand Storage for Warehouse or locator * @param ctx context * @param M_Warehouse_ID ignore if M_Locator_ID > 0 * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance id, 0 to retrieve all instance * @param minGuaranteeDate optional minimum guarantee date filter. ignore if M_AttributeSetInstance_ID != 0 * @param FiFo true first in-first-out, false for LIFO * @param positiveOnly if true, only return storage records with qtyOnHand > 0 * @param M_Locator_ID optional locator id * @param trxName transaction * @return array of MStorageOnHand - ordered by location priority (desc) and/or guarantee date */ public static MStorageOnHand[] getWarehouse (Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, Timestamp minGuaranteeDate, boolean FiFo, boolean positiveOnly, int M_Locator_ID, String trxName) { return getWarehouse(ctx, M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, minGuaranteeDate, FiFo, positiveOnly, M_Locator_ID, trxName, false); } /** * Get On Hand Storage for Warehouse or locator * @param ctx context * @param M_Warehouse_ID ignore if M_Locator_ID > 0 * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance id, 0 to retrieve all instance * @param minGuaranteeDate optional minimum guarantee date filter. ignore if M_AttributeSetInstance_ID != 0 * @param FiFo true for first in-first-out, false for LIFO * @param positiveOnly if true, only return storage records with qtyOnHand > 0 * @param M_Locator_ID optional locator id * @param trxName transaction * @param forUpdate true to acquire DB lock with FOR UPDATE clause * @return array of MStorageOnHand - ordered by location priority (desc) and/or guarantee date */ public static MStorageOnHand[] getWarehouse (Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, Timestamp minGuaranteeDate, boolean FiFo, boolean positiveOnly, int M_Locator_ID, String trxName, boolean forUpdate) { return getWarehouse(ctx, M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, minGuaranteeDate, FiFo, positiveOnly, M_Locator_ID, trxName, forUpdate, 0); } /** * Get On Hand Storage for Warehouse or locator * @param ctx context * @param M_Warehouse_ID ignore if M_Locator_ID > 0 * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance id, 0 to retrieve all instance * @param minGuaranteeDate optional minimum guarantee date filter. ignore if M_AttributeSetInstance_ID != 0 * @param FiFo true for first in-first-out, false for LIFO * @param positiveOnly if true, only return storage records with qtyOnHand > 0 * @param M_Locator_ID optional locator id * @param trxName transaction * @param forUpdate true to acquire DB lock with FOR UPDATE clause * @param timeout if forUpdate is true, value for query timeout (0 for no timeout). * @return array of MStorageOnHand - ordered by location priority (desc) and/or guarantee date */ public static MStorageOnHand[] getWarehouse (Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, Timestamp minGuaranteeDate, boolean FiFo, boolean positiveOnly, int M_Locator_ID, String trxName, boolean forUpdate, int timeout) { if ((M_Warehouse_ID == 0 && M_Locator_ID == 0) || M_Product_ID == 0) return new MStorageOnHand[0]; boolean allAttributeInstances = false; if (M_AttributeSetInstance_ID == 0) allAttributeInstances = true; ArrayList list = new ArrayList(); String sql; if (! allAttributeInstances) { // Specific Attribute Set Instance sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID," + "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy," + "s.QtyOnHand,s.DateLastInventory,s.M_StorageOnHand_UU,s.DateMaterialPolicy " + "FROM M_StorageOnHand s" + " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID) "; if (M_Locator_ID > 0) sql += "WHERE l.M_Locator_ID = ?"; else sql += "WHERE l.M_Warehouse_ID=?"; sql += " AND s.M_Product_ID=?" + " AND COALESCE(s.M_AttributeSetInstance_ID,0)=? "; if (positiveOnly) { sql += " AND s.QtyOnHand > 0 "; } else { sql += " AND s.QtyOnHand <> 0 "; } sql += " ORDER BY l.PriorityNo DESC, DateMaterialPolicy "; if (!FiFo) sql += " DESC, s.M_AttributeSetInstance_ID DESC "; else sql += ", s.M_AttributeSetInstance_ID "; } else { // All Attribute Set Instances sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID," + " s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy," + " s.QtyOnHand,s.DateLastInventory,s.M_StorageOnHand_UU,s.DateMaterialPolicy " + " FROM M_StorageOnHand s" + " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID)" + " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) "; if (M_Locator_ID > 0) sql += "WHERE l.M_Locator_ID = ?"; else sql += "WHERE l.M_Warehouse_ID=?"; sql += " AND s.M_Product_ID=? "; if (positiveOnly) { sql += " AND s.QtyOnHand > 0 "; } else { sql += " AND s.QtyOnHand <> 0 "; } if (minGuaranteeDate != null) { sql += " AND (asi.GuaranteeDate IS NULL OR asi.GuaranteeDate>?) "; } MProduct product = MProduct.get(Env.getCtx(), M_Product_ID); if(product.isUseGuaranteeDateForMPolicy()){ sql += " ORDER BY l.PriorityNo DESC, COALESCE(asi.GuaranteeDate,s.DateMaterialPolicy)"; if (!FiFo) sql += " DESC, s.M_AttributeSetInstance_ID DESC "; else sql += ", s.M_AttributeSetInstance_ID "; } else { sql += " ORDER BY l.PriorityNo DESC, s.DateMaterialPolicy"; if (!FiFo) sql += " DESC, s.M_AttributeSetInstance_ID DESC "; else sql += ", s.M_AttributeSetInstance_ID "; } sql += ", s.QtyOnHand DESC"; } PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, trxName); pstmt.setInt(1, M_Locator_ID > 0 ? M_Locator_ID : M_Warehouse_ID); pstmt.setInt(2, M_Product_ID); if (!allAttributeInstances) { pstmt.setInt(3, M_AttributeSetInstance_ID); } else if (minGuaranteeDate != null) { pstmt.setTimestamp(3, minGuaranteeDate); } rs = pstmt.executeQuery(); while (rs.next()) { if(rs.getBigDecimal(11).signum() != 0) { MStorageOnHand storage = new MStorageOnHand (ctx, rs, trxName); if (!Util.isEmpty(trxName) && forUpdate) { DB.getDatabase().forUpdate(storage, timeout); } list.add (storage); } } } catch (Exception e) { s_log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } MStorageOnHand[] retValue = new MStorageOnHand[list.size()]; list.toArray(retValue); return retValue; } // getWarehouse /** * Get On Hand Storage for Warehouse or locator * @param ctx context * @param M_Warehouse_ID ignore if M_Locator_ID > 0 * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance id, 0 to retrieve all instance * @param minGuaranteeDate optional minimum guarantee date filter. ignore if M_AttributeSetInstance_ID != 0 * @param FiFo true for first in-first-out, false for LIFO * @param M_Locator_ID optional locator id * @param trxName transaction * @return array of MStorageOnHand - ordered by location priority (desc) and/or guarantee date */ public static MStorageOnHand[] getWarehouseNegative (Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, Timestamp minGuaranteeDate, boolean FiFo, int M_Locator_ID, String trxName) { return getWarehouseNegative(ctx, M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, minGuaranteeDate, FiFo, M_Locator_ID, trxName, false); } /** * Get On Hand Storage for Warehouse or locator * @param ctx context * @param M_Warehouse_ID ignore if M_Locator_ID > 0 * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance id, 0 to retrieve storages that don't have asi, -1 to retrieve all instance * @param minGuaranteeDate optional minimum guarantee date filter. ignore if M_AttributeSetInstance_ID != 0 * @param FiFo true for first in-first-out, false for LIFO * @param M_Locator_ID optional locator id * @param trxName transaction * @param forUpdate true to acquire DB lock with FOR UPDATE clause * @return array of MStorageOnHand - ordered by location priority (desc) and/or guarantee date */ public static MStorageOnHand[] getWarehouseNegative (Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, Timestamp minGuaranteeDate, boolean FiFo, int M_Locator_ID, String trxName, boolean forUpdate) { return getWarehouseNegative(ctx, M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, minGuaranteeDate, FiFo, M_Locator_ID, trxName, forUpdate, 0); } /** * Get On Hand Storage for Warehouse or locator * @param ctx context * @param M_Warehouse_ID ignore if M_Locator_ID > 0 * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance id, 0 to retrieve storages that don't have asi, -1 to retrieve all instance * @param minGuaranteeDate optional minimum guarantee date filter * @param FiFo true for first in-first-out, false for LIFO * @param M_Locator_ID optional locator id * @param trxName transaction * @param forUpdate true to acquire DB lock with FOR UPDATE clause * @param timeout if forUpdate is true, value for query timeout (0 for no timeout). * @return array of MStorageOnHand - ordered by location priority (desc) and/or guarantee date */ public static MStorageOnHand[] getWarehouseNegative (Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, Timestamp minGuaranteeDate, boolean FiFo, int M_Locator_ID, String trxName, boolean forUpdate, int timeout) { if ((M_Warehouse_ID == 0 && M_Locator_ID == 0) || M_Product_ID == 0) return new MStorageOnHand[0]; ArrayList list = new ArrayList(); String sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID," + "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy," + "s.QtyOnHand,s.DateLastInventory,s.M_StorageOnHand_UU,s.DateMaterialPolicy " + "FROM M_StorageOnHand s" + " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID)" + " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) "; if (M_Locator_ID > 0) sql += "WHERE l.M_Locator_ID = ?"; else sql += "WHERE l.M_Warehouse_ID=?"; sql += " AND s.M_Product_ID=? " + " AND s.QtyOnHand < 0 "; if (minGuaranteeDate != null) { sql += "AND (asi.GuaranteeDate IS NULL OR asi.GuaranteeDate>?) "; } if (M_AttributeSetInstance_ID > 0) { sql += "AND s.M_AttributeSetInstance_ID=? "; } else if (M_AttributeSetInstance_ID == 0) { sql += "AND (s.M_AttributeSetInstance_ID=0 OR s.M_AttributeSetInstance_ID IS NULL) "; } MProduct product = MProduct.get(Env.getCtx(), M_Product_ID, trxName); if(product.isUseGuaranteeDateForMPolicy()){ sql += " ORDER BY l.PriorityNo DESC, " + "asi.GuaranteeDate"; if (!FiFo) sql += " DESC"; } else { sql += " ORDER BY l.PriorityNo DESC, s.DateMaterialPolicy"; if (!FiFo) sql += " DESC, s.M_AttributeSetInstance_ID DESC "; else sql += ", s.M_AttributeSetInstance_ID "; } sql += ", s.QtyOnHand DESC"; PreparedStatement pstmt = null; ResultSet rs = null; try { int index = 0; pstmt = DB.prepareStatement(sql, trxName); pstmt.setInt(++index, M_Locator_ID > 0 ? M_Locator_ID : M_Warehouse_ID); pstmt.setInt(++index, M_Product_ID); if (minGuaranteeDate != null) { pstmt.setTimestamp(++index, minGuaranteeDate); } if (M_AttributeSetInstance_ID > 0) { pstmt.setInt(++index, M_AttributeSetInstance_ID); } rs = pstmt.executeQuery(); while (rs.next()) { if(rs.getBigDecimal(11).signum() != 0) { MStorageOnHand storage = new MStorageOnHand (ctx, rs, trxName); if (!Util.isEmpty(trxName) && forUpdate) { DB.getDatabase().forUpdate(storage, timeout); } list.add(storage); } } } catch (Exception e) { s_log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } MStorageOnHand[] retValue = new MStorageOnHand[list.size()]; list.toArray(retValue); return retValue; } // getWarehouse /** * Create or Get On Hand Storage * @param ctx context * @param M_Locator_ID locator * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance * @param trxName transaction * @return existing or new MStorageOnHand */ public static MStorageOnHand getCreate (Properties ctx, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID,Timestamp dateMPolicy, String trxName) { return getCreate(ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, dateMPolicy, trxName, false); } /** * Create or Get On Hand Storage * @param ctx context * @param M_Locator_ID locator * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance * @param dateMPolicy optional DateMaterialPolicy filter * @param trxName transaction * @param forUpdate true to acquire DB lock with FOR UPDATE clause * @return existing or new MStorageOnHand */ public static MStorageOnHand getCreate (Properties ctx, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID,Timestamp dateMPolicy, String trxName, boolean forUpdate) { return getCreate(ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, dateMPolicy, trxName, forUpdate, 0); } /** * Create or Get On Hand Storage * @param ctx context * @param M_Locator_ID locator * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance * @param dateMPolicy optional DateMaterialPolicy filter * @param trxName transaction * @param forUpdate true to acquire DB lock with FOR UPDATE clause * @param timeout if forUpdate is true, value for query timeout (0 for no timeout). * @return existing or new MStorageOnHand */ public static MStorageOnHand getCreate (Properties ctx, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID,Timestamp dateMPolicy, String trxName, boolean forUpdate, int timeout) { if (M_Locator_ID == 0) throw new IllegalArgumentException("M_Locator_ID=0"); if (M_Product_ID == 0) throw new IllegalArgumentException("M_Product_ID=0"); if (dateMPolicy != null) dateMPolicy = Util.removeTime(dateMPolicy); MStorageOnHand retValue = get(ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID,dateMPolicy, trxName); if (retValue != null) { if (forUpdate) DB.getDatabase().forUpdate(retValue, timeout); return retValue; } // Insert row based on locator MLocator locator = new MLocator (ctx, M_Locator_ID, trxName); if (locator.get_ID() != M_Locator_ID) throw new IllegalArgumentException("Not found M_Locator_ID=" + M_Locator_ID); // if (dateMPolicy == null) { dateMPolicy = new Timestamp(new Date().getTime()); dateMPolicy = Util.removeTime(dateMPolicy); } retValue = new MStorageOnHand (locator, M_Product_ID, M_AttributeSetInstance_ID,dateMPolicy); retValue.saveEx(trxName); if (s_log.isLoggable(Level.FINE)) s_log.fine("New " + retValue); return retValue; } // getCreate /** * Update On Hand Storage * Called from MProjectIssue * @param ctx context * @param M_Warehouse_ID warehouse * @param M_Locator_ID locator * @param M_Product_ID product * @param M_AttributeSetInstance_ID AS Instance * @param diffQtyOnHand add on hand * @param trxName transaction * @return true if updated * @deprecated */ @Deprecated public static boolean add (Properties ctx, int M_Warehouse_ID, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID, BigDecimal diffQtyOnHand, String trxName) { return add(ctx, M_Warehouse_ID, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, diffQtyOnHand, null, trxName); } /** * Update On Hand Storage * Called from MProjectIssue * @param ctx context * @param M_Warehouse_ID warehouse, not use * @param M_Locator_ID locator * @param M_Product_ID product * @param M_AttributeSetInstance_ID AS Instance * @param diffQtyOnHand add on hand * @param dateMPolicy * @param trxName transaction * @return true if updated * @deprecated */ @Deprecated public static boolean add (Properties ctx, int M_Warehouse_ID, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID, BigDecimal diffQtyOnHand,Timestamp dateMPolicy, String trxName) { return add(ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, diffQtyOnHand, dateMPolicy, null, trxName); } public static boolean add (Properties ctx, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID, BigDecimal diffQtyOnHand,Timestamp dateMPolicy, String trxName) { return add(ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, diffQtyOnHand, dateMPolicy, null, trxName); } /** * Update On Hand Storage * Called from MProjectIssue * @param ctx context * @param M_Locator_ID locator * @param M_Product_ID product * @param M_AttributeSetInstance_ID AS Instance * @param diffQtyOnHand difference to add to current on hand quantity * @param dateMPolicy optional DateMaterialPolicy filter * @param trxName transaction * @return true if updated */ public static boolean add (Properties ctx, int M_Locator_ID, int M_Product_ID, int M_AttributeSetInstance_ID, BigDecimal diffQtyOnHand,Timestamp dateMPolicy, Timestamp dateLastInventory, String trxName) { if (diffQtyOnHand == null || diffQtyOnHand.signum() == 0) return true; if (dateMPolicy != null) dateMPolicy = Util.removeTime(dateMPolicy); // Get Storage MStorageOnHand storage = getCreate (ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, dateMPolicy, trxName, true, 120); // Verify if (storage.getM_Locator_ID() != M_Locator_ID && storage.getM_Product_ID() != M_Product_ID && storage.getM_AttributeSetInstance_ID() != M_AttributeSetInstance_ID) { s_log.severe ("No Storage found - M_Locator_ID=" + M_Locator_ID + ",M_Product_ID=" + M_Product_ID + ",ASI=" + M_AttributeSetInstance_ID); return false; } if(dateLastInventory != null) storage.updateDateLastInventory(dateLastInventory); storage.addQtyOnHand(diffQtyOnHand); if (s_log.isLoggable(Level.FINE)) { StringBuilder diffText = new StringBuilder("(OnHand=").append(diffQtyOnHand).append(") -> ").append(storage.toString()); s_log.fine(diffText.toString()); } return true; } // add /** * Add addition to quantity on hand with direct SQL - not using cached value - solving IDEMPIERE-2629 * @param addition */ public void addQtyOnHand(BigDecimal addition) { final String sql = "UPDATE M_StorageOnHand SET QtyOnHand=QtyOnHand+?, Updated=getDate(), UpdatedBy=? " + "WHERE M_Product_ID=? AND M_Locator_ID=? AND M_AttributeSetInstance_ID=? AND DateMaterialPolicy=?"; DB.executeUpdateEx(sql, new Object[] {addition, Env.getAD_User_ID(Env.getCtx()), getM_Product_ID(), getM_Locator_ID(), getM_AttributeSetInstance_ID(), getDateMaterialPolicy()}, get_TrxName()); load(get_TrxName()); if (getQtyOnHand().signum() == -1) { MWarehouse wh = MWarehouse.get(Env.getCtx(), getM_Warehouse_ID()); if (wh.isDisallowNegativeInv()) { throw new NegativeInventoryDisallowedException(getCtx(), getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(), getM_Locator_ID(), getQtyOnHand().subtract(addition), addition.negate()); } } } /** * Update Date Last Inventory of this record with direct SQL * @param dateLastInv */ public void updateDateLastInventory(Timestamp dateLastInv) { final String sql = "UPDATE M_StorageOnHand SET DateLastInventory=? " + "WHERE M_Product_ID=? AND M_Locator_ID=? AND M_AttributeSetInstance_ID=? AND DateMaterialPolicy=?"; DB.executeUpdateEx(sql, new Object[] {dateLastInv, getM_Product_ID(), getM_Locator_ID(), getM_AttributeSetInstance_ID(), getDateMaterialPolicy()}, get_TrxName()); load(get_TrxName()); } /** * Get Locator with highest Locator Priority and a sufficient OnHand Qty * @param M_Warehouse_ID warehouse * @param M_Product_ID product * @param M_AttributeSetInstance_ID asi id, use negative value (for e.g -1) to match all asi including 0 * @param Qty qty * @param trxName transaction * @return locator id (0 if no match found) */ public static int getM_Locator_ID (int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, BigDecimal Qty, String trxName) { int M_Locator_ID = 0; int firstM_Locator_ID = 0; String sql = "SELECT s.M_Locator_ID, s.QtyOnHand " + "FROM M_StorageOnHand s" + " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)" + " INNER JOIN M_Product p ON (s.M_Product_ID=p.M_Product_ID) "; if (M_AttributeSetInstance_ID >= 0) sql = sql + " LEFT OUTER JOIN M_AttributeSet mas ON (p.M_AttributeSet_ID=mas.M_AttributeSet_ID) "; sql = sql + "WHERE l.M_Warehouse_ID=? " + " AND s.M_Product_ID=? "; if (M_AttributeSetInstance_ID >= 0) sql = sql + " AND (mas.IsInstanceAttribute IS NULL OR mas.IsInstanceAttribute='N' OR s.M_AttributeSetInstance_ID=?) "; sql = sql + " AND l.IsActive='Y' " + "ORDER BY l.PriorityNo DESC, s.QtyOnHand DESC"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, trxName); pstmt.setInt(1, M_Warehouse_ID); pstmt.setInt(2, M_Product_ID); if (M_AttributeSetInstance_ID >= 0) pstmt.setInt(3, M_AttributeSetInstance_ID); rs = pstmt.executeQuery(); while (rs.next()) { BigDecimal QtyOnHand = rs.getBigDecimal(2); if (QtyOnHand != null && Qty.compareTo(QtyOnHand) <= 0) { M_Locator_ID = rs.getInt(1); break; } if (firstM_Locator_ID == 0) firstM_Locator_ID = rs.getInt(1); } } catch (SQLException ex) { s_log.log(Level.SEVERE, sql, ex); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } if (M_Locator_ID != 0) return M_Locator_ID; return firstM_Locator_ID; } // getM_Locator_ID /** * UUID based Constructor * @param ctx Context * @param M_StorageOnHand_UU UUID key * @param trxName Transaction */ public MStorageOnHand(Properties ctx, String M_StorageOnHand_UU, String trxName) { super(ctx, M_StorageOnHand_UU, trxName); if (Util.isEmpty(M_StorageOnHand_UU)) setInitialDefaults(); } /** * @param ctx context * @param ignored ignored * @param trxName transaction */ public MStorageOnHand (Properties ctx, int ignored, String trxName) { super(ctx, 0, trxName); if (ignored != 0) throw new IllegalArgumentException("Multi-Key"); setInitialDefaults(); } // MStorageOnHand /** * Set the initial defaults for a new record */ private void setInitialDefaults() { setQtyOnHand (Env.ZERO); } /** * Load Constructor * @param ctx context * @param rs result set * @param trxName transaction */ public MStorageOnHand (Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MStorageOnHand /** * NEW MStorageOnHand Constructor * @param locator (parent) locator * @param M_Product_ID product * @param M_AttributeSetInstance_ID attribute * @param dateMPolicy */ private MStorageOnHand (MLocator locator, int M_Product_ID, int M_AttributeSetInstance_ID, Timestamp dateMPolicy) { this (locator.getCtx(), 0, locator.get_TrxName()); setClientOrg(locator); setM_Locator_ID (locator.getM_Locator_ID()); setM_Product_ID (M_Product_ID); setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID); dateMPolicy = Util.removeTime(dateMPolicy); setDateMaterialPolicy(dateMPolicy); } // MStorageOnHand /** Log */ private static CLogger s_log = CLogger.getCLogger (MStorageOnHand.class); /** Warehouse */ private int m_M_Warehouse_ID = 0; /** * Get M_Warehouse_ID of Locator * @return warehouse */ public int getM_Warehouse_ID() { if (m_M_Warehouse_ID == 0) { MLocator loc = MLocator.get(getCtx(), getM_Locator_ID(), get_TrxName()); m_M_Warehouse_ID = loc.getM_Warehouse_ID(); } return m_M_Warehouse_ID; } // getM_Warehouse_ID /** * Before Save * @param newRecord new * @return success */ @Override protected boolean beforeSave(boolean newRecord) { // Negative Inventory check if (newRecord || is_ValueChanged("QtyOnHand")) { MWarehouse wh = new MWarehouse(getCtx(), getM_Warehouse_ID(), get_TrxName()); if (wh.isDisallowNegativeInv()) { String sql = "SELECT SUM(QtyOnHand) " + "FROM M_StorageOnHand s" + " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID) " + "WHERE s.M_Product_ID=?" // #1 + " AND l.M_Warehouse_ID=?" + " AND l.M_Locator_ID=?" + " AND s.M_AttributeSetInstance_ID<>?"; BigDecimal QtyOnHand = DB.getSQLValueBDEx(get_TrxName(), sql, new Object[] {getM_Product_ID(), getM_Warehouse_ID(), getM_Locator_ID(), getM_AttributeSetInstance_ID()}); if (QtyOnHand == null) QtyOnHand = Env.ZERO; // Add qty onhand for current record QtyOnHand = QtyOnHand.add(getQtyOnHand()); if (getQtyOnHand().compareTo(BigDecimal.ZERO) < 0 || QtyOnHand.compareTo(Env.ZERO) < 0) { log.saveError("Error", new NegativeInventoryDisallowedException(getCtx(), getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(), getM_Locator_ID(), QtyOnHand.subtract(getQtyOnHand()), getQtyOnHand().negate())); return false; } if (getM_AttributeSetInstance_ID() > 0 && getQtyOnHand().signum() < 0) { log.saveError("Error", new NegativeInventoryDisallowedException(getCtx(), getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(), getM_Locator_ID(), QtyOnHand.subtract(getQtyOnHand()), getQtyOnHand().negate())); return false; } } } return true; } /** * Get Quantity On Hand of Warehouse * @param M_Product_ID * @param M_Warehouse_ID * @param M_AttributeSetInstance_ID M_AttributeSetInstance_ID filter, ignore if 0 * @param trxName * @return QtyOnHand */ public static BigDecimal getQtyOnHand(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName) { StringBuilder sql = new StringBuilder(); sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh JOIN M_Locator loc ON (oh.M_Locator_ID=loc.M_Locator_ID)") .append(" WHERE oh.M_Product_ID=?") .append(" AND loc.M_Warehouse_ID=?"); ArrayList params = new ArrayList(); params.add(M_Product_ID); params.add(M_Warehouse_ID); // With ASI if (M_AttributeSetInstance_ID != 0) { sql.append(" AND oh.M_AttributeSetInstance_ID=?"); params.add(M_AttributeSetInstance_ID); } BigDecimal qty = DB.getSQLValueBD(trxName, sql.toString(), params); if (qty == null) qty = Env.ZERO; return qty; } /** * Get Quantity On Hand of Warehouse with ASI=0 * @param M_Product_ID * @param M_Warehouse_ID * @param trxName * @return QtyOnHand */ public static BigDecimal getQtyOnHandWithASIZero(int M_Product_ID, int M_Warehouse_ID, String trxName) { StringBuilder sql = new StringBuilder(); sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh JOIN M_Locator loc ON (oh.M_Locator_ID=loc.M_Locator_ID)") .append(" WHERE oh.M_Product_ID=?") .append(" AND loc.M_Warehouse_ID=?") .append(" AND oh.M_AttributeSetInstance_ID=0"); ArrayList params = new ArrayList(); params.add(M_Product_ID); params.add(M_Warehouse_ID); BigDecimal qty = DB.getSQLValueBD(trxName, sql.toString(), params); if (qty == null) qty = Env.ZERO; return qty; } /** * Get Quantity On Hand of Warehouse (only include Locator with Locator Type = Available for Reservation) * @param M_Product_ID * @param M_Warehouse_ID * @param M_AttributeSetInstance_ID * @param trxName * @return QtyOnHand */ public static BigDecimal getQtyOnHandForReservation(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName) { StringBuilder sql = new StringBuilder(); sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh" + " JOIN M_Locator loc ON (oh.M_Locator_ID=loc.M_Locator_ID)" + " LEFT JOIN M_LocatorType lt ON (loc.M_LocatorType_ID=lt.M_LocatorType_ID)") .append(" WHERE oh.M_Product_ID=?") .append(" AND loc.M_Warehouse_ID=? AND COALESCE(lt.IsAvailableForReservation,'Y')='Y'"); ArrayList params = new ArrayList(); params.add(M_Product_ID); params.add(M_Warehouse_ID); // With ASI if (M_AttributeSetInstance_ID != 0) { sql.append(" AND oh.M_AttributeSetInstance_ID=?"); params.add(M_AttributeSetInstance_ID); } BigDecimal qty = DB.getSQLValueBDEx(trxName, sql.toString(), params); if (qty == null) qty = Env.ZERO; return qty; } /** * Get Quantity On Hand of Warehouse with ASI=0 (only include Locator with Locator Type = Available for Reservation) * @param M_Product_ID * @param M_Warehouse_ID * @param trxName * @return QtyOnHand */ public static BigDecimal getQtyOnHandForReservationWithASIZero(int M_Product_ID, int M_Warehouse_ID, String trxName) { StringBuilder sql = new StringBuilder(); sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh" + " JOIN M_Locator loc ON (oh.M_Locator_ID=loc.M_Locator_ID)" + " LEFT JOIN M_LocatorType lt ON (loc.M_LocatorType_ID=lt.M_LocatorType_ID)") .append(" WHERE oh.M_Product_ID=?") .append(" AND loc.M_Warehouse_ID=? AND COALESCE(lt.IsAvailableForReservation,'Y')='Y'") .append(" AND oh.M_AttributeSetInstance_ID=0"); ArrayList params = new ArrayList(); params.add(M_Product_ID); params.add(M_Warehouse_ID); BigDecimal qty = DB.getSQLValueBDEx(trxName, sql.toString(), params); if (qty == null) qty = Env.ZERO; return qty; } /** * Get Quantity On Hand of Warehouse (only include Locator with Locator Type = available for shipping) * @param M_Product_ID * @param M_Warehouse_ID * @param M_AttributeSetInstance_ID * @param trxName * @return QtyOnHand */ public static BigDecimal getQtyOnHandForShipping(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName) { StringBuilder sql = new StringBuilder(); sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh JOIN M_Locator loc ON (oh.M_Locator_ID=loc.M_Locator_ID)") .append(" LEFT JOIN M_LocatorType lt ON (loc.M_LocatorType_ID=lt.M_LocatorType_ID)") .append(" WHERE oh.M_Product_ID=?") .append(" AND loc.M_Warehouse_ID=? AND COALESCE(lt.IsAvailableForShipping,'Y')='Y'"); ArrayList params = new ArrayList(); params.add(M_Product_ID); params.add(M_Warehouse_ID); // With ASI if (M_AttributeSetInstance_ID != 0) { sql.append(" AND oh.M_AttributeSetInstance_ID=?"); params.add(M_AttributeSetInstance_ID); } BigDecimal qty = DB.getSQLValueBDEx(trxName, sql.toString(), params); if (qty == null) qty = Env.ZERO; return qty; } /** * Get Quantity On Hand of Warehouse with ASI=0 (only include Locator with Locator Type = available for shipping) * @param M_Product_ID * @param M_Warehouse_ID * @param trxName * @return QtyOnHand */ public static BigDecimal getQtyOnHandForShippingWithASIZero(int M_Product_ID, int M_Warehouse_ID, String trxName) { StringBuilder sql = new StringBuilder(); sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh JOIN M_Locator loc ON (oh.M_Locator_ID=loc.M_Locator_ID)") .append(" LEFT JOIN M_LocatorType lt ON (loc.M_LocatorType_ID=lt.M_LocatorType_ID)") .append(" WHERE oh.M_Product_ID=?") .append(" AND loc.M_Warehouse_ID=? AND COALESCE(lt.IsAvailableForShipping,'Y')='Y'") .append(" AND oh.M_AttributeSetInstance_ID=0"); ArrayList params = new ArrayList(); params.add(M_Product_ID); params.add(M_Warehouse_ID); BigDecimal qty = DB.getSQLValueBDEx(trxName, sql.toString(), params); if (qty == null) qty = Env.ZERO; return qty; } /** * Get Quantity On Hand of Locator * @param M_Product_ID * @param M_Locator_ID * @param M_AttributeSetInstance_ID * @param trxName * @return QtyOnHand */ public static BigDecimal getQtyOnHandForLocator(int M_Product_ID, int M_Locator_ID, int M_AttributeSetInstance_ID, String trxName) { StringBuilder sql = new StringBuilder(); sql.append(" SELECT SUM(oh.QtyOnHand) FROM M_StorageOnHand oh") .append(" WHERE oh.M_Product_ID=?") .append(" AND oh.M_Locator_ID=?"); ArrayList params = new ArrayList(); params.add(M_Product_ID); params.add(M_Locator_ID); // With ASI if (M_AttributeSetInstance_ID != 0) { sql.append(" AND oh.M_AttributeSetInstance_ID=?"); params.add(M_AttributeSetInstance_ID); } BigDecimal qty = DB.getSQLValueBD(trxName, sql.toString(), params); if (qty == null) qty = Env.ZERO; return qty; } /** * Get Quantity On Hand of Locator with ASI=0 * @param M_Product_ID * @param M_Locator_ID * @param trxName * @return QtyOnHand */ public static BigDecimal getQtyOnHandForLocatorWithASIZero(int M_Product_ID, int M_Locator_ID, String trxName) { StringBuilder sql = new StringBuilder(); sql.append(" SELECT SUM(oh.QtyOnHand) FROM M_StorageOnHand oh") .append(" WHERE oh.M_Product_ID=?") .append(" AND oh.M_Locator_ID=?") .append(" AND oh.M_AttributeSetInstance_ID=0"); ArrayList params = new ArrayList(); params.add(M_Product_ID); params.add(M_Locator_ID); BigDecimal qty = DB.getSQLValueBD(trxName, sql.toString(), params); if (qty == null) qty = Env.ZERO; return qty; } /** * String Representation * @return info */ @Override public String toString() { StringBuilder sb = new StringBuilder("MStorageOnHand[") .append("M_Locator_ID=").append(getM_Locator_ID()) .append(",M_Product_ID=").append(getM_Product_ID()) .append(",M_AttributeSetInstance_ID=").append(getM_AttributeSetInstance_ID()) .append(",DateMaterialPolicy=").append(getDateMaterialPolicy()) .append(": OnHand=").append(getQtyOnHand()) .append("]"); return sb.toString(); } // toString /** * Get DateMaterialPolicy ORDER BY QtyOnHand DESC * @param M_Product_ID * @param M_AttributeSetInstance_ID * @param trxName * @return DateMaterialPolicy time stamp */ public static Timestamp getDateMaterialPolicy(int M_Product_ID, int M_AttributeSetInstance_ID,String trxName){ if (M_Product_ID <= 0 || M_AttributeSetInstance_ID <= 0) return null; String sql = "SELECT dateMaterialPolicy FROM M_StorageOnHand WHERE M_Product_ID=? and M_AttributeSetInstance_ID=? ORDER BY QtyOnHand DESC"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, trxName); pstmt.setInt(1, M_Product_ID); pstmt.setInt(2, M_AttributeSetInstance_ID); rs = pstmt.executeQuery(); if (rs.next()) { return rs.getTimestamp(1); } }catch (SQLException ex) { s_log.log(Level.SEVERE, sql, ex); }finally { DB.close(rs, pstmt); rs = null; pstmt = null; } return null; } //getDateMaterialPolicy /** * Get DateMaterialPolicy ORDER BY QtyOnHand DESC * @param M_Product_ID * @param M_AttributeSetInstance_ID * @param M_Locator_ID * @param trxName * @return DateMaterialPolicy time stamp */ public static Timestamp getDateMaterialPolicy(int M_Product_ID, int M_AttributeSetInstance_ID, int M_Locator_ID, String trxName) { if (M_Product_ID <= 0 || M_AttributeSetInstance_ID <= 0) return null; String sql = "SELECT dateMaterialPolicy FROM M_StorageOnHand WHERE M_Product_ID=? and M_AttributeSetInstance_ID=? AND M_Locator_ID=? ORDER BY QtyOnHand DESC"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, trxName); pstmt.setInt(1, M_Product_ID); pstmt.setInt(2, M_AttributeSetInstance_ID); pstmt.setInt(3, M_Locator_ID); rs = pstmt.executeQuery(); if (rs.next()) { return rs.getTimestamp(1); } } catch (SQLException ex) { s_log.log(Level.SEVERE, sql, ex); }finally { DB.close(rs, pstmt); rs = null; pstmt = null; } return null; } //getDateMaterialPolicy } // MStorageOnHand