Пример #1
0
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="helper">Product URL helper.</param>
        /// <param name="productId">Product identifier.</param>
        /// <param name="productSlug">Product URL slug.</param>
        /// <param name="bundleItemId">Bundle item identifier. 0 if it's not a bundle item.</param>
        /// <param name="variantValues">Variant values<./param>
        /// <returns>Product URL.</returns>
        public static string GetProductUrl(
            this ProductUrlHelper helper,
            int productId,
            string productSlug,
            int bundleItemId,
            params ProductVariantAttributeValue[] variantValues)
        {
            Guard.NotNull(helper, nameof(helper));
            Guard.NotZero(productId, nameof(productId));

            var query = new ProductVariantQuery();

            foreach (var value in variantValues)
            {
                var attribute = value.ProductVariantAttribute;

                query.AddVariant(new ProductVariantQueryItem(value.Id.ToString())
                {
                    ProductId          = productId,
                    BundleItemId       = bundleItemId,
                    AttributeId        = attribute.ProductAttributeId,
                    VariantAttributeId = attribute.Id,
                    Alias      = attribute.ProductAttribute.Alias,
                    ValueAlias = value.Alias
                });
            }

            return(helper.GetProductUrl(productSlug, query));
        }
Пример #2
0
        public async Task <IActionResult> ProductDetails(int productId, ProductVariantQuery query)
        {
            var product = await _db.Products.FindByIdAsync(productId, false);

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

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

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

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

            // TODO: (mh) (core) Continue CatalogController.Category()

            var store = Services.StoreContext.CurrentStore;
            var price = store.PrimaryStoreCurrency.AsMoney(product.Price).ExchangeTo(Services.WorkContext.WorkingCurrency);

            return(Content($"Product --> Id: {product.Id}, Name: {product.Name}, Price: {price}"));
        }
        public void ProductVariant(ProductVariantQuery variant, Dictionary <string, int> imageResolutions)
        {
            variant
            .id()
            .availableForSale()
            .image(pnvi => pnvi
                   .altText()
                   .transformedSrc()
                   )
            .price()
            .title()
            .weight()
            .selectedOptions(pnvso => pnvso
                             .name()
                             .value()
                             )
            .weightUnit();

            foreach (string alias in imageResolutions.Keys)
            {
                variant.image(
                    pnvi => pnvi
                    .altText()
                    .transformedSrc(),
                    maxWidth: imageResolutions[alias], maxHeight: imageResolutions[alias], alias: alias
                    );
            }
        }
Пример #4
0
        public async Task <IActionResult> AskQuestionAjax(int id, ProductVariantQuery query)
        {
            // Get rawAttributes from product variant query
            if (query != null && id > 0)
            {
                var attributes = await _db.ProductVariantAttributes
                                 .Include(x => x.ProductAttribute)
                                 .ApplyProductFilter(new[] { id })
                                 .ToListAsync();

                var selection = await _productAttributeMaterializer.Value.CreateAttributeSelectionAsync(query, attributes, id, 0, false);

                var rawAttributes = selection.Selection.AsJson();

                if (rawAttributes.HasValue() && TempData["AskQuestionAttributeSelection-" + id] == null)
                {
                    TempData.Add("AskQuestionAttributeSelection-" + id, rawAttributes);
                }
            }

            return(new JsonResult(new
            {
                Data = new { redirect = Url.Action("AskQuestion", new { id }) }
            }));
        }
Пример #5
0
        /// <summary>
        /// Converts a query object into a URL query string.
        /// </summary>
        /// <param name="query">Product variant query.</param>
        /// <returns>URL query string.</returns>
        public virtual string ToQueryString(ProductVariantQuery query)
        {
            Guard.NotNull(query, nameof(query));

            var qs         = InitialQuery ?? new MutableQueryCollection();
            var languageId = _workContext.WorkingLanguage.Id;

            // Checkout attributes.
            foreach (var item in query.CheckoutAttributes)
            {
                if (item.Date.HasValue)
                {
                    qs.Add(item.ToString(), string.Join("-", item.Date.Value.Year, item.Date.Value.Month, item.Date.Value.Day));
                }
                else
                {
                    qs.Add(item.ToString(), item.Value);
                }
            }

            // Gift cards.
            foreach (var item in query.GiftCards)
            {
                qs.Add(item.ToString(), item.Value);
            }

            // Variants.
            foreach (var item in query.Variants)
            {
                if (item.Alias.IsEmpty())
                {
                    item.Alias = _catalogSearchQueryAliasMapper.Value.GetVariantAliasById(item.AttributeId, languageId);
                }

                if (item.Date.HasValue)
                {
                    qs.Add(item.ToString(), string.Join("-", item.Date.Value.Year, item.Date.Value.Month, item.Date.Value.Day));
                }
                else if (item.IsFile || item.IsText)
                {
                    qs.Add(item.ToString(), item.Value);
                }
                else
                {
                    if (item.ValueAlias.IsEmpty())
                    {
                        item.ValueAlias = _catalogSearchQueryAliasMapper.Value.GetVariantOptionAliasById(item.Value.ToInt(), languageId);
                    }

                    var value = item.ValueAlias.HasValue()
                        ? $"{item.ValueAlias}-{item.Value}"
                        : item.Value;

                    qs.Add(item.ToString(), value);
                }
            }

            return(qs.ToString());
        }
Пример #6
0
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="productId">Product identifier.</param>
        /// <param name="productSlug">Product URL slug.</param>
        /// <param name="selection">Selected attributes.</param>
        /// <returns>Product URL.</returns>
        public virtual async Task <string> GetProductUrlAsync(int productId, string productSlug, ProductVariantAttributeSelection selection)
        {
            var query = new ProductVariantQuery();

            await AddAttributesToQueryAsync(query, selection, productId);

            return(GetProductUrl(productSlug, query));
        }
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="productId">Product identifier</param>
        /// <param name="productSeName">Product SEO name</param>
        /// <param name="attributesXml">XML formatted attributes</param>
        /// <returns>Product URL</returns>
        public virtual string GetProductUrl(int productId, string productSeName, string attributesXml)
        {
            var query = new ProductVariantQuery();

            DeserializeQuery(query, productId, attributesXml);

            return(GetProductUrl(query, productSeName));
        }
