public IHttpActionResult ListItemsSearch(coreModel.SearchCriteria searchCriteria)
        {
            ApplyRestrictionsForCurrentUser(searchCriteria);

            searchCriteria.WithHidden = true;
            //Need search in children categories if user specify keyword
            if (!string.IsNullOrEmpty(searchCriteria.Keyword))
            {
                searchCriteria.SearchInChildren   = true;
                searchCriteria.SearchInVariations = true;
            }
            var serviceResult = _searchService.Search(searchCriteria);

            var retVal = new webModel.ListEntrySearchResult();

            var start = searchCriteria.Skip;
            var count = searchCriteria.Take;

            // all categories
            var categories = serviceResult.Categories.Select(x => new webModel.ListEntryCategory(x.ToWebModel(_blobUrlResolver))).ToList();
            var products   = serviceResult.Products.Select(x => new webModel.ListEntryProduct(x.ToWebModel(_blobUrlResolver)));

            retVal.TotalCount = categories.Count() + serviceResult.ProductsTotalCount;
            retVal.ListEntries.AddRange(categories.Skip(start).Take(count));

            count -= categories.Count();

            retVal.ListEntries.AddRange(products.Take(count));

            return(Ok(retVal));
        }
        public IHttpActionResult Search(SearchCriteria criteria)
        {
            ApplyRestrictionsForCurrentUser(criteria);
            var serviceResult = _searchService.Search(criteria);

            return Ok(serviceResult.ToWebModel(_blobUrlResolver));
        }
예제 #3
0
        public IHttpActionResult SearchCategory(
            string store,
            string language           = "en-us",
            [FromUri] string parentId = null)
        {
            var catalog  = _storeService.GetById(store).Catalog;
            var criteria = new moduleModel.SearchCriteria
            {
                CatalogId  = catalog,
                CategoryId = parentId,
                Start      = 0,
                Count      = int.MaxValue,
                HideDirectLinedCategories = true,
                ResponseGroup             = moduleModel.ResponseGroup.WithCategories,
                GetAllCategories          = string.IsNullOrEmpty(parentId)
            };
            var result     = this._searchService.Search(criteria);
            var categories = result.Categories.Where(x => x.IsActive);

            return(this.Ok(
                       new webModel.ResponseCollection <webModel.Category>
            {
                TotalCount = categories.Count(),
                Items = categories.Select(x => x.ToWebModel()).ToList()
            }));
        }
예제 #4
0
        public static webModel.ListEntrySearchCriteria ToWebModel(this coreModel.SearchCriteria criteria)
        {
            var retVal = new webModel.ListEntrySearchCriteria();

            retVal.InjectFrom(criteria);
            retVal.ResponseGroup = (webModel.ResponseGroup)(int) criteria.ResponseGroup;
            return(retVal);
        }
예제 #5
0
		public static moduleModel.SearchCriteria ToModuleModel(this webModel.ListEntrySearchCriteria criteria)
		{
			var retVal = new moduleModel.SearchCriteria();
			retVal.InjectFrom(criteria);
			retVal.ResponseGroup = (moduleModel.ResponseGroup)(int)criteria.ResponseGroup;
			
			return retVal;
		}
        private void SearchCategories(SearchCriteria criteria, SearchResult result)
		{
			// TODO: optimize for performance, need to eliminate number of database queries
			// 1. Catalog should either be passed or loaded using caching
			// 2. Categories should be loaded by passing array of ids instead of parallel loading one by one
			using (var repository = _catalogRepositoryFactory())
			{
                var query = repository.Categories.Where(x => criteria.WithHidden ? true : x.IsActive);

                //Get list of search in categories
                var searchCategoryIds = criteria.CategoryIds;
                if (searchCategoryIds != null && searchCategoryIds.Any() && criteria.SearchInChildren)
                {
                    searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                }

                //Filter by keyword in all categories
                if (!string.IsNullOrEmpty(criteria.Keyword))
				{
					query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
				}
				else if (searchCategoryIds != null && searchCategoryIds.Any())
				{
                    if (criteria.HideDirectLinkedCategories)
                    {
                        query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategory.ParentCategoryId)));
                    }
                    else
                    {
                        query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategoryId)));
                    }
 				}
                else if (!string.IsNullOrEmpty(criteria.Code))
				{
					query = query.Where(x => x.Code == criteria.Code);
				}
                else if (criteria.CatalogIds != null)
                {
                    query = query.Where(x => (criteria.CatalogIds.Contains(x.CatalogId) && (x.ParentCategoryId == null || criteria.SearchInChildren)) || (x.OutgoingLinks.Any(y => y.TargetCategoryId == null && criteria.CatalogIds.Contains(y.TargetCatalogId))));

                }

                var categoryIds = query.Select(x => x.Id).ToArray();
                var categoryResponseGroup = CategoryResponseGroup.Info | CategoryResponseGroup.WithImages | CategoryResponseGroup.WithSeo | CategoryResponseGroup.WithLinks | CategoryResponseGroup.WithParents;
                if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties)
                {
                    categoryResponseGroup |= CategoryResponseGroup.WithProperties;
                }

                result.Categories = _categoryService.GetByIds(categoryIds, categoryResponseGroup)
                                                    .OrderByDescending(x => x.Priority)
                                                    .ThenBy(x => x.Name)
                                                    .ToList();
            
			}
		}
 public IHttpActionResult GetCatalogs()
 {
     var criteria = new moduleModel.SearchCriteria
     {
         ResponseGroup = moduleModel.ResponseGroup.WithCatalogs
     };
     var serviceResult = _searchService.Search(criteria);
     var retVal = serviceResult.Catalogs.Select(x => x.ToWebModel()).ToArray();
     return Ok(retVal);
 }
        public IHttpActionResult GetCatalogs()
        {
            var criteria = new moduleModel.SearchCriteria
            {
                ResponseGroup = moduleModel.ResponseGroup.WithCatalogs
            };
            var serviceResult = _searchService.Search(criteria);
            var retVal        = serviceResult.Catalogs.Select(x => x.ToWebModel()).ToArray();

            return(Ok(retVal));
        }
