public IQueryable <Product> PrepareQuery(CatalogSearchQuery searchQuery, IQueryable <Product> baseQuery = null)
 {
     return(GetProductQuery(searchQuery, baseQuery));
 }
        protected virtual IDictionary <string, FacetGroup> GetFacets(CatalogSearchQuery searchQuery, int totalHits)
        {
            var result     = new Dictionary <string, FacetGroup>();
            var storeId    = searchQuery.StoreId ?? _services.StoreContext.CurrentStore.Id;
            var languageId = searchQuery.LanguageId ?? _services.WorkContext.WorkingLanguage.Id;

            foreach (var key in searchQuery.FacetDescriptors.Keys)
            {
                var descriptor = searchQuery.FacetDescriptors[key];
                var facets     = new List <Facet>();
                var kind       = FacetGroup.GetKindByKey("Catalog", key);

                switch (kind)
                {
                case FacetGroupKind.Category:
                case FacetGroupKind.Brand:
                case FacetGroupKind.DeliveryTime:
                case FacetGroupKind.Rating:
                case FacetGroupKind.Price:
                    if (totalHits == 0 && !descriptor.Values.Any(x => x.IsSelected))
                    {
                        continue;
                    }
                    break;
                }

                if (kind == FacetGroupKind.Category)
                {
                    var categoryTree = _categoryService.GetCategoryTree(0, false, storeId);
                    var categories   = categoryTree.Flatten(false);

                    if (descriptor.MaxChoicesCount > 0)
                    {
                        categories = categories.Take(descriptor.MaxChoicesCount);
                    }

                    var nameQuery = _localizedPropertyRepository.TableUntracked
                                    .Where(x => x.LocaleKeyGroup == "Category" && x.LocaleKey == "Name" && x.LanguageId == languageId);
                    var names = nameQuery.ToList().ToDictionarySafe(x => x.EntityId, x => x.LocaleValue);

                    foreach (var category in categories)
                    {
                        names.TryGetValue(category.Id, out var label);

                        facets.Add(new Facet(new FacetValue(category.Id, IndexTypeCode.Int32)
                        {
                            IsSelected   = descriptor.Values.Any(x => x.IsSelected && x.Value.Equals(category.Id)),
                            Label        = label.HasValue() ? label : category.Name,
                            DisplayOrder = category.DisplayOrder
                        }));
                    }
                }
                else if (kind == FacetGroupKind.Brand)
                {
                    var manufacturers = _manufacturerService.GetAllManufacturers(null, storeId);
                    if (descriptor.MaxChoicesCount > 0)
                    {
                        manufacturers = manufacturers.Take(descriptor.MaxChoicesCount).ToList();
                    }

                    var nameQuery = _localizedPropertyRepository.TableUntracked
                                    .Where(x => x.LocaleKeyGroup == "Manufacturer" && x.LocaleKey == "Name" && x.LanguageId == languageId);
                    var names = nameQuery.ToList().ToDictionarySafe(x => x.EntityId, x => x.LocaleValue);

                    foreach (var manu in manufacturers)
                    {
                        names.TryGetValue(manu.Id, out var label);

                        facets.Add(new Facet(new FacetValue(manu.Id, IndexTypeCode.Int32)
                        {
                            IsSelected   = descriptor.Values.Any(x => x.IsSelected && x.Value.Equals(manu.Id)),
                            Label        = label.HasValue() ? label : manu.Name,
                            DisplayOrder = manu.DisplayOrder
                        }));
                    }
                }
                else if (kind == FacetGroupKind.DeliveryTime)
                {
                    var deliveryTimes = _deliveryTimeService.GetAllDeliveryTimes();
                    var nameQuery     = _localizedPropertyRepository.TableUntracked
                                        .Where(x => x.LocaleKeyGroup == "DeliveryTime" && x.LocaleKey == "Name" && x.LanguageId == languageId);
                    var names = nameQuery.ToList().ToDictionarySafe(x => x.EntityId, x => x.LocaleValue);

                    foreach (var deliveryTime in deliveryTimes)
                    {
                        if (descriptor.MaxChoicesCount > 0 && facets.Count >= descriptor.MaxChoicesCount)
                        {
                            break;
                        }

                        names.TryGetValue(deliveryTime.Id, out var label);

                        facets.Add(new Facet(new FacetValue(deliveryTime.Id, IndexTypeCode.Int32)
                        {
                            IsSelected   = descriptor.Values.Any(x => x.IsSelected && x.Value.Equals(deliveryTime.Id)),
                            Label        = label.HasValue() ? label : deliveryTime.Name,
                            DisplayOrder = deliveryTime.DisplayOrder
                        }));
                    }
                }
                else if (kind == FacetGroupKind.Price)
                {
                    var count = 0;
                    var hasActivePredefinedFacet = false;
                    var minPrice = _productRepository.Table.Where(x => x.Published && !x.Deleted && !x.IsSystemProduct).Min(x => (double)x.Price);
                    var maxPrice = _productRepository.Table.Where(x => x.Published && !x.Deleted && !x.IsSystemProduct).Max(x => (double)x.Price);
                    minPrice = FacetUtility.MakePriceEven(minPrice);
                    maxPrice = FacetUtility.MakePriceEven(maxPrice);

                    for (var i = 0; i < _priceThresholds.Length; ++i)
                    {
                        if (descriptor.MaxChoicesCount > 0 && facets.Count >= descriptor.MaxChoicesCount)
                        {
                            break;
                        }

                        var price = _priceThresholds[i];
                        if (price < minPrice)
                        {
                            continue;
                        }

                        if (price >= maxPrice)
                        {
                            i = int.MaxValue - 1;
                        }

                        var selected = descriptor.Values.Any(x => x.IsSelected && x.Value == null && x.UpperValue != null && (double)x.UpperValue == price);
                        if (selected)
                        {
                            hasActivePredefinedFacet = true;
                        }

                        facets.Add(new Facet(new FacetValue(null, price, IndexTypeCode.Double, false, true)
                        {
                            DisplayOrder = ++count,
                            IsSelected   = selected
                        }));
                    }

                    // Add facet for custom price range.
                    var priceDescriptorValue = descriptor.Values.FirstOrDefault();

                    var customPriceFacetValue = new FacetValue(
                        priceDescriptorValue != null && !hasActivePredefinedFacet ? priceDescriptorValue.Value : null,
                        priceDescriptorValue != null && !hasActivePredefinedFacet ? priceDescriptorValue.UpperValue : null,
                        IndexTypeCode.Double,
                        true,
                        true);

                    customPriceFacetValue.IsSelected = customPriceFacetValue.Value != null || customPriceFacetValue.UpperValue != null;

                    if (!(totalHits == 0 && !customPriceFacetValue.IsSelected))
                    {
                        facets.Insert(0, new Facet("custom", customPriceFacetValue));
                    }
                }
                else if (kind == FacetGroupKind.Rating)
                {
                    foreach (var rating in FacetUtility.GetRatings())
                    {
                        var newFacet = new Facet(rating);
                        newFacet.Value.IsSelected = descriptor.Values.Any(x => x.IsSelected && x.Value.Equals(rating.Value));
                        facets.Add(newFacet);
                    }
                }
                else if (kind == FacetGroupKind.Availability || kind == FacetGroupKind.NewArrivals)
                {
                    var value = descriptor.Values.FirstOrDefault();
                    if (value != null)
                    {
                        if (kind == FacetGroupKind.NewArrivals && totalHits == 0 && !value.IsSelected)
                        {
                            continue;
                        }

                        var newValue = value.Clone();
                        newValue.Value      = true;
                        newValue.TypeCode   = IndexTypeCode.Boolean;
                        newValue.IsRange    = false;
                        newValue.IsSelected = value.IsSelected;

                        facets.Add(new Facet(newValue));
                    }
                }

                if (facets.Any(x => x.Published))
                {
                    //facets.Each(x => $"{key} {x.Value.ToString()}".Dump());

                    result.Add(key, new FacetGroup(
                                   "Catalog",
                                   key,
                                   descriptor.Label,
                                   descriptor.IsMultiSelect,
                                   false,
                                   descriptor.DisplayOrder,
                                   facets.OrderBy(descriptor)));
                }
            }

            return(result);
        }
        protected virtual IQueryable <Product> ApplySearchTerm(IQueryable <Product> query, CatalogSearchQuery searchQuery, out bool isGroupingRequired)
        {
            isGroupingRequired = false;

            var term       = searchQuery.Term;
            var fields     = searchQuery.Fields;
            var languageId = searchQuery.LanguageId ?? 0;

            if (term.HasValue() && fields != null && fields.Length != 0 && fields.Any(x => x.HasValue()))
            {
                isGroupingRequired = true;

                // SearchMode.ExactMatch doesn't make sense here
                if (searchQuery.Mode == SearchMode.StartsWith)
                {
                    query =
                        from p in query
                        join lp in _localizedPropertyRepository.Table on p.Id equals lp.EntityId into plp
                        from lp in plp.DefaultIfEmpty()
                        where
                        (fields.Contains("name") && p.Name.StartsWith(term)) ||
                        (fields.Contains("sku") && p.Sku.StartsWith(term)) ||
                        (fields.Contains("shortdescription") && p.ShortDescription.StartsWith(term)) ||
                        (languageId != 0 && lp.LanguageId == languageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "Name" && lp.LocaleValue.StartsWith(term)) ||
                        (languageId != 0 && lp.LanguageId == languageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "ShortDescription" && lp.LocaleValue.StartsWith(term))
                        select p;
                }
                else
                {
                    query =
                        from p in query
                        join lp in _localizedPropertyRepository.Table on p.Id equals lp.EntityId into plp
                        from lp in plp.DefaultIfEmpty()
                        where
                        (fields.Contains("name") && p.Name.Contains(term)) ||
                        (fields.Contains("sku") && p.Sku.Contains(term)) ||
                        (fields.Contains("shortdescription") && p.ShortDescription.Contains(term)) ||
                        (languageId != 0 && lp.LanguageId == languageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "Name" && lp.LocaleValue.Contains(term)) ||
                        (languageId != 0 && lp.LanguageId == languageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "ShortDescription" && lp.LocaleValue.Contains(term))
                        select p;
                }
            }

            return(query);
        }