Пример #8
0
        protected virtual string ToQueryString(ProductVariantQuery query)
        {
            var qs = InitialQuery != null
                                ? new QueryString(InitialQuery)
                                : new QueryString();

            // Checkout Attributes
            foreach (var item in query.CheckoutAttributes)
            {
                if (item.Date.HasValue)
                {
                    qs.Add(item.ToString(), string.Join("-", item.Date.Value.Year, item.Date.Value.Month, item.Date.Value.Day));
                }
                else
                {
                    qs.Add(item.ToString(), item.Value);
                }
            }

            // Gift cards
            foreach (var item in query.GiftCards)
            {
                qs.Add(item.ToString(), item.Value);
            }

            // Variants
            foreach (var item in query.Variants)
            {
                if (item.Alias.IsEmpty())
                {
                    item.Alias = _catalogSearchQueryAliasMapper.Value.GetVariantAliasById(item.AttributeId, _languageId);
                }

                if (item.Date.HasValue)
                {
                    qs.Add(item.ToString(), string.Join("-", item.Date.Value.Year, item.Date.Value.Month, item.Date.Value.Day));
                }
                else if (item.IsFile || item.IsText)
                {
                    qs.Add(item.ToString(), item.Value);
                }
                else
                {
                    if (item.ValueAlias.IsEmpty())
                    {
                        item.ValueAlias = _catalogSearchQueryAliasMapper.Value.GetVariantOptionAliasById(item.Value.ToInt(), _languageId);
                    }

                    var value = item.ValueAlias.HasValue()
                                                ? $"{item.ValueAlias}-{item.Value}"
                                                : item.Value;

                    qs.Add(item.ToString(), value);
                }
            }

            return(qs.ToString(false));
        }
        /// <summary>
        /// Creates an absolute product URL.
        /// </summary>
        /// <param name="productId">Product identifier</param>
        /// <param name="productSeName">Product SEO name</param>
        /// <param name="attributesXml">XML formatted attributes</param>
        /// <param name="store">Store entity</param>
        /// <param name="language">Language entity</param>
        /// <returns>Absolute product URL</returns>
        public virtual string GetAbsoluteProductUrl(
            int productId,
            string productSeName,
            string attributesXml,
            Store store       = null,
            Language language = null)
        {
            if (_httpRequest == null || productSeName.IsEmpty())
            {
                return(null);
            }

            var url = Url;

            if (url.IsEmpty())
            {
                // No given URL. Create SEO friendly URL.
                var urlHelper = new LocalizedUrlHelper(_httpRequest.ApplicationPath, productSeName, false);

                store    = store ?? _services.StoreContext.CurrentStore;
                language = language ?? _services.WorkContext.WorkingLanguage;

                if (_localizationSettings.Value.SeoFriendlyUrlsForLanguagesEnabled)
                {
                    var defaultSeoCode = _languageService.Value.GetDefaultLanguageSeoCode(store.Id);

                    if (language.UniqueSeoCode == defaultSeoCode && _localizationSettings.Value.DefaultLanguageRedirectBehaviour > 0)
                    {
                        urlHelper.StripSeoCode();
                    }
                    else
                    {
                        urlHelper.PrependSeoCode(language.UniqueSeoCode, true);
                    }
                }

                var storeUrl = store.Url.TrimEnd('/');

                // Prevent duplicate occurrence of application path.
                if (urlHelper.ApplicationPath.HasValue() && storeUrl.EndsWith(urlHelper.ApplicationPath, StringComparison.OrdinalIgnoreCase))
                {
                    storeUrl = storeUrl.Substring(0, storeUrl.Length - urlHelper.ApplicationPath.Length).TrimEnd('/');
                }

                url = storeUrl + urlHelper.GetAbsolutePath();
            }

            if (attributesXml.HasValue())
            {
                var query = new ProductVariantQuery();
                DeserializeQuery(query, productId, attributesXml);

                url = url + ToQueryString(query);
            }

            return(url);
        }
Пример #10
0
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="productSlug">Product URL slug.</param>
        /// <param name="query">Product variant query.</param>
        /// <returns>Product URL.</returns>
        public virtual string GetProductUrl(string productSlug, ProductVariantQuery query)
        {
            if (productSlug.IsEmpty())
            {
                return(null);
            }

            var url = Url ?? _urlHelper.Value.RouteUrl("Product", new { SeName = productSlug });

            return(url.TrimEnd('/') + ToQueryString(query));
        }
Пример #11
0
        /// <summary>
        /// Deserializes attributes XML into a product variant query
        /// </summary>
        /// <param name="query">Product variant query</param>
        /// <param name="productId">Product identifier</param>
        /// <param name="bundleItemId">Bundle item identifier</param>
        /// <param name="attributesXml">XML formatted attributes</param>
        public virtual void DeserializeQuery(ProductVariantQuery query, int productId, string attributesXml, int bundleItemId = 0)
        {
            Guard.NotNull(query, nameof(query));
            Guard.NotZero(productId, nameof(productId));

            if (attributesXml.IsEmpty() || productId == 0)
            {
                return;
            }

            var attributeMap = _productAttributeParser.DeserializeProductVariantAttributes(attributesXml);
            var attributes   = _productAttributeService.GetProductVariantAttributesByIds(attributeMap.Keys);

            foreach (var attribute in attributes)
            {
                foreach (var originalValue in attributeMap[attribute.Id])
                {
                    var      value = originalValue;
                    DateTime?date  = null;

                    if (attribute.AttributeControlType == AttributeControlType.Datepicker)
                    {
                        date = originalValue.ToDateTime(new string[] { "D" }, CultureInfo.CurrentCulture, DateTimeStyles.None, null);
                        if (date == null)
                        {
                            continue;
                        }

                        value = string.Join("-", date.Value.Year, date.Value.Month, date.Value.Day);
                    }

                    var queryItem = new ProductVariantQueryItem(value);
                    queryItem.ProductId          = productId;
                    queryItem.BundleItemId       = bundleItemId;
                    queryItem.AttributeId        = attribute.ProductAttributeId;
                    queryItem.VariantAttributeId = attribute.Id;
                    queryItem.Alias  = _catalogSearchQueryAliasMapper.Value.GetVariantAliasById(attribute.ProductAttributeId, _languageId);
                    queryItem.Date   = date;
                    queryItem.IsFile = attribute.AttributeControlType == AttributeControlType.FileUpload;
                    queryItem.IsText = attribute.AttributeControlType == AttributeControlType.TextBox || attribute.AttributeControlType == AttributeControlType.MultilineTextbox;

                    if (attribute.ShouldHaveValues())
                    {
                        queryItem.ValueAlias = _catalogSearchQueryAliasMapper.Value.GetVariantOptionAliasById(value.ToInt(), _languageId);
                    }

                    query.AddVariant(queryItem);
                }
            }
        }
Пример #12
0
 public void ProductVariant(ProductVariantQuery variant, Dictionary <string, int> imageResolutions)
 {
     variant
     .id()
     .availableForSale()
     .image(i => AliasedTransformedSrcImages(i.altText().transformedSrc(), imageResolutions))
     .price()
     .title()
     .weight()
     .selectedOptions(pnvso => pnvso
                      .name()
                      .value()
                      )
     .weightUnit();
 }
