From 39ad82ebf0086412d37aabbb38dfb6e83c80b180 Mon Sep 17 00:00:00 2001 From: Carlos Ruiz Date: Fri, 3 Sep 2021 16:20:50 +0200 Subject: [PATCH] IDEMPIERE-4470 Window Advanced Search - New operator types: AND Not, Or Not (#850) * IDEMPIERE-4470 Window Advanced Search - New operator types: AND Not, Or Not Based on pull request 170 Co-authored-by: Igor Pojzl * IDEMPIERE-4470 Window Advanced Search - New operator types: AND Not, Or Not Rename migration scripts as suggested by Heng Sin --- .../oracle/202007171100_IDEMPIERE-4364.sql | 14 +++ ...24.sql => 202109031531_IDEMPIERE-4470.sql} | 3 +- .../202007171100_IDEMPIERE-4364.sql | 11 ++ ...24.sql => 202109031531_IDEMPIERE-4470.sql} | 3 +- .../src/org/compiere/model/MQuery.java | 108 ++++++++++++++++-- .../adempiere/webui/window/FindWindow.java | 22 ++-- 6 files changed, 137 insertions(+), 24 deletions(-) create mode 100644 migration/i8.2z/oracle/202007171100_IDEMPIERE-4364.sql rename migration/i8.2z/oracle/{202103081000_IDEMPIERE-4724.sql => 202109031531_IDEMPIERE-4470.sql} (98%) create mode 100644 migration/i8.2z/postgresql/202007171100_IDEMPIERE-4364.sql rename migration/i8.2z/postgresql/{202103081000_IDEMPIERE-4724.sql => 202109031531_IDEMPIERE-4470.sql} (98%) diff --git a/migration/i8.2z/oracle/202007171100_IDEMPIERE-4364.sql b/migration/i8.2z/oracle/202007171100_IDEMPIERE-4364.sql new file mode 100644 index 0000000000..ef88d0e5b6 --- /dev/null +++ b/migration/i8.2z/oracle/202007171100_IDEMPIERE-4364.sql @@ -0,0 +1,14 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- IDEMPIERE-4364 - Advanced Search - Allow select column from window tabs. +-- Jul 17, 2020, 9:33:17 AM CEST +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 ('I','AND NOT',0,0,'Y',TO_DATE('2020-07-17 09:33:17','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-07-17 09:33:17','YYYY-MM-DD HH24:MI:SS'),100,200621,'ANDNOT','D','edddd9d0-bfc5-44b9-bba8-cfa4e5ab8d2a') +; + +-- Jul 17, 2020, 9:35:20 AM CEST +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 ('I','OR NOT',0,0,'Y',TO_DATE('2020-07-17 09:35:20','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-07-17 09:35:20','YYYY-MM-DD HH24:MI:SS'),100,200622,'ORNOT','D','dc113e24-35bc-4736-8de0-22a036e9f01b') +; + +SELECT register_migration_script('202007171100_IDEMPIERE-4364.sql') FROM dual +; diff --git a/migration/i8.2z/oracle/202103081000_IDEMPIERE-4724.sql b/migration/i8.2z/oracle/202109031531_IDEMPIERE-4470.sql similarity index 98% rename from migration/i8.2z/oracle/202103081000_IDEMPIERE-4724.sql rename to migration/i8.2z/oracle/202109031531_IDEMPIERE-4470.sql index afe12c4d80..f7fd946ef1 100644 --- a/migration/i8.2z/oracle/202103081000_IDEMPIERE-4724.sql +++ b/migration/i8.2z/oracle/202109031531_IDEMPIERE-4470.sql @@ -46,7 +46,6 @@ UPDATE AD_Field SET SeqNo=170,IsDisplayed='Y', Updated=getDate(), UpdatedBy=100 UPDATE AD_Field SET DisplayLogic='@DataType@=S', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-03-07 21:09:10','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206602 ; -SELECT register_migration_script('202103081000_IDEMPIERE-4724.sql') FROM dual +SELECT register_migration_script('202109031531_IDEMPIERE-4470.sql') FROM dual ; - diff --git a/migration/i8.2z/postgresql/202007171100_IDEMPIERE-4364.sql b/migration/i8.2z/postgresql/202007171100_IDEMPIERE-4364.sql new file mode 100644 index 0000000000..41742f09a7 --- /dev/null +++ b/migration/i8.2z/postgresql/202007171100_IDEMPIERE-4364.sql @@ -0,0 +1,11 @@ +-- IDEMPIERE-4364 - Advanced Search - Allow select column from window tabs. +-- Jul 17, 2020, 9:33:17 AM CEST +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 ('I','AND NOT',0,0,'Y',TO_TIMESTAMP('2020-07-17 09:33:17','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-07-17 09:33:17','YYYY-MM-DD HH24:MI:SS'),100,200621,'ANDNOT','D','edddd9d0-bfc5-44b9-bba8-cfa4e5ab8d2a') +; + +-- Jul 17, 2020, 9:35:20 AM CEST +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 ('I','OR NOT',0,0,'Y',TO_TIMESTAMP('2020-07-17 09:35:20','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-07-17 09:35:20','YYYY-MM-DD HH24:MI:SS'),100,200622,'ORNOT','D','dc113e24-35bc-4736-8de0-22a036e9f01b') +; + +SELECT register_migration_script('202007171100_IDEMPIERE-4364.sql') FROM dual +; diff --git a/migration/i8.2z/postgresql/202103081000_IDEMPIERE-4724.sql b/migration/i8.2z/postgresql/202109031531_IDEMPIERE-4470.sql similarity index 98% rename from migration/i8.2z/postgresql/202103081000_IDEMPIERE-4724.sql rename to migration/i8.2z/postgresql/202109031531_IDEMPIERE-4470.sql index df2f129584..b3de358bef 100644 --- a/migration/i8.2z/postgresql/202103081000_IDEMPIERE-4724.sql +++ b/migration/i8.2z/postgresql/202109031531_IDEMPIERE-4470.sql @@ -43,7 +43,6 @@ UPDATE AD_Field SET SeqNo=170,IsDisplayed='Y', Updated=statement_timestamp(), Up UPDATE AD_Field SET DisplayLogic='@DataType@=S', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-03-07 21:09:10','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206602 ; -SELECT register_migration_script('202103081000_IDEMPIERE-4724.sql') FROM dual +SELECT register_migration_script('202109031531_IDEMPIERE-4470.sql') FROM dual ; - diff --git a/org.adempiere.base/src/org/compiere/model/MQuery.java b/org.adempiere.base/src/org/compiere/model/MQuery.java index f4098f2fe0..55cc52d4d7 100644 --- a/org.adempiere.base/src/org/compiere/model/MQuery.java +++ b/org.adempiere.base/src/org/compiere/model/MQuery.java @@ -55,7 +55,7 @@ public class MQuery implements Serializable, Cloneable /** * */ - private static final long serialVersionUID = -8412818805510431201L; + private static final long serialVersionUID = 4726305684993324747L; /** * Get Query from Parameter @@ -659,6 +659,24 @@ public class MQuery implements Serializable, Cloneable m_list.add(r); } // addRestriction + /************************************************************************* + * Add Restriction + * @param ColumnName ColumnName + * @param Operator Operator, e.g. = != .. + * @param Code Code, e.g 0, All% + * @param InfoName Display Name + * @param InfoDisplay Display of Code (Lookup) + * @param andOrCondition AND/OR/AND NOT/OR NOT - concatenation of parenthesis + * @param depth ( = no open brackets ) + */ + public void addRestriction (String ColumnName, String Operator, + Object Code, String InfoName, String InfoDisplay, String andOrCondition, int depth) + { + Restriction r = new Restriction (ColumnName, Operator, + Code, InfoName, InfoDisplay, andOrCondition, depth); + m_list.add(r); + } // addRestriction + /************************************************************************* * Add Restriction * @param ColumnName ColumnName @@ -717,9 +735,29 @@ public class MQuery implements Serializable, Cloneable public void addRangeRestriction (String ColumnName, Object Code, Object Code_to, String InfoName, String InfoDisplay, String InfoDisplay_to, boolean andCondition, int depth) + { + addRangeRestriction(ColumnName, + Code, Code_to, + InfoName, InfoDisplay, InfoDisplay_to, andCondition ? "AND" : "OR", depth); + } + + /** + * Add Range Restriction (BETWEEN) + * @param ColumnName ColumnName + * @param Code Code, e.g 0, All% + * @param Code_to Code, e.g 0, All% + * @param InfoName Display Name + * @param InfoDisplay Display of Code (Lookup) + * @param InfoDisplay_to Display of Code (Lookup) + * @param andOrCondition AND/OR/AND NOT/OR NOT - concatenation of parenthesis + * @param depth ( = no open brackets ) + */ + public void addRangeRestriction (String ColumnName, + Object Code, Object Code_to, + String InfoName, String InfoDisplay, String InfoDisplay_to, String andOrCondition, int depth) { Restriction r = new Restriction (ColumnName, Code, Code_to, - InfoName, InfoDisplay, InfoDisplay_to, andCondition, depth); + InfoName, InfoDisplay, InfoDisplay_to, andOrCondition, depth); m_list.add(r); } // addRestriction @@ -842,7 +880,7 @@ public class MQuery implements Serializable, Cloneable { Restriction r = (Restriction)m_list.get(i); if (i != 0) - sb.append(r.andCondition ? " AND " : " OR "); + sb.append(" ").append(r.andOrCondition).append(" "); for ( ; currentDepth < r.joinDepth; currentDepth++ ) { sb.append('('); @@ -890,7 +928,7 @@ public class MQuery implements Serializable, Cloneable sb.append(')'); } if (i != 0) - sb.append(r.andCondition ? " AND " : " OR "); + sb.append(" ").append(r.andOrCondition).append(" "); // sb.append(r.getInfoName()) .append(r.getInfoOperator()) @@ -1211,9 +1249,29 @@ class Restriction implements Serializable * @param code Code, e.g 0, All% * @param infoName Display Name * @param infoDisplay Display of Code (Lookup) + * @param andCondition true->AND false->OR + * @param depth number of parenthesis */ Restriction (String columnName, String operator, Object code, String infoName, String infoDisplay, boolean andCondition, int depth) + { + this(columnName, operator, code, infoName, infoDisplay, + andCondition ? "AND" : "OR", + depth); + } + + /** + * Restriction + * @param columnName ColumnName + * @param operator Operator, e.g. = != .. + * @param code Code, e.g 0, All% + * @param infoName Display Name + * @param infoDisplay Display of Code (Lookup) + * @param andOrCondition AND/OR/AND NOT/OR NOT - concatenation of parenthesis + * @param depth number of parenthesis + */ + Restriction (String columnName, String operator, + Object code, String infoName, String infoDisplay, String andOrCondition, int depth) { this.ColumnName = columnName.trim(); if (infoName != null) @@ -1222,7 +1280,7 @@ class Restriction implements Serializable InfoName = ColumnName; - this.andCondition = andCondition; + this.andOrCondition = andOrCondition; this.joinDepth = depth < 0 ? 0 : depth; // @@ -1258,12 +1316,33 @@ class Restriction implements Serializable * @param infoName Display Name * @param infoDisplay Display of Code (Lookup) * @param infoDisplay_to Display of Code (Lookup) + * @param andCondition true->AND false->OR + * @param depth number of parenthesis */ Restriction (String columnName, Object code, Object code_to, String infoName, String infoDisplay, String infoDisplay_to, boolean andCondition, int depth) { - this (columnName, MQuery.BETWEEN, code, infoName, infoDisplay, andCondition, depth); + this(columnName, code, code_to, + infoName, infoDisplay, infoDisplay_to, andCondition ? "AND" : "OR", depth); + } + + /** + * Range Restriction (BETWEEN) + * @param columnName ColumnName + * @param code Code, e.g 0, All% + * @param code_to Code, e.g 0, All% + * @param infoName Display Name + * @param infoDisplay Display of Code (Lookup) + * @param infoDisplay_to Display of Code (Lookup) + * @param andOrCondition AND/OR/AND NOT/OR NOT - concatenation of parenthesis + * @param depth number of parenthesis + */ + Restriction (String columnName, + Object code, Object code_to, + String infoName, String infoDisplay, String infoDisplay_to, String andOrCondition, int depth) + { + this (columnName, MQuery.BETWEEN, code, infoName, infoDisplay, andOrCondition, depth); // Code_to Code_to = code_to; @@ -1284,11 +1363,24 @@ class Restriction implements Serializable /** * Create Restriction with direct WHERE clause * @param whereClause SQL WHERE Clause + * @param andCondition true->AND false->OR + * @param depth number of parenthesis */ Restriction (String whereClause, boolean andCondition, int depth) + { + this(whereClause, andCondition ? "AND" : "OR", depth); + } + + /** + * Create Restriction with direct WHERE clause + * @param whereClause SQL WHERE Clause + * @param andOrCondition AND/OR/AND NOT/OR NOT - concatenation of parenthesis + * @param depth number of parenthesis + */ + Restriction (String whereClause, String andOrCondition, int depth) { DirectWhereClause = whereClause; - this.andCondition = andCondition; + this.andOrCondition = andOrCondition; this.joinDepth = depth; } // Restriction @@ -1309,7 +1401,7 @@ class Restriction implements Serializable /** Info To */ protected String InfoDisplay_to; /** And/Or Condition */ - protected boolean andCondition = true; + protected String andOrCondition = "AND"; /** And/Or condition nesting depth ( = number of open brackets at and/or) */ protected int joinDepth = 0; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java index 3aa9865261..003f68cd99 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java @@ -1041,11 +1041,13 @@ public class FindWindow extends Window implements EventListener, ValueCha setValues(listColumn, listOperator, fields); - // And Or + // And / Or / And Not / Or Not ValueNamePair[] andOr = new ValueNamePair[] { new ValueNamePair ("", ""), new ValueNamePair ("AND", Msg.getMsg(Env.getCtx(),"AND")), - new ValueNamePair ("OR", Msg.getMsg(Env.getCtx(),"OR")) + new ValueNamePair ("OR", Msg.getMsg(Env.getCtx(),"OR")), + new ValueNamePair ("AND NOT", Msg.getMsg(Env.getCtx(),"ANDNOT")), + new ValueNamePair ("OR NOT", Msg.getMsg(Env.getCtx(),"ORNOT")) }; for (ValueNamePair item: andOr) @@ -1845,10 +1847,6 @@ public class FindWindow extends Window implements EventListener, ValueCha // And Or Listbox listAndOr = (Listbox)row.getFellow("listAndOr"+row.getId()); String andOr = listAndOr.getSelectedItem().getValue().toString(); - boolean and = true; - if ( rowIndex > 1 ) { - and = !"OR".equals(andOr); - } // Op Combobox op = (Combobox)row.getFellow("listOperator"+row.getId()); if (op == null) @@ -1880,7 +1878,7 @@ public class FindWindow extends Window implements EventListener, ValueCha if(Operator.equals(MQuery.NULL) || Operator.equals(MQuery.NOT_NULL)) { m_query.addRestriction(ColumnSQL, Operator, null, - infoName, null, and, openBrackets); + infoName, null, andOr, openBrackets); appendCode(code, ColumnName, Operator, "", "", andOr, lBrackets, rBrackets); } continue; @@ -1924,26 +1922,26 @@ public class FindWindow extends Window implements EventListener, ValueCha if (parsedValue2 == null) continue; m_query.addRangeRestriction(ColumnSQL, parsedValue, parsedValue2, - infoName, infoDisplay, infoDisplay_to, and, openBrackets); + infoName, infoDisplay, infoDisplay_to, andOr, openBrackets); } else if (isProductCategoryField && MQuery.OPERATORS[MQuery.EQUAL_INDEX].getValue().equals(Operator)) { if (!(parsedValue instanceof Integer)) { continue; } - m_query.addRestriction(getSubCategoryWhereClause(field, ((Integer) parsedValue).intValue()), and, openBrackets); + m_query.addRestriction(getSubCategoryWhereClause(field, ((Integer) parsedValue).intValue()), andOr, openBrackets); } else if ((field.getDisplayType()==DisplayType.ChosenMultipleSelectionList||field.getDisplayType()==DisplayType.ChosenMultipleSelectionSearch||field.getDisplayType()==DisplayType.ChosenMultipleSelectionTable) && (MQuery.OPERATORS[MQuery.EQUAL_INDEX].getValue().equals(Operator) || MQuery.OPERATORS[MQuery.NOT_EQUAL_INDEX].getValue().equals(Operator))) { String clause = DB.intersectClauseForCSV(ColumnSQL, parsedValue.toString()); if (MQuery.OPERATORS[MQuery.EQUAL_INDEX].getValue().equals(Operator)) - m_query.addRestriction(clause, and, openBrackets); + m_query.addRestriction(clause, andOr, openBrackets); else - m_query.addRestriction("NOT (" + clause + ")", and, openBrackets); + m_query.addRestriction("NOT (" + clause + ")", andOr, openBrackets); } else m_query.addRestriction(ColumnSQL, Operator, parsedValue, - infoName, infoDisplay, and, openBrackets); + infoName, infoDisplay, andOr, openBrackets); appendCode(code, ColumnName, Operator, value != null ? value.toString() : "", value2 != null ? value2.toString() : "", andOr, lBrackets, rBrackets); }