Esempio n. 1
0
        public virtual async Task <IActionResult> DownloadFile(Guid downloadGuid)
        {
            var download = await _downloadService.GetDownloadByGuidAsync(downloadGuid);

            if (download == null)
            {
                return(Content("No download record found with the specified id"));
            }

            //A warning (SCS0027 - Open Redirect) from the "Security Code Scan" analyzer may appear at this point.
            //In this case, it is not relevant. Url may not be local.
            if (download.UseDownloadUrl)
            {
                return(new RedirectResult(download.DownloadUrl));
            }

            //use stored data
            if (download.DownloadBinary == null)
            {
                return(Content($"Download data is not available any more. Download GD={download.Id}"));
            }

            var fileName    = !string.IsNullOrWhiteSpace(download.Filename) ? download.Filename : download.Id.ToString();
            var contentType = !string.IsNullOrWhiteSpace(download.ContentType)
                ? download.ContentType
                : MimeTypes.ApplicationOctetStream;

            return(new FileContentResult(download.DownloadBinary, contentType)
            {
                FileDownloadName = fileName + download.Extension
            });
        }
        public virtual async Task <IActionResult> ReturnRequestSubmit(int orderId, SubmitReturnRequestModel model, IFormCollection form)
        {
            var order = await _orderService.GetOrderByIdAsync(orderId);

            if (order == null || order.Deleted || (await _workContext.GetCurrentCustomerAsync()).Id != order.CustomerId)
            {
                return(Challenge());
            }

            if (!await _orderProcessingService.IsReturnRequestAllowedAsync(order))
            {
                return(RedirectToRoute("Homepage"));
            }

            var count = 0;

            var downloadId = 0;

            if (_orderSettings.ReturnRequestsAllowFiles)
            {
                var download = await _downloadService.GetDownloadByGuidAsync(model.UploadedFileGuid);

                if (download != null)
                {
                    downloadId = download.Id;
                }
            }

            //returnable products
            var orderItems = await _orderService.GetOrderItemsAsync(order.Id, isNotReturnable : false);

            foreach (var orderItem in orderItems)
            {
                var quantity = 0; //parse quantity
                foreach (var formKey in form.Keys)
                {
                    if (formKey.Equals($"quantity{orderItem.Id}", StringComparison.InvariantCultureIgnoreCase))
                    {
                        int.TryParse(form[formKey], out quantity);
                        break;
                    }
                }
                if (quantity > 0)
                {
                    var rrr = await _returnRequestService.GetReturnRequestReasonByIdAsync(model.ReturnRequestReasonId);

                    var rra = await _returnRequestService.GetReturnRequestActionByIdAsync(model.ReturnRequestActionId);

                    var rr = new ReturnRequest
                    {
                        CustomNumber        = "",
                        StoreId             = (await _storeContext.GetCurrentStoreAsync()).Id,
                        OrderItemId         = orderItem.Id,
                        Quantity            = quantity,
                        CustomerId          = (await _workContext.GetCurrentCustomerAsync()).Id,
                        ReasonForReturn     = rrr != null ? await _localizationService.GetLocalizedAsync(rrr, x => x.Name) : "not available",
                        RequestedAction     = rra != null ? await _localizationService.GetLocalizedAsync(rra, x => x.Name) : "not available",
                        CustomerComments    = model.Comments,
                        UploadedFileId      = downloadId,
                        StaffNotes          = string.Empty,
                        ReturnRequestStatus = ReturnRequestStatus.Pending,
                        CreatedOnUtc        = DateTime.UtcNow,
                        UpdatedOnUtc        = DateTime.UtcNow
                    };

                    await _returnRequestService.InsertReturnRequestAsync(rr);

                    //set return request custom number
                    rr.CustomNumber = _customNumberFormatter.GenerateReturnRequestCustomNumber(rr);
                    await _customerService.UpdateCustomerAsync(await _workContext.GetCurrentCustomerAsync());

                    await _returnRequestService.UpdateReturnRequestAsync(rr);

                    //notify store owner
                    await _workflowMessageService.SendNewReturnRequestStoreOwnerNotificationAsync(rr, orderItem, order, _localizationSettings.DefaultAdminLanguageId);

                    //notify customer
                    await _workflowMessageService.SendNewReturnRequestCustomerNotificationAsync(rr, orderItem, order);

                    count++;
                }
            }

            model = await _returnRequestModelFactory.PrepareSubmitReturnRequestModelAsync(model, order);

            if (count > 0)
            {
                model.Result = await _localizationService.GetResourceAsync("ReturnRequests.Submitted");
            }
            else
            {
                model.Result = await _localizationService.GetResourceAsync("ReturnRequests.NoItemsSubmitted");
            }

            return(View(model));
        }
        public async Task <string> ConvertToXmlAsync(List <ProductItemAttributeDto> attributeDtos, int productId)
        {
            var attributesXml = "";

            if (attributeDtos == null)
            {
                return(attributesXml);
            }

            var productAttributes = await _productAttributeService.GetProductAttributeMappingsByProductIdAsync(productId);

            foreach (var attribute in productAttributes)
            {
                switch (attribute.AttributeControlType)
                {
                case AttributeControlType.DropdownList:
                case AttributeControlType.RadioList:
                case AttributeControlType.ColorSquares:
                case AttributeControlType.ImageSquares:
                {
                    // there should be only one selected value for this attribute
                    var selectedAttribute = attributeDtos.Where(x => x.Id == attribute.Id).FirstOrDefault();
                    if (selectedAttribute != null)
                    {
                        int selectedAttributeValue;
                        var isInt = int.TryParse(selectedAttribute.Value, out selectedAttributeValue);
                        if (isInt && selectedAttributeValue > 0)
                        {
                            attributesXml = _productAttributeParser.AddProductAttribute(attributesXml,
                                                                                        attribute, selectedAttributeValue.ToString());
                        }
                    }
                }
                break;

                case AttributeControlType.Checkboxes:
                {
                    // there could be more than one selected value for this attribute
                    var selectedAttributes = attributeDtos.Where(x => x.Id == attribute.Id);
                    foreach (var selectedAttribute in selectedAttributes)
                    {
                        int selectedAttributeValue;
                        var isInt = int.TryParse(selectedAttribute.Value, out selectedAttributeValue);
                        if (isInt && selectedAttributeValue > 0)
                        {
                            // currently there is no support for attribute quantity
                            var quantity = 1;

                            attributesXml = _productAttributeParser.AddProductAttribute(attributesXml,
                                                                                        attribute, selectedAttributeValue.ToString(), quantity);
                        }
                    }
                }
                break;

                case AttributeControlType.ReadonlyCheckboxes:
                {
                    //load read-only(already server - side selected) values
                    var attributeValues = await _productAttributeService.GetProductAttributeValuesAsync(attribute.Id);

                    foreach (var selectedAttributeId in attributeValues
                             .Where(v => v.IsPreSelected)
                             .Select(v => v.Id)
                             .ToList())
                    {
                        attributesXml = _productAttributeParser.AddProductAttribute(attributesXml,
                                                                                    attribute, selectedAttributeId.ToString());
                    }
                }
                break;

                case AttributeControlType.TextBox:
                case AttributeControlType.MultilineTextbox:
                {
                    var selectedAttribute = attributeDtos.Where(x => x.Id == attribute.Id).FirstOrDefault();

                    if (selectedAttribute != null)
                    {
                        attributesXml = _productAttributeParser.AddProductAttribute(attributesXml,
                                                                                    attribute, selectedAttribute.Value);
                    }
                }
                break;

                case AttributeControlType.Datepicker:
                {
                    var selectedAttribute = attributeDtos.Where(x => x.Id == attribute.Id).FirstOrDefault();

                    if (selectedAttribute != null)
                    {
                        DateTime selectedDate;

                        // Since nopCommerce uses this format to keep the date in the database to keep it consisten we will expect the same format to be passed
                        var validDate = DateTime.TryParseExact(selectedAttribute.Value, "D", CultureInfo.CurrentCulture,
                                                               DateTimeStyles.None, out selectedDate);

                        if (validDate)
                        {
                            attributesXml = _productAttributeParser.AddProductAttribute(attributesXml,
                                                                                        attribute, selectedDate.ToString("D"));
                        }
                    }
                }
                break;

                case AttributeControlType.FileUpload:
                {
                    var selectedAttribute = attributeDtos.Where(x => x.Id == attribute.Id).FirstOrDefault();

                    if (selectedAttribute != null)
                    {
                        Guid downloadGuid;
                        Guid.TryParse(selectedAttribute.Value, out downloadGuid);
                        var download = await _downloadService.GetDownloadByGuidAsync(downloadGuid);

                        if (download != null)
                        {
                            attributesXml = _productAttributeParser.AddProductAttribute(attributesXml,
                                                                                        attribute, download.DownloadGuid.ToString());
                        }
                    }
                }
                break;
                }
            }

            // No Gift Card attributes support yet

            return(attributesXml);
        }
        /// <summary>
        /// Formats attributes
        /// </summary>
        /// <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="allowHyperlinks">A value indicating whether to HTML hyperlink tags could be rendered (if required)</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the attributes
        /// </returns>
        public virtual async Task <string> FormatAttributesAsync(string attributesXml,
                                                                 Customer customer,
                                                                 string separator     = "<br />",
                                                                 bool htmlEncode      = true,
                                                                 bool renderPrices    = true,
                                                                 bool allowHyperlinks = true)
        {
            var result = new StringBuilder();

            var attributes = await _checkoutAttributeParser.ParseCheckoutAttributesAsync(attributesXml);

            for (var i = 0; i < attributes.Count; i++)
            {
                var attribute = attributes[i];
                var valuesStr = _checkoutAttributeParser.ParseValues(attributesXml, attribute.Id);
                for (var j = 0; j < valuesStr.Count; j++)
                {
                    var valueStr           = valuesStr[j];
                    var formattedAttribute = string.Empty;
                    if (!attribute.ShouldHaveValues())
                    {
                        //no values
                        if (attribute.AttributeControlType == AttributeControlType.MultilineTextbox)
                        {
                            //multiline textbox
                            var attributeName = await _localizationService.GetLocalizedAsync(attribute, a => a.Name, (await _workContext.GetWorkingLanguageAsync()).Id);

                            //encode (if required)
                            if (htmlEncode)
                            {
                                attributeName = WebUtility.HtmlEncode(attributeName);
                            }
                            formattedAttribute = $"{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.TryParse(valueStr, out var downloadGuid);
                            var download = await _downloadService.GetDownloadByGuidAsync(downloadGuid);

                            if (download != null)
                            {
                                string attributeText;
                                var    fileName = $"{download.Filename ?? download.DownloadGuid.ToString()}{download.Extension}";
                                //encode (if required)
                                if (htmlEncode)
                                {
                                    fileName = WebUtility.HtmlEncode(fileName);
                                }
                                if (allowHyperlinks)
                                {
                                    //hyperlinks are allowed
                                    var downloadLink = $"{_webHelper.GetStoreLocation(false)}download/getfileupload/?downloadId={download.DownloadGuid}";
                                    attributeText = $"<a href=\"{downloadLink}\" class=\"fileuploadattribute\">{fileName}</a>";
                                }
                                else
                                {
                                    //hyperlinks aren't allowed
                                    attributeText = fileName;
                                }

                                var attributeName = await _localizationService.GetLocalizedAsync(attribute, a => a.Name, (await _workContext.GetWorkingLanguageAsync()).Id);

                                //encode (if required)
                                if (htmlEncode)
                                {
                                    attributeName = WebUtility.HtmlEncode(attributeName);
                                }
                                formattedAttribute = $"{attributeName}: {attributeText}";
                            }
                        }
                        else
                        {
                            //other attributes (textbox, datepicker)
                            formattedAttribute = $"{await _localizationService.GetLocalizedAsync(attribute, a => a.Name, (await _workContext.GetWorkingLanguageAsync()).Id)}: {valueStr}";
                            //encode (if required)
                            if (htmlEncode)
                            {
                                formattedAttribute = WebUtility.HtmlEncode(formattedAttribute);
                            }
                        }
                    }
                    else
                    {
                        if (int.TryParse(valueStr, out var attributeValueId))
                        {
                            var attributeValue = await _checkoutAttributeService.GetCheckoutAttributeValueByIdAsync(attributeValueId);

                            if (attributeValue != null)
                            {
                                formattedAttribute = $"{await _localizationService.GetLocalizedAsync(attribute, a => a.Name, (await _workContext.GetWorkingLanguageAsync()).Id)}: {await _localizationService.GetLocalizedAsync(attributeValue, a => a.Name, (await _workContext.GetWorkingLanguageAsync()).Id)}";
                                if (renderPrices)
                                {
                                    var priceAdjustmentBase = (await _taxService.GetCheckoutAttributePriceAsync(attribute, attributeValue, customer)).price;
                                    var priceAdjustment     = await _currencyService.ConvertFromPrimaryStoreCurrencyAsync(priceAdjustmentBase, await _workContext.GetWorkingCurrencyAsync());

                                    if (priceAdjustmentBase > 0)
                                    {
                                        formattedAttribute += string.Format(
                                            await _localizationService.GetResourceAsync("FormattedAttributes.PriceAdjustment"),
                                            "+", await _priceFormatter.FormatPriceAsync(priceAdjustment), string.Empty);
                                    }
                                }
                            }

                            //encode (if required)
                            if (htmlEncode)
                            {
                                formattedAttribute = WebUtility.HtmlEncode(formattedAttribute);
                            }
                        }
                    }

                    if (string.IsNullOrEmpty(formattedAttribute))
                    {
                        continue;
                    }

                    if (i != 0 || j != 0)
                    {
                        result.Append(separator);
                    }
                    result.Append(formattedAttribute);
                }
            }

            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>
        /// A task that represents the asynchronous operation
        /// The task result contains the attributes
        /// </returns>
        public virtual async Task <string> FormatAttributesAsync(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 await _productAttributeParser.ParseProductAttributeMappingsAsync(attributesXml))
                {
                    var productAttribute = await _productAttributeService.GetProductAttributeByIdAsync(attribute.ProductAttributeId);

                    var attributeName = await _localizationService.GetLocalizedAsync(productAttribute, a => a.Name, (await _workContext.GetWorkingLanguageAsync()).Id);

                    //attributes without values
                    if (!attribute.ShouldHaveValues())
                    {
                        foreach (var value in _productAttributeParser.ParseValues(attributesXml, attribute.Id))
                        {
                            var formattedAttribute = string.Empty;
                            if (attribute.AttributeControlType == AttributeControlType.MultilineTextbox)
                            {
                                //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 = await _downloadService.GetDownloadByGuidAsync(downloadGuid);

                                if (download != null)
                                {
                                    var fileName = $"{download.Filename ?? download.DownloadGuid.ToString()}{download.Extension}";

                                    //encode (if required)
                                    if (htmlEncode)
                                    {
                                        fileName = WebUtility.HtmlEncode(fileName);
                                    }

                                    var attributeText = allowHyperlinks ? $"<a href=\"{_webHelper.GetStoreLocation(false)}download/getfileupload/?downloadId={download.DownloadGuid}\" class=\"fileuploadattribute\">{fileName}</a>"
                                        : fileName;

                                    //encode (if required)
                                    if (htmlEncode)
                                    {
                                        attributeName = WebUtility.HtmlEncode(attributeName);
                                    }

                                    formattedAttribute = $"{attributeName}: {attributeText}";
                                }
                            }
                            else
                            {
                                //other attributes (textbox, datepicker)
                                formattedAttribute = $"{attributeName}: {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 await _productAttributeParser.ParseProductAttributeValuesAsync(attributesXml, attribute.Id))
                        {
                            var formattedAttribute = $"{attributeName}: {await _localizationService.GetLocalizedAsync(attributeValue, a => a.Name, (await _workContext.GetWorkingLanguageAsync()).Id)}";

                            if (renderPrices)
                            {
                                if (attributeValue.PriceAdjustmentUsePercentage)
                                {
                                    if (attributeValue.PriceAdjustment > decimal.Zero)
                                    {
                                        formattedAttribute += string.Format(
                                            await _localizationService.GetResourceAsync("FormattedAttributes.PriceAdjustment"),
                                            "+", attributeValue.PriceAdjustment.ToString("G29"), "%");
                                    }
                                    else if (attributeValue.PriceAdjustment < decimal.Zero)
                                    {
                                        formattedAttribute += string.Format(
                                            await _localizationService.GetResourceAsync("FormattedAttributes.PriceAdjustment"),
                                            string.Empty, attributeValue.PriceAdjustment.ToString("G29"), "%");
                                    }
                                }
                                else
                                {
                                    var attributeValuePriceAdjustment = await _priceCalculationService.GetProductAttributeValuePriceAdjustmentAsync(product, attributeValue, customer);

                                    var(priceAdjustmentBase, _) = await _taxService.GetProductPriceAsync(product, attributeValuePriceAdjustment, customer);

                                    var priceAdjustment = await _currencyService.ConvertFromPrimaryStoreCurrencyAsync(priceAdjustmentBase, await _workContext.GetWorkingCurrencyAsync());

                                    if (priceAdjustmentBase > decimal.Zero)
                                    {
                                        formattedAttribute += string.Format(
                                            await _localizationService.GetResourceAsync("FormattedAttributes.PriceAdjustment"),
                                            "+", await _priceFormatter.FormatPriceAsync(priceAdjustment, false, false), string.Empty);
                                    }
                                    else if (priceAdjustmentBase < decimal.Zero)
                                    {
                                        formattedAttribute += string.Format(
                                            await _localizationService.GetResourceAsync("FormattedAttributes.PriceAdjustment"),
                                            "-", await _priceFormatter.FormatPriceAsync(-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(await _localizationService.GetResourceAsync("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(await _localizationService.GetResourceAsync("GiftCardAttribute.From.Virtual"), giftCardSenderName, giftCardSenderEmail) :
                               string.Format(await _localizationService.GetResourceAsync("GiftCardAttribute.From.Physical"), giftCardSenderName);
            //recipient
            var giftCardFor = product.GiftCardType == GiftCardType.Virtual ?
                              string.Format(await _localizationService.GetResourceAsync("GiftCardAttribute.For.Virtual"), giftCardRecipientName, giftCardRecipientEmail) :
                              string.Format(await _localizationService.GetResourceAsync("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());
        }
        /// <summary>
        /// Gets product attributes in XML format
        /// </summary>
        /// <param name="product">Product</param>
        /// <param name="form">Form</param>
        /// <param name="errors">Errors</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the attributes in XML format
        /// </returns>
        protected virtual async Task <string> GetProductAttributesXmlAsync(Product product, IFormCollection form, List <string> errors)
        {
            var attributesXml     = string.Empty;
            var productAttributes = await _productAttributeService.GetProductAttributeMappingsByProductIdAsync(product.Id);

            foreach (var attribute in productAttributes)
            {
                var controlId = $"{NopCatalogDefaults.ProductAttributePrefix}{attribute.Id}";
                switch (attribute.AttributeControlType)
                {
                case AttributeControlType.DropdownList:
                case AttributeControlType.RadioList:
                case AttributeControlType.ColorSquares:
                case AttributeControlType.ImageSquares:
                {
                    var ctrlAttributes = form[controlId];
                    if (!StringValues.IsNullOrEmpty(ctrlAttributes))
                    {
                        var selectedAttributeId = int.Parse(ctrlAttributes);
                        if (selectedAttributeId > 0)
                        {
                            //get quantity entered by customer
                            var quantity    = 1;
                            var quantityStr = form[$"{NopCatalogDefaults.ProductAttributePrefix}{attribute.Id}_{selectedAttributeId}_qty"];
                            if (!StringValues.IsNullOrEmpty(quantityStr) &&
                                (!int.TryParse(quantityStr, out quantity) || quantity < 1))
                            {
                                errors.Add(await _localizationService.GetResourceAsync("Products.QuantityShouldBePositive"));
                            }

                            attributesXml = AddProductAttribute(attributesXml,
                                                                attribute, selectedAttributeId.ToString(), quantity > 1 ? (int?)quantity : null);
                        }
                    }
                }
                break;

                case AttributeControlType.Checkboxes:
                {
                    var ctrlAttributes = form[controlId];
                    if (!StringValues.IsNullOrEmpty(ctrlAttributes))
                    {
                        foreach (var item in ctrlAttributes.ToString()
                                 .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            var selectedAttributeId = int.Parse(item);
                            if (selectedAttributeId > 0)
                            {
                                //get quantity entered by customer
                                var quantity    = 1;
                                var quantityStr = form[$"{NopCatalogDefaults.ProductAttributePrefix}{attribute.Id}_{item}_qty"];
                                if (!StringValues.IsNullOrEmpty(quantityStr) &&
                                    (!int.TryParse(quantityStr, out quantity) || quantity < 1))
                                {
                                    errors.Add(await _localizationService.GetResourceAsync("Products.QuantityShouldBePositive"));
                                }

                                attributesXml = AddProductAttribute(attributesXml,
                                                                    attribute, selectedAttributeId.ToString(), quantity > 1 ? (int?)quantity : null);
                            }
                        }
                    }
                }
                break;

                case AttributeControlType.ReadonlyCheckboxes:
                {
                    //load read-only (already server-side selected) values
                    var attributeValues = await _productAttributeService.GetProductAttributeValuesAsync(attribute.Id);

                    foreach (var selectedAttributeId in attributeValues
                             .Where(v => v.IsPreSelected)
                             .Select(v => v.Id)
                             .ToList())
                    {
                        //get quantity entered by customer
                        var quantity    = 1;
                        var quantityStr = form[$"{NopCatalogDefaults.ProductAttributePrefix}{attribute.Id}_{selectedAttributeId}_qty"];
                        if (!StringValues.IsNullOrEmpty(quantityStr) &&
                            (!int.TryParse(quantityStr, out quantity) || quantity < 1))
                        {
                            errors.Add(await _localizationService.GetResourceAsync("Products.QuantityShouldBePositive"));
                        }

                        attributesXml = AddProductAttribute(attributesXml,
                                                            attribute, selectedAttributeId.ToString(), quantity > 1 ? (int?)quantity : null);
                    }
                }
                break;

                case AttributeControlType.TextBox:
                case AttributeControlType.MultilineTextbox:
                {
                    var ctrlAttributes = form[controlId];
                    if (!StringValues.IsNullOrEmpty(ctrlAttributes))
                    {
                        var enteredText = ctrlAttributes.ToString().Trim();
                        attributesXml = AddProductAttribute(attributesXml, attribute, enteredText);
                    }
                }
                break;

                case AttributeControlType.Datepicker:
                {
                    var      day          = form[controlId + "_day"];
                    var      month        = form[controlId + "_month"];
                    var      year         = form[controlId + "_year"];
                    DateTime?selectedDate = null;
                    try
                    {
                        selectedDate = new DateTime(int.Parse(year), int.Parse(month), int.Parse(day));
                    }
                    catch
                    {
                        // ignored
                    }

                    if (selectedDate.HasValue)
                    {
                        attributesXml = AddProductAttribute(attributesXml, attribute, selectedDate.Value.ToString("D"));
                    }
                }
                break;

                case AttributeControlType.FileUpload:
                {
                    _ = Guid.TryParse(form[controlId], out var downloadGuid);
                    var download = await _downloadService.GetDownloadByGuidAsync(downloadGuid);

                    if (download != null)
                    {
                        attributesXml = AddProductAttribute(attributesXml,
                                                            attribute, download.DownloadGuid.ToString());
                    }
                }
                break;

                default:
                    break;
                }
            }
            //validate conditional attributes (if specified)
            foreach (var attribute in productAttributes)
            {
                var conditionMet = await IsConditionMetAsync(attribute, attributesXml);

                if (conditionMet.HasValue && !conditionMet.Value)
                {
                    attributesXml = RemoveProductAttribute(attributesXml, attribute);
                }
            }
            return(attributesXml);
        }