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 2b1a844e6f..b05a50e7d8 100644 --- a/org.adempiere.base.callout/src/org/compiere/model/CalloutMovement.java +++ b/org.adempiere.base.callout/src/org/compiere/model/CalloutMovement.java @@ -118,15 +118,14 @@ public class CalloutMovement extends CalloutEngine if (MovementQty == null) MovementQty = (BigDecimal) mTab.getValue("MovementQty"); int M_Locator_ID = Env.getContextAsInt(ctx, WindowNo, "M_Locator_ID"); - // If no locator, don't check anything and assume is ok if (M_Locator_ID <= 0) return; - //@win - IDEMPIERE-385 - int M_Warehouse_ID = DB.getSQLValue(null, "SELECT M_Warehouse_ID FROM M_Locator WHERE M_Locator_ID=?", M_Locator_ID); - // int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, "M_AttributeSetInstance_ID"); - BigDecimal available = MStorageReservation.getQtyAvailable(M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, null); + BigDecimal available = Env.ZERO; + MStorageOnHand oh = MStorageOnHand.get(ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, null); + if (oh != null) + available = oh.getQtyOnHand(); if (available == null) available = Env.ZERO; if (available.signum() == 0) diff --git a/org.adempiere.base.process/src/org/compiere/process/OrgOwnership.java b/org.adempiere.base.process/src/org/compiere/process/OrgOwnership.java index ec7cf3c77c..6213572be1 100644 --- a/org.adempiere.base.process/src/org/compiere/process/OrgOwnership.java +++ b/org.adempiere.base.process/src/org/compiere/process/OrgOwnership.java @@ -150,6 +150,16 @@ public class OrgOwnership extends SvrProcess no = DB.executeUpdate(sql.toString(), get_TrxName()); addLog (0,null, new BigDecimal(no), Msg.translate(getCtx(), "Storage")); + // Set Storage Reservation + sql = new StringBuilder(); + sql.append("UPDATE M_StorageReservation s ") + .append("SET AD_Org_ID=").append(p_AD_Org_ID) + .append(" WHERE M_Warehouse_ID=").append(p_M_Warehouse_ID) + .append(" AND AD_Client_ID=").append(getAD_Client_ID()) + .append(" AND AD_Org_ID<>").append(p_AD_Org_ID); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + addLog (0,null, new BigDecimal(no), Msg.translate(getCtx(), "StorageReservation")); + return ""; } // warehouseOwnership diff --git a/org.adempiere.base.process/src/org/compiere/process/ReplenishReport.java b/org.adempiere.base.process/src/org/compiere/process/ReplenishReport.java index 56b124b3a6..b3f1e7510b 100644 --- a/org.adempiere.base.process/src/org/compiere/process/ReplenishReport.java +++ b/org.adempiere.base.process/src/org/compiere/process/ReplenishReport.java @@ -251,10 +251,10 @@ public class ReplenishReport extends SvrProcess sql = new StringBuilder("UPDATE T_Replenish t SET "); sql.append("QtyOnHand = (SELECT COALESCE(SUM(QtyOnHand),0) FROM M_StorageOnHand s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID"); sql.append(" AND l.M_Locator_ID=s.M_Locator_ID AND l.M_Warehouse_ID=t.M_Warehouse_ID),"); - sql.append("QtyReserved = (SELECT COALESCE(SUM(QtyReserved),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID"); - sql.append(" AND l.M_Warehouse_ID=t.M_Warehouse_ID),"); - sql.append("QtyOrdered = (SELECT COALESCE(SUM(QtyOrdered),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID"); - sql.append(" AND l.M_Warehouse_ID=t.M_Warehouse_ID)"); + sql.append("QtyReserved = (SELECT COALESCE(SUM(Qty),0) FROM M_StorageReservation s WHERE t.M_Product_ID=s.M_Product_ID"); + sql.append(" AND t.M_Warehouse_ID=s.M_Warehouse_ID),"); + sql.append("QtyOrdered = (SELECT COALESCE(SUM(Qty),0) FROM M_StorageReservation s WHERE t.M_Product_ID=s.M_Product_ID"); + sql.append(" AND t.M_Warehouse_ID=s.M_Warehouse_ID)"); if (p_C_DocType_ID != 0) sql.append(", C_DocType_ID=").append(p_C_DocType_ID); sql.append(" WHERE AD_PInstance_ID=").append(getAD_PInstance_ID()); @@ -534,10 +534,9 @@ public class ReplenishReport extends SvrProcess // From: Look-up Storage MProduct product = MProduct.get(getCtx(), replenish.getM_Product_ID()); String MMPolicy = product.getMMPolicy(); - MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), - whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, 0, - true, null, - MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName()); + MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), + whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, null, + MClient.MMPOLICY_FiFo.equals(MMPolicy), false, 0, get_TrxName()); // BigDecimal target = replenish.getQtyToOrder(); for (int j = 0; j < storages.length; j++) diff --git a/org.adempiere.base.process/src/org/compiere/process/ReplenishReportProduction.java b/org.adempiere.base.process/src/org/compiere/process/ReplenishReportProduction.java index 0db921456e..50795a7efb 100644 --- a/org.adempiere.base.process/src/org/compiere/process/ReplenishReportProduction.java +++ b/org.adempiere.base.process/src/org/compiere/process/ReplenishReportProduction.java @@ -269,12 +269,12 @@ public class ReplenishReportProduction extends SvrProcess } sql = new StringBuilder("UPDATE T_Replenish t SET "); - sql.append("QtyOnHand = (SELECT COALESCE(SUM(QtyOnHand),0) FROM M_Storage s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID"); + sql.append("QtyOnHand = (SELECT COALESCE(SUM(QtyOnHand),0) FROM M_StorageOnHand s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID"); sql.append(" AND l.M_Locator_ID=s.M_Locator_ID AND l.M_Warehouse_ID=t.M_Warehouse_ID),"); - sql.append("QtyReserved = (SELECT COALESCE(SUM(QtyReserved),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID"); - sql.append(" AND l.M_Warehouse_ID=t.M_Warehouse_ID),"); - sql.append("QtyOrdered = (SELECT COALESCE(SUM(QtyOrdered),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID"); - sql.append(" AND l.M_Warehouse_ID=t.M_Warehouse_ID)"); + sql.append("QtyReserved = (SELECT COALESCE(SUM(Qty),0) FROM M_StorageReservation s WHERE t.M_Product_ID=s.M_Product_ID"); + sql.append(" AND t.M_Warehouse_ID=s.M_Warehouse_ID),"); + sql.append("QtyOrdered = (SELECT COALESCE(SUM(Qty),0) FROM M_StorageReservation s WHERE t.M_Product_ID=s.M_Product_ID"); + sql.append(" AND t.M_Warehouse_ID=s.M_Warehouse_ID)"); if (p_C_DocType_ID != 0) sql.append(", C_DocType_ID=").append(p_C_DocType_ID); sql.append(" WHERE AD_PInstance_ID=").append(getAD_PInstance_ID()); @@ -570,10 +570,9 @@ public class ReplenishReportProduction extends SvrProcess // From: Look-up Storage MProduct product = MProduct.get(getCtx(), replenish.getM_Product_ID()); String MMPolicy = product.getMMPolicy(); - MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), - whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, 0, - true, null, - MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName()); + MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), + whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, null, + MClient.MMPOLICY_FiFo.equals(MMPolicy), false, 0, get_TrxName()); // BigDecimal target = replenish.getQtyToOrder(); for (int j = 0; j < storages.length; j++) diff --git a/org.adempiere.base.process/src/org/compiere/process/StorageCleanup.java b/org.adempiere.base.process/src/org/compiere/process/StorageCleanup.java index 863330efee..373f486556 100644 --- a/org.adempiere.base.process/src/org/compiere/process/StorageCleanup.java +++ b/org.adempiere.base.process/src/org/compiere/process/StorageCleanup.java @@ -69,11 +69,18 @@ public class StorageCleanup extends SvrProcess log.info(""); // Clean up empty Storage String sql = "DELETE FROM M_StorageOnHand " - + "WHERE QtyOnHand = 0 AND QtyReserved = 0 AND QtyOrdered = 0" + + "WHERE QtyOnHand = 0" + " AND Created < SysDate-3"; int no = DB.executeUpdate(sql, get_TrxName()); log.info("Delete Empty #" + no); - + + // Clean up empty Reservation Storage + sql = "DELETE FROM M_StorageReservation " + + "WHERE Qty = 0" + + " AND Created < SysDate-3"; + no = DB.executeUpdate(sql, get_TrxName()); + log.info("Delete Empty #" + no); + // sql = "SELECT * " + "FROM M_StorageOnHand s " diff --git a/org.adempiere.base/src/org/compiere/model/MInOut.java b/org.adempiere.base/src/org/compiere/model/MInOut.java index 3e10ce861b..5e0c2e3723 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOut.java +++ b/org.adempiere.base/src/org/compiere/model/MInOut.java @@ -1361,21 +1361,59 @@ public class MInOut extends X_M_InOut implements DocAction get_TrxName())) { String lastError = CLogger.retrieveErrorString(""); - m_processMsg = "Cannot correct Inventory (MA) - " + lastError; + m_processMsg = "Cannot correct Inventory OnHand (MA) - " + lastError; return DocAction.STATUS_Invalid; } + if (sameWarehouse && reservedDiff.signum() != 0) { + if (!MStorageReservation.add(getCtx(), getM_Warehouse_ID(), + sLine.getM_Product_ID(), + ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, + reservedDiff, + true, + get_TrxName())) + { + String lastError = CLogger.retrieveErrorString(""); + m_processMsg = "Cannot correct Inventory Reserved (MA) - " + lastError; + return DocAction.STATUS_Invalid; + } + } + if (sameWarehouse && orderedDiff.signum() != 0) { + if (!MStorageReservation.add(getCtx(), getM_Warehouse_ID(), + sLine.getM_Product_ID(), + ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, + orderedDiff, + false, + get_TrxName())) + { + String lastError = CLogger.retrieveErrorString(""); + m_processMsg = "Cannot correct Inventory Ordered (MA) - " + lastError; + return DocAction.STATUS_Invalid; + } + } if (!sameWarehouse) { //correct qtyOrdered in warehouse of order MWarehouse wh = MWarehouse.get(getCtx(), oLine.getM_Warehouse_ID()); - if (!MStorageOnHand.add(getCtx(), oLine.getM_Warehouse_ID(), - wh.getDefaultLocator().getM_Locator_ID(), - sLine.getM_Product_ID(), - ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, - Env.ZERO, get_TrxName())) + if (reservedDiff.signum() != 0) { + if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(), + sLine.getM_Product_ID(), + ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, + reservedDiff, true, get_TrxName())) { - m_processMsg = "Cannot correct Inventory (MA) in order warehouse"; + m_processMsg = "Cannot correct Inventory Reserved (MA) in order warehouse"; return DocAction.STATUS_Invalid; } + } + if (orderedDiff.signum() != 0) { + if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(), + sLine.getM_Product_ID(), + ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, + orderedDiff, false, get_TrxName())) + { + m_processMsg = "Cannot correct Inventory Ordered (MA) in order warehouse"; + return DocAction.STATUS_Invalid; + } + + } } // Create Transaction mtrx = new MTransaction (getCtx(), sLine.getAD_Org_ID(), @@ -1403,21 +1441,52 @@ public class MInOut extends X_M_InOut implements DocAction sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, Qty, get_TrxName())) { - m_processMsg = "Cannot correct Inventory"; + m_processMsg = "Cannot correct Inventory OnHand"; return DocAction.STATUS_Invalid; } + if (reservedDiff.signum() != 0) { + if (!MStorageReservation.add(getCtx(), getM_Warehouse_ID(), + sLine.getM_Product_ID(), + sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, + reservedDiff, true, get_TrxName())) + { + m_processMsg = "Cannot correct Inventory Reserved"; + return DocAction.STATUS_Invalid; + } + } + if (orderedDiff.signum() != 0) { + if (!MStorageReservation.add(getCtx(), getM_Warehouse_ID(), + sLine.getM_Product_ID(), + sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, + orderedDiff, false, get_TrxName())) + { + m_processMsg = "Cannot correct Inventory Ordered"; + return DocAction.STATUS_Invalid; + } + } if (!sameWarehouse) { //correct qtyOrdered in warehouse of order MWarehouse wh = MWarehouse.get(getCtx(), oLine.getM_Warehouse_ID()); - if (!MStorageOnHand.add(getCtx(), oLine.getM_Warehouse_ID(), - wh.getDefaultLocator().getM_Locator_ID(), - sLine.getM_Product_ID(), - sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, - Env.ZERO, get_TrxName())) + if (QtySO.signum() != 0) { + if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(), + sLine.getM_Product_ID(), + sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, + QtySO.negate(), true, get_TrxName())) { - m_processMsg = "Cannot correct Inventory"; + m_processMsg = "Cannot correct Inventory Reserved"; return DocAction.STATUS_Invalid; } + } + if (QtyPO.signum() != 0) { + if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(), + sLine.getM_Product_ID(), + sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, + QtyPO.negate(), false, get_TrxName())) + { + m_processMsg = "Cannot correct Inventory Ordered"; + return DocAction.STATUS_Invalid; + } + } } // FallBack: Create Transaction mtrx = new MTransaction (getCtx(), sLine.getAD_Org_ID(), diff --git a/org.adempiere.base/src/org/compiere/model/MLocatorLookup.java b/org.adempiere.base/src/org/compiere/model/MLocatorLookup.java index 9d84e98b04..608c046b78 100644 --- a/org.adempiere.base/src/org/compiere/model/MLocatorLookup.java +++ b/org.adempiere.base/src/org/compiere/model/MLocatorLookup.java @@ -332,7 +332,7 @@ public final class MLocatorLookup extends Lookup implements Serializable sql.append(" AND (IsDefault='Y' ") // Default Locator .append("OR EXISTS (SELECT * FROM M_Product p ") // Product Locator .append("WHERE p.M_Locator_ID=M_Locator.M_Locator_ID AND p.M_Product_ID=?)") - .append("OR EXISTS (SELECT * FROM M_StorageOnHand s ") // Storage Locator + .append("OR EXISTS (SELECT * FROM M_Storage s ") // Storage Locator .append("WHERE s.M_Locator_ID=M_Locator.M_Locator_ID AND s.M_Product_ID=?))"); sql.append(" ORDER BY "); if (local_only_warehouse_id == 0) diff --git a/org.adempiere.base/src/org/compiere/model/MOrder.java b/org.adempiere.base/src/org/compiere/model/MOrder.java index 18ec2981a6..8a801b4ed2 100644 --- a/org.adempiere.base/src/org/compiere/model/MOrder.java +++ b/org.adempiere.base/src/org/compiere/model/MOrder.java @@ -1566,38 +1566,13 @@ public class MOrder extends X_C_Order implements DocAction { if (product.isStocked()) { - BigDecimal ordered = isSOTrx ? Env.ZERO : difference; - BigDecimal reserved = isSOTrx ? difference : Env.ZERO; - int M_Locator_ID = 0; - // Get Locator to reserve - if (line.getM_AttributeSetInstance_ID() != 0) // Get existing Location - M_Locator_ID = MStorageOnHand.getM_Locator_ID (line.getM_Warehouse_ID(), - line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), - ordered, get_TrxName()); - // Get default Location - if (M_Locator_ID == 0) - { - // try to take default locator for product first - // if it is from the selected warehouse - MWarehouse wh = MWarehouse.get(getCtx(), line.getM_Warehouse_ID()); - M_Locator_ID = product.getM_Locator_ID(); - if (M_Locator_ID!=0) { - MLocator locator = new MLocator(getCtx(), product.getM_Locator_ID(), get_TrxName()); - //product has default locator defined but is not from the order warehouse - if(locator.getM_Warehouse_ID()!=wh.get_ID()) { - M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID(); - } - } else { - M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID(); - } - } - // Update Storage - if (!MStorageOnHand.add(getCtx(), line.getM_Warehouse_ID(), M_Locator_ID, + // Update Reservation Storage + if (!MStorageReservation.add(getCtx(), line.getM_Warehouse_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), line.getM_AttributeSetInstance_ID(), - Env.ZERO, get_TrxName())) + difference, isSOTrx, get_TrxName())) return false; - } // stockec + } // stocked // update line line.setQtyReserved(line.getQtyReserved().add(difference)); if (!line.save(get_TrxName())) diff --git a/org.adempiere.base/src/org/compiere/model/MOrderLine.java b/org.adempiere.base/src/org/compiere/model/MOrderLine.java index ef7dec5b31..ed492b9eba 100644 --- a/org.adempiere.base/src/org/compiere/model/MOrderLine.java +++ b/org.adempiere.base/src/org/compiere/model/MOrderLine.java @@ -19,6 +19,7 @@ package org.compiere.model; import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.Timestamp; import java.util.Properties; import java.util.logging.Level; @@ -875,7 +876,7 @@ public class MOrderLine extends X_C_OrderLine { MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(), - M_AttributeSet_ID, false, null, true, get_TrxName()); + null, true, false, 0, get_TrxName()); BigDecimal qty = Env.ZERO; for (int i = 0; i < storages.length; i++) { diff --git a/org.adempiere.base/src/org/compiere/model/MProduct.java b/org.adempiere.base/src/org/compiere/model/MProduct.java index e8928ef744..c6f3a768a0 100644 --- a/org.adempiere.base/src/org/compiere/model/MProduct.java +++ b/org.adempiere.base/src/org/compiere/model/MProduct.java @@ -26,6 +26,7 @@ import org.compiere.util.CCache; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Msg; +import org.compiere.util.Util; /** * Product Model @@ -571,33 +572,8 @@ public class MProduct extends X_M_Product || (is_ValueChanged("ProductType") // from Item && PRODUCTTYPE_Item.equals(get_ValueOld("ProductType"))))) { - // large modified related to storages by zuhri - MStorageOnHand[] onHandStorages = MStorageOnHand.getOfProduct(getCtx(), get_ID(), get_TrxName()); - MStorageReservation[] reservationStorages = MStorageReservation.getOfProduct(getCtx(), get_ID(), get_TrxName()); - BigDecimal OnHand = Env.ZERO; - BigDecimal Ordered = Env.ZERO; - BigDecimal Reserved = Env.ZERO; - for (int i = 0; i < onHandStorages.length; i++) - { - OnHand = OnHand.add(onHandStorages[i].getQtyOnHand()); - - } - for (int i = 0; i < reservationStorages.length; i++) - { - if(reservationStorages[i].isSOTrx()) - Reserved = Reserved.add(reservationStorages[i].getQty()); - else - Ordered = Ordered.add(reservationStorages[i].getQty()); - } - // end large modified related to storages by zuhri - String errMsg = ""; - if (OnHand.signum() != 0) - errMsg = "@QtyOnHand@ = " + OnHand; - if (Ordered.signum() != 0) - errMsg += " - @QtyOrdered@ = " + Ordered; - if (Reserved.signum() != 0) - errMsg += " - @QtyReserved@" + Reserved; - if (errMsg.length() > 0) + String errMsg = verifyStorage(); + if (! Util.isEmpty(errMsg)) { log.saveError("Error", Msg.parseTranslation(getCtx(), errMsg)); return false; @@ -638,6 +614,32 @@ public class MProduct extends X_M_Product return true; } // beforeSave + private String verifyStorage() { + BigDecimal qtyOnHand = Env.ZERO; + BigDecimal qtyOrdered = Env.ZERO; + BigDecimal qtyReserved = Env.ZERO; + for (MStorageOnHand ohs: MStorageOnHand.getOfProduct(getCtx(), get_ID(), get_TrxName())) + { + qtyOnHand = qtyOnHand.add(ohs.getQtyOnHand()); + } + for (MStorageReservation rs : MStorageReservation.getOfProduct(getCtx(), get_ID(), get_TrxName())) + { + if (rs.isSOTrx()) + qtyReserved = qtyReserved.add(rs.getQty()); + else + qtyOrdered = qtyOrdered.add(rs.getQty()); + } + + StringBuilder errMsg = new StringBuilder(); + if (qtyOnHand.signum() != 0) + errMsg.append("@QtyOnHand@ = ").append(qtyOnHand); + if (qtyOrdered.signum() != 0) + errMsg.append(" - @QtyOrdered@ = ").append(qtyOrdered); + if (qtyReserved.signum() != 0) + errMsg.append(" - @QtyReserved@").append(qtyReserved); + return errMsg.toString(); + } + /** * HasInventoryOrCost * @return true if it has Inventory or Cost @@ -719,31 +721,8 @@ public class MProduct extends X_M_Product // Check Storage if (isStocked() || PRODUCTTYPE_Item.equals(getProductType())) { - MStorageOnHand[] storages = MStorageOnHand.getOfProduct(getCtx(), get_ID(), get_TrxName()); - MStorageReservation[] reserves = MStorageReservation.getOfProduct(getCtx(), get_ID(), get_TrxName()); - - BigDecimal OnHand = Env.ZERO; - BigDecimal Ordered = Env.ZERO; - BigDecimal Reserved = Env.ZERO; - for (int i = 0; i < storages.length; i++) - { - OnHand = OnHand.add(storages[i].getQtyOnHand()); - } - - for (int i = 0; i < reserves.length; i++) - { - Ordered = OnHand.add(reserves[i].getQtyOrdered()); - Reserved = OnHand.add(reserves[i].getQtyReserved()); - } - - String errMsg = ""; - if (OnHand.signum() != 0) - errMsg = "@QtyOnHand@ = " + OnHand; - if (Ordered.signum() != 0) - errMsg += " - @QtyOrdered@ = " + Ordered; - if (Reserved.signum() != 0) - errMsg += " - @QtyReserved@" + Reserved; - if (errMsg.length() > 0) + String errMsg = verifyStorage(); + if (! Util.isEmpty(errMsg)) { log.saveError("Error", Msg.parseTranslation(getCtx(), errMsg)); return false; diff --git a/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java b/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java index 308ef3c493..4c85594f02 100644 --- a/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java +++ b/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java @@ -22,11 +22,10 @@ import java.sql.ResultSet; 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 java.util.List; -import org.compiere.util.CLogMgt; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; @@ -36,14 +35,14 @@ import org.compiere.util.Msg; * Inventory Storage Model * * @author Jorg Janke - * @version $Id: MStorage.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $ + * @version $Id: MStorageOnHand.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $ */ public class MStorageOnHand extends X_M_StorageOnHand { /** * */ - private static final long serialVersionUID = 3911132565445025309L; + private static final long serialVersionUID = 3649163126231150631L; /** * Get Storage Info @@ -132,12 +131,10 @@ public class MStorageOnHand extends X_M_StorageOnHand public static MStorageOnHand[] getAll (Properties ctx, int M_Product_ID, int M_Locator_ID, String trxName) { - String sqlWhere = "M_Product_ID=? AND M_Locator_ID=?" - + " AND QtyOnHand <> 0 " - + "ORDER BY M_AttributeSetInstance_ID"; - + String sqlWhere = "M_Product_ID=? AND M_Locator_ID=? AND QtyOnHand <> 0"; List list = new Query(ctx, MStorageOnHand.Table_Name, sqlWhere, trxName) .setParameters(M_Product_ID, M_Locator_ID) + .setOrderBy(MStorageOnHand.COLUMNNAME_M_AttributeSetInstance_ID) .list(); MStorageOnHand[] retValue = new MStorageOnHand[list.size()]; @@ -173,8 +170,8 @@ public class MStorageOnHand extends X_M_StorageOnHand * @param M_Warehouse_ID * @param M_Product_ID product * @param M_AttributeSetInstance_ID instance - * @param M_AttributeSet_ID attribute set - * @param allAttributeInstances if true, all attribute set instances + * @param M_AttributeSet_ID attribute set (NOT USED) + * @param allAttributeInstances if true, all attribute set instances (NOT USED) * @param minGuaranteeDate optional minimum guarantee date if all attribute instances * @param FiFo first in-first-out * @param trxName transaction @@ -219,11 +216,7 @@ public class MStorageOnHand extends X_M_StorageOnHand // Specific Attribute Set Instance 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," - //@win change - //+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory " + "s.QtyOnHand,s.DateLastInventory " - //end @win change - + "FROM M_StorageOnHand s" + " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID) "; if (M_Locator_ID > 0) @@ -248,11 +241,7 @@ public class MStorageOnHand extends X_M_StorageOnHand { 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," - //@win change - //+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory " - + "s.QtyOnHand,s.DateLastInventory " - //end @win change - + + "s.QtyOnHand,s.DateLastInventory,s.M_StorageOnHand_UU " + "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) "; @@ -349,7 +338,7 @@ public class MStorageOnHand extends X_M_StorageOnHand throw new IllegalArgumentException("Not found M_Locator_ID=" + M_Locator_ID); // retValue = new MStorageOnHand (locator, M_Product_ID, M_AttributeSetInstance_ID); - retValue.save(trxName); + retValue.saveEx(trxName); s_log.fine("New " + retValue); return retValue; } // getCreate @@ -442,7 +431,7 @@ public class MStorageOnHand extends X_M_StorageOnHand diffText.append(") -> ").append(storage.toString()); s_log.fine(diffText.toString()); if (storage0 != null) - storage0.save(trxName); // No AttributeSetInstance (reserved/ordered) + storage0.saveEx(trxName); // No AttributeSetInstance (reserved/ordered) return storage.save (trxName); } @@ -525,7 +514,7 @@ public class MStorageOnHand extends X_M_StorageOnHand // setQtyOnHand (Env.ZERO); - } // MStorage + } // MStorageOnHand /** * Load Constructor @@ -536,7 +525,7 @@ public class MStorageOnHand extends X_M_StorageOnHand public MStorageOnHand (Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); - } // MStorage + } // MStorageOnHand /** * Full NEW Constructor @@ -551,7 +540,7 @@ public class MStorageOnHand extends X_M_StorageOnHand setM_Locator_ID (locator.getM_Locator_ID()); setM_Product_ID (M_Product_ID); setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID); - } // MStorage + } // MStorageOnHand /** Log */ private static CLogger s_log = CLogger.getCLogger (MStorageOnHand.class); @@ -639,26 +628,26 @@ public class MStorageOnHand extends X_M_StorageOnHand * @param trxName * @return */ - public static BigDecimal getQtyOnHand(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName){ - ArrayList params = new ArrayList(); + public static BigDecimal getQtyOnHand(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName) { StringBuffer sql = new StringBuffer(); - sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh") + 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 EXISTS(SELECT 1 FROM M_Locator loc WHERE oh.M_Locator_ID=loc.M_Locator_ID AND loc.M_Warehouse_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 M_AttributeSetInstance_ID=?"); + sql.append(" AND oh.M_AttributeSetInstance_ID=?"); params.add(M_AttributeSetInstance_ID); } - + BigDecimal qty = DB.getSQLValueBD(trxName, sql.toString(), params); - if(qty==null) + if (qty == null) qty = Env.ZERO; - + return qty; } @@ -668,7 +657,7 @@ public class MStorageOnHand extends X_M_StorageOnHand */ public String toString() { - StringBuffer sb = new StringBuffer("MStorage[") + StringBuffer sb = new StringBuffer("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()) @@ -681,4 +670,4 @@ public class MStorageOnHand extends X_M_StorageOnHand return sb.toString(); } // toString -} // MStorage +} // MStorageOnHand diff --git a/org.adempiere.base/src/org/compiere/model/MStorageReservation.java b/org.adempiere.base/src/org/compiere/model/MStorageReservation.java index 6b9c736055..ed5707dfce 100644 --- a/org.adempiere.base/src/org/compiere/model/MStorageReservation.java +++ b/org.adempiere.base/src/org/compiere/model/MStorageReservation.java @@ -1,36 +1,118 @@ +/****************************************************************************** + * Product: iDempiere ERP & CRM Smart Business Solution * + * Copyright (C) 1999-2012 iDempiere 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. * + *****************************************************************************/ package org.compiere.model; import java.math.BigDecimal; +import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Properties; +import java.util.logging.Level; -import org.compiere.util.CLogMgt; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; public class MStorageReservation extends X_M_StorageReservation { - /** * */ - private static final long serialVersionUID = 8114446879871270122L; + private static final long serialVersionUID = -8646802850122507899L; + + /** + * Get Storage Info + * @param ctx context + * @param M_Warehouse_ID warehouse + * @param M_Product_ID product + * @param M_AttributeSetInstance_ID instance + * @param isSOTrx + * @param trxName transaction + * @return existing or null + */ + public static MStorageReservation get (Properties ctx, int M_Warehouse_ID, + int M_Product_ID, int M_AttributeSetInstance_ID, boolean isSOTrx, String trxName) + { + MStorageReservation retValue = null; + String sql = "SELECT * FROM M_StorageReservation " + + "WHERE M_Warehouse_ID=? AND M_Product_ID=? AND IsSOTrx=? AND "; + if (M_AttributeSetInstance_ID == 0) + sql += "(M_AttributeSetInstance_ID=? OR M_AttributeSetInstance_ID IS NULL)"; + else + sql += "M_AttributeSetInstance_ID=?"; + PreparedStatement pstmt = null; + ResultSet rs = null; + try + { + pstmt = DB.prepareStatement (sql, trxName); + pstmt.setInt (1, M_Warehouse_ID); + pstmt.setInt (2, M_Product_ID); + pstmt.setString (3, isSOTrx ? "Y" : "N"); + pstmt.setInt (4, M_AttributeSetInstance_ID); + rs = pstmt.executeQuery (); + if (rs.next ()) + retValue = new MStorageReservation (ctx, rs, trxName); + } + catch (SQLException ex) + { + s_log.log(Level.SEVERE, sql, ex); + } + finally + { + DB.close(rs, pstmt); + rs = null; pstmt = null; + } + if (retValue == null) + s_log.fine("Not Found - M_Warehouse_ID=" + M_Warehouse_ID + + ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID + ", IsSOTrx=" + isSOTrx); + else + s_log.fine("M_Warehouse_ID=" + M_Warehouse_ID + + ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID + ", IsSOTrx=" + isSOTrx); + return retValue; + } // get + 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); - // TODO Auto-generated constructor stub } public MStorageReservation(Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); - // TODO Auto-generated constructor stub } + /** + * Full NEW Constructor + * @param warehouse (parent) warehouse + * @param M_Product_ID product + * @param M_AttributeSetInstance_ID attribute + * @param isSOTrx + */ + private MStorageReservation (MWarehouse warehouse, int M_Product_ID, int M_AttributeSetInstance_ID, boolean isSOTrx) + { + this (warehouse.getCtx(), 0, warehouse.get_TrxName()); + setClientOrg(warehouse); + setM_Warehouse_ID(warehouse.getM_Warehouse_ID()); + setM_Product_ID (M_Product_ID); + setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID); + setIsSOTrx(isSOTrx); + setQty(Env.ZERO); + } // MStorageReservation + /** * Get Storage Info for Product on specified Warehouse * @param ctx @@ -73,47 +155,40 @@ public class MStorageReservation extends X_M_StorageReservation { return retValue; } // getOfProduct - - - + /** * Get Quantity Reserved of Warehouse * @param M_Product_ID * @param M_Warehouse_ID * @param M_AttributeSetInstance_ID + * @param isSOTrx - true to get reserved, false to get ordered * @param trxName * @return */ - public static BigDecimal getQtyReserved(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName){ + private static BigDecimal getQty(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, boolean isSOTrx, String trxName) { ArrayList params = new ArrayList(); StringBuffer sql = new StringBuffer(); - sql.append(" SELECT SUM(Qty) FROM M_StorageReservation oh") - .append(" WHERE oh.M_Product_ID=? AND oh.M_Warehouse_ID=?") - .append(" AND oh.IsSOTrx='Y'"); - + sql.append(" SELECT SUM(Qty) FROM M_StorageReservation sr") + .append(" WHERE sr.M_Product_ID=? AND sr.M_Warehouse_ID=?") + .append(" AND sr.IsSOTrx=?"); + params.add(M_Product_ID); params.add(M_Warehouse_ID); - + params.add(isSOTrx ? "Y" : "N"); + // With ASI if (M_AttributeSetInstance_ID != 0) { sql.append(" AND M_AttributeSetInstance_ID=?"); params.add(M_AttributeSetInstance_ID); } - + BigDecimal qty = DB.getSQLValueBD(trxName, sql.toString(), params); - if(qty==null) + if (qty==null) qty = Env.ZERO; - + return qty; } - - - public static BigDecimal getQtyOrdered (int M_Warehouse_ID, - int M_Product_ID, int M_AttributeSetInstance_ID, String trxName) - { - BigDecimal retValue = null; - return retValue; - } + /** * Get Available Qty. * The call is accurate only if there is a storage record @@ -128,19 +203,116 @@ public class MStorageReservation extends X_M_StorageReservation { int M_Product_ID, int M_AttributeSetInstance_ID, String trxName) { BigDecimal qtyOnHand = MStorageOnHand.getQtyOnHand(M_Product_ID, M_Warehouse_ID, M_AttributeSetInstance_ID, trxName); - BigDecimal qtyReserved = getQtyReserved(M_Product_ID, M_Warehouse_ID, M_AttributeSetInstance_ID, trxName); + BigDecimal qtyReserved = MStorageReservation.getQty(M_Product_ID, M_Warehouse_ID, M_AttributeSetInstance_ID, true, trxName); BigDecimal retValue = qtyOnHand.subtract(qtyReserved); return retValue; } - public BigDecimal getQtyOrdered() { - // TODO Auto-generated method stub - return null; - } + /** + * Update Storage Info add. + * Called from MProjectIssue + * @param ctx context + * @param M_Warehouse_ID warehouse + * @param M_Product_ID product + * @param M_AttributeSetInstance_ID AS Instance + * @param reservationAttributeSetInstance_ID reservation AS Instance + * @param diffQty add + * @param isSOTrx + * @param trxName transaction + * @return true if updated + */ + public static boolean add (Properties ctx, int M_Warehouse_ID, + int M_Product_ID, int M_AttributeSetInstance_ID, int reservationAttributeSetInstance_ID, + BigDecimal diffQty, boolean isSOTrx, String trxName) + { + /* Do NOT use FIFO ASI for reservation */ + MProduct prd = new MProduct(ctx, M_Product_ID, trxName); + if (prd.getM_AttributeSet_ID() == 0 || ! prd.getM_AttributeSet().isInstanceAttribute()) { + // Product doesn't manage attribute set, always reserved with 0 + reservationAttributeSetInstance_ID = 0; + M_AttributeSetInstance_ID = 0; + } + // + + MStorageReservation storage = null; + StringBuffer diffText = new StringBuffer("("); + + // Get Storage + if (storage == null) + storage = getCreate (ctx, M_Warehouse_ID, + M_Product_ID, M_AttributeSetInstance_ID, isSOTrx, trxName); + // Verify + if (storage.getM_Warehouse_ID() != M_Warehouse_ID + && storage.getM_Product_ID() != M_Product_ID + && storage.getM_AttributeSetInstance_ID() != M_AttributeSetInstance_ID) + { + s_log.severe ("No Storage found - M_Warehouse_ID=" + M_Warehouse_ID + + ",M_Product_ID=" + M_Product_ID + ",ASI=" + M_AttributeSetInstance_ID); + return false; + } + + MStorageReservation storage0 = null; + if (M_AttributeSetInstance_ID != reservationAttributeSetInstance_ID) + { + storage0 = get(ctx, M_Warehouse_ID, + M_Product_ID, reservationAttributeSetInstance_ID, isSOTrx, trxName); + if (storage0 == null) // create if not existing - should not happen + { + storage0 = getCreate (ctx, M_Warehouse_ID, + M_Product_ID, reservationAttributeSetInstance_ID, isSOTrx, trxName); + } + } + boolean changed = false; + if (diffQty != null && diffQty.signum() != 0) + { + if (storage0 == null) + storage.setQty (storage.getQty().add(diffQty)); + else + storage0.setQty (storage0.getQty().add (diffQty)); + diffText.append(" Qty=").append(diffQty); + changed = true; + } + if (changed) + { + diffText.append(") -> ").append(storage.toString()); + s_log.fine(diffText.toString()); + if (storage0 != null) + storage0.saveEx(trxName); // No AttributeSetInstance + return storage.save (trxName); + } + + return true; + } // add + + /** + * Create or Get Storage Info + * @param ctx context + * @param M_Locator_ID locator + * @param M_Product_ID product + * @param M_AttributeSetInstance_ID instance + * @param trxName transaction + * @return existing/new or null + */ + public static MStorageReservation getCreate (Properties ctx, int M_Warehouse_ID, + int M_Product_ID, int M_AttributeSetInstance_ID, boolean isSOTrx, String trxName) + { + if (M_Warehouse_ID == 0) + throw new IllegalArgumentException("M_Warehouse_ID=0"); + if (M_Product_ID == 0) + throw new IllegalArgumentException("M_Product_ID=0"); + MStorageReservation retValue = get(ctx, M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, isSOTrx, trxName); + if (retValue != null) + return retValue; + + // Insert row based on warehouse + MWarehouse warehouse = new MWarehouse (ctx, M_Warehouse_ID, trxName); + if (warehouse.get_ID() != M_Warehouse_ID) + throw new IllegalArgumentException("Not found M_Warehouse_ID=" + M_Warehouse_ID); + // + retValue = new MStorageReservation (warehouse, M_Product_ID, M_AttributeSetInstance_ID, isSOTrx); + retValue.saveEx(trxName); + s_log.fine("New " + retValue); + return retValue; + } // getCreate - public BigDecimal getQtyReserved() { - // TODO Auto-generated method stub - return null; - } - } diff --git a/org.adempiere.base/src/org/eevolution/model/MDDOrderLine.java b/org.adempiere.base/src/org/eevolution/model/MDDOrderLine.java index 7aa9b06a07..852cbb453f 100644 --- a/org.adempiere.base/src/org/eevolution/model/MDDOrderLine.java +++ b/org.adempiere.base/src/org/eevolution/model/MDDOrderLine.java @@ -23,6 +23,7 @@ import java.util.Properties; import org.compiere.model.MAttributeSet; import org.compiere.model.MCharge; +import org.compiere.model.MClient; import org.compiere.model.MLocator; import org.compiere.model.MProduct; import org.compiere.model.MStorageOnHand; @@ -577,9 +578,9 @@ public class MDDOrderLine extends X_DD_OrderLine if (isInstance) { MLocator locator_from = MLocator.get(getCtx(), getM_Locator_ID()); - MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), - locator_from.getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(), - M_AttributeSet_ID, false, null, true, get_TrxName()); + MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), + locator_from.getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(), + null, true, false, 0, get_TrxName()); BigDecimal qty = Env.ZERO; for (int i = 0; i < storages.length; i++) { diff --git a/org.adempiere.ui.swing/src/org/compiere/apps/search/InfoPAttribute.java b/org.adempiere.ui.swing/src/org/compiere/apps/search/InfoPAttribute.java index 65dbace003..3a49c78d8d 100644 --- a/org.adempiere.ui.swing/src/org/compiere/apps/search/InfoPAttribute.java +++ b/org.adempiere.ui.swing/src/org/compiere/apps/search/InfoPAttribute.java @@ -512,7 +512,7 @@ public class InfoPAttribute extends CDialog // finish Instance Attributes if (sb.length() > 0) { - sb.insert(0, " AND EXISTS (SELECT * FROM M_StorageOnHand s" + sb.insert(0, " AND EXISTS (SELECT * FROM M_Storage s" + " INNER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) " + "WHERE s.M_Product_ID=p.M_Product_ID"); sb.append(")"); diff --git a/org.adempiere.ui.swing/src/org/compiere/apps/search/InfoProduct.java b/org.adempiere.ui.swing/src/org/compiere/apps/search/InfoProduct.java index 4689946bff..4ac9588740 100644 --- a/org.adempiere.ui.swing/src/org/compiere/apps/search/InfoProduct.java +++ b/org.adempiere.ui.swing/src/org/compiere/apps/search/InfoProduct.java @@ -1240,23 +1240,21 @@ public class InfoProduct extends Info implements ActionListener, ChangeListener // Fill Storage Data boolean showDetail = CLogMgt.isLevelFine(); - String sql = "SELECT s.QtyOnHand, r.Qty as QtyReserved, o.Qty as QtyOrdered," + String sql = "SELECT s.QtyOnHand, s.QtyReserved, s.QtyOrdered," + " productAttribute(s.M_AttributeSetInstance_ID), s.M_AttributeSetInstance_ID,"; if (!showDetail) - sql = "SELECT SUM(s.QtyOnHand), SUM(r.Qty), SUM(o.Qty)," + sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered)," + " productAttribute(s.M_AttributeSetInstance_ID), 0,"; sql += " w.Name, l.Value " - + "FROM M_StorageOnHand s" + + "FROM M_Storage s" + " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)" + " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) " - + " LEFT JOIN M_StorageReservation r ON (s.M_Product_ID=r.M_Product_ID AND w.M_Warehouse_ID=r.M_Warehouse_ID AND r.IsSOTrx='Y') " - + " LEFT JOIN M_StorageReservation o ON (s.M_Product_ID=o.M_Product_ID AND w.M_Warehouse_ID=o.M_Warehouse_ID AND o.IsSOTrx='N') " - + "WHERE s.M_Product_ID=?"; + + "WHERE M_Product_ID=?"; if (m_M_Warehouse_ID != 0) sql += " AND l.M_Warehouse_ID=?"; if (m_M_AttributeSetInstance_ID > 0) sql += " AND s.M_AttributeSetInstance_ID=?"; - sql += " AND (s.QtyOnHand<>0 OR r.Qty<>0 OR o.Qty<>0)"; + sql += " AND (s.QtyOnHand<>0 OR s.QtyReserved<>0 OR s.QtyOrdered<>0)"; if (!showDetail) sql += " GROUP BY productAttribute(s.M_AttributeSetInstance_ID), w.Name, l.Value"; sql += " ORDER BY l.Value"; diff --git a/org.adempiere.ui.swing/src/org/compiere/apps/search/InvoiceHistory.java b/org.adempiere.ui.swing/src/org/compiere/apps/search/InvoiceHistory.java index 5b789b2072..aef7cc3b94 100644 --- a/org.adempiere.ui.swing/src/org/compiere/apps/search/InvoiceHistory.java +++ b/org.adempiere.ui.swing/src/org/compiere/apps/search/InvoiceHistory.java @@ -566,7 +566,7 @@ public class InvoiceHistory extends CDialog sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered)," + " productAttribute(s.M_AttributeSetInstance_ID), 0,"; sql += " w.Name, l.Value " - + "FROM M_StorageOnHand s" + + "FROM M_Storage s" + " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)" + " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) " + "WHERE M_Product_ID=?"; diff --git a/org.adempiere.ui.swing/src/org/compiere/apps/search/PAttributeInstance.java b/org.adempiere.ui.swing/src/org/compiere/apps/search/PAttributeInstance.java index 66be052e8f..4e1c05bbe2 100644 --- a/org.adempiere.ui.swing/src/org/compiere/apps/search/PAttributeInstance.java +++ b/org.adempiere.ui.swing/src/org/compiere/apps/search/PAttributeInstance.java @@ -178,7 +178,7 @@ public class PAttributeInstance extends CDialog new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class), }; /** From Clause */ - private static String s_sqlFrom = "M_StorageOnHand s" + private static String s_sqlFrom = "M_Storage 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)" + " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)"; diff --git a/org.adempiere.ui.swing/src/org/compiere/grid/ed/VLocator.java b/org.adempiere.ui.swing/src/org/compiere/grid/ed/VLocator.java index 67ee41bc05..16a1055739 100644 --- a/org.adempiere.ui.swing/src/org/compiere/grid/ed/VLocator.java +++ b/org.adempiere.ui.swing/src/org/compiere/grid/ed/VLocator.java @@ -456,7 +456,7 @@ public class VLocator extends JComponent sql.append(" AND (IsDefault='Y' ") // Default Locator .append("OR EXISTS (SELECT * FROM M_Product p ") // Product Locator .append("WHERE p.M_Locator_ID=M_Locator.M_Locator_ID AND p.M_Product_ID=?)") - .append("OR EXISTS (SELECT * FROM M_StorageOnHand s ") // Storage Locator + .append("OR EXISTS (SELECT * FROM M_Storage s ") // Storage Locator .append("WHERE s.M_Locator_ID=M_Locator.M_Locator_ID AND s.M_Product_ID=?))"); String finalSql = MRole.getDefault(Env.getCtx(), false).addAccessSQL( sql.toString(), "M_Locator", MRole.SQL_NOTQUALIFIED, MRole.SQL_RO); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPAttributeInstancePanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPAttributeInstancePanel.java index 23a17c2722..f5e390fb67 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPAttributeInstancePanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPAttributeInstancePanel.java @@ -166,7 +166,7 @@ public class InfoPAttributeInstancePanel extends Window implements EventListener new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class), }; /** From Clause */ - private static String s_sqlFrom = "M_StorageOnHand s" + private static String s_sqlFrom = "M_Storage 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)" + " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)"; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPAttributePanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPAttributePanel.java index 454f7c673d..4e17950667 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPAttributePanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPAttributePanel.java @@ -614,7 +614,7 @@ public class InfoPAttributePanel extends Window implements EventListener // finish Instance Attributes if (sb.length() > 0) { - sb.insert(0, " AND EXISTS (SELECT * FROM M_StorageOnHand s" + sb.insert(0, " AND EXISTS (SELECT * FROM M_Storage s" + " INNER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) " + "WHERE s.M_Product_ID=p.M_Product_ID"); sb.append(")"); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoProductPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoProductPanel.java index 07f1e31d26..e88b7150a2 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoProductPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoProductPanel.java @@ -1453,7 +1453,7 @@ public class InfoProductPanel extends InfoPanel implements EventListener sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered)," + " productAttribute(s.M_AttributeSetInstance_ID), 0,"; sql += " w.Name, l.Value " - + "FROM M_StorageOnHand s" + + "FROM M_Storage s" + " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)" + " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) " + "WHERE M_Product_ID=?"; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InvoiceHistory.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InvoiceHistory.java index 60e0b658cc..5e2b7c1ec8 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InvoiceHistory.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InvoiceHistory.java @@ -599,7 +599,7 @@ public class InvoiceHistory extends Window implements EventListener sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered)," + " productAttribute(s.M_AttributeSetInstance_ID), 0,"; sql += " w.Name, l.Value " - + "FROM M_StorageOnHand s" + + "FROM M_Storage s" + " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)" + " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) " + "WHERE M_Product_ID=?"; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WPAttributeInstance.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WPAttributeInstance.java index 30fdf38d95..db3650136d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WPAttributeInstance.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/WPAttributeInstance.java @@ -173,7 +173,7 @@ public class WPAttributeInstance extends Window implements EventListener new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class), }; /** From Clause */ - private static String s_sqlFrom = "M_StorageOnHand s" + private static String s_sqlFrom = "M_Storage 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)" + " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)"; diff --git a/org.adempiere.ui/src/org/compiere/apps/form/Match.java b/org.adempiere.ui/src/org/compiere/apps/form/Match.java index c64e7ade8f..4872ab035f 100644 --- a/org.adempiere.ui/src/org/compiere/apps/form/Match.java +++ b/org.adempiere.ui/src/org/compiere/apps/form/Match.java @@ -32,6 +32,7 @@ import org.compiere.model.MMatchPO; import org.compiere.model.MOrderLine; import org.compiere.model.MRole; import org.compiere.model.MStorageOnHand; +import org.compiere.model.MStorageReservation; import org.compiere.process.DocumentEngine; import org.compiere.util.CLogger; import org.compiere.util.DB; @@ -491,11 +492,10 @@ public class Match success = true; // Correct Ordered Qty for Stocked Products (see MOrder.reserveStock / MInOut.processIt) if (sLine.getProduct() != null && sLine.getProduct().isStocked()) - success = MStorageOnHand.add (Env.getCtx(), sLine.getM_Warehouse_ID(), - sLine.getM_Locator_ID(), - sLine.getM_Product_ID(), - sLine.getM_AttributeSetInstance_ID(), oLine.getM_AttributeSetInstance_ID(), - null, trxName); + success = MStorageReservation.add (Env.getCtx(), sLine.getM_Warehouse_ID(), + sLine.getM_Product_ID(), + sLine.getM_AttributeSetInstance_ID(), oLine.getM_AttributeSetInstance_ID(), + qty.negate(), false, trxName); } } else