package com.salesmanager.core.business.repositories.catalog.product; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import com.salesmanager.core.business.constants.Constants; import com.salesmanager.core.model.catalog.product.Product; import com.salesmanager.core.model.catalog.product.ProductCriteria; import com.salesmanager.core.model.catalog.product.ProductList; import com.salesmanager.core.model.catalog.product.attribute.AttributeCriteria; import com.salesmanager.core.model.merchant.MerchantStore; import com.salesmanager.core.model.reference.language.Language; import com.salesmanager.core.model.tax.taxclass.TaxClass; public class ProductRepositoryImpl implements ProductRepositoryCustom { @PersistenceContext private EntityManager em; @Override public Product getById(Long productId) { try { StringBuilder qs = new StringBuilder(); qs.append("select distinct p from Product as p "); qs.append("join fetch p.availabilities pa "); qs.append("join fetch p.merchantStore merch "); qs.append("join fetch p.descriptions pd "); qs.append("left join fetch p.categories categs "); qs.append("left join fetch pa.prices pap "); qs.append("left join fetch pap.descriptions papd "); qs.append("left join fetch categs.descriptions categsd "); //images qs.append("left join fetch p.images images "); //options qs.append("left join fetch p.attributes pattr "); qs.append("left join fetch pattr.productOption po "); qs.append("left join fetch po.descriptions pod "); qs.append("left join fetch pattr.productOptionValue pov "); qs.append("left join fetch pov.descriptions povd "); qs.append("left join fetch p.relationships pr "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); qs.append("where p.id=:pid"); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("pid", productId); Product p = (Product)q.getSingleResult(); return p; } catch(javax.persistence.NoResultException ers) { return null; } } @Override public Product getByCode(String productCode, Language language) { try { StringBuilder qs = new StringBuilder(); qs.append("select distinct p from Product as p "); qs.append("join fetch p.availabilities pa "); qs.append("join fetch p.descriptions pd "); qs.append("join fetch p.merchantStore pm "); qs.append("left join fetch pa.prices pap "); qs.append("left join fetch pap.descriptions papd "); //images qs.append("left join fetch p.images images "); //options qs.append("left join fetch p.attributes pattr "); qs.append("left join fetch pattr.productOption po "); qs.append("left join fetch po.descriptions pod "); qs.append("left join fetch pattr.productOptionValue pov "); qs.append("left join fetch pov.descriptions povd "); qs.append("left join fetch p.relationships pr "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); qs.append("where p.sku=:code "); qs.append("and pd.language.id=:lang and papd.language.id=:lang"); //this cannot be done on child elements from left join //qs.append("and pod.languageId=:lang and povd.languageId=:lang"); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("code", productCode); q.setParameter("lang", language.getId()); Product p = (Product)q.getSingleResult(); return p; } catch(javax.persistence.NoResultException ers) { return null; } } public Product getByFriendlyUrl(MerchantStore store,String seUrl, Locale locale) { List regionList = new ArrayList(); regionList.add("*"); regionList.add(locale.getCountry()); StringBuilder qs = new StringBuilder(); qs.append("select distinct p from Product as p "); qs.append("join fetch p.availabilities pa "); qs.append("join fetch p.descriptions pd "); qs.append("join fetch p.merchantStore pm "); qs.append("left join fetch pa.prices pap "); qs.append("left join fetch pap.descriptions papd "); //images qs.append("left join fetch p.images images "); //options qs.append("left join fetch p.attributes pattr "); qs.append("left join fetch pattr.productOption po "); qs.append("left join fetch po.descriptions pod "); qs.append("left join fetch pattr.productOptionValue pov "); qs.append("left join fetch pov.descriptions povd "); qs.append("left join fetch p.relationships pr "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); qs.append("where pa.region in (:lid) "); qs.append("and pd.seUrl=:seUrl "); qs.append("and p.available=true and p.dateAvailable<=:dt "); qs.append("order by pattr.productOptionSortOrder "); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("lid", regionList); q.setParameter("dt", new Date()); q.setParameter("seUrl", seUrl); Product p = null; try { p = (Product)q.getSingleResult(); } catch(javax.persistence.NoResultException ignore) { } return p; } @Override public List<Product> getProductsForLocale(MerchantStore store, Set<Long> categoryIds, Language language, Locale locale) { ProductList products = this.getProductsListForLocale(store, categoryIds, language, locale, 0, -1); return products.getProducts(); } @Override public Product getProductForLocale(long productId, Language language, Locale locale) { List regionList = new ArrayList(); regionList.add("*"); regionList.add(locale.getCountry()); StringBuilder qs = new StringBuilder(); qs.append("select distinct p from Product as p "); qs.append("join fetch p.availabilities pa "); qs.append("join fetch p.descriptions pd "); qs.append("join fetch p.merchantStore pm "); qs.append("left join fetch pa.prices pap "); qs.append("left join fetch pap.descriptions papd "); //images qs.append("left join fetch p.images images "); //options qs.append("left join fetch p.attributes pattr "); qs.append("left join fetch pattr.productOption po "); qs.append("left join fetch po.descriptions pod "); qs.append("left join fetch pattr.productOptionValue pov "); qs.append("left join fetch pov.descriptions povd "); qs.append("left join fetch p.relationships pr "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); qs.append("where p.id=:pid and pa.region in (:lid) "); qs.append("and pd.language.id=:lang and papd.language.id=:lang "); qs.append("and p.available=true and p.dateAvailable<=:dt "); //this cannot be done on child elements from left join //qs.append("and pod.languageId=:lang and povd.languageId=:lang"); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("pid", productId); q.setParameter("lid", regionList); q.setParameter("dt", new Date()); q.setParameter("lang", language.getId()); Product p = (Product)q.getSingleResult(); return p; } @SuppressWarnings("rawtypes") @Override public List<Product> getProductsListByCategories(Set categoryIds) { //List regionList = new ArrayList(); //regionList.add("*"); //regionList.add(locale.getCountry()); //TODO Test performance /** * Testing in debug mode takes a long time with this query * running in normal mode is fine */ StringBuilder qs = new StringBuilder(); qs.append("select distinct p from Product as p "); qs.append("join fetch p.merchantStore merch "); qs.append("join fetch p.availabilities pa "); qs.append("left join fetch pa.prices pap "); qs.append("join fetch p.descriptions pd "); qs.append("join fetch p.categories categs "); qs.append("left join fetch pap.descriptions papd "); //images qs.append("left join fetch p.images images "); //options (do not need attributes for listings) qs.append("left join fetch p.attributes pattr "); qs.append("left join fetch pattr.productOption po "); qs.append("left join fetch po.descriptions pod "); qs.append("left join fetch pattr.productOptionValue pov "); qs.append("left join fetch pov.descriptions povd "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); //qs.append("where pa.region in (:lid) "); qs.append("where categs.id in (:cid)"); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("cid", categoryIds); @SuppressWarnings("unchecked") List<Product> products = q.getResultList(); return products; } @Override public List<Product> getProductsListByCategories(Set<Long> categoryIds, Language language) { //List regionList = new ArrayList(); //regionList.add("*"); //regionList.add(locale.getCountry()); //TODO Test performance /** * Testing in debug mode takes a long time with this query * running in normal mode is fine */ StringBuilder qs = new StringBuilder(); qs.append("select distinct p from Product as p "); qs.append("join fetch p.merchantStore merch "); qs.append("join fetch p.availabilities pa "); qs.append("left join fetch pa.prices pap "); qs.append("join fetch p.descriptions pd "); qs.append("join fetch p.categories categs "); qs.append("left join fetch pap.descriptions papd "); //images qs.append("left join fetch p.images images "); //options (do not need attributes for listings) qs.append("left join fetch p.attributes pattr "); qs.append("left join fetch pattr.productOption po "); qs.append("left join fetch po.descriptions pod "); qs.append("left join fetch pattr.productOptionValue pov "); qs.append("left join fetch pov.descriptions povd "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); //qs.append("where pa.region in (:lid) "); qs.append("where categs.id in (:cid) "); //qs.append("and pd.language.id=:lang and papd.language.id=:lang and manufd.language.id=:lang "); qs.append("and pd.language.id=:lang and papd.language.id=:lang "); qs.append("and p.available=true and p.dateAvailable<=:dt "); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("cid", categoryIds); q.setParameter("lang", language.getId()); q.setParameter("dt", new Date()); @SuppressWarnings("unchecked") List<Product> products = q.getResultList(); return products; } /** * This query is used for category listings. All collections are not fully loaded, only the required objects * so the listing page can display everything related to all products */ @SuppressWarnings({ "rawtypes", "unchecked", "unused" }) private ProductList getProductsListForLocale(MerchantStore store, Set categoryIds, Language language, Locale locale, int first, int max) { List regionList = new ArrayList(); regionList.add(Constants.ALL_REGIONS); if(locale!=null) { regionList.add(locale.getCountry()); } ProductList productList = new ProductList(); Query countQ = this.em.createQuery( "select count(p) from Product as p INNER JOIN p.availabilities pa INNER JOIN p.categories categs where p.merchantStore.id=:mId and categs.id in (:cid) and pa.region in (:lid) and p.available=1 and p.dateAvailable<=:dt"); //"select p from Product as p join fetch p.availabilities pa join fetch p.categories categs where categs.id in (:cid) and pa.region in (:lid) and p.available=1 and p.dateAvailable<=:dt"); countQ.setParameter("cid", categoryIds); countQ.setParameter("lid", regionList); countQ.setParameter("dt", new Date()); countQ.setParameter("mId", store.getId()); //List<Product> ps = countQ.getResultList(); Number count = (Number) countQ.getSingleResult (); productList.setTotalCount(count.intValue()); if(count.intValue()==0) return productList; StringBuilder qs = new StringBuilder(); qs.append("select p from Product as p "); qs.append("join fetch p.merchantStore merch "); qs.append("join fetch p.availabilities pa "); qs.append("left join fetch pa.prices pap "); qs.append("join fetch p.descriptions pd "); qs.append("join fetch p.categories categs "); //not necessary //qs.append("join fetch pap.descriptions papd "); //images qs.append("left join fetch p.images images "); //options (do not need attributes for listings) //qs.append("left join fetch p.attributes pattr "); //qs.append("left join fetch pattr.productOption po "); //qs.append("left join fetch po.descriptions pod "); //qs.append("left join fetch pattr.productOptionValue pov "); //qs.append("left join fetch pov.descriptions povd "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); //qs.append("where pa.region in (:lid) "); qs.append("where p.merchantStore.id=mId and categs.id in (:cid) and pa.region in (:lid) "); //qs.append("and p.available=true and p.dateAvailable<=:dt and pd.language.id=:lang and manufd.language.id=:lang"); qs.append("and p.available=true and p.dateAvailable<=:dt and pd.language.id=:lang"); qs.append(" order by p.sortOrder asc"); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("cid", categoryIds); q.setParameter("lid", regionList); q.setParameter("dt", new Date()); q.setParameter("lang", language.getId()); q.setParameter("mId", store.getId()); q.setFirstResult(first); if(max>0) { int maxCount = first + max; if(maxCount < count.intValue()) { q.setMaxResults(maxCount); } else { q.setMaxResults(count.intValue()); } } List<Product> products = q.getResultList(); productList.setProducts(products); return productList; } /** * Used for all purpose ! * @param store * @param first * @param max * @return */ @Override public ProductList listByStore(MerchantStore store, Language language, ProductCriteria criteria) { ProductList productList = new ProductList(); StringBuilder countBuilderSelect = new StringBuilder(); countBuilderSelect.append("select count(distinct p) from Product as p"); StringBuilder countBuilderWhere = new StringBuilder(); countBuilderWhere.append(" where p.merchantStore.id=:mId"); if(!CollectionUtils.isEmpty(criteria.getProductIds())) { countBuilderWhere.append(" and p.id in (:pId)"); } countBuilderSelect.append(" inner join p.descriptions pd"); countBuilderWhere.append(" and pd.language.id=:lang"); if(!StringUtils.isBlank(criteria.getProductName())) { countBuilderWhere.append(" and lower(pd.name) like:nm"); } if(!CollectionUtils.isEmpty(criteria.getCategoryIds())) { countBuilderSelect.append(" INNER JOIN p.categories categs"); countBuilderWhere.append(" and categs.id in (:cid)"); } if(criteria.getManufacturerId()!=null) { countBuilderSelect.append(" INNER JOIN p.manufacturer manuf"); countBuilderWhere.append(" and manuf.id = :manufid"); } if(!StringUtils.isBlank(criteria.getCode())) { countBuilderWhere.append(" and lower(p.sku) like :sku"); } if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) { countBuilderSelect.append(" INNER JOIN p.attributes pattr"); countBuilderSelect.append(" INNER JOIN pattr.productOption po"); countBuilderSelect.append(" INNER JOIN pattr.productOptionValue pov "); countBuilderSelect.append(" INNER JOIN pov.descriptions povd "); int count = 0; for(AttributeCriteria attributeCriteria : criteria.getAttributeCriteria()) { if(count==0) { countBuilderWhere.append(" and po.code =:").append(attributeCriteria.getAttributeCode()); countBuilderWhere.append(" and povd.description like :").append("val").append(count).append(attributeCriteria.getAttributeCode()); } count++; } countBuilderWhere.append(" and povd.language.id=:lang"); } if(criteria.getAvailable()!=null) { if(criteria.getAvailable().booleanValue()) { countBuilderWhere.append(" and p.available=true and p.dateAvailable<=:dt"); } else { countBuilderWhere.append(" and p.available=false or p.dateAvailable>:dt"); } } Query countQ = this.em.createQuery( countBuilderSelect.toString() + countBuilderWhere.toString()); countQ.setParameter("mId", store.getId()); if(!CollectionUtils.isEmpty(criteria.getCategoryIds())) { countQ.setParameter("cid", criteria.getCategoryIds()); } if(criteria.getAvailable()!=null) { countQ.setParameter("dt", new Date()); } if(!StringUtils.isBlank(criteria.getCode())) { countQ.setParameter("sku", new StringBuilder().append("%").append(criteria.getCode().toLowerCase()).append("%").toString()); } if(criteria.getManufacturerId()!=null) { countQ.setParameter("manufid", criteria.getManufacturerId()); } if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) { int count = 0; for(AttributeCriteria attributeCriteria : criteria.getAttributeCriteria()) { countQ.setParameter(attributeCriteria.getAttributeCode(),attributeCriteria.getAttributeCode()); countQ.setParameter("val" + count + attributeCriteria.getAttributeCode(),"%" + attributeCriteria.getAttributeValue() + "%"); count ++; } } countQ.setParameter("lang", language.getId()); if(!StringUtils.isBlank(criteria.getProductName())) { countQ.setParameter("nm", new StringBuilder().append("%").append(criteria.getProductName().toLowerCase()).append("%").toString()); } if(!CollectionUtils.isEmpty(criteria.getProductIds())) { countQ.setParameter("pId", criteria.getProductIds()); } Number count = (Number) countQ.getSingleResult (); productList.setTotalCount(count.intValue()); if(count.intValue()==0) return productList; StringBuilder qs = new StringBuilder(); qs.append("select distinct p from Product as p "); qs.append("join fetch p.merchantStore merch "); qs.append("join fetch p.availabilities pa "); qs.append("left join fetch pa.prices pap "); qs.append("join fetch p.descriptions pd "); qs.append("left join fetch p.categories categs "); //images qs.append("left join fetch p.images images "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); //attributes if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) { qs.append(" inner join p.attributes pattr"); qs.append(" inner join pattr.productOption po"); qs.append(" inner join po.descriptions pod"); qs.append(" inner join pattr.productOptionValue pov "); qs.append(" inner join pov.descriptions povd"); } else { qs.append(" left join fetch p.attributes pattr"); qs.append(" left join fetch pattr.productOption po"); qs.append(" left join fetch po.descriptions pod"); qs.append(" left join fetch pattr.productOptionValue pov"); qs.append(" left join fetch pov.descriptions povd"); } qs.append(" left join fetch p.relationships pr"); qs.append(" where merch.id=:mId"); qs.append(" and pd.language.id=:lang"); if(!CollectionUtils.isEmpty(criteria.getProductIds())) { qs.append(" and p.id in (:pId)"); } if(!CollectionUtils.isEmpty(criteria.getCategoryIds())) { qs.append(" and categs.id in (:cid)"); } if(criteria.getManufacturerId()!=null) { qs.append(" and manuf.id = :manufid"); } if(criteria.getAvailable()!=null) { if(criteria.getAvailable().booleanValue()) { qs.append(" and p.available=true and p.dateAvailable<=:dt"); } else { qs.append(" and p.available=false and p.dateAvailable>:dt"); } } if(!StringUtils.isBlank(criteria.getProductName())) { qs.append(" and lower(pd.name) like :nm"); } if(!StringUtils.isBlank(criteria.getCode())) { qs.append(" and lower(p.sku) like :sku"); } if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) { int cnt = 0; for(AttributeCriteria attributeCriteria : criteria.getAttributeCriteria()) { qs.append(" and po.code =:").append(attributeCriteria.getAttributeCode()); qs.append(" and povd.description like :").append("val").append(cnt).append(attributeCriteria.getAttributeCode()); cnt++; } qs.append(" and povd.language.id=:lang"); } qs.append(" order by p.sortOrder asc"); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("lang", language.getId()); q.setParameter("mId", store.getId()); if(!CollectionUtils.isEmpty(criteria.getCategoryIds())) { q.setParameter("cid", criteria.getCategoryIds()); } if(!CollectionUtils.isEmpty(criteria.getProductIds())) { q.setParameter("pId", criteria.getProductIds()); } if(criteria.getAvailable()!=null) { q.setParameter("dt", new Date()); } if(criteria.getManufacturerId()!=null) { q.setParameter("manufid", criteria.getManufacturerId()); } if(!StringUtils.isBlank(criteria.getCode())) { q.setParameter("sku", new StringBuilder().append("%").append(criteria.getCode().toLowerCase()).append("%").toString()); } if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) { int cnt = 0; for(AttributeCriteria attributeCriteria : criteria.getAttributeCriteria()) { q.setParameter(attributeCriteria.getAttributeCode(),attributeCriteria.getAttributeCode()); q.setParameter("val" + cnt + attributeCriteria.getAttributeCode(),"%" + attributeCriteria.getAttributeValue() + "%"); cnt++; } } if(!StringUtils.isBlank(criteria.getProductName())) { q.setParameter("nm", new StringBuilder().append("%").append(criteria.getProductName().toLowerCase()).append("%").toString()); } if(criteria.getMaxCount()>0) { q.setFirstResult(criteria.getStartIndex()); if(criteria.getMaxCount()<count.intValue()) { q.setMaxResults(criteria.getMaxCount()); } else { q.setMaxResults(count.intValue()); } } @SuppressWarnings("unchecked") List<Product> products = q.getResultList(); productList.setProducts(products); return productList; } @Override public List<Product> listByStore(MerchantStore store) { /** * Testing in debug mode takes a long time with this query * running in normal mode is fine */ StringBuilder qs = new StringBuilder(); qs.append("select p from Product as p "); qs.append("join fetch p.merchantStore merch "); qs.append("join fetch p.availabilities pa "); qs.append("left join fetch pa.prices pap "); qs.append("join fetch p.descriptions pd "); qs.append("join fetch p.categories categs "); qs.append("left join fetch pap.descriptions papd "); //images qs.append("left join fetch p.images images "); //options (do not need attributes for listings) qs.append("left join fetch p.attributes pattr "); qs.append("left join fetch pattr.productOption po "); qs.append("left join fetch po.descriptions pod "); qs.append("left join fetch pattr.productOptionValue pov "); qs.append("left join fetch pov.descriptions povd "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); //qs.append("where pa.region in (:lid) "); qs.append("where merch.id=:mid"); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("mid", store.getId()); @SuppressWarnings("unchecked") List<Product> products = q.getResultList(); return products; } @Override public List<Product> listByTaxClass(TaxClass taxClass) { /** * Testing in debug mode takes a long time with this query * running in normal mode is fine */ StringBuilder qs = new StringBuilder(); qs.append("select p from Product as p "); qs.append("join fetch p.merchantStore merch "); qs.append("join fetch p.availabilities pa "); qs.append("left join fetch pa.prices pap "); qs.append("join fetch p.descriptions pd "); qs.append("join fetch p.categories categs "); qs.append("left join fetch pap.descriptions papd "); //images qs.append("left join fetch p.images images "); //options (do not need attributes for listings) qs.append("left join fetch p.attributes pattr "); qs.append("left join fetch pattr.productOption po "); qs.append("left join fetch po.descriptions pod "); qs.append("left join fetch pattr.productOptionValue pov "); qs.append("left join fetch pov.descriptions povd "); //other lefts qs.append("left join fetch p.manufacturer manuf "); qs.append("left join fetch manuf.descriptions manufd "); qs.append("left join fetch p.type type "); qs.append("left join fetch p.taxClass tx "); //qs.append("where pa.region in (:lid) "); qs.append("where tx.id=:tid"); String hql = qs.toString(); Query q = this.em.createQuery(hql); q.setParameter("tid", taxClass.getId()); @SuppressWarnings("unchecked") List<Product> products = q.getResultList(); return products; } }