IDEMPIERE-5139 BOM validation for Deactivation of Product (#1111)

This commit is contained in:
hengsin 2022-01-04 22:24:07 +08:00 committed by GitHub
parent 57d4caa101
commit 55e9e87f0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 0 deletions

View File

@ -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
;

View File

@ -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
;

View File

@ -28,6 +28,8 @@ import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
import org.eevolution.model.MPPProductBOM;
import org.eevolution.model.MPPProductBOMLine;
import org.idempiere.cache.ImmutableIntPOCache;
import org.idempiere.cache.ImmutablePOSupport;
@ -653,6 +655,17 @@ public class MProduct extends X_M_Product implements ImmutablePOSupport
}
removeStorageRecords();
// check bom
if (is_ValueChanged("IsActive") && !isActive())
{
errMsg = verifyBOM();
if (! Util.isEmpty(errMsg))
{
log.saveError("Error", errMsg);
return false;
}
}
} // storage
// 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
* @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"))
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;
} // afterSave

View File

@ -58,6 +58,8 @@ import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.TimeUtil;
import org.compiere.wf.MWorkflow;
import org.eevolution.model.MPPProductBOM;
import org.eevolution.model.MPPProductBOMLine;
import org.idempiere.test.AbstractTestCase;
import org.junit.jupiter.api.Test;
@ -241,4 +243,20 @@ public class MProductTest extends AbstractTestCase {
count = query.setParameters(product.get_ID()).count();
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");
}
}