From 3b866698947f06c8e1ac60a071f320bf85de5bab Mon Sep 17 00:00:00 2001 From: Carlos Ruiz Date: Wed, 5 Aug 2015 12:42:53 -0500 Subject: [PATCH] IDEMPIERE-2675: Adding custom table support in Tree --- .../oracle/201508051109_IDEMPIERE-2675.sql | 55 +++++++++++++++++++ .../201506241206_IDEMPIERE-2675.sql | 1 - .../201508051109_IDEMPIERE-2675.sql | 52 ++++++++++++++++++ .../src/org/compiere/model/MTree.java | 23 ++++++-- .../src/org/compiere/model/MTree_Base.java | 25 +++++---- .../src/org/compiere/model/PO.java | 43 +++++++++++++-- 6 files changed, 177 insertions(+), 22 deletions(-) create mode 100644 migration/i2.1z/oracle/201508051109_IDEMPIERE-2675.sql create mode 100644 migration/i2.1z/postgresql/201508051109_IDEMPIERE-2675.sql diff --git a/migration/i2.1z/oracle/201508051109_IDEMPIERE-2675.sql b/migration/i2.1z/oracle/201508051109_IDEMPIERE-2675.sql new file mode 100644 index 0000000000..a55d425796 --- /dev/null +++ b/migration/i2.1z/oracle/201508051109_IDEMPIERE-2675.sql @@ -0,0 +1,55 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- IDEMPIERE-2675 Supporting tree on any custom table +-- Aug 5, 2015 11:07:44 AM COT +UPDATE AD_Ref_List SET IsActive='N',Updated=TO_DATE('2015-08-05 11:07:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=888 +; + +-- Aug 5, 2015 11:07:47 AM COT +UPDATE AD_Ref_List SET IsActive='N',Updated=TO_DATE('2015-08-05 11:07:47','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=891 +; + +-- Aug 5, 2015 11:07:52 AM COT +UPDATE AD_Ref_List SET IsActive='N',Updated=TO_DATE('2015-08-05 11:07:52','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=889 +; + +-- Aug 5, 2015 11:07:55 AM COT +UPDATE AD_Ref_List SET IsActive='N',Updated=TO_DATE('2015-08-05 11:07:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=890 +; + +-- Aug 5, 2015 11:15:48 AM COT +UPDATE AD_Tree SET IsActive='N', IsDefault='N',Updated=TO_DATE('2015-08-05 11:15:48','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tree_ID=115 +; + +-- Aug 5, 2015 11:15:59 AM COT +UPDATE AD_Tree SET IsActive='N', IsDefault='N',Updated=TO_DATE('2015-08-05 11:15:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tree_ID=118 +; + +-- Aug 5, 2015 11:16:01 AM COT +UPDATE AD_Tree SET IsActive='N', IsDefault='N',Updated=TO_DATE('2015-08-05 11:16:01','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tree_ID=116 +; + +-- Aug 5, 2015 11:16:04 AM COT +UPDATE AD_Tree SET IsActive='N', IsDefault='N',Updated=TO_DATE('2015-08-05 11:16:04','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tree_ID=117 +; + +-- Aug 5, 2015 11:25:19 AM COT +UPDATE AD_Column SET IsUpdateable='N',Updated=TO_DATE('2015-08-05 11:25:19','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=212212 +; + +-- Aug 5, 2015 11:25:59 AM COT +UPDATE AD_Column SET MandatoryLogic='@TreeType@=''TL''',Updated=TO_DATE('2015-08-05 11:25:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=212212 +; + +-- Aug 5, 2015 11:29:40 AM COT +INSERT INTO AD_Val_Rule (AD_Val_Rule_ID,Name,Type,Code,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,EntityType,AD_Val_Rule_UU) VALUES (200083,'AD_Table with IsSummary','S','EXISTS (SELECT * FROM AD_Column c WHERE AD_Table.AD_Table_ID=c.AD_Table_ID AND c.ColumnName=''IsSummary'' AND c.IsActive=''Y'') AND AD_Table.IsView=''N''',0,0,'Y',TO_DATE('2015-08-05 11:29:39','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2015-08-05 11:29:39','YYYY-MM-DD HH24:MI:SS'),100,'D','8a00a911-354b-40c8-9cfa-a40ec65df11d') +; + +-- Aug 5, 2015 11:29:51 AM COT +UPDATE AD_Column SET AD_Val_Rule_ID=200083,Updated=TO_DATE('2015-08-05 11:29:51','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=212212 +; + +SELECT register_migration_script('201508051109_IDEMPIERE-2675.sql') FROM dual +; + diff --git a/migration/i2.1z/postgresql/201506241206_IDEMPIERE-2675.sql b/migration/i2.1z/postgresql/201506241206_IDEMPIERE-2675.sql index 92394278b6..8776a6f474 100644 --- a/migration/i2.1z/postgresql/201506241206_IDEMPIERE-2675.sql +++ b/migration/i2.1z/postgresql/201506241206_IDEMPIERE-2675.sql @@ -1,4 +1,3 @@ - -- Jun 18, 2015 10:47:07 AM IST INSERT INTO AD_Column (SeqNoSelection,AD_Column_ID,IsAlwaysUpdateable,IsSyncDatabase,AD_Client_ID,AD_Org_ID,CreatedBy,Updated,UpdatedBy,EntityType,IsSecure,IsEncrypted,IsParent,IsMandatory,IsIdentifier,SeqNo,Help,Version,FieldLength,IsKey,IsTranslated,Created,IsUpdateable,IsAutocomplete,IsAllowLogging,IsAllowCopy,Description,ColumnName,Name,IsSelectionColumn,AD_Column_UU,IsActive,IsToolbarButton,FKConstraintType,AD_Element_ID,AD_Reference_ID,AD_Table_ID) VALUES (0,212212,'N','N',0,0,100,TO_TIMESTAMP('2015-06-18 10:47:06','YYYY-MM-DD HH24:MI:SS'),100,'D','N','N','N','N','N',0,'The Database Table provides the information of the table definition',0,10,'N','N',TO_TIMESTAMP('2015-06-18 10:47:06','YYYY-MM-DD HH24:MI:SS'),'Y','N','Y','Y','Database Table information','AD_Table_ID','Table','N','cd639a6d-243f-4737-80b7-e953534cafa6','Y','N','N',126,19,288) ; diff --git a/migration/i2.1z/postgresql/201508051109_IDEMPIERE-2675.sql b/migration/i2.1z/postgresql/201508051109_IDEMPIERE-2675.sql new file mode 100644 index 0000000000..bed5e97a49 --- /dev/null +++ b/migration/i2.1z/postgresql/201508051109_IDEMPIERE-2675.sql @@ -0,0 +1,52 @@ +-- IDEMPIERE-2675 Supporting tree on any custom table +-- Aug 5, 2015 11:07:44 AM COT +UPDATE AD_Ref_List SET IsActive='N',Updated=TO_TIMESTAMP('2015-08-05 11:07:44','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=888 +; + +-- Aug 5, 2015 11:07:47 AM COT +UPDATE AD_Ref_List SET IsActive='N',Updated=TO_TIMESTAMP('2015-08-05 11:07:47','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=891 +; + +-- Aug 5, 2015 11:07:52 AM COT +UPDATE AD_Ref_List SET IsActive='N',Updated=TO_TIMESTAMP('2015-08-05 11:07:52','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=889 +; + +-- Aug 5, 2015 11:07:55 AM COT +UPDATE AD_Ref_List SET IsActive='N',Updated=TO_TIMESTAMP('2015-08-05 11:07:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Ref_List_ID=890 +; + +-- Aug 5, 2015 11:15:48 AM COT +UPDATE AD_Tree SET IsActive='N', IsDefault='N',Updated=TO_TIMESTAMP('2015-08-05 11:15:48','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tree_ID=115 +; + +-- Aug 5, 2015 11:15:59 AM COT +UPDATE AD_Tree SET IsActive='N', IsDefault='N',Updated=TO_TIMESTAMP('2015-08-05 11:15:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tree_ID=118 +; + +-- Aug 5, 2015 11:16:01 AM COT +UPDATE AD_Tree SET IsActive='N', IsDefault='N',Updated=TO_TIMESTAMP('2015-08-05 11:16:01','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tree_ID=116 +; + +-- Aug 5, 2015 11:16:04 AM COT +UPDATE AD_Tree SET IsActive='N', IsDefault='N',Updated=TO_TIMESTAMP('2015-08-05 11:16:04','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tree_ID=117 +; + +-- Aug 5, 2015 11:25:19 AM COT +UPDATE AD_Column SET IsUpdateable='N',Updated=TO_TIMESTAMP('2015-08-05 11:25:19','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=212212 +; + +-- Aug 5, 2015 11:25:59 AM COT +UPDATE AD_Column SET MandatoryLogic='@TreeType@=''TL''',Updated=TO_TIMESTAMP('2015-08-05 11:25:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=212212 +; + +-- Aug 5, 2015 11:29:40 AM COT +INSERT INTO AD_Val_Rule (AD_Val_Rule_ID,Name,Type,Code,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,EntityType,AD_Val_Rule_UU) VALUES (200083,'AD_Table with IsSummary','S','EXISTS (SELECT * FROM AD_Column c WHERE AD_Table.AD_Table_ID=c.AD_Table_ID AND c.ColumnName=''IsSummary'' AND c.IsActive=''Y'') AND AD_Table.IsView=''N''',0,0,'Y',TO_TIMESTAMP('2015-08-05 11:29:39','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2015-08-05 11:29:39','YYYY-MM-DD HH24:MI:SS'),100,'D','8a00a911-354b-40c8-9cfa-a40ec65df11d') +; + +-- Aug 5, 2015 11:29:51 AM COT +UPDATE AD_Column SET AD_Val_Rule_ID=200083,Updated=TO_TIMESTAMP('2015-08-05 11:29:51','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=212212 +; + +SELECT register_migration_script('201508051109_IDEMPIERE-2675.sql') FROM dual +; + diff --git a/org.adempiere.base/src/org/compiere/model/MTree.java b/org.adempiere.base/src/org/compiere/model/MTree.java index f4a963e60b..6a7a7f3030 100644 --- a/org.adempiere.base/src/org/compiere/model/MTree.java +++ b/org.adempiere.base/src/org/compiere/model/MTree.java @@ -29,6 +29,7 @@ import java.util.logging.Level; import javax.sql.RowSet; import org.compiere.print.MPrintColor; +import org.compiere.util.CCache; import org.compiere.util.CLogMgt; import org.compiere.util.CLogger; import org.compiere.util.DB; @@ -111,6 +112,8 @@ public class MTree extends MTree_Base /** Logger */ private static CLogger s_log = CLogger.getCLogger(MTree.class); + /** Cache */ + private static CCache tree_cache = new CCache("AD_Tree_ID", 5); /************************************************************************** * Get default (oldest) complete AD_Tree_ID for KeyColumn. @@ -121,6 +124,10 @@ public class MTree extends MTree_Base */ public static int getDefaultAD_Tree_ID (int AD_Client_ID, String keyColumnName) { + String key = AD_Client_ID + "|" + keyColumnName; + if (tree_cache.containsKey(key)) + return tree_cache.get(key); + s_log.config(keyColumnName); if (keyColumnName == null || keyColumnName.length() == 0) return 0; @@ -160,14 +167,19 @@ public class MTree extends MTree_Base else { String tableName = keyColumnName.substring(0, keyColumnName.length() - 3); - String query = "SELECT tr.AD_Tree_ID FROM AD_Tree tr inner join AD_Table t on (tr.AD_Table_ID=t.AD_Table_ID) WHERE tr.AD_Client_ID=? AND tr.TreeType='" - + TREETYPE_Table - + " ' AND tr.IsActive='Y' AND tr.IsAllNodes='Y' AND t.TableName = ?"; - int treeID = DB.getSQLValue(null, query, Env.getAD_Client_ID(Env.getCtx()),tableName); + String query = "SELECT tr.AD_Tree_ID " + + "FROM AD_Tree tr " + + "JOIN AD_Table t ON (tr.AD_Table_ID=t.AD_Table_ID) " + + "WHERE tr.AD_Client_ID=? AND tr.TreeType=? AND tr.IsActive='Y' AND tr.IsAllNodes='Y' AND t.TableName = ? " + + "ORDER BY tr.AD_Tree_ID"; + int treeID = DB.getSQLValueEx(null, query, Env.getAD_Client_ID(Env.getCtx()), TREETYPE_Table, tableName); - if (treeID != -1) + if (treeID != -1) { + tree_cache.put(key, treeID); return treeID; + } s_log.log(Level.SEVERE, "Could not map " + keyColumnName); + tree_cache.put(key, 0); return 0; } @@ -197,6 +209,7 @@ public class MTree extends MTree_Base pstmt = null; } + tree_cache.put(key, AD_Tree_ID); return AD_Tree_ID; } // getDefaultAD_Tree_ID diff --git a/org.adempiere.base/src/org/compiere/model/MTree_Base.java b/org.adempiere.base/src/org/compiere/model/MTree_Base.java index f0497df8bd..cddca0eeaf 100644 --- a/org.adempiere.base/src/org/compiere/model/MTree_Base.java +++ b/org.adempiere.base/src/org/compiere/model/MTree_Base.java @@ -190,10 +190,6 @@ public class MTree_Base extends X_AD_Tree treeType.equals(TREETYPE_User3) || treeType.equals(TREETYPE_User4)) sourceTable = "C_ElementValue"; - - // else if (treeType.equals(TREETYPE_User1)) - // sourceTable = "??"; - // end afalcone return sourceTable; } // getSourceTableName @@ -300,6 +296,11 @@ public class MTree_Base extends X_AD_Tree public String getSourceTableName (boolean tableNameOnly) { String tableName = getSourceTableName(getTreeType()); + if (tableName == null) + { + if (getAD_Table_ID() > 0) + tableName = MTable.getTableName(getCtx(), getAD_Table_ID()); + } if (tableNameOnly) return tableName; if ("M_Product".equals(tableName)) @@ -343,18 +344,22 @@ public class MTree_Base extends X_AD_Tree if (!isActive() || !isAllNodes()) setIsDefault(false); + String tableName = getSourceTableName(true); + MTable table = MTable.get(getCtx(), tableName); + if (table.getColumnIndex("IsSummary") < 0) { + // IsSummary is mandatory column to have a tree + log.saveError("Error", "IsSummary column required for tree tables"); + return false; + } if (isTreeDrivenByValue()) { - String tableName = getSourceTableName(true); - MTable table = MTable.get(getCtx(), tableName); - // Value and IsSummary are mandatory columns to have a tree driven by Value - if ( table.getColumn("Value") == null - || table.getColumn("IsSummary") == null) { + if (table.getColumnIndex("Value") < 0) { + // Value is mandatory column to have a tree driven by Value setIsTreeDrivenByValue(false); } } return true; - } // beforeSabe + } // beforeSave /** * After Save diff --git a/org.adempiere.base/src/org/compiere/model/PO.java b/org.adempiere.base/src/org/compiere/model/PO.java index 83bb9c1e3d..750f900ef9 100644 --- a/org.adempiere.base/src/org/compiere/model/PO.java +++ b/org.adempiere.base/src/org/compiere/model/PO.java @@ -2241,6 +2241,15 @@ public abstract class PO insertTranslations(); else updateTranslations(); + + // table with potential tree + if (get_ColumnIndex("IsSummary") >= 0) { + if (newRecord) + insert_Tree(MTree_Base.TREETYPE_Table); + int idxValue = get_ColumnIndex("Value"); + if (newRecord || (idxValue >= 0 && is_ValueChanged(idxValue))) + update_Tree(MTree_Base.TREETYPE_Table); + } } // try @@ -3250,6 +3259,9 @@ public abstract class PO { // deleteTranslations(localTrxName); + if (get_ColumnIndex("IsSummary") >= 0) { + delete_Tree(MTree_Base.TREETYPE_Table); + } // Delete Cascade AD_Table_ID/Record_ID (Attachments, ..) PO_Record.deleteCascade(AD_Table_ID, Record_ID, localTrxName); @@ -3859,6 +3871,8 @@ public abstract class PO .append(C_Element_ID).append(" AND t.AD_Tree_ID=ae.AD_Tree_ID)"); else // std trees sb.append(" AND t.IsAllNodes='Y' AND t.TreeType='").append(treeType).append("'"); + if (MTree_Base.TREETYPE_Table.equals(treeType)) + sb.append(" AND t.AD_Table_ID=").append(get_Table_ID()); // Duplicate Check sb.append(" AND NOT EXISTS (SELECT * FROM " + MTree_Base.getNodeTableName(treeType) + " e " + "WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=").append(get_ID()).append(")"); @@ -3895,16 +3909,27 @@ public abstract class PO return; String tableName = MTree_Base.getNodeTableName(treeType); - String sourceTableName = MTree_Base.getSourceTableName(treeType); + String sourceTableName; + String whereTree; + Object[] parameters; + if (MTree_Base.TREETYPE_Table.equals(treeType)) { + sourceTableName = this.get_TableName(); + whereTree = "TreeType=? AND AD_Table_ID=?"; + parameters = new Object[]{treeType, this.get_Table_ID()}; + } else { + sourceTableName = MTree_Base.getSourceTableName(treeType); + whereTree = "TreeType=?"; + parameters = new Object[]{treeType}; + } String updateSeqNo = "UPDATE " + tableName + " SET SeqNo=SeqNo+1 WHERE Parent_ID=? AND SeqNo>=? AND AD_Tree_ID=?"; String update = "UPDATE " + tableName + " SET SeqNo=?, Parent_ID=? WHERE Node_ID=? AND AD_Tree_ID=?"; String selMinSeqNo = "SELECT COALESCE(MIN(tn.SeqNo),-1) FROM AD_TreeNode tn JOIN " + sourceTableName + " n ON (tn.Node_ID=n." + sourceTableName + "_ID) WHERE tn.Parent_ID=? AND tn.AD_Tree_ID=? AND n.Value>?"; String selMaxSeqNo = "SELECT COALESCE(MAX(tn.SeqNo)+1,999) FROM AD_TreeNode tn JOIN " + sourceTableName + " n ON (tn.Node_ID=n." + sourceTableName + "_ID) WHERE tn.Parent_ID=? AND tn.AD_Tree_ID=? AND n.Value trees = new Query(getCtx(), MTree_Base.Table_Name, "TreeType=?", get_TrxName()) + List trees = new Query(getCtx(), MTree_Base.Table_Name, whereTree, get_TrxName()) .setClient_ID() .setOnlyActiveRecords(true) - .setParameters(treeType) + .setParameters(parameters) .list(); for (MTree_Base tree : trees) { @@ -3948,8 +3973,11 @@ public abstract class PO // IDEMPIERE-2453 StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM ") .append(MTree_Base.getNodeTableName(treeType)) - .append(" WHERE Parent_ID=?"); - int cnt = DB.getSQLValue( get_TrxName(), countSql.toString(), id); + .append(" n JOIN AD_Tree t ON n.AD_Tree_ID=t.AD_Tree_ID") + .append(" WHERE Parent_ID=? AND t.TreeType=?"); + if (MTree_Base.TREETYPE_Table.equals(treeType)) + countSql.append(" AND t.AD_Table_ID=").append(get_Table_ID()); + int cnt = DB.getSQLValueEx( get_TrxName(), countSql.toString(), id, treeType); if (cnt > 0) throw new AdempiereException(Msg.getMsg(Env.getCtx(),"NoParentDelete", new Object[] {cnt})); @@ -3958,7 +3986,10 @@ public abstract class PO .append(" n WHERE Node_ID=").append(id) .append(" AND EXISTS (SELECT * FROM AD_Tree t " + "WHERE t.AD_Tree_ID=n.AD_Tree_ID AND t.TreeType='") - .append(treeType).append("')"); + .append(treeType).append("'"); + if (MTree_Base.TREETYPE_Table.equals(treeType)) + sb.append(" AND t.AD_Table_ID=").append(get_Table_ID()); + sb.append(")"); int no = DB.executeUpdate(sb.toString(), get_TrxName()); if (no > 0) { if (log.isLoggable(Level.FINE)) log.fine("#" + no + " - TreeType=" + treeType);