예제 #9
0
        public static coreModel.SearchCriteria ToCoreModel(this webModel.ListEntrySearchCriteria criteria)
        {
            var retVal = new coreModel.SearchCriteria();
            retVal.InjectFrom(criteria);
            retVal.Skip = criteria.Start;
            retVal.Take = criteria.Count;
            retVal.WithHidden = true;
            retVal.ResponseGroup = (coreModel.SearchResponseGroup)(int)criteria.ResponseGroup;

            return retVal;
        }
        public IHttpActionResult ListItemsSearch(coreModel.SearchCriteria searchCriteria)
        {
            ApplyRestrictionsForCurrentUser(searchCriteria);

            searchCriteria.WithHidden = true;
            //Need search in children categories if user specify keyword
            if (!string.IsNullOrEmpty(searchCriteria.Keyword))
            {
                searchCriteria.SearchInChildren   = true;
                searchCriteria.SearchInVariations = true;
            }

            var retVal = new webModel.ListEntrySearchResult();

            int categorySkip = 0;
            int categoryTake = 0;

            //Because products and categories represent in search result as two separated collections for handle paging request
            //we should join two resulting collection artificially
            //search categories
            if ((searchCriteria.ResponseGroup & coreModel.SearchResponseGroup.WithCategories) == coreModel.SearchResponseGroup.WithCategories)
            {
                searchCriteria.ResponseGroup = searchCriteria.ResponseGroup & ~coreModel.SearchResponseGroup.WithProducts;
                var categoriesSearchResult = _searchService.Search(searchCriteria);
                var categoriesTotalCount   = categoriesSearchResult.Categories.Count();

                categorySkip = Math.Min(categoriesTotalCount, searchCriteria.Skip);
                categoryTake = Math.Min(searchCriteria.Take, Math.Max(0, categoriesTotalCount - searchCriteria.Skip));
                var categories = categoriesSearchResult.Categories.Skip(categorySkip).Take(categoryTake).Select(x => new webModel.ListEntryCategory(x.ToWebModel(_blobUrlResolver))).ToList();

                retVal.TotalCount = categoriesTotalCount;
                retVal.ListEntries.AddRange(categories);

                searchCriteria.ResponseGroup = searchCriteria.ResponseGroup | coreModel.SearchResponseGroup.WithProducts;
            }

            //search products
            if ((searchCriteria.ResponseGroup & coreModel.SearchResponseGroup.WithProducts) == coreModel.SearchResponseGroup.WithProducts)
            {
                searchCriteria.ResponseGroup = searchCriteria.ResponseGroup & ~coreModel.SearchResponseGroup.WithCategories;
                searchCriteria.Skip          = searchCriteria.Skip - categorySkip;
                searchCriteria.Take          = searchCriteria.Take - categoryTake;
                var productsSearchResult = _searchService.Search(searchCriteria);

                var products = productsSearchResult.Products.Select(x => new webModel.ListEntryProduct(x.ToWebModel(_blobUrlResolver)));

                retVal.TotalCount += productsSearchResult.ProductsTotalCount;
                retVal.ListEntries.AddRange(products);
            }


            return(Ok(retVal));
        }
예제 #11
0
        public static coreModel.SearchCriteria ToCoreModel(this webModel.ListEntrySearchCriteria criteria)
        {
            var retVal = new coreModel.SearchCriteria();

            retVal.InjectFrom(criteria);
            retVal.Skip          = criteria.Start;
            retVal.Take          = criteria.Count;
            retVal.WithHidden    = true;
            retVal.ResponseGroup = (coreModel.SearchResponseGroup)(int) criteria.ResponseGroup;

            return(retVal);
        }
        private ListEntrySearchResult SearchProductsInCategories(string[] categoryIds, int skip, int take)
        {
            var searchCriteria = new SearchCriteria
            {
                CategoryIds        = categoryIds,
                Skip               = skip,
                Take               = take,
                ResponseGroup      = SearchResponseGroup.WithProducts,
                SearchInChildren   = true,
                SearchInVariations = true
            };

            var result = _listEntrySearchService.Search(searchCriteria);

            return(result);
        }
        /// <summary>
        /// Try to find (create if not) categories for products with Category.Path
        /// </summary>
        private void SaveCategoryTree(Catalog catalog, IEnumerable <CsvProduct> csvProducts, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback)
        {
            var cachedCategoryMap = new Dictionary <string, Category>();

            foreach (var csvProduct in csvProducts.Where(x => x.Category != null && !string.IsNullOrEmpty(x.Category.Path)))
            {
                var    outline = "";
                var    productCategoryNames = csvProduct.Category.Path.Split(_categoryDelimiters);
                string parentCategoryId     = null;
                foreach (var categoryName in productCategoryNames)
                {
                    outline += "\\" + categoryName;
                    Category category;
                    if (!cachedCategoryMap.TryGetValue(outline, out category))
                    {
                        var searchCriteria = new SearchCriteria
                        {
                            CatalogId     = catalog.Id,
                            CategoryId    = parentCategoryId,
                            ResponseGroup = SearchResponseGroup.WithCategories
                        };
                        category = _searchService.Search(searchCriteria).Categories.FirstOrDefault(x => x.Name == categoryName);
                    }

                    if (category == null)
                    {
                        var code = categoryName.GenerateSlug();
                        if (string.IsNullOrEmpty(code))
                        {
                            code = Guid.NewGuid().ToString("N");
                        }
                        category = _categoryService.Create(new Category()
                        {
                            Name = categoryName, Code = code, CatalogId = catalog.Id, ParentId = parentCategoryId
                        });
                        //Raise notification each notifyCategorySizeLimit category
                        var count = progressInfo.ProcessedCount;
                        progressInfo.Description = $"Creating categories: {++count} created";
                        progressCallback(progressInfo);
                    }
                    csvProduct.CategoryId      = category.Id;
                    csvProduct.Category        = category;
                    parentCategoryId           = category.Id;
                    cachedCategoryMap[outline] = category;
                }
            }
        }
 public IHttpActionResult GetCatalogs()
 {
     var criteria = new moduleModel.SearchCriteria
     {
         ResponseGroup = moduleModel.ResponseGroup.WithCatalogs
     };
     criteria = base.ChangeCriteriaToCurentUserPermissions(criteria);
     var serviceResult = _searchService.Search(criteria);
     var retVal = new List<webModel.Catalog>();
     foreach (var catalog in serviceResult.Catalogs)
     {
         var webCatalog = catalog.ToWebModel();
         webCatalog.SecurityScopes = base.GetObjectPermissionScopeStrings(catalog);
         retVal.Add(webCatalog);
     }
     return Ok(retVal.ToArray());
 }
