From f937cdbf35cdaefd620887b623b248468e38672d Mon Sep 17 00:00:00 2001 From: hengsin Date: Fri, 12 Nov 2021 01:48:27 +0800 Subject: [PATCH] =?UTF-8?q?IDEMPIERE-5029=20User=20can=20make=20Shipment/R?= =?UTF-8?q?eceipt=20Line=20Product=20different=20=E2=80=A6=20(#968)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product * IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product Merge patch from Carlos * IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product Make consistent with previous patch - always use oLine.M_Product_ID for reservation * IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product add safe guard against oLine is Charge and sLine is Product. * IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product - need to apply the oLine.getM_Product_ID changes to reservation log too. * IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product More fix for update of qtyreserved not using product id from oLine. * IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product update of qtyreserved: should use warehouse and issotrx from order too --- .../i8.2z/oracle/202111051150_IDEMPIERE-5029.sql | 15 +++++++++++++++ .../postgresql/202111051150_IDEMPIERE-5029.sql | 12 ++++++++++++ .../src/org/compiere/model/MInOut.java | 12 ++++++------ .../src/org/compiere/model/MInOutLine.java | 16 ++++++++++++++-- .../src/org/compiere/model/MSysConfig.java | 3 ++- .../src/org/compiere/apps/form/Match.java | 14 +++++++------- 6 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 migration/i8.2z/oracle/202111051150_IDEMPIERE-5029.sql create mode 100644 migration/i8.2z/postgresql/202111051150_IDEMPIERE-5029.sql diff --git a/migration/i8.2z/oracle/202111051150_IDEMPIERE-5029.sql b/migration/i8.2z/oracle/202111051150_IDEMPIERE-5029.sql new file mode 100644 index 0000000000..c02ae1d914 --- /dev/null +++ b/migration/i8.2z/oracle/202111051150_IDEMPIERE-5029.sql @@ -0,0 +1,15 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product +-- Nov 5, 2021, 7:31:15 PM MYT +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Shipment/Receipt Line Product is different from Order Line Product',0,0,'Y',TO_DATE('2021-11-05 19:31:14','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-11-05 19:31:14','YYYY-MM-DD HH24:MI:SS'),100,200720,'MInOutLineAndOrderLineProductDifferent','D','2e24aa42-6a8e-4ff1-b236-43d16e543389') +; + +-- Nov 8, 2021, 5:28:35 PM CET +INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200187,0,0,TO_DATE('2021-11-08 17:28:34','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2021-11-08 17:28:34','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','VALIDATE_MATCHING_PRODUCT_ON_SHIPMENT','Y','Validate if the product on shipment line must match the same product on order line (Y/N)','D','C','f8eb3b4b-a267-409a-ab83-fccdb11c8c88') +; + +SELECT register_migration_script('202111051150_IDEMPIERE-5029.sql') FROM dual +; + diff --git a/migration/i8.2z/postgresql/202111051150_IDEMPIERE-5029.sql b/migration/i8.2z/postgresql/202111051150_IDEMPIERE-5029.sql new file mode 100644 index 0000000000..6767f567c6 --- /dev/null +++ b/migration/i8.2z/postgresql/202111051150_IDEMPIERE-5029.sql @@ -0,0 +1,12 @@ +-- IDEMPIERE-5029 User can make Shipment/Receipt Line Product different from Order Line Product +-- Nov 5, 2021, 7:31:15 PM MYT +INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Shipment/Receipt Line Product is different from Order Line Product',0,0,'Y',TO_TIMESTAMP('2021-11-05 19:31:14','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-11-05 19:31:14','YYYY-MM-DD HH24:MI:SS'),100,200720,'MInOutLineAndOrderLineProductDifferent','D','2e24aa42-6a8e-4ff1-b236-43d16e543389') +; + +-- Nov 8, 2021, 5:28:35 PM CET +INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200187,0,0,TO_TIMESTAMP('2021-11-08 17:28:34','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2021-11-08 17:28:34','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','VALIDATE_MATCHING_PRODUCT_ON_SHIPMENT','Y','Validate if the product on shipment line must match the same product on order line (Y/N)','D','C','f8eb3b4b-a267-409a-ab83-fccdb11c8c88') +; + +SELECT register_migration_script('202111051150_IDEMPIERE-5029.sql') FROM dual +; + diff --git a/org.adempiere.base/src/org/compiere/model/MInOut.java b/org.adempiere.base/src/org/compiere/model/MInOut.java index 10a9169c25..b787e1b89f 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOut.java +++ b/org.adempiere.base/src/org/compiere/model/MInOut.java @@ -1423,18 +1423,18 @@ public class MInOut extends X_M_InOut implements DocAction if (oLine!=null && mtrx!=null && oLine.getQtyOrdered().signum() >= 0) { - if (sLine.getC_OrderLine_ID() != 0) + if (sLine.getC_OrderLine_ID() != 0 && oLine.getM_Product_ID() > 0) { IReservationTracer tracer = null; IReservationTracerFactory factory = Core.getReservationTracerFactory(); if (factory != null) { tracer = factory.newTracer(getC_DocType_ID(), getDocumentNo(), sLine.getLine(), sLine.get_Table_ID(), sLine.get_ID(), oLine.getM_Warehouse_ID(), - sLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), isSOTrx(), + oLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), isSOTrx(), get_TrxName()); } if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(), - sLine.getM_Product_ID(), + oLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), orderedQtyToUpdate.negate(), isSOTrx(), @@ -1510,18 +1510,18 @@ public class MInOut extends X_M_InOut implements DocAction m_processMsg = "Cannot correct Inventory OnHand [" + product.getValue() + "] - " + lastError; return DocAction.STATUS_Invalid; } - if (oLine!=null && oLine.getQtyOrdered().signum() >= 0) + if (oLine!=null && oLine.getQtyOrdered().signum() >= 0 && oLine.getM_Product_ID() > 0) { IReservationTracer tracer = null; IReservationTracerFactory factory = Core.getReservationTracerFactory(); if (factory != null) { tracer = factory.newTracer(getC_DocType_ID(), getDocumentNo(), sLine.getLine(), sLine.get_Table_ID(), sLine.get_ID(), oLine.getM_Warehouse_ID(), - sLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), isSOTrx(), + oLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), isSOTrx(), get_TrxName()); } if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(), - sLine.getM_Product_ID(), + oLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), orderedQtyToUpdate.negate(), isSOTrx(), get_TrxName(), tracer)) { diff --git a/org.adempiere.base/src/org/compiere/model/MInOutLine.java b/org.adempiere.base/src/org/compiere/model/MInOutLine.java index be0198bb21..759b51bf94 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOutLine.java +++ b/org.adempiere.base/src/org/compiere/model/MInOutLine.java @@ -575,7 +575,7 @@ public class MInOutLine extends X_M_InOutLine { if (getParent().isSOTrx()) { - log.saveError("FillMandatory", Msg.translate(getCtx(), "C_Order_ID")); + log.saveError("FillMandatory", Msg.translate(getCtx(), "C_OrderLine_ID")); return false; } } @@ -626,7 +626,19 @@ public class MInOutLine extends X_M_InOutLine return false; } } - + + if (MSysConfig.getBooleanValue(MSysConfig.VALIDATE_MATCHING_PRODUCT_ON_SHIPMENT, true, Env.getAD_Client_ID(getCtx()))) { + if (getC_OrderLine_ID() > 0) { + MOrderLine orderLine = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName()); + if (orderLine.getM_Product_ID() != getM_Product_ID()) { + log.saveError("MInOutLineAndOrderLineProductDifferent", (getM_Product_ID() > 0 ? MProduct.get(getM_Product_ID()).getValue() : "") + + " <> " + (orderLine.getM_Product_ID() > 0 ? MProduct.get(orderLine.getM_Product_ID()).getValue() : "")); + return false; + } + } + + } + return true; } // beforeSave diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java index d21ba55eca..8c041378fa 100644 --- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java +++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java @@ -44,7 +44,7 @@ public class MSysConfig extends X_AD_SysConfig /** * */ - private static final long serialVersionUID = -2487508787436200753L; + private static final long serialVersionUID = 4071371201535378277L; public static final String ADDRESS_VALIDATION = "ADDRESS_VALIDATION"; public static final String ALERT_SEND_ATTACHMENT_AS_XLS = "ALERT_SEND_ATTACHMENT_AS_XLS"; @@ -168,6 +168,7 @@ public class MSysConfig extends X_AD_SysConfig public static final String USER_LOCKING_MAX_PASSWORD_AGE_DAY = "USER_LOCKING_MAX_PASSWORD_AGE_DAY"; public static final String USER_LOCKING_PASSWORD_NOTIFY_DAY = "USER_LOCKING_PASSWORD_NOTIFY_DAY"; public static final String USER_PASSWORD_HASH = "USER_PASSWORD_HASH"; + public static final String VALIDATE_MATCHING_PRODUCT_ON_SHIPMENT = "VALIDATE_MATCHING_PRODUCT_ON_SHIPMENT"; public static final String VALIDATE_MATCHING_TO_ORDERED_QTY = "VALIDATE_MATCHING_TO_ORDERED_QTY"; public static final String WEBUI_LOGOURL = "WEBUI_LOGOURL"; public static final String ZK_ADVANCE_FIND_FILTER_COLUMN_LIST = "ZK_ADVANCE_FIND_FILTER_COLUMN_LIST"; 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 6ca0b20a23..b729de1eea 100644 --- a/org.adempiere.ui/src/org/compiere/apps/form/Match.java +++ b/org.adempiere.ui/src/org/compiere/apps/form/Match.java @@ -525,19 +525,19 @@ public class Match { success = true; // Correct Ordered Qty for Stocked Products (see MOrder.reserveStock / MInOut.processIt) - if (sLine.getProduct() != null && sLine.getProduct().isStocked()) { + if (oLine.get_ID() > 0 && oLine.getM_Product_ID() > 0 && oLine.getProduct().isStocked()) { IReservationTracer tracer = null; IReservationTracerFactory factory = Core.getReservationTracerFactory(); if (factory != null) { tracer = factory.newTracer(sLine.getParent().getC_DocType_ID(), sLine.getParent().getDocumentNo(), sLine.getLine(), - sLine.get_Table_ID(), sLine.get_ID(), sLine.getM_Warehouse_ID(), - sLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), sLine.getParent().isSOTrx(), + sLine.get_Table_ID(), sLine.get_ID(), oLine.getM_Warehouse_ID(), + oLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), oLine.getParent().isSOTrx(), trxName); } - success = MStorageReservation.add (Env.getCtx(), sLine.getM_Warehouse_ID(), - sLine.getM_Product_ID(), - sLine.getM_AttributeSetInstance_ID(), - qty.negate(), false, trxName, tracer); + success = MStorageReservation.add (Env.getCtx(), oLine.getM_Warehouse_ID(), + oLine.getM_Product_ID(), + oLine.getM_AttributeSetInstance_ID(), + qty.negate(), oLine.getParent().isSOTrx(), trxName, tracer); } } }