From 9d0eea8fe398498e206911070be55f21f5f133d9 Mon Sep 17 00:00:00 2001 From: hengsin Date: Fri, 11 Mar 2022 19:43:22 +0800 Subject: [PATCH] IDEMPIERE-5094 Implement validation for costing level change ( Accounting Schema and Product Category Accounting ) (#1235) --- .../i9/oracle/202203090311_IDEMPIERE-5094.sql | 10 +++++ .../202203090311_IDEMPIERE-5094.sql | 8 ++++ .../src/org/compiere/model/MAcctSchema.java | 29 +++++++++++++ .../compiere/model/MProductCategoryAcct.java | 41 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 migration/i9/oracle/202203090311_IDEMPIERE-5094.sql create mode 100644 migration/i9/postgresql/202203090311_IDEMPIERE-5094.sql diff --git a/migration/i9/oracle/202203090311_IDEMPIERE-5094.sql b/migration/i9/oracle/202203090311_IDEMPIERE-5094.sql new file mode 100644 index 0000000000..84c7b353b8 --- /dev/null +++ b/migration/i9/oracle/202203090311_IDEMPIERE-5094.sql @@ -0,0 +1,10 @@ +SELECT register_migration_script('202203090311_IDEMPIERE-5094.sql') FROM dual +; + +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- IDEMPIERE-5094 Implement validation for costing level change ( Accounting Schema and Product Category Accounting ) +INSERT INTO AD_Message (AD_Client_ID,AD_Message_ID,AD_Message_UU,AD_Org_ID,Created,CreatedBy,EntityType,IsActive,MsgText,MsgType,Updated,UpdatedBy,Value) VALUES (0,200478,'dc008155-cfe9-4394-9280-4817f3bb4f21',0,TO_DATE('2022-03-08 15:22:40','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','Costing level can''t be changed if there are product cost details created with current costing level','E',TO_DATE('2022-03-08 15:22:40','YYYY-MM-DD HH24:MI:SS'),100,'ChangeCostingLevelError') +; + diff --git a/migration/i9/postgresql/202203090311_IDEMPIERE-5094.sql b/migration/i9/postgresql/202203090311_IDEMPIERE-5094.sql new file mode 100644 index 0000000000..2550e2cdfe --- /dev/null +++ b/migration/i9/postgresql/202203090311_IDEMPIERE-5094.sql @@ -0,0 +1,8 @@ +SELECT register_migration_script('202203090311_IDEMPIERE-5094.sql') FROM dual +; + +-- IDEMPIERE-5094 Implement validation for costing level change ( Accounting Schema and Product Category Accounting ) +INSERT INTO AD_Message (AD_Client_ID,AD_Message_ID,AD_Message_UU,AD_Org_ID,Created,CreatedBy,EntityType,IsActive,MsgText,MsgType,Updated,UpdatedBy,Value) VALUES (0,200478,'dc008155-cfe9-4394-9280-4817f3bb4f21',0,TO_TIMESTAMP('2022-03-08 15:22:40','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','Costing level can''t be changed if there are product cost details created with current costing level','E',TO_TIMESTAMP('2022-03-08 15:22:40','YYYY-MM-DD HH24:MI:SS'),100,'ChangeCostingLevelError') +; + + diff --git a/org.adempiere.base/src/org/compiere/model/MAcctSchema.java b/org.adempiere.base/src/org/compiere/model/MAcctSchema.java index f98cfd4e1e..d3b7035e51 100644 --- a/org.adempiere.base/src/org/compiere/model/MAcctSchema.java +++ b/org.adempiere.base/src/org/compiere/model/MAcctSchema.java @@ -25,8 +25,11 @@ import java.util.logging.Level; import org.compiere.report.MReportTree; import org.compiere.util.CCache; +import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.KeyNamePair; +import org.compiere.util.Msg; +import org.compiere.util.Util; import org.idempiere.cache.ImmutableIntPOCache; import org.idempiere.cache.ImmutablePOSupport; @@ -712,9 +715,35 @@ public class MAcctSchema extends X_C_AcctSchema implements ImmutablePOSupport if (info.getC_AcctSchema1_ID() == getC_AcctSchema_ID()) setAD_OrgOnly_ID(0); } + if (!newRecord && is_ValueChanged(COLUMNNAME_CostingLevel)) + { + String products = getProductsWithCost(); + if (!Util.isEmpty(products)) { + log.saveError("Error", Msg.getMsg(getCtx(), "ChangeCostingLevelError") + ". Products: " + products); + return false; + } + } return true; } // beforeSave + private String getProductsWithCost() { + StringBuilder products = new StringBuilder(); + StringBuilder sql = new StringBuilder("SELECT DISTINCT p.Value FROM M_Product p JOIN M_CostDetail d ON p.M_Product_ID=d.M_Product_ID"); + sql.append(" JOIN M_Product_Category_Acct pc ON p.M_Product_Category_ID=pc.M_Product_Category_ID AND d.C_AcctSchema_ID=pc.C_AcctSchema_ID"); + sql.append(" WHERE p.IsActive='Y' AND pc.IsActive='Y' AND pc.CostingLevel IS NULL AND d.C_AcctSchema_ID=?"); + String query = DB.getDatabase().addPagingSQL(sql.toString(), 0, 50); + List> list = DB.getSQLArrayObjectsEx(get_TrxName(), query, getC_AcctSchema_ID()); + if (list != null) { + for(List entry : list) { + String value = (String) entry.get(0); + if (products.length() > 0) + products.append(","); + products.append(value); + } + } + return products.toString(); + } + @Override public MAcctSchema markImmutable() { diff --git a/org.adempiere.base/src/org/compiere/model/MProductCategoryAcct.java b/org.adempiere.base/src/org/compiere/model/MProductCategoryAcct.java index 5bb8f9e661..4bf829624e 100644 --- a/org.adempiere.base/src/org/compiere/model/MProductCategoryAcct.java +++ b/org.adempiere.base/src/org/compiere/model/MProductCategoryAcct.java @@ -17,9 +17,13 @@ package org.compiere.model; import java.sql.ResultSet; +import java.util.List; import java.util.Properties; +import org.compiere.util.DB; import org.compiere.util.Env; +import org.compiere.util.Msg; +import org.compiere.util.Util; import org.idempiere.cache.ImmutablePOSupport; import org.idempiere.cache.ImmutablePOCache; @@ -192,4 +196,41 @@ public class MProductCategoryAcct extends X_M_Product_Category_Acct implements I return sb.toString (); } // toString + @Override + protected boolean beforeSave(boolean newRecord) { + if (!newRecord && is_ValueChanged(COLUMNNAME_CostingLevel)) { + String newCostingLevel = getCostingLevel(); + String oldCostingLevel = (String) get_ValueOld(COLUMNNAME_CostingLevel); + I_C_AcctSchema schema = getC_AcctSchema(); + if (newCostingLevel == null) + newCostingLevel = schema.getCostingLevel(); + if (oldCostingLevel == null) + oldCostingLevel = schema.getCostingLevel(); + if (!newCostingLevel.equals(oldCostingLevel)) { + String products = getProductsWithCost(); + if (!Util.isEmpty(products)) { + log.saveError("Error", Msg.getMsg(getCtx(), "ChangeCostingLevelError") + ". Products: " + products); + return false; + } + } + } + return true; + } + + private String getProductsWithCost() { + StringBuilder products = new StringBuilder(); + StringBuilder sql = new StringBuilder("SELECT DISTINCT p.Value FROM M_Product p JOIN M_CostDetail d ON p.M_Product_ID=d.M_Product_ID"); + sql.append(" WHERE p.IsActive='Y' AND p.M_Product_Category_ID=? AND d.C_AcctSchema_ID=?"); + String query = DB.getDatabase().addPagingSQL(sql.toString(), 0, 50); + List> list = DB.getSQLArrayObjectsEx(get_TrxName(), query, getM_Product_Category_ID(), getC_AcctSchema_ID()); + if (list != null) { + for(List entry : list) { + String value = (String) entry.get(0); + if (products.length() > 0) + products.append(","); + products.append(value); + } + } + return products.toString(); + } } // MProductCategoryAcct