예제 #15
0
 private void SearchCatalogs(coreModel.SearchCriteria criteria, coreModel.SearchResult result)
 {
     using (var repository = _catalogRepositoryFactory())
     {
         var catalogIds      = repository.Catalogs.Select(x => x.Id).ToArray();
         var catalogs        = new ConcurrentBag <coreModel.Catalog>();
         var parallelOptions = new ParallelOptions
         {
             MaxDegreeOfParallelism = 10
         };
         Parallel.ForEach(catalogIds, parallelOptions, (x) =>
         {
             var catalog = _catalogService.GetById(x);
             catalogs.Add(catalog);
         });
         result.Catalogs = catalogs.OrderByDescending(x => x.Name).ToList();
     }
 }
예제 #16
0
        public IHttpActionResult GetCatalogs()
        {
            var criteria = new moduleModel.SearchCriteria
            {
                ResponseGroup = moduleModel.ResponseGroup.WithCatalogs
            };

            criteria = base.ChangeCriteriaToCurentUserPermissions(criteria);
            var serviceResult = _searchService.Search(criteria);
            var retVal        = new List <webModel.Catalog>();

            foreach (var catalog in serviceResult.Catalogs)
            {
                var webCatalog = catalog.ToWebModel();
                webCatalog.SecurityScopes = base.GetObjectPermissionScopeStrings(catalog);
                retVal.Add(webCatalog);
            }
            return(Ok(retVal.ToArray()));
        }
예제 #17
0
        public coreModel.SearchResult Search(coreModel.SearchCriteria criteria)
        {
            var retVal   = new coreModel.SearchResult();
            var taskList = new List <Task>();

            if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithProducts) == coreModel.ResponseGroup.WithProducts)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchItems(criteria, retVal)));
            }
            if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCatalogs) == coreModel.ResponseGroup.WithCatalogs)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchCatalogs(criteria, retVal)));
            }
            if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCategories) == coreModel.ResponseGroup.WithCategories)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchCategories(criteria, retVal)));
            }
            Task.WaitAll(taskList.ToArray());

            return(retVal);
        }
        public static coreModel.SearchCriteria ToCoreModel(this webModel.SearchCriteria criteria)
        {
            var retVal = new coreModel.SearchCriteria();

            retVal.InjectFrom(criteria);

            retVal.ResponseGroup = criteria.ResponseGroup;
            retVal.CategoryIds   = criteria.CategoryIds;
            retVal.CatalogIds    = criteria.CatalogIds;
            retVal.PricelistIds  = criteria.PricelistIds;
            retVal.Terms         = criteria.Terms;
            retVal.Facets        = criteria.Facets;
            retVal.ProductTypes  = criteria.ProductTypes;
            retVal.VendorIds     = criteria.VendorIds;

            if (!criteria.PropertyValues.IsNullOrEmpty())
            {
                retVal.PropertyValues = criteria.PropertyValues.Select(x => x.ToCoreModel()).ToArray();
            }

            return(retVal);
        }
		public IHttpActionResult GetCategoryByCode(string store, [FromUri] string code, string language = "en-us")
		{
			var catalog = _storeService.GetById(store).Catalog;
			var searchCriteria = new SearchCriteria
			{
				ResponseGroup = ResponseGroup.WithCategories,
				Code = code,
				CatalogId = catalog
			};

			var result = _searchService.Search(searchCriteria);
			if (result.Categories != null && result.Categories.Any())
			{
				var category = _categoryService.GetById(result.Categories.First().Id);
				if (category != null)
				{
					return Ok(category.ToWebModel());
				}
			}

			return NotFound();
		}
예제 #20
0
        public virtual SearchResult Search(SearchCriteria criteria)
        {
            SearchResult result;

            var useIndexedSearch = _settingsManager.GetValue("Catalog.Search.UseCatalogIndexedSearchInManager", true);
            var searchProducts   = criteria.ResponseGroup.HasFlag(SearchResponseGroup.WithProducts);

            if (useIndexedSearch && searchProducts && !string.IsNullOrEmpty(criteria.Keyword))
            {
                result = new SearchResult();

                // TODO: create outline for category
                // TODO: implement sorting

                const ItemResponseGroup responseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.Outlines;

                var serviceCriteria = AbstractTypeFactory <ProductSearchCriteria> .TryCreateInstance();

                serviceCriteria.ObjectType    = KnownDocumentTypes.Product;
                serviceCriteria.SearchPhrase  = criteria.Keyword;
                serviceCriteria.CatalogId     = criteria.CatalogId;
                serviceCriteria.Outline       = criteria.CategoryId;
                serviceCriteria.WithHidden    = criteria.WithHidden;
                serviceCriteria.Skip          = criteria.Skip;
                serviceCriteria.Take          = criteria.Take;
                serviceCriteria.ResponseGroup = responseGroup.ToString();
                serviceCriteria.Sort          = criteria.Sort;

                SearchItems(result, serviceCriteria, responseGroup);
            }
            else
            {
                // use original implementation from catalog module
                result = _catalogSearchService.Search(criteria);
            }

            return(result);
        }
