protected virtual void ConvertAvailability(CatalogSearchQuery query, RouteData routeData, string origin)
        {
            bool availability;

            GetValueFor(query, "a", FacetGroupKind.Availability, out availability);

            // Setting specifies the logical direction of the filter. That's smarter than just to specify a default value.
            if (_searchSettings.IncludeNotAvailable)
            {
                // False = show, True = hide unavailable products.
                if (availability)
                {
                    query.AvailableOnly(true);
                }
            }
            else
            {
                // False = hide, True = show unavailable products.
                if (!availability)
                {
                    query.AvailableOnly(true);
                }
            }

            AddFacet(query, FacetGroupKind.Availability, true, FacetSorting.LabelAsc, descriptor =>
            {
                descriptor.MinHitCount = 0;

                var newValue = availability
                                        ? new FacetValue(true, IndexTypeCode.Boolean)
                                        : new FacetValue(null, IndexTypeCode.Empty);

                newValue.IsSelected = availability;
                newValue.Label      = _services.Localization.GetResource(_searchSettings.IncludeNotAvailable ? "Search.Facet.ExcludeOutOfStock" : "Search.Facet.IncludeOutOfStock");

                descriptor.AddValue(newValue);
            });
        }
        protected virtual void ConvertDeliveryTime(CatalogSearchQuery query, RouteData routeData, string origin)
        {
            List <int> ids;

            if (GetValueFor(query, "d", FacetGroupKind.DeliveryTime, out ids) && ids != null && ids.Any())
            {
                query.WithDeliveryTimeIds(ids.ToArray());
            }

            AddFacet(query, FacetGroupKind.DeliveryTime, true, FacetSorting.DisplayOrder, descriptor =>
            {
                if (ids != null)
                {
                    foreach (var id in ids)
                    {
                        descriptor.AddValue(new FacetValue(id, IndexTypeCode.Int32)
                        {
                            IsSelected = true
                        });
                    }
                }
            });
        }
        protected virtual void ConvertRating(CatalogSearchQuery query, string origin)
        {
            var alias = _catalogSearchQueryAliasMapper.GetCommonFacetAliasByGroupKind(FacetGroupKind.Rating, query.LanguageId ?? 0);

            if (TryGetValueFor(alias ?? "r", out double?fromRate) && fromRate.HasValue)
            {
                query.WithRating(fromRate, null);
            }

            AddFacet(query, FacetGroupKind.Rating, false, FacetSorting.DisplayOrder, descriptor =>
            {
                descriptor.MinHitCount     = 0;
                descriptor.MaxChoicesCount = 5;

                if (fromRate.HasValue)
                {
                    descriptor.AddValue(new FacetValue(fromRate.Value, IndexTypeCode.Double)
                    {
                        IsSelected = true
                    });
                }
            });
        }
        protected virtual void ConvertRating(CatalogSearchQuery query, RouteData routeData, string origin)
        {
            double?fromRate;

            if (GetValueFor(query, "r", FacetGroupKind.Rating, out fromRate) && fromRate.HasValue)
            {
                query.WithRating(fromRate, null);
            }

            AddFacet(query, FacetGroupKind.Rating, false, FacetSorting.DisplayOrder, descriptor =>
            {
                descriptor.MinHitCount     = 0;
                descriptor.MaxChoicesCount = 5;

                if (fromRate.HasValue)
                {
                    descriptor.AddValue(new FacetValue(fromRate.Value, IndexTypeCode.Double)
                    {
                        IsSelected = true
                    });
                }
            });
        }
        protected virtual void ConvertDeliveryTime(CatalogSearchQuery query, string origin)
        {
            var alias = _catalogSearchQueryAliasMapper.GetCommonFacetAliasByGroupKind(FacetGroupKind.DeliveryTime, query.LanguageId ?? 0);

            if (TryGetValueFor(alias ?? "d", out List <int> ids) && ids != null && ids.Any())
            {
                query.WithDeliveryTimeIds(ids.ToArray());
            }

            AddFacet(query, FacetGroupKind.DeliveryTime, true, FacetSorting.DisplayOrder, descriptor =>
            {
                if (ids != null)
                {
                    foreach (var id in ids)
                    {
                        descriptor.AddValue(new FacetValue(id, IndexTypeCode.Int32)
                        {
                            IsSelected = true
                        });
                    }
                }
            });
        }
        private decimal?CalculatePrice(int key, bool lowestPrice)
        {
            string  requiredProperties = "TierPrices, AppliedDiscounts, ProductBundleItems";
            var     entity             = GetExpandedEntity(key, requiredProperties);
            var     customer           = Services.WorkContext.CurrentCustomer;
            decimal?result             = null;

            this.ProcessEntity(() =>
            {
                if (lowestPrice)
                {
                    if (entity.ProductType == ProductType.GroupedProduct)
                    {
                        Product lowestPriceProduct;
                        var searchQuery = new CatalogSearchQuery()
                                          .VisibleOnly()
                                          .HasParentGroupedProduct(entity.Id);

                        var query = _catalogSearchService.Value.PrepareQuery(searchQuery, GetExpandedEntitySet(requiredProperties));
                        var associatedProducts = query.OrderBy(x => x.DisplayOrder).ToList();

                        result = _priceCalculationService.Value.GetLowestPrice(entity, customer, null, associatedProducts, out lowestPriceProduct);
                    }
                    else
                    {
                        bool displayFromMessage;
                        result = _priceCalculationService.Value.GetLowestPrice(entity, customer, null, out displayFromMessage);
                    }
                }
                else
                {
                    result = _priceCalculationService.Value.GetPreselectedPrice(entity, customer, Services.WorkContext.WorkingCurrency, null);
                }
            });

            return(result);
        }
示例#7
0
        /// <param name="contextProduct">The product or the first associated product of a group.</param>
        /// <returns>The final price</returns>
        private decimal MapSummaryItemPrice(Product product, ref Product contextProduct, ProductSummaryModel.SummaryItem item, MapProductSummaryItemContext ctx)
        {
            var displayFromMessage = false;
            var taxRate            = decimal.Zero;
            var oldPriceBase       = decimal.Zero;
            var oldPrice           = decimal.Zero;
            var finalPriceBase     = decimal.Zero;
            var finalPrice         = decimal.Zero;
            var displayPrice       = decimal.Zero;
            ICollection <Product> associatedProducts = null;

            var priceModel = new ProductSummaryModel.PriceModel();

            item.Price = priceModel;

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing && !ctx.BatchContext.ProductBundleItems.FullyLoaded)
            {
                ctx.BatchContext.ProductBundleItems.LoadAll();
            }

            if (product.ProductType == ProductType.GroupedProduct)
            {
                priceModel.DisableBuyButton      = true;
                priceModel.DisableWishlistButton = true;
                priceModel.AvailableForPreOrder  = false;

                if (ctx.GroupedProducts == null)
                {
                    // One-time batched retrieval of all associated products.
                    var searchQuery = new CatalogSearchQuery()
                                      .PublishedOnly(true)
                                      .HasStoreId(ctx.Store.Id)
                                      .HasParentGroupedProduct(ctx.BatchContext.ProductIds.ToArray());

                    // Get all associated products for this batch grouped by ParentGroupedProductId.
                    var allAssociatedProducts = _catalogSearchService.Search(searchQuery).Hits
                                                .OrderBy(x => x.ParentGroupedProductId)
                                                .ThenBy(x => x.DisplayOrder);

                    ctx.GroupedProducts = allAssociatedProducts.ToMultimap(x => x.ParentGroupedProductId, x => x);
                    ctx.AssociatedProductBatchContext = _dataExporter.Value.CreateProductExportContext(allAssociatedProducts, ctx.Customer, null, null, false);
                }

                associatedProducts = ctx.GroupedProducts[product.Id];
                if (associatedProducts.Any())
                {
                    contextProduct = associatedProducts.OrderBy(x => x.DisplayOrder).First();

                    _services.DisplayControl.Announce(contextProduct);
                }
            }
            else
            {
                priceModel.DisableBuyButton      = product.DisableBuyButton || !ctx.AllowShoppingCart || !ctx.AllowPrices;
                priceModel.DisableWishlistButton = product.DisableWishlistButton || !ctx.AllowWishlist || !ctx.AllowPrices;
                priceModel.AvailableForPreOrder  = product.AvailableForPreOrder;
            }

            // Return if there's no pricing at all.
            if (contextProduct == null || contextProduct.CustomerEntersPrice || !ctx.AllowPrices || _catalogSettings.PriceDisplayType == PriceDisplayType.Hide)
            {
                return(finalPrice);
            }
            // Return if group has no associated products.
            if (product.ProductType == ProductType.GroupedProduct && !associatedProducts.Any())
            {
                return(finalPrice);
            }

            // Call for price.
            priceModel.CallForPrice = contextProduct.CallForPrice;
            if (contextProduct.CallForPrice)
            {
                priceModel.Price = ctx.Resources["Products.CallForPrice"];
                return(finalPrice);
            }

            // Calculate prices.
            var batchContext = product.ProductType == ProductType.GroupedProduct ? ctx.AssociatedProductBatchContext : ctx.BatchContext;

            if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice)
            {
                displayPrice = _priceCalculationService.GetPreselectedPrice(contextProduct, ctx.Customer, ctx.Currency, batchContext);
            }
            else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes)
            {
                displayPrice = _priceCalculationService.GetFinalPrice(contextProduct, null, ctx.Customer, decimal.Zero, false, 1, null, batchContext);
            }
            else
            {
                // Display lowest price.
                if (product.ProductType == ProductType.GroupedProduct)
                {
                    displayFromMessage = true;
                    displayPrice       = _priceCalculationService.GetLowestPrice(product, ctx.Customer, batchContext, associatedProducts, out contextProduct) ?? decimal.Zero;
                }
                else
                {
                    displayPrice = _priceCalculationService.GetLowestPrice(product, ctx.Customer, batchContext, out displayFromMessage);
                }
            }

            oldPriceBase   = _taxService.GetProductPrice(contextProduct, contextProduct.OldPrice, out taxRate);
            finalPriceBase = _taxService.GetProductPrice(contextProduct, displayPrice, out taxRate);

            oldPrice   = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, ctx.Currency);
            finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, ctx.Currency);

            priceModel.PriceValue = finalPrice;
            priceModel.Price      = displayFromMessage
                                ? string.Format(ctx.Resources["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice))
                                : _priceFormatter.FormatPrice(finalPrice);

            priceModel.HasDiscount = oldPriceBase > decimal.Zero && oldPriceBase > finalPriceBase;
            if (priceModel.HasDiscount)
            {
                priceModel.RegularPriceValue = oldPrice;
                priceModel.RegularPrice      = _priceFormatter.FormatPrice(oldPrice);
            }

            // Calculate saving.
            var finalPriceWithDiscount = _priceCalculationService.GetFinalPrice(contextProduct, null, ctx.Customer, decimal.Zero, true, 1, null, batchContext);

            finalPriceWithDiscount = _taxService.GetProductPrice(contextProduct, finalPriceWithDiscount, out taxRate);
            finalPriceWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceWithDiscount, ctx.Currency);

            var finalPriceWithoutDiscount = finalPrice;

            if (_catalogSettings.PriceDisplayType != PriceDisplayType.PriceWithoutDiscountsAndAttributes)
            {
                finalPriceWithoutDiscount = _priceCalculationService.GetFinalPrice(contextProduct, null, ctx.Customer, decimal.Zero, false, 1, null, batchContext);
                finalPriceWithoutDiscount = _taxService.GetProductPrice(contextProduct, finalPriceWithoutDiscount, out taxRate);
                finalPriceWithoutDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceWithoutDiscount, ctx.Currency);
            }

            // Discounted price has priority over the old price (avoids differing percentage discount in product lists and detail page).
            var regularPrice = finalPriceWithDiscount < finalPriceWithoutDiscount
                                ? finalPriceWithoutDiscount
                                : oldPrice;

            if (regularPrice > 0 && regularPrice > finalPriceWithDiscount)
            {
                priceModel.HasDiscount   = true;
                priceModel.SavingPercent = (float)((regularPrice - finalPriceWithDiscount) / regularPrice) * 100;
                priceModel.SavingAmount  = _priceFormatter.FormatPrice(regularPrice - finalPriceWithDiscount, true, false);

                if (!priceModel.RegularPriceValue.HasValue)
                {
                    priceModel.RegularPriceValue = regularPrice;
                    priceModel.RegularPrice      = _priceFormatter.FormatPrice(regularPrice);
                }

                if (ctx.Model.ShowDiscountBadge)
                {
                    item.Badges.Add(new ProductSummaryModel.Badge
                    {
                        Label = T("Products.SavingBadgeLabel", priceModel.SavingPercent.ToString("N0")),
                        Style = BadgeStyle.Danger
                    });
                }
            }

            return(finalPrice);
        }
示例#8
0
 public SearchResultModel(CatalogSearchQuery query)
 {
     Query     = query;
     HitGroups = new List <HitGroup>();
 }
