/// <summary>
        /// Check whether condition of some attribute is met (if specified). Return "null" if not condition is specified
        /// </summary>
        /// <param name="pam">Article attribute</param>
        /// <param name="selectedAttributesXml">Selected attributes (XML format)</param>
        /// <returns>Result</returns>
        public virtual bool?IsConditionMet(ArticleAttributeMapping pam, string selectedAttributesXml)
        {
            if (pam == null)
            {
                throw new ArgumentNullException("pam");
            }

            var conditionAttributeXml = pam.ConditionAttributeXml;

            if (String.IsNullOrEmpty(conditionAttributeXml))
            {
                //no condition
                return(null);
            }

            //load an attribute this one depends on
            var dependOnAttribute = ParseArticleAttributeMappings(conditionAttributeXml).FirstOrDefault();

            if (dependOnAttribute == null)
            {
                return(true);
            }

            var valuesThatShouldBeSelected = ParseValues(conditionAttributeXml, dependOnAttribute.Id)
                                             //a workaround here:
                                             //ConditionAttributeXml can contain "empty" values (nothing is selected)
                                             //but in other cases (like below) we do not store empty values
                                             //that's why we remove empty values here
                                             .Where(x => !String.IsNullOrEmpty(x))
                                             .ToList();
            var selectedValues = ParseValues(selectedAttributesXml, dependOnAttribute.Id);

            if (valuesThatShouldBeSelected.Count != selectedValues.Count)
            {
                return(false);
            }

            //compare values
            var allFound = true;

            foreach (var t1 in valuesThatShouldBeSelected)
            {
                bool found = false;
                foreach (var t2 in selectedValues)
                {
                    if (t1 == t2)
                    {
                        found = true;
                    }
                }
                if (!found)
                {
                    allFound = false;
                }
            }

            return(allFound);
        }
        /// <summary>
        /// Remove an attribute
        /// </summary>
        /// <param name="attributesXml">Attributes in XML format</param>
        /// <param name="articleAttributeMapping">Article attribute mapping</param>
        /// <returns>Updated result (XML format)</returns>
        public virtual string RemoveArticleAttribute(string attributesXml, ArticleAttributeMapping articleAttributeMapping)
        {
            string result = string.Empty;

            try
            {
                var xmlDoc = new XmlDocument();
                if (String.IsNullOrEmpty(attributesXml))
                {
                    var element1 = xmlDoc.CreateElement("Attributes");
                    xmlDoc.AppendChild(element1);
                }
                else
                {
                    xmlDoc.LoadXml(attributesXml);
                }
                var rootElement = (XmlElement)xmlDoc.SelectSingleNode(@"//Attributes");

                XmlElement attributeElement = null;
                //find existing
                var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ArticleAttribute");
                foreach (XmlNode node1 in nodeList1)
                {
                    if (node1.Attributes != null && node1.Attributes["ID"] != null)
                    {
                        string str1 = node1.Attributes["ID"].InnerText.Trim();
                        int    id;
                        if (int.TryParse(str1, out id))
                        {
                            if (id == articleAttributeMapping.Id)
                            {
                                attributeElement = (XmlElement)node1;
                                break;
                            }
                        }
                    }
                }

                //found
                if (attributeElement != null)
                {
                    rootElement.RemoveChild(attributeElement);
                }

                result = xmlDoc.OuterXml;
            }
            catch (Exception exc)
            {
                Debug.Write(exc.ToString());
            }
            return(result);
        }