예제 #21
0
        /// <summary>
        /// Filter catalog search criteria relate to current user permissions
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        protected coreModel.SearchCriteria ChangeCriteriaToCurentUserPermissions(coreModel.SearchCriteria criteria)
        {
            var userName = User.Identity.Name;

            //first check global permission
            if (!_securityService.UserHasAnyPermission(userName, null, CatalogPredefinedPermissions.Read))
            {
                //Get user 'read' permission scopes
                var readPermissionScopes = _securityService.GetUserPermissions(userName)
                                           .Where(x => x.Id.StartsWith(CatalogPredefinedPermissions.Read))
                                           .SelectMany(x => x.AssignedScopes);

                //Filter by selected catalog
                criteria.CatalogsIds = readPermissionScopes.OfType <CatalogSelectedScope>()
                                       .Select(x => x.Scope)
                                       .Where(x => !String.IsNullOrEmpty(x)).ToArray();
                //Filter by selected category
                criteria.CategoriesIds = readPermissionScopes.OfType <CatalogSelectedCategoryScope>()
                                         .Select(x => x.Scope)
                                         .Where(x => !String.IsNullOrEmpty(x)).ToArray();
            }
            return(criteria);
        }
        public SearchResult Search(SearchCriteria criteria)
        {
            var retVal = new SearchResult();
            var taskList = new List<Task>();

            if ((criteria.ResponseGroup & SearchResponseGroup.WithProducts) == SearchResponseGroup.WithProducts)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchItems(criteria, retVal)));
            }

            if ((criteria.ResponseGroup & SearchResponseGroup.WithCatalogs) == SearchResponseGroup.WithCatalogs)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchCatalogs(criteria, retVal)));
            }

            if ((criteria.ResponseGroup & SearchResponseGroup.WithCategories) == SearchResponseGroup.WithCategories)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchCategories(criteria, retVal)));
            }

            Task.WaitAll(taskList.ToArray());

            return retVal;
        }
예제 #23
0
        public IHttpActionResult GetCatalogs(string sort = null, int skip = 0, int take = 20)
        {
            var criteria = new moduleModel.SearchCriteria
            {
                ResponseGroup = moduleModel.SearchResponseGroup.WithCatalogs,
                Sort          = sort,
                Skip          = skip,
                Take          = take,
            };

            ApplyRestrictionsForCurrentUser(criteria);

            var serviceResult = _searchService.Search(criteria);
            var retVal        = new List <webModel.Catalog>();

            foreach (var catalog in serviceResult.Catalogs)
            {
                var webCatalog = catalog.ToWebModel();
                webCatalog.SecurityScopes = GetObjectPermissionScopeStrings(catalog);
                retVal.Add(webCatalog);
            }

            return(Ok(retVal.ToArray()));
        }
		public IHttpActionResult GetProductByCode(string store, [FromUri] string code, [FromUri] coreModel.ItemResponseGroup responseGroup = coreModel.ItemResponseGroup.ItemLarge, string language = "en-us")
		{

			var searchCriteria = new SearchCriteria
			{
				ResponseGroup = ResponseGroup.WithProducts | ResponseGroup.WithVariations,
				Code = code,
			};

			var result = _searchService.Search(searchCriteria);
			if (result.Products != null && result.Products.Any())
			{
				var products = InnerGetProductsByIds(new string[] { result.Products.First().Id }, responseGroup);
				var retVal = products.FirstOrDefault();
				if (retVal != null)
				{
					return Ok(retVal);
				}
			}

			return NotFound();
		}
        private void SearchCatalogs(SearchCriteria criteria, SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                var catalogIds = criteria.CatalogIds;
                if (catalogIds.IsNullOrEmpty())
                {
                    catalogIds = repository.Catalogs.Select(x => x.Id).ToArray();
                }

                var catalogs = new ConcurrentBag<Catalog>();
                var parallelOptions = new ParallelOptions
                {
                    MaxDegreeOfParallelism = 10
                };

                Parallel.ForEach(catalogIds, parallelOptions, catalogId =>
                {
                    var catalog = _catalogService.GetById(catalogId);
                    catalogs.Add(catalog);
                });

                result.Catalogs = catalogs.OrderByDescending(x => x.Name).ToList();
            }
        }
        private void SearchItems(SearchCriteria criteria, SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                //list of search categories
                var searchCategoryIds = criteria.CategoryIds;
                if (criteria.SearchInChildren)
                {
                    if (!searchCategoryIds.IsNullOrEmpty())
                    {
                        searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                        //linked categories
                        var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray();
                        searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray();
                    }
                    else if (!criteria.CatalogIds.IsNullOrEmpty())
                    {
                        //If category not specified need search in all linked and children categories
                        searchCategoryIds = repository.Categories.Where(x => criteria.CatalogIds.Contains(x.CatalogId)).Select(x => x.Id).ToArray();
                        var allCatalogLinkedCategories = repository.CategoryLinks.Where(x => criteria.CatalogIds.Contains(x.TargetCatalogId)).Select(x => x.SourceCategoryId).ToArray();
                        searchCategoryIds = searchCategoryIds.Concat(allCatalogLinkedCategories).Distinct().ToArray();
                    }
                }

                var query = repository.Items.Where(x => criteria.WithHidden || x.IsActive);

                if (!criteria.SearchInVariations)
                {
                    query = query.Where(x => x.ParentId == null);
                }

                if (!searchCategoryIds.IsNullOrEmpty())
                {
                    query = query.Where(x => searchCategoryIds.Contains(x.CategoryId) || x.CategoryLinks.Any(c => searchCategoryIds.Contains(c.CategoryId)));
                }
                else if (!criteria.CatalogIds.IsNullOrEmpty())
                {
                    query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId) && (criteria.SearchInChildren || x.CategoryId == null));
                }

                if (!string.IsNullOrEmpty(criteria.Code))
                {
                    query = query.Where(x => x.Code == criteria.Code);
                }
                else if (!string.IsNullOrEmpty(criteria.Keyword))
                {
                    query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword) || x.ItemPropertyValues.Any(y => y.ShortTextValue == criteria.Keyword));
                }


                //Filter by property dictionary values
                if (!criteria.PropertyValues.IsNullOrEmpty())
                {
                    var propValueIds = criteria.PropertyValues.Select(x => x.ValueId).Distinct().ToArray();
                    query = query.Where(x => x.ItemPropertyValues.Any(y => propValueIds.Contains(y.KeyValue)));
                }

                if (!criteria.ProductTypes.IsNullOrEmpty())
                {
                    query = query.Where(x => criteria.ProductTypes.Contains(x.ProductType));
                }

                if (criteria.OnlyBuyable != null)
                {
                    query = query.Where(x => x.IsBuyable == criteria.OnlyBuyable);
                }

                if (criteria.OnlyWithTrackingInventory != null)
                {
                    query = query.Where(x => x.TrackInventory == criteria.OnlyWithTrackingInventory);
                }

                result.ProductsTotalCount = query.Count();

                var sortInfos = criteria.SortInfos;
                if (sortInfos.IsNullOrEmpty())
                {
                    sortInfos = new[] { new SortInfo { SortColumn = "Name" } };
                }
                //Try to replace sorting columns names
                TryTransformSortingInfoColumnNames(_productSortingAliases, sortInfos);

                query = query.OrderBySortInfos(sortInfos);

                var itemIds = query.Skip(criteria.Skip)
                                   .Take(criteria.Take)
                                   .Select(x => x.Id)
                                   .ToArray();

                var productResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Links | ItemResponseGroup.Seo;

                if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties)
                {
                    productResponseGroup |= ItemResponseGroup.ItemProperties;
                }

                if ((criteria.ResponseGroup & SearchResponseGroup.WithVariations) == SearchResponseGroup.WithVariations)
                {
                    productResponseGroup |= ItemResponseGroup.Variations;
                }

                if ((criteria.ResponseGroup & SearchResponseGroup.WithOutlines) == SearchResponseGroup.WithOutlines)
                {
                    productResponseGroup |= ItemResponseGroup.Outlines;
                }

                var products = _itemService.GetByIds(itemIds, productResponseGroup, criteria.CatalogId);
                result.Products = products.AsQueryable().OrderBySortInfos(sortInfos).ToList();
            }

        }
 /// <summary>
 /// Filter catalog search criteria based on current user permissions
 /// </summary>
 /// <param name="criteria"></param>
 /// <returns></returns>
 protected void ApplyRestrictionsForCurrentUser(SearchCriteria criteria)
 {
     var userName = User.Identity.Name;
     criteria.ApplyRestrictionsForUser(userName, _securityService);
 }