示例#9
0
        public virtual void InheritAclIntoChildren(
            int categoryId,
            bool touchProductsWithMultipleCategories = false,
            bool touchExistingAcls = false,
            bool categoriesOnly    = false)
        {
            var category              = GetCategoryById(categoryId);
            var subcategories         = GetAllCategoriesByParentCategoryId(categoryId, true);
            var allCustomerRoles      = _customerService.GetAllCustomerRoles(true);
            var categoryCustomerRoles = _aclService.GetCustomerRoleIdsWithAccessTo(category);

            var categoryIds = new HashSet <int>(subcategories.Select(x => x.Id));

            categoryIds.Add(categoryId);

            var searchQuery = new CatalogSearchQuery()
                              .WithCategoryIds(null, categoryIds.ToArray());

            var query    = _catalogSearchService.PrepareQuery(searchQuery);
            var products = query.OrderBy(p => p.Id).ToList();

            using (var scope = new DbContextScope(ctx: _aclRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false))
            {
                _aclRepository.AutoCommitEnabled = false;

                foreach (var subcategory in subcategories)
                {
                    if (subcategory.SubjectToAcl != category.SubjectToAcl)
                    {
                        subcategory.SubjectToAcl = category.SubjectToAcl;
                        _categoryRepository.Update(subcategory);
                    }

                    var existingAclRecords = _aclService.GetAclRecords(subcategory).ToDictionarySafe(x => x.CustomerRoleId);

                    foreach (var customerRole in allCustomerRoles)
                    {
                        if (categoryCustomerRoles.Contains(customerRole.Id))
                        {
                            if (!existingAclRecords.ContainsKey(customerRole.Id))
                            {
                                _aclRepository.Insert(new AclRecord {
                                    CustomerRole = customerRole, CustomerRoleId = customerRole.Id, EntityId = subcategory.Id, EntityName = "Category"
                                });
                            }
                        }
                        else
                        {
                            if (existingAclRecords.TryGetValue(customerRole.Id, out var aclRecordToDelete))
                            {
                                _aclRepository.Delete(aclRecordToDelete);
                            }
                        }
                    }
                }

                _aclRepository.Context.SaveChanges();

                foreach (var product in products)
                {
                    if (product.SubjectToAcl != category.SubjectToAcl)
                    {
                        product.SubjectToAcl = category.SubjectToAcl;
                        _productRepository.Update(product);
                    }

                    var existingAclRecords = _aclService.GetAclRecords(product).ToDictionarySafe(x => x.CustomerRoleId);

                    foreach (var customerRole in allCustomerRoles)
                    {
                        if (categoryCustomerRoles.Contains(customerRole.Id))
                        {
                            if (!existingAclRecords.ContainsKey(customerRole.Id))
                            {
                                _aclRepository.Insert(new AclRecord {
                                    CustomerRole = customerRole, CustomerRoleId = customerRole.Id, EntityId = product.Id, EntityName = "Product"
                                });
                            }
                        }
                        else
                        {
                            if (existingAclRecords.TryGetValue(customerRole.Id, out var aclRecordToDelete))
                            {
                                _aclRepository.Delete(aclRecordToDelete);
                            }
                        }
                    }
                }

                _aclRepository.Context.SaveChanges();
            }
        }
        public async Task <IActionResult> RecentlyAddedProductsRSS(CatalogSearchQuery query)
        {
            // TODO: (mc) find a more prominent place for the "NewProducts" link (may be in main menu?)
            var store              = Services.StoreContext.CurrentStore;
            var protocol           = Services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http";
            var selfLink           = Url.RouteUrl("RecentlyAddedProductsRSS", null, protocol);
            var recentProductsLink = Url.RouteUrl("RecentlyAddedProducts", null, protocol);
            var title              = $"{store.Name} - {T("RSS.RecentlyAddedProducts")}";
            var feed = new SmartSyndicationFeed(new Uri(recentProductsLink), title, T("RSS.InformationAboutProducts"));

            feed.AddNamespaces(true);
            feed.Init(selfLink, Services.WorkContext.WorkingLanguage.LanguageCulture);

            if (!_catalogSettings.RecentlyAddedProductsEnabled || _catalogSettings.RecentlyAddedProductsNumber <= 0)
            {
                return(new RssActionResult {
                    Feed = feed
                });
            }

            var items = new List <SyndicationItem>();

            query.Sorting.Clear();
            query = query
                    .BuildFacetMap(false)
                    .SortBy(ProductSortingEnum.CreatedOn)
                    .Slice(0, _catalogSettings.RecentlyAddedProductsNumber);

            var result = await _catalogSearchService.SearchAsync(query);

            var hits = await result.GetHitsAsync();

            var storeUrl = store.GetHost();

            // Prefetching.
            var fileIds = hits
                          .Select(x => x.MainPictureId ?? 0)
                          .Where(x => x != 0)
                          .Distinct()
                          .ToArray();

            var files = (await Services.MediaService.GetFilesByIdsAsync(fileIds)).ToDictionarySafe(x => x.Id);

            foreach (var product in hits)
            {
                var productUrl = Url.RouteUrl("Product", new { SeName = await product.GetActiveSlugAsync() }, protocol);
                if (productUrl.HasValue())
                {
                    var content = product.GetLocalized(x => x.FullDescription).Value;

                    if (content.HasValue())
                    {
                        content = WebHelper.MakeAllUrlsAbsolute(content, Request);
                    }

                    var item = feed.CreateItem(
                        product.GetLocalized(x => x.Name),
                        product.GetLocalized(x => x.ShortDescription),
                        productUrl,
                        product.CreatedOnUtc,
                        content);

                    try
                    {
                        // We add only the first media file.
                        if (files.TryGetValue(product.MainPictureId ?? 0, out var file))
                        {
                            var url = Services.MediaService.GetUrl(file, _mediaSettings.ProductDetailsPictureSize, storeUrl, false);
                            feed.AddEnclosure(item, file, url);
                        }
                    }
                    catch
                    {
                    }

                    items.Add(item);
                }
            }

            feed.Items = items;

            Services.DisplayControl.AnnounceRange(hits);

            return(new RssActionResult {
                Feed = feed
            });
        }
        public ActionResult Category(int categoryId, CatalogSearchQuery query)
        {
            var category = _categoryService.GetCategoryById(categoryId);

            if (category == null || category.Deleted)
            {
                return(HttpNotFound());
            }

            // Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a category before publishing.
            if (!category.Published && !Services.Permissions.Authorize(Permissions.Catalog.Category.Read))
            {
                return(HttpNotFound());
            }

            // ACL (access control list).
            if (!_aclService.Authorize(category))
            {
                return(HttpNotFound());
            }

            // Store mapping.
            if (!_storeMappingService.Authorize(category))
            {
                return(HttpNotFound());
            }

            var store    = Services.StoreContext.CurrentStore;
            var customer = Services.WorkContext.CurrentCustomer;

            // 'Continue shopping' URL.
            if (!Services.WorkContext.CurrentCustomer.IsSystemAccount)
            {
                _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastContinueShoppingPage, Services.WebHelper.GetThisPageUrl(false), store.Id);
            }

            var model = category.ToModel();

            if (query.IsSubPage && !_catalogSettings.ShowDescriptionInSubPages)
            {
                model.Description.ChangeValue(string.Empty);
                model.BottomDescription.ChangeValue(string.Empty);
            }

            Services.DisplayControl.Announce(category);

            // Category breadcrumb.
            if (_catalogSettings.CategoryBreadcrumbEnabled)
            {
                _helper.GetCategoryBreadcrumb(_breadcrumb, ControllerContext);
            }

            // Products.
            var catIds = new int[] { categoryId };

            if (_catalogSettings.ShowProductsFromSubcategories)
            {
                // Include subcategories.
                catIds = catIds.Concat(_helper.GetChildCategoryIds(categoryId)).ToArray();
            }

            query.WithCategoryIds(_catalogSettings.IncludeFeaturedProductsInNormalLists ? (bool?)null : false, catIds);

            var searchResult = _catalogSearchService.Search(query);

            model.SearchResult = searchResult;

            var mappingSettings = _helper.GetBestFitProductSummaryMappingSettings(query.GetViewMode());

            model.Products = _helper.MapProductSummaryModel(searchResult.Hits, mappingSettings);

            model.SubCategoryDisplayType = _catalogSettings.SubCategoryDisplayType;

            var customerRolesIds = customer.CustomerRoleMappings
                                   .Select(x => x.CustomerRole)
                                   .Where(x => x.Active)
                                   .Select(x => x.Id)
                                   .ToList();

            var pictureSize  = _mediaSettings.CategoryThumbPictureSize;
            var fallbackType = _catalogSettings.HideCategoryDefaultPictures ? FallbackPictureType.NoFallback : FallbackPictureType.Entity;

            var hideSubCategories = _catalogSettings.SubCategoryDisplayType == SubCategoryDisplayType.Hide ||
                                    (_catalogSettings.SubCategoryDisplayType == SubCategoryDisplayType.AboveProductList && query.IsSubPage && !_catalogSettings.ShowSubCategoriesInSubPages);
            var hideFeaturedProducts = _catalogSettings.IgnoreFeaturedProducts || (query.IsSubPage && !_catalogSettings.IncludeFeaturedProductsInSubPages);

            // Subcategories.
            if (!hideSubCategories)
            {
                var subCategories = _categoryService.GetAllCategoriesByParentCategoryId(categoryId);
                model.SubCategories = _helper.MapCategorySummaryModel(subCategories, pictureSize);
            }

            // Featured Products.
            if (!hideFeaturedProducts)
            {
                CatalogSearchResult featuredProductsResult = null;

                string cacheKey = ModelCacheEventConsumer.CATEGORY_HAS_FEATURED_PRODUCTS_KEY.FormatInvariant(categoryId, string.Join(",", customerRolesIds), store.Id);
                var    hasFeaturedProductsCache = Services.Cache.Get <bool?>(cacheKey);

                var featuredProductsQuery = new CatalogSearchQuery()
                                            .VisibleOnly(customer)
                                            .WithVisibility(ProductVisibility.Full)
                                            .WithCategoryIds(true, categoryId)
                                            .HasStoreId(Services.StoreContext.CurrentStore.Id)
                                            .WithLanguage(Services.WorkContext.WorkingLanguage)
                                            .WithCurrency(Services.WorkContext.WorkingCurrency);

                if (!hasFeaturedProductsCache.HasValue)
                {
                    featuredProductsResult   = _catalogSearchService.Search(featuredProductsQuery);
                    hasFeaturedProductsCache = featuredProductsResult.TotalHitsCount > 0;
                    Services.Cache.Put(cacheKey, hasFeaturedProductsCache, TimeSpan.FromHours(6));
                }

                if (hasFeaturedProductsCache.Value && featuredProductsResult == null)
                {
                    featuredProductsResult = _catalogSearchService.Search(featuredProductsQuery);
                }

                if (featuredProductsResult != null)
                {
                    var featuredProductsmappingSettings = _helper.GetBestFitProductSummaryMappingSettings(ProductSummaryViewMode.Grid);
                    model.FeaturedProducts = _helper.MapProductSummaryModel(featuredProductsResult.Hits, featuredProductsmappingSettings);
                }
            }

            // Prepare paging/sorting/mode stuff.
            _helper.MapListActions(model.Products, category, _catalogSettings.DefaultPageSizeOptions);

            // Template.
            var templateCacheKey = string.Format(ModelCacheEventConsumer.CATEGORY_TEMPLATE_MODEL_KEY, category.CategoryTemplateId);
            var templateViewPath = Services.Cache.Get(templateCacheKey, () =>
            {
                var template = _categoryTemplateService.GetCategoryTemplateById(category.CategoryTemplateId);
                if (template == null)
                {
                    template = _categoryTemplateService.GetAllCategoryTemplates().FirstOrDefault();
                }
                return(template.ViewPath);
            });

            // Activity log.
            Services.CustomerActivity.InsertActivity("PublicStore.ViewCategory", T("ActivityLog.PublicStore.ViewCategory"), category.Name);

            return(View(templateViewPath, model));
        }
