# HG changeset patch
# User Asier Lostalé <asier.lostale@openbravo.com>
# Date 1441612681 -7200
#      Mon Sep 07 09:58:01 2015 +0200
# Node ID 92f47278d535542f27cd20785b83d4dfc7b01f1d
# Parent  32eed95daa4afb5933dff07f5d71a2a0439901fd
related to issue 30761: product characteristics popup shows all values

  Filter out values in product characteristics popup when the parent grid is a
  selector based on a custom HQL query.

diff -r 32eed95daa4a -r 92f47278d535 modules/org.openbravo.client.application/web/org.openbravo.client.application/js/form/formitem/ob-formitem-characteristics.js
--- a/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/form/formitem/ob-formitem-characteristics.js	Fri Sep 04 15:26:38 2015 +0200
+++ b/modules/org.openbravo.client.application/web/org.openbravo.client.application/js/form/formitem/ob-formitem-characteristics.js	Mon Sep 07 09:58:01 2015 +0200
@@ -347,6 +347,7 @@
 
         ds.requestProperties.params._parentDSIdentifier = me.parentDSIdentifier;
         ds.requestProperties.params._propertyPath = me.propertyName;
+        ds.requestProperties.params._selectorDefinition = me.selectorDefinition;
 
         return this.Super('setDataSource', [ds, fields]);
       }
@@ -516,7 +517,8 @@
   },
 
   init: function () {
-    var propertyPath, i, parentDSIdentifier = null;
+    var propertyPath, i, parentDSIdentifier = null,
+        selectorDefinition = null;
 
     // Getting the product property in the entity we are filtering it.
     // It is obtained based on fieldName, in case its path is compound (i.e.
@@ -539,10 +541,16 @@
       parentDSIdentifier = this.parentGrid.getDataSource().dataURL.substr(this.parentGrid.getDataSource().dataURL.lastIndexOf('/') + 1);
     }
 
+    if (this.parentGrid.selector) {
+      // parent grid is a selector
+      selectorDefinition = this.parentGrid.selector.selectorDefinitionId;
+    }
+
     this.addAutoChild('filterDialog', {
       title: this.title,
       callback: this.getID() + '.filterDialogCallback(value)',
       parentDSIdentifier: parentDSIdentifier,
+      selectorDefinition: selectorDefinition,
       propertyName: this.propertyName
     });
 
diff -r 32eed95daa4a -r 92f47278d535 modules/org.openbravo.userinterface.selector/src/org/openbravo/userinterface/selector/CustomQuerySelectorDatasource.java
--- a/modules/org.openbravo.userinterface.selector/src/org/openbravo/userinterface/selector/CustomQuerySelectorDatasource.java	Fri Sep 04 15:26:38 2015 +0200
+++ b/modules/org.openbravo.userinterface.selector/src/org/openbravo/userinterface/selector/CustomQuerySelectorDatasource.java	Mon Sep 07 09:58:01 2015 +0200
@@ -65,7 +65,7 @@
   private static final String ADDITIONAL_FILTERS = "@additional_filters@";
   private static final String NEW_FILTER_CLAUSE = "\n AND ";
   private static final String NEW_OR_FILTER_CLAUSE = "\n OR ";