예제 #28
0
        private void SearchCategories(coreModel.SearchCriteria criteria, coreModel.SearchResult result)
        {
            // TODO: optimize for performance, need to eliminate number of database queries
            // 1. Catalog should either be passed or loaded using caching
            // 2. Categories should be loaded by passing array of ids instead of parallel loading one by one
            using (var repository = _catalogRepositoryFactory())
            {
                var query = repository.Categories;

                dataModel.CatalogBase dbCatalog = null;
                var isVirtual = false;

                if (!String.IsNullOrEmpty(criteria.CatalogId))
                {
                    dbCatalog = repository.GetCatalogById(criteria.CatalogId);
                    isVirtual = dbCatalog is dataModel.VirtualCatalog;

                    query = query.Where(x => x.CatalogId == criteria.CatalogId);
                }

                if (!String.IsNullOrEmpty(criteria.Keyword))
                {
                    query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
                }
                else if (!String.IsNullOrEmpty(criteria.CategoryId))
                {
                    if (isVirtual)
                    {
                        var dbCategory = repository.GetCategoryById(criteria.CategoryId);
                        //Need return all linked categories also
                        var allLinkedPhysicalCategoriesIds = dbCategory.IncommingLinks.Select(x => x.SourceCategoryId).ToArray();
                        query = repository.Categories;
                        if (allLinkedPhysicalCategoriesIds.Any())
                        {
                            if (criteria.HideDirectLinedCategories)
                            {
                                query = query.Where(x => x.ParentCategoryId == criteria.CategoryId || allLinkedPhysicalCategoriesIds.Contains(x.ParentCategoryId));
                            }
                            else
                            {
                                query = query.Where(x => x.ParentCategoryId == criteria.CategoryId || allLinkedPhysicalCategoriesIds.Contains(x.Id));
                            }
                        }
                        else
                        {
                            query = query.Where(x => x.ParentCategoryId == criteria.CategoryId);
                        }
                    }
                    else
                    {
                        query = query.Where(x => x.ParentCategoryId == criteria.CategoryId);
                    }
                }
                else if (!String.IsNullOrEmpty(criteria.Code))
                {
                    query = query.Where(x => x.Code == criteria.Code);
                }
                else if (!String.IsNullOrEmpty(criteria.SeoKeyword))
                {
                    var urlKeyword = _commerceService.GetSeoByKeyword(criteria.SeoKeyword).Where(x => x.ObjectType == typeof(coreModel.Category).Name).FirstOrDefault();
                    if (urlKeyword == null)
                    {
                        query = query.Where(x => false);
                    }
                    else
                    {
                        query = query.Where(x => x.Id == urlKeyword.ObjectId);
                    }
                }
                else if (!String.IsNullOrEmpty(criteria.CatalogId))
                {
                    query = query.Where(x => x.CatalogId == criteria.CatalogId && (x.ParentCategoryId == null || criteria.GetAllCategories));
                    if (isVirtual)
                    {
                        //Need return only catalog linked categories
                        var allLinkedCategoriesIds = ((dataModel.VirtualCatalog)dbCatalog).IncommingLinks
                                                     .Where(x => x.TargetCategoryId == null)
                                                     .Select(x => x.SourceCategoryId);
                        //Search in all catalogs
                        query = repository.Categories;
                        query = query.Where(x => (x.CatalogId == criteria.CatalogId && (x.ParentCategoryId == null || criteria.GetAllCategories)) || allLinkedCategoriesIds.Contains(x.Id));
                    }
                }

                var categoryIds = query.Select(x => x.Id).ToArray();

                var categories      = new ConcurrentBag <coreModel.Category>();
                var parallelOptions = new ParallelOptions
                {
                    MaxDegreeOfParallelism = 10
                };
                Parallel.ForEach(categoryIds, parallelOptions, (x) =>
                {
                    var category = _categoryService.GetById(x);

                    categories.Add(category);
                });
                //Must order by priority
                result.Categories = categories.OrderByDescending(x => x.Priority).ThenBy(x => x.Name).ToList();
            }
        }
        private void SearchCategories(SearchCriteria criteria, SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                var query = repository.Categories.Where(x => criteria.WithHidden || x.IsActive);

                //Get list of search in categories
                var searchCategoryIds = criteria.CategoryIds;

                if (!searchCategoryIds.IsNullOrEmpty())
                {
                    if (criteria.SearchInChildren)
                    {
                        searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                        //linked categories
                        var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray();
                        searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray();
                    }

                    if (criteria.HideDirectLinkedCategories)
                    {
                        query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategory.ParentCategoryId)));
                    }
                    else
                    {
                        query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategoryId)));
                    }
                }
                else if (!criteria.CatalogIds.IsNullOrEmpty())
                {
                    if (criteria.SearchInChildren)
                    {
                        //need search in all catalog linked and children categories 
                        //First need load all categories belong to searched catalogs
                        searchCategoryIds = repository.Categories.Where(x => criteria.CatalogIds.Contains(x.CatalogId)).Select(x => x.Id).ToArray();
                        //Then load all physical categories linked to catalog
                        var allCatalogLinkedCategories = repository.CategoryLinks.Where(x => criteria.CatalogIds.Contains(x.TargetCatalogId)).Select(x => x.SourceCategoryId).ToArray();
                        searchCategoryIds = searchCategoryIds.Concat(allCatalogLinkedCategories).Distinct().ToArray();
                        //Then expand all categories, get all children's
                        searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                        if (!searchCategoryIds.IsNullOrEmpty())
                        {
                            //find all categories belong searched catalogs and all categories direct or implicitly linked to catalogs
                            query = query.Where(x => searchCategoryIds.Contains(x.Id));
                        }
                    }
                    else
                    {
                        query = query.Where(x => (criteria.CatalogIds.Contains(x.CatalogId) && x.ParentCategoryId == null) || (x.OutgoingLinks.Any(y => y.TargetCategoryId == null && criteria.CatalogIds.Contains(y.TargetCatalogId))));
                    }
                }

                if (!string.IsNullOrEmpty(criteria.Keyword))
                {
                    query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
                }
                else if (!string.IsNullOrEmpty(criteria.Code))
                {
                    query = query.Where(x => x.Code == criteria.Code);
                }

                var sortInfos = criteria.SortInfos;
                if (sortInfos.IsNullOrEmpty())
                {
                    sortInfos = new[] { new SortInfo { SortColumn = "Name" } };
                }
                //Try to replace sorting columns names
                TryTransformSortingInfoColumnNames(_categorySortingAliases, sortInfos);

                query = query.OrderBySortInfos(sortInfos);

                var categoryIds = query.Select(x => x.Id).ToArray();
                var categoryResponseGroup = CategoryResponseGroup.Info | CategoryResponseGroup.WithImages | CategoryResponseGroup.WithSeo | CategoryResponseGroup.WithLinks | CategoryResponseGroup.WithParents;

                if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties)
                {
                    categoryResponseGroup |= CategoryResponseGroup.WithProperties;
                }

                if ((criteria.ResponseGroup & SearchResponseGroup.WithOutlines) == SearchResponseGroup.WithOutlines)
                {
                    categoryResponseGroup |= CategoryResponseGroup.WithOutlines;
                }

                result.Categories = _categoryService.GetByIds(categoryIds, categoryResponseGroup, criteria.CatalogId)
                                                    .AsQueryable()
                                                    .OrderBySortInfos(sortInfos)
                                                    .ToList();
            }
        }