Example #4
0
        protected virtual IDictionary <string, FacetGroup> GetFacets(CatalogSearchQuery searchQuery, int totalHits)
        {
            var result     = new Dictionary <string, FacetGroup>();
            var languageId = searchQuery.LanguageId ?? _services.WorkContext.WorkingLanguage.Id;

            foreach (var key in searchQuery.FacetDescriptors.Keys)
            {
                var descriptor = searchQuery.FacetDescriptors[key];
                var facets     = new List <Facet>();
                var kind       = FacetGroup.GetKindByKey(key);

                if (kind == FacetGroupKind.Category)
                {
                    #region Category

                    // order by product count
                    var categoryQuery =
                        from c in _categoryRepository.TableUntracked
                        where !c.Deleted && c.Published
                        join pc in _productCategoryRepository.TableUntracked on c.Id equals pc.CategoryId into pcm
                        from pc in pcm.DefaultIfEmpty()
                        group c by c.Id into grp
                        orderby grp.Count() descending
                        select new
                    {
                        Id           = grp.FirstOrDefault().Id,
                        Name         = grp.FirstOrDefault().Name,
                        DisplayOrder = grp.FirstOrDefault().DisplayOrder
                    };

                    if (descriptor.MaxChoicesCount > 0)
                    {
                        categoryQuery = categoryQuery.Take(descriptor.MaxChoicesCount);
                    }

                    var categories = categoryQuery.ToList();

                    var nameQuery = _localizedPropertyRepository.TableUntracked
                                    .Where(x => x.LocaleKeyGroup == "Category" && x.LocaleKey == "Name" && x.LanguageId == languageId);

                    var names = nameQuery.ToList().ToDictionarySafe(x => x.EntityId, x => x.LocaleValue);

                    foreach (var category in categories)
                    {
                        var selected = descriptor.Values.Any(x => x.IsSelected && x.Value.Equals(category.Id));
                        if (totalHits == 0 && !selected)
                        {
                            continue;
                        }

                        string label = null;
                        names.TryGetValue(category.Id, out label);

                        facets.Add(new Facet(new FacetValue(category.Id, IndexTypeCode.Int32)
                        {
                            IsSelected   = selected,
                            Label        = label.HasValue() ? label : category.Name,
                            DisplayOrder = category.DisplayOrder
                        }));
                    }

                    #endregion
                }
                else if (kind == FacetGroupKind.Brand)
                {
                    #region Brand

                    // order by product count
                    var manufacturerQuery =
                        from m in _manufacturerRepository.TableUntracked
                        where !m.Deleted && m.Published
                        join pm in _productManufacturerRepository.TableUntracked on m.Id equals pm.ManufacturerId into pmm
                        from pm in pmm.DefaultIfEmpty()
                        group m by m.Id into grp
                        orderby grp.Count() descending
                        select new
                    {
                        Id           = grp.FirstOrDefault().Id,
                        Name         = grp.FirstOrDefault().Name,
                        DisplayOrder = grp.FirstOrDefault().DisplayOrder
                    };

                    if (descriptor.MaxChoicesCount > 0)
                    {
                        manufacturerQuery = manufacturerQuery.Take(descriptor.MaxChoicesCount);
                    }

                    var manufacturers = manufacturerQuery.ToList();

                    var nameQuery = _localizedPropertyRepository.TableUntracked
                                    .Where(x => x.LocaleKeyGroup == "Manufacturer" && x.LocaleKey == "Name" && x.LanguageId == languageId);

                    var names = nameQuery.ToList().ToDictionarySafe(x => x.EntityId, x => x.LocaleValue);

                    foreach (var manu in manufacturers)
                    {
                        var selected = descriptor.Values.Any(x => x.IsSelected && x.Value.Equals(manu.Id));
                        if (totalHits == 0 && !selected)
                        {
                            continue;
                        }

                        string label = null;
                        names.TryGetValue(manu.Id, out label);

                        facets.Add(new Facet(new FacetValue(manu.Id, IndexTypeCode.Int32)
                        {
                            IsSelected   = selected,
                            Label        = label.HasValue() ? label : manu.Name,
                            DisplayOrder = manu.DisplayOrder
                        }));
                    }

                    #endregion
                }
                else if (kind == FacetGroupKind.DeliveryTime)
                {
                    #region Delivery time

                    var deliveryTimes = _deliveryTimeService.GetAllDeliveryTimes();

                    var nameQuery = _localizedPropertyRepository.TableUntracked
                                    .Where(x => x.LocaleKeyGroup == "DeliveryTime" && x.LocaleKey == "Name" && x.LanguageId == languageId);

                    var names = nameQuery.ToList().ToDictionarySafe(x => x.EntityId, x => x.LocaleValue);

                    foreach (var deliveryTime in deliveryTimes)
                    {
                        if (descriptor.MaxChoicesCount > 0 && facets.Count >= descriptor.MaxChoicesCount)
                        {
                            break;
                        }

                        var selected = descriptor.Values.Any(x => x.IsSelected && x.Value.Equals(deliveryTime.Id));
                        if (totalHits == 0 && !selected)
                        {
                            continue;
                        }

                        string label = null;
                        names.TryGetValue(deliveryTime.Id, out label);

                        facets.Add(new Facet(new FacetValue(deliveryTime.Id, IndexTypeCode.Int32)
                        {
                            IsSelected   = selected,
                            Label        = label.HasValue() ? label : deliveryTime.Name,
                            DisplayOrder = deliveryTime.DisplayOrder
                        }));
                    }

                    #endregion
                }
                else if (kind == FacetGroupKind.Price)
                {
                    #region Price

                    var count = 0;
                    var hasActivePredefinedFacet = false;
                    var minPrice = _productRepository.Table.Where(x => !x.Deleted && x.Published).Min(x => (double)x.Price);
                    var maxPrice = _productRepository.Table.Where(x => !x.Deleted && x.Published).Max(x => (double)x.Price);
                    minPrice = FacetUtility.MakePriceEven(minPrice);
                    maxPrice = FacetUtility.MakePriceEven(maxPrice);

                    for (var i = 0; i < _priceThresholds.Length; ++i)
                    {
                        if (descriptor.MaxChoicesCount > 0 && facets.Count >= descriptor.MaxChoicesCount)
                        {
                            break;
                        }

                        var price = _priceThresholds[i];
                        if (price < minPrice)
                        {
                            continue;
                        }

                        if (price >= maxPrice)
                        {
                            i = int.MaxValue - 1;
                        }

                        var selected = descriptor.Values.Any(x => x.IsSelected && x.Value == null && x.UpperValue != null && (double)x.UpperValue == price);
                        if (totalHits == 0 && !selected)
                        {
                            continue;
                        }

                        if (selected)
                        {
                            hasActivePredefinedFacet = true;
                        }

                        facets.Add(new Facet(new FacetValue(null, price, IndexTypeCode.Double, false, true)
                        {
                            DisplayOrder = ++count,
                            IsSelected   = selected
                        }));
                    }

                    // Add facet for custom price range.
                    var priceDescriptorValue = descriptor.Values.FirstOrDefault();

                    var customPriceFacetValue = new FacetValue(
                        priceDescriptorValue != null && !hasActivePredefinedFacet ? priceDescriptorValue.Value : null,
                        priceDescriptorValue != null && !hasActivePredefinedFacet ? priceDescriptorValue.UpperValue : null,
                        IndexTypeCode.Double,
                        true,
                        true);

                    customPriceFacetValue.IsSelected = customPriceFacetValue.Value != null || customPriceFacetValue.UpperValue != null;

                    if (!(totalHits == 0 && !customPriceFacetValue.IsSelected))
                    {
                        facets.Insert(0, new Facet("custom", customPriceFacetValue));
                    }

                    #endregion
                }
                else if (kind == FacetGroupKind.Rating)
                {
                    if (totalHits == 0 && !descriptor.Values.Any(x => x.IsSelected))
                    {
                        continue;
                    }

                    foreach (var rating in FacetUtility.GetRatings())
                    {
                        var newFacet = new Facet(rating);
                        newFacet.Value.IsSelected = descriptor.Values.Any(x => x.IsSelected && x.Value.Equals(rating.Value));
                        facets.Add(newFacet);
                    }
                }
                else if (kind == FacetGroupKind.Availability || kind == FacetGroupKind.NewArrivals)
                {
                    var value = descriptor.Values.FirstOrDefault();
                    if (value != null && !(totalHits == 0 && !value.IsSelected))
                    {
                        var newValue = value.Clone();
                        newValue.Value      = true;
                        newValue.TypeCode   = IndexTypeCode.Boolean;
                        newValue.IsRange    = false;
                        newValue.IsSelected = value.IsSelected;

                        facets.Add(new Facet(newValue));
                    }
                }

                if (facets.Any(x => x.Published))
                {
                    //facets.Each(x => $"{key} {x.Value.ToString()}".Dump());

                    result.Add(key, new FacetGroup(
                                   key,
                                   descriptor.Label,
                                   descriptor.IsMultiSelect,
                                   descriptor.DisplayOrder,
                                   facets.OrderBy(descriptor)));
                }
            }

            return(result);
        }
        protected virtual IQueryable <Product> GetProductQuery(CatalogSearchQuery searchQuery, IQueryable <Product> baseQuery)
        {
            var ordered        = false;
            var utcNow         = DateTime.UtcNow;
            var categoryId     = 0;
            var manufacturerId = 0;
            var query          = baseQuery ?? _productRepository.Table;

            query = query.Where(x => !x.Deleted && !x.IsSystemProduct);
            query = ApplySearchTerm(query, searchQuery, out var isGroupingRequired);

            #region Filters

            var filters = new List <ISearchFilter>();
            FlattenFilters(searchQuery.Filters, filters);

            var productIds = GetIdList(filters, "id");
            if (productIds.Any())
            {
                query = query.Where(x => productIds.Contains(x.Id));
            }

            var categoryIds = GetIdList(filters, "categoryid");
            if (categoryIds.Any())
            {
                isGroupingRequired = true;
                categoryId         = categoryIds.First();
                if (categoryIds.Count == 1 && categoryId == 0)
                {
                    // Has no category.
                    query = query.Where(x => x.ProductCategories.Count == 0);
                }
                else
                {
                    query = QueryCategories(query, categoryIds, null);
                }
            }

            var featuredCategoryIds    = GetIdList(filters, "featuredcategoryid");
            var notFeaturedCategoryIds = GetIdList(filters, "notfeaturedcategoryid");
            if (featuredCategoryIds.Any())
            {
                isGroupingRequired = true;
                categoryId         = categoryId == 0 ? featuredCategoryIds.First() : categoryId;
                query = QueryCategories(query, featuredCategoryIds, true);
            }
            if (notFeaturedCategoryIds.Any())
            {
                isGroupingRequired = true;
                categoryId         = categoryId == 0 ? notFeaturedCategoryIds.First() : categoryId;
                query = QueryCategories(query, notFeaturedCategoryIds, false);
            }

            var manufacturerIds = GetIdList(filters, "manufacturerid");
            if (manufacturerIds.Any())
            {
                isGroupingRequired = true;
                manufacturerId     = manufacturerIds.First();
                if (manufacturerIds.Count == 1 && manufacturerId == 0)
                {
                    // Has no manufacturer.
                    query = query.Where(x => x.ProductManufacturers.Count == 0);
                }
                else
                {
                    query = QueryManufacturers(query, manufacturerIds, null);
                }
            }

            var featuredManuIds    = GetIdList(filters, "featuredmanufacturerid");
            var notFeaturedManuIds = GetIdList(filters, "notfeaturedmanufacturerid");
            if (featuredManuIds.Any())
            {
                isGroupingRequired = true;
                manufacturerId     = manufacturerId == 0 ? featuredManuIds.First() : manufacturerId;
                query = QueryManufacturers(query, featuredManuIds, true);
            }
            if (notFeaturedManuIds.Any())
            {
                isGroupingRequired = true;
                manufacturerId     = manufacturerId == 0 ? notFeaturedManuIds.First() : manufacturerId;
                query = QueryManufacturers(query, notFeaturedManuIds, false);
            }

            var tagIds = GetIdList(filters, "tagid");
            if (tagIds.Any())
            {
                isGroupingRequired = true;
                query =
                    from p in query
                    from pt in p.ProductTags.Where(pt => tagIds.Contains(pt.Id))
                    select p;
            }

            if (!QuerySettings.IgnoreAcl)
            {
                var roleIds = GetIdList(filters, "roleid");
                if (roleIds.Any())
                {
                    isGroupingRequired = true;
                    query =
                        from p in query
                        join acl in _aclRepository.Table on new { pid = p.Id, pname = "Product" } equals new { pid = acl.EntityId, pname = acl.EntityName } into pacl
                    from acl in pacl.DefaultIfEmpty()
                    where !p.SubjectToAcl || roleIds.Contains(acl.CustomerRoleId)
                    select p;
                }
            }

            var deliverTimeIds = GetIdList(filters, "deliveryid");
            if (deliverTimeIds.Any())
            {
                query = query.Where(x => x.DeliveryTimeId != null && deliverTimeIds.Contains(x.DeliveryTimeId.Value));
            }

            var parentProductIds = GetIdList(filters, "parentid");
            if (parentProductIds.Any())
            {
                query = query.Where(x => parentProductIds.Contains(x.ParentGroupedProductId));
            }

            var conditions = GetIdList(filters, "condition");
            if (conditions.Any())
            {
                query = query.Where(x => conditions.Contains((int)x.Condition));
            }

            foreach (IAttributeSearchFilter filter in filters)
            {
                var rf = filter as IRangeSearchFilter;

                if (filter.FieldName == "id")
                {
                    if (rf != null)
                    {
                        var lower = filter.Term as int?;
                        var upper = rf.UpperTerm as int?;

                        if (lower.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => x.Id >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.Id > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rf.IncludesUpper)
                            {
                                query = query.Where(x => x.Id <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.Id < upper.Value);
                            }
                        }
                    }
                }
                else if (filter.FieldName == "categoryid")
                {
                    if (rf != null && 1 == ((filter.Term as int?) ?? 0) && int.MaxValue == ((rf.UpperTerm as int?) ?? 0))
                    {
                        isGroupingRequired = true;
                        // Has any category.
                        query = query.Where(x => x.ProductCategories.Count > 0);
                    }
                }
                else if (filter.FieldName == "manufacturerid")
                {
                    if (rf != null && 1 == ((filter.Term as int?) ?? 0) && int.MaxValue == ((rf.UpperTerm as int?) ?? 0))
                    {
                        isGroupingRequired = true;
                        // Has any manufacturer.
                        query = query.Where(x => x.ProductManufacturers.Count > 0);
                    }
                }
                else if (filter.FieldName == "published")
                {
                    query = query.Where(x => x.Published == (bool)filter.Term);
                }
                else if (filter.FieldName == "availablestart")
                {
                    if (rf != null)
                    {
                        var lower = filter.Term as DateTime?;
                        var upper = rf.UpperTerm as DateTime?;

                        if (lower.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => !x.AvailableStartDateTimeUtc.HasValue || x.AvailableStartDateTimeUtc >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => !x.AvailableStartDateTimeUtc.HasValue || x.AvailableStartDateTimeUtc > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => !x.AvailableStartDateTimeUtc.HasValue || x.AvailableStartDateTimeUtc <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => !x.AvailableStartDateTimeUtc.HasValue || x.AvailableStartDateTimeUtc < upper.Value);
                            }
                        }
                    }
                }
                else if (filter.FieldName == "availableend")
                {
                    if (rf != null)
                    {
                        var lower = filter.Term as DateTime?;
                        var upper = rf.UpperTerm as DateTime?;

                        if (lower.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => !x.AvailableEndDateTimeUtc.HasValue || x.AvailableEndDateTimeUtc >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => !x.AvailableEndDateTimeUtc.HasValue || x.AvailableEndDateTimeUtc > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => !x.AvailableEndDateTimeUtc.HasValue || x.AvailableEndDateTimeUtc <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => !x.AvailableEndDateTimeUtc.HasValue || x.AvailableEndDateTimeUtc < upper.Value);
                            }
                        }
                    }
                }
                else if (filter.FieldName == "visibility")
                {
                    var visibility = (ProductVisibility)filter.Term;
                    switch (visibility)
                    {
                    case ProductVisibility.SearchResults:
                        query = query.Where(x => x.Visibility <= visibility);
                        break;

                    default:
                        query = query.Where(x => x.Visibility == visibility);
                        break;
                    }
                }
                else if (filter.FieldName == "showonhomepage")
                {
                    query = query.Where(p => p.ShowOnHomePage == (bool)filter.Term);
                }
                else if (filter.FieldName == "download")
                {
                    query = query.Where(p => p.IsDownload == (bool)filter.Term);
                }
                else if (filter.FieldName == "recurring")
                {
                    query = query.Where(p => p.IsRecurring == (bool)filter.Term);
                }
                else if (filter.FieldName == "shipenabled")
                {
                    query = query.Where(p => p.IsShipEnabled == (bool)filter.Term);
                }
                else if (filter.FieldName == "shipfree")
                {
                    query = query.Where(p => p.IsFreeShipping == (bool)filter.Term);
                }
                else if (filter.FieldName == "taxexempt")
                {
                    query = query.Where(p => p.IsTaxExempt == (bool)filter.Term);
                }
                else if (filter.FieldName == "esd")
                {
                    query = query.Where(p => p.IsEsd == (bool)filter.Term);
                }
                else if (filter.FieldName == "discount")
                {
                    query = query.Where(p => p.HasDiscountsApplied == (bool)filter.Term);
                }
                else if (filter.FieldName == "typeid")
                {
                    query = query.Where(x => x.ProductTypeId == (int)filter.Term);
                }
                else if (filter.FieldName == "stockquantity")
                {
                    if (rf != null)
                    {
                        var lower = filter.Term as int?;
                        var upper = rf.UpperTerm as int?;

                        if (lower.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => x.StockQuantity >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.StockQuantity > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rf.IncludesUpper)
                            {
                                query = query.Where(x => x.StockQuantity <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.StockQuantity < upper.Value);
                            }
                        }
                    }
                    else
                    {
                        if (filter.Occurence == SearchFilterOccurence.MustNot)
                        {
                            query = query.Where(x => x.StockQuantity != (int)filter.Term);
                        }
                        else
                        {
                            query = query.Where(x => x.StockQuantity == (int)filter.Term);
                        }
                    }
                }
                else if (filter.FieldName == "rating")
                {
                    if (rf != null)
                    {
                        var lower = filter.Term as double?;
                        var upper = rf.UpperTerm as double?;

                        if (lower.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => x.ApprovedTotalReviews != 0 && ((double)x.ApprovedRatingSum / (double)x.ApprovedTotalReviews) >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.ApprovedTotalReviews != 0 && ((double)x.ApprovedRatingSum / (double)x.ApprovedTotalReviews) > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rf.IncludesUpper)
                            {
                                query = query.Where(x => x.ApprovedTotalReviews != 0 && ((double)x.ApprovedRatingSum / (double)x.ApprovedTotalReviews) <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.ApprovedTotalReviews != 0 && ((double)x.ApprovedRatingSum / (double)x.ApprovedTotalReviews) < upper.Value);
                            }
                        }
                    }
                    else
                    {
                        if (filter.Occurence == SearchFilterOccurence.MustNot)
                        {
                            query = query.Where(x => x.ApprovedTotalReviews != 0 && ((double)x.ApprovedRatingSum / (double)x.ApprovedTotalReviews) != (double)filter.Term);
                        }
                        else
                        {
                            query = query.Where(x => x.ApprovedTotalReviews != 0 && ((double)x.ApprovedRatingSum / (double)x.ApprovedTotalReviews) == (double)filter.Term);
                        }
                    }
                }
                else if (filter.FieldName == "available")
                {
                    query = query.Where(x =>
                                        x.ManageInventoryMethodId == (int)ManageInventoryMethod.DontManageStock ||
                                        (x.ManageInventoryMethodId == (int)ManageInventoryMethod.ManageStock && (x.StockQuantity > 0 || x.BackorderModeId != (int)BackorderMode.NoBackorders)) ||
                                        (x.ManageInventoryMethodId == (int)ManageInventoryMethod.ManageStockByAttributes && x.ProductVariantAttributeCombinations.Any(pvac => pvac.StockQuantity > 0 || pvac.AllowOutOfStockOrders))
                                        );
                }
                else if (filter.FieldName.StartsWith("price"))
                {
                    if (rf != null)
                    {
                        var lower = filter.Term as double?;
                        var upper = rf.UpperTerm as double?;

                        if (lower.HasValue)
                        {
                            var minPrice = Convert.ToDecimal(lower.Value);

                            query = query.Where(x =>
                                                ((x.SpecialPrice.HasValue &&
                                                  ((!x.SpecialPriceStartDateTimeUtc.HasValue || x.SpecialPriceStartDateTimeUtc.Value < utcNow) &&
                                                   (!x.SpecialPriceEndDateTimeUtc.HasValue || x.SpecialPriceEndDateTimeUtc.Value > utcNow))) &&
                                                 (x.SpecialPrice >= minPrice))
                                                ||
                                                ((!x.SpecialPrice.HasValue ||
                                                  ((x.SpecialPriceStartDateTimeUtc.HasValue && x.SpecialPriceStartDateTimeUtc.Value > utcNow) ||
                                                   (x.SpecialPriceEndDateTimeUtc.HasValue && x.SpecialPriceEndDateTimeUtc.Value < utcNow))) &&
                                                 (x.Price >= minPrice))
                                                );
                        }

                        if (upper.HasValue)
                        {
                            var maxPrice = Convert.ToDecimal(upper);

                            query = query.Where(x =>
                                                ((x.SpecialPrice.HasValue &&
                                                  ((!x.SpecialPriceStartDateTimeUtc.HasValue || x.SpecialPriceStartDateTimeUtc.Value < utcNow) &&
                                                   (!x.SpecialPriceEndDateTimeUtc.HasValue || x.SpecialPriceEndDateTimeUtc.Value > utcNow))) &&
                                                 (x.SpecialPrice <= maxPrice))
                                                ||
                                                ((!x.SpecialPrice.HasValue ||
                                                  ((x.SpecialPriceStartDateTimeUtc.HasValue && x.SpecialPriceStartDateTimeUtc.Value > utcNow) ||
                                                   (x.SpecialPriceEndDateTimeUtc.HasValue && x.SpecialPriceEndDateTimeUtc.Value < utcNow))) &&
                                                 (x.Price <= maxPrice))
                                                );
                        }
                    }
                    else
                    {
                        var price = Convert.ToDecimal(filter.Term);

                        if (filter.Occurence == SearchFilterOccurence.MustNot)
                        {
                            query = query.Where(x =>
                                                ((x.SpecialPrice.HasValue &&
                                                  ((!x.SpecialPriceStartDateTimeUtc.HasValue || x.SpecialPriceStartDateTimeUtc.Value < utcNow) &&
                                                   (!x.SpecialPriceEndDateTimeUtc.HasValue || x.SpecialPriceEndDateTimeUtc.Value > utcNow))) &&
                                                 (x.SpecialPrice != price))
                                                ||
                                                ((!x.SpecialPrice.HasValue ||
                                                  ((x.SpecialPriceStartDateTimeUtc.HasValue && x.SpecialPriceStartDateTimeUtc.Value > utcNow) ||
                                                   (x.SpecialPriceEndDateTimeUtc.HasValue && x.SpecialPriceEndDateTimeUtc.Value < utcNow))) &&
                                                 (x.Price != price))
                                                );
                        }
                        else
                        {
                            query = query.Where(x =>
                                                ((x.SpecialPrice.HasValue &&
                                                  ((!x.SpecialPriceStartDateTimeUtc.HasValue || x.SpecialPriceStartDateTimeUtc.Value < utcNow) &&
                                                   (!x.SpecialPriceEndDateTimeUtc.HasValue || x.SpecialPriceEndDateTimeUtc.Value > utcNow))) &&
                                                 (x.SpecialPrice == price))
                                                ||
                                                ((!x.SpecialPrice.HasValue ||
                                                  ((x.SpecialPriceStartDateTimeUtc.HasValue && x.SpecialPriceStartDateTimeUtc.Value > utcNow) ||
                                                   (x.SpecialPriceEndDateTimeUtc.HasValue && x.SpecialPriceEndDateTimeUtc.Value < utcNow))) &&
                                                 (x.Price == price))
                                                );
                        }
                    }
                }
                else if (filter.FieldName == "createdon")
                {
                    if (rf != null)
                    {
                        var lower = filter.Term as DateTime?;
                        var upper = rf.UpperTerm as DateTime?;

                        if (lower.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => x.CreatedOnUtc >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.CreatedOnUtc > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rf.IncludesLower)
                            {
                                query = query.Where(x => x.CreatedOnUtc <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.CreatedOnUtc < upper.Value);
                            }
                        }
                    }
                    else
                    {
                        if (filter.Occurence == SearchFilterOccurence.MustNot)
                        {
                            query = query.Where(x => x.CreatedOnUtc != (DateTime)filter.Term);
                        }
                        else
                        {
                            query = query.Where(x => x.CreatedOnUtc == (DateTime)filter.Term);
                        }
                    }
                }
                else if (filter.FieldName == "storeid")
                {
                    if (!QuerySettings.IgnoreMultiStore)
                    {
                        var storeId = (int)filter.Term;
                        if (storeId != 0)
                        {
                            isGroupingRequired = true;
                            query =
                                from p in query
                                join sm in _storeMappingRepository.Table on new { pid = p.Id, pname = "Product" } equals new { pid = sm.EntityId, pname = sm.EntityName } into psm
                            from sm in psm.DefaultIfEmpty()
                            where !p.LimitedToStores || sm.StoreId == storeId
                            select p;
                        }
                    }
                }
            }

            #endregion

            // Grouping is very slow if there are many products.
            if (isGroupingRequired)
            {
                query =
                    from p in query
                    group p by p.Id into grp
                    orderby grp.Key
                    select grp.FirstOrDefault();
            }

            #region Sorting

            foreach (var sort in searchQuery.Sorting)
            {
                if (sort.FieldName.IsEmpty())
                {
                    // Sort by relevance.
                    if (categoryId != 0)
                    {
                        query = OrderBy(ref ordered, query, x => x.ProductCategories.Where(pc => pc.CategoryId == categoryId).FirstOrDefault().DisplayOrder);
                    }
                    else if (manufacturerId != 0)
                    {
                        query = OrderBy(ref ordered, query, x => x.ProductManufacturers.Where(pm => pm.ManufacturerId == manufacturerId).FirstOrDefault().DisplayOrder);
                    }
                    else if (FindFilter(searchQuery.Filters, "parentid") != null)
                    {
                        query = OrderBy(ref ordered, query, x => x.DisplayOrder);
                    }
                    else
                    {
                        query = OrderBy(ref ordered, query, x => x.Name);
                    }
                }
                else if (sort.FieldName == "createdon")
                {
                    query = OrderBy(ref ordered, query, x => x.CreatedOnUtc, sort.Descending);
                }
                else if (sort.FieldName == "name")
                {
                    query = OrderBy(ref ordered, query, x => x.Name, sort.Descending);
                }
                else if (sort.FieldName == "price")
                {
                    query = OrderBy(ref ordered, query, x => x.Price, sort.Descending);
                }
                else
                {
                    query = OrderBy(ref ordered, query, x => x.Name);
                }
            }

            if (!ordered)
            {
                if (FindFilter(searchQuery.Filters, "parentid") != null)
                {
                    query = query.OrderBy(x => x.DisplayOrder);
                }
                else
                {
                    query = query.OrderBy(x => x.Id);
                }
            }

            #endregion

            return(query);
        }
