diff --git a/org.adempiere.base.callout/src/org/compiere/model/CalloutMovement.java b/org.adempiere.base.callout/src/org/compiere/model/CalloutMovement.java index e11d85cee7..a197a2827f 100644 --- a/org.adempiere.base.callout/src/org/compiere/model/CalloutMovement.java +++ b/org.adempiere.base.callout/src/org/compiere/model/CalloutMovement.java @@ -121,7 +121,7 @@ public class CalloutMovement extends CalloutEngine if (M_Locator_ID <= 0) return; int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, "M_AttributeSetInstance_ID"); - BigDecimal available = MStorageOnHand.getQtyAvailable(0, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, null); + BigDecimal available = MStorageReservation.getQtyAvailable(0, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, null); if (available == null) available = Env.ZERO; if (available.signum() == 0) diff --git a/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java b/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java index 33f2353964..2cb9ce56c7 100644 --- a/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java +++ b/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java @@ -821,7 +821,7 @@ public class CalloutOrder extends CalloutEngine BigDecimal QtyOrdered = (BigDecimal)mTab.getValue("QtyOrdered"); int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID"); int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, "M_AttributeSetInstance_ID"); - BigDecimal available = MStorageOnHand.getQtyAvailable + BigDecimal available = MStorageReservation.getQtyAvailable (M_Warehouse_ID, 0, M_Product_ID.intValue(), M_AttributeSetInstance_ID, null); if (available == null) available = Env.ZERO; @@ -1296,7 +1296,7 @@ public class CalloutOrder extends CalloutEngine { int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID"); int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, "M_AttributeSetInstance_ID"); - BigDecimal available = MStorageOnHand.getQtyAvailable + BigDecimal available = MStorageReservation.getQtyAvailable (M_Warehouse_ID, 0, M_Product_ID, M_AttributeSetInstance_ID, null); if (available == null) available = Env.ZERO; diff --git a/org.adempiere.base.process/src/org/compiere/process/M_Production_Run.java b/org.adempiere.base.process/src/org/compiere/process/M_Production_Run.java index ea590e3769..01cefa90a5 100644 --- a/org.adempiere.base.process/src/org/compiere/process/M_Production_Run.java +++ b/org.adempiere.base.process/src/org/compiere/process/M_Production_Run.java @@ -25,6 +25,7 @@ import org.compiere.model.MClient; import org.compiere.model.MLocator; import org.compiere.model.MProduct; import org.compiere.model.MStorageOnHand; +import org.compiere.model.MStorageReservation; import org.compiere.model.MTransaction; import org.compiere.model.Query; import org.compiere.model.X_M_Production; @@ -140,7 +141,7 @@ public class M_Production_Run extends SvrProcess { continue ; else if(MovementQty.signum() < 0) { - BigDecimal QtyAvailable = MStorageOnHand.getQtyAvailable( + BigDecimal QtyAvailable = MStorageReservation.getQtyAvailable( locator.getM_Warehouse_ID(), locator.getM_Locator_ID(), pline.getM_Product_ID(), diff --git a/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java b/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java index b174a1ebff..b1fa31e525 100644 --- a/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java +++ b/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java @@ -510,65 +510,6 @@ public class MStorageOnHand extends X_M_StorageOnHand return M_Locator_ID; return firstM_Locator_ID; } // getM_Locator_ID - - /** - * Get Available Qty. - * The call is accurate only if there is a storage record - * and assumes that the product is stocked - * @param M_Warehouse_ID wh - * @param M_Product_ID product - * @param M_AttributeSetInstance_ID masi - * @param trxName transaction - * @return qty available (QtyOnHand-QtyReserved) or null - * @deprecated Since 331b. Please use {@link #getQtyAvailable(int, int, int, int, String)}. - */ - public static BigDecimal getQtyAvailable (int M_Warehouse_ID, - int M_Product_ID, int M_AttributeSetInstance_ID, String trxName) - { - return getQtyAvailable(M_Warehouse_ID, 0, M_Product_ID, M_AttributeSetInstance_ID, trxName); - } - - /** - * Get Warehouse/Locator Available Qty. - * The call is accurate only if there is a storage record - * and assumes that the product is stocked - * @param M_Warehouse_ID wh (if the M_Locator_ID!=0 then M_Warehouse_ID is ignored) - * @param M_Locator_ID locator (if 0, the whole warehouse will be evaluated) - * @param M_Product_ID product - * @param M_AttributeSetInstance_ID masi - * @param trxName transaction - * @return qty available (QtyOnHand-QtyReserved) or null if error - */ - public static BigDecimal getQtyAvailable (int M_Warehouse_ID, int M_Locator_ID, - int M_Product_ID, int M_AttributeSetInstance_ID, String trxName) - { - ArrayList params = new ArrayList(); - StringBuffer sql = new StringBuffer("SELECT COALESCE(SUM(s.QtyOnHand-s.QtyReserved),0)") - .append(" FROM M_StorageOnHand s") - .append(" WHERE s.M_Product_ID=?"); - params.add(M_Product_ID); - // Warehouse level - if (M_Locator_ID == 0) { - sql.append(" AND EXISTS (SELECT 1 FROM M_Locator l WHERE s.M_Locator_ID=l.M_Locator_ID AND l.M_Warehouse_ID=?)"); - params.add(M_Warehouse_ID); - } - // Locator level - else { - sql.append(" AND s.M_Locator_ID=?"); - params.add(M_Locator_ID); - } - // With ASI - if (M_AttributeSetInstance_ID != 0) { - sql.append(" AND s.M_AttributeSetInstance_ID=?"); - params.add(M_AttributeSetInstance_ID); - } - // - BigDecimal retValue = DB.getSQLValueBD(trxName, sql.toString(), params); - if (CLogMgt.isLevelFine()) - s_log.fine("M_Warehouse_ID=" + M_Warehouse_ID + ", M_Locator_ID=" + M_Locator_ID - + ",M_Product_ID=" + M_Product_ID + " = " + retValue); - return retValue; - } // getQtyAvailable /************************************************************************** * Persistency Constructor diff --git a/org.adempiere.base/src/org/compiere/model/MStorageReservation.java b/org.adempiere.base/src/org/compiere/model/MStorageReservation.java index 0c3881b266..0f711d99a0 100644 --- a/org.adempiere.base/src/org/compiere/model/MStorageReservation.java +++ b/org.adempiere.base/src/org/compiere/model/MStorageReservation.java @@ -1,10 +1,22 @@ package org.compiere.model; +import java.math.BigDecimal; import java.sql.ResultSet; +import java.util.ArrayList; import java.util.Properties; +import org.compiere.util.CLogMgt; +import org.compiere.util.CLogger; +import org.compiere.util.DB; + public class MStorageReservation extends X_M_StorageReservation { + /** + * + */ + private static final long serialVersionUID = 8114446879871270122L; + private static CLogger s_log = CLogger.getCLogger(MStorageReservation.class); + public MStorageReservation(Properties ctx, int M_StorageReservation_ID, String trxName) { super(ctx, M_StorageReservation_ID, trxName); @@ -16,5 +28,67 @@ public class MStorageReservation extends X_M_StorageReservation { super(ctx, rs, trxName); // TODO Auto-generated constructor stub } + + /** + * Get Available Qty. + * The call is accurate only if there is a storage record + * and assumes that the product is stocked + * @param M_Warehouse_ID wh + * @param M_Product_ID product + * @param M_AttributeSetInstance_ID masi + * @param trxName transaction + * @return qty available (QtyOnHand-QtyReserved) or null + * @deprecated Since 331b. Please use {@link #getQtyAvailable(int, int, int, int, String)}. + */ + public static BigDecimal getQtyAvailable (int M_Warehouse_ID, + int M_Product_ID, int M_AttributeSetInstance_ID, String trxName) + { + return getQtyAvailable(M_Warehouse_ID, 0, M_Product_ID, M_AttributeSetInstance_ID, trxName); + } + + /** + * Get Warehouse/Locator Available Qty. + * The call is accurate only if there is a storage record + * and assumes that the product is stocked + * @param M_Warehouse_ID wh (if the M_Locator_ID!=0 then M_Warehouse_ID is ignored) + * @param M_Locator_ID locator (if 0, the whole warehouse will be evaluated) + * @param M_Product_ID product + * @param M_AttributeSetInstance_ID masi + * @param trxName transaction + * @return qty available (QtyOnHand-QtyReserved) or null if error + */ + public static BigDecimal getQtyAvailable (int M_Warehouse_ID, int M_Locator_ID, + int M_Product_ID, int M_AttributeSetInstance_ID, String trxName) + { + ArrayList params = new ArrayList(); + StringBuffer sql = new StringBuffer("SELECT COALESCE(SUM(COALESCE(SUM(s.QtyOnHand),0)-COALESCE(SUM(r.Qty),0),0)") + .append(" FROM M_StorageOnHand s") + .append(" JOIN M_StorageReservation r ON s.M_Product_ID=r.M_Product_ID") + .append(" WHERE s.M_Product_ID=?") + .append(" AND EXISTS (SELECT 1 FROM M_Locator l WHERE s.M_Locator_ID=l.M_Locator_ID AND l.M_Warehouse_ID=r.M_Warehouse_ID"); + + params.add(M_Product_ID, M_Product_ID); + // Warehouse level + if (M_Locator_ID == 0) { + sql.append(" AND l.M_Warehouse_ID=?)"); + params.add(M_Warehouse_ID); + } + // Locator level + else { + sql.append(" AND s.M_Locator_ID=?)"); + params.add(M_Locator_ID); + } + // With ASI + if (M_AttributeSetInstance_ID != 0) { + sql.append(" AND s.M_AttributeSetInstance_ID=? AND r.M_AttributeSetInstance_ID=?"); + params.add(M_AttributeSetInstance_ID, M_AttributeSetInstance_ID); + } + // + BigDecimal retValue = DB.getSQLValueBD(trxName, sql.toString(), params); + if (CLogMgt.isLevelFine()) + s_log.fine("M_Warehouse_ID=" + M_Warehouse_ID + ", M_Locator_ID=" + M_Locator_ID + + ",M_Product_ID=" + M_Product_ID + " = " + retValue); + return retValue; + } // getQtyAvailable } diff --git a/org.adempiere.extend/src/test/functional/MStorageTest.java b/org.adempiere.extend/src/test/functional/MStorageTest.java index 3ab9090883..3af6afef7c 100644 --- a/org.adempiere.extend/src/test/functional/MStorageTest.java +++ b/org.adempiere.extend/src/test/functional/MStorageTest.java @@ -17,6 +17,7 @@ import java.math.BigDecimal; import org.compiere.model.MLocator; import org.compiere.model.MStorageOnHand; +import org.compiere.model.MStorageReservation; import org.compiere.model.MWarehouse; import org.compiere.util.Env; @@ -48,14 +49,14 @@ public class MStorageTest extends AdempiereTestCase s1.setQtyOnHand(targetQty); s1.saveEx(); // - BigDecimal qty = MStorageOnHand.getQtyAvailable(wh.get_ID(), loc.get_ID(), product_id, 0, getTrxName()).setScale(12, BigDecimal.ROUND_HALF_UP); + BigDecimal qty = MStorageReservation.getQtyAvailable(wh.get_ID(), loc.get_ID(), product_id, 0, getTrxName()).setScale(12, BigDecimal.ROUND_HALF_UP); assertEquals("Error on locator "+locatorValue, targetQty, qty); // return loc; } private void assertWarehouseQty(MWarehouse wh, BigDecimal targetQty) { - BigDecimal qty = MStorageOnHand.getQtyAvailable(wh.get_ID(), 0, product_id, 0, getTrxName()); + BigDecimal qty = MStorageReservation.getQtyAvailable(wh.get_ID(), 0, product_id, 0, getTrxName()); qty = qty.setScale(12, BigDecimal.ROUND_HALF_UP); targetQty = targetQty.setScale(12, BigDecimal.ROUND_HALF_UP); assertEquals(targetQty, qty); diff --git a/org.adempiere.ui.swing/src/org/compiere/apps/form/VAttributeGrid.java b/org.adempiere.ui.swing/src/org/compiere/apps/form/VAttributeGrid.java index 7c0b975914..01ff562713 100644 --- a/org.adempiere.ui.swing/src/org/compiere/apps/form/VAttributeGrid.java +++ b/org.adempiere.ui.swing/src/org/compiere/apps/form/VAttributeGrid.java @@ -51,6 +51,7 @@ import org.compiere.model.MProduct; import org.compiere.model.MProductPrice; import org.compiere.model.MRole; import org.compiere.model.MStorageOnHand; +import org.compiere.model.MStorageReservation; import org.compiere.swing.CComboBox; import org.compiere.swing.CLabel; import org.compiere.swing.CPanel; @@ -518,7 +519,7 @@ public class VAttributeGrid extends CPanel formatted = ""; if (m_M_Warehouse_ID != 0) { - BigDecimal qty = MStorageOnHand.getQtyAvailable(m_M_Warehouse_ID, M_Product_ID, 0, null); + BigDecimal qty = MStorageReservation.getQtyAvailable(m_M_Warehouse_ID, 0, M_Product_ID, 0, null); if (qty == null) formatted = "-"; else diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WAttributeGrid.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WAttributeGrid.java index 0403a13f66..fa64d58b14 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WAttributeGrid.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WAttributeGrid.java @@ -44,6 +44,7 @@ import org.compiere.model.MProduct; import org.compiere.model.MProductPrice; import org.compiere.model.MRole; import org.compiere.model.MStorageOnHand; +import org.compiere.model.MStorageReservation; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.DisplayType; @@ -607,7 +608,7 @@ public class WAttributeGrid extends ADForm implements EventListener formatted = ""; if (m_M_Warehouse_ID != 0) { - BigDecimal qty = MStorageOnHand.getQtyAvailable(m_M_Warehouse_ID, M_Product_ID, 0, null); + BigDecimal qty = MStorageReservation.getQtyAvailable(m_M_Warehouse_ID, M_Product_ID, 0, null); if (qty == null) formatted = "-"; else