Пример #13
0
        /// <summary>
        /// Creates an absolute product URL.
        /// </summary>
        /// <param name="productId">Product identifier.</param>
        /// <param name="productSlug">Product URL slug.</param>
        /// <param name="selection">Selected attributes.</param>
        /// <param name="store">Store.</param>
        /// <param name="language">Language.</param>
        /// <returns>Absolute product URL.</returns>
        public virtual async Task <string> GetAbsoluteProductUrlAsync(
            int productId,
            string productSlug,
            ProductVariantAttributeSelection selection = null,
            Store store       = null,
            Language language = null)
        {
            var request = _httpContextAccessor?.HttpContext?.Request;

            if (request == null || productSlug.IsEmpty())
            {
                return(null);
            }

            var url = Url;

            if (url.IsEmpty())
            {
                store ??= _storeContext.CurrentStore;
                language ??= _workContext.WorkingLanguage;

                string hostName = null;

                try
                {
                    // Do not create crappy URLs (exclude scheme, include port and no slash)!
                    hostName = new Uri(store.GetHost(true)).Authority;
                }
                catch { }

                url = _urlHelper.Value.RouteUrl(
                    "Product",
                    new { SeName = productSlug, culture = language.UniqueSeoCode },
                    store.SupportsHttps() ? "https" : "http",
                    hostName);
            }

            if (selection?.AttributesMap?.Any() ?? false)
            {
                var query = new ProductVariantQuery();
                await AddAttributesToQueryAsync(query, selection, productId);

                url = url.TrimEnd('/') + ToQueryString(query);
            }

            return(url);
        }
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="query">Product variant query</param>
        /// <param name="productSeName">Product SEO name</param>
        /// <returns>Product URL</returns>
        public virtual string GetProductUrl(ProductVariantQuery query, string productSeName)
        {
            if (productSeName.IsEmpty())
            {
                return(null);
            }

            var url = Url ?? UrlHelper.GenerateUrl(
                "Product",
                null,
                null,
                new RouteValueDictionary(new { SeName = productSeName }),
                RouteTable.Routes,
                _httpRequest.RequestContext,
                false);

            return(url + ToQueryString(query));
        }
 public void ProductVariant(ProductVariantQuery variant, Dictionary <string, int> imageResolutions)
 {
     variant
     .id()
     .availableForSale()
     .metafields(
         ff => MetafieldConnectionDelegate(ff, imageResolutions),
         first: DefaultQueries.MaxPageSize
         )
     .image(i => AliasedTransformedSrcImages(i.altText().transformedSrc(), imageResolutions))
     .price()
     .title()
     .weight()
     .selectedOptions(pnvso => pnvso
                      .name()
                      .value()
                      )
     .weightUnit();
 }
Пример #16
0
        public async Task <IActionResult> ProductDetails(int productId, ProductVariantQuery query)
        {
            var product = await _db.Products.FindByIdAsync(productId, false);

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

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

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

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

            // Save as recently viewed
            _recentlyViewedProductsService.AddProductToRecentlyViewedList(product.Id);

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

            // TODO: (mh) (core) Continue CatalogController.Category()

            var store = Services.StoreContext.CurrentStore;
            var price = Services.CurrencyService.ConvertToWorkingCurrency(product.Price);

            return(Content($"Product --> Id: {product.Id}, Name: {product.Name}, Price: {price}"));
        }
Пример #17
0
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="helper">Product URL helper.</param>
        /// <param name="productSlug">Product URL slug.</param>
        /// <param name="cartItem">Organized shopping cart item.</param>
        /// <returns>Product URL.</returns>
        public static async Task <string> GetProductUrlAsync(this ProductUrlHelper helper, string productSlug, OrganizedShoppingCartItem cartItem)
        {
            Guard.NotNull(helper, nameof(helper));
            Guard.NotNull(cartItem, nameof(cartItem));

            var query   = new ProductVariantQuery();
            var product = cartItem.Item.Product;

            if (product.ProductType != ProductType.BundledProduct)
            {
                await helper.AddAttributesToQueryAsync(query, cartItem.Item.AttributeSelection, product.Id);
            }
            else if (cartItem.ChildItems != null && product.BundlePerItemPricing)
            {
                foreach (var childItem in cartItem.ChildItems.Where(x => x.Item.Id != cartItem.Item.Id))
                {
                    await helper.AddAttributesToQueryAsync(query, childItem.Item.AttributeSelection, childItem.Item.ProductId, childItem.Item.BundleItem.Id);
                }
            }

            return(helper.GetProductUrl(productSlug, query));
        }
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="helper">Product URL helper</param>
        /// <param name="productSeName">Product SEO name</param>
        /// <param name="orderItem">Order item</param>
        /// <returns>Product URL</returns>
        public static string GetProductUrl(
            this ProductUrlHelper helper,
            string productSeName,
            OrderItem orderItem)
        {
            Guard.NotNull(orderItem, nameof(orderItem));

            var query = new ProductVariantQuery();

            if (orderItem.Product.ProductType != ProductType.BundledProduct)
            {
                helper.DeserializeQuery(query, orderItem.ProductId, orderItem.AttributesXml);
            }
            else if (orderItem.Product.BundlePerItemPricing && orderItem.BundleData.HasValue())
            {
                var bundleData = orderItem.GetBundleData();

                bundleData.ForEach(x => helper.DeserializeQuery(query, x.ProductId, x.AttributesXml, x.BundleItemId));
            }

            return(helper.GetProductUrl(query, productSeName));
        }
Пример #19
0
        public ActionResult AskQuestionAjax(int id, ProductVariantQuery query)
        {
            // Get attributeXml from product variant query
            if (query != null && id > 0)
            {
                var attributes    = _productAttributeService.GetProductVariantAttributesByProductId(id);
                var warnings      = new List <string>();
                var attributesXml = query.CreateSelectedAttributesXml(id, 0, attributes, _productAttributeParser,
                                                                      _localizationService, _downloadService, _catalogSettings, null, warnings);

                if (attributesXml.HasValue())
                {
                    TempData.Add("AskQuestionAttributesXml-" + id, attributesXml);
                }
            }

            return(new JsonResult
            {
                Data = new { redirect = Url.Action("AskQuestion", new { id }) },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            });
        }