示例#12
0
        public virtual void InheritAclIntoChildren(
            int categoryId,
            bool touchProductsWithMultipleCategories = false,
            bool touchExistingAcls = false,
            bool categoriesOnly    = false)
        {
            var allCustomerRoles  = _customerService.GetAllCustomerRoles(true);
            var referenceCategory = GetCategoryById(categoryId);
            var referenceRoleIds  = _aclService.GetCustomerRoleIdsWithAccessTo(referenceCategory);

            using (var scope = new DbContextScope(ctx: _aclRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                ProcessCategory(scope, referenceCategory);
            }

            _cache.RemoveByPattern(AclService.ACL_SEGMENT_PATTERN);


            void ProcessCategory(DbContextScope scope, Category c)
            {
                // Process sub-categories.
                var subCategories = GetAllCategoriesByParentCategoryId(c.Id, true);

                foreach (var subCategory in subCategories)
                {
                    if (subCategory.SubjectToAcl != referenceCategory.SubjectToAcl)
                    {
                        subCategory.SubjectToAcl = referenceCategory.SubjectToAcl;
                        _categoryRepository.Update(subCategory);
                    }

                    var existingAclRecords = _aclService.GetAclRecords(subCategory).ToDictionarySafe(x => x.CustomerRoleId);

                    foreach (var role in allCustomerRoles)
                    {
                        if (referenceRoleIds.Contains(role.Id))
                        {
                            if (!existingAclRecords.ContainsKey(role.Id))
                            {
                                _aclRepository.Insert(new AclRecord {
                                    CustomerRoleId = role.Id, EntityId = subCategory.Id, EntityName = "Category"
                                });
                            }
                        }
                        else if (existingAclRecords.TryGetValue(role.Id, out var aclRecordToDelete))
                        {
                            _aclRepository.Delete(aclRecordToDelete);
                        }
                    }
                }

                scope.Commit();

                // Process products.
                var categoryIds = new HashSet <int>(subCategories.Select(x => x.Id));

                categoryIds.Add(c.Id);

                var searchQuery   = new CatalogSearchQuery().WithCategoryIds(null, categoryIds.ToArray());
                var productsQuery = _catalogSearchService.PrepareQuery(searchQuery);
                var productsPager = new FastPager <Product>(productsQuery, 500);

                while (productsPager.ReadNextPage(out var products))
                {
                    foreach (var product in products)
                    {
                        if (product.SubjectToAcl != referenceCategory.SubjectToAcl)
                        {
                            product.SubjectToAcl = referenceCategory.SubjectToAcl;
                            _productRepository.Update(product);
                        }

                        var existingAclRecords = _aclService.GetAclRecords(product).ToDictionarySafe(x => x.CustomerRoleId);

                        foreach (var role in allCustomerRoles)
                        {
                            if (referenceRoleIds.Contains(role.Id))
                            {
                                if (!existingAclRecords.ContainsKey(role.Id))
                                {
                                    _aclRepository.Insert(new AclRecord {
                                        CustomerRoleId = role.Id, EntityId = product.Id, EntityName = "Product"
                                    });
                                }
                            }
                            else if (existingAclRecords.TryGetValue(role.Id, out var aclRecordToDelete))
                            {
                                _aclRepository.Delete(aclRecordToDelete);
                            }
                        }
                    }

                    scope.Commit();
                }

                scope.Commit();

                try
                {
                    scope.DbContext.DetachEntities(x => x is Product || x is Category || x is AclRecord, false);
                }
                catch { }

                foreach (var subCategory in subCategories)
                {
                    ProcessCategory(scope, subCategory);
                }
            }
        }
示例#13
0
        /// <summary>
        /// Create a copy of product with all depended data
        /// </summary>
        /// <param name="product">The product</param>
        /// <param name="newName">The name of product duplicate</param>
        /// <param name="isPublished">A value indicating whether the product duplicate should be published</param>
        /// <param name="copyImages">A value indicating whether the product images should be copied</param>
        /// <param name="copyAssociatedProducts">A value indicating whether the copy associated products</param>
        /// <returns>Product entity</returns>
        public virtual Product CopyProduct(Product product, string newName, bool isPublished, bool copyImages, bool copyAssociatedProducts = true)
        {
            if (product == null)
            {
                throw new ArgumentNullException("product");
            }

            if (String.IsNullOrEmpty(newName))
            {
                throw new ArgumentException("Product name is required");
            }

            Product productCopy = null;
            var     utcNow      = DateTime.UtcNow;

            // product download & sample download
            int downloadId       = 0;
            int?sampleDownloadId = null;

            if (product.IsDownload)
            {
                var download = _downloadService.GetDownloadById(product.DownloadId);
                if (download != null)
                {
                    var downloadCopy = new Download
                    {
                        DownloadGuid   = Guid.NewGuid(),
                        UseDownloadUrl = download.UseDownloadUrl,
                        DownloadUrl    = download.DownloadUrl,
                        ContentType    = download.ContentType,
                        Filename       = download.Filename,
                        Extension      = download.Extension,
                        IsNew          = download.IsNew,
                        UpdatedOnUtc   = utcNow
                    };

                    if ((download.MediaStorageId ?? 0) != 0 && download.MediaStorage != null)
                    {
                        _downloadService.InsertDownload(downloadCopy, download.MediaStorage.Data);
                    }
                    else
                    {
                        _downloadService.InsertDownload(downloadCopy, null);
                    }

                    downloadId = downloadCopy.Id;
                }

                if (product.HasSampleDownload)
                {
                    var sampleDownload = _downloadService.GetDownloadById(product.SampleDownloadId.GetValueOrDefault());
                    if (sampleDownload != null)
                    {
                        var sampleDownloadCopy = new Download
                        {
                            DownloadGuid   = Guid.NewGuid(),
                            UseDownloadUrl = sampleDownload.UseDownloadUrl,
                            DownloadUrl    = sampleDownload.DownloadUrl,
                            ContentType    = sampleDownload.ContentType,
                            Filename       = sampleDownload.Filename,
                            Extension      = sampleDownload.Extension,
                            IsNew          = sampleDownload.IsNew,
                            UpdatedOnUtc   = utcNow
                        };

                        if ((sampleDownload.MediaStorageId ?? 0) != 0 && sampleDownload.MediaStorage != null)
                        {
                            _downloadService.InsertDownload(sampleDownloadCopy, sampleDownload.MediaStorage.Data);
                        }
                        else
                        {
                            _downloadService.InsertDownload(sampleDownloadCopy, null);
                        }

                        sampleDownloadId = sampleDownloadCopy.Id;
                    }
                }
            }

            // product
            productCopy = new Product
            {
                ProductTypeId          = product.ProductTypeId,
                ParentGroupedProductId = product.ParentGroupedProductId,
                VisibleIndividually    = product.VisibleIndividually,
                Name                 = newName,
                ShortDescription     = product.ShortDescription,
                FullDescription      = product.FullDescription,
                ProductTemplateId    = product.ProductTemplateId,
                AdminComment         = product.AdminComment,
                ShowOnHomePage       = product.ShowOnHomePage,
                HomePageDisplayOrder = product.HomePageDisplayOrder,
                MetaKeywords         = product.MetaKeywords,
                MetaDescription      = product.MetaDescription,
                MetaTitle            = product.MetaTitle,
                AllowCustomerReviews = product.AllowCustomerReviews,
                LimitedToStores      = product.LimitedToStores,
                Sku = product.Sku,
                ManufacturerPartNumber = product.ManufacturerPartNumber,
                Gtin                             = product.Gtin,
                IsGiftCard                       = product.IsGiftCard,
                GiftCardType                     = product.GiftCardType,
                RequireOtherProducts             = product.RequireOtherProducts,
                RequiredProductIds               = product.RequiredProductIds,
                AutomaticallyAddRequiredProducts = product.AutomaticallyAddRequiredProducts,
                IsDownload                       = product.IsDownload,
                DownloadId                       = downloadId,
                UnlimitedDownloads               = product.UnlimitedDownloads,
                MaxNumberOfDownloads             = product.MaxNumberOfDownloads,
                DownloadExpirationDays           = product.DownloadExpirationDays,
                DownloadActivationType           = product.DownloadActivationType,
                HasSampleDownload                = product.HasSampleDownload,
                SampleDownloadId                 = sampleDownloadId,
                HasUserAgreement                 = product.HasUserAgreement,
                UserAgreementText                = product.UserAgreementText,
                IsRecurring                      = product.IsRecurring,
                RecurringCycleLength             = product.RecurringCycleLength,
                RecurringCyclePeriod             = product.RecurringCyclePeriod,
                RecurringTotalCycles             = product.RecurringTotalCycles,
                IsShipEnabled                    = product.IsShipEnabled,
                IsFreeShipping                   = product.IsFreeShipping,
                AdditionalShippingCharge         = product.AdditionalShippingCharge,
                IsEsd                            = product.IsEsd,
                IsTaxExempt                      = product.IsTaxExempt,
                TaxCategoryId                    = product.TaxCategoryId,
                ManageInventoryMethod            = product.ManageInventoryMethod,
                StockQuantity                    = product.StockQuantity,
                DisplayStockAvailability         = product.DisplayStockAvailability,
                DisplayStockQuantity             = product.DisplayStockQuantity,
                MinStockQuantity                 = product.MinStockQuantity,
                LowStockActivityId               = product.LowStockActivityId,
                NotifyAdminForQuantityBelow      = product.NotifyAdminForQuantityBelow,
                BackorderMode                    = product.BackorderMode,
                AllowBackInStockSubscriptions    = product.AllowBackInStockSubscriptions,
                OrderMinimumQuantity             = product.OrderMinimumQuantity,
                OrderMaximumQuantity             = product.OrderMaximumQuantity,
                HideQuantityControl              = product.HideQuantityControl,
                AllowedQuantities                = product.AllowedQuantities,
                DisableBuyButton                 = product.DisableBuyButton,
                DisableWishlistButton            = product.DisableWishlistButton,
                AvailableForPreOrder             = product.AvailableForPreOrder,
                CallForPrice                     = product.CallForPrice,
                Price                            = product.Price,
                OldPrice                         = product.OldPrice,
                ProductCost                      = product.ProductCost,
                SpecialPrice                     = product.SpecialPrice,
                SpecialPriceStartDateTimeUtc     = product.SpecialPriceStartDateTimeUtc,
                SpecialPriceEndDateTimeUtc       = product.SpecialPriceEndDateTimeUtc,
                CustomerEntersPrice              = product.CustomerEntersPrice,
                MinimumCustomerEnteredPrice      = product.MinimumCustomerEnteredPrice,
                MaximumCustomerEnteredPrice      = product.MaximumCustomerEnteredPrice,
                LowestAttributeCombinationPrice  = product.LowestAttributeCombinationPrice,
                Weight                           = product.Weight,
                Length                           = product.Length,
                Width                            = product.Width,
                Height                           = product.Height,
                AvailableStartDateTimeUtc        = product.AvailableStartDateTimeUtc,
                AvailableEndDateTimeUtc          = product.AvailableEndDateTimeUtc,
                DisplayOrder                     = product.DisplayOrder,
                Published                        = isPublished,
                Deleted                          = product.Deleted,
                DeliveryTimeId                   = product.DeliveryTimeId,
                QuantityUnitId                   = product.QuantityUnitId,
                BasePriceEnabled                 = product.BasePriceEnabled,
                BasePriceMeasureUnit             = product.BasePriceMeasureUnit,
                BasePriceAmount                  = product.BasePriceAmount,
                BasePriceBaseAmount              = product.BasePriceBaseAmount,
                BundleTitleText                  = product.BundleTitleText,
                BundlePerItemShipping            = product.BundlePerItemShipping,
                BundlePerItemPricing             = product.BundlePerItemPricing,
                BundlePerItemShoppingCart        = product.BundlePerItemShoppingCart,
                CustomsTariffNumber              = product.CustomsTariffNumber,
                CountryOfOriginId                = product.CountryOfOriginId
            };

            _productService.InsertProduct(productCopy);

            //search engine name
            _urlRecordService.SaveSlug(productCopy, productCopy.ValidateSeName("", productCopy.Name, true), 0);

            var languages = _languageService.GetAllLanguages(true);

            //localization
            foreach (var lang in languages)
            {
                var name = product.GetLocalized(x => x.Name, lang.Id, false, false);
                if (!String.IsNullOrEmpty(name))
                {
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.Name, name, lang.Id);
                }

                var shortDescription = product.GetLocalized(x => x.ShortDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(shortDescription))
                {
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.ShortDescription, shortDescription, lang.Id);
                }

                var fullDescription = product.GetLocalized(x => x.FullDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(fullDescription))
                {
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.FullDescription, fullDescription, lang.Id);
                }

                var metaKeywords = product.GetLocalized(x => x.MetaKeywords, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaKeywords))
                {
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaKeywords, metaKeywords, lang.Id);
                }

                var metaDescription = product.GetLocalized(x => x.MetaDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaDescription))
                {
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaDescription, metaDescription, lang.Id);
                }

                var metaTitle = product.GetLocalized(x => x.MetaTitle, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaTitle))
                {
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaTitle, metaTitle, lang.Id);
                }

                var bundleTitleText = product.GetLocalized(x => x.BundleTitleText, lang.Id, false, false);
                if (!String.IsNullOrEmpty(bundleTitleText))
                {
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.BundleTitleText, bundleTitleText, lang.Id);
                }

                //search engine name
                _urlRecordService.SaveSlug(productCopy, productCopy.ValidateSeName("", name, false), lang.Id);
            }

            // product pictures
            if (copyImages)
            {
                foreach (var productPicture in product.ProductPictures)
                {
                    var picture     = productPicture.Picture;
                    var pictureCopy = _pictureService.InsertPicture(
                        _pictureService.LoadPictureBinary(picture),
                        picture.MimeType,
                        _pictureService.GetPictureSeName(newName),
                        true,
                        false,
                        false);

                    _productService.InsertProductPicture(new ProductPicture
                    {
                        ProductId    = productCopy.Id,
                        PictureId    = pictureCopy.Id,
                        DisplayOrder = productPicture.DisplayOrder
                    });
                }
            }

            // product <-> categories mappings
            foreach (var productCategory in product.ProductCategories)
            {
                var productCategoryCopy = new ProductCategory
                {
                    ProductId         = productCopy.Id,
                    CategoryId        = productCategory.CategoryId,
                    IsFeaturedProduct = productCategory.IsFeaturedProduct,
                    DisplayOrder      = productCategory.DisplayOrder
                };

                _categoryService.InsertProductCategory(productCategoryCopy);
            }

            // product <-> manufacturers mappings
            foreach (var productManufacturers in product.ProductManufacturers)
            {
                var productManufacturerCopy = new ProductManufacturer
                {
                    ProductId         = productCopy.Id,
                    ManufacturerId    = productManufacturers.ManufacturerId,
                    IsFeaturedProduct = productManufacturers.IsFeaturedProduct,
                    DisplayOrder      = productManufacturers.DisplayOrder
                };

                _manufacturerService.InsertProductManufacturer(productManufacturerCopy);
            }

            // product <-> releated products mappings
            foreach (var relatedProduct in _productService.GetRelatedProductsByProductId1(product.Id, true))
            {
                _productService.InsertRelatedProduct(new RelatedProduct
                {
                    ProductId1   = productCopy.Id,
                    ProductId2   = relatedProduct.ProductId2,
                    DisplayOrder = relatedProduct.DisplayOrder
                });
            }

            // product <-> cross sells mappings
            foreach (var csProduct in _productService.GetCrossSellProductsByProductId1(product.Id, true))
            {
                _productService.InsertCrossSellProduct(new CrossSellProduct
                {
                    ProductId1 = productCopy.Id,
                    ProductId2 = csProduct.ProductId2,
                });
            }

            // product specifications
            foreach (var productSpecificationAttribute in product.ProductSpecificationAttributes)
            {
                var psaCopy = new ProductSpecificationAttribute
                {
                    ProductId = productCopy.Id,
                    SpecificationAttributeOptionId = productSpecificationAttribute.SpecificationAttributeOptionId,
                    AllowFiltering    = productSpecificationAttribute.AllowFiltering,
                    ShowOnProductPage = productSpecificationAttribute.ShowOnProductPage,
                    DisplayOrder      = productSpecificationAttribute.DisplayOrder
                };

                _specificationAttributeService.InsertProductSpecificationAttribute(psaCopy);
            }

            //store mapping
            var selectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(product);

            foreach (var id in selectedStoreIds)
            {
                _storeMappingService.InsertStoreMapping(productCopy, id);
            }

            // product <-> attributes mappings
            var associatedAttributes      = new Dictionary <int, int>();
            var associatedAttributeValues = new Dictionary <int, int>();

            foreach (var productVariantAttribute in _productAttributeService.GetProductVariantAttributesByProductId(product.Id))
            {
                var productVariantAttributeCopy = new ProductVariantAttribute
                {
                    ProductId              = productCopy.Id,
                    ProductAttributeId     = productVariantAttribute.ProductAttributeId,
                    TextPrompt             = productVariantAttribute.TextPrompt,
                    IsRequired             = productVariantAttribute.IsRequired,
                    AttributeControlTypeId = productVariantAttribute.AttributeControlTypeId,
                    DisplayOrder           = productVariantAttribute.DisplayOrder
                };

                _productAttributeService.InsertProductVariantAttribute(productVariantAttributeCopy);
                //save associated value (used for combinations copying)
                associatedAttributes.Add(productVariantAttribute.Id, productVariantAttributeCopy.Id);

                // product variant attribute values
                var productVariantAttributeValues = _productAttributeService.GetProductVariantAttributeValues(productVariantAttribute.Id);

                foreach (var productVariantAttributeValue in productVariantAttributeValues)
                {
                    var pvavCopy = new ProductVariantAttributeValue
                    {
                        ProductVariantAttributeId = productVariantAttributeCopy.Id,
                        Name             = productVariantAttributeValue.Name,
                        Color            = productVariantAttributeValue.Color,
                        PriceAdjustment  = productVariantAttributeValue.PriceAdjustment,
                        WeightAdjustment = productVariantAttributeValue.WeightAdjustment,
                        IsPreSelected    = productVariantAttributeValue.IsPreSelected,
                        DisplayOrder     = productVariantAttributeValue.DisplayOrder,
                        ValueTypeId      = productVariantAttributeValue.ValueTypeId,
                        LinkedProductId  = productVariantAttributeValue.LinkedProductId,
                        Quantity         = productVariantAttributeValue.Quantity,
                    };

                    _productAttributeService.InsertProductVariantAttributeValue(pvavCopy);

                    //save associated value (used for combinations copying)
                    associatedAttributeValues.Add(productVariantAttributeValue.Id, pvavCopy.Id);

                    //localization
                    foreach (var lang in languages)
                    {
                        var name = productVariantAttributeValue.GetLocalized(x => x.Name, lang.Id, false, false);
                        if (!String.IsNullOrEmpty(name))
                        {
                            _localizedEntityService.SaveLocalizedValue(pvavCopy, x => x.Name, name, lang.Id);
                        }
                    }
                }
            }

            // attribute combinations
            using (var scope = new DbContextScope(lazyLoading: false, forceNoTracking: false))
            {
                scope.LoadCollection(product, (Product p) => p.ProductVariantAttributeCombinations);
            }

            foreach (var combination in product.ProductVariantAttributeCombinations)
            {
                //generate new AttributesXml according to new value IDs
                string newAttributesXml = "";
                var    parsedProductVariantAttributes = _productAttributeParser.ParseProductVariantAttributes(combination.AttributesXml);
                foreach (var oldPva in parsedProductVariantAttributes)
                {
                    if (associatedAttributes.ContainsKey(oldPva.Id))
                    {
                        int newPvaId = associatedAttributes[oldPva.Id];
                        var newPva   = _productAttributeService.GetProductVariantAttributeById(newPvaId);
                        if (newPva != null)
                        {
                            var oldPvaValuesStr = _productAttributeParser.ParseValues(combination.AttributesXml, oldPva.Id);
                            foreach (var oldPvaValueStr in oldPvaValuesStr)
                            {
                                if (newPva.ShouldHaveValues())
                                {
                                    //attribute values
                                    int oldPvaValue = int.Parse(oldPvaValueStr);
                                    if (associatedAttributeValues.ContainsKey(oldPvaValue))
                                    {
                                        int newPvavId = associatedAttributeValues[oldPvaValue];
                                        var newPvav   = _productAttributeService.GetProductVariantAttributeValueById(newPvavId);
                                        if (newPvav != null)
                                        {
                                            newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, newPva, newPvav.Id.ToString());
                                        }
                                    }
                                }
                                else
                                {
                                    //just a text
                                    newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, newPva, oldPvaValueStr);
                                }
                            }
                        }
                    }
                }
                var combinationCopy = new ProductVariantAttributeCombination
                {
                    ProductId             = productCopy.Id,
                    AttributesXml         = newAttributesXml,
                    StockQuantity         = combination.StockQuantity,
                    AllowOutOfStockOrders = combination.AllowOutOfStockOrders,

                    // SmartStore extension
                    Sku  = combination.Sku,
                    Gtin = combination.Gtin,
                    ManufacturerPartNumber = combination.ManufacturerPartNumber,
                    Price = combination.Price,
                    AssignedPictureIds = copyImages ? combination.AssignedPictureIds : null,
                    Length             = combination.Length,
                    Width               = combination.Width,
                    Height              = combination.Height,
                    BasePriceAmount     = combination.BasePriceAmount,
                    BasePriceBaseAmount = combination.BasePriceBaseAmount,
                    DeliveryTimeId      = combination.DeliveryTimeId,
                    QuantityUnitId      = combination.QuantityUnitId,
                    IsActive            = combination.IsActive
                                          //IsDefaultCombination = combination.IsDefaultCombination
                };
                _productAttributeService.InsertProductVariantAttributeCombination(combinationCopy);
            }

            // tier prices
            foreach (var tierPrice in product.TierPrices)
            {
                _productService.InsertTierPrice(new TierPrice
                {
                    ProductId      = productCopy.Id,
                    StoreId        = tierPrice.StoreId,
                    CustomerRoleId = tierPrice.CustomerRoleId,
                    Quantity       = tierPrice.Quantity,
                    Price          = tierPrice.Price
                });
            }

            // product <-> discounts mapping
            foreach (var discount in product.AppliedDiscounts)
            {
                productCopy.AppliedDiscounts.Add(discount);
                _productService.UpdateProduct(productCopy);
            }

            // update "HasTierPrices" and "HasDiscountsApplied" properties
            _productService.UpdateHasTierPricesProperty(productCopy);
            _productService.UpdateLowestAttributeCombinationPriceProperty(productCopy);
            _productService.UpdateHasDiscountsApplied(productCopy);

            // associated products
            if (copyAssociatedProducts && product.ProductType != ProductType.BundledProduct)
            {
                var copyOf      = _localizationService.GetResource("Admin.Common.CopyOf");
                var searchQuery = new CatalogSearchQuery()
                                  .HasParentGroupedProduct(product.Id);

                var query = _catalogSearchService.PrepareQuery(searchQuery);
                var associatedProducts = query.OrderBy(p => p.DisplayOrder).ToList();

                foreach (var associatedProduct in associatedProducts)
                {
                    var associatedProductCopy = CopyProduct(associatedProduct, $"{copyOf} {associatedProduct.Name}", isPublished, copyImages, false);
                    associatedProductCopy.ParentGroupedProductId = productCopy.Id;

                    _productService.UpdateProduct(productCopy);
                }
            }

            // bundled products
            var bundledItems = _productService.GetBundleItems(product.Id, true);

            foreach (var bundleItem in bundledItems)
            {
                var newBundleItem = bundleItem.Item.Clone();
                newBundleItem.BundleProductId = productCopy.Id;

                _productService.InsertBundleItem(newBundleItem);

                foreach (var itemFilter in bundleItem.Item.AttributeFilters)
                {
                    var newItemFilter = itemFilter.Clone();
                    newItemFilter.BundleItemId = newBundleItem.Id;

                    _productAttributeService.InsertProductBundleItemAttributeFilter(newItemFilter);
                }
            }

            return(productCopy);
        }
        private void AddFacet(
            CatalogSearchQuery query,
            FacetGroupKind kind,
            bool isMultiSelect,
            FacetSorting sorting,
            Action <FacetDescriptor> addValues)
        {
            string fieldName;
            var    displayOrder = 0;

            switch (kind)
            {
            case FacetGroupKind.Category:
                fieldName = _catalogSettings.IncludeFeaturedProductsInNormalLists ? "categoryid" : "notfeaturedcategoryid";
                break;

            case FacetGroupKind.Brand:
                if (_searchSettings.BrandDisabled)
                {
                    return;
                }
                fieldName    = "manufacturerid";
                displayOrder = _searchSettings.BrandDisplayOrder;
                break;

            case FacetGroupKind.Price:
                if (_searchSettings.PriceDisabled || !_services.Permissions.Authorize(StandardPermissionProvider.DisplayPrices))
                {
                    return;
                }
                fieldName    = "price";
                displayOrder = _searchSettings.PriceDisplayOrder;
                break;

            case FacetGroupKind.Rating:
                if (_searchSettings.RatingDisabled)
                {
                    return;
                }
                fieldName    = "rating";
                displayOrder = _searchSettings.RatingDisplayOrder;
                break;

            case FacetGroupKind.DeliveryTime:
                if (_searchSettings.DeliveryTimeDisabled)
                {
                    return;
                }
                fieldName    = "deliveryid";
                displayOrder = _searchSettings.DeliveryTimeDisplayOrder;
                break;

            case FacetGroupKind.Availability:
                if (_searchSettings.AvailabilityDisabled)
                {
                    return;
                }
                fieldName    = "available";
                displayOrder = _searchSettings.AvailabilityDisplayOrder;
                break;

            case FacetGroupKind.NewArrivals:
                if (_searchSettings.NewArrivalsDisabled)
                {
                    return;
                }
                fieldName    = "createdon";
                displayOrder = _searchSettings.NewArrivalsDisplayOrder;
                break;

            default:
                throw new SmartException($"Unknown field name for facet group '{kind.ToString()}'");
            }

            var descriptor = new FacetDescriptor(fieldName);

            descriptor.Label           = _services.Localization.GetResource(FacetUtility.GetLabelResourceKey(kind) ?? kind.ToString());
            descriptor.IsMultiSelect   = isMultiSelect;
            descriptor.DisplayOrder    = displayOrder;
            descriptor.OrderBy         = sorting;
            descriptor.MinHitCount     = _searchSettings.FilterMinHitCount;
            descriptor.MaxChoicesCount = _searchSettings.FilterMaxChoicesCount;

            addValues(descriptor);
            query.WithFacet(descriptor);
        }
        private int GetPageSize(CatalogSearchQuery query, RouteData routeData, string origin)
        {
            string entityViewMode = null;

            // Determine entity id if possible
            IPagingOptions entity = null;
            int?           entityId;

            if (origin.IsCaseInsensitiveEqual("Catalog/Category"))
            {
                entityId = (int?)routeData.Values["categoryId"];
                if (entityId.HasValue)
                {
                    entity         = _services.Resolve <ICategoryService>().GetCategoryById(entityId.Value) as IPagingOptions;
                    entityViewMode = ((Category)entity)?.DefaultViewMode;
                }
            }
            else if (origin.IsCaseInsensitiveEqual("Catalog/Manufacturer"))
            {
                entityId = (int?)routeData.Values["manufacturerId"];
                if (entityId.HasValue)
                {
                    entity = _services.Resolve <IManufacturerService>().GetManufacturerById(entityId.Value) as IPagingOptions;
                }
            }

            var entitySize = entity?.PageSize;

            var sessionKey = origin;

            if (entitySize.HasValue)
            {
                sessionKey += "/" + entitySize.Value;
            }

            DetectViewMode(query, sessionKey, entityViewMode);

            var allowChange = entity?.AllowCustomersToSelectPageSize ?? _catalogSettings.AllowCustomersToSelectPageSize;

            if (!allowChange)
            {
                return(entitySize ?? _catalogSettings.DefaultProductListPageSize);
            }

            sessionKey = "PageSize:" + sessionKey;

            // Get from form or query
            var selectedSize = GetValueFor <int?>("s");

            if (selectedSize.HasValue)
            {
                // Save the selection in session. We'll fetch this session value
                // on subsequent requests for this route.
                if (_httpContext.Session != null)
                {
                    _httpContext.Session[sessionKey] = selectedSize.Value;
                }
                return(selectedSize.Value);
            }

            // Return user size from session
            if (_httpContext.Session != null)
            {
                var sessionSize = _httpContext.Session[sessionKey].Convert <int?>();
                if (sessionSize.HasValue)
                {
                    return(sessionSize.Value);
                }
            }

            // Return default size for entity (IPagingOptions)
            if (entitySize.HasValue)
            {
                return(entitySize.Value);
            }

            // Return default page size
            return(_catalogSettings.DefaultProductListPageSize);
        }