Exemple #3
0
        /// <summary>
        /// A value indicating whether this article attribute should can have some validation rules
        /// </summary>
        /// <param name="articleAttributeMapping">Article attribute mapping</param>
        /// <returns>Result</returns>
        public static bool ValidationRulesAllowed(this ArticleAttributeMapping articleAttributeMapping)
        {
            if (articleAttributeMapping == null)
            {
                return(false);
            }

            if (articleAttributeMapping.AttributeControlType == AttributeControlType.TextBox ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.MultilineTextbox ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.FileUpload)
            {
                return(true);
            }

            //other attribute controle types does not have validation
            return(false);
        }
        /// <summary>
        /// Updates the article attribute mapping
        /// </summary>
        /// <param name="articleAttributeMapping">The article attribute mapping</param>
        public virtual void UpdateArticleAttributeMapping(ArticleAttributeMapping articleAttributeMapping)
        {
            if (articleAttributeMapping == null)
            {
                throw new ArgumentNullException("articleAttributeMapping");
            }

            _articleAttributeMappingRepository.Update(articleAttributeMapping);

            //cache
            _cacheManager.RemoveByPattern(ARTICLEATTRIBUTES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(ARTICLEATTRIBUTEMAPPINGS_PATTERN_KEY);
            _cacheManager.RemoveByPattern(ARTICLEATTRIBUTEVALUES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(ARTICLEATTRIBUTECOMBINATIONS_PATTERN_KEY);

            //event notification
            _eventPublisher.EntityUpdated(articleAttributeMapping);
        }
Exemple #5
0
        /// <summary>
        /// A value indicating whether this article attribute should have values
        /// </summary>
        /// <param name="articleAttributeMapping">Article attribute mapping</param>
        /// <returns>Result</returns>
        public static bool ShouldHaveValues(this ArticleAttributeMapping articleAttributeMapping)
        {
            if (articleAttributeMapping == null)
            {
                return(false);
            }

            if (articleAttributeMapping.AttributeControlType == AttributeControlType.TextBox ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.MultilineTextbox ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.Datepicker ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.FileUpload)
            {
                return(false);
            }

            //other attribute controle types support values
            return(true);
        }
Exemple #6
0
        /// <summary>
        /// A value indicating whether this article attribute is non-combinable
        /// </summary>
        /// <param name="articleAttributeMapping">Article attribute mapping</param>
        /// <returns>Result</returns>
        public static bool IsNonCombinable(this ArticleAttributeMapping articleAttributeMapping)
        {
            //When you have a article with several attributes it may well be that some are combinable,
            //whose combination may form a new SKU with its own inventory,
            //and some non-combinable are more used to add accesories

            if (articleAttributeMapping == null)
            {
                return(false);
            }

            //we can add a new property to "ArticleAttributeMapping" entity indicating whether it's combinable/non-combinable
            //but we assume that attributes
            //which cannot have values (any value can be entered by a customer)
            //are non-combinable
            var result = !ShouldHaveValues(articleAttributeMapping);

            return(result);
        }
Exemple #7
0
        /// <summary>
        /// A value indicating whether this article attribute can be used as condition for some other attribute
        /// </summary>
        /// <param name="articleAttributeMapping">Article attribute mapping</param>
        /// <returns>Result</returns>
        public static bool CanBeUsedAsCondition(this ArticleAttributeMapping articleAttributeMapping)
        {
            if (articleAttributeMapping == null)
            {
                return(false);
            }

            if (articleAttributeMapping.AttributeControlType == AttributeControlType.ReadonlyCheckboxes ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.TextBox ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.MultilineTextbox ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.Datepicker ||
                articleAttributeMapping.AttributeControlType == AttributeControlType.FileUpload)
            {
                return(false);
            }

            //other attribute controle types support it
            return(true);
        }
Exemple #8
0
        /// <summary>
        /// Create a copy of article with all depended data
        /// </summary>
        /// <param name="article">The article to copy</param>
        /// <param name="newName">The name of article duplicate</param>
        /// <param name="isPublished">A value indicating whether the article duplicate should be published</param>
        /// <param name="copyImages">A value indicating whether the article images should be copied</param>
        /// <param name="copyAssociatedArticles">A value indicating whether the copy associated articles</param>
        /// <returns>Article copy</returns>
        public virtual Article CopyArticle(Article article, string newName,
                                           bool isPublished = true, bool copyImages = true, bool copyAssociatedArticles = true)
        {
            if (article == null)
            {
                throw new ArgumentNullException("article");
            }

            if (String.IsNullOrEmpty(newName))
            {
                throw new ArgumentException("Article name is required");
            }



            var newSku = !String.IsNullOrWhiteSpace(article.Sku)
                ? string.Format(_localizationService.GetResource("Admin.Catalog.Articles.Copy.SKU.New"), article.Sku) :
                         article.Sku;
            // article
            var articleCopy = new Article
            {
                ArticleTypeId          = article.ArticleTypeId,
                ParentGroupedArticleId = article.ParentGroupedArticleId,
                VisibleIndividually    = article.VisibleIndividually,
                Name                 = newName,
                ShortDescription     = article.ShortDescription,
                FullDescription      = article.FullDescription,
                ContributorId        = article.ContributorId,
                ArticleTemplateId    = article.ArticleTemplateId,
                AdminComment         = article.AdminComment,
                ShowOnHomePage       = article.ShowOnHomePage,
                MetaKeywords         = article.MetaKeywords,
                MetaDescription      = article.MetaDescription,
                MetaTitle            = article.MetaTitle,
                AllowCustomerReviews = article.AllowCustomerReviews,
                LimitedToStores      = article.LimitedToStores,
                Sku = newSku,
                PublisherPartNumber = article.PublisherPartNumber,
                Gtin       = article.Gtin,
                IsGiftCard = article.IsGiftCard,

                OverriddenGiftCardAmount         = article.OverriddenGiftCardAmount,
                RequireOtherArticles             = article.RequireOtherArticles,
                RequiredArticleIds               = article.RequiredArticleIds,
                AutomaticallyAddRequiredArticles = article.AutomaticallyAddRequiredArticles,

                HasUserAgreement     = article.HasUserAgreement,
                UserAgreementText    = article.UserAgreementText,
                IsRecurring          = article.IsRecurring,
                RecurringCycleLength = article.RecurringCycleLength,
                RecurringCyclePeriod = article.RecurringCyclePeriod,
                RecurringTotalCycles = article.RecurringTotalCycles,
                IsRental             = article.IsRental,
                RentalPriceLength    = article.RentalPriceLength,
                RentalPricePeriod    = article.RentalPricePeriod,

                IsTaxExempt   = article.IsTaxExempt,
                TaxCategoryId = article.TaxCategoryId,

                AllowAddingOnlyExistingAttributeCombinations = article.AllowAddingOnlyExistingAttributeCombinations,
                NotReturnable               = article.NotReturnable,
                DisableBuyButton            = article.DisableBuyButton,
                DisableWishlistButton       = article.DisableWishlistButton,
                AvailableForPreSubscription = article.AvailableForPreSubscription,
                PreSubscriptionAvailabilityStartDateTimeUtc = article.PreSubscriptionAvailabilityStartDateTimeUtc,
                CallForPrice = article.CallForPrice,
                Price        = article.Price,
                OldPrice     = article.OldPrice,
                ArticleCost  = article.ArticleCost,

                MarkAsNew = article.MarkAsNew,
                MarkAsNewStartDateTimeUtc = article.MarkAsNewStartDateTimeUtc,
                MarkAsNewEndDateTimeUtc   = article.MarkAsNewEndDateTimeUtc,

                AvailableStartDateTimeUtc = article.AvailableStartDateTimeUtc,
                AvailableEndDateTimeUtc   = article.AvailableEndDateTimeUtc,
                DisplaySubscription       = article.DisplaySubscription,
                Published    = isPublished,
                Deleted      = article.Deleted,
                CreatedOnUtc = DateTime.UtcNow,
                UpdatedOnUtc = DateTime.UtcNow
            };

            //validate search engine name
            _articleService.InsertArticle(articleCopy);

            //search engine name
            _urlRecordService.SaveSlug(articleCopy, articleCopy.ValidateSeName("", articleCopy.Name, true), 0);

            var languages = _languageService.GetAllLanguages(true);

            //localization
            foreach (var lang in languages)
            {
                var name = article.GetLocalized(x => x.Name, lang.Id, false, false);
                if (!String.IsNullOrEmpty(name))
                {
                    _localizedEntityService.SaveLocalizedValue(articleCopy, x => x.Name, name, lang.Id);
                }

                var shortDescription = article.GetLocalized(x => x.ShortDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(shortDescription))
                {
                    _localizedEntityService.SaveLocalizedValue(articleCopy, x => x.ShortDescription, shortDescription, lang.Id);
                }

                var fullDescription = article.GetLocalized(x => x.FullDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(fullDescription))
                {
                    _localizedEntityService.SaveLocalizedValue(articleCopy, x => x.FullDescription, fullDescription, lang.Id);
                }

                var metaKeywords = article.GetLocalized(x => x.MetaKeywords, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaKeywords))
                {
                    _localizedEntityService.SaveLocalizedValue(articleCopy, x => x.MetaKeywords, metaKeywords, lang.Id);
                }

                var metaDescription = article.GetLocalized(x => x.MetaDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaDescription))
                {
                    _localizedEntityService.SaveLocalizedValue(articleCopy, x => x.MetaDescription, metaDescription, lang.Id);
                }

                var metaTitle = article.GetLocalized(x => x.MetaTitle, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaTitle))
                {
                    _localizedEntityService.SaveLocalizedValue(articleCopy, x => x.MetaTitle, metaTitle, lang.Id);
                }

                //search engine name
                _urlRecordService.SaveSlug(articleCopy, articleCopy.ValidateSeName("", name, false), lang.Id);
            }

            //article tags
            foreach (var articleTag in article.ArticleTags)
            {
                articleCopy.ArticleTags.Add(articleTag);
            }
            _articleService.UpdateArticle(articleCopy);

            //article pictures
            //variable to store original and new picture identifiers
            var originalNewPictureIdentifiers = new Dictionary <int, int>();

            if (copyImages)
            {
                foreach (var articlePicture in article.ArticlePictures)
                {
                    var picture     = articlePicture.Picture;
                    var pictureCopy = _pictureService.InsertPicture(
                        _pictureService.LoadPictureBinary(picture),
                        picture.MimeType,
                        _pictureService.GetPictureSeName(newName),
                        picture.AltAttribute,
                        picture.TitleAttribute);
                    _articleService.InsertArticlePicture(new ArticlePicture
                    {
                        ArticleId           = articleCopy.Id,
                        PictureId           = pictureCopy.Id,
                        DisplaySubscription = articlePicture.DisplaySubscription
                    });
                    originalNewPictureIdentifiers.Add(picture.Id, pictureCopy.Id);
                }
            }


            _articleService.UpdateArticle(articleCopy);

            // article <-> categories mappings
            foreach (var articleCategory in article.ArticleCategories)
            {
                var articleCategoryCopy = new ArticleCategory
                {
                    ArticleId           = articleCopy.Id,
                    CategoryId          = articleCategory.CategoryId,
                    IsFeaturedArticle   = articleCategory.IsFeaturedArticle,
                    DisplaySubscription = articleCategory.DisplaySubscription
                };

                _categoryService.InsertArticleCategory(articleCategoryCopy);
            }

            // article <-> publishers mappings
            foreach (var articlePublishers in article.ArticlePublishers)
            {
                var articlePublisherCopy = new ArticlePublisher
                {
                    ArticleId           = articleCopy.Id,
                    PublisherId         = articlePublishers.PublisherId,
                    IsFeaturedArticle   = articlePublishers.IsFeaturedArticle,
                    DisplaySubscription = articlePublishers.DisplaySubscription
                };

                _publisherService.InsertArticlePublisher(articlePublisherCopy);
            }

            // article <-> releated articles mappings
            foreach (var relatedArticle in _articleService.GetRelatedArticlesByArticleId1(article.Id, true))
            {
                _articleService.InsertRelatedArticle(
                    new RelatedArticle
                {
                    ArticleId1          = articleCopy.Id,
                    ArticleId2          = relatedArticle.ArticleId2,
                    DisplaySubscription = relatedArticle.DisplaySubscription
                });
            }

            // article <-> cross sells mappings
            foreach (var csArticle in _articleService.GetCrossSellArticlesByArticleId1(article.Id, true))
            {
                _articleService.InsertCrossSellArticle(
                    new CrossSellArticle
                {
                    ArticleId1 = articleCopy.Id,
                    ArticleId2 = csArticle.ArticleId2,
                });
            }

            // article specifications
            foreach (var articleSpecificationAttribute in article.ArticleSpecificationAttributes)
            {
                var psaCopy = new ArticleSpecificationAttribute
                {
                    ArticleId       = articleCopy.Id,
                    AttributeTypeId = articleSpecificationAttribute.AttributeTypeId,
                    SpecificationAttributeOptionId = articleSpecificationAttribute.SpecificationAttributeOptionId,
                    CustomValue         = articleSpecificationAttribute.CustomValue,
                    AllowFiltering      = articleSpecificationAttribute.AllowFiltering,
                    ShowOnArticlePage   = articleSpecificationAttribute.ShowOnArticlePage,
                    DisplaySubscription = articleSpecificationAttribute.DisplaySubscription
                };
                _specificationAttributeService.InsertArticleSpecificationAttribute(psaCopy);
            }

            //store mapping
            var selectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(article);

            foreach (var id in selectedStoreIds)
            {
                _storeMappingService.InsertStoreMapping(articleCopy, id);
            }

            //article <-> attributes mappings
            var associatedAttributes      = new Dictionary <int, int>();
            var associatedAttributeValues = new Dictionary <int, int>();

            //attribute mapping with condition attributes
            var oldCopyWithConditionAttributes = new List <ArticleAttributeMapping>();

            //all article attribute mapping copies
            var articleAttributeMappingCopies = new Dictionary <int, ArticleAttributeMapping>();

            foreach (var articleAttributeMapping in _articleAttributeService.GetArticleAttributeMappingsByArticleId(article.Id))
            {
                var articleAttributeMappingCopy = new ArticleAttributeMapping
                {
                    ArticleId                       = articleCopy.Id,
                    ArticleAttributeId              = articleAttributeMapping.ArticleAttributeId,
                    TextPrompt                      = articleAttributeMapping.TextPrompt,
                    IsRequired                      = articleAttributeMapping.IsRequired,
                    AttributeControlTypeId          = articleAttributeMapping.AttributeControlTypeId,
                    DisplaySubscription             = articleAttributeMapping.DisplaySubscription,
                    ValidationMinLength             = articleAttributeMapping.ValidationMinLength,
                    ValidationMaxLength             = articleAttributeMapping.ValidationMaxLength,
                    ValidationFileAllowedExtensions = articleAttributeMapping.ValidationFileAllowedExtensions,
                    ValidationFileMaximumSize       = articleAttributeMapping.ValidationFileMaximumSize,
                    DefaultValue                    = articleAttributeMapping.DefaultValue
                };
                _articleAttributeService.InsertArticleAttributeMapping(articleAttributeMappingCopy);

                articleAttributeMappingCopies.Add(articleAttributeMappingCopy.Id, articleAttributeMappingCopy);

                if (!string.IsNullOrEmpty(articleAttributeMapping.ConditionAttributeXml))
                {
                    oldCopyWithConditionAttributes.Add(articleAttributeMapping);
                }

                //save associated value (used for combinations copying)
                associatedAttributes.Add(articleAttributeMapping.Id, articleAttributeMappingCopy.Id);

                // article attribute values
                var articleAttributeValues = _articleAttributeService.GetArticleAttributeValues(articleAttributeMapping.Id);
                foreach (var articleAttributeValue in articleAttributeValues)
                {
                    int attributeValuePictureId = 0;
                    if (originalNewPictureIdentifiers.ContainsKey(articleAttributeValue.PictureId))
                    {
                        attributeValuePictureId = originalNewPictureIdentifiers[articleAttributeValue.PictureId];
                    }
                    var attributeValueCopy = new ArticleAttributeValue
                    {
                        ArticleAttributeMappingId = articleAttributeMappingCopy.Id,
                        AttributeValueTypeId      = articleAttributeValue.AttributeValueTypeId,
                        AssociatedArticleId       = articleAttributeValue.AssociatedArticleId,
                        Name                = articleAttributeValue.Name,
                        ColorSquaresRgb     = articleAttributeValue.ColorSquaresRgb,
                        PriceAdjustment     = articleAttributeValue.PriceAdjustment,
                        WeightAdjustment    = articleAttributeValue.WeightAdjustment,
                        Cost                = articleAttributeValue.Cost,
                        CustomerEntersQty   = articleAttributeValue.CustomerEntersQty,
                        Quantity            = articleAttributeValue.Quantity,
                        IsPreSelected       = articleAttributeValue.IsPreSelected,
                        DisplaySubscription = articleAttributeValue.DisplaySubscription,
                        PictureId           = attributeValuePictureId,
                    };
                    //picture associated to "iamge square" attribute type (if exists)
                    if (articleAttributeValue.ImageSquaresPictureId > 0)
                    {
                        var origImageSquaresPicture = _pictureService.GetPictureById(articleAttributeValue.ImageSquaresPictureId);
                        if (origImageSquaresPicture != null)
                        {
                            //copy the picture
                            var imageSquaresPictureCopy = _pictureService.InsertPicture(
                                _pictureService.LoadPictureBinary(origImageSquaresPicture),
                                origImageSquaresPicture.MimeType,
                                origImageSquaresPicture.SeoFilename,
                                origImageSquaresPicture.AltAttribute,
                                origImageSquaresPicture.TitleAttribute);
                            attributeValueCopy.ImageSquaresPictureId = imageSquaresPictureCopy.Id;
                        }
                    }

                    _articleAttributeService.InsertArticleAttributeValue(attributeValueCopy);

                    //save associated value (used for combinations copying)
                    associatedAttributeValues.Add(articleAttributeValue.Id, attributeValueCopy.Id);

                    //localization
                    foreach (var lang in languages)
                    {
                        var name = articleAttributeValue.GetLocalized(x => x.Name, lang.Id, false, false);
                        if (!String.IsNullOrEmpty(name))
                        {
                            _localizedEntityService.SaveLocalizedValue(attributeValueCopy, x => x.Name, name, lang.Id);
                        }
                    }
                }
            }

            //copy attribute conditions
            foreach (var articleAttributeMapping in oldCopyWithConditionAttributes)
            {
                var oldConditionAttributeMapping = _articleAttributeParser.ParseArticleAttributeMappings(articleAttributeMapping.ConditionAttributeXml).FirstOrDefault();

                if (oldConditionAttributeMapping == null)
                {
                    continue;
                }

                var oldConditionValues = _articleAttributeParser.ParseArticleAttributeValues(articleAttributeMapping.ConditionAttributeXml, oldConditionAttributeMapping.Id);

                if (!oldConditionValues.Any())
                {
                    continue;
                }

                var newAttributeMappingId        = associatedAttributes[oldConditionAttributeMapping.Id];
                var newConditionAttributeMapping = articleAttributeMappingCopies[newAttributeMappingId];

                var newConditionAttributeXml = string.Empty;

                foreach (var oldConditionValue in oldConditionValues)
                {
                    newConditionAttributeXml = _articleAttributeParser.AddArticleAttribute(newConditionAttributeXml, newConditionAttributeMapping, associatedAttributeValues[oldConditionValue.Id].ToString());
                }

                var attributeMappingId = associatedAttributes[articleAttributeMapping.Id];
                var conditionAttribute = articleAttributeMappingCopies[attributeMappingId];
                conditionAttribute.ConditionAttributeXml = newConditionAttributeXml;

                _articleAttributeService.UpdateArticleAttributeMapping(conditionAttribute);
            }

            //attribute combinations
            foreach (var combination in _articleAttributeService.GetAllArticleAttributeCombinations(article.Id))
            {
                //generate new AttributesXml according to new value IDs
                string newAttributesXml        = "";
                var    parsedArticleAttributes = _articleAttributeParser.ParseArticleAttributeMappings(combination.AttributesXml);
                foreach (var oldAttribute in parsedArticleAttributes)
                {
                    if (associatedAttributes.ContainsKey(oldAttribute.Id))
                    {
                        var newAttribute = _articleAttributeService.GetArticleAttributeMappingById(associatedAttributes[oldAttribute.Id]);
                        if (newAttribute != null)
                        {
                            var oldAttributeValuesStr = _articleAttributeParser.ParseValues(combination.AttributesXml, oldAttribute.Id);
                            foreach (var oldAttributeValueStr in oldAttributeValuesStr)
                            {
                                if (newAttribute.ShouldHaveValues())
                                {
                                    //attribute values
                                    int oldAttributeValue = int.Parse(oldAttributeValueStr);
                                    if (associatedAttributeValues.ContainsKey(oldAttributeValue))
                                    {
                                        var newAttributeValue = _articleAttributeService.GetArticleAttributeValueById(associatedAttributeValues[oldAttributeValue]);
                                        if (newAttributeValue != null)
                                        {
                                            newAttributesXml = _articleAttributeParser.AddArticleAttribute(newAttributesXml,
                                                                                                           newAttribute, newAttributeValue.Id.ToString());
                                        }
                                    }
                                }
                                else
                                {
                                    //just a text
                                    newAttributesXml = _articleAttributeParser.AddArticleAttribute(newAttributesXml,
                                                                                                   newAttribute, oldAttributeValueStr);
                                }
                            }
                        }
                    }
                }
                var combinationCopy = new ArticleAttributeCombination
                {
                    ArticleId     = articleCopy.Id,
                    AttributesXml = newAttributesXml,
                    StockQuantity = combination.StockQuantity,
                    AllowOutOfStockSubscriptions = combination.AllowOutOfStockSubscriptions,
                    Sku = combination.Sku,
                    PublisherPartNumber = combination.PublisherPartNumber,
                    Gtin                        = combination.Gtin,
                    OverriddenPrice             = combination.OverriddenPrice,
                    NotifyAdminForQuantityBelow = combination.NotifyAdminForQuantityBelow
                };
                _articleAttributeService.InsertArticleAttributeCombination(combinationCopy);
            }



            _articleService.UpdateHasDiscountsApplied(articleCopy);

            //associated articles
            if (copyAssociatedArticles)
            {
                var associatedArticles = _articleService.GetAssociatedArticles(article.Id, showHidden: true);
                foreach (var associatedArticle in associatedArticles)
                {
                    var associatedArticleCopy = CopyArticle(associatedArticle, string.Format("Copy of {0}", associatedArticle.Name),
                                                            isPublished, copyImages, false);
                    associatedArticleCopy.ParentGroupedArticleId = articleCopy.Id;
                    _articleService.UpdateArticle(articleCopy);
                }
            }

            return(articleCopy);
        }
        /// <summary>
        /// Adds an attribute
        /// </summary>
        /// <param name="attributesXml">Attributes in XML format</param>
        /// <param name="articleAttributeMapping">Article attribute mapping</param>
        /// <param name="value">Value</param>
        /// <param name="quantity">Quantity (used with AttributeValueType.AssociatedToArticle to specify the quantity entered by the customer)</param>
        /// <returns>Updated result (XML format)</returns>
        public virtual string AddArticleAttribute(string attributesXml, ArticleAttributeMapping articleAttributeMapping, string value, int?quantity = null)
        {
            string result = string.Empty;

            try
            {
                var xmlDoc = new XmlDocument();
                if (String.IsNullOrEmpty(attributesXml))
                {
                    var element1 = xmlDoc.CreateElement("Attributes");
                    xmlDoc.AppendChild(element1);
                }
                else
                {
                    xmlDoc.LoadXml(attributesXml);
                }
                var rootElement = (XmlElement)xmlDoc.SelectSingleNode(@"//Attributes");

                XmlElement attributeElement = null;
                //find existing
                var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ArticleAttribute");
                foreach (XmlNode node1 in nodeList1)
                {
                    if (node1.Attributes != null && node1.Attributes["ID"] != null)
                    {
                        string str1 = node1.Attributes["ID"].InnerText.Trim();
                        int    id;
                        if (int.TryParse(str1, out id))
                        {
                            if (id == articleAttributeMapping.Id)
                            {
                                attributeElement = (XmlElement)node1;
                                break;
                            }
                        }
                    }
                }

                //create new one if not found
                if (attributeElement == null)
                {
                    attributeElement = xmlDoc.CreateElement("ArticleAttribute");
                    attributeElement.SetAttribute("ID", articleAttributeMapping.Id.ToString());
                    rootElement.AppendChild(attributeElement);
                }
                var attributeValueElement = xmlDoc.CreateElement("ArticleAttributeValue");
                attributeElement.AppendChild(attributeValueElement);

                var attributeValueValueElement = xmlDoc.CreateElement("Value");
                attributeValueValueElement.InnerText = value;
                attributeValueElement.AppendChild(attributeValueValueElement);

                //the quantity entered by the customer
                if (quantity.HasValue)
                {
                    var attributeValueQuantity = xmlDoc.CreateElement("Quantity");
                    attributeValueQuantity.InnerText = quantity.ToString();
                    attributeValueElement.AppendChild(attributeValueQuantity);
                }

                result = xmlDoc.OuterXml;
            }
            catch (Exception exc)
            {
                Debug.Write(exc.ToString());
            }
            return(result);
        }