Пример #20
0
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="helper">Product URL helper.</param>
        /// <param name="productSlug">Product URL slug.</param>
        /// <param name="orderItem">Order item.</param>
        /// <returns>Product URL.</returns>
        public static async Task <string> GetProductUrlAsync(this ProductUrlHelper helper, string productSlug, OrderItem orderItem)
        {
            Guard.NotNull(helper, nameof(helper));
            Guard.NotNull(orderItem, nameof(orderItem));

            var query = new ProductVariantQuery();

            if (orderItem.Product.ProductType != ProductType.BundledProduct)
            {
                await helper.AddAttributesToQueryAsync(query, orderItem.AttributeSelection, orderItem.ProductId);
            }
            else if (orderItem.Product.BundlePerItemPricing && orderItem.BundleData.HasValue())
            {
                var bundleData = orderItem.GetBundleData();

                foreach (var item in bundleData)
                {
                    await helper.AddAttributesToQueryAsync(query, item.AttributeSelection, item.ProductId, item.BundleItemId);
                }
            }

            return(helper.GetProductUrl(productSlug, query));
        }
        /// <summary>
        /// Deserializes attributes XML into a product variant query
        /// </summary>
        /// <param name="query">Product variant query</param>
        /// <param name="productId">Product identifier</param>
        /// <param name="bundleItemId">Bundle item identifier</param>
        /// <param name="attributesXml">XML formatted attributes</param>
        public virtual void DeserializeQuery(ProductVariantQuery query, int productId, string attributesXml, int bundleItemId = 0)
        {
            Guard.NotNull(query, nameof(query));
            Guard.NotZero(productId, nameof(productId));

            if (attributesXml.HasValue() && productId != 0)
            {
                var attributeValues = _productAttributeParser.ParseProductVariantAttributeValues(attributesXml).ToList();

                foreach (var value in attributeValues)
                {
                    query.AddVariant(new ProductVariantQueryItem(value.Id.ToString())
                    {
                        ProductId          = productId,
                        BundleItemId       = bundleItemId,
                        AttributeId        = value.ProductVariantAttribute.ProductAttributeId,
                        VariantAttributeId = value.ProductVariantAttributeId,
                        Alias      = value.ProductVariantAttribute.ProductAttribute.Alias,
                        ValueAlias = value.Alias
                    });
                }
            }
        }
        /// <summary>
        /// Creates a product URL including variant query string.
        /// </summary>
        /// <param name="helper">Product URL helper</param>
        /// <param name="productSeName">Product SEO name</param>
        /// <param name="cartItem">Organized shopping cart item</param>
        /// <returns>Product URL</returns>
        public static string GetProductUrl(
            this ProductUrlHelper helper,
            string productSeName,
            OrganizedShoppingCartItem cartItem)
        {
            Guard.NotNull(cartItem, nameof(cartItem));

            var query   = new ProductVariantQuery();
            var product = cartItem.Item.Product;

            if (product.ProductType != ProductType.BundledProduct)
            {
                helper.DeserializeQuery(query, product.Id, cartItem.Item.AttributesXml);
            }
            else if (cartItem.ChildItems != null && product.BundlePerItemPricing)
            {
                foreach (var childItem in cartItem.ChildItems.Where(x => x.Item.Id != cartItem.Item.Id))
                {
                    helper.DeserializeQuery(query, childItem.Item.ProductId, childItem.Item.AttributesXml, childItem.BundleItemData.Item.Id);
                }
            }

            return(helper.GetProductUrl(query, productSeName));
        }
        public static string CreateSelectedAttributesXml(
            this ProductVariantQuery query,
            int productId,
            int bundleItemId,
            IEnumerable <ProductVariantAttribute> variantAttributes,
            IProductAttributeParser productAttributeParser,
            ILocalizationService localization,
            IDownloadService downloadService,
            CatalogSettings catalogSettings,
            HttpRequestBase request,
            List <string> warnings)
        {
            var result = string.Empty;

            foreach (var pva in variantAttributes)
            {
                var selectedItems = query.Variants.Where(x =>
                                                         x.ProductId == productId &&
                                                         x.BundleItemId == bundleItemId &&
                                                         x.AttributeId == pva.ProductAttributeId &&
                                                         x.VariantAttributeId == pva.Id);

                switch (pva.AttributeControlType)
                {
                case AttributeControlType.DropdownList:
                case AttributeControlType.RadioList:
                case AttributeControlType.Boxes:
                {
                    var firstItemValue = selectedItems.FirstOrDefault()?.Value;
                    if (firstItemValue.HasValue())
                    {
                        var selectedAttributeId = firstItemValue.SplitSafe(",").SafeGet(0).ToInt();
                        if (selectedAttributeId > 0)
                        {
                            result = productAttributeParser.AddProductAttribute(result, pva, selectedAttributeId.ToString());
                        }
                    }
                }
                break;

                case AttributeControlType.Checkboxes:
                    foreach (var item in selectedItems)
                    {
                        var selectedAttributeId = item.Value.SplitSafe(",").SafeGet(0).ToInt();
                        if (selectedAttributeId > 0)
                        {
                            result = productAttributeParser.AddProductAttribute(result, pva, selectedAttributeId.ToString());
                        }
                    }
                    break;

                case AttributeControlType.TextBox:
                case AttributeControlType.MultilineTextbox:
                {
                    var selectedValue = string.Join(",", selectedItems.Select(x => x.Value));
                    if (selectedValue.HasValue())
                    {
                        result = productAttributeParser.AddProductAttribute(result, pva, selectedValue);
                    }
                }
                break;

                case AttributeControlType.Datepicker:
                {
                    var firstItemDate = selectedItems.FirstOrDefault()?.Date;
                    if (firstItemDate.HasValue)
                    {
                        result = productAttributeParser.AddProductAttribute(result, pva, firstItemDate.Value.ToString("D"));
                    }
                }
                break;

                case AttributeControlType.FileUpload:
                    if (request == null)
                    {
                        var firstItemValue = selectedItems.FirstOrDefault()?.Value;
                        Guid.TryParse(firstItemValue, out var downloadGuid);

                        var download = downloadService.GetDownloadByGuid(downloadGuid);
                        if (download != null)
                        {
                            if (download.IsTransient)
                            {
                                download.IsTransient = false;
                                downloadService.UpdateDownload(download);
                            }

                            result = productAttributeParser.AddProductAttribute(result, pva, download.DownloadGuid.ToString());
                        }
                    }
                    else
                    {
                        var postedFile = request.Files[ProductVariantQueryItem.CreateKey(productId, bundleItemId, pva.ProductAttributeId, pva.Id)];
                        if (postedFile != null && postedFile.FileName.HasValue())
                        {
                            if (postedFile.ContentLength > catalogSettings.FileUploadMaximumSizeBytes)
                            {
                                warnings.Add(localization.GetResource("ShoppingCart.MaximumUploadedFileSize").FormatInvariant((int)(catalogSettings.FileUploadMaximumSizeBytes / 1024)));
                            }
                            else
                            {
                                var download = new Download
                                {
                                    DownloadGuid   = Guid.NewGuid(),
                                    UseDownloadUrl = false,
                                    DownloadUrl    = "",
                                    UpdatedOnUtc   = DateTime.UtcNow,
                                    EntityId       = productId,
                                    EntityName     = "ProductAttribute"
                                };

                                downloadService.InsertDownload(download, postedFile.InputStream, postedFile.FileName);

                                result = productAttributeParser.AddProductAttribute(result, pva, download.DownloadGuid.ToString());
                            }
                        }
                    }
                    break;
                }
            }

            return(result);
        }