示例#16
0
        public virtual async Task <(int AffectedCategories, int AffectedProducts)> InheritStoresIntoChildrenAsync(
            int categoryId,
            bool touchProductsWithMultipleCategories = false,
            bool touchExistingAcls = false,
            bool categoriesOnly    = false)
        {
            var categoryEntityName = nameof(Category);
            var productEntityName  = nameof(Product);
            var affectedCategories = 0;
            var affectedProducts   = 0;

            var allStoreIds = await _db.Stores
                              .AsQueryable()
                              .Select(x => x.Id)
                              .ToListAsync();

            var referenceCategory = await _db.Categories.FindByIdAsync(categoryId);

            var referenceStoreMappingIds = await _storeMappingService.GetAuthorizedStoreIdsAsync(referenceCategory);

            using (var scope = new DbContextScope(_db, autoDetectChanges: false))
            {
                await ProcessCategory(scope, referenceCategory);
            }

            _cache.RemoveByPattern(StoreMappingService.STOREMAPPING_SEGMENT_PATTERN);

            return(affectedCategories, affectedProducts);

            async Task ProcessCategory(DbContextScope scope, Category c)
            {
                // Process sub-categories.
                var subCategories = await _db.Categories
                                    .AsQueryable()
                                    .Where(x => x.ParentCategoryId == c.Id)
                                    .OrderBy(x => x.DisplayOrder)
                                    .ToListAsync();

                foreach (var subCategory in subCategories)
                {
                    if (subCategory.LimitedToStores != referenceCategory.LimitedToStores)
                    {
                        subCategory.LimitedToStores = referenceCategory.LimitedToStores;
                    }

                    var storeMappings = await _db.StoreMappings
                                        .ApplyEntityFilter(subCategory)
                                        .ToListAsync();

                    var storeMappingsDic = storeMappings.ToDictionarySafe(x => x.StoreId);

                    foreach (var storeId in allStoreIds)
                    {
                        if (referenceStoreMappingIds.Contains(storeId))
                        {
                            if (!storeMappingsDic.ContainsKey(storeId))
                            {
                                _db.StoreMappings.Add(new StoreMapping {
                                    StoreId = storeId, EntityId = subCategory.Id, EntityName = categoryEntityName
                                });
                            }
                        }
                        else if (storeMappingsDic.TryGetValue(storeId, out var storeMappingToDelete))
                        {
                            _db.StoreMappings.Remove(storeMappingToDelete);
                        }
                    }
                }

                await scope.CommitAsync();

                affectedCategories += subCategories.Count;

                // Process products.
                var categoryIds = new HashSet <int>(subCategories.Select(x => x.Id))
                {
                    c.Id
                };

                var searchQuery   = new CatalogSearchQuery().WithCategoryIds(null, categoryIds.ToArray());
                var productsQuery = _catalogSearchService.PrepareQuery(searchQuery);
                var productsPager = new FastPager <Product>(productsQuery, 500);

                while ((await productsPager.ReadNextPageAsync <Product>()).Out(out var products))
                {
                    foreach (var product in products)
                    {
                        if (product.LimitedToStores != referenceCategory.LimitedToStores)
                        {
                            product.LimitedToStores = referenceCategory.LimitedToStores;
                        }

                        var storeMappings = await _db.StoreMappings
                                            .ApplyEntityFilter(product)
                                            .ToListAsync();

                        var storeMappingsDic = storeMappings.ToDictionarySafe(x => x.StoreId);

                        foreach (var storeId in allStoreIds)
                        {
                            if (referenceStoreMappingIds.Contains(storeId))
                            {
                                if (!storeMappingsDic.ContainsKey(storeId))
                                {
                                    _db.StoreMappings.Add(new StoreMapping {
                                        StoreId = storeId, EntityId = product.Id, EntityName = productEntityName
                                    });
                                }
                            }
                            else if (storeMappingsDic.TryGetValue(storeId, out var storeMappingToDelete))
                            {
                                _db.StoreMappings.Remove(storeMappingToDelete);
                            }
                        }
                    }

                    await scope.CommitAsync();

                    affectedProducts += products.Count;
                }

                await scope.CommitAsync();

                try
                {
                    scope.DbContext.DetachEntities(x => x is Product || x is Category || x is StoreMapping, false);
                }
                catch { }

                foreach (var subCategory in subCategories)
                {
                    await ProcessCategory(scope, subCategory);
                }
            }
        }