예제 #30
0
        private void SearchItems(coreModel.SearchCriteria criteria, coreModel.SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                var searchInAllCategories = criteria.GetAllCategories || !String.IsNullOrEmpty(criteria.Keyword);
                var isVirtual             = false;
                if (criteria.CatalogId != null)
                {
                    var dbCatalog = repository.GetCatalogById(criteria.CatalogId);
                    isVirtual = dbCatalog is dataModel.VirtualCatalog;
                }

                var query = repository.Items;
                if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithVariations) != coreModel.ResponseGroup.WithVariations)
                {
                    query = query.Where(x => x.ParentId == null);
                }


                if (!searchInAllCategories && !String.IsNullOrEmpty(criteria.CategoryId))
                {
                    if (isVirtual)
                    {
                        var dbCategory = repository.GetCategoryById(criteria.CategoryId);
                        ////Need return all items belongs to linked categories
                        //var allLinkedPhysicalCategoriesIds = dbCategory.IncommingLinks.Select(x => x.SourceCategoryId).ToArray();

                        query = query.Where(x => x.CategoryId == criteria.CategoryId || x.CategoryLinks.Any(c => c.CategoryId == criteria.CategoryId));
                    }
                    else
                    {
                        query = query.Where(x => x.CategoryId == criteria.CategoryId);
                    }
                }
                else if (!String.IsNullOrEmpty(criteria.CatalogId))
                {
                    query = query.Where(x => x.CatalogId == criteria.CatalogId && (searchInAllCategories || x.CategoryId == null));
                }

                if (!String.IsNullOrEmpty(criteria.Code))
                {
                    query = query.Where(x => x.Code == criteria.Code);
                }
                else if (!String.IsNullOrEmpty(criteria.SeoKeyword))
                {
                    var urlKeyword = _commerceService.GetSeoByKeyword(criteria.SeoKeyword).Where(x => x.ObjectType == typeof(coreModel.CatalogProduct).Name).FirstOrDefault();
                    if (urlKeyword == null)
                    {
                        query = query.Where(x => false);
                    }
                    else
                    {
                        query = query.Where(x => x.Id == urlKeyword.ObjectId);
                    }
                }
                else if (!String.IsNullOrEmpty(criteria.Keyword))
                {
                    query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
                }

                result.TotalCount = query.Count();

                var itemIds = query.OrderByDescending(x => x.Name)
                              .Skip(criteria.Start)
                              .Take(criteria.Count)
                              .Select(x => x.Id)
                              .ToArray();

                var productResponseGroup = coreModel.ItemResponseGroup.ItemInfo | coreModel.ItemResponseGroup.ItemAssets | ItemResponseGroup.Categories;
                if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithProperties) == coreModel.ResponseGroup.WithProperties)
                {
                    productResponseGroup |= coreModel.ItemResponseGroup.ItemProperties;
                }
                if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithVariations) == coreModel.ResponseGroup.WithVariations)
                {
                    productResponseGroup |= coreModel.ItemResponseGroup.Variations;
                }

                var products = _itemService.GetByIds(itemIds, productResponseGroup);
                result.Products = products.OrderByDescending(x => x.Name).ToList();
            }
        }
 public IHttpActionResult SearchCategory(
     string store,
     string language = "en-us",
     [FromUri] string parentId = null)
 {
     var catalog = _storeService.GetById(store).Catalog;
     var criteria = new moduleModel.SearchCriteria
     {
         CatalogId = catalog,
         CategoryId = parentId,
         Start = 0,
         Count = int.MaxValue,
         HideDirectLinedCategories = true,
         ResponseGroup = moduleModel.ResponseGroup.WithCategories,
         GetAllCategories = false //string.IsNullOrEmpty(parentId)
     };
     var result = this._searchService.Search(criteria);
     var categories = result.Categories.Where(x => x.IsActive ?? true);
     return this.Ok(
         new webModel.CategoryResponseCollection
         {
             TotalCount = categories.Count(),
             Items = categories.Select(x => x.ToWebModel(_blobUrlResolver)).ToList()
         });
 }