Пример #24
0
        protected virtual async Task <decimal> GetPreselectedPriceAmountAsync(
            Product product,
            Customer customer,
            PriceCalculationContext context,
            ProductBundleItemData bundleItem,
            IEnumerable <ProductBundleItemData> bundleItems)
        {
            var attributesTotalPriceBase       = decimal.Zero;
            var preSelectedPriceAdjustmentBase = decimal.Zero;
            var isBundle            = product.ProductType == ProductType.BundledProduct;
            var isBundleItemPricing = bundleItem?.Item?.BundleProduct?.BundlePerItemPricing ?? false;
            var isBundlePricing     = bundleItem != null && !bundleItem.Item.BundleProduct.BundlePerItemPricing;
            var bundleItemId        = bundleItem?.Item?.Id ?? 0;

            var query = new ProductVariantQuery();
            var selectedAttributeValues = new List <ProductVariantAttributeValue>();
            var attributes = await context.Attributes.GetOrLoadAsync(product.Id);

            // 1. Fill query with initially selected attributes.
            foreach (var attribute in attributes.Where(x => x.ProductVariantAttributeValues.Any() && x.IsListTypeAttribute()))
            {
                await _db.LoadCollectionAsync(attribute, x => x.ProductVariantAttributeValues);

                var preSelectedValueId = 0;
                var selectedValueIds   = new List <int>();
                ProductVariantAttributeValue defaultValue = null;
                var pvaValues = attribute.ProductVariantAttributeValues;

                foreach (var pvaValue in pvaValues)
                {
                    ProductBundleItemAttributeFilter attributeFilter = null;
                    if (bundleItem?.Item?.IsFilteredOut(pvaValue, out attributeFilter) ?? false)
                    {
                        continue;
                    }

                    if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected)
                    {
                        preSelectedValueId = attributeFilter.AttributeValueId;
                    }

                    if (!isBundlePricing && pvaValue.IsPreSelected)
                    {
                        var attributeValuePriceAdjustment = await GetVariantPriceAdjustmentAsync(pvaValue, product, customer, context, 1);

                        // We cannot avoid money usage in calls between interfaces.
                        var(priceAdjustmentBase, _) = await _taxService.GetProductPriceAsync(product, new(attributeValuePriceAdjustment, _primaryCurrency), customer : customer);

                        preSelectedPriceAdjustmentBase += priceAdjustmentBase.Amount;
                    }
                }

                // Value pre-selected by a bundle item filter discards the default pre-selection.
                if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null)
                {
                    //defaultValue.IsPreSelected = true;
                    selectedAttributeValues.Add(defaultValue);
                    query.AddVariant(new ProductVariantQueryItem(defaultValue.Id.ToString())
                    {
                        ProductId          = product.Id,
                        BundleItemId       = bundleItemId,
                        AttributeId        = attribute.ProductAttributeId,
                        VariantAttributeId = attribute.Id,
                        Alias      = attribute.ProductAttribute.Alias,
                        ValueAlias = defaultValue.Alias
                    });
                }
                else
                {
                    foreach (var value in pvaValues.Where(x => x.IsPreSelected))
                    {
                        selectedAttributeValues.Add(value);
                        query.AddVariant(new ProductVariantQueryItem(value.Id.ToString())
                        {
                            ProductId          = product.Id,
                            BundleItemId       = bundleItemId,
                            AttributeId        = attribute.ProductAttributeId,
                            VariantAttributeId = attribute.Id,
                            Alias      = attribute.ProductAttribute.Alias,
                            ValueAlias = value.Alias
                        });
                    }
                }
            }

            // 2. Find attribute combination for selected attributes and merge it.
            if (!isBundle && query.Variants.Any())
            {
                var(selection, warnings) = await _productAttributeMaterializer.CreateAttributeSelectionAsync(query, attributes, product.Id, bundleItemId, true);

                var combinations = await context.AttributeCombinations.GetOrLoadAsync(product.Id);

                var selectedCombination = combinations.FirstOrDefault(x => x.AttributeSelection.Equals(selection));

                if (selectedCombination != null && selectedCombination.IsActive && selectedCombination.Price.HasValue)
                {
                    product.MergedDataValues = new Dictionary <string, object> {
                        { "Price", selectedCombination.Price.Value }
                    };

                    if (selectedCombination.BasePriceAmount.HasValue)
                    {
                        product.MergedDataValues.Add("BasePriceAmount", selectedCombination.BasePriceAmount.Value);
                    }

                    if (selectedCombination.BasePriceBaseAmount.HasValue)
                    {
                        product.MergedDataValues.Add("BasePriceBaseAmount", selectedCombination.BasePriceBaseAmount.Value);
                    }
                }
            }

            if (_catalogSettings.EnableDynamicPriceUpdate && !isBundlePricing)
            {
                if (selectedAttributeValues.Count > 0)
                {
                    foreach (var value in selectedAttributeValues)
                    {
                        attributesTotalPriceBase += await GetVariantPriceAdjustmentAsync(value, product, customer, context, 1);
                    }
                }
                else
                {
                    attributesTotalPriceBase = preSelectedPriceAdjustmentBase;
                }
            }

            if (bundleItem != null)
            {
                bundleItem.AdditionalCharge = new(attributesTotalPriceBase, _primaryCurrency);
            }

            var result = await GetFinalPriceAmountAsync(product, bundleItems, attributesTotalPriceBase, customer, true, 1, bundleItem, context);

            return(result);
        }