Example #6
0
        protected virtual IQueryable <Product> GetProductQuery(CatalogSearchQuery searchQuery, IQueryable <Product> baseQuery)
        {
            var ordered = false;
            var utcNow  = DateTime.UtcNow;
            var query   = baseQuery ?? _productRepository.Table;

            query = query.Where(x => !x.Deleted);
            query = ApplySearchTerm(query, searchQuery);

            #region Filters

            var filters = new List <ISearchFilter>();
            FlattenFilters(searchQuery.Filters, filters);

            var productIds = GetIdList(filters, "id");
            if (productIds.Any())
            {
                query = query.Where(x => productIds.Contains(x.Id));
            }

            var categoryIds = GetIdList(filters, "categoryid");
            if (categoryIds.Any())
            {
                if (categoryIds.Count == 1 && categoryIds.First() == 0)
                {
                    // has no category
                    query = query.Where(x => x.ProductCategories.Count == 0);
                }
                else
                {
                    query = QueryCategories(query, categoryIds, null);
                }
            }

            query = QueryCategories(query, GetIdList(filters, "featuredcategoryid"), true);
            query = QueryCategories(query, GetIdList(filters, "notfeaturedcategoryid"), false);

            var manufacturerIds = GetIdList(filters, "manufacturerid");
            if (manufacturerIds.Any())
            {
                if (manufacturerIds.Count == 1 && manufacturerIds.First() == 0)
                {
                    // has no manufacturer
                    query = query.Where(x => x.ProductManufacturers.Count == 0);
                }
                else
                {
                    query = QueryManufacturers(query, manufacturerIds, null);
                }
            }

            query = QueryManufacturers(query, GetIdList(filters, "featuredmanufacturerid"), true);
            query = QueryManufacturers(query, GetIdList(filters, "notfeaturedmanufacturerid"), false);

            var tagIds = GetIdList(filters, "tagid");
            if (tagIds.Any())
            {
                query =
                    from p in query
                    from pt in p.ProductTags.Where(pt => tagIds.Contains(pt.Id))
                    select p;
            }

            if (!QuerySettings.IgnoreAcl)
            {
                var roleIds = GetIdList(filters, "roleid");
                if (roleIds.Any())
                {
                    query =
                        from p in query
                        join acl in _aclRepository.Table on new { pid = p.Id, pname = "Product" } equals new { pid = acl.EntityId, pname = acl.EntityName } into pacl
                    from acl in pacl.DefaultIfEmpty()
                    where !p.SubjectToAcl || roleIds.Contains(acl.CustomerRoleId)
                    select p;
                }
            }

            var deliverTimeIds = GetIdList(filters, "deliveryid");
            if (deliverTimeIds.Any())
            {
                query = query.Where(x => x.DeliveryTimeId != null && deliverTimeIds.Contains(x.DeliveryTimeId.Value));
            }

            var parentProductIds = GetIdList(filters, "parentid");
            if (parentProductIds.Any())
            {
                query = query.Where(x => parentProductIds.Contains(x.ParentGroupedProductId));
            }

            foreach (IAttributeSearchFilter filter in filters)
            {
                var rangeFilter = filter as IRangeSearchFilter;

                if (filter.FieldName == "id")
                {
                    if (rangeFilter != null)
                    {
                        var lower = filter.Term as int?;
                        var upper = rangeFilter.UpperTerm as int?;

                        if (lower.HasValue)
                        {
                            if (rangeFilter.IncludesLower)
                            {
                                query = query.Where(x => x.Id >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.Id > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rangeFilter.IncludesUpper)
                            {
                                query = query.Where(x => x.Id <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.Id < upper.Value);
                            }
                        }
                    }
                }
                else if (filter.FieldName == "categoryid")
                {
                    if (rangeFilter != null && 1 == ((filter.Term as int?) ?? 0) && int.MaxValue == ((rangeFilter.UpperTerm as int?) ?? 0))
                    {
                        // has any category
                        query = query.Where(x => x.ProductCategories.Count > 0);
                    }
                }
                else if (filter.FieldName == "manufacturerid")
                {
                    if (rangeFilter != null && 1 == ((filter.Term as int?) ?? 0) && int.MaxValue == ((rangeFilter.UpperTerm as int?) ?? 0))
                    {
                        // has any manufacturer
                        query = query.Where(x => x.ProductManufacturers.Count > 0);
                    }
                }
                else if (filter.FieldName == "published")
                {
                    query = query.Where(x => x.Published == (bool)filter.Term);
                }
                else if (filter.FieldName == "availablestart")
                {
                    if (rangeFilter != null)
                    {
                        var lower = filter.Term as DateTime?;
                        var upper = rangeFilter.UpperTerm as DateTime?;

                        if (lower.HasValue)
                        {
                            if (rangeFilter.IncludesLower)
                            {
                                query = query.Where(x => !x.AvailableStartDateTimeUtc.HasValue || x.AvailableStartDateTimeUtc >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => !x.AvailableStartDateTimeUtc.HasValue || x.AvailableStartDateTimeUtc > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rangeFilter.IncludesLower)
                            {
                                query = query.Where(x => !x.AvailableStartDateTimeUtc.HasValue || x.AvailableStartDateTimeUtc <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => !x.AvailableStartDateTimeUtc.HasValue || x.AvailableStartDateTimeUtc < upper.Value);
                            }
                        }
                    }
                }
                else if (filter.FieldName == "availableend")
                {
                    if (rangeFilter != null)
                    {
                        var lower = filter.Term as DateTime?;
                        var upper = rangeFilter.UpperTerm as DateTime?;

                        if (lower.HasValue)
                        {
                            if (rangeFilter.IncludesLower)
                            {
                                query = query.Where(x => !x.AvailableEndDateTimeUtc.HasValue || x.AvailableEndDateTimeUtc >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => !x.AvailableEndDateTimeUtc.HasValue || x.AvailableEndDateTimeUtc > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rangeFilter.IncludesLower)
                            {
                                query = query.Where(x => !x.AvailableEndDateTimeUtc.HasValue || x.AvailableEndDateTimeUtc <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => !x.AvailableEndDateTimeUtc.HasValue || x.AvailableEndDateTimeUtc < upper.Value);
                            }
                        }
                    }
                }
                else if (filter.FieldName == "visibleindividually")
                {
                    query = query.Where(x => x.VisibleIndividually == (bool)filter.Term);
                }
                else if (filter.FieldName == "showonhomepage")
                {
                    query = query.Where(p => p.ShowOnHomePage == (bool)filter.Term);
                }
                else if (filter.FieldName == "typeid")
                {
                    query = query.Where(x => x.ProductTypeId == (int)filter.Term);
                }
                else if (filter.FieldName == "stockquantity")
                {
                    if (rangeFilter != null)
                    {
                        var lower = filter.Term as int?;
                        var upper = rangeFilter.UpperTerm as int?;

                        if (lower.HasValue)
                        {
                            if (rangeFilter.IncludesLower)
                            {
                                query = query.Where(x => x.StockQuantity >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.StockQuantity > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rangeFilter.IncludesUpper)
                            {
                                query = query.Where(x => x.StockQuantity <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.StockQuantity < upper.Value);
                            }
                        }
                    }
                }
                else if (filter.FieldName == "rating")
                {
                    query = query.Where(x => x.ApprovedTotalReviews != 0 && ((double)x.ApprovedRatingSum / (double)x.ApprovedTotalReviews) >= (double)filter.Term);
                }
                else if (filter.FieldName == "available")
                {
                    query = query.Where(x => !(
                                            x.StockQuantity <= 0 && x.BackorderModeId == (int)BackorderMode.NoBackorders &&
                                            (x.ManageInventoryMethodId == (int)ManageInventoryMethod.ManageStock || x.ManageInventoryMethodId == (int)ManageInventoryMethod.ManageStockByAttributes)
                                            ));
                }
                else if (filter.FieldName.StartsWith("price"))
                {
                    if (rangeFilter != null)
                    {
                        var lower = filter.Term as double?;
                        var upper = rangeFilter.UpperTerm as double?;

                        if (lower.HasValue)
                        {
                            var minPrice = Convert.ToDecimal(lower.Value);

                            query = query.Where(x =>
                                                ((x.SpecialPrice.HasValue &&
                                                  ((!x.SpecialPriceStartDateTimeUtc.HasValue || x.SpecialPriceStartDateTimeUtc.Value < utcNow) &&
                                                   (!x.SpecialPriceEndDateTimeUtc.HasValue || x.SpecialPriceEndDateTimeUtc.Value > utcNow))) &&
                                                 (x.SpecialPrice >= minPrice))
                                                ||
                                                ((!x.SpecialPrice.HasValue ||
                                                  ((x.SpecialPriceStartDateTimeUtc.HasValue && x.SpecialPriceStartDateTimeUtc.Value > utcNow) ||
                                                   (x.SpecialPriceEndDateTimeUtc.HasValue && x.SpecialPriceEndDateTimeUtc.Value < utcNow))) &&
                                                 (x.Price >= minPrice))
                                                );
                        }

                        if (upper.HasValue)
                        {
                            var maxPrice = Convert.ToDecimal(upper);

                            query = query.Where(x =>
                                                ((x.SpecialPrice.HasValue &&
                                                  ((!x.SpecialPriceStartDateTimeUtc.HasValue || x.SpecialPriceStartDateTimeUtc.Value < utcNow) &&
                                                   (!x.SpecialPriceEndDateTimeUtc.HasValue || x.SpecialPriceEndDateTimeUtc.Value > utcNow))) &&
                                                 (x.SpecialPrice <= maxPrice))
                                                ||
                                                ((!x.SpecialPrice.HasValue ||
                                                  ((x.SpecialPriceStartDateTimeUtc.HasValue && x.SpecialPriceStartDateTimeUtc.Value > utcNow) ||
                                                   (x.SpecialPriceEndDateTimeUtc.HasValue && x.SpecialPriceEndDateTimeUtc.Value < utcNow))) &&
                                                 (x.Price <= maxPrice))
                                                );
                        }
                    }
                }
                else if (filter.FieldName == "createdon")
                {
                    if (rangeFilter != null)
                    {
                        var lower = filter.Term as DateTime?;
                        var upper = rangeFilter.UpperTerm as DateTime?;

                        if (lower.HasValue)
                        {
                            if (rangeFilter.IncludesLower)
                            {
                                query = query.Where(x => x.CreatedOnUtc >= lower.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.CreatedOnUtc > lower.Value);
                            }
                        }

                        if (upper.HasValue)
                        {
                            if (rangeFilter.IncludesLower)
                            {
                                query = query.Where(x => x.CreatedOnUtc <= upper.Value);
                            }
                            else
                            {
                                query = query.Where(x => x.CreatedOnUtc < upper.Value);
                            }
                        }
                    }
                }
                else if (filter.FieldName == "storeid")
                {
                    if (!QuerySettings.IgnoreMultiStore)
                    {
                        var storeId = (int)filter.Term;
                        if (storeId != 0)
                        {
                            query =
                                from p in query
                                join sm in _storeMappingRepository.Table on new { pid = p.Id, pname = "Product" } equals new { pid = sm.EntityId, pname = sm.EntityName } into psm
                            from sm in psm.DefaultIfEmpty()
                            where !p.LimitedToStores || sm.StoreId == storeId
                            select p;
                        }
                    }
                }
            }

            #endregion

            query = query.GroupBy(x => x.Id).Select(x => x.FirstOrDefault());

            #region Sorting

            foreach (var sort in searchQuery.Sorting)
            {
                if (sort.FieldName.IsEmpty())
                {
                    // sort by relevance
                    if (categoryIds.Any())
                    {
                        var categoryId = categoryIds.First();
                        query = OrderBy(ref ordered, query, x => x.ProductCategories.Where(pc => pc.CategoryId == categoryId).FirstOrDefault().DisplayOrder);
                    }
                    else if (manufacturerIds.Any())
                    {
                        var manufacturerId = manufacturerIds.First();
                        query = OrderBy(ref ordered, query, x => x.ProductManufacturers.Where(pm => pm.ManufacturerId == manufacturerId).FirstOrDefault().DisplayOrder);
                    }
                    else if (searchQuery.Filters.OfType <IAttributeSearchFilter>().Any(x => x.FieldName == "parentid"))
                    {
                        query = OrderBy(ref ordered, query, x => x.DisplayOrder);
                    }
                    else
                    {
                        query = OrderBy(ref ordered, query, x => x.Name);
                    }
                }
                else if (sort.FieldName == "createdon")
                {
                    query = OrderBy(ref ordered, query, x => x.CreatedOnUtc, sort.Descending);
                }
                else if (sort.FieldName == "name")
                {
                    query = OrderBy(ref ordered, query, x => x.Name, sort.Descending);
                }
                else if (sort.FieldName == "price")
                {
                    query = OrderBy(ref ordered, query, x => x.Price, sort.Descending);
                }
                else
                {
                    query = OrderBy(ref ordered, query, x => x.Name);
                }
            }

            if (!ordered)
            {
                query = query.OrderBy(x => x.Id);
            }

            #endregion

            return(query);
        }
 /// <summary>
 /// Constructor for an instance without any search hits
 /// </summary>
 /// <param name="query">Catalog search query</param>
 public CatalogSearchResult(CatalogSearchQuery query)
     : this(null, query, 0, () => new List <Product>(), null, null)
 {
 }
        public IQueryable <Product> PrepareQuery(CatalogSearchQuery searchQuery, IQueryable <Product> baseQuery = null)
        {
            var linqCatalogSearchService = _services.Container.ResolveNamed <ICatalogSearchService>("linq");

            return(linqCatalogSearchService.PrepareQuery(searchQuery, baseQuery));
        }
        public CatalogSearchResult Search(
            CatalogSearchQuery searchQuery,
            ProductLoadFlags loadFlags = ProductLoadFlags.None,
            bool direct = false)
        {
            Guard.NotNull(searchQuery, nameof(searchQuery));
            Guard.NotNegative(searchQuery.Take, nameof(searchQuery.Take));

            var provider = _indexManager.GetIndexProvider("Catalog");

            if (!direct && provider != null)
            {
                var indexStore = provider.GetIndexStore("Catalog");
                if (indexStore.Exists)
                {
                    var searchEngine = provider.GetSearchEngine(indexStore, searchQuery);
                    var stepPrefix   = searchEngine.GetType().Name + " - ";

                    int      totalCount = 0;
                    string[] spellCheckerSuggestions = null;
                    IEnumerable <ISearchHit>         searchHits;
                    Func <IList <Product> >          hitsFactory = null;
                    IDictionary <string, FacetGroup> facets      = null;

                    _services.EventPublisher.Publish(new CatalogSearchingEvent(searchQuery, false));

                    if (searchQuery.Take > 0)
                    {
                        using (_services.Chronometer.Step(stepPrefix + "Search"))
                        {
                            totalCount = searchEngine.Count();
                            // Fix paging boundaries
                            if (searchQuery.Skip > 0 && searchQuery.Skip >= totalCount)
                            {
                                searchQuery.Slice((totalCount / searchQuery.Take) * searchQuery.Take, searchQuery.Take);
                            }
                        }

                        if (searchQuery.ResultFlags.HasFlag(SearchResultFlags.WithHits))
                        {
                            using (_services.Chronometer.Step(stepPrefix + "Hits"))
                            {
                                searchHits = searchEngine.Search();
                            }

                            using (_services.Chronometer.Step(stepPrefix + "Collect"))
                            {
                                var productIds = searchHits.Select(x => x.EntityId).ToArray();
                                hitsFactory = () => _productService.Value.GetProductsByIds(productIds, loadFlags);
                            }
                        }

                        if (searchQuery.ResultFlags.HasFlag(SearchResultFlags.WithFacets))
                        {
                            try
                            {
                                using (_services.Chronometer.Step(stepPrefix + "Facets"))
                                {
                                    facets = searchEngine.GetFacetMap();
                                    ApplyFacetLabels(facets);
                                }
                            }
                            catch (Exception ex)
                            {
                                _logger.Error(ex);
                            }
                        }
                    }

                    if (searchQuery.ResultFlags.HasFlag(SearchResultFlags.WithSuggestions))
                    {
                        try
                        {
                            using (_services.Chronometer.Step(stepPrefix + "Spellcheck"))
                            {
                                spellCheckerSuggestions = searchEngine.CheckSpelling();
                            }
                        }
                        catch (Exception ex)
                        {
                            // Spell checking should not break the search.
                            _logger.Error(ex);
                        }
                    }

                    var result = new CatalogSearchResult(
                        searchEngine,
                        searchQuery,
                        totalCount,
                        hitsFactory,
                        spellCheckerSuggestions,
                        facets);

                    var searchedEvent = new CatalogSearchedEvent(searchQuery, result);
                    _services.EventPublisher.Publish(searchedEvent);

                    return(searchedEvent.Result);
                }
                else if (searchQuery.Origin.IsCaseInsensitiveEqual("Search/Search"))
                {
                    IndexingRequiredNotification(_services, _urlHelper);
                }
            }

            return(SearchDirect(searchQuery));
        }
Example #10
0
        public CatalogSearchingEvent(CatalogSearchQuery query)
        {
            Guard.NotNull(query, nameof(query));

            Query = query;
        }