예제 #32
0
        /// <summary>
        /// Get product by Code from given catalog 
        /// </summary>
        private CatalogProduct GetProductByCode(string code, string catalogId)
        {
            var responseGroup = SearchResponseGroup.WithProducts | SearchResponseGroup.WithVariations;

            var criteria = new SearchCriteria { Take = 1, Skip = 0, ResponseGroup = responseGroup, Code = code, CatalogId = catalogId, SearchInChildren = true, WithHidden = true};
            var searchResponse = _searchService.Search(criteria);
            return searchResponse.Products.FirstOrDefault();
        }
        //protected virtual void IndexReviews(ref ResultDocument doc, CatalogProduct item)
        //{
        //	var reviews = ReviewRepository.Reviews.Where(r => r.ItemId == item.ItemId).ToArray();
        //	var count = reviews.Count();
        //	var avg = count > 0 ? Math.Round(reviews.Average(r => r.OverallRating), 2) : 0;
        //	doc.Add(new DocumentField("__reviewstotal", count, new[] { IndexStore.YES, IndexType.NOT_ANALYZED }));
        //	doc.Add(new DocumentField("__reviewsavg", avg, new[] { IndexStore.YES, IndexType.NOT_ANALYZED }));
        //}


        private IEnumerable<Partition> GetPartitionsForAllProducts()
        {
            var partitions = new List<Partition>();

            var criteria = new SearchCriteria
            {
                ResponseGroup = ResponseGroup.WithProducts,
                Count = 0
            };

            var result = _catalogSearchService.Search(criteria);

            for (var start = 0; start < result.TotalCount; start += _partitionSizeCount)
            {
                criteria.Start = start;
                criteria.Count = _partitionSizeCount;

                // TODO: Need optimize search to return only product ids
                result = _catalogSearchService.Search(criteria);

                var productIds = result.Products.Select(p => p.Id).ToArray();
                partitions.Add(new Partition(OperationType.Index, productIds));
            }

            return partitions;
        }
예제 #34
0
		public void SearchTest()
		{
			var criteria = new SearchCriteria()
			{
				ResponseGroup = ResponseGroup.WithCatalogs | ResponseGroup.WithCategories
			};
			var searchService = GetSearchService();

			var result = searchService.Search(criteria);

			criteria.CatalogId = "Samsung";
			
			result = searchService.Search(criteria);

			criteria.ResponseGroup = ResponseGroup.WithProducts;
			criteria.CategoryId = result.Categories[0].Id;

			result = searchService.Search(criteria);
		}