Пример #25
0
        public async Task <IActionResult> UpdateProductDetails(int productId, string itemType, int bundleItemId, ProductVariantQuery query)
        {
            // TODO: (core) UpdateProductDetails action needs some decent refactoring.
            var    form              = HttpContext.Request.Form;
            int    quantity          = 1;
            int    galleryStartIndex = -1;
            string galleryHtml       = null;
            string dynamicThumbUrl   = null;
            var    isAssociated      = itemType.EqualsNoCase("associateditem");

            var product = await _db.Products.FindByIdAsync(productId);

            var batchContext = _productService.CreateProductBatchContext(new[] { product }, includeHidden: false);
            var bItem        = await _db.ProductBundleItem
                               .Include(x => x.BundleProduct)
                               .FindByIdAsync(bundleItemId, false);

            IList <ProductBundleItemData> bundleItemDatas = null;
            ProductBundleItemData         bundleItem      = bItem == null ? null : new ProductBundleItemData(bItem);

            // Quantity required for tier prices.
            string quantityKey = form.Keys.FirstOrDefault(k => k.EndsWith("EnteredQuantity"));

            if (quantityKey.HasValue())
            {
                _ = int.TryParse(form[quantityKey], out quantity);
            }

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)
            {
                var bundleItemQuery = await _db.ProductBundleItem
                                      .AsNoTracking()
                                      .ApplyBundledProductsFilter(new[] { product.Id })
                                      .Include(x => x.Product)
                                      .Include(x => x.BundleProduct)
                                      .ToListAsync();

                if (bundleItemQuery.Count > 0)
                {
                    bundleItemDatas = new List <ProductBundleItemData>();
                    bundleItemQuery.Each(x => bundleItemDatas.Add(new ProductBundleItemData(x)));
                }

                if (query.Variants.Count > 0)
                {
                    batchContext.Collect(bundleItemDatas.Select(x => x.Item.Product.Id).ToArray());

                    // May add elements to query object if they are preselected by bundle item filter.
                    foreach (var itemData in bundleItemDatas)
                    {
                        await _helper.MapProductDetailsPageModelAsync(new ProductDetailsModelContext
                        {
                            Product           = itemData.Item.Product,
                            BatchContext      = batchContext,
                            VariantQuery      = query,
                            ProductBundleItem = itemData
                        });
                    }
                }
            }

            var modelContext = new ProductDetailsModelContext
            {
                Product             = product,
                BatchContext        = batchContext,
                VariantQuery        = query,
                IsAssociatedProduct = isAssociated,
                ProductBundleItem   = bundleItem,
                BundleItemDatas     = bundleItemDatas,
                Customer            = batchContext.Customer,
                Store    = batchContext.Store,
                Currency = Services.WorkContext.WorkingCurrency
            };

            // Get merged model data.
            var model = new ProductDetailsModel();
            await _helper.PrepareProductDetailModelAsync(model, modelContext, quantity);

            if (bundleItem != null)
            {
                // Update bundle item thumbnail.
                if (!bundleItem.Item.HideThumbnail)
                {
                    var assignedMediaIds = model.SelectedCombination?.GetAssignedMediaIds() ?? Array.Empty <int>();
                    var hasFile          = assignedMediaIds.Any() && await _db.MediaFiles.AnyAsync(x => x.Id == assignedMediaIds[0]);

                    if (assignedMediaIds.Any() && hasFile)
                    {
                        var file = await _db.ProductMediaFiles
                                   .AsNoTracking()
                                   .ApplyProductFilter(new[] { bundleItem.Item.ProductId }, 1)
                                   .Select(x => x.MediaFile)
                                   .FirstOrDefaultAsync();

                        dynamicThumbUrl = _mediaService.GetUrl(file, _mediaSettings.BundledProductPictureSize, null, false);
                    }
                }
            }
            else if (isAssociated)
            {
                // Update associated product thumbnail.
                var assignedMediaIds = model.SelectedCombination?.GetAssignedMediaIds() ?? new int[0];
                var hasFile          = await _db.MediaFiles.AnyAsync(x => x.Id == assignedMediaIds[0]);

                if (assignedMediaIds.Any() && hasFile)
                {
                    var file = await _db.ProductMediaFiles
                               .AsNoTracking()
                               .ApplyProductFilter(new[] { productId }, 1)
                               .Select(x => x.MediaFile)
                               .FirstOrDefaultAsync();

                    dynamicThumbUrl = _mediaService.GetUrl(file, _mediaSettings.AssociatedProductPictureSize, null, false);
                }
            }
            else if (product.ProductType != ProductType.BundledProduct)
            {
                // Update image gallery.
                var files = await _db.ProductMediaFiles
                            .AsNoTracking()
                            .ApplyProductFilter(new[] { productId })
                            .Select(x => _mediaService.ConvertMediaFile(x.MediaFile))
                            .ToListAsync();

                if (product.HasPreviewPicture && files.Count > 1)
                {
                    files.RemoveAt(0);
                }

                if (files.Count <= _catalogSettings.DisplayAllImagesNumber)
                {
                    // All pictures rendered... only index is required.
                    galleryStartIndex = 0;

                    var assignedMediaIds = model.SelectedCombination?.GetAssignedMediaIds() ?? new int[0];
                    if (assignedMediaIds.Any())
                    {
                        var file = files.FirstOrDefault(p => p.Id == assignedMediaIds[0]);
                        galleryStartIndex = file == null ? 0 : files.IndexOf(file);
                    }
                }
                else
                {
                    var allCombinationPictureIds = await _productAttributeService.GetAttributeCombinationFileIdsAsync(product.Id);

                    var mediaModel = _helper.PrepareProductDetailsMediaGalleryModel(
                        files,
                        product.GetLocalized(x => x.Name),
                        allCombinationPictureIds,
                        false,
                        bundleItem,
                        model.SelectedCombination);

                    galleryStartIndex = mediaModel.GalleryStartIndex;
                    galleryHtml       = (await this.InvokeViewAsync("Product.Media", mediaModel)).ToString();
                }

                model.PriceDisplayStyle        = _catalogSettings.PriceDisplayStyle;
                model.DisplayTextForZeroPrices = _catalogSettings.DisplayTextForZeroPrices;
            }

            object partials = null;

            if (model.IsBundlePart)
            {
                partials = new
                {
                    BundleItemPrice    = await this.InvokeViewAsync("Product.Offer.Price", model),
                    BundleItemStock    = await this.InvokeViewAsync("Product.StockInfo", model),
                    BundleItemVariants = await this.InvokeViewAsync("Product.Variants", model.ProductVariantAttributes)
                };
            }
            else
            {
                var dataDictAddToCart = new ViewDataDictionary(ViewData)
                {
                    Model = model
                };
                dataDictAddToCart.TemplateInfo.HtmlFieldPrefix = $"addtocart_{model.Id}";

                decimal adjustment = decimal.Zero;
                decimal taxRate    = decimal.Zero;

                // TODO: (mh) (core) Implement when pricing is available.
                //var finalPriceWithDiscountBase = _taxService.GetProductPrice(product, product.Price, Services.WorkContext.CurrentCustomer, out taxRate);

                //if (!_taxSettings.Value.PricesIncludeTax && Services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax)
                //{
                //    adjustment = (m.ProductPrice.PriceValue - finalPriceWithDiscountBase) / (taxRate / 100 + 1);
                //}
                //else if (_taxSettings.Value.PricesIncludeTax && Services.WorkContext.TaxDisplayType == TaxDisplayType.ExcludingTax)
                //{
                //    adjustment = (m.ProductPrice.PriceValue - finalPriceWithDiscountBase) * (taxRate / 100 + 1);
                //}
                //else
                //{
                //    adjustment = m.ProductPrice.PriceValue - finalPriceWithDiscountBase;
                //}

                partials = new
                {
                    Attrs        = await this.InvokeViewAsync("Product.Attrs", model),
                    Price        = await this.InvokeViewAsync("Product.Offer.Price", model),
                    Stock        = await this.InvokeViewAsync("Product.StockInfo", model),
                    Variants     = await this.InvokeViewAsync("Product.Variants", model.ProductVariantAttributes),
                    OfferActions = await this.InvokeViewAsync("Product.Offer.Actions", dataDictAddToCart),
                    TierPrices   = await this.InvokeViewAsync("Product.TierPrices", model.TierPrices),
                    BundlePrice  = product.ProductType == ProductType.BundledProduct ? await this.InvokeViewAsync("Product.Bundle.Price", model) : null
                };
            }

            object data = new
            {
                Partials          = partials,
                DynamicThumblUrl  = dynamicThumbUrl,
                GalleryStartIndex = galleryStartIndex,
                GalleryHtml       = galleryHtml
            };

            return(new JsonResult(new { Data = data }));
        }
Пример #26
0
        public async Task <IActionResult> ProductDetails(int productId, ProductVariantQuery query)
        {
            var product = await _db.Products
                          .IncludeMedia()
                          .IncludeManufacturers()
                          .Where(x => x.Id == productId)
                          .FirstOrDefaultAsync();

            if (product == null || product.IsSystemProduct)
            {
                return(NotFound());
            }

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

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

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

            // Is product individually visible?
            if (product.Visibility == ProductVisibility.Hidden)
            {
                // Find parent grouped product.
                var parentGroupedProduct = await _db.Products.FindByIdAsync(product.ParentGroupedProductId, false);

                if (parentGroupedProduct == null)
                {
                    return(NotFound());
                }

                var seName = await parentGroupedProduct.GetActiveSlugAsync();

                if (seName.IsEmpty())
                {
                    return(NotFound());
                }

                var routeValues = new RouteValueDictionary
                {
                    { "SeName", seName }
                };

                // Add query string parameters.
                Request.Query.Each(x => routeValues.Add(x.Key, Request.Query[x.Value].ToString()));

                return(RedirectToRoute("Product", routeValues));
            }

            // Prepare the view model
            var model = await _helper.MapProductDetailsPageModelAsync(product, query);

            // Some cargo data
            model.PictureSize            = _mediaSettings.ProductDetailsPictureSize;
            model.HotlineTelephoneNumber = _contactDataSettings.HotlineTelephoneNumber.NullEmpty();
            if (_seoSettings.CanonicalUrlsEnabled)
            {
                model.CanonicalUrl = _urlHelper.Value.RouteUrl("Product", new { model.SeName }, Request.Scheme);
            }

            // Save as recently viewed
            _recentlyViewedProductsService.AddProductToRecentlyViewedList(product.Id);

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

            // Breadcrumb
            if (_catalogSettings.CategoryBreadcrumbEnabled)
            {
                await _helper.GetBreadcrumbAsync(_breadcrumb, ControllerContext, product);

                _breadcrumb.Track(new MenuItem
                {
                    Text     = model.Name,
                    Rtl      = model.Name.CurrentLanguage.Rtl,
                    EntityId = product.Id,
                    Url      = Url.RouteUrl("Product", new { model.SeName })
                });
            }

            return(View(model.ProductTemplateViewPath, model));
        }
        protected virtual string ToQueryString(ProductVariantQuery query)
        {
            var qs = InitialQuery != null
                                ? new QueryString(InitialQuery)
                                : new QueryString();

            // Checkout Attributes
            foreach (var item in query.CheckoutAttributes)
            {
                var name = item.ToString();

                if (item.Date.HasValue)
                {
                    qs.Add(name + "-date", string.Join("-", item.Date.Value.Year, item.Date.Value.Month, item.Date.Value.Day));
                }
                else
                {
                    qs.Add(name, item.Value);
                }
            }

            // Gift cards
            foreach (var item in query.GiftCards)
            {
                qs.Add(item.ToString(), item.Value);
            }

            // Variants
            foreach (var item in query.Variants)
            {
                if (item.Alias.IsEmpty())
                {
                    item.Alias = _catalogSearchQueryAliasMapper.Value.GetVariantAliasById(item.AttributeId, _languageId);
                }

                var name = item.Alias.HasValue()
                                        ? $"{item.Alias}-{item.ProductId}-{item.BundleItemId}-{item.VariantAttributeId}"
                                        : item.ToString();

                if (item.Date.HasValue)
                {
                    // TODO: Code never reached because of ParseProductVariantAttributeValues
                    qs.Add(name + "-date", string.Join("-", item.Date.Value.Year, item.Date.Value.Month, item.Date.Value.Day));
                }
                else
                {
                    if (item.ValueAlias.IsEmpty())
                    {
                        item.ValueAlias = _catalogSearchQueryAliasMapper.Value.GetVariantOptionAliasById(item.Value.ToInt(), _languageId);
                    }

                    var value = item.ValueAlias.HasValue()
                                                ? $"{item.ValueAlias}-{item.Value}"
                                                : item.Value;

                    qs.Add(name, value);
                }
            }

            return(qs.ToString(false));
        }
Пример #28
0
        public ActionResult ProductDetails(int productId, string attributes, ProductVariantQuery query)
        {
            var product = _productService.GetProductById(productId);

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

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

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

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

            // Is product individually visible?
            if (!product.VisibleIndividually)
            {
                // Find parent grouped product.
                var parentGroupedProduct = _productService.GetProductById(product.ParentGroupedProductId);

                if (parentGroupedProduct == null)
                {
                    return(HttpNotFound());
                }

                var routeValues = new RouteValueDictionary();
                routeValues.Add("SeName", parentGroupedProduct.GetSeName());

                // Add query string parameters.
                Request.QueryString.AllKeys.Each(x => routeValues.Add(x, Request.QueryString[x]));

                return(RedirectToRoute("Product", routeValues));
            }

            // Prepare the view model
            var model = _helper.PrepareProductDetailsPageModel(product, query);

            // Some cargo data
            model.PictureSize          = _mediaSettings.ProductDetailsPictureSize;
            model.CanonicalUrlsEnabled = _seoSettings.CanonicalUrlsEnabled;

            // Save as recently viewed
            _recentlyViewedProductsService.AddProductToRecentlyViewedList(product.Id);

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

            // Breadcrumb
            if (_catalogSettings.CategoryBreadcrumbEnabled)
            {
                _helper.GetCategoryBreadCrumb(0, productId).Select(x => x.Value).Each(x => _breadcrumb.Track(x));
                _breadcrumb.Track(new MenuItem
                {
                    Text     = model.Name,
                    Rtl      = model.Name.CurrentLanguage.Rtl,
                    EntityId = product.Id,
                    Url      = Url.RouteUrl("Product", new { productId = product.Id, SeName = model.SeName })
                });
            }

            return(View(model.ProductTemplateViewPath, model));
        }
Пример #29
0
        public ActionResult UpdateProductDetails(int productId, string itemType, int bundleItemId, ProductVariantQuery query, FormCollection form)
        {
            int    quantity          = 1;
            int    galleryStartIndex = -1;
            string galleryHtml       = null;
            string dynamicThumbUrl   = null;
            var    isAssociated      = itemType.IsCaseInsensitiveEqual("associateditem");
            var    pictureModel      = new ProductDetailsPictureModel();
            var    m       = new ProductDetailsModel();
            var    product = _productService.GetProductById(productId);
            var    bItem   = _productService.GetBundleItemById(bundleItemId);
            IList <ProductBundleItemData> bundleItems = null;
            ProductBundleItemData         bundleItem  = (bItem == null ? null : new ProductBundleItemData(bItem));

            // Quantity required for tier prices.
            string quantityKey = form.AllKeys.FirstOrDefault(k => k.EndsWith("EnteredQuantity"));

            if (quantityKey.HasValue())
            {
                int.TryParse(form[quantityKey], out quantity);
            }

            if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)
            {
                bundleItems = _productService.GetBundleItems(product.Id);
                if (query.Variants.Count > 0)
                {
                    // May add elements to query object if they are preselected by bundle item filter.
                    foreach (var itemData in bundleItems)
                    {
                        _helper.PrepareProductDetailsPageModel(itemData.Item.Product, query, false, itemData, null);
                    }
                }
            }

            // Get merged model data.
            _helper.PrepareProductDetailModel(m, product, query, isAssociated, bundleItem, bundleItems, quantity);

            if (bundleItem != null)
            {
                // Update bundle item thumbnail.
                if (!bundleItem.Item.HideThumbnail)
                {
                    var picture = m.GetAssignedPicture(_pictureService, null, bundleItem.Item.ProductId);
                    dynamicThumbUrl = _pictureService.GetUrl(picture, _mediaSettings.BundledProductPictureSize, false);
                }
            }
            else if (isAssociated)
            {
                // Update associated product thumbnail.
                var picture = m.GetAssignedPicture(_pictureService, null, productId);
                dynamicThumbUrl = _pictureService.GetUrl(picture, _mediaSettings.AssociatedProductPictureSize, false);
            }
            else if (product.ProductType != ProductType.BundledProduct)
            {
                // Update image gallery.
                var pictures = _pictureService.GetPicturesByProductId(productId);

                if (pictures.Count <= _catalogSettings.DisplayAllImagesNumber)
                {
                    // All pictures rendered... only index is required.
                    var picture = m.GetAssignedPicture(_pictureService, pictures);
                    galleryStartIndex = (picture == null ? 0 : pictures.IndexOf(picture));
                }
                else
                {
                    var allCombinationPictureIds = _productAttributeService.GetAllProductVariantAttributeCombinationPictureIds(product.Id);

                    _helper.PrepareProductDetailsPictureModel(
                        pictureModel,
                        pictures,
                        product.GetLocalized(x => x.Name),
                        allCombinationPictureIds,
                        false,
                        bundleItem,
                        m.SelectedCombination);

                    galleryStartIndex = pictureModel.GalleryStartIndex;
                    galleryHtml       = this.RenderPartialViewToString("Product.Picture", pictureModel);
                }
            }

            object partials = null;

            if (m.IsBundlePart)
            {
                partials = new
                {
                    BundleItemPrice = this.RenderPartialViewToString("Product.Offer.Price", m),
                    BundleItemStock = this.RenderPartialViewToString("Product.StockInfo", m)
                };
            }
            else
            {
                var dataDictAddToCart = new ViewDataDictionary();
                dataDictAddToCart.TemplateInfo.HtmlFieldPrefix = string.Format("addtocart_{0}", m.Id);

                decimal adjustment = decimal.Zero;
                decimal taxRate    = decimal.Zero;
                var     finalPriceWithDiscountBase = _taxService.GetProductPrice(product, product.Price, _services.WorkContext.CurrentCustomer, out taxRate);

                if (!_taxSettings.Value.PricesIncludeTax && _services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax)
                {
                    adjustment = (m.ProductPrice.PriceValue - finalPriceWithDiscountBase) / (taxRate / 100 + 1);
                }
                else if (_taxSettings.Value.PricesIncludeTax && _services.WorkContext.TaxDisplayType == TaxDisplayType.ExcludingTax)
                {
                    adjustment = (m.ProductPrice.PriceValue - finalPriceWithDiscountBase) * (taxRate / 100 + 1);
                }
                else
                {
                    adjustment = m.ProductPrice.PriceValue - finalPriceWithDiscountBase;
                }

                partials = new
                {
                    Attrs        = this.RenderPartialViewToString("Product.Attrs", m),
                    Price        = this.RenderPartialViewToString("Product.Offer.Price", m),
                    Stock        = this.RenderPartialViewToString("Product.StockInfo", m),
                    OfferActions = this.RenderPartialViewToString("Product.Offer.Actions", m, dataDictAddToCart),
                    TierPrices   = this.RenderPartialViewToString("Product.TierPrices", _helper.CreateTierPriceModel(product, adjustment)),
                    BundlePrice  = product.ProductType == ProductType.BundledProduct ? this.RenderPartialViewToString("Product.Bundle.Price", m) : (string)null
                };
            }

            object data = new
            {
                Partials          = partials,
                DynamicThumblUrl  = dynamicThumbUrl,
                GalleryStartIndex = galleryStartIndex,
                GalleryHtml       = galleryHtml
            };

            return(new JsonResult {
                Data = data
            });
        }
Пример #30
0
        protected virtual decimal GetPreselectedPrice(
            Product product,
            Customer customer,
            PriceCalculationContext context,
            ProductBundleItemData bundleItem,
            IEnumerable <ProductBundleItemData> bundleItems)
        {
            var taxRate = decimal.Zero;
            var attributesTotalPriceBase       = decimal.Zero;
            var preSelectedPriceAdjustmentBase = decimal.Zero;
            var isBundle            = (product.ProductType == ProductType.BundledProduct);
            var isBundleItemPricing = (bundleItem != null && bundleItem.Item.BundleProduct.BundlePerItemPricing);
            var isBundlePricing     = (bundleItem != null && !bundleItem.Item.BundleProduct.BundlePerItemPricing);
            var bundleItemId        = (bundleItem == null ? 0 : bundleItem.Item.Id);

            var query = new ProductVariantQuery();
            var selectedAttributeValues = new List <ProductVariantAttributeValue>();
            var attributes = context.Attributes.GetOrLoad(product.Id);

            // 1. Fill query with initially selected attributes.
            foreach (var attribute in attributes.Where(x => x.ProductVariantAttributeValues.Count > 0 && x.ShouldHaveValues()))
            {
                int preSelectedValueId = 0;
                ProductVariantAttributeValue defaultValue = null;
                var selectedValueIds = new List <int>();
                var pvaValues        = attribute.ProductVariantAttributeValues;

                foreach (var pvaValue in pvaValues)
                {
                    ProductBundleItemAttributeFilter attributeFilter = null;

                    if (bundleItem.FilterOut(pvaValue, out attributeFilter))
                    {
                        continue;
                    }

                    if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected)
                    {
                        preSelectedValueId = attributeFilter.AttributeValueId;
                    }

                    if (!isBundlePricing && pvaValue.IsPreSelected)
                    {
                        decimal attributeValuePriceAdjustment = GetProductVariantAttributeValuePriceAdjustment(pvaValue);
                        decimal priceAdjustmentBase           = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, out taxRate);

                        preSelectedPriceAdjustmentBase = decimal.Add(preSelectedPriceAdjustmentBase, priceAdjustmentBase);
                    }
                }

                // Value pre-selected by a bundle item filter discards the default pre-selection.
                if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null)
                {
                    //defaultValue.IsPreSelected = true;
                    selectedAttributeValues.Add(defaultValue);
                    query.AddVariant(new ProductVariantQueryItem(defaultValue.Id.ToString())
                    {
                        ProductId          = product.Id,
                        BundleItemId       = bundleItemId,
                        AttributeId        = attribute.ProductAttributeId,
                        VariantAttributeId = attribute.Id,
                        Alias      = attribute.ProductAttribute.Alias,
                        ValueAlias = defaultValue.Alias
                    });
                }
                else
                {
                    foreach (var value in pvaValues.Where(x => x.IsPreSelected))
                    {
                        selectedAttributeValues.Add(value);
                        query.AddVariant(new ProductVariantQueryItem(value.Id.ToString())
                        {
                            ProductId          = product.Id,
                            BundleItemId       = bundleItemId,
                            AttributeId        = attribute.ProductAttributeId,
                            VariantAttributeId = attribute.Id,
                            Alias      = attribute.ProductAttribute.Alias,
                            ValueAlias = value.Alias
                        });
                    }
                }
            }

            // 2. Find attribute combination for selected attributes and merge it.
            if (!isBundle && query.Variants.Count > 0)
            {
                var attributeXml = query.CreateSelectedAttributesXml(product.Id, bundleItemId, attributes, _productAttributeParser, _services.Localization,
                                                                     _downloadService, _catalogSettings, _httpRequestBase, new List <string>());

                var combinations = context.AttributeCombinations.GetOrLoad(product.Id);

                var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml));

                if (selectedCombination != null && selectedCombination.IsActive && selectedCombination.Price.HasValue)
                {
                    product.MergedDataValues = new Dictionary <string, object> {
                        { "Price", selectedCombination.Price.Value }
                    };

                    if (selectedCombination.BasePriceAmount.HasValue)
                    {
                        product.MergedDataValues.Add("BasePriceAmount", selectedCombination.BasePriceAmount.Value);
                    }

                    if (selectedCombination.BasePriceBaseAmount.HasValue)
                    {
                        product.MergedDataValues.Add("BasePriceBaseAmount", selectedCombination.BasePriceBaseAmount.Value);
                    }
                }
            }

            if (_catalogSettings.EnableDynamicPriceUpdate && !isBundlePricing)
            {
                if (selectedAttributeValues.Count > 0)
                {
                    selectedAttributeValues.Each(x => attributesTotalPriceBase += GetProductVariantAttributeValuePriceAdjustment(x));
                }
                else
                {
                    attributesTotalPriceBase = preSelectedPriceAdjustmentBase;
                }
            }

            if (bundleItem != null)
            {
                bundleItem.AdditionalCharge = attributesTotalPriceBase;
            }

            var result = GetFinalPrice(product, bundleItems, customer, attributesTotalPriceBase, true, 1, bundleItem, context);

            return(result);
        }