Disallow negative inventories configurable per warehouse

Integrate solution from Compiere GPL Version 3.2 - and adapt to Adempiere
https://sourceforge.net/tracker/?func=detail&aid=3123715&group_id=176962&atid=879335
- Validation on Storage is per ASI - so it must be the same on Warehouse
- Fix a problem found on migration script - message trl updated wrongly and new message not created
- With negative inventory disallowed then reversing a movement requires copy of the ASI (LineMA) - also to make this reverse behave the same way as reversing MInventory
This commit is contained in:
Carlos Ruiz 2011-03-25 19:25:34 -05:00
parent dafa950221
commit 27e8db31ed
14 changed files with 361 additions and 15 deletions

View File

@ -0,0 +1,61 @@
-- 29-nov-2010 12:13:39 COT
-- Disallow Negative Inventory - configurable per warehouse
INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,Description,EntityType,Help,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,54377,0,'IsDisallowNegativeInv',TO_DATE('2010-11-29 12:13:38','YYYY-MM-DD HH24:MI:SS'),100,'Negative Inventory is not allowed in this warehouse','D','If checked, any transaction that results in the onhand inventory being driven negative will be prevented.','Y','Disallow Negative Inventory','Disallow Negative Inventory',TO_DATE('2010-11-29 12:13:38','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 29-nov-2010 12:13:40 COT
INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=54377 AND EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language!=l.AD_Language OR tt.AD_Element_ID!=t.AD_Element_ID)
;
-- 29-nov-2010 12:14:57 COT
UPDATE AD_Element_Trl SET IsTranslated='Y',Name='No Permitir Inventario Negativo',PrintName='No Permitir Inventario Negativo',Description='Inventario negativo no es permitido en esta bodega',Help='Si se marca, no se permiten transacciones que resulte en una cantidad de inventario negativa.',Updated=TO_DATE('2010-11-29 12:14:57','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=54377 AND AD_Language LIKE 'es_%'
;
-- 29-nov-2010 12:15:48 COT
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,DefaultValue,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,60108,54377,0,20,190,'IsDisallowNegativeInv',TO_DATE('2010-11-29 12:15:47','YYYY-MM-DD HH24:MI:SS'),100,'N','Negative Inventory is not allowed in this warehouse','D',1,'If checked, any transaction that results in the onhand inventory being driven negative will be prevented.','Y','N','N','N','N','Y','N','N','N','N','Y','Disallow Negative Inventory',0,TO_DATE('2010-11-29 12:15:47','YYYY-MM-DD HH24:MI:SS'),100,0)
;
-- 29-nov-2010 12:15:48 COT
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=60108 AND EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language!=l.AD_Language OR tt.AD_Column_ID!=t.AD_Column_ID)
;
-- 29-nov-2010 12:15:52 COT
ALTER TABLE M_Warehouse ADD IsDisallowNegativeInv CHAR(1) DEFAULT 'N' CHECK (IsDisallowNegativeInv IN ('Y','N')) NOT NULL
;
-- 29-nov-2010 12:16:58 COT
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,SortNo,Updated,UpdatedBy) VALUES (0,60108,60864,0,177,TO_DATE('2010-11-29 12:16:57','YYYY-MM-DD HH24:MI:SS'),100,'Negative Inventory is not allowed in this warehouse',1,'D','If checked, any transaction that results in the onhand inventory being driven negative will be prevented.','Y','Y','Y','N','N','N','N','N','Disallow Negative Inventory',110,0,TO_DATE('2010-11-29 12:16:57','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 29-nov-2010 12:16:58 COT
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=60864 AND EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language!=l.AD_Language OR tt.AD_Field_ID!=t.AD_Field_ID)
;
-- Nov 29, 2010 12:28:56 PM COT
INSERT INTO AD_Message (AD_Client_ID,AD_Message_ID,AD_Org_ID,Created,CreatedBy,EntityType,IsActive,MsgText,MsgType,Updated,UpdatedBy,Value) VALUES (0,53118,0,TO_DATE('2010-11-29 12:28:55','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','Negative on hand exists in this warehouse','E',TO_DATE('2010-11-29 12:28:55','YYYY-MM-DD HH24:MI:SS'),100,'NegativeOnhandExists')
;
-- Nov 29, 2010 12:28:56 PM COT
INSERT INTO AD_Message_Trl (AD_Language,AD_Message_ID, MsgText,MsgTip, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Message_ID, t.MsgText,t.MsgTip, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Message t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Message_ID=53118 AND NOT EXISTS (SELECT * FROM AD_Message_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Message_ID=t.AD_Message_ID)
;
-- Nov 29, 2010 12:29:10 PM COT
UPDATE AD_Message_Trl SET IsTranslated='Y',MsgText='Existen inventarios negativos en esta bodega',Updated=TO_DATE('2010-11-29 12:29:10','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=53118 AND AD_Language LIKE 'es_%'
;
-- Nov 29, 2010 12:35:26 PM COT
UPDATE AD_Field SET SeqNo=120,Updated=TO_DATE('2010-11-29 12:35:26','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=60864
;
-- Nov 29, 2010 12:44:58 PM COT
UPDATE AD_Column SET Callout='org.compiere.model.CalloutOrder.warehouse',Updated=TO_DATE('2010-11-29 12:44:58','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=2202
;
-- Nov 29, 2010 1:03:25 PM COT
UPDATE AD_Message_Trl SET MsgText='Existen inventarios negativos en este almacén',Updated=TO_DATE('2010-11-29 13:03:25','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=53118 AND AD_Language LIKE 'es_%'
;
-- Nov 29, 2010 1:03:57 PM COT
UPDATE AD_Element_Trl SET Description='Inventario negativo no es permitido en este almacén',Updated=TO_DATE('2010-11-29 13:03:57','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=54377 AND AD_Language LIKE 'es_%'
;

View File

@ -0,0 +1,13 @@
-- Dec 31, 2010 12:43:26 PM COT
-- Disallow Negative Inventory - configurable per warehouse
INSERT INTO AD_Message (AD_Client_ID,AD_Message_ID,AD_Org_ID,Created,CreatedBy,EntityType,IsActive,MsgText,MsgType,Updated,UpdatedBy,Value) VALUES (0,53132,0,TO_DATE('2010-12-31 12:43:23','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','Negative inventory disallowed in this warehouse','E',TO_DATE('2010-12-31 12:43:23','YYYY-MM-DD HH24:MI:SS'),100,'NegativeInventoryDisallowed')
;
-- Dec 31, 2010 12:43:26 PM COT
INSERT INTO AD_Message_Trl (AD_Language,AD_Message_ID, MsgText,MsgTip, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Message_ID, t.MsgText,t.MsgTip, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Message t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Message_ID=53132 AND NOT EXISTS (SELECT * FROM AD_Message_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Message_ID=t.AD_Message_ID)
;
-- Dec 31, 2010 12:44:35 PM COT
UPDATE AD_Message_Trl SET IsTranslated='Y',MsgText='No se permite inventario negativo en este almacén',Updated=TO_DATE('2010-12-31 12:44:35','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=53132 AND AD_Language LIKE 'es_%'
;

View File

@ -0,0 +1,63 @@
SET CLIENT_ENCODING TO 'UTF8';
-- 29-nov-2010 12:13:39 COT
-- Disallow Negative Inventory - configurable per warehouse
INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,Description,EntityType,Help,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,54377,0,'IsDisallowNegativeInv',TO_TIMESTAMP('2010-11-29 12:13:38','YYYY-MM-DD HH24:MI:SS'),100,'Negative Inventory is not allowed in this warehouse','D','If checked, any transaction that results in the onhand inventory being driven negative will be prevented.','Y','Disallow Negative Inventory','Disallow Negative Inventory',TO_TIMESTAMP('2010-11-29 12:13:38','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 29-nov-2010 12:13:40 COT
INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=54377 AND EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language!=l.AD_Language OR tt.AD_Element_ID!=t.AD_Element_ID)
;
-- 29-nov-2010 12:14:57 COT
UPDATE AD_Element_Trl SET IsTranslated='Y',Name='No Permitir Inventario Negativo',PrintName='No Permitir Inventario Negativo',Description='Inventario negativo no es permitido en esta bodega',Help='Si se marca, no se permiten transacciones que resulte en una cantidad de inventario negativa.',Updated=TO_TIMESTAMP('2010-11-29 12:14:57','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=54377 AND AD_Language LIKE 'es_%'
;
-- 29-nov-2010 12:15:48 COT
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,DefaultValue,Description,EntityType,FieldLength,Help,IsActive,IsAlwaysUpdateable,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,60108,54377,0,20,190,'IsDisallowNegativeInv',TO_TIMESTAMP('2010-11-29 12:15:47','YYYY-MM-DD HH24:MI:SS'),100,'N','Negative Inventory is not allowed in this warehouse','D',1,'If checked, any transaction that results in the onhand inventory being driven negative will be prevented.','Y','N','N','N','N','Y','N','N','N','N','Y','Disallow Negative Inventory',0,TO_TIMESTAMP('2010-11-29 12:15:47','YYYY-MM-DD HH24:MI:SS'),100,0)
;
-- 29-nov-2010 12:15:48 COT
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=60108 AND EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language!=l.AD_Language OR tt.AD_Column_ID!=t.AD_Column_ID)
;
-- 29-nov-2010 12:15:52 COT
ALTER TABLE M_Warehouse ADD COLUMN IsDisallowNegativeInv CHAR(1) DEFAULT 'N' CHECK (IsDisallowNegativeInv IN ('Y','N')) NOT NULL
;
-- 29-nov-2010 12:16:58 COT
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,SortNo,Updated,UpdatedBy) VALUES (0,60108,60864,0,177,TO_TIMESTAMP('2010-11-29 12:16:57','YYYY-MM-DD HH24:MI:SS'),100,'Negative Inventory is not allowed in this warehouse',1,'D','If checked, any transaction that results in the onhand inventory being driven negative will be prevented.','Y','Y','Y','N','N','N','N','N','Disallow Negative Inventory',110,0,TO_TIMESTAMP('2010-11-29 12:16:57','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 29-nov-2010 12:16:58 COT
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=60864 AND EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language!=l.AD_Language OR tt.AD_Field_ID!=t.AD_Field_ID)
;
-- Nov 29, 2010 12:28:56 PM COT
INSERT INTO AD_Message (AD_Client_ID,AD_Message_ID,AD_Org_ID,Created,CreatedBy,EntityType,IsActive,MsgText,MsgType,Updated,UpdatedBy,Value) VALUES (0,53118,0,TO_TIMESTAMP('2010-11-29 12:28:55','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','Negative on hand exists in this warehouse','E',TO_TIMESTAMP('2010-11-29 12:28:55','YYYY-MM-DD HH24:MI:SS'),100,'NegativeOnhandExists')
;
-- Nov 29, 2010 12:28:56 PM COT
INSERT INTO AD_Message_Trl (AD_Language,AD_Message_ID, MsgText,MsgTip, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Message_ID, t.MsgText,t.MsgTip, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Message t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Message_ID=53118 AND NOT EXISTS (SELECT * FROM AD_Message_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Message_ID=t.AD_Message_ID)
;
-- Nov 29, 2010 12:29:10 PM COT
UPDATE AD_Message_Trl SET IsTranslated='Y',MsgText='Existen inventarios negativos en esta bodega',Updated=TO_TIMESTAMP('2010-11-29 12:29:10','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=53118 AND AD_Language LIKE 'es_%'
;
-- Nov 29, 2010 12:35:26 PM COT
UPDATE AD_Field SET SeqNo=120,Updated=TO_TIMESTAMP('2010-11-29 12:35:26','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=60864
;
-- Nov 29, 2010 12:44:58 PM COT
UPDATE AD_Column SET Callout='org.compiere.model.CalloutOrder.warehouse',Updated=TO_DATE('2010-11-29 12:44:58','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=2202
;
-- Nov 29, 2010 1:03:25 PM COT
UPDATE AD_Message_Trl SET MsgText='Existen inventarios negativos en este almacén',Updated=TO_TIMESTAMP('2010-11-29 13:03:25','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=53118 AND AD_Language LIKE 'es_%'
;
-- Nov 29, 2010 1:03:57 PM COT
UPDATE AD_Element_Trl SET Description='Inventario negativo no es permitido en este almacén',Updated=TO_TIMESTAMP('2010-11-29 13:03:57','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=54377 AND AD_Language LIKE 'es_%'
;

View File

@ -0,0 +1,15 @@
SET CLIENT_ENCODING TO 'UTF8';
-- Dec 31, 2010 12:43:26 PM COT
-- Disallow Negative Inventory - configurable per warehouse
INSERT INTO AD_Message (AD_Client_ID,AD_Message_ID,AD_Org_ID,Created,CreatedBy,EntityType,IsActive,MsgText,MsgType,Updated,UpdatedBy,Value) VALUES (0,53132,0,TO_TIMESTAMP('2010-12-31 12:43:23','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','Negative inventory disallowed in this warehouse','E',TO_TIMESTAMP('2010-12-31 12:43:23','YYYY-MM-DD HH24:MI:SS'),100,'NegativeInventoryDisallowed')
;
-- Dec 31, 2010 12:43:26 PM COT
INSERT INTO AD_Message_Trl (AD_Language,AD_Message_ID, MsgText,MsgTip, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Message_ID, t.MsgText,t.MsgTip, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Message t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Message_ID=53132 AND NOT EXISTS (SELECT * FROM AD_Message_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Message_ID=t.AD_Message_ID)
;
-- Dec 31, 2010 12:44:35 PM COT
UPDATE AD_Message_Trl SET IsTranslated='Y',MsgText='No se permite inventario negativo en este almacén',Updated=TO_TIMESTAMP('2010-12-31 12:44:35','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=53132 AND AD_Language LIKE 'es_%'
;

View File

@ -323,7 +323,7 @@ public class CalloutInOut extends CalloutEngine
if (M_Warehouse_ID == null || M_Warehouse_ID.intValue() == 0) if (M_Warehouse_ID == null || M_Warehouse_ID.intValue() == 0)
return ""; return "";
String sql = "SELECT w.AD_Org_ID, l.M_Locator_ID " String sql = "SELECT w.AD_Org_ID, l.M_Locator_ID, w.IsDisallowNegativeInv "
+ "FROM M_Warehouse w" + "FROM M_Warehouse w"
+ " LEFT OUTER JOIN M_Locator l ON (l.M_Warehouse_ID=w.M_Warehouse_ID AND l.IsDefault='Y') " + " LEFT OUTER JOIN M_Locator l ON (l.M_Warehouse_ID=w.M_Warehouse_ID AND l.IsDefault='Y') "
+ "WHERE w.M_Warehouse_ID=?"; // 1 + "WHERE w.M_Warehouse_ID=?"; // 1
@ -352,6 +352,12 @@ public class CalloutInOut extends CalloutEngine
Env.setContext(ctx, WindowNo, "M_Locator_ID", ii.intValue()); Env.setContext(ctx, WindowNo, "M_Locator_ID", ii.intValue());
} }
} }
Boolean disallowNegInv = rs.getString(3).equals("Y");
String DeliveryRule = mTab.get_ValueAsString("DeliveryRule");
if((disallowNegInv && DeliveryRule.equals(X_C_Order.DELIVERYRULE_Force)) ||
(DeliveryRule == null || DeliveryRule.length()==0))
mTab.setValue("DeliveryRule",X_C_Order.DELIVERYRULE_Availability);
} }
catch (SQLException e) catch (SQLException e)
{ {

View File

@ -621,6 +621,32 @@ public class CalloutOrder extends CalloutEngine
return ""; return "";
} // bPartnerBill } // bPartnerBill
/**
* Set Delivery Rule if Warehouse is changed.
* @param ctx context
* @param WindowNo window no
* @param mTab tab
* @param mField field
* @param value value
* @return null or error message
*/
public String warehouse (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
{
if (isCalloutActive()) // assuming it is resetting value
return "";
Integer M_Warehouse_ID = (Integer)value;
if (M_Warehouse_ID == null || M_Warehouse_ID.intValue() == 0)
return "";
MWarehouse wh = MWarehouse.get(ctx, M_Warehouse_ID);
String DeliveryRule = mTab.get_ValueAsString("DeliveryRule");
if((wh.isDisallowNegativeInv() && DeliveryRule.equals(X_C_Order.DELIVERYRULE_Force)) ||
(DeliveryRule == null || DeliveryRule.length()==0))
mTab.setValue("DeliveryRule",X_C_Order.DELIVERYRULE_Availability);
return "";
} // warehouse
/** /**
* Order Header - PriceList. * Order Header - PriceList.

View File

@ -31,7 +31,7 @@ public interface I_M_Warehouse
public static final String Table_Name = "M_Warehouse"; public static final String Table_Name = "M_Warehouse";
/** AD_Table_ID=190 */ /** AD_Table_ID=190 */
public static final int Table_ID = MTable.getTable_ID(Table_Name); public static final int Table_ID = 190;
KeyNamePair Model = new KeyNamePair(Table_ID, Table_Name); KeyNamePair Model = new KeyNamePair(Table_ID, Table_Name);
@ -119,6 +119,19 @@ public interface I_M_Warehouse
*/ */
public boolean isActive(); public boolean isActive();
/** Column name IsDisallowNegativeInv */
public static final String COLUMNNAME_IsDisallowNegativeInv = "IsDisallowNegativeInv";
/** Set Disallow Negative Inventory.
* Negative Inventory is not allowed in this warehouse
*/
public void setIsDisallowNegativeInv (boolean IsDisallowNegativeInv);
/** Get Disallow Negative Inventory.
* Negative Inventory is not allowed in this warehouse
*/
public boolean isDisallowNegativeInv();
/** Column name IsInTransit */ /** Column name IsInTransit */
public static final String COLUMNNAME_IsInTransit = "IsInTransit"; public static final String COLUMNNAME_IsInTransit = "IsInTransit";
@ -158,7 +171,7 @@ public interface I_M_Warehouse
*/ */
public int getM_WarehouseSource_ID(); public int getM_WarehouseSource_ID();
public I_M_Warehouse getM_WarehouseSource() throws RuntimeException; public org.compiere.model.I_M_Warehouse getM_WarehouseSource() throws RuntimeException;
/** Column name Name */ /** Column name Name */
public static final String COLUMNNAME_Name = "Name"; public static final String COLUMNNAME_Name = "Name";

View File

@ -970,10 +970,10 @@ public class MInOut extends X_M_InOut implements DocAction
*/ */
protected boolean beforeSave (boolean newRecord) protected boolean beforeSave (boolean newRecord)
{ {
MWarehouse wh = MWarehouse.get(getCtx(), getM_Warehouse_ID());
// Warehouse Org // Warehouse Org
if (newRecord) if (newRecord)
{ {
MWarehouse wh = MWarehouse.get(getCtx(), getM_Warehouse_ID());
if (wh.getAD_Org_ID() != getAD_Org_ID()) if (wh.getAD_Org_ID() != getAD_Org_ID())
{ {
log.saveError("WarehouseOrgConflict", ""); log.saveError("WarehouseOrgConflict", "");
@ -981,6 +981,12 @@ public class MInOut extends X_M_InOut implements DocAction
} }
} }
boolean disallowNegInv = wh.isDisallowNegativeInv();
String DeliveryRule = getDeliveryRule();
if((disallowNegInv && DELIVERYRULE_Force.equals(DeliveryRule)) ||
(DeliveryRule == null || DeliveryRule.length()==0))
setDeliveryRule(DELIVERYRULE_Availability);
// Shipment/Receipt can have either Order/RMA (For Movement type) // Shipment/Receipt can have either Order/RMA (For Movement type)
if (getC_Order_ID() != 0 && getM_RMA_ID() != 0) if (getC_Order_ID() != 0 && getM_RMA_ID() != 0)
{ {
@ -1332,7 +1338,8 @@ public class MInOut extends X_M_InOut implements DocAction
sameWarehouse ? orderedDiff : Env.ZERO, sameWarehouse ? orderedDiff : Env.ZERO,
get_TrxName())) get_TrxName()))
{ {
m_processMsg = "Cannot correct Inventory (MA)"; String lastError = CLogger.retrieveErrorString("");
m_processMsg = "Cannot correct Inventory (MA) - " + lastError;
return DocAction.STATUS_Invalid; return DocAction.STATUS_Invalid;
} }
if (!sameWarehouse) { if (!sameWarehouse) {

View File

@ -26,6 +26,7 @@ import java.util.Properties;
import org.compiere.process.DocAction; import org.compiere.process.DocAction;
import org.compiere.process.DocumentEngine; import org.compiere.process.DocumentEngine;
import org.compiere.util.CCache; import org.compiere.util.CCache;
import org.compiere.util.CLogger;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Msg; import org.compiere.util.Msg;
@ -438,7 +439,8 @@ public class MInventory extends X_M_Inventory implements DocAction
ma.getM_AttributeSetInstance_ID(), 0, ma.getM_AttributeSetInstance_ID(), 0,
QtyMA.negate(), Env.ZERO, Env.ZERO, get_TrxName())) QtyMA.negate(), Env.ZERO, Env.ZERO, get_TrxName()))
{ {
m_processMsg = "Cannot correct Inventory (MA)"; String lastError = CLogger.retrieveErrorString("");
m_processMsg = "Cannot correct Inventory (MA) - " + lastError;
return DocAction.STATUS_Invalid; return DocAction.STATUS_Invalid;
} }

View File

@ -734,6 +734,21 @@ public class MMovement extends X_M_Movement implements DocAction
m_processMsg = "Could not create Movement Reversal Line"; m_processMsg = "Could not create Movement Reversal Line";
return false; return false;
} }
//We need to copy MA
if (rLine.getM_AttributeSetInstance_ID() == 0)
{
MMovementLineMA mas[] = MMovementLineMA.get(getCtx(),
oLine.getM_MovementLine_ID(), get_TrxName());
for (int j = 0; j < mas.length; j++)
{
MMovementLineMA ma = new MMovementLineMA (rLine,
mas[j].getM_AttributeSetInstance_ID(),
mas[j].getMovementQty().negate());
ma.saveEx();
}
}
} }
// //
if (!reversal.processIt(DocAction.ACTION_Complete)) if (!reversal.processIt(DocAction.ACTION_Complete))

View File

@ -898,14 +898,21 @@ public class MOrder extends X_C_Order implements DocAction
throw new FillMandatoryException(COLUMNNAME_M_Warehouse_ID); throw new FillMandatoryException(COLUMNNAME_M_Warehouse_ID);
} }
} }
MWarehouse wh = MWarehouse.get(getCtx(), getM_Warehouse_ID());
// Warehouse Org // Warehouse Org
if (newRecord if (newRecord
|| is_ValueChanged("AD_Org_ID") || is_ValueChanged("M_Warehouse_ID")) || is_ValueChanged("AD_Org_ID") || is_ValueChanged("M_Warehouse_ID"))
{ {
MWarehouse wh = MWarehouse.get(getCtx(), getM_Warehouse_ID());
if (wh.getAD_Org_ID() != getAD_Org_ID()) if (wh.getAD_Org_ID() != getAD_Org_ID())
log.saveWarning("WarehouseOrgConflict", ""); log.saveWarning("WarehouseOrgConflict", "");
} }
boolean disallowNegInv = wh.isDisallowNegativeInv();
String DeliveryRule = getDeliveryRule();
if((disallowNegInv && DELIVERYRULE_Force.equals(DeliveryRule)) ||
(DeliveryRule == null || DeliveryRule.length()==0))
setDeliveryRule(DELIVERYRULE_Availability);
// Reservations in Warehouse // Reservations in Warehouse
if (!newRecord && is_ValueChanged("M_Warehouse_ID")) if (!newRecord && is_ValueChanged("M_Warehouse_ID"))
{ {
@ -1680,7 +1687,11 @@ public class MOrder extends X_C_Order implements DocAction
|| MDocType.DOCSUBTYPESO_PrepayOrder.equals(DocSubTypeSO)) || MDocType.DOCSUBTYPESO_PrepayOrder.equals(DocSubTypeSO))
{ {
if (!DELIVERYRULE_Force.equals(getDeliveryRule())) if (!DELIVERYRULE_Force.equals(getDeliveryRule()))
setDeliveryRule(DELIVERYRULE_Force); {
MWarehouse wh = new MWarehouse (getCtx(), getM_Warehouse_ID(), get_TrxName());
if (!wh.isDisallowNegativeInv())
setDeliveryRule(DELIVERYRULE_Force);
}
// //
shipment = createShipment (dt, realTimePOS ? null : getDateOrdered()); shipment = createShipment (dt, realTimePOS ? null : getDateOrdered());
if (shipment == null) if (shipment == null)

View File

@ -29,6 +29,7 @@ import org.compiere.util.CLogMgt;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Msg;
/** /**
* Inventory Storage Model * Inventory Storage Model
@ -39,9 +40,9 @@ import org.compiere.util.Env;
public class MStorage extends X_M_Storage public class MStorage extends X_M_Storage
{ {
/** /**
* generated serialVersionUID *
*/ */
private static final long serialVersionUID = 9086223702645715061L; private static final long serialVersionUID = 3911132565445025309L;
/** /**
* Get Storage Info * Get Storage Info
@ -611,7 +612,6 @@ public class MStorage extends X_M_Storage
return retValue; return retValue;
} // getQtyAvailable } // getQtyAvailable
/************************************************************************** /**************************************************************************
* Persistency Constructor * Persistency Constructor
* @param ctx context * @param ctx context
@ -689,6 +689,47 @@ public class MStorage extends X_M_Storage
return m_M_Warehouse_ID; return m_M_Warehouse_ID;
} // getM_Warehouse_ID } // getM_Warehouse_ID
/**
* Before Save
* @param newRecord new
* @param success success
* @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_Storage 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", Msg.getMsg(getCtx(), "NegativeInventoryDisallowed"));
return false;
}
}
}
return true;
}
/** /**
* String Representation * String Representation
* @return info * @return info

View File

@ -21,6 +21,9 @@ import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.compiere.util.CCache; import org.compiere.util.CCache;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
/** /**
* Warehouse Model * Warehouse Model
@ -37,7 +40,7 @@ public class MWarehouse extends X_M_Warehouse
/** /**
* *
*/ */
private static final long serialVersionUID = -848214135445693460L; private static final long serialVersionUID = 7037547130625087045L;
/** /**
* Get from Cache * Get from Cache
* @param ctx context * @param ctx context
@ -197,6 +200,50 @@ public class MWarehouse extends X_M_Warehouse
return loc; return loc;
} // getLocators } // getLocators
/**
* Before Save
* @param newRecord new
* @param success success
* @return success
*/
@Override
protected boolean beforeSave(boolean newRecord)
{
/* Disallow Negative Inventory cannot be checked if there are storage records
with negative onhand. */
if (is_ValueChanged("IsDisallowNegativeInv") && isDisallowNegativeInv())
{
String sql = "SELECT M_Product_ID FROM M_Storage s "+
"WHERE s.M_Locator_ID IN (SELECT M_Locator_ID FROM M_Locator l " +
"WHERE M_Warehouse_ID=? )" +
" GROUP BY M_Product_ID, M_Locator_ID, M_AttributeSetInstance_ID " +
" HAVING SUM(s.QtyOnHand) < 0 ";
int prdid = DB.getSQLValueEx(get_TrxName(), sql, getM_Warehouse_ID());
if (prdid > 0) {
log.saveError("Error", Msg.translate(getCtx(), "NegativeOnhandExists"));
return false;
}
}
if (getAD_Org_ID() == 0)
{
int context_AD_Org_ID = Env.getAD_Org_ID(getCtx());
if (context_AD_Org_ID != 0)
{
setAD_Org_ID(context_AD_Org_ID);
log.warning("Changed Org to Context=" + context_AD_Org_ID);
}
else
{
log.saveError("Error", Msg.translate(getCtx(), "Org0NotAllowed"));
return false;
}
}
return true;
}
/** /**
* After Save * After Save
* @param newRecord new * @param newRecord new

View File

@ -30,7 +30,7 @@ public class X_M_Warehouse extends PO implements I_M_Warehouse, I_Persistent
/** /**
* *
*/ */
private static final long serialVersionUID = 20100614L; private static final long serialVersionUID = 20110325L;
/** Standard Constructor */ /** Standard Constructor */
public X_M_Warehouse (Properties ctx, int M_Warehouse_ID, String trxName) public X_M_Warehouse (Properties ctx, int M_Warehouse_ID, String trxName)
@ -39,6 +39,8 @@ public class X_M_Warehouse extends PO implements I_M_Warehouse, I_Persistent
/** if (M_Warehouse_ID == 0) /** if (M_Warehouse_ID == 0)
{ {
setC_Location_ID (0); setC_Location_ID (0);
setIsDisallowNegativeInv (false);
// N
setM_Warehouse_ID (0); setM_Warehouse_ID (0);
setName (null); setName (null);
setSeparator (null); setSeparator (null);
@ -120,6 +122,30 @@ public class X_M_Warehouse extends PO implements I_M_Warehouse, I_Persistent
return (String)get_Value(COLUMNNAME_Description); return (String)get_Value(COLUMNNAME_Description);
} }
/** Set Disallow Negative Inventory.
@param IsDisallowNegativeInv
Negative Inventory is not allowed in this warehouse
*/
public void setIsDisallowNegativeInv (boolean IsDisallowNegativeInv)
{
set_Value (COLUMNNAME_IsDisallowNegativeInv, Boolean.valueOf(IsDisallowNegativeInv));
}
/** Get Disallow Negative Inventory.
@return Negative Inventory is not allowed in this warehouse
*/
public boolean isDisallowNegativeInv ()
{
Object oo = get_Value(COLUMNNAME_IsDisallowNegativeInv);
if (oo != null)
{
if (oo instanceof Boolean)
return ((Boolean)oo).booleanValue();
return "Y".equals(oo);
}
return false;
}
/** Set In Transit. /** Set In Transit.
@param IsInTransit @param IsInTransit
Movement is in transit Movement is in transit
@ -167,9 +193,9 @@ public class X_M_Warehouse extends PO implements I_M_Warehouse, I_Persistent
return ii.intValue(); return ii.intValue();
} }
public I_M_Warehouse getM_WarehouseSource() throws RuntimeException public org.compiere.model.I_M_Warehouse getM_WarehouseSource() throws RuntimeException
{ {
return (I_M_Warehouse)MTable.get(getCtx(), I_M_Warehouse.Table_Name) return (org.compiere.model.I_M_Warehouse)MTable.get(getCtx(), org.compiere.model.I_M_Warehouse.Table_Name)
.getPO(getM_WarehouseSource_ID(), get_TrxName()); } .getPO(getM_WarehouseSource_ID(), get_TrxName()); }
/** Set Source Warehouse. /** Set Source Warehouse.