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 515ab3419c..7405e8f07f 100644 --- a/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java +++ b/org.adempiere.base.callout/src/org/compiere/model/CalloutOrder.java @@ -837,7 +837,7 @@ public class CalloutOrder extends CalloutEngine if (Env.isSOTrx(ctx, WindowNo)) { MProduct product = MProduct.get (ctx, M_Product_ID.intValue()); - if (product.isStocked()) + if (product.isStocked() && Env.getContext(ctx, WindowNo, "IsDropShip").equals("N")) { BigDecimal QtyOrdered = (BigDecimal)mTab.getValue("QtyOrdered"); int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID"); @@ -1324,7 +1324,7 @@ public class CalloutOrder extends CalloutEngine && QtyOrdered.signum() > 0) // no negative (returns) { MProduct product = MProduct.get (ctx, M_Product_ID); - if (product.isStocked()) + if (product.isStocked() && Env.getContext(ctx, WindowNo, "IsDropShip").equals("N")) { int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID"); int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, mTab.getTabNo(), "M_AttributeSetInstance_ID"); diff --git a/org.adempiere.base/src/org/compiere/model/GridFieldVO.java b/org.adempiere.base/src/org/compiere/model/GridFieldVO.java index b9e53c0a8e..b38563c10e 100644 --- a/org.adempiere.base/src/org/compiere/model/GridFieldVO.java +++ b/org.adempiere.base/src/org/compiere/model/GridFieldVO.java @@ -706,7 +706,7 @@ public class GridFieldVO implements Serializable public void loadLookupInfo() { try { - lookupInfo = MLookupFactory.getLookupInfo (ctx, WindowNo, AD_Column_ID, displayType, + lookupInfo = MLookupFactory.getLookupInfo (ctx, WindowNo, TabNo, AD_Column_ID, displayType, Env.getLanguage(ctx), ColumnName, AD_Reference_Value_ID, IsParent, ValidationCode); if (lookupInfo == null) diff --git a/org.adempiere.base/src/org/compiere/model/MLookup.java b/org.adempiere.base/src/org/compiere/model/MLookup.java index f5d2940b51..c54d55ac29 100644 --- a/org.adempiere.base/src/org/compiere/model/MLookup.java +++ b/org.adempiere.base/src/org/compiere/model/MLookup.java @@ -742,7 +742,7 @@ public final class MLookup extends Lookup implements Serializable // not validated if (!m_info.IsValidated) { - String validation = Env.parseContext(m_info.ctx, m_info.WindowNo, m_info.ValidationCode, false); + String validation = Env.parseContext(m_info.ctx, m_info.WindowNo, m_info.tabNo, m_info.ValidationCode, false); m_info.parsedValidationCode = validation; if (validation.length() == 0 && m_info.ValidationCode.length() > 0) { diff --git a/org.adempiere.base/src/org/compiere/model/MLookupFactory.java b/org.adempiere.base/src/org/compiere/model/MLookupFactory.java index 9a8cd9f388..0a705da80c 100644 --- a/org.adempiere.base/src/org/compiere/model/MLookupFactory.java +++ b/org.adempiere.base/src/org/compiere/model/MLookupFactory.java @@ -85,6 +85,11 @@ public class MLookupFactory } // create public static MLookupInfo getLookupInfo(Properties ctx, int WindowNo, int Column_ID, int AD_Reference_ID) + { + return getLookupInfo(ctx, WindowNo, 0, Column_ID, AD_Reference_ID); + } + + public static MLookupInfo getLookupInfo(Properties ctx, int WindowNo, int TabNo, int Column_ID, int AD_Reference_ID) { String ColumnName = ""; int AD_Reference_Value_ID = 0; @@ -124,7 +129,7 @@ public class MLookupFactory pstmt = null; } // - MLookupInfo info = getLookupInfo (ctx, WindowNo, Column_ID, AD_Reference_ID, + MLookupInfo info = getLookupInfo (ctx, WindowNo, TabNo, Column_ID, AD_Reference_ID, Env.getLanguage(ctx), ColumnName, AD_Reference_Value_ID, IsParent, ValidationCode); return info; @@ -143,7 +148,7 @@ public class MLookupFactory public static MLookup get (Properties ctx, int WindowNo, int TabNo, int Column_ID, int AD_Reference_ID) { // - MLookupInfo info = getLookupInfo (ctx, WindowNo, Column_ID, AD_Reference_ID); + MLookupInfo info = getLookupInfo (ctx, WindowNo, TabNo, Column_ID, AD_Reference_ID); return new MLookup(info, TabNo); } // get @@ -170,6 +175,36 @@ public class MLookupFactory int Column_ID, int AD_Reference_ID, Language language, String ColumnName, int AD_Reference_Value_ID, boolean IsParent, String ValidationCode) + { + return getLookupInfo(ctx, WindowNo, 0, + Column_ID, AD_Reference_ID, + language, ColumnName, AD_Reference_Value_ID, + IsParent, ValidationCode); + } // getLookupInfo + + /************************************************************************** + * Get Information for Lookups based on Column_ID for Table Columns or Process Parameters. + * + * The SQL returns three columns: + *
+ * Key, Value, Name, IsActive (where either key or value is null) + *+ * @param ctx context for access + * @param language report language + * @param WindowNo window no + * @param tabNo tab no + * @param Column_ID AD_Column_ID or AD_Process_Para_ID + * @param ColumnName key column name + * @param AD_Reference_ID display type + * @param AD_Reference_Value_ID AD_Reference (List, Table) + * @param IsParent parent (prevents query to directly access value) + * @param ValidationCode optional SQL validation + * @return lookup info structure + */ + static public MLookupInfo getLookupInfo (Properties ctx, int WindowNo, int tabNo, + int Column_ID, int AD_Reference_ID, + Language language, String ColumnName, int AD_Reference_Value_ID, + boolean IsParent, String ValidationCode) { MLookupInfo info = null; boolean needToAddSecurity = true; @@ -199,6 +234,7 @@ public class MLookupFactory // remaining values info.ctx = ctx; info.WindowNo = WindowNo; + info.tabNo = tabNo; info.Column_ID = Column_ID; info.DisplayType = AD_Reference_ID; info.AD_Reference_Value_ID = AD_Reference_Value_ID; @@ -271,7 +307,7 @@ public class MLookupFactory // s_log.finest("Query: " + info.Query); // s_log.finest("Direct: " + info.QueryDirect); return info; - } // createLookupInfo + } // getLookupInfo /************************************************************************** diff --git a/org.adempiere.base/src/org/compiere/model/MLookupInfo.java b/org.adempiere.base/src/org/compiere/model/MLookupInfo.java index 530c3b0639..800a296232 100644 --- a/org.adempiere.base/src/org/compiere/model/MLookupInfo.java +++ b/org.adempiere.base/src/org/compiere/model/MLookupInfo.java @@ -160,7 +160,7 @@ public class MLookupInfo implements Serializable, Cloneable ZoomQuery = zoomQuery; } // MLookupInfo - static final long serialVersionUID = -7958664359250070233L; + static final long serialVersionUID = -1869207615748248653L; /** SQL Query */ public String Query = null; @@ -190,6 +190,8 @@ public class MLookupInfo implements Serializable, Cloneable public Properties ctx = null; /** WindowNo */ public int WindowNo; + /** TabNo */ + public int tabNo; /** AD_Column_Info or AD_Process_Para */ public int Column_ID; diff --git a/org.adempiere.base/src/org/compiere/model/MMovement.java b/org.adempiere.base/src/org/compiere/model/MMovement.java index 31bc0ef42f..1ad6d522e2 100644 --- a/org.adempiere.base/src/org/compiere/model/MMovement.java +++ b/org.adempiere.base/src/org/compiere/model/MMovement.java @@ -474,13 +474,44 @@ public class MMovement extends X_M_Movement implements DocAction // Fallback - We have ASI if (trxFrom == null) { + Timestamp dateMPolicy= null; + MStorageOnHand[] storages = null; + if (line.getMovementQty().compareTo(Env.ZERO) > 0) { + // Find Date Material Policy bases on ASI + storages = MStorageOnHand.getWarehouse(getCtx(), 0, + line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), null, + MClient.MMPOLICY_FiFo.equals(product.getMMPolicy()), false, + line.getM_Locator_ID(), get_TrxName()); + } else { + //Case of reversal + storages = MStorageOnHand.getWarehouse(getCtx(), 0, + line.getM_Product_ID(), line.getM_AttributeSetInstanceTo_ID(), null, + MClient.MMPOLICY_FiFo.equals(product.getMMPolicy()), false, + line.getM_LocatorTo_ID(), get_TrxName()); + } + for (MStorageOnHand storage : storages) { + if (storage.getQtyOnHand().compareTo(line.getMovementQty()) >= 0) { + dateMPolicy = storage.getDateMaterialPolicy(); + break; + } + } + + if (dateMPolicy == null && storages.length > 0) + dateMPolicy = storages[0].getDateMaterialPolicy(); + + if (dateMPolicy==null && line.getM_AttributeSetInstanceTo_ID()!=0) { + I_M_AttributeSetInstance asi = line.getM_AttributeSetInstance(); + dateMPolicy = asi.getCreated(); + } else if(dateMPolicy==null) + dateMPolicy = getMovementDate(); + MLocator locator = new MLocator (getCtx(), line.getM_Locator_ID(), get_TrxName()); //Update Storage if (!MStorageOnHand.add(getCtx(),locator.getM_Warehouse_ID(), line.getM_Locator_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), - line.getMovementQty().negate(), null, get_TrxName())) + line.getMovementQty().negate(),dateMPolicy, get_TrxName())) { String lastError = CLogger.retrieveErrorString(""); m_processMsg = "Cannot correct Inventory OnHand (MA) - " + lastError; @@ -493,7 +524,7 @@ public class MMovement extends X_M_Movement implements DocAction line.getM_LocatorTo_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstanceTo_ID(), - line.getMovementQty(), null, get_TrxName())) + line.getMovementQty(),dateMPolicy, get_TrxName())) { String lastError = CLogger.retrieveErrorString(""); m_processMsg = "Cannot correct Inventory OnHand (MA) - " + lastError; diff --git a/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java b/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java index 4f0e00b5b6..0a80755095 100644 --- a/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java +++ b/org.adempiere.base/src/org/compiere/model/MStorageOnHand.java @@ -324,7 +324,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," - + "s.QtyOnHand,s.DateLastInventory,s.DateMaterialPolicy " + + "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) diff --git a/org.adempiere.base/src/org/compiere/util/Env.java b/org.adempiere.base/src/org/compiere/util/Env.java index dec7d67fb3..a38435e474 100644 --- a/org.adempiere.base/src/org/compiere/util/Env.java +++ b/org.adempiere.base/src/org/compiere/util/Env.java @@ -599,8 +599,7 @@ public final class Env */ public static String getContext (Properties ctx, int WindowNo, int TabNo, String context, boolean onlyTab) { - final boolean onlyWindow = onlyTab ? true : false; - return getContext(ctx, WindowNo, TabNo, context, onlyTab, onlyWindow); + return getContext(ctx, WindowNo, TabNo, context, onlyTab, onlyTab); } /** @@ -1455,6 +1454,78 @@ public final class Env return outStr.toString(); } // parseContext + + /** + * Parse Context replaces global or Window context @tag@ with actual value. + * + * @tag@ are ignored otherwise "" is returned + * @param ctx context + * @param WindowNo Number of Window + * @param tabNo Number of Tab + * @param value Message to be parsed + * @param onlyTab if true, no defaults are used + * @param ignoreUnparsable if true, unsuccessful @return parsed String or "" if not successful and ignoreUnparsable + * @return parsed context + */ + public static String parseContext (Properties ctx, int WindowNo, int tabNo, String value, + boolean onlyTab, boolean ignoreUnparsable) + { + if (value == null || value.length() == 0) + return ""; + + String token; + String inStr = new String(value); + StringBuilder outStr = new StringBuilder(); + + int i = inStr.indexOf('@'); + while (i != -1) + { + outStr.append(inStr.substring(0, i)); // up to @ + inStr = inStr.substring(i+1, inStr.length()); // from first @ + + int j = inStr.indexOf('@'); // next @ + if (j < 0) + { + if (log.isLoggable(Level.INFO)) log.log(Level.INFO, "No second tag: " + inStr); + //not context variable, add back @ and break + outStr.append("@"); + break; + } + + token = inStr.substring(0, j); + + // IDEMPIERE-194 Handling null context variable + String defaultV = null; + int idx = token.indexOf(":"); // or clause + if (idx >= 0) + { + defaultV = token.substring(idx+1, token.length()); + token = token.substring(0, idx); + } + + String ctxInfo = getContext(ctx, WindowNo, tabNo, token, onlyTab); // get context + if (ctxInfo.length() == 0 && (token.startsWith("#") || token.startsWith("$")) ) + ctxInfo = getContext(ctx, token); // get global context + + if (ctxInfo.length() == 0 && defaultV != null) + ctxInfo = defaultV; + + if (ctxInfo.length() == 0) + { + if (log.isLoggable(Level.CONFIG)) log.config("No Context Win=" + WindowNo + " for: " + token); + if (!ignoreUnparsable) + return ""; // token not found + } + else + outStr.append(ctxInfo); // replace context with Context + + inStr = inStr.substring(j+1, inStr.length()); // from second @ + i = inStr.indexOf('@'); + } + outStr.append(inStr); // add the rest of the string + + return outStr.toString(); + } // parseContext /** * Parse Context replaces global or Window context @tag@ with actual value. @@ -1470,6 +1541,22 @@ public final class Env { return parseContext(ctx, WindowNo, value, onlyWindow, false); } // parseContext + + /** + * Parse Context replaces global or Window context @tag@ with actual value. + * + * @param ctx context + * @param WindowNo Number of Window + * @param TabNo Number of Tab + * @param value Message to be parsed + * @param onlyWindow if true, no defaults are used + * @return parsed String or "" if not successful + */ + public static String parseContext (Properties ctx, int WindowNo, int tabNo, String value, + boolean onlyWindow) + { + return parseContext(ctx, WindowNo, tabNo, value, onlyWindow, false); + } // parseContext /** * Parse expression, replaces global or PO properties @tag@ with actual value. diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java index fd1d8fe4cd..df1bbc6288 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java @@ -2322,7 +2322,7 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements //error will be catch in the dataStatusChanged event adTabbox.getSelectedGridTab().dataDelete(); adTabbox.getSelectedGridTab().dataRefreshAll(true, true); - adTabbox.getSelectedGridTab().refreshParentTabs(); + adTabbox.getSelectedGridTab().refreshParentTabs(); adTabbox.getSelectedTabpanel().dynamicDisplay(0); focusToActivePanel(); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/WAttachment.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/WAttachment.java index ee7c6a2f2f..e33129af42 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/WAttachment.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/WAttachment.java @@ -480,28 +480,31 @@ public class WAttachment extends Window implements EventListener