示例#17
0
        public virtual void InheritStoresIntoChildren(
            int categoryId,
            bool touchProductsWithMultipleCategories = false,
            bool touchExistingAcls = false,
            bool categoriesOnly    = false)
        {
            var allStores              = _storeService.GetAllStores();
            var referenceCategory      = GetCategoryById(categoryId);
            var referenceStoreMappings = _storeMappingService.GetStoresIdsWithAccess(referenceCategory);

            using (var scope = new DbContextScope(ctx: _storeMappingRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                ProcessCategory(scope, referenceCategory);
            }

            _cache.RemoveByPattern(StoreMappingService.STOREMAPPING_SEGMENT_PATTERN);


            void ProcessCategory(DbContextScope scope, Category c)
            {
                // Process sub-categories.
                var subCategories = GetAllCategoriesByParentCategoryId(c.Id, true);

                foreach (var subCategory in subCategories)
                {
                    if (subCategory.LimitedToStores != referenceCategory.LimitedToStores)
                    {
                        subCategory.LimitedToStores = referenceCategory.LimitedToStores;
                        _categoryRepository.Update(subCategory);
                    }

                    var existingStoreMappingsRecords = _storeMappingService.GetStoreMappings(subCategory).ToDictionary(x => x.StoreId);

                    foreach (var store in allStores)
                    {
                        if (referenceStoreMappings.Contains(store.Id))
                        {
                            if (!existingStoreMappingsRecords.ContainsKey(store.Id))
                            {
                                _storeMappingRepository.Insert(new StoreMapping {
                                    StoreId = store.Id, EntityId = subCategory.Id, EntityName = "Category"
                                });
                            }
                        }
                        else if (existingStoreMappingsRecords.TryGetValue(store.Id, out var storeMappingToDelete))
                        {
                            _storeMappingRepository.Delete(storeMappingToDelete);
                        }
                    }
                }

                scope.Commit();

                // Process products.
                var categoryIds = new HashSet <int>(subCategories.Select(x => x.Id));

                categoryIds.Add(c.Id);

                var searchQuery   = new CatalogSearchQuery().WithCategoryIds(null, categoryIds.ToArray());
                var productsQuery = _catalogSearchService.PrepareQuery(searchQuery);
                var productsPager = new FastPager <Product>(productsQuery, 500);

                while (productsPager.ReadNextPage(out var products))
                {
                    foreach (var product in products)
                    {
                        if (product.LimitedToStores != referenceCategory.LimitedToStores)
                        {
                            product.LimitedToStores = referenceCategory.LimitedToStores;
                            _productRepository.Update(product);
                        }

                        var existingStoreMappingsRecords = _storeMappingService.GetStoreMappings(product).ToDictionary(x => x.StoreId);

                        foreach (var store in allStores)
                        {
                            if (referenceStoreMappings.Contains(store.Id))
                            {
                                if (!existingStoreMappingsRecords.ContainsKey(store.Id))
                                {
                                    _storeMappingRepository.Insert(new StoreMapping {
                                        StoreId = store.Id, EntityId = product.Id, EntityName = "Product"
                                    });
                                }
                            }
                            else if (existingStoreMappingsRecords.TryGetValue(store.Id, out var storeMappingToDelete))
                            {
                                _storeMappingRepository.Delete(storeMappingToDelete);
                            }
                        }
                    }

                    scope.Commit();
                }

                scope.Commit();

                try
                {
                    scope.DbContext.DetachEntities(x => x is Product || x is Category || x is StoreMapping, false);
                }
                catch { }

                foreach (var subCategory in subCategories)
                {
                    ProcessCategory(scope, subCategory);
                }
            }
        }
示例#18
0
        public ActionResult Picker(EntityPickerModel model, FormCollection form)
        {
            try
            {
                var languageId = model.LanguageId == 0 ? Services.WorkContext.WorkingLanguage.Id : model.LanguageId;
                var disableIf  = model.DisableIf.SplitSafe(",").Select(x => x.ToLower().Trim()).ToList();
                var disableIds = model.DisableIds.SplitSafe(",").Select(x => x.ToInt()).ToList();
                var selected   = model.Selected.SplitSafe(",");
                var returnSku  = model.ReturnField.IsCaseInsensitiveEqual("sku");

                using (var scope = new DbContextScope(Services.DbContext, autoDetectChanges: false, proxyCreation: true, validateOnSave: false, forceNoTracking: true))
                {
                    if (model.EntityType.IsCaseInsensitiveEqual("product"))
                    {
                        model.SearchTerm = model.SearchTerm.TrimSafe();

                        var hasPermission             = Services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog);
                        var disableIfNotSimpleProduct = disableIf.Contains("notsimpleproduct");
                        var disableIfGroupedProduct   = disableIf.Contains("groupedproduct");
                        var labelTextGrouped          = T("Admin.Catalog.Products.ProductType.GroupedProduct.Label").Text;
                        var labelTextBundled          = T("Admin.Catalog.Products.ProductType.BundledProduct.Label").Text;
                        var sku = T("Products.Sku").Text;

                        var fields = new List <string> {
                            "name"
                        };
                        if (_searchSettings.SearchFields.Contains("sku"))
                        {
                            fields.Add("sku");
                        }
                        if (_searchSettings.SearchFields.Contains("shortdescription"))
                        {
                            fields.Add("shortdescription");
                        }

                        var searchQuery = new CatalogSearchQuery(fields.ToArray(), model.SearchTerm)
                                          .HasStoreId(model.StoreId);

                        if (!hasPermission)
                        {
                            searchQuery = searchQuery.VisibleOnly(Services.WorkContext.CurrentCustomer);
                        }

                        if (model.ProductTypeId > 0)
                        {
                            searchQuery = searchQuery.IsProductType((ProductType)model.ProductTypeId);
                        }

                        if (model.ManufacturerId != 0)
                        {
                            searchQuery = searchQuery.WithManufacturerIds(null, model.ManufacturerId);
                        }

                        if (model.CategoryId != 0)
                        {
                            var node = _categoryService.GetCategoryTree(model.CategoryId, true);
                            if (node != null)
                            {
                                searchQuery = searchQuery.WithCategoryIds(null, node.Flatten(true).Select(x => x.Id).ToArray());
                            }
                        }

                        var skip  = model.PageIndex * model.PageSize;
                        var query = _catalogSearchService.PrepareQuery(searchQuery);

                        var products = query
                                       .Select(x => new
                        {
                            x.Id,
                            x.Sku,
                            x.Name,
                            x.Published,
                            x.ProductTypeId,
                            x.MainPictureId
                        })
                                       .OrderBy(x => x.Name)
                                       .Skip(() => skip)
                                       .Take(() => model.PageSize)
                                       .ToList();

                        var allPictureIds   = products.Select(x => x.MainPictureId.GetValueOrDefault());
                        var allPictureInfos = _pictureService.GetPictureInfos(allPictureIds);

                        model.SearchResult = products
                                             .Select(x =>
                        {
                            var item = new EntityPickerModel.SearchResultModel
                            {
                                Id           = x.Id,
                                Title        = x.Name,
                                Summary      = x.Sku,
                                SummaryTitle = "{0}: {1}".FormatInvariant(sku, x.Sku.NaIfEmpty()),
                                Published    = hasPermission ? x.Published : (bool?)null,
                                ReturnValue  = returnSku ? x.Sku : x.Id.ToString()
                            };

                            item.Selected = selected.Contains(item.ReturnValue);

                            if (disableIfNotSimpleProduct)
                            {
                                item.Disable = x.ProductTypeId != (int)ProductType.SimpleProduct;
                            }
                            else if (disableIfGroupedProduct)
                            {
                                item.Disable = x.ProductTypeId == (int)ProductType.GroupedProduct;
                            }

                            if (!item.Disable && disableIds.Contains(x.Id))
                            {
                                item.Disable = true;
                            }

                            if (x.ProductTypeId == (int)ProductType.GroupedProduct)
                            {
                                item.LabelText      = labelTextGrouped;
                                item.LabelClassName = "badge-success";
                            }
                            else if (x.ProductTypeId == (int)ProductType.BundledProduct)
                            {
                                item.LabelText      = labelTextBundled;
                                item.LabelClassName = "badge-info";
                            }

                            var pictureInfo  = allPictureInfos.Get(x.MainPictureId.GetValueOrDefault());
                            var fallbackType = _catalogSettings.HideProductDefaultPictures ? FallbackPictureType.NoFallback : FallbackPictureType.Entity;

                            item.ImageUrl = _pictureService.GetUrl(
                                allPictureInfos.Get(x.MainPictureId.GetValueOrDefault()),
                                _mediaSettings.ProductThumbPictureSizeOnProductDetailsPage,
                                fallbackType);

                            return(item);
                        })
                                             .ToList();
                    }
                    else if (model.EntityType.IsCaseInsensitiveEqual("category"))
                    {
                        var categories      = _categoryService.GetAllCategories(model.SearchTerm, showHidden: true);
                        var allPictureIds   = categories.Select(x => x.PictureId.GetValueOrDefault());
                        var allPictureInfos = _pictureService.GetPictureInfos(allPictureIds);

                        model.SearchResult = categories
                                             .Select(x =>
                        {
                            var path = ((ICategoryNode)x).GetCategoryPath(_categoryService, languageId, "({0})");
                            var item = new EntityPickerModel.SearchResultModel
                            {
                                Id           = x.Id,
                                Title        = x.Name,
                                Summary      = path,
                                SummaryTitle = path,
                                Published    = x.Published,
                                ReturnValue  = x.Id.ToString(),
                                Selected     = selected.Contains(x.Id.ToString()),
                                Disable      = disableIds.Contains(x.Id)
                            };

                            if (x.Alias.HasValue())
                            {
                                item.LabelText      = x.Alias;
                                item.LabelClassName = "badge-secondary";
                            }

                            var pictureInfo  = allPictureInfos.Get(x.PictureId.GetValueOrDefault());
                            var fallbackType = _catalogSettings.HideProductDefaultPictures ? FallbackPictureType.NoFallback : FallbackPictureType.Entity;

                            item.ImageUrl = _pictureService.GetUrl(
                                allPictureInfos.Get(x.PictureId.GetValueOrDefault()),
                                _mediaSettings.ProductThumbPictureSizeOnProductDetailsPage,
                                fallbackType);

                            return(item);
                        })
                                             .ToList();
                    }
                    else if (model.EntityType.IsCaseInsensitiveEqual("manufacturer"))
                    {
                        var manufacturers   = _manufacturerService.GetAllManufacturers(model.SearchTerm, model.PageIndex, model.PageSize, showHidden: true);
                        var allPictureIds   = manufacturers.Select(x => x.PictureId.GetValueOrDefault());
                        var allPictureInfos = _pictureService.GetPictureInfos(allPictureIds);

                        model.SearchResult = manufacturers
                                             .Select(x =>
                        {
                            var item = new EntityPickerModel.SearchResultModel
                            {
                                Id          = x.Id,
                                Title       = x.Name,
                                Published   = x.Published,
                                ReturnValue = x.Id.ToString(),
                                Selected    = selected.Contains(x.Id.ToString()),
                                Disable     = disableIds.Contains(x.Id)
                            };

                            var pictureInfo  = allPictureInfos.Get(x.PictureId.GetValueOrDefault());
                            var fallbackType = _catalogSettings.HideProductDefaultPictures ? FallbackPictureType.NoFallback : FallbackPictureType.Entity;

                            item.ImageUrl = _pictureService.GetUrl(
                                allPictureInfos.Get(x.PictureId.GetValueOrDefault()),
                                _mediaSettings.ProductThumbPictureSizeOnProductDetailsPage,
                                fallbackType);

                            return(item);
                        })
                                             .ToList();
                    }
                    else if (model.EntityType.IsCaseInsensitiveEqual("customer"))
                    {
                        var registeredRoleId         = _customerService.GetCustomerRoleBySystemName("Registered").Id;
                        var searchTermName           = string.Empty;
                        var searchTermEmail          = string.Empty;
                        var searchTermCustomerNumber = string.Empty;

                        if (model.CustomerSearchType.IsCaseInsensitiveEqual("Name"))
                        {
                            searchTermName = model.SearchTerm;
                        }
                        else if (model.CustomerSearchType.IsCaseInsensitiveEqual("Email"))
                        {
                            searchTermEmail = model.SearchTerm;
                        }
                        else if (model.CustomerSearchType.IsCaseInsensitiveEqual("CustomerNumber"))
                        {
                            searchTermCustomerNumber = model.SearchTerm;
                        }

                        var q = new CustomerSearchQuery
                        {
                            SearchTerm      = searchTermName,
                            Email           = searchTermEmail,
                            CustomerNumber  = searchTermCustomerNumber,
                            CustomerRoleIds = new int[] { registeredRoleId },
                            PageIndex       = model.PageIndex,
                            PageSize        = model.PageSize
                        };

                        var customers = _customerService.SearchCustomers(q);

                        model.SearchResult = customers
                                             .Select(x =>
                        {
                            var fullName = x.GetFullName();

                            var item = new EntityPickerModel.SearchResultModel
                            {
                                Id           = x.Id,
                                ReturnValue  = x.Id.ToString(),
                                Title        = x.Username.NullEmpty() ?? x.Email,
                                Summary      = fullName,
                                SummaryTitle = fullName,
                                Published    = true,
                                Selected     = selected.Contains(x.Id.ToString()),
                                Disable      = disableIds.Contains(x.Id)
                            };

                            return(item);
                        })
                                             .ToList();
                    }
                }
            }
            catch (Exception ex)
            {
                NotifyError(ex.ToAllMessages());
            }

            return(PartialView("Picker.List", model));
        }
示例#19
0
        private decimal MapSummaryItemPrice(Product product, ref Product contextProduct, ProductSummaryModel.SummaryItem item, MapProductSummaryItemContext ctx)
        {
            // Returns the final price
            var finalPrice = decimal.Zero;
            var model      = ctx.Model;

            var priceModel = new ProductSummaryModel.PriceModel();

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing && !ctx.BatchContext.ProductBundleItems.FullyLoaded)
            {
                ctx.BatchContext.ProductBundleItems.LoadAll();
            }

            if (product.ProductType == ProductType.GroupedProduct)
            {
                #region Grouped product

                if (ctx.GroupedProducts == null)
                {
                    // One-time batched retrieval of all associated products
                    var searchQuery = new CatalogSearchQuery()
                                      .PublishedOnly(true)
                                      .HasStoreId(ctx.Store.Id)
                                      .HasParentGroupedProduct(ctx.BatchContext.ProductIds.ToArray());

                    // Get all associated products for this batch grouped by ParentGroupedProductId
                    var allAssociatedProducts = _catalogSearchService.Search(searchQuery).Hits
                                                .OrderBy(x => x.ParentGroupedProductId)
                                                .ThenBy(x => x.DisplayOrder);

                    ctx.GroupedProducts = allAssociatedProducts.ToMultimap(x => x.ParentGroupedProductId, x => x);

                    if (ctx.GroupedProducts.Any())
                    {
                        ctx.BatchContext.AppliedDiscounts.Collect(allAssociatedProducts.Select(x => x.Id));
                    }
                }

                var associatedProducts = ctx.GroupedProducts[product.Id];

                priceModel.DisableBuyButton      = true;
                priceModel.DisableWishlistButton = true;
                priceModel.AvailableForPreOrder  = false;

                if (associatedProducts.Count > 0)
                {
                    contextProduct = associatedProducts.OrderBy(x => x.DisplayOrder).First();

                    _services.DisplayControl.Announce(contextProduct);

                    if (ctx.AllowPrices && _catalogSettings.PriceDisplayType != PriceDisplayType.Hide)
                    {
                        decimal?displayPrice       = null;
                        bool    displayFromMessage = false;

                        if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice)
                        {
                            displayPrice = _priceCalculationService.GetPreselectedPrice(contextProduct, ctx.Customer, ctx.BatchContext);
                        }
                        else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes)
                        {
                            displayPrice = _priceCalculationService.GetFinalPrice(contextProduct, null, ctx.Customer, decimal.Zero, false, 1, null, ctx.BatchContext);
                        }
                        else
                        {
                            displayFromMessage = true;
                            displayPrice       = _priceCalculationService.GetLowestPrice(product, ctx.Customer, ctx.BatchContext, associatedProducts, out contextProduct);
                        }

                        if (contextProduct != null && !contextProduct.CustomerEntersPrice)
                        {
                            if (contextProduct.CallForPrice)
                            {
                                priceModel.RegularPriceValue = null;
                                priceModel.PriceValue        = 0;
                                priceModel.RegularPrice      = null;
                                priceModel.Price             = ctx.Resources["Products.CallForPrice"];
                            }
                            else if (displayPrice.HasValue)
                            {
                                // Calculate prices
                                decimal taxRate        = decimal.Zero;
                                decimal oldPriceBase   = _taxService.GetProductPrice(contextProduct, contextProduct.OldPrice, out taxRate);
                                decimal finalPriceBase = _taxService.GetProductPrice(contextProduct, displayPrice.Value, out taxRate);
                                finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, ctx.Currency);

                                priceModel.RegularPriceValue = null;
                                priceModel.PriceValue        = finalPrice;
                                priceModel.RegularPrice      = null;

                                if (displayFromMessage)
                                {
                                    priceModel.Price = String.Format(ctx.Resources["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice));
                                }
                                else
                                {
                                    priceModel.Price = _priceFormatter.FormatPrice(finalPrice);
                                }

                                if (oldPriceBase > 0)
                                {
                                    priceModel.RegularPriceValue = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, ctx.Currency);
                                }

                                priceModel.HasDiscount = (finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero);
                            }
                            else
                            {
                                // Actually it's not possible (we presume that displayPrice always has a value). We never should get here
                                Debug.WriteLine(string.Format("Cannot calculate displayPrice for product #{0}", product.Id));
                            }
                        }
                    }
                }

                #endregion
            }
            else
            {
                #region Simple product

                //add to cart button
                priceModel.DisableBuyButton = product.DisableBuyButton || !ctx.AllowShoppingCart || !ctx.AllowPrices;

                //add to wishlist button
                priceModel.DisableWishlistButton = product.DisableWishlistButton || !ctx.AllowWishlist || !ctx.AllowPrices;

                //pre-order
                priceModel.AvailableForPreOrder = product.AvailableForPreOrder;

                //prices
                if (ctx.AllowPrices && _catalogSettings.PriceDisplayType != PriceDisplayType.Hide && !product.CustomerEntersPrice)
                {
                    if (product.CallForPrice)
                    {
                        // call for price
                        priceModel.RegularPriceValue = null;
                        priceModel.PriceValue        = 0;
                        priceModel.RegularPrice      = null;
                        priceModel.Price             = ctx.Resources["Products.CallForPrice"];
                    }
                    else
                    {
                        //calculate prices
                        bool    displayFromMessage = false;
                        decimal displayPrice       = decimal.Zero;

                        if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice)
                        {
                            displayPrice = _priceCalculationService.GetPreselectedPrice(product, ctx.Customer, ctx.BatchContext);
                        }
                        else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes)
                        {
                            displayPrice = _priceCalculationService.GetFinalPrice(product, null, ctx.Customer, decimal.Zero, false, 1, null, ctx.BatchContext);
                        }
                        else
                        {
                            displayPrice = _priceCalculationService.GetLowestPrice(product, ctx.Customer, ctx.BatchContext, out displayFromMessage);
                        }

                        decimal taxRate        = decimal.Zero;
                        decimal oldPriceBase   = _taxService.GetProductPrice(product, product.OldPrice, out taxRate);
                        decimal finalPriceBase = _taxService.GetProductPrice(product, displayPrice, out taxRate);

                        decimal oldPrice = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, ctx.Currency);
                        finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, ctx.Currency);

                        priceModel.HasDiscount = (finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero);

                        if (displayFromMessage)
                        {
                            priceModel.RegularPriceValue = null;
                            priceModel.RegularPrice      = null;
                            priceModel.Price             = String.Format(ctx.Resources["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice));
                        }
                        else
                        {
                            priceModel.PriceValue = finalPrice;
                            if (priceModel.HasDiscount)
                            {
                                priceModel.RegularPriceValue = oldPrice;
                                priceModel.RegularPrice      = _priceFormatter.FormatPrice(oldPrice);
                                priceModel.Price             = _priceFormatter.FormatPrice(finalPrice);
                            }
                            else
                            {
                                priceModel.RegularPriceValue = null;
                                priceModel.RegularPrice      = null;
                                priceModel.Price             = _priceFormatter.FormatPrice(finalPrice);
                            }
                        }
                    }
                }

                #endregion
            }

            var regularPriceValue = priceModel.RegularPriceValue.GetValueOrDefault();
            if (priceModel.HasDiscount && regularPriceValue > 0 && regularPriceValue > priceModel.PriceValue)
            {
                priceModel.SavingPercent = (float)((priceModel.RegularPriceValue - priceModel.PriceValue) / priceModel.RegularPriceValue) * 100;
                priceModel.SavingAmount  = _priceFormatter.FormatPrice(regularPriceValue - priceModel.PriceValue, true, false);

                if (model.ShowDiscountBadge)
                {
                    item.Badges.Add(new ProductSummaryModel.Badge
                    {
                        Label = T("Products.SavingBadgeLabel", priceModel.SavingPercent.ToString("N0")),
                        Style = BadgeStyle.Danger
                    });
                }
            }

            priceModel.CallForPrice = product.CallForPrice;

            item.Price = priceModel;

            return(finalPrice);
        }
        public ActionResult Manufacturer(int manufacturerId, CatalogSearchQuery query)
        {
            var manufacturer = _manufacturerService.GetManufacturerById(manufacturerId);

            if (manufacturer == null || manufacturer.Deleted)
            {
                return(HttpNotFound());
            }

            // Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a manufacturer before publishing.
            if (!manufacturer.Published && !Services.Permissions.Authorize(Permissions.Catalog.Manufacturer.Read))
            {
                return(HttpNotFound());
            }

            // ACL (access control list).
            if (!_aclService.Authorize(manufacturer))
            {
                return(HttpNotFound());
            }

            // Store mapping.
            if (!_storeMappingService.Authorize(manufacturer))
            {
                return(HttpNotFound());
            }

            var store    = Services.StoreContext.CurrentStore;
            var customer = Services.WorkContext.CurrentCustomer;

            // 'Continue shopping' URL.
            if (!customer.IsSystemAccount)
            {
                _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastContinueShoppingPage, Services.WebHelper.GetThisPageUrl(false), store.Id);
            }

            var model = manufacturer.ToModel();

            if (query.IsSubPage && !_catalogSettings.ShowDescriptionInSubPages)
            {
                model.Description.ChangeValue(string.Empty);
                model.BottomDescription.ChangeValue(string.Empty);
            }

            model.PictureModel = _helper.PrepareManufacturerPictureModel(manufacturer, model.Name);

            // Featured products.
            var hideFeaturedProducts = _catalogSettings.IgnoreFeaturedProducts || (query.IsSubPage && !_catalogSettings.IncludeFeaturedProductsInSubPages);

            if (!hideFeaturedProducts)
            {
                CatalogSearchResult featuredProductsResult = null;

                var customerRolesIds = customer.CustomerRoleMappings
                                       .Select(x => x.CustomerRole)
                                       .Where(x => x.Active)
                                       .Select(x => x.Id)
                                       .ToList();

                var cacheKey = ModelCacheEventConsumer.MANUFACTURER_HAS_FEATURED_PRODUCTS_KEY.FormatInvariant(manufacturerId, string.Join(",", customerRolesIds), store.Id);
                var hasFeaturedProductsCache = Services.Cache.Get <bool?>(cacheKey);

                var featuredProductsQuery = new CatalogSearchQuery()
                                            .VisibleOnly(customer)
                                            .WithVisibility(ProductVisibility.Full)
                                            .WithManufacturerIds(true, manufacturerId)
                                            .HasStoreId(store.Id)
                                            .WithLanguage(Services.WorkContext.WorkingLanguage)
                                            .WithCurrency(Services.WorkContext.WorkingCurrency);

                if (!hasFeaturedProductsCache.HasValue)
                {
                    featuredProductsResult   = _catalogSearchService.Search(featuredProductsQuery);
                    hasFeaturedProductsCache = featuredProductsResult.TotalHitsCount > 0;
                    Services.Cache.Put(cacheKey, hasFeaturedProductsCache, TimeSpan.FromHours(6));
                }

                if (hasFeaturedProductsCache.Value && featuredProductsResult == null)
                {
                    featuredProductsResult = _catalogSearchService.Search(featuredProductsQuery);
                }

                if (featuredProductsResult != null)
                {
                    // TODO: (mc) determine settings properly
                    var featuredProductsmappingSettings = _helper.GetBestFitProductSummaryMappingSettings(ProductSummaryViewMode.Grid);
                    model.FeaturedProducts = _helper.MapProductSummaryModel(featuredProductsResult.Hits, featuredProductsmappingSettings);
                }
            }

            // Products
            query.WithManufacturerIds(_catalogSettings.IncludeFeaturedProductsInNormalLists ? null : (bool?)false, manufacturerId);

            var searchResult = _catalogSearchService.Search(query);

            model.SearchResult = searchResult;

            var mappingSettings = _helper.GetBestFitProductSummaryMappingSettings(query.GetViewMode());

            model.Products = _helper.MapProductSummaryModel(searchResult.Hits, mappingSettings);

            // Prepare paging/sorting/mode stuff
            _helper.MapListActions(model.Products, manufacturer, _catalogSettings.DefaultPageSizeOptions);

            // Template
            var templateCacheKey = string.Format(ModelCacheEventConsumer.MANUFACTURER_TEMPLATE_MODEL_KEY, manufacturer.ManufacturerTemplateId);
            var templateViewPath = Services.Cache.Get(templateCacheKey, () =>
            {
                var template = _manufacturerTemplateService.GetManufacturerTemplateById(manufacturer.ManufacturerTemplateId);
                if (template == null)
                {
                    template = _manufacturerTemplateService.GetAllManufacturerTemplates().FirstOrDefault();
                }
                return(template.ViewPath);
            });

            //activity log
            Services.CustomerActivity.InsertActivity("PublicStore.ViewManufacturer", T("ActivityLog.PublicStore.ViewManufacturer"), manufacturer.Name);

            Services.DisplayControl.Announce(manufacturer);

            return(View(templateViewPath, model));
        }
示例#21
0
        public ActionResult Category(int categoryId, CatalogSearchQuery query)
        {
            var category = _categoryService.GetCategoryById(categoryId);

            if (category == null || category.Deleted)
            {
                return(HttpNotFound());
            }

            // Check whether the current user has a "Manage catalog" permission
            // It allows him to preview a category before publishing
            if (!category.Published && !_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog))
            {
                return(HttpNotFound());
            }

            // ACL (access control list)
            if (!_aclService.Authorize(category))
            {
                return(HttpNotFound());
            }

            // Store mapping
            if (!_storeMappingService.Authorize(category))
            {
                return(HttpNotFound());
            }

            // 'Continue shopping' URL
            if (!_services.WorkContext.CurrentCustomer.IsSystemAccount)
            {
                _genericAttributeService.SaveAttribute(_services.WorkContext.CurrentCustomer,
                                                       SystemCustomerAttributeNames.LastContinueShoppingPage,
                                                       _services.WebHelper.GetThisPageUrl(false),
                                                       _services.StoreContext.CurrentStore.Id);
            }

            var model = category.ToModel();

            _services.DisplayControl.Announce(category);

            // Category breadcrumb
            if (_catalogSettings.CategoryBreadcrumbEnabled)
            {
                _helper.GetCategoryBreadCrumb(category.Id, 0).Select(x => x.Value).Each(x => _breadcrumb.Track(x));
            }

            model.SubCategoryDisplayType = _catalogSettings.SubCategoryDisplayType;

            var customerRolesIds = _services.WorkContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList();

            // subcategories
            model.SubCategories = _categoryService
                                  .GetAllCategoriesByParentCategoryId(categoryId)
                                  .Select(x =>
            {
                var subCatName  = x.GetLocalized(y => y.Name);
                var subCatModel = new CategoryModel.SubCategoryModel
                {
                    Id     = x.Id,
                    Name   = subCatName,
                    SeName = x.GetSeName(),
                };

                _services.DisplayControl.Announce(x);

                // prepare picture model
                int pictureSize             = _mediaSettings.CategoryThumbPictureSize;
                var categoryPictureCacheKey = string.Format(ModelCacheEventConsumer.CATEGORY_PICTURE_MODEL_KEY, x.Id, pictureSize, true, _services.WorkContext.WorkingLanguage.Id, _services.StoreContext.CurrentStore.Id);
                subCatModel.PictureModel    = _services.Cache.Get(categoryPictureCacheKey, () =>
                {
                    var picture      = _pictureService.GetPictureById(x.PictureId.GetValueOrDefault());
                    var pictureModel = new PictureModel
                    {
                        PictureId           = x.PictureId.GetValueOrDefault(),
                        Size                = pictureSize,
                        FullSizeImageUrl    = _pictureService.GetPictureUrl(picture),
                        FullSizeImageWidth  = picture?.Width,
                        FullSizeImageHeight = picture?.Height,
                        ImageUrl            = _pictureService.GetPictureUrl(picture, pictureSize, !_catalogSettings.HideCategoryDefaultPictures),
                        Title               = string.Format(T("Media.Category.ImageLinkTitleFormat"), subCatName),
                        AlternateText       = string.Format(T("Media.Category.ImageAlternateTextFormat"), subCatName)
                    };

                    return(pictureModel);
                }, TimeSpan.FromHours(6));

                return(subCatModel);
            })
                                  .ToList();

            // Featured Products
            if (!_catalogSettings.IgnoreFeaturedProducts)
            {
                CatalogSearchResult featuredProductsResult = null;

                string cacheKey = ModelCacheEventConsumer.CATEGORY_HAS_FEATURED_PRODUCTS_KEY.FormatInvariant(categoryId, string.Join(",", customerRolesIds), _services.StoreContext.CurrentStore.Id);
                var    hasFeaturedProductsCache = _services.Cache.Get <bool?>(cacheKey);

                var featuredProductsQuery = new CatalogSearchQuery()
                                            .VisibleOnly(_services.WorkContext.CurrentCustomer)
                                            .VisibleIndividuallyOnly(true)
                                            .WithCategoryIds(true, categoryId)
                                            .HasStoreId(_services.StoreContext.CurrentStore.Id)
                                            .WithLanguage(_services.WorkContext.WorkingLanguage)
                                            .WithCurrency(_services.WorkContext.WorkingCurrency);

                if (!hasFeaturedProductsCache.HasValue)
                {
                    featuredProductsResult   = _catalogSearchService.Search(featuredProductsQuery);
                    hasFeaturedProductsCache = featuredProductsResult.TotalHitsCount > 0;
                    _services.Cache.Put(cacheKey, hasFeaturedProductsCache, TimeSpan.FromHours(6));
                }

                if (hasFeaturedProductsCache.Value && featuredProductsResult == null)
                {
                    featuredProductsResult = _catalogSearchService.Search(featuredProductsQuery);
                }

                if (featuredProductsResult != null)
                {
                    var featuredProductsmappingSettings = _helper.GetBestFitProductSummaryMappingSettings(ProductSummaryViewMode.Grid);
                    model.FeaturedProducts = _helper.MapProductSummaryModel(featuredProductsResult.Hits, featuredProductsmappingSettings);
                }
            }

            // Products
            int[] catIds = new int[] { categoryId };
            if (_catalogSettings.ShowProductsFromSubcategories)
            {
                // Include subcategories
                catIds = catIds.Concat(_helper.GetChildCategoryIds(categoryId)).ToArray();
            }

            query.WithCategoryIds(_catalogSettings.IncludeFeaturedProductsInNormalLists ? (bool?)null : false, catIds);

            var searchResult = _catalogSearchService.Search(query);

            model.SearchResult = searchResult;

            var mappingSettings = _helper.GetBestFitProductSummaryMappingSettings(query.GetViewMode());

            model.Products = _helper.MapProductSummaryModel(searchResult.Hits, mappingSettings);

            // Prepare paging/sorting/mode stuff
            _helper.MapListActions(model.Products, category, _catalogSettings.DefaultPageSizeOptions);

            // template
            var templateCacheKey = string.Format(ModelCacheEventConsumer.CATEGORY_TEMPLATE_MODEL_KEY, category.CategoryTemplateId);
            var templateViewPath = _services.Cache.Get(templateCacheKey, () =>
            {
                var template = _categoryTemplateService.GetCategoryTemplateById(category.CategoryTemplateId);
                if (template == null)
                {
                    template = _categoryTemplateService.GetAllCategoryTemplates().FirstOrDefault();
                }
                return(template.ViewPath);
            });

            // Activity log
            _services.CustomerActivity.InsertActivity("PublicStore.ViewCategory", T("ActivityLog.PublicStore.ViewCategory"), category.Name);

            return(View(templateViewPath, model));
        }
 protected virtual void OnConverted(CatalogSearchQuery query, RouteData routeData, string origin)
 {
 }
        public ActionResult RecentlyAddedProductsRss(CatalogSearchQuery query)
        {
            // TODO: (mc) find a more prominent place for the "NewProducts" link (may be in main menu?)
            var protocol           = Services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http";
            var selfLink           = Url.RouteUrl("RecentlyAddedProductsRSS", null, protocol);
            var recentProductsLink = Url.RouteUrl("RecentlyAddedProducts", null, protocol);

            var title = "{0} - {1}".FormatInvariant(Services.StoreContext.CurrentStore.Name, T("RSS.RecentlyAddedProducts"));

            var feed = new SmartSyndicationFeed(new Uri(recentProductsLink), title, T("RSS.InformationAboutProducts"));

            feed.AddNamespaces(true);
            feed.Init(selfLink, Services.WorkContext.WorkingLanguage);

            if (!_catalogSettings.RecentlyAddedProductsEnabled || _catalogSettings.RecentlyAddedProductsNumber <= 0)
            {
                return(new RssActionResult {
                    Feed = feed
                });
            }

            var items = new List <SyndicationItem>();

            query.Sorting.Clear();
            query = query
                    .BuildFacetMap(false)
                    .SortBy(ProductSortingEnum.CreatedOn)
                    .Slice(0, _catalogSettings.RecentlyAddedProductsNumber);

            var result = _catalogSearchService.Search(query);

            var storeUrl = Services.StoreService.GetHost(Services.StoreContext.CurrentStore);

            // Prefecthing
            var allPictureInfos = Services.PictureService.GetPictureInfos(result.Hits);

            //_mediaSettings.ProductDetailsPictureSize, false, storeUrl

            foreach (var product in result.Hits)
            {
                string productUrl = Url.RouteUrl("Product", new { SeName = product.GetSeName() }, protocol);
                if (productUrl.HasValue())
                {
                    var item = feed.CreateItem(
                        product.GetLocalized(x => x.Name),
                        product.GetLocalized(x => x.ShortDescription),
                        productUrl,
                        product.CreatedOnUtc,
                        product.FullDescription);

                    try
                    {
                        // we add only the first picture
                        var picture = Services.PictureService.GetPictureById(product.MainPictureId.GetValueOrDefault());
                        if (picture != null)
                        {
                            feed.AddEnclosure(item, picture, Services.PictureService.GetUrl(picture, _mediaSettings.ProductDetailsPictureSize, FallbackPictureType.NoFallback, storeUrl));
                        }
                    }
                    catch { }

                    items.Add(item);
                }
            }

            feed.Items = items;

            Services.DisplayControl.AnnounceRange(result.Hits);

            return(new RssActionResult {
                Feed = feed
            });
        }
 protected virtual bool GetValueFor <T>(CatalogSearchQuery query, string key, FacetGroupKind kind, out T value)
 {
     return(GetValueFor(_catalogSearchQueryAliasMapper.GetCommonFacetAliasByGroupKind(kind, query.LanguageId ?? 0) ?? key, out value));
 }
        public async Task <IActionResult> Manufacturer(int manufacturerId, CatalogSearchQuery query)
        {
            var manufacturer = await _db.Manufacturers.FindByIdAsync(manufacturerId, false);

            if (manufacturer == null || manufacturer.Deleted)
            {
                return(NotFound());
            }

            // Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a manufacturer before publishing.
            if (!manufacturer.Published && !await Services.Permissions.AuthorizeAsync(Permissions.Catalog.Manufacturer.Read))
            {
                return(NotFound());
            }

            // ACL (access control list).
            if (!await _aclService.AuthorizeAsync(manufacturer))
            {
                return(NotFound());
            }

            // Store mapping.
            if (!await _storeMappingService.AuthorizeAsync(manufacturer))
            {
                return(NotFound());
            }

            var customer = Services.WorkContext.CurrentCustomer;
            var storeId  = Services.StoreContext.CurrentStore.Id;

            // 'Continue shopping' URL.
            if (!customer.IsSystemAccount)
            {
                customer.GenericAttributes.LastContinueShoppingPage = Services.WebHelper.GetCurrentPageUrl(false);
            }

            var model = await _helper.PrepareBrandModelAsync(manufacturer);

            if (_seoSettings.CanonicalUrlsEnabled)
            {
                model.CanonicalUrl = _urlHelper.Value.RouteUrl("Manufacturer", new { model.SeName }, Request.Scheme);
            }

            if (query.IsSubPage && !_catalogSettings.ShowDescriptionInSubPages)
            {
                model.Description.ChangeValue(string.Empty);
                model.BottomDescription.ChangeValue(string.Empty);
            }

            model.Image = await _helper.PrepareBrandImageModelAsync(manufacturer, model.Name);

            // Featured products.
            var hideFeaturedProducts = _catalogSettings.IgnoreFeaturedProducts || (query.IsSubPage && !_catalogSettings.IncludeFeaturedProductsInSubPages);

            if (!hideFeaturedProducts)
            {
                CatalogSearchResult featuredProductsResult = null;

                var cacheKey = ModelCacheInvalidator.MANUFACTURER_HAS_FEATURED_PRODUCTS_KEY.FormatInvariant(manufacturerId, string.Join(",", customer.GetRoleIds()), storeId);
                var hasFeaturedProductsCache = await Services.Cache.GetAsync <bool?>(cacheKey);

                var featuredProductsQuery = new CatalogSearchQuery()
                                            .VisibleOnly(customer)
                                            .WithVisibility(ProductVisibility.Full)
                                            .WithManufacturerIds(true, manufacturerId)
                                            .HasStoreId(storeId)
                                            .WithLanguage(Services.WorkContext.WorkingLanguage)
                                            .WithCurrency(Services.WorkContext.WorkingCurrency);

                if (!hasFeaturedProductsCache.HasValue)
                {
                    featuredProductsResult = await _catalogSearchService.SearchAsync(featuredProductsQuery);

                    hasFeaturedProductsCache = featuredProductsResult.TotalHitsCount > 0;
                    await Services.Cache.PutAsync(cacheKey, hasFeaturedProductsCache);
                }

                if (hasFeaturedProductsCache.Value && featuredProductsResult == null)
                {
                    featuredProductsResult = await _catalogSearchService.SearchAsync(featuredProductsQuery);
                }

                if (featuredProductsResult != null)
                {
                    // TODO: (mc) determine settings properly
                    var featuredProductsmappingSettings = _helper.GetBestFitProductSummaryMappingSettings(ProductSummaryViewMode.Grid);
                    model.FeaturedProducts = await _helper.MapProductSummaryModelAsync(featuredProductsResult, featuredProductsmappingSettings);
                }
            }

            // Products
            query.WithManufacturerIds(_catalogSettings.IncludeFeaturedProductsInNormalLists ? null : false, manufacturerId);

            var searchResult = await _catalogSearchService.SearchAsync(query);

            model.SearchResult = searchResult;

            var viewMode        = _helper.GetSearchQueryViewMode(query);
            var mappingSettings = _helper.GetBestFitProductSummaryMappingSettings(viewMode);

            model.Products = await _helper.MapProductSummaryModelAsync(searchResult, mappingSettings);

            // Prepare paging/sorting/mode stuff
            _helper.MapListActions(model.Products, manufacturer, _catalogSettings.DefaultPageSizeOptions);

            // Template.
            var templateCacheKey = string.Format(ModelCacheInvalidator.MANUFACTURER_TEMPLATE_MODEL_KEY, manufacturer.ManufacturerTemplateId);
            var templateViewPath = await Services.Cache.GetAsync(templateCacheKey, async() =>
            {
                var template = await _db.ManufacturerTemplates.FindByIdAsync(manufacturer.ManufacturerTemplateId, false)
                               ?? await _db.ManufacturerTemplates.FirstOrDefaultAsync();

                return(template.ViewPath);
            });

            // Activity log.
            Services.ActivityLogger.LogActivity("PublicStore.ViewManufacturer", T("ActivityLog.PublicStore.ViewManufacturer"), manufacturer.Name);

            Services.DisplayControl.Announce(manufacturer);

            return(View(templateViewPath, model));
        }
        public CatalogSearchQuery CreateFromQuery()
        {
            var ctx = _httpContext;

            if (ctx.Request == null)
            {
                return(null);
            }

            var routeData  = ctx.Request.RequestContext.RouteData;
            var area       = routeData.GetAreaName();
            var controller = routeData.GetRequiredString("controller");
            var action     = routeData.GetRequiredString("action");
            var origin     = "{0}{1}/{2}".FormatInvariant(area == null ? "" : area + "/", controller, action);
            var fields     = new List <string> {
                "name"
            };
            var term            = GetValueFor <string>("q");
            var isInstantSearch = origin.IsCaseInsensitiveEqual("Search/InstantSearch");

            if (isInstantSearch)
            {
                fields.Add("shortdescription");
                fields.Add("tagname");

                foreach (var fieldName in _instantSearchFields)
                {
                    if (_searchSettings.SearchFields.Contains(fieldName))
                    {
                        fields.Add(fieldName);
                    }
                }
            }
            else
            {
                fields.AddRange(_searchSettings.SearchFields);
            }

            var query = new CatalogSearchQuery(fields.ToArray(), term, _searchSettings.SearchMode)
                        .OriginatesFrom(origin)
                        .WithLanguage(_services.WorkContext.WorkingLanguage)
                        .WithCurrency(_services.WorkContext.WorkingCurrency)
                        .VisibleIndividuallyOnly(true)
                        .BuildFacetMap(!isInstantSearch);

            // Visibility.
            query.VisibleOnly(!QuerySettings.IgnoreAcl ? _services.WorkContext.CurrentCustomer : null);

            // Store.
            if (!QuerySettings.IgnoreMultiStore)
            {
                query.HasStoreId(_services.StoreContext.CurrentStore.Id);
            }

            // Availability.
            ConvertAvailability(query, routeData, origin);

            // Instant-Search never uses these filter parameters.
            if (!isInstantSearch)
            {
                ConvertPagingSorting(query, routeData, origin);
                ConvertPrice(query, routeData, origin);
                ConvertCategory(query, routeData, origin);
                ConvertManufacturer(query, routeData, origin);
                ConvertRating(query, routeData, origin);
                ConvertNewArrivals(query, routeData, origin);
                ConvertDeliveryTime(query, routeData, origin);
            }

            OnConverted(query, routeData, origin);

            Current = query;
            return(query);
        }
        public async Task <IActionResult> Category(int categoryId, CatalogSearchQuery query)
        {
            var category = await _db.Categories
                           .Include(x => x.MediaFile)
                           .FindByIdAsync(categoryId, false);

            if (category == null || category.Deleted)
            {
                return(NotFound());
            }

            // Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a category before publishing.
            if (!category.Published && !await Services.Permissions.AuthorizeAsync(Permissions.Catalog.Category.Read))
            {
                return(NotFound());
            }

            // ACL (access control list).
            if (!await _aclService.AuthorizeAsync(category))
            {
                return(NotFound());
            }

            // Store mapping.
            if (!await _storeMappingService.AuthorizeAsync(category))
            {
                return(NotFound());
            }

            var customer = Services.WorkContext.CurrentCustomer;
            var storeId  = Services.StoreContext.CurrentStore.Id;

            // 'Continue shopping' URL.
            if (!customer.IsSystemAccount)
            {
                customer.GenericAttributes.LastContinueShoppingPage = Services.WebHelper.GetCurrentPageUrl(false);
            }

            var model = await _helper.PrepareCategoryModelAsync(category);

            if (_seoSettings.CanonicalUrlsEnabled)
            {
                model.CanonicalUrl = _urlHelper.Value.RouteUrl("Category", new { model.SeName }, Request.Scheme);
            }

            if (query.IsSubPage && !_catalogSettings.ShowDescriptionInSubPages)
            {
                model.Description.ChangeValue(string.Empty);
                model.BottomDescription.ChangeValue(string.Empty);
            }

            model.Image = await _helper.PrepareCategoryImageModelAsync(category, model.Name);

            // Category breadcrumb.
            if (_catalogSettings.CategoryBreadcrumbEnabled)
            {
                await _helper.GetBreadcrumbAsync(_breadcrumb, ControllerContext);
            }

            // Products.
            var catIds = new int[] { categoryId };

            if (_catalogSettings.ShowProductsFromSubcategories)
            {
                // Include subcategories.
                catIds = catIds.Concat(await _helper.GetChildCategoryIdsAsync(categoryId)).ToArray();
            }

            query.WithCategoryIds(_catalogSettings.IncludeFeaturedProductsInNormalLists ? null : false, catIds);

            var searchResult = await _catalogSearchService.SearchAsync(query);

            model.SearchResult = searchResult;

            var viewMode        = _helper.GetSearchQueryViewMode(query);
            var mappingSettings = _helper.GetBestFitProductSummaryMappingSettings(viewMode);

            model.Products = await _helper.MapProductSummaryModelAsync(searchResult, mappingSettings);

            model.SubCategoryDisplayType = _catalogSettings.SubCategoryDisplayType;

            var pictureSize  = _mediaSettings.CategoryThumbPictureSize;
            var fallbackType = _catalogSettings.HideCategoryDefaultPictures ? FallbackPictureType.NoFallback : FallbackPictureType.Entity;

            var hideSubCategories = _catalogSettings.SubCategoryDisplayType == SubCategoryDisplayType.Hide ||
                                    (_catalogSettings.SubCategoryDisplayType == SubCategoryDisplayType.AboveProductList && query.IsSubPage && !_catalogSettings.ShowSubCategoriesInSubPages);
            var hideFeaturedProducts = _catalogSettings.IgnoreFeaturedProducts || (query.IsSubPage && !_catalogSettings.IncludeFeaturedProductsInSubPages);

            // Subcategories.
            if (!hideSubCategories)
            {
                var subCategories = await _categoryService.GetCategoriesByParentCategoryIdAsync(categoryId);

                model.SubCategories = await _helper.MapCategorySummaryModelAsync(subCategories, pictureSize);
            }

            // Featured Products.
            if (!hideFeaturedProducts)
            {
                CatalogSearchResult featuredProductsResult = null;

                string cacheKey = ModelCacheInvalidator.CATEGORY_HAS_FEATURED_PRODUCTS_KEY.FormatInvariant(categoryId, string.Join(",", customer.GetRoleIds()), storeId);
                var    hasFeaturedProductsCache = await Services.Cache.GetAsync <bool?>(cacheKey);

                var featuredProductsQuery = new CatalogSearchQuery()
                                            .VisibleOnly(customer)
                                            .WithVisibility(ProductVisibility.Full)
                                            .WithCategoryIds(true, categoryId)
                                            .HasStoreId(storeId)
                                            .WithLanguage(Services.WorkContext.WorkingLanguage)
                                            .WithCurrency(Services.WorkContext.WorkingCurrency);

                if (!hasFeaturedProductsCache.HasValue)
                {
                    featuredProductsResult = await _catalogSearchService.SearchAsync(featuredProductsQuery);

                    hasFeaturedProductsCache = featuredProductsResult.TotalHitsCount > 0;
                    await Services.Cache.PutAsync(cacheKey, hasFeaturedProductsCache);
                }

                if (hasFeaturedProductsCache.Value && featuredProductsResult == null)
                {
                    featuredProductsResult = await _catalogSearchService.SearchAsync(featuredProductsQuery);
                }

                if (featuredProductsResult != null)
                {
                    var featuredProductsMappingSettings = _helper.GetBestFitProductSummaryMappingSettings(ProductSummaryViewMode.Grid);
                    model.FeaturedProducts = await _helper.MapProductSummaryModelAsync(featuredProductsResult, featuredProductsMappingSettings);
                }
            }

            // Prepare paging/sorting/mode stuff.
            _helper.MapListActions(model.Products, category, _catalogSettings.DefaultPageSizeOptions);

            // Template.
            var templateCacheKey = string.Format(ModelCacheInvalidator.CATEGORY_TEMPLATE_MODEL_KEY, category.CategoryTemplateId);
            var templateViewPath = await Services.Cache.GetAsync(templateCacheKey, async() =>
            {
                var template = await _db.CategoryTemplates.FindByIdAsync(category.CategoryTemplateId, false)
                               ?? await _db.CategoryTemplates.FirstOrDefaultAsync();

                return(template.ViewPath);
            });

            // Activity log.
            Services.ActivityLogger.LogActivity("PublicStore.ViewCategory", T("ActivityLog.PublicStore.ViewCategory"), category.Name);

            Services.DisplayControl.Announce(category);

            return(View(templateViewPath, model));
        }
示例#28
0
        public async Task <IActionResult> Search(CatalogSearchQuery query)
        {
            var model = new SearchResultModel(query);
            CatalogSearchResult result = null;

            if (query.Term == null || query.Term.Length < _searchSettings.InstantSearchTermMinLength)
            {
                model.SearchResult = new CatalogSearchResult(query);
                model.Error        = T("Search.SearchTermMinimumLengthIsNCharacters", _searchSettings.InstantSearchTermMinLength);
                return(View(model));
            }

            Services.WorkContext.CurrentCustomer.GenericAttributes.LastContinueShoppingPage = Services.WebHelper.GetCurrentPageUrl(false);

            try
            {
                if (_searchSettings.SearchProductByIdentificationNumber)
                {
                    var(product, attributeCombination) = await _productService.Value.GetProductByIdentificationNumberAsync(query.Term);

                    if (product != null)
                    {
                        if (attributeCombination != null)
                        {
                            return(Redirect(await _productUrlHelper.GetProductUrlAsync(product.Id, await product.GetActiveSlugAsync(), attributeCombination.AttributeSelection)));
                        }

                        return(RedirectToRoute("Product", new { SeName = await product.GetActiveSlugAsync() }));
                    }
                }

                result = await _catalogSearchService.SearchAsync(query);
            }
            catch (Exception ex)
            {
                model.Error = ex.ToString();
                result      = new CatalogSearchResult(query);
            }

            if (result.TotalHitsCount == 0 && result.SpellCheckerSuggestions.Any())
            {
                // No matches, but spell checker made a suggestion.
                // We implicitly search again with the first suggested term.
                var oldSuggestions = result.SpellCheckerSuggestions;
                var oldTerm        = query.Term;
                query.Term = oldSuggestions[0];

                result = await _catalogSearchService.SearchAsync(query);

                if (result.TotalHitsCount > 0)
                {
                    model.AttemptedTerm = oldTerm;
                    // Restore the original suggestions.
                    result.SpellCheckerSuggestions = oldSuggestions.Where(x => x != query.Term).ToArray();
                }
                else
                {
                    query.Term = oldTerm;
                }
            }

            model.SearchResult       = result;
            model.Term               = query.Term;
            model.TotalProductsCount = result.TotalHitsCount;

            var mappingSettings = _catalogHelper.GetBestFitProductSummaryMappingSettings(_catalogHelper.GetSearchQueryViewMode(query));
            var summaryModel    = await _catalogHelper.MapProductSummaryModelAsync(await result.GetHitsAsync(), mappingSettings);

            // Prepare paging/sorting/mode stuff.
            _catalogHelper.MapListActions(summaryModel, null, _catalogSettings.DefaultPageSizeOptions);

            // Add product hits.
            model.TopProducts = summaryModel;

            return(View(model));
        }
示例#29
0
        public virtual void InheritStoresIntoChildren(
            int categoryId,
            bool touchProductsWithMultipleCategories = false,
            bool touchExistingAcls = false,
            bool categoriesOnly    = false)
        {
            var category              = GetCategoryById(categoryId);
            var subcategories         = GetAllCategoriesByParentCategoryId(categoryId, true);
            var allStores             = _storeService.GetAllStores();
            var categoryStoreMappings = _storeMappingService.GetStoresIdsWithAccess(category);

            var categoryIds = new HashSet <int>(subcategories.Select(x => x.Id));

            categoryIds.Add(categoryId);

            var searchQuery = new CatalogSearchQuery()
                              .WithCategoryIds(null, categoryIds.ToArray());

            var query    = _catalogSearchService.PrepareQuery(searchQuery);
            var products = query.OrderBy(p => p.Id).ToList();

            using (var scope = new DbContextScope(ctx: _storeMappingRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false))
            {
                _storeMappingRepository.AutoCommitEnabled = false;

                foreach (var subcategory in subcategories)
                {
                    if (subcategory.LimitedToStores != category.LimitedToStores)
                    {
                        subcategory.LimitedToStores = category.LimitedToStores;
                        _categoryRepository.Update(subcategory);
                    }

                    var existingStoreMappingsRecords = _storeMappingService.GetStoreMappings(subcategory).ToDictionary(x => x.StoreId);

                    foreach (var store in allStores)
                    {
                        if (categoryStoreMappings.Contains(store.Id))
                        {
                            if (!existingStoreMappingsRecords.ContainsKey(store.Id))
                            {
                                _storeMappingRepository.Insert(new StoreMapping {
                                    StoreId = store.Id, EntityId = subcategory.Id, EntityName = "Category"
                                });
                            }
                        }
                        else
                        {
                            if (existingStoreMappingsRecords.TryGetValue(store.Id, out var storeMappingToDelete))
                            {
                                _storeMappingRepository.Delete(storeMappingToDelete);
                            }
                        }
                    }
                }

                _storeMappingRepository.Context.SaveChanges();

                foreach (var product in products)
                {
                    if (product.LimitedToStores != category.LimitedToStores)
                    {
                        product.LimitedToStores = category.LimitedToStores;
                        _productRepository.Update(product);
                    }

                    var existingStoreMappingsRecords = _storeMappingService.GetStoreMappings(product).ToDictionary(x => x.StoreId);

                    foreach (var store in allStores)
                    {
                        if (categoryStoreMappings.Contains(store.Id))
                        {
                            if (!existingStoreMappingsRecords.ContainsKey(store.Id))
                            {
                                _storeMappingRepository.Insert(new StoreMapping {
                                    StoreId = store.Id, EntityId = product.Id, EntityName = "Product"
                                });
                            }
                        }
                        else
                        {
                            if (existingStoreMappingsRecords.TryGetValue(store.Id, out var storeMappingToDelete))
                            {
                                _storeMappingRepository.Delete(storeMappingToDelete);
                            }
                        }
                    }
                }

                _storeMappingRepository.Context.SaveChanges();
            }
        }
        public ActionResult Search(CatalogSearchQuery query)
        {
            var model = new SearchResultModel(query);
            CatalogSearchResult result = null;

            if (query.Term == null || query.Term.Length < _searchSettings.InstantSearchTermMinLength)
            {
                model.SearchResult = new CatalogSearchResult(query);
                model.Error        = T("Search.SearchTermMinimumLengthIsNCharacters", _searchSettings.InstantSearchTermMinLength);
                return(View(model));
            }

            // 'Continue shopping' URL
            _genericAttributeService.SaveAttribute(Services.WorkContext.CurrentCustomer,
                                                   SystemCustomerAttributeNames.LastContinueShoppingPage,
                                                   Services.WebHelper.GetThisPageUrl(false),
                                                   Services.StoreContext.CurrentStore.Id);

            try
            {
                result = _catalogSearchService.Search(query);
            }
            catch (Exception ex)
            {
                model.Error = ex.ToString();
                result      = new CatalogSearchResult(query);
            }

            if (result.TotalHitsCount == 0 && result.SpellCheckerSuggestions.Any())
            {
                // No matches, but spell checker made a suggestion.
                // We implicitly search again with the first suggested term.
                var oldSuggestions = result.SpellCheckerSuggestions;
                var oldTerm        = query.Term;
                query.Term = oldSuggestions[0];

                result = _catalogSearchService.Search(query);

                if (result.TotalHitsCount > 0)
                {
                    model.AttemptedTerm = oldTerm;
                    // Restore the original suggestions.
                    result.SpellCheckerSuggestions = oldSuggestions.Where(x => x != query.Term).ToArray();
                }
                else
                {
                    query.Term = oldTerm;
                }
            }

            model.SearchResult       = result;
            model.Term               = query.Term;
            model.TotalProductsCount = result.TotalHitsCount;

            var mappingSettings = _catalogHelper.GetBestFitProductSummaryMappingSettings(query.GetViewMode());
            var summaryModel    = _catalogHelper.MapProductSummaryModel(result.Hits, mappingSettings);

            // Prepare paging/sorting/mode stuff.
            _catalogHelper.MapListActions(summaryModel, null, _catalogSettings.DefaultPageSizeOptions);

            // Add product hits.
            model.TopProducts = summaryModel;

            return(View(model));
        }