IDEMPIERE-5139 BOM validation for Deactivation of Product (#1111)
This commit is contained in:
parent
57d4caa101
commit
55e9e87f0b
|
@ -0,0 +1,11 @@
|
||||||
|
SET SQLBLANKLINES ON
|
||||||
|
SET DEFINE OFF
|
||||||
|
|
||||||
|
-- IDEMPIERE-5139 BOM validation for Deactivation of Product
|
||||||
|
-- Jan 4, 2022, 3:43:47 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','This product is being used as a component in an active BOM. Please remove from BOM or inactivate BOM before marking this product as inactive.',0,0,'Y',TO_DATE('2022-01-04 15:43:42','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2022-01-04 15:43:42','YYYY-MM-DD HH24:MI:SS'),100,200724,'DeActivateProductInActiveBOM','D','748a4e5b-95ec-4106-a949-ab700376a4a1')
|
||||||
|
;
|
||||||
|
|
||||||
|
SELECT register_migration_script('202201040800_IDEMPIERE-5139.sql') FROM dual
|
||||||
|
;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
-- IDEMPIERE-5139 BOM validation for Deactivation of Product
|
||||||
|
-- Jan 4, 2022, 3:43:47 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','This product is being used as a component in an active BOM. Please remove from BOM or inactivate BOM before marking this product as inactive.',0,0,'Y',TO_TIMESTAMP('2022-01-04 15:43:42','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-01-04 15:43:42','YYYY-MM-DD HH24:MI:SS'),100,200724,'DeActivateProductInActiveBOM','D','748a4e5b-95ec-4106-a949-ab700376a4a1')
|
||||||
|
;
|
||||||
|
|
||||||
|
SELECT register_migration_script('202201040800_IDEMPIERE-5139.sql') FROM dual
|
||||||
|
;
|
||||||
|
|
|
@ -28,6 +28,8 @@ 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;
|
||||||
import org.compiere.util.Util;
|
import org.compiere.util.Util;
|
||||||
|
import org.eevolution.model.MPPProductBOM;
|
||||||
|
import org.eevolution.model.MPPProductBOMLine;
|
||||||
import org.idempiere.cache.ImmutableIntPOCache;
|
import org.idempiere.cache.ImmutableIntPOCache;
|
||||||
import org.idempiere.cache.ImmutablePOSupport;
|
import org.idempiere.cache.ImmutablePOSupport;
|
||||||
|
|
||||||
|
@ -653,6 +655,17 @@ public class MProduct extends X_M_Product implements ImmutablePOSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
removeStorageRecords();
|
removeStorageRecords();
|
||||||
|
|
||||||
|
// check bom
|
||||||
|
if (is_ValueChanged("IsActive") && !isActive())
|
||||||
|
{
|
||||||
|
errMsg = verifyBOM();
|
||||||
|
if (! Util.isEmpty(errMsg))
|
||||||
|
{
|
||||||
|
log.saveError("Error", errMsg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
} // storage
|
} // storage
|
||||||
|
|
||||||
// it checks if UOM has been changed , if so disallow the change if the condition is true.
|
// it checks if UOM has been changed , if so disallow the change if the condition is true.
|
||||||
|
@ -753,6 +766,31 @@ public class MProduct extends X_M_Product implements ImmutablePOSupport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String verifyBOM() {
|
||||||
|
Query query = new Query(getCtx(), MPPProductBOMLine.Table_Name, MPPProductBOMLine.COLUMNNAME_M_Product_ID+"=?", get_TrxName());
|
||||||
|
List<MPPProductBOMLine> list = query.setOnlyActiveRecords(true)
|
||||||
|
.setClient_ID()
|
||||||
|
.setParameters(getM_Product_ID())
|
||||||
|
.list();
|
||||||
|
for(MPPProductBOMLine line : list) {
|
||||||
|
MPPProductBOM bom = line.getParent();
|
||||||
|
if (bom.isActive()) {
|
||||||
|
StringBuilder errMsg = new StringBuilder();
|
||||||
|
errMsg.append(Msg.getMsg(Env.getCtx(), "DeActivateProductInActiveBOM"));
|
||||||
|
String bomName = bom.getName();
|
||||||
|
errMsg.append(" (BOM: ")
|
||||||
|
.append(bomName);
|
||||||
|
String parentValue = MProduct.get(bom.getM_Product_ID()).getValue();
|
||||||
|
if (!parentValue.equals(bomName))
|
||||||
|
errMsg.append(", ").append(parentValue);
|
||||||
|
errMsg.append(")");
|
||||||
|
return errMsg.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HasInventoryOrCost
|
* HasInventoryOrCost
|
||||||
* @return true if it has Inventory or Cost
|
* @return true if it has Inventory or Cost
|
||||||
|
@ -822,6 +860,25 @@ public class MProduct extends X_M_Product implements ImmutablePOSupport
|
||||||
if (newRecord || is_ValueChanged("M_Product_Category_ID"))
|
if (newRecord || is_ValueChanged("M_Product_Category_ID"))
|
||||||
MCost.create(this);
|
MCost.create(this);
|
||||||
|
|
||||||
|
|
||||||
|
if (!newRecord && success && is_ValueChanged(COLUMNNAME_IsActive))
|
||||||
|
{
|
||||||
|
if (!isActive() && isBOM())
|
||||||
|
{
|
||||||
|
StringBuilder where = new StringBuilder();
|
||||||
|
where.append("AD_Client_ID=? ")
|
||||||
|
.append("AND M_Product_ID=? ")
|
||||||
|
.append("AND IsActive='Y'");
|
||||||
|
Query query = new Query(Env.getCtx(), MPPProductBOM.Table_Name, where.toString(), get_TrxName());
|
||||||
|
List<MPPProductBOM> boms = query.setParameters(getAD_Client_ID(), getM_Product_ID()).list();
|
||||||
|
for(MPPProductBOM bom : boms)
|
||||||
|
{
|
||||||
|
bom.setIsActive(false);
|
||||||
|
bom.saveEx();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
} // afterSave
|
} // afterSave
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,8 @@ import org.compiere.util.DB;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
import org.compiere.util.TimeUtil;
|
import org.compiere.util.TimeUtil;
|
||||||
import org.compiere.wf.MWorkflow;
|
import org.compiere.wf.MWorkflow;
|
||||||
|
import org.eevolution.model.MPPProductBOM;
|
||||||
|
import org.eevolution.model.MPPProductBOMLine;
|
||||||
import org.idempiere.test.AbstractTestCase;
|
import org.idempiere.test.AbstractTestCase;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -241,4 +243,20 @@ public class MProductTest extends AbstractTestCase {
|
||||||
count = query.setParameters(product.get_ID()).count();
|
count = query.setParameters(product.get_ID()).count();
|
||||||
assertEquals(0, count, "Storage Reservation Record > 0");
|
assertEquals(0, count, "Storage Reservation Record > 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeactivateProductBOMValidation() {
|
||||||
|
Query query = new Query(Env.getCtx(), MPPProductBOM.Table_Name, MPPProductBOM.COLUMNNAME_PP_Product_BOM_ID+"<1000000", getTrxName());
|
||||||
|
MPPProductBOM bom = query.setClient_ID().setOnlyActiveRecords(true).first();
|
||||||
|
MPPProductBOMLine[] lines = bom.getLines();
|
||||||
|
final MProduct product = new MProduct(Env.getCtx(), lines[0].getM_Product_ID(), getTrxName());
|
||||||
|
product.setIsActive(false);
|
||||||
|
assertThrows(AdempiereException.class, () -> product.saveEx(), "No exception throw for deactivation of product in active BOM");
|
||||||
|
|
||||||
|
MProduct parent = new MProduct(Env.getCtx(), bom.getM_Product_ID(), getTrxName());
|
||||||
|
parent.setIsActive(false);
|
||||||
|
parent.saveEx();
|
||||||
|
bom.load(getTrxName());
|
||||||
|
assertFalse(bom.isActive(), "BOM not auto deactivated after deactivation of parent product");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue