/// <summary> /// Finds a product attribute combination by attributes stored in XML /// </summary> /// <param name="product">Product</param> /// <param name="attributesXml">Attributes in XML format</param> /// <param name="ignoreNonCombinableAttributes">A value indicating whether we should ignore non-combinable attributes</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the found product attribute combination /// </returns> public virtual async Task <ProductAttributeCombination> FindProductAttributeCombinationAsync(Product product, string attributesXml, bool ignoreNonCombinableAttributes = true) { if (product == null) { throw new ArgumentNullException(nameof(product)); } //anyway combination cannot contains non combinable attributes if (string.IsNullOrEmpty(attributesXml)) { return(null); } var combinations = await _productAttributeService.GetAllProductAttributeCombinationsAsync(product.Id); return(await combinations.FirstOrDefaultAwaitAsync(async x => await AreProductAttributesEqualAsync(x.AttributesXml, attributesXml, ignoreNonCombinableAttributes))); }
/// <summary> /// Copy attributes mapping /// </summary> /// <param name="product">Product</param> /// <param name="productCopy">New product</param> /// <param name="originalNewPictureIdentifiers">Identifiers of pictures</param> /// <returns>A task that represents the asynchronous operation</returns> protected virtual async Task CopyAttributesMappingAsync(Product product, Product productCopy, Dictionary <int, int> originalNewPictureIdentifiers) { var associatedAttributes = new Dictionary <int, int>(); var associatedAttributeValues = new Dictionary <int, int>(); //attribute mapping with condition attributes var oldCopyWithConditionAttributes = new List <ProductAttributeMapping>(); //all product attribute mapping copies var productAttributeMappingCopies = new Dictionary <int, ProductAttributeMapping>(); var languages = await _languageService.GetAllLanguagesAsync(true); foreach (var productAttributeMapping in await _productAttributeService.GetProductAttributeMappingsByProductIdAsync(product.Id)) { var productAttributeMappingCopy = new ProductAttributeMapping { ProductId = productCopy.Id, ProductAttributeId = productAttributeMapping.ProductAttributeId, TextPrompt = productAttributeMapping.TextPrompt, IsRequired = productAttributeMapping.IsRequired, AttributeControlTypeId = productAttributeMapping.AttributeControlTypeId, DisplayOrder = productAttributeMapping.DisplayOrder, ValidationMinLength = productAttributeMapping.ValidationMinLength, ValidationMaxLength = productAttributeMapping.ValidationMaxLength, ValidationFileAllowedExtensions = productAttributeMapping.ValidationFileAllowedExtensions, ValidationFileMaximumSize = productAttributeMapping.ValidationFileMaximumSize, DefaultValue = productAttributeMapping.DefaultValue }; await _productAttributeService.InsertProductAttributeMappingAsync(productAttributeMappingCopy); //localization foreach (var lang in languages) { var textPrompt = await _localizationService.GetLocalizedAsync(productAttributeMapping, x => x.TextPrompt, lang.Id, false, false); if (!string.IsNullOrEmpty(textPrompt)) { await _localizedEntityService.SaveLocalizedValueAsync(productAttributeMappingCopy, x => x.TextPrompt, textPrompt, lang.Id); } } productAttributeMappingCopies.Add(productAttributeMappingCopy.Id, productAttributeMappingCopy); if (!string.IsNullOrEmpty(productAttributeMapping.ConditionAttributeXml)) { oldCopyWithConditionAttributes.Add(productAttributeMapping); } //save associated value (used for combinations copying) associatedAttributes.Add(productAttributeMapping.Id, productAttributeMappingCopy.Id); // product attribute values var productAttributeValues = await _productAttributeService.GetProductAttributeValuesAsync(productAttributeMapping.Id); foreach (var productAttributeValue in productAttributeValues) { var attributeValuePictureId = 0; if (originalNewPictureIdentifiers.ContainsKey(productAttributeValue.PictureId)) { attributeValuePictureId = originalNewPictureIdentifiers[productAttributeValue.PictureId]; } var attributeValueCopy = new ProductAttributeValue { ProductAttributeMappingId = productAttributeMappingCopy.Id, AttributeValueTypeId = productAttributeValue.AttributeValueTypeId, AssociatedProductId = productAttributeValue.AssociatedProductId, Name = productAttributeValue.Name, ColorSquaresRgb = productAttributeValue.ColorSquaresRgb, PriceAdjustment = productAttributeValue.PriceAdjustment, PriceAdjustmentUsePercentage = productAttributeValue.PriceAdjustmentUsePercentage, WeightAdjustment = productAttributeValue.WeightAdjustment, Cost = productAttributeValue.Cost, CustomerEntersQty = productAttributeValue.CustomerEntersQty, Quantity = productAttributeValue.Quantity, IsPreSelected = productAttributeValue.IsPreSelected, DisplayOrder = productAttributeValue.DisplayOrder, PictureId = attributeValuePictureId, }; //picture associated to "iamge square" attribute type (if exists) if (productAttributeValue.ImageSquaresPictureId > 0) { var origImageSquaresPicture = await _pictureService.GetPictureByIdAsync(productAttributeValue.ImageSquaresPictureId); if (origImageSquaresPicture != null) { //copy the picture var imageSquaresPictureCopy = await _pictureService.InsertPictureAsync( await _pictureService.LoadPictureBinaryAsync(origImageSquaresPicture), origImageSquaresPicture.MimeType, origImageSquaresPicture.SeoFilename, origImageSquaresPicture.AltAttribute, origImageSquaresPicture.TitleAttribute); attributeValueCopy.ImageSquaresPictureId = imageSquaresPictureCopy.Id; } } await _productAttributeService.InsertProductAttributeValueAsync(attributeValueCopy); //save associated value (used for combinations copying) associatedAttributeValues.Add(productAttributeValue.Id, attributeValueCopy.Id); //localization foreach (var lang in languages) { var name = await _localizationService.GetLocalizedAsync(productAttributeValue, x => x.Name, lang.Id, false, false); if (!string.IsNullOrEmpty(name)) { await _localizedEntityService.SaveLocalizedValueAsync(attributeValueCopy, x => x.Name, name, lang.Id); } } } } //copy attribute conditions foreach (var productAttributeMapping in oldCopyWithConditionAttributes) { var oldConditionAttributeMapping = (await _productAttributeParser .ParseProductAttributeMappingsAsync(productAttributeMapping.ConditionAttributeXml)).FirstOrDefault(); if (oldConditionAttributeMapping == null) { continue; } var oldConditionValues = await _productAttributeParser.ParseProductAttributeValuesAsync( productAttributeMapping.ConditionAttributeXml, oldConditionAttributeMapping.Id); if (!oldConditionValues.Any()) { continue; } var newAttributeMappingId = associatedAttributes[oldConditionAttributeMapping.Id]; var newConditionAttributeMapping = productAttributeMappingCopies[newAttributeMappingId]; var newConditionAttributeXml = string.Empty; foreach (var oldConditionValue in oldConditionValues) { newConditionAttributeXml = _productAttributeParser.AddProductAttribute(newConditionAttributeXml, newConditionAttributeMapping, associatedAttributeValues[oldConditionValue.Id].ToString()); } var attributeMappingId = associatedAttributes[productAttributeMapping.Id]; var conditionAttribute = productAttributeMappingCopies[attributeMappingId]; conditionAttribute.ConditionAttributeXml = newConditionAttributeXml; await _productAttributeService.UpdateProductAttributeMappingAsync(conditionAttribute); } //attribute combinations foreach (var combination in await _productAttributeService.GetAllProductAttributeCombinationsAsync(product.Id)) { //generate new AttributesXml according to new value IDs var newAttributesXml = string.Empty; var parsedProductAttributes = await _productAttributeParser.ParseProductAttributeMappingsAsync(combination.AttributesXml); foreach (var oldAttribute in parsedProductAttributes) { if (!associatedAttributes.ContainsKey(oldAttribute.Id)) { continue; } var newAttribute = await _productAttributeService.GetProductAttributeMappingByIdAsync(associatedAttributes[oldAttribute.Id]); if (newAttribute == null) { continue; } var oldAttributeValuesStr = _productAttributeParser.ParseValues(combination.AttributesXml, oldAttribute.Id); foreach (var oldAttributeValueStr in oldAttributeValuesStr) { if (newAttribute.ShouldHaveValues()) { //attribute values var oldAttributeValue = int.Parse(oldAttributeValueStr); if (!associatedAttributeValues.ContainsKey(oldAttributeValue)) { continue; } var newAttributeValue = await _productAttributeService.GetProductAttributeValueByIdAsync(associatedAttributeValues[oldAttributeValue]); if (newAttributeValue != null) { newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, newAttribute, newAttributeValue.Id.ToString()); } } else { //just a text newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, newAttribute, oldAttributeValueStr); } } } //picture originalNewPictureIdentifiers.TryGetValue(combination.PictureId, out var combinationPictureId); var combinationCopy = new ProductAttributeCombination { ProductId = productCopy.Id, AttributesXml = newAttributesXml, StockQuantity = combination.StockQuantity, MinStockQuantity = combination.MinStockQuantity, AllowOutOfStockOrders = combination.AllowOutOfStockOrders, Sku = combination.Sku, ManufacturerPartNumber = combination.ManufacturerPartNumber, Gtin = combination.Gtin, OverriddenPrice = combination.OverriddenPrice, NotifyAdminForQuantityBelow = combination.NotifyAdminForQuantityBelow, PictureId = combinationPictureId }; await _productAttributeService.InsertProductAttributeCombinationAsync(combinationCopy); //quantity change history await _productService.AddStockQuantityHistoryEntryAsync(productCopy, combination.StockQuantity, combination.StockQuantity, message : string.Format(await _localizationService.GetResourceAsync("Admin.StockQuantityHistory.Messages.CopyProduct"), product.Id), combinationId : combination.Id); } }