-  private static final String ALIAS_PREFIX = "alias_";
+  public static final String ALIAS_PREFIX = "alias_";
 
   @Override
   protected int getCount(Map<String, String> parameters) {
@@ -185,7 +185,7 @@
    * @return a String with the HQL to be executed.
    */
 
-  private String parseOptionalFilters(Map<String, String> parameters, Selector sel,
+  public String parseOptionalFilters(Map<String, String> parameters, Selector sel,
       SimpleDateFormat xmlDateFormat, List<Object> typedParameters) {
     String HQL = sel.getHQL();
     if (!HQL.contains(ADDITIONAL_FILTERS)) {
diff -r 32eed95daa4a -r 92f47278d535 src/org/openbravo/materialmgmt/ProductCharacteristicsDS.java
--- a/src/org/openbravo/materialmgmt/ProductCharacteristicsDS.java	Fri Sep 04 15:26:38 2015 +0200
+++ b/src/org/openbravo/materialmgmt/ProductCharacteristicsDS.java	Mon Sep 07 09:58:01 2015 +0200
@@ -26,11 +26,15 @@
 import java.util.Map.Entry;
 import java.util.Set;
 
+import javax.inject.Inject;
+
 import org.apache.commons.lang.StringUtils;
 import org.codehaus.jettison.json.JSONArray;
 import org.codehaus.jettison.json.JSONException;
 import org.codehaus.jettison.json.JSONObject;
+import org.hibernate.Hibernate;
 import org.hibernate.Query;
+import org.openbravo.base.exception.OBException;
 import org.openbravo.base.model.Entity;
 import org.openbravo.base.model.ModelProvider;
 import org.openbravo.base.provider.OBProvider;
@@ -38,13 +42,20 @@
 import org.openbravo.dal.core.OBContext;
 import org.openbravo.dal.security.OrganizationStructureProvider;
 import org.openbravo.dal.service.OBDal;
+import org.openbravo.dal.service.OBDao;
 import org.openbravo.model.ad.access.Role;
 import org.openbravo.model.ad.access.RoleOrganization;
+import org.openbravo.service.datasource.DataSourceService;
+import org.openbravo.service.datasource.DataSourceServiceProvider;
 import org.openbravo.service.datasource.DefaultDataSourceService;
 import org.openbravo.service.json.AdvancedQueryBuilder;
 import org.openbravo.service.json.DataEntityQueryService;
 import org.openbravo.service.json.JsonConstants;
 import org.openbravo.service.json.JsonUtils;
+import org.openbravo.userinterface.selector.CustomQuerySelectorDatasource;
+import org.openbravo.userinterface.selector.Selector;
+import org.openbravo.userinterface.selector.SelectorConstants;
+import org.openbravo.userinterface.selector.SelectorField;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -68,18 +79,20 @@
   final static int VAL_NAME = 3;
   final static int VAL_PARENT = 4;
 
+  @Inject
+  private DataSourceServiceProvider dataSourceServiceProvider;
+
   @Override
   public String fetch(Map<String, String> parameters) {
     OBContext.setAdminMode(true);
     try {
-      String entityName = parameters.get("_parentDSIdentifier");
+      String dsIdentifier = parameters.get("_parentDSIdentifier");
 
-      Entity parentGridEntity = ModelProvider.getInstance().getEntity(entityName, false);
       String productPath = parameters.get("_propertyPath");
       List<String> allNodes = new ArrayList<String>();
       Set<String> missingNodes = new HashSet<String>();
 
-      JSONArray responseData = getAllNodes(parameters, parentGridEntity, productPath, allNodes,
+      JSONArray responseData = getAllNodes(parameters, dsIdentifier, productPath, allNodes,
           missingNodes, false);
 
       final JSONObject jsonResult = new JSONObject();
@@ -90,7 +103,6 @@
       jsonResponse.put(JsonConstants.RESPONSE_TOTALROWS, responseData.length());
       jsonResponse.put(JsonConstants.RESPONSE_STARTROW, 0);
       jsonResponse.put(JsonConstants.RESPONSE_ENDROW, responseData.length() - 1);
-      jsonResponse.put(JsonConstants.ENTITYNAME, entityName);
       jsonResult.put(JsonConstants.RESPONSE_RESPONSE, jsonResponse);
 
       return jsonResult.toString();
@@ -102,30 +114,62 @@
     }
   }
 
-  private JSONArray getAllNodes(Map<String, String> parameters, Entity parentGridEntity,
+  private JSONArray getAllNodes(Map<String, String> parameters, String dsIdentifier,
       String productPath, List<String> allNodes, Set<String> missingNodes, boolean addMissingNodes)
       throws JSONException {
 
     String gridWhereClause = null;
+    String customSelectorWhereClause = null;
     AdvancedQueryBuilder qb = null;
     int initialNumOfMissingNodes = 0;
-    if (!addMissingNodes && parentGridEntity != null) {
-      final DataEntityQueryService queryService = OBProvider.getInstance().get(
-          DataEntityQueryService.class);
+    Entity parentGridEntity = null;
+    final List<Object> selectorParameters = new ArrayList<Object>();
+    if (!addMissingNodes && dsIdentifier != null) {
+      parentGridEntity = ModelProvider.getInstance().getEntity(dsIdentifier, false);
+      if (parentGridEntity != null) {
+        final DataEntityQueryService queryService = OBProvider.getInstance().get(
+            DataEntityQueryService.class);
 
-      queryService.setEntityName(parentGridEntity.getName());
-      queryService.setFilterOnReadableOrganizations(true);
-      if (parameters.containsKey(JsonConstants.USE_ALIAS)) {
-        queryService.setUseAlias();
-      }
+        queryService.setEntityName(parentGridEntity.getName());
+        queryService.setFilterOnReadableOrganizations(true);
+        if (parameters.containsKey(JsonConstants.USE_ALIAS)) {
+          queryService.setUseAlias();
+        }
 
-      final JSONObject criteria = JsonUtils.buildCriteria(parameters);
-      queryService.setCriteria(criteria);
+        final JSONObject criteria = JsonUtils.buildCriteria(parameters);
+        queryService.setCriteria(criteria);
 
-      qb = queryService.getQueryBuilder();
-      qb.setMainAlias("e");
-      if (StringUtils.isNotBlank(qb.getWhereClause())) {
-        gridWhereClause = queryService.getWhereClause();
+        qb = queryService.getQueryBuilder();
+        qb.setMainAlias("e");
+        if (StringUtils.isNotBlank(qb.getWhereClause())) {
+          gridWhereClause = queryService.getWhereClause();
+        }
+      } else {
+        // check if this is a custom HQL selector
+        DataSourceService ds = dataSourceServiceProvider.getDataSource(dsIdentifier);
+        if (ds != null && ds instanceof CustomQuerySelectorDatasource) {
+          CustomQuerySelectorDatasource selDS = (CustomQuerySelectorDatasource) ds;
+          String selectorId = parameters.get("_selectorDefinition");
+          Selector sel = OBDal.getInstance().get(Selector.class, selectorId);
+          List<SelectorField> fields = OBDao.getActiveOBObjectList(sel,
+              Selector.PROPERTY_OBUISELSELECTORFIELDLIST);
+
+          // Forcing object initialization to prevent LazyInitializationException in case session is
+          // cleared when number of records is big enough
+          Hibernate.initialize(fields);
+
+          // forces to use AND instead of OR in case of multiple fields with filter
+          parameters.put(SelectorConstants.DS_REQUEST_TYPE_PARAMETER, "Window");
+
+          customSelectorWhereClause = selDS.parseOptionalFilters(parameters, sel,
+              JsonUtils.createDateFormat(), selectorParameters);
+
+          if (StringUtils.isNotBlank(customSelectorWhereClause)
+              && customSelectorWhereClause.indexOf("from ") != -1) {
+            customSelectorWhereClause = customSelectorWhereClause
+                .substring(customSelectorWhereClause.indexOf("from ") + 5);
+          }
+        }
       }
     } else {
       initialNumOfMissingNodes = missingNodes.size();
@@ -149,6 +193,10 @@
           + gridWhereClause + "  and pcv.characteristicValue = v and pcv.product = " + productPath
           + ")");
 
+    } else if (StringUtils.isNotBlank(customSelectorWhereClause)) {
+      hqlBuilder.append("  and exists (from ProductCharacteristicValue pcv, "
+          + customSelectorWhereClause + "  and pcv.characteristicValue = v and pcv.product = "
+          + productPath + ")");
     }
 
     hqlBuilder.append(" order by c.name, ");
@@ -156,12 +204,35 @@
     hqlBuilder.append("          tn.sequenceNumber ");
 
     String hql = hqlBuilder.toString();
-    log.info("HQL:\n " + hql);
+    log.debug("HQL:\n " + hql);
 
-    Query qTree = OBDal.getInstance().getSession().createQuery(hql);
+    Query qTree;
+    try {
+      qTree = OBDal.getInstance().getSession().createQuery(hql);
+    } catch (Exception e) {
+      if (StringUtils.isNotBlank(customSelectorWhereClause)
+          || StringUtils.isNotBlank(gridWhereClause)) {
+        log.error(
+            "Error in product characteristics tree generated query, trying to generate it without parent grid limit {}",
+            hql, e);
+        // fallback: if it is not possible to restrict nodes to the filters applied in parent grid,
+        // try to at least show all nodes
+        return getAllNodes(parameters, null, productPath, allNodes, missingNodes, false);
+      } else {
+        throw new OBException(e);
+      }
+    }
     if (StringUtils.isNotBlank(gridWhereClause)) {
       for (Entry<String, Object> param : qb.getNamedParameters().entrySet()) {
         qTree.setParameter(param.getKey(), param.getValue());
+        log.debug("Param {}:{}", param.getKey(), param.getValue());
+      }
+    } else if (StringUtils.isNotBlank(customSelectorWhereClause)) {
+      for (int i = 0; i < selectorParameters.size(); i++) {
+        qTree.setParameter(CustomQuerySelectorDatasource.ALIAS_PREFIX + Integer.toString(i),
+            selectorParameters.get(i));
+        log.debug("Param {}:{}", CustomQuerySelectorDatasource.ALIAS_PREFIX + Integer.toString(i)
+            + " ", selectorParameters.get(i));
       }
     } else if (addMissingNodes) {
       qTree.setParameterList("missingNodes", missingNodes);
@@ -220,7 +291,7 @@
       if (addMissingNodes && initialNumOfMissingNodes == missingNodes.size()) {
         log.warn("Could not find all missing nodes in product characteristics {}", missingNodes);
       } else {
-        JSONArray foundNodes = getAllNodes(parameters, parentGridEntity, productPath, allNodes,
+        JSONArray foundNodes = getAllNodes(parameters, dsIdentifier, productPath, allNodes,
             missingNodes, true);
         for (int i = 0; i < foundNodes.length(); i++) {
           responseData.put(foundNodes.get(i));