예제 #35
0
 /// <summary>
 /// Get category by Code from given catalog 
 /// </summary>
 private Category GetCategoriesByCode(string code, string catalogId)
 {
     var responseGroup = SearchResponseGroup.WithCatalogs | SearchResponseGroup.WithCategories;
     var criteria = new SearchCriteria { Take = 1, Skip = 0, ResponseGroup = responseGroup, Code = code, CatalogId = catalogId, WithHidden = true };
     var searchResponse = _searchService.Search(criteria);
     return searchResponse.Categories.FirstOrDefault();
 }
		private void SaveCategoryTree(coreModel.Catalog catalog, IEnumerable<CsvProduct> csvProducts, ExportImportProgressInfo progressInfo, Action<ExportImportProgressInfo> progressCallback)
		{
			var categories = new List<coreModel.Category>();
			progressInfo.ProcessedCount = 0;
			var cachedCategoryMap = new Dictionary<string, Category>();

			foreach (var csvProduct in csvProducts.Where(x => x.Category != null && !String.IsNullOrEmpty(x.Category.Path)))
			{
				var outline = "";
				var productCategoryNames = csvProduct.Category.Path.Split(_categoryDelimiters);
				string parentCategoryId = null;
				foreach (var categoryName in productCategoryNames)
				{
					outline += "\\" + categoryName;
					Category category;
					if (!cachedCategoryMap.TryGetValue(outline, out category))
					{
						var searchCriteria = new SearchCriteria
						{
							CatalogId = catalog.Id,
							CategoryId = parentCategoryId,
							ResponseGroup = ResponseGroup.WithCategories
						};
						category = _searchService.Search(searchCriteria).Categories.FirstOrDefault(x => x.Name == categoryName);
					}

					if (category == null)
					{
						category = _categoryService.Create(new coreModel.Category() { Name = categoryName, Code = categoryName.GenerateSlug(), CatalogId = catalog.Id, ParentId = parentCategoryId });
						//Raise notification each notifyCategorySizeLimit category
						progressInfo.Description = string.Format("Creating categories: {0} created", ++progressInfo.ProcessedCount);
						progressCallback(progressInfo);
					}
					csvProduct.CategoryId = category.Id;
					csvProduct.Category = category;
					parentCategoryId = category.Id;
					cachedCategoryMap[outline] = category;
				}
			}

		}
		private void SaveProduct(coreModel.Catalog catalog, FulfillmentCenter defaultFulfillmentCenter, CsvProduct csvProduct)
		{
			var defaultLanguge = catalog.DefaultLanguage != null ? catalog.DefaultLanguage.LanguageCode : "EN-US";

			coreModel.CatalogProduct alreadyExistProduct = null;
			//For new product try to find them by code
			if (csvProduct.IsTransient() && !String.IsNullOrEmpty(csvProduct.Code))
			{
				var criteria = new SearchCriteria
				{
					CatalogId = catalog.Id,
					CategoryId = csvProduct.CategoryId,
					Code = csvProduct.Code,
					ResponseGroup = ResponseGroup.WithProducts | ResponseGroup.WithVariations
				};
				var result = _searchService.Search(criteria);
				alreadyExistProduct = result.Products.FirstOrDefault();
				csvProduct.Id = alreadyExistProduct != null ? alreadyExistProduct.Id : csvProduct.Id;
			}
			else if (!csvProduct.IsTransient())
			{
				//If id specified need check that product really exist 
				alreadyExistProduct = _productService.GetById(csvProduct.Id, ItemResponseGroup.ItemInfo);
			}
			var isNewProduct = alreadyExistProduct == null;

			csvProduct.CatalogId = catalog.Id;

			if (String.IsNullOrEmpty(csvProduct.Code))
			{
				csvProduct.Code = _skuGenerator.GenerateSku(csvProduct);
			}
			//Set a parent relations
			if (csvProduct.MainProductId == null && csvProduct.MainProduct != null)
			{
				csvProduct.MainProductId = csvProduct.MainProduct.Id;
			}
			csvProduct.EditorialReview.LanguageCode = defaultLanguge;
			csvProduct.SeoInfo.LanguageCode = defaultLanguge;
			csvProduct.SeoInfo.SemanticUrl = String.IsNullOrEmpty(csvProduct.SeoInfo.SemanticUrl) ? csvProduct.Code : csvProduct.SeoInfo.SemanticUrl;

			var properties = !String.IsNullOrEmpty(csvProduct.CategoryId) ? _propertyService.GetCategoryProperties(csvProduct.CategoryId) : _propertyService.GetCatalogProperties(csvProduct.CatalogId);

			if (csvProduct.PropertyValues != null)
			{
				//Try to fill properties meta information for values
				foreach (var propertyValue in csvProduct.PropertyValues)
				{
					if (propertyValue.Value != null)
					{
						var property = properties.FirstOrDefault(x => String.Equals(x.Name, propertyValue.PropertyName));
						if (property != null)
						{
							propertyValue.ValueType = property.ValueType;
							if (property.Dictionary)
							{
								property = _propertyService.GetById(property.Id);
								var dicValue = property.DictionaryValues.FirstOrDefault(x => String.Equals(x.Value, propertyValue.Value));
								propertyValue.ValueId = dicValue != null ? dicValue.Id : null;
							}
						}
					}
				}
			}

			if (!isNewProduct)
			{
				_productService.Update(new coreModel.CatalogProduct[] { csvProduct });
			}
			else
			{
				var newProduct = _productService.Create(csvProduct);
				csvProduct.Id = newProduct.Id;
			}

			//Create price in default price list

			if (csvProduct.Price.EffectiveValue > 0)
			{
				csvProduct.Price.ProductId = csvProduct.Id;

				if (csvProduct.Price.IsTransient() || _pricingService.GetPriceById(csvProduct.Price.Id) == null)
				{
					_pricingService.CreatePrice(csvProduct.Price);
				}
				else
				{
					_pricingService.UpdatePrices(new Price[] { csvProduct.Price });
				}
			}

			//Create inventory
			csvProduct.Inventory.ProductId = csvProduct.Id;
			csvProduct.Inventory.FulfillmentCenterId = csvProduct.Inventory.FulfillmentCenterId ?? defaultFulfillmentCenter.Id;
			_inventoryService.UpsertInventory(csvProduct.Inventory);
		}
        private void SearchItems(SearchCriteria criteria, SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                //list of search categories
                var searchCategoryIds = criteria.CategoryIds;
                if (searchCategoryIds != null && criteria.SearchInChildren)
                {
                    searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                    //linked categories
                    var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray();
                    searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray();
                }

                //Do not search in variations
                var query = repository.Items.Where(x => x.ParentId == null).Where(x => criteria.WithHidden ? true : x.IsActive);

                if (searchCategoryIds != null)
                {
                   query = query.Where(x => searchCategoryIds.Contains(x.CategoryId) || x.CategoryLinks.Any(c => searchCategoryIds.Contains(c.CategoryId)));
                }
				else if (criteria.CatalogIds != null)
				{
					query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId) && (criteria.SearchInChildren || x.CategoryId == null));
				}

                if (!string.IsNullOrEmpty(criteria.Code))
				{
					query = query.Where(x => x.Code == criteria.Code);
				}
                else if (!string.IsNullOrEmpty(criteria.Keyword))
				{
					query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
				}

                //Filter by property  dictionary values
                if (criteria.PropertyValues != null && criteria.PropertyValues.Any())
                {
                    var propValueIds = criteria.PropertyValues.Select(x => x.ValueId).Distinct().ToArray();
                    query = query.Where(x => x.ItemPropertyValues.Any(y => propValueIds.Contains(y.KeyValue)));
                }

                result.ProductsTotalCount = query.Count();

                var itemIds = query.OrderByDescending(x => x.Name)
                                   .Skip(criteria.Skip)
                                   .Take(criteria.Take)
                                   .Select(x => x.Id)
                                   .ToArray();

                var productResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Links | ItemResponseGroup.Seo;

                if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties)
				{
                    productResponseGroup |= ItemResponseGroup.ItemProperties;
				}

                if ((criteria.ResponseGroup & SearchResponseGroup.WithVariations) == SearchResponseGroup.WithVariations)
				{
                    productResponseGroup |= ItemResponseGroup.Variations;
				}

				var products = _itemService.GetByIds(itemIds, productResponseGroup);
                result.Products = products.OrderByDescending(x => x.Name).ToList();
            }
        }