/// <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)); }
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 ); } }
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 }) } })); }
/// <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()); }
/// <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)); }
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); }
/// <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)); }
/// <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); } } }
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(); }
/// <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(); }
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}")); }
/// <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)); }
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 }); }
/// <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); }
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); }
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 })); }
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)); }
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)); }
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 }); }
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); }