private async Task <StringBuilder> PrepareFormattedAttribute(Product product, string attributesXml, string langId, string serapator, bool htmlEncode, bool renderPrices, bool allowHyperlinks, bool showInAdmin) { var result = new StringBuilder(); var attributes = _productAttributeParser.ParseProductAttributeMappings(product, attributesXml); for (int i = 0; i < attributes.Count; i++) { var productAttribute = await _productAttributeService.GetProductAttributeById(attributes[i].ProductAttributeId); var attribute = attributes[i]; var valuesStr = _productAttributeParser.ParseValues(attributesXml, attribute.Id); for (int j = 0; j < valuesStr.Count; j++) { string valueStr = valuesStr[j]; string formattedAttribute = string.Empty; if (!attribute.ShouldHaveValues()) { //no values if (attribute.AttributeControlType == AttributeControlType.MultilineTextbox) { //multiline textbox var attributeName = productAttribute.GetLocalized(a => a.Name, langId); //encode (if required) if (htmlEncode) { attributeName = WebUtility.HtmlEncode(attributeName); } formattedAttribute = string.Format("{0}: {1}", attributeName, HtmlHelper.FormatText(valueStr)); //we never encode multiline textbox input } else if (attribute.AttributeControlType == AttributeControlType.FileUpload) { //file upload Guid downloadGuid; Guid.TryParse(valueStr, out downloadGuid); var download = await _downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) string attributeText = ""; var fileName = string.Format("{0}{1}", download.Filename ?? download.DownloadGuid.ToString(), download.Extension); //encode (if required) if (htmlEncode) { fileName = WebUtility.HtmlEncode(fileName); } if (allowHyperlinks) { //hyperlinks are allowed var downloadLink = string.Format("{0}download/getfileupload/?downloadId={1}", _webHelper.GetStoreLocation(false), download.DownloadGuid); attributeText = string.Format("<a href=\"{0}\" class=\"fileuploadattribute\">{1}</a>", downloadLink, fileName); } else { //hyperlinks aren't allowed attributeText = fileName; } var attributeName = productAttribute.GetLocalized(a => a.Name, langId); //encode (if required) if (htmlEncode) { attributeName = WebUtility.HtmlEncode(attributeName); } formattedAttribute = string.Format("{0}: {1}", attributeName, attributeText); } } else { //other attributes (textbox, datepicker) formattedAttribute = string.Format("{0}: {1}", productAttribute.GetLocalized(a => a.Name, langId), valueStr); //encode (if required) if (htmlEncode) { formattedAttribute = WebUtility.HtmlEncode(formattedAttribute); } } } else { //attributes with values if (product.ProductAttributeMappings.Where(x => x.Id == attributes[i].Id).FirstOrDefault() != null) { var attributeValue = product.ProductAttributeMappings.Where(x => x.Id == attributes[i].Id).FirstOrDefault().ProductAttributeValues.Where(x => x.Id == valueStr).FirstOrDefault(); if (attributeValue != null) { formattedAttribute = string.Format("{0}: {1}", productAttribute.GetLocalized(a => a.Name, langId), attributeValue.GetLocalized(a => a.Name, langId)); if (renderPrices) { decimal attributeValuePriceAdjustment = await _priceCalculationService.GetProductAttributeValuePriceAdjustment(attributeValue); var prices = await _taxService.GetProductPrice(product, attributeValuePriceAdjustment, _workContext.CurrentCustomer); decimal priceAdjustmentBase = prices.productprice; decimal taxRate = prices.taxRate; decimal priceAdjustment = await _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > 0) { string priceAdjustmentStr = _priceFormatter.FormatPrice(priceAdjustment, false, false); formattedAttribute += string.Format(" [+{0}]", priceAdjustmentStr); } else if (priceAdjustmentBase < decimal.Zero) { string priceAdjustmentStr = _priceFormatter.FormatPrice(-priceAdjustment, false, false); formattedAttribute += string.Format(" [-{0}]", priceAdjustmentStr); } } //display quantity if (_shoppingCartSettings.RenderAssociatedAttributeValueQuantity && attributeValue.AttributeValueType == AttributeValueType.AssociatedToProduct) { //render only when more than 1 if (attributeValue.Quantity > 1) { //TODO localize resource formattedAttribute += string.Format(" - qty {0}", attributeValue.Quantity); } } } else { if (showInAdmin) { formattedAttribute += string.Format("{0}: {1}", productAttribute.GetLocalized(a => a.Name, langId), ""); } } //encode (if required) if (htmlEncode) { formattedAttribute = WebUtility.HtmlEncode(formattedAttribute); } } } if (!String.IsNullOrEmpty(formattedAttribute)) { if (i != 0 || j != 0) { result.Append(serapator); } result.Append(formattedAttribute); } } } return(result); }
/// <summary> /// Formats attributes /// </summary> /// <param name="product">Product</param> /// <param name="attributesXml">Attributes in XML format</param> /// <param name="customer">Customer</param> /// <param name="serapator">Serapator</param> /// <param name="htmlEncode">A value indicating whether to encode (HTML) values</param> /// <param name="renderPrices">A value indicating whether to render prices</param> /// <param name="renderProductAttributes">A value indicating whether to render product attributes</param> /// <param name="renderGiftCardAttributes">A value indicating whether to render gift card attributes</param> /// <param name="allowHyperlinks">A value indicating whether to HTML hyperink tags could be rendered (if required)</param> /// <returns>Attributes</returns> public virtual string FormatAttributes(Product product, string attributesXml, Customer customer, string serapator = "<br />", bool htmlEncode = true, bool renderPrices = true, bool renderProductAttributes = true, bool renderGiftCardAttributes = true, bool allowHyperlinks = true) { var result = new StringBuilder(); //attributes if (renderProductAttributes) { var attributes = _productAttributeParser.ParseProductAttributeMappings(product, attributesXml); for (int i = 0; i < attributes.Count; i++) { var productAttribute = _productAttributeService.GetProductAttributeById(attributes[i].ProductAttributeId); var attribute = attributes[i]; var valuesStr = _productAttributeParser.ParseValues(attributesXml, attribute.Id); for (int j = 0; j < valuesStr.Count; j++) { string valueStr = valuesStr[j]; string formattedAttribute = string.Empty; if (!attribute.ShouldHaveValues()) { //no values if (attribute.AttributeControlType == AttributeControlType.MultilineTextbox) { //multiline textbox var attributeName = productAttribute.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = HttpUtility.HtmlEncode(attributeName); } formattedAttribute = string.Format("{0}: {1}", attributeName, HtmlHelper.FormatText(valueStr, false, true, false, false, false, false)); //we never encode multiline textbox input } else if (attribute.AttributeControlType == AttributeControlType.FileUpload) { //file upload Guid downloadGuid; Guid.TryParse(valueStr, out downloadGuid); var download = _downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) string attributeText = ""; var fileName = string.Format("{0}{1}", download.Filename ?? download.DownloadGuid.ToString(), download.Extension); //encode (if required) if (htmlEncode) { fileName = HttpUtility.HtmlEncode(fileName); } if (allowHyperlinks) { //hyperlinks are allowed var downloadLink = string.Format("{0}download/getfileupload/?downloadId={1}", _webHelper.GetStoreLocation(false), download.DownloadGuid); attributeText = string.Format("<a href=\"{0}\" class=\"fileuploadattribute\">{1}</a>", downloadLink, fileName); } else { //hyperlinks aren't allowed attributeText = fileName; } var attributeName = productAttribute.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = HttpUtility.HtmlEncode(attributeName); } formattedAttribute = string.Format("{0}: {1}", attributeName, attributeText); } } else { //other attributes (textbox, datepicker) formattedAttribute = string.Format("{0}: {1}", productAttribute.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id), valueStr); //encode (if required) if (htmlEncode) { formattedAttribute = HttpUtility.HtmlEncode(formattedAttribute); } } } else { //attributes with values int attributeValueId; if (int.TryParse(valueStr, out attributeValueId)) { if (product.ProductAttributeMappings.Where(x => x.ProductAttributeId == attributes[i].ProductAttributeId).FirstOrDefault() != null) { var attributeValue = product.ProductAttributeMappings.Where(x => x.ProductAttributeId == attributes[i].ProductAttributeId).FirstOrDefault().ProductAttributeValues.Where(x => x.Id == attributeValueId).FirstOrDefault(); //_productAttributeService.GetProductAttributeValueById(attributeValueId); if (attributeValue != null) { formattedAttribute = string.Format("{0}: {1}", productAttribute.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id), attributeValue.GetLocalized(a => a.Name, _workContext.WorkingLanguage.Id)); if (renderPrices) { decimal taxRate; decimal attributeValuePriceAdjustment = _priceCalculationService.GetProductAttributeValuePriceAdjustment(attributeValue); decimal priceAdjustmentBase = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, customer, out taxRate); decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > 0) { string priceAdjustmentStr = _priceFormatter.FormatPrice(priceAdjustment, false, false); formattedAttribute += string.Format(" [+{0}]", priceAdjustmentStr); } else if (priceAdjustmentBase < decimal.Zero) { string priceAdjustmentStr = _priceFormatter.FormatPrice(-priceAdjustment, false, false); formattedAttribute += string.Format(" [-{0}]", priceAdjustmentStr); } } //display quantity if (_shoppingCartSettings.RenderAssociatedAttributeValueQuantity && attributeValue.AttributeValueType == AttributeValueType.AssociatedToProduct) { //render only when more than 1 if (attributeValue.Quantity > 1) { //TODO localize resource formattedAttribute += string.Format(" - qty {0}", attributeValue.Quantity); } } } } //encode (if required) if (htmlEncode) { formattedAttribute = HttpUtility.HtmlEncode(formattedAttribute); } } } if (!String.IsNullOrEmpty(formattedAttribute)) { if (i != 0 || j != 0) { result.Append(serapator); } result.Append(formattedAttribute); } } } } //gift cards if (renderGiftCardAttributes) { if (product.IsGiftCard) { string giftCardRecipientName; string giftCardRecipientEmail; string giftCardSenderName; string giftCardSenderEmail; string giftCardMessage; _productAttributeParser.GetGiftCardAttribute(attributesXml, out giftCardRecipientName, out giftCardRecipientEmail, out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage); //sender var giftCardFrom = product.GiftCardType == GiftCardType.Virtual ? string.Format(_localizationService.GetResource("GiftCardAttribute.From.Virtual"), giftCardSenderName, giftCardSenderEmail) : string.Format(_localizationService.GetResource("GiftCardAttribute.From.Physical"), giftCardSenderName); //recipient var giftCardFor = product.GiftCardType == GiftCardType.Virtual ? string.Format(_localizationService.GetResource("GiftCardAttribute.For.Virtual"), giftCardRecipientName, giftCardRecipientEmail) : string.Format(_localizationService.GetResource("GiftCardAttribute.For.Physical"), giftCardRecipientName); //encode (if required) if (htmlEncode) { giftCardFrom = HttpUtility.HtmlEncode(giftCardFrom); giftCardFor = HttpUtility.HtmlEncode(giftCardFor); } if (!String.IsNullOrEmpty(result.ToString())) { result.Append(serapator); } result.Append(giftCardFrom); result.Append(serapator); result.Append(giftCardFor); } } return(result.ToString()); }
/// <summary> /// Formats attributes /// </summary> /// <param name="product">Product</param> /// <param name="attributesXml">Attributes in XML format</param> /// <param name="customer">Customer</param> /// <param name="separator">Separator</param> /// <param name="htmlEncode">A value indicating whether to encode (HTML) values</param> /// <param name="renderPrices">A value indicating whether to render prices</param> /// <param name="renderProductAttributes">A value indicating whether to render product attributes</param> /// <param name="renderGiftCardAttributes">A value indicating whether to render gift card attributes</param> /// <param name="allowHyperlinks">A value indicating whether to HTML hyperink tags could be rendered (if required)</param> /// <returns>Attributes</returns> public virtual string FormatAttributes(Product product, string attributesXml, Customer customer, string separator = "<br />", bool htmlEncode = true, bool renderPrices = true, bool renderProductAttributes = true, bool renderGiftCardAttributes = true, bool allowHyperlinks = true) { var result = new StringBuilder(); //attributes if (renderProductAttributes) { foreach (var attribute in _productAttributeParser.ParseProductAttributeMappings(attributesXml)) { //attributes without values if (!attribute.ShouldHaveValues()) { foreach (var value in _productAttributeParser.ParseValues(attributesXml, attribute.Id)) { var formattedAttribute = string.Empty; if (attribute.AttributeControlType == AttributeControlType.MultilineTextbox) { //multiline textbox var attributeName = _localizationService.GetLocalized(attribute.ProductAttribute, a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = WebUtility.HtmlEncode(attributeName); } //we never encode multiline textbox input formattedAttribute = $"{attributeName}: {HtmlHelper.FormatText(value, false, true, false, false, false, false)}"; } else if (attribute.AttributeControlType == AttributeControlType.FileUpload) { //file upload Guid.TryParse(value, out var downloadGuid); var download = _downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { var fileName = $"{download.Filename ?? download.DownloadGuid.ToString()}{download.Extension}"; //encode (if required) if (htmlEncode) { fileName = WebUtility.HtmlEncode(fileName); } //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) var attributeText = allowHyperlinks ? $"<a href=\"{_webHelper.GetStoreLocation(false)}download/getfileupload/?downloadId={download.DownloadGuid}\" class=\"fileuploadattribute\">{fileName}</a>" : fileName; var attributeName = _localizationService.GetLocalized(attribute.ProductAttribute, a => a.Name, _workContext.WorkingLanguage.Id); //encode (if required) if (htmlEncode) { attributeName = WebUtility.HtmlEncode(attributeName); } formattedAttribute = $"{attributeName}: {attributeText}"; } } else { //other attributes (textbox, datepicker) formattedAttribute = $"{_localizationService.GetLocalized(attribute.ProductAttribute, a => a.Name, _workContext.WorkingLanguage.Id)}: {value}"; //encode (if required) if (htmlEncode) { formattedAttribute = WebUtility.HtmlEncode(formattedAttribute); } } if (string.IsNullOrEmpty(formattedAttribute)) { continue; } if (result.Length > 0) { result.Append(separator); } result.Append(formattedAttribute); } } //product attribute values else { foreach (var attributeValue in _productAttributeParser.ParseProductAttributeValues(attributesXml, attribute.Id)) { var formattedAttribute = $"{_localizationService.GetLocalized(attribute.ProductAttribute, a => a.Name, _workContext.WorkingLanguage.Id)}: {_localizationService.GetLocalized(attributeValue, a => a.Name, _workContext.WorkingLanguage.Id)}"; if (renderPrices) { if (attributeValue.PriceAdjustmentUsePercentage) { if (attributeValue.PriceAdjustment > decimal.Zero) { formattedAttribute += string.Format( _localizationService.GetResource("FormattedAttributes.PriceAdjustment"), "+", attributeValue.PriceAdjustment.ToString("G29"), "%"); } else if (attributeValue.PriceAdjustment < decimal.Zero) { formattedAttribute += string.Format( _localizationService.GetResource("FormattedAttributes.PriceAdjustment"), string.Empty, attributeValue.PriceAdjustment.ToString("G29"), "%"); } } else { var attributeValuePriceAdjustment = _priceCalculationService.GetProductAttributeValuePriceAdjustment(attributeValue, customer); var priceAdjustmentBase = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, customer, out var _); var priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (priceAdjustmentBase > decimal.Zero) { formattedAttribute += string.Format( _localizationService.GetResource("FormattedAttributes.PriceAdjustment"), "+", _priceFormatter.FormatPrice(priceAdjustment, false, false), string.Empty); } else if (priceAdjustmentBase < decimal.Zero) { formattedAttribute += string.Format( _localizationService.GetResource("FormattedAttributes.PriceAdjustment"), "-", _priceFormatter.FormatPrice(-priceAdjustment, false, false), string.Empty); } } } //display quantity if (_shoppingCartSettings.RenderAssociatedAttributeValueQuantity && attributeValue.AttributeValueType == AttributeValueType.AssociatedToProduct) { //render only when more than 1 if (attributeValue.Quantity > 1) { formattedAttribute += string.Format(_localizationService.GetResource("ProductAttributes.Quantity"), attributeValue.Quantity); } } //encode (if required) if (htmlEncode) { formattedAttribute = WebUtility.HtmlEncode(formattedAttribute); } if (string.IsNullOrEmpty(formattedAttribute)) { continue; } if (result.Length > 0) { result.Append(separator); } result.Append(formattedAttribute); } } } } //gift cards if (!renderGiftCardAttributes) { return(result.ToString()); } if (!product.IsGiftCard) { return(result.ToString()); } _productAttributeParser.GetGiftCardAttribute(attributesXml, out var giftCardRecipientName, out var giftCardRecipientEmail, out var giftCardSenderName, out var giftCardSenderEmail, out var _); //sender var giftCardFrom = product.GiftCardType == GiftCardType.Virtual ? string.Format(_localizationService.GetResource("GiftCardAttribute.From.Virtual"), giftCardSenderName, giftCardSenderEmail) : string.Format(_localizationService.GetResource("GiftCardAttribute.From.Physical"), giftCardSenderName); //recipient var giftCardFor = product.GiftCardType == GiftCardType.Virtual ? string.Format(_localizationService.GetResource("GiftCardAttribute.For.Virtual"), giftCardRecipientName, giftCardRecipientEmail) : string.Format(_localizationService.GetResource("GiftCardAttribute.For.Physical"), giftCardRecipientName); //encode (if required) if (htmlEncode) { giftCardFrom = WebUtility.HtmlEncode(giftCardFrom); giftCardFor = WebUtility.HtmlEncode(giftCardFor); } if (!string.IsNullOrEmpty(result.ToString())) { result.Append(separator); } result.Append(giftCardFrom); result.Append(separator); result.Append(giftCardFor); return(result.ToString()); }
/// <inheritdoc /> /// <summary> /// Function remains unmodifed and is present so custom code is called (PrepareProductAttributeModels) /// Prepare the product details model /// </summary> /// <param name="product">Product</param> /// <param name="updatecartitem">Updated shopping cart item</param> /// <param name="isAssociatedProduct">Whether the product is associated</param> /// <returns>Product details model</returns> //public override ProductDetailsModel PrepareProductDetailsModel(Product product, // ShoppingCartItem updatecartitem = null, bool isAssociatedProduct = false) //{ // if (product == null) // throw new ArgumentNullException(nameof(product)); // //standard properties // var model = new ProductDetailsModel // { // Id = product.Id, // Name = _localizationService.GetLocalized(product, x => x.Name), // ShortDescription = _localizationService.GetLocalized(product, x => x.ShortDescription), // FullDescription = _localizationService.GetLocalized(product, x => x.FullDescription), // MetaKeywords = _localizationService.GetLocalized(product, x => x.MetaKeywords), // MetaDescription = _localizationService.GetLocalized(product, x => x.MetaDescription), // MetaTitle = _localizationService.GetLocalized(product, x => x.MetaTitle), // SeName = _urlRecordService.GetSeName(product), // ProductType = product.ProductType, // ShowSku = _catalogSettings.ShowSkuOnProductDetailsPage, // Sku = product.Sku, // ShowManufacturerPartNumber = _catalogSettings.ShowManufacturerPartNumber, // FreeShippingNotificationEnabled = _catalogSettings.ShowFreeShippingNotification, // ManufacturerPartNumber = product.ManufacturerPartNumber, // ShowGtin = _catalogSettings.ShowGtin, // Gtin = product.Gtin, // ManageInventoryMethod = product.ManageInventoryMethod, // StockAvailability = _productService.FormatStockMessage(product, ""), // HasSampleDownload = product.IsDownload && product.HasSampleDownload, // DisplayDiscontinuedMessage = !product.Published && _catalogSettings.DisplayDiscontinuedMessageForUnpublishedProducts // }; // //automatically generate product description? // if (_seoSettings.GenerateProductMetaDescription && string.IsNullOrEmpty(model.MetaDescription)) // { // //based on short description // model.MetaDescription = model.ShortDescription; // } // //shipping info // model.IsShipEnabled = product.IsShipEnabled; // if (product.IsShipEnabled) // { // model.IsFreeShipping = product.IsFreeShipping; // //delivery date // var deliveryDate = _dateRangeService.GetDeliveryDateById(product.DeliveryDateId); // if (deliveryDate != null) // { // model.DeliveryDate = _localizationService.GetLocalized(deliveryDate, dd => dd.Name); // } // } // //email a friend // model.EmailAFriendEnabled = _catalogSettings.EmailAFriendEnabled; // //compare products // model.CompareProductsEnabled = _catalogSettings.CompareProductsEnabled; // //store name // model.CurrentStoreName = _localizationService.GetLocalized(_storeContext.CurrentStore, x => x.Name); // //vendor details // if (_vendorSettings.ShowVendorOnProductDetailsPage) // { // var vendor = _vendorService.GetVendorById(product.VendorId); // if (vendor != null && !vendor.Deleted && vendor.Active) // { // model.ShowVendor = true; // model.VendorModel = new VendorBriefInfoModel // { // Id = vendor.Id, // Name = _localizationService.GetLocalized(vendor, x => x.Name), // SeName = _urlRecordService.GetSeName(vendor), // }; // } // } // //page sharing // if (_catalogSettings.ShowShareButton && !string.IsNullOrEmpty(_catalogSettings.PageShareCode)) // { // var shareCode = _catalogSettings.PageShareCode; // if (_webHelper.IsCurrentConnectionSecured()) // { // //need to change the add this link to be https linked when the page is, so that the page doesn't ask about mixed mode when viewed in https... // shareCode = shareCode.Replace("http://", "https://"); // } // model.PageShareCode = shareCode; // } // //back in stock subscriptions // if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock && // product.BackorderMode == BackorderMode.NoBackorders && // product.AllowBackInStockSubscriptions && // _productService.GetTotalStockQuantity(product) <= 0) // { // //out of stock // model.DisplayBackInStockSubscription = true; // } // //breadcrumb // //do not prepare this model for the associated products. anyway it's not used // if (_catalogSettings.CategoryBreadcrumbEnabled && !isAssociatedProduct) // { // model.Breadcrumb = PrepareProductBreadcrumbModel(product); // } // //product tags // //do not prepare this model for the associated products. anyway it's not used // if (!isAssociatedProduct) // { // model.ProductTags = PrepareProductTagModels(product); // } // //pictures // model.DefaultPictureZoomEnabled = _mediaSettings.DefaultPictureZoomEnabled; // model.DefaultPictureModel = PrepareProductDetailsPictureModel(product, isAssociatedProduct, out IList<PictureModel> allPictureModels); // model.PictureModels = allPictureModels; // //price // model.ProductPrice = PrepareProductPriceModel(product); // //'Add to cart' model // model.AddToCart = PrepareProductAddToCartModel(product, updatecartitem); // //gift card // if (product.IsGiftCard) // { // model.GiftCard.IsGiftCard = true; // model.GiftCard.GiftCardType = product.GiftCardType; // if (updatecartitem == null) // { // model.GiftCard.SenderName = _customerService.GetCustomerFullName(_workContext.CurrentCustomer); // model.GiftCard.SenderEmail = _workContext.CurrentCustomer.Email; // } // else // { // _productAttributeParser.GetGiftCardAttribute(updatecartitem.AttributesXml, // out string giftCardRecipientName, out string giftCardRecipientEmail, // out string giftCardSenderName, out string giftCardSenderEmail, out string giftCardMessage); // model.GiftCard.RecipientName = giftCardRecipientName; // model.GiftCard.RecipientEmail = giftCardRecipientEmail; // model.GiftCard.SenderName = giftCardSenderName; // model.GiftCard.SenderEmail = giftCardSenderEmail; // model.GiftCard.Message = giftCardMessage; // } // } // //product attributes // model.ProductAttributes = PrepareProductAttributeModels(product, updatecartitem); // //product specifications // //do not prepare this model for the associated products. anyway it's not used // if (!isAssociatedProduct) // { // model.ProductSpecifications = PrepareProductSpecificationModel(product); // } // //product review overview // model.ProductReviewOverview = PrepareProductReviewOverviewModel(product); // //tier prices // if (product.HasTierPrices && _permissionService.Authorize(StandardPermissionProvider.DisplayPrices)) // { // model.TierPrices = PrepareProductTierPriceModels(product); // } // //manufacturers // //do not prepare this model for the associated products. anyway it's not used // if (!isAssociatedProduct) // { // model.ProductManufacturers = PrepareProductManufacturerModels(product); // } // //rental products // if (product.IsRental) // { // model.IsRental = true; // //set already entered dates attributes (if we're going to update the existing shopping cart item) // if (updatecartitem != null) // { // model.RentalStartDate = updatecartitem.RentalStartDateUtc; // model.RentalEndDate = updatecartitem.RentalEndDateUtc; // } // } // //associated products // if (product.ProductType == ProductType.GroupedProduct) // { // //ensure no circular references // if (!isAssociatedProduct) // { // var associatedProducts = _productService.GetAssociatedProducts(product.Id, _storeContext.CurrentStore.Id); // foreach (var associatedProduct in associatedProducts) // model.AssociatedProducts.Add(PrepareProductDetailsModel(associatedProduct, null, true)); // } // } // return model; //} /// <inheritdoc /> /// <summary> /// See custom code region, rest of function remains unaltered /// </summary> /// <param name="product">Product</param> /// <param name="updatecartitem">Updated shopping cart item</param> /// <returns>List of product attribute model</returns> protected override IList <ProductDetailsModel.ProductAttributeModel> PrepareProductAttributeModels(Product product, ShoppingCartItem updatecartitem) { if (product == null) { throw new ArgumentNullException(nameof(product)); } var model = new List <ProductDetailsModel.ProductAttributeModel>(); var productAttributeMapping = _productAttributeService.GetProductAttributeMappingsByProductId(product.Id); foreach (var attribute in productAttributeMapping) { var attributeModel = new ProductDetailsModel.ProductAttributeModel { Id = attribute.Id, ProductId = product.Id, ProductAttributeId = attribute.ProductAttributeId, Name = _localizationService.GetLocalized(attribute.ProductAttribute, x => x.Name), Description = _localizationService.GetLocalized(attribute.ProductAttribute, x => x.Description), TextPrompt = _localizationService.GetLocalized(attribute, x => x.TextPrompt), IsRequired = attribute.IsRequired, AttributeControlType = attribute.AttributeControlType, DefaultValue = updatecartitem != null ? null : _localizationService.GetLocalized(attribute, x => x.DefaultValue), HasCondition = !string.IsNullOrEmpty(attribute.ConditionAttributeXml) }; if (!string.IsNullOrEmpty(attribute.ValidationFileAllowedExtensions)) { attributeModel.AllowedFileExtensions = attribute.ValidationFileAllowedExtensions .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList(); } if (attribute.ShouldHaveValues()) { //values var attributeValues = _productAttributeService.GetProductAttributeValues(attribute.Id); #region CUSTOM CODE // Only custom code in function lives here! FilterAttributes(product, ref attributeValues); #endregion foreach (var attributeValue in attributeValues) { var valueModel = new ProductDetailsModel.ProductAttributeValueModel { Id = attributeValue.Id, Name = _localizationService.GetLocalized(attributeValue, x => x.Name), ColorSquaresRgb = attributeValue.ColorSquaresRgb, //used with "Color squares" attribute type IsPreSelected = attributeValue.IsPreSelected, CustomerEntersQty = attributeValue.CustomerEntersQty, Quantity = attributeValue.Quantity }; attributeModel.Values.Add(valueModel); //display price if allowed if (_permissionService.Authorize(StandardPermissionProvider.DisplayPrices)) { var attributeValuePriceAdjustment = _priceCalculationService.GetProductAttributeValuePriceAdjustment(attributeValue, updatecartitem?.Customer ?? _workContext.CurrentCustomer); var priceAdjustmentBase = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, out decimal _); var priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); if (attributeValue.PriceAdjustmentUsePercentage) { var priceAdjustmentStr = attributeValue.PriceAdjustment.ToString("G29"); if (attributeValue.PriceAdjustment > decimal.Zero) { valueModel.PriceAdjustment = "+"; } valueModel.PriceAdjustment += priceAdjustmentStr + "%"; } else { if (priceAdjustmentBase > decimal.Zero) { valueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment, false, false); } else if (priceAdjustmentBase < decimal.Zero) { valueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment, false, false); } } valueModel.PriceAdjustmentValue = priceAdjustment; } //"image square" picture (with with "image squares" attribute type only) if (attributeValue.ImageSquaresPictureId > 0) { var productAttributeImageSquarePictureCacheKey = string.Format(NopModelCacheDefaults.ProductAttributeImageSquarePictureModelKey, attributeValue.ImageSquaresPictureId, _webHelper.IsCurrentConnectionSecured(), _storeContext.CurrentStore.Id); valueModel.ImageSquaresPictureModel = _cacheManager.Get(productAttributeImageSquarePictureCacheKey, () => { var imageSquaresPicture = _pictureService.GetPictureById(attributeValue.ImageSquaresPictureId); if (imageSquaresPicture != null) { return(new PictureModel { FullSizeImageUrl = _pictureService.GetPictureUrl(imageSquaresPicture), ImageUrl = _pictureService.GetPictureUrl(imageSquaresPicture, _mediaSettings.ImageSquarePictureSize) }); } return(new PictureModel()); }); } //picture of a product attribute value valueModel.PictureId = attributeValue.PictureId; } } //set already selected attributes (if we're going to update the existing shopping cart item) if (updatecartitem != null) { switch (attribute.AttributeControlType) { case AttributeControlType.DropdownList: case AttributeControlType.RadioList: case AttributeControlType.Checkboxes: case AttributeControlType.ColorSquares: case AttributeControlType.ImageSquares: { if (!string.IsNullOrEmpty(updatecartitem.AttributesXml)) { //clear default selection foreach (var item in attributeModel.Values) { item.IsPreSelected = false; } //select new values var selectedValues = _productAttributeParser.ParseProductAttributeValues(updatecartitem.AttributesXml); foreach (var attributeValue in selectedValues) { foreach (var item in attributeModel.Values) { if (attributeValue.Id == item.Id) { item.IsPreSelected = true; //set customer entered quantity if (attributeValue.CustomerEntersQty) { item.Quantity = attributeValue.Quantity; } } } } } } break; case AttributeControlType.ReadonlyCheckboxes: { //values are already pre-set //set customer entered quantity if (!string.IsNullOrEmpty(updatecartitem.AttributesXml)) { foreach (var attributeValue in _productAttributeParser.ParseProductAttributeValues(updatecartitem.AttributesXml) .Where(value => value.CustomerEntersQty)) { var item = attributeModel.Values.FirstOrDefault(value => value.Id == attributeValue.Id); if (item != null) { item.Quantity = attributeValue.Quantity; } } } } break; case AttributeControlType.TextBox: case AttributeControlType.MultilineTextbox: { if (!string.IsNullOrEmpty(updatecartitem.AttributesXml)) { var enteredText = _productAttributeParser.ParseValues(updatecartitem.AttributesXml, attribute.Id); if (enteredText.Any()) { attributeModel.DefaultValue = enteredText[0]; } } } break; case AttributeControlType.Datepicker: { //keep in mind my that the code below works only in the current culture var selectedDateStr = _productAttributeParser.ParseValues(updatecartitem.AttributesXml, attribute.Id); if (selectedDateStr.Any()) { if (DateTime.TryParseExact(selectedDateStr[0], "D", CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime selectedDate)) { //successfully parsed attributeModel.SelectedDay = selectedDate.Day; attributeModel.SelectedMonth = selectedDate.Month; attributeModel.SelectedYear = selectedDate.Year; } } } break; case AttributeControlType.FileUpload: { if (!string.IsNullOrEmpty(updatecartitem.AttributesXml)) { var downloadGuidStr = _productAttributeParser.ParseValues(updatecartitem.AttributesXml, attribute.Id).FirstOrDefault(); Guid.TryParse(downloadGuidStr, out Guid downloadGuid); var download = _downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { attributeModel.DefaultValue = download.DownloadGuid.ToString(); } } } break; default: break; } } model.Add(attributeModel); } return(model); }