diff --git a/src/main/java/org/spin/base/util/DictionaryUtil.java b/src/main/java/org/spin/base/util/DictionaryUtil.java index b08eb1633..c845d4558 100644 --- a/src/main/java/org/spin/base/util/DictionaryUtil.java +++ b/src/main/java/org/spin/base/util/DictionaryUtil.java @@ -15,6 +15,17 @@ *************************************************************************************/ package org.spin.base.util; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.adempiere.model.MBrowse; +import org.adempiere.model.MBrowseField; +import org.adempiere.model.MViewColumn; import org.compiere.model.MColumn; import org.compiere.model.MField; import org.compiere.model.MTab; @@ -22,6 +33,7 @@ import org.compiere.util.DisplayType; import org.compiere.util.Env; import org.compiere.util.Language; +import org.spin.util.ASPUtil; /** * Class for handle records utils values @@ -70,4 +82,127 @@ public static String getQueryWithReferencesFromTab(MTab tab) { queryToAdd.append(joinsToAdd); return queryToAdd.toString(); } + + /** + * Get Context column names from context + * @param context + * @return + * @return List + */ + public static List getContextColumnNames(String context) { + if(context == null) { + return new ArrayList(); + } + String START = "\\@"; // A literal "(" character in regex + String END = "\\@"; // A literal ")" character in regex + + // Captures the word(s) between the above two character(s) + String patternValue = START + "(#|$){0,1}(\\w+)" + END; + + Pattern pattern = Pattern.compile(patternValue); + Matcher matcher = pattern.matcher(context); + Map columnNamesMap = new HashMap(); + while(matcher.find()) { + columnNamesMap.put(matcher.group().replace("@", "").replace("@", ""), true); + } + return new ArrayList(columnNamesMap.keySet()); + } + + /** + * Get SQL from View with a custom column as alias + * @param viewId + * @param columnNameForAlias + * @param trxName + * @return + */ + public static String getSQLFromBrowser(MBrowse browser) { + StringBuffer sql = new StringBuffer(); + sql.append("SELECT DISTINCT "); + AtomicBoolean co = new AtomicBoolean(false); + ASPUtil.getInstance().getBrowseDisplayFields(browser.getAD_Browse_ID()).forEach(field -> { + if (co.get()) + sql.append(","); + MViewColumn viewColumn = field.getAD_View_Column(); + if (viewColumn.getColumnSQL() != null + && viewColumn.getColumnSQL().length() > 0) { + sql.append(viewColumn.getColumnSQL()); + co.set(true); + } + sql.append(" AS \"" + viewColumn.getColumnName() + "\""); + }); + sql.append(" FROM ").append(browser.getAD_View().getFromClause()); + return sql.toString(); + } + + /** + * Add references to original query from smart browser + * @param originalQuery + * @return + */ + public static String addQueryReferencesFromBrowser(MBrowse browser) { + String originalQuery = getSQLFromBrowser(browser); + int fromIndex = originalQuery.toUpperCase().indexOf(" FROM "); + StringBuffer queryToAdd = new StringBuffer(originalQuery.substring(0, fromIndex)); + StringBuffer joinsToAdd = new StringBuffer(originalQuery.substring(fromIndex, originalQuery.length() - 1)); + for (MBrowseField browseField : ASPUtil.getInstance().getBrowseDisplayFields(browser.getAD_Browse_ID())) { + int displayTypeId = browseField.getAD_Reference_ID(); + if(DisplayType.isLookup(displayTypeId)) { + // Reference Value + int referenceValueId = browseField.getAD_Reference_Value_ID(); + // Validation Code + String columnName = browseField.getAD_Element().getColumnName(); + String tableName = browseField.getAD_View_Column().getAD_View_Definition().getTableAlias(); + if(browseField.getAD_View_Column().getAD_Column_ID() > 0) { + columnName = browseField.getAD_View_Column().getAD_Column().getColumnName(); + } + queryToAdd.append(", "); + ReferenceInfo referenceInfo = ReferenceUtil.getInstance(Env.getCtx()).getReferenceInfo(displayTypeId, referenceValueId, columnName, Env.getAD_Language(Env.getCtx()), tableName); + if(referenceInfo != null) { + queryToAdd.append(referenceInfo.getDisplayValue(browseField.getAD_View_Column().getColumnName())); + joinsToAdd.append(referenceInfo.getJoinValue(columnName, tableName)); + } + } + } + queryToAdd.append(joinsToAdd); + return queryToAdd.toString(); + } + + /** + * Get Order By + * @param browser + * @return + */ + public static String getSQLOrderBy(MBrowse browser) { + StringBuilder sqlOrderBy = new StringBuilder(); + for (MBrowseField field : ASPUtil.getInstance().getBrowseOrderByFields(browser.getAD_Browse_ID())) { + if (field.isOrderBy()) { + int orderByPosition = getOrderByPosition(browser, field); + if (orderByPosition <= 0) + continue; + + if (sqlOrderBy.length() > 0) { + sqlOrderBy.append(","); + } + sqlOrderBy.append(orderByPosition); + } + } + return sqlOrderBy.length() > 0 ? sqlOrderBy.toString(): ""; + } + + /** + * Get Order By Postirion for SB + * @param BrowserField + * @return + */ + public static int getOrderByPosition(MBrowse browser, MBrowseField BrowserField) { + int colOffset = 1; // columns start with 1 + int col = 0; + for (MBrowseField field : browser.getFields()) { + int sortBySqlNo = col + colOffset; + if (BrowserField.getAD_Browse_Field_ID() == field.getAD_Browse_Field_ID()) + return sortBySqlNo; + col ++; + } + return -1; + } } diff --git a/src/main/java/org/spin/grpc/service/DictionaryServiceImplementation.java b/src/main/java/org/spin/grpc/service/DictionaryServiceImplementation.java index 1268615bd..46dfb0723 100644 --- a/src/main/java/org/spin/grpc/service/DictionaryServiceImplementation.java +++ b/src/main/java/org/spin/grpc/service/DictionaryServiceImplementation.java @@ -27,7 +27,6 @@ import org.adempiere.model.I_AD_Browse; import org.adempiere.model.MBrowse; import org.adempiere.model.MBrowseField; -import org.adempiere.model.MView; import org.compiere.model.I_AD_Column; import org.compiere.model.I_AD_Element; import org.compiere.model.I_AD_Field; @@ -69,12 +68,11 @@ import org.spin.base.util.ContextManager; import org.spin.base.util.DictionaryUtil; import org.spin.base.util.RecordUtil; -import org.spin.base.util.ReferenceInfo; -import org.spin.base.util.ReferenceUtil; import org.spin.base.util.ValueUtil; import org.spin.grpc.util.ApplicationRequest; import org.spin.grpc.util.Browser; import org.spin.grpc.util.ContextInfo; +import org.spin.grpc.util.DictionaryGrpc.DictionaryImplBase; import org.spin.grpc.util.EntityRequest; import org.spin.grpc.util.Field; import org.spin.grpc.util.FieldCondition; @@ -91,7 +89,6 @@ import org.spin.grpc.util.ValidationRule; import org.spin.grpc.util.Window; import org.spin.grpc.util.ZoomWindow; -import org.spin.grpc.util.DictionaryGrpc.DictionaryImplBase; import org.spin.model.MADContextInfo; import org.spin.model.MADFieldCondition; import org.spin.model.MADFieldDefinition; @@ -716,12 +713,10 @@ private Tab.Builder convertTab(Properties context, MTab tab, List tabs, bo .setIsView(table.isView()) .setTabLevel(tab.getTabLevel()) .setTableName(ValueUtil.validateNull(table.getTableName())) - .setQuery(ValueUtil.validateNull(DictionaryUtil.getQueryWithReferencesFromTab(tab))) - .setWhereClause(whereClause.toString()) - .setOrderByClause(ValueUtil.validateNull(tab.getOrderByClause())) .setParentTabUuid(ValueUtil.validateNull(parentTabUuid)) .setIsChangeLog(table.isChangeLog()) - .setIsActive(tab.isActive()); + .setIsActive(tab.isActive()) + .addAllContextColumnNames(DictionaryUtil.getContextColumnNames(Optional.ofNullable(whereClause.toString()).orElse("") + Optional.ofNullable(tab.getOrderByClause()).orElse(""))); // For link if(contextInfoId > 0) { ContextInfo.Builder contextInfoBuilder = convertContextInfo(context, contextInfoId); @@ -888,8 +883,8 @@ private Process.Builder convertProcess(Properties context, MProcess process, boo * @return */ private Browser.Builder convertBrowser(Properties context, MBrowse browser, boolean withFields) { - String query = addQueryReferencesFromBrowser(browser, MView.getSQLFromView(browser.getAD_View_ID(), null)); - String orderByClause = getSQLOrderBy(browser); + String query = DictionaryUtil.addQueryReferencesFromBrowser(browser); + String orderByClause = DictionaryUtil.getSQLOrderBy(browser); Browser.Builder builder = Browser.newBuilder() .setId(browser.getAD_Process_ID()) .setUuid(ValueUtil.validateNull(browser.getUUID())) @@ -905,9 +900,7 @@ private Browser.Builder convertBrowser(Properties context, MBrowse browser, bool .setIsSelectedByDefault(browser.isSelectedByDefault()) .setIsShowTotal(browser.isShowTotal()) .setIsUpdateable(browser.isUpdateable()) - .setQuery(ValueUtil.validateNull(query)) - .setWhereClause(ValueUtil.validateNull(browser.getWhereClause())) - .setOrderByClause(ValueUtil.validateNull(orderByClause)); + .addAllContextColumnNames(DictionaryUtil.getContextColumnNames(Optional.ofNullable(query).orElse("") + Optional.ofNullable(browser.getWhereClause()).orElse("") + Optional.ofNullable(orderByClause).orElse(""))); // Set View UUID if(browser.getAD_View_ID() > 0) { builder.setViewUuid(ValueUtil.validateNull(browser.getAD_View().getUUID())); @@ -935,77 +928,6 @@ private Browser.Builder convertBrowser(Properties context, MBrowse browser, bool return builder; } - /** - * Add references to original query from smart browser - * @param originalQuery - * @return - */ - private String addQueryReferencesFromBrowser(MBrowse browser, String originalQuery) { - int fromIndex = originalQuery.toUpperCase().indexOf(" FROM "); - StringBuffer queryToAdd = new StringBuffer(originalQuery.substring(0, fromIndex)); - StringBuffer joinsToAdd = new StringBuffer(originalQuery.substring(fromIndex, originalQuery.length() - 1)); - for (MBrowseField browseField : browser.getDisplayFields()) { - int displayTypeId = browseField.getAD_Reference_ID(); - if(DisplayType.isLookup(displayTypeId)) { - // Reference Value - int referenceValueId = browseField.getAD_Reference_Value_ID(); - // Validation Code - String columnName = browseField.getAD_Element().getColumnName(); - String tableName = browseField.getAD_View_Column().getAD_View_Definition().getTableAlias(); - if(browseField.getAD_View_Column().getAD_Column_ID() > 0) { - columnName = browseField.getAD_View_Column().getAD_Column().getColumnName(); - } - queryToAdd.append(", "); - ReferenceInfo referenceInfo = ReferenceUtil.getInstance(Env.getCtx()).getReferenceInfo(displayTypeId, referenceValueId, columnName, Env.getAD_Language(Env.getCtx()), tableName); - if(referenceInfo != null) { - queryToAdd.append(referenceInfo.getDisplayValue(browseField.getAD_View_Column().getColumnName())); - joinsToAdd.append(referenceInfo.getJoinValue(columnName, tableName)); - } - } - } - queryToAdd.append(joinsToAdd); - return queryToAdd.toString(); - } - - /** - * Get Order By - * @param browser - * @return - */ - public String getSQLOrderBy(MBrowse browser) { - StringBuilder sqlOrderBy = new StringBuilder(); - for (MBrowseField field : browser.getOrderByFields()) { - if (field.isOrderBy()) { - int orderByPosition = getOrderByPosition(browser, field); - if (orderByPosition <= 0) - continue; - - if (sqlOrderBy.length() > 0) { - sqlOrderBy.append(","); - } - sqlOrderBy.append(orderByPosition); - } - } - return sqlOrderBy.length() > 0 ? sqlOrderBy.toString(): ""; - } - - /** - * Get Order By Postirion for SB - * @param BrowserField - * @return - */ - private int getOrderByPosition(MBrowse browser, MBrowseField BrowserField) { - int colOffset = 1; // columns start with 1 - int col = 0; - for (MBrowseField field : browser.getFields()) { - int sortBySqlNo = col + colOffset; - if (BrowserField.getAD_Browse_Field_ID() == field.getAD_Browse_Field_ID()) - return sortBySqlNo; - col ++; - } - return -1; - } - /** * Get process action from tab * @param tab diff --git a/src/main/java/org/spin/grpc/service/UserInterfaceServiceImplementation.java b/src/main/java/org/spin/grpc/service/UserInterfaceServiceImplementation.java index a8e7729cb..2eb1a2447 100644 --- a/src/main/java/org/spin/grpc/service/UserInterfaceServiceImplementation.java +++ b/src/main/java/org/spin/grpc/service/UserInterfaceServiceImplementation.java @@ -131,6 +131,7 @@ import org.spin.grpc.util.GetReportOutputRequest; import org.spin.grpc.util.GetResourceReferenceRequest; import org.spin.grpc.util.GetResourceRequest; +import org.spin.grpc.util.KeyValue; import org.spin.grpc.util.ListBrowserItemsRequest; import org.spin.grpc.util.ListBrowserItemsResponse; import org.spin.grpc.util.ListDrillTablesRequest; @@ -854,7 +855,7 @@ private ListTabEntitiesResponse.Builder convertEntitiesList(Properties context, MTab tab = MTab.get(context, tabId); String tableName = MTable.getTableName(context, tab.getAD_Table_ID()); Env.clearWinContext(request.getWindowNo()); - Map attributes = ValueUtil.convertValuesToObjects(request.getAttributesList()); + Map attributes = ValueUtil.convertValuesToObjects(request.getContextAttributesList()); // Fill context attributes.entrySet().forEach(attribute -> { if(attribute.getValue() instanceof Integer) { @@ -2341,10 +2342,17 @@ private MQuery getReportQueryFromCriteria(Criteria criteria) { * @param values * @return */ - private String getBrowserWhereClause(MBrowse browser, String parsedWhereClause, HashMap parameterMap, List values) { + private String getBrowserWhereClause(MBrowse browser, String parsedWhereClause, List contextAttributes, HashMap parameterMap, List values) { StringBuilder browserWhereClause = new StringBuilder(); List fields = ASPUtil.getInstance().getBrowseFields(browser.getAD_Browse_ID()); LinkedHashMap fieldsMap = new LinkedHashMap<>(); + AtomicReference convertedWhereClause = new AtomicReference(parsedWhereClause); + if(parsedWhereClause != null + && contextAttributes != null) { + contextAttributes.forEach(contextValue -> { + convertedWhereClause.set(convertedWhereClause.get().replaceAll("@" + contextValue.getKey() + "@", String.valueOf(ValueUtil.getObjectFromValue(contextValue.getValue())))); + }); + } // Add field to map for(MBrowseField field: fields) { fieldsMap.put(field.getAD_View_Column().getColumnName(), field); @@ -2432,8 +2440,8 @@ else if (parameterValue == null && field.isRange()) { // String whereClause = null; // - if(!Util.isEmpty(parsedWhereClause)) { - whereClause = parsedWhereClause.toString(); + if(!Util.isEmpty(convertedWhereClause.get())) { + whereClause = convertedWhereClause.get(); } if(browserWhereClause.length() > 0) { if(Util.isEmpty(whereClause)) { @@ -2461,12 +2469,16 @@ private ListBrowserItemsResponse.Builder convertBrowserList(ListBrowserItemsRequ // Populate map criteria.getConditionsList().forEach(condition -> parameterMap.put(condition.getColumnName(), ValueUtil.getObjectFromValue(condition.getValue()))); List values = new ArrayList(); - String whereClause = getBrowserWhereClause(browser, criteria.getWhereClause(), parameterMap, values); + String whereClause = getBrowserWhereClause(browser, browser.getWhereClause(), request.getContextAttributesList(), parameterMap, values); // Page prefix int page = RecordUtil.getPageNumber(request.getClientRequest().getSessionUuid(), request.getPageToken()); - StringBuilder sql = new StringBuilder(criteria.getQuery()); + String query = DictionaryUtil.addQueryReferencesFromBrowser(browser); + String orderByClause = DictionaryUtil.getSQLOrderBy(browser); + StringBuilder sql = new StringBuilder(query); if (!Util.isEmpty(whereClause)) { sql.append(" WHERE ").append(whereClause); // includes first AND + } else { + sql.append(" WHERE 1=1"); } MView view = browser.getAD_View(); MViewDefinition parentDefinition = view.getParentViewDefinition(); @@ -2476,7 +2488,6 @@ private ListBrowserItemsResponse.Builder convertBrowserList(ListBrowserItemsRequ String parsedSQL = MRole.getDefault().addAccessSQL(sql.toString(), tableNameAlias, MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO); - String orderByClause = criteria.getOrderByClause(); if(Util.isEmpty(orderByClause)) { orderByClause = ""; } else { @@ -2490,11 +2501,7 @@ private ListBrowserItemsResponse.Builder convertBrowserList(ListBrowserItemsRequ nexPageToken = RecordUtil.getPagePrefix(request.getClientRequest().getSessionUuid()) + (page + 1); } // Add Row Number - if(!Util.isEmpty(whereClause)) { - parsedSQL = parsedSQL + " AND ROWNUM >= " + page + " AND ROWNUM <= " + RecordUtil.PAGE_SIZE; - } else { - parsedSQL = parsedSQL + " WHERE ROWNUM >= " + page + " AND ROWNUM <= " + RecordUtil.PAGE_SIZE; - } + parsedSQL = parsedSQL + " AND ROWNUM >= " + page + " AND ROWNUM <= " + RecordUtil.PAGE_SIZE; // Add Order By parsedSQL = parsedSQL + orderByClause; // Return @@ -2639,7 +2646,7 @@ private org.spin.grpc.util.Callout.Builder runcallout(RunCalloutRequest request) gridTab.clearSelection(); gridTab.dataNew(false); // load values - Map attributes = ValueUtil.convertValuesToObjects(request.getAttributesList()); + Map attributes = ValueUtil.convertValuesToObjects(request.getContextAttributesList()); for(Entry attribute : attributes.entrySet()) { gridTab.setValue(attribute.getKey(), attribute.getValue()); } diff --git a/src/main/proto/business.proto b/src/main/proto/business.proto index 11f87a191..0af6f2573 100644 --- a/src/main/proto/business.proto +++ b/src/main/proto/business.proto @@ -408,7 +408,7 @@ message ListTabEntitiesRequest { string tab_uuid = 3; int32 window_no = 4; Criteria filters = 5; - repeated KeyValue attributes = 6; + repeated KeyValue context_attributes = 6; repeated string columns = 7; int32 page_size = 8; string page_token = 9; @@ -449,7 +449,7 @@ message RunCalloutRequest { Value old_value = 7; Value value = 8; int32 window_no = 9; - repeated KeyValue attributes = 10; + repeated KeyValue context_attributes = 10; } // Callout response with data from server @@ -1090,6 +1090,7 @@ message ListBrowserItemsRequest { string uuid = 1; ClientRequest client_request = 2; Criteria criteria = 3; + repeated KeyValue context_attributes = 4; int32 page_size = 5; string page_token = 6; } diff --git a/src/main/proto/dictionary.proto b/src/main/proto/dictionary.proto index ad7db2b30..e947735ee 100644 --- a/src/main/proto/dictionary.proto +++ b/src/main/proto/dictionary.proto @@ -132,15 +132,13 @@ message Tab { string parent_column_name = 26; string display_logic = 27; string commit_warning = 28; - string query = 29; - string where_clause = 30; - string order_by_clause = 31; string parent_tab_uuid = 32; + repeated string context_column_names = 33; // External Info - ContextInfo context_info = 33; - repeated Process processes = 34; - repeated Field fields = 35; - FieldGroup field_group = 36; + ContextInfo context_info = 34; + repeated Process processes = 35; + repeated Field fields = 36; + FieldGroup field_group = 37; } // Field @@ -292,21 +290,19 @@ message Browser { string description = 5; string help = 6; int32 access_level = 8; - string query = 9; - string where_clause = 10; - string order_by_clause = 11; - bool is_updateable = 12; - bool is_deleteable = 13; - bool is_selected_by_default = 14; - bool is_collapsible_by_default = 15; - bool is_executed_query_by_default = 16; - bool is_show_total = 17; - string view_uuid = 18; + repeated string context_column_names = 9; + bool is_updateable = 10; + bool is_deleteable = 11; + bool is_selected_by_default = 12; + bool is_collapsible_by_default = 13; + bool is_executed_query_by_default = 14; + bool is_show_total = 15; + string view_uuid = 16; // External Reference - Window window = 19; - Process process = 20; - repeated Field fields = 21; - bool is_active = 22; + Window window = 17; + Process process = 18; + repeated Field fields = 19; + bool is_active = 20; } // Zoom Window