public async Task <ActionResult <CatalogProduct> > GetNewProductByCatalogAndCategory(string catalogId, string categoryId)
        {
            var retVal = AbstractTypeFactory <CatalogProduct> .TryCreateInstance();

            retVal.CategoryId = categoryId;
            retVal.CatalogId  = catalogId;
            retVal.IsActive   = true;
            retVal.SeoInfos   = Array.Empty <SeoInfo>();

            //CheckCurrentUserHasPermissionForObjects(CatalogPredefinedPermissions.Create, retVal.ToModuleModel(_blobUrlResolver));

            if (catalogId != null)
            {
                var catalog = (await _catalogService.GetByIdsAsync(new[] { catalogId })).FirstOrDefault();
                retVal.Properties = catalog?.Properties.ToList();
            }
            if (categoryId != null)
            {
                var category = (await _categoryService.GetByIdsAsync(new[] { categoryId }, CategoryResponseGroup.WithProperties.ToString())).FirstOrDefault();
                retVal.Properties = category?.Properties.ToList();
            }
            //foreach (var property in retVal.Properties)
            //{
            //    property.Values = new List<PropertyValue>();
            //    property.IsManageable = true;
            //    property.IsReadOnly = property.Type != PropertyType.Product && property.Type != PropertyType.Variation;
            //}
            retVal.Code = _skuGenerator.GenerateSku(retVal);

            return(Ok(retVal));
        }
Example #2
0
        public IHttpActionResult GetNewProductByCatalogAndCategory(string catalogId, string categoryId)
        {
            var retVal = new webModel.Product
            {
                CategoryId = categoryId,
                CatalogId  = catalogId,
                IsActive   = true,
            };

            base.CheckCurrentUserHasPermissionForObjects(CatalogPredefinedPermissions.Create, retVal.ToModuleModel(_blobUrlResolver));


            if (catalogId != null)
            {
                var properites = GetAllCatalogProperies(catalogId, categoryId);
                retVal.Properties = properites.Select(x => x.ToWebModel()).ToList();

                foreach (var property in retVal.Properties)
                {
                    property.Values       = new List <webModel.PropertyValue>();
                    property.IsManageable = true;
                    property.IsReadOnly   = property.Type != coreModel.PropertyType.Product && property.Type != coreModel.PropertyType.Variation;
                }
            }

            retVal.Code = _skuGenerator.GenerateSku(retVal.ToModuleModel(null));

            return(Ok(retVal));
        }
        public IHttpActionResult GetNewProduct(string catalogId, string categoryId)
        {
            var retVal = new webModel.Product
            {
                CategoryId = categoryId,
                CatalogId  = catalogId,
                IsActive   = true,
            };

            if (catalogId != null)
            {
                var properites = GetAllCatalogProperies(catalogId, categoryId);
                retVal.Properties = properites.Select(x => x.ToWebModel()).ToList();

                foreach (var property in retVal.Properties)
                {
                    property.Values       = new List <webModel.PropertyValue>();
                    property.IsManageable = true;
                    property.IsReadOnly   = property.Type != coreModel.PropertyType.Product && property.Type != coreModel.PropertyType.Variation;
                }
            }

            retVal.Code = _skuGenerator.GenerateSku(retVal.ToModuleModel(null));

            return(Ok(retVal));
        }
Example #4
0
        private async Task LoadProductDependencies(IEnumerable <CsvProduct> csvProducts, Catalog catalog, CsvImportInfo importInfo)
        {
            var allCategoriesIds = csvProducts.Select(x => x.CategoryId).Distinct().ToArray();
            var categoriesMap    = (await _categoryService.GetByIdsAsync(allCategoriesIds, CategoryResponseGroup.Full.ToString())).ToDictionary(x => x.Id);

            foreach (var csvProduct in csvProducts)
            {
                csvProduct.Catalog   = catalog;
                csvProduct.CatalogId = catalog.Id;
                if (csvProduct.CategoryId != null)
                {
                    csvProduct.Category = categoriesMap[csvProduct.CategoryId];
                }

                //Try to set parent relations
                //By id or code reference
                var parentProduct = csvProducts.FirstOrDefault(x => !string.IsNullOrEmpty(csvProduct.MainProductId) && (x.Id.EqualsInvariant(csvProduct.MainProductId) || x.Code.EqualsInvariant(csvProduct.MainProductId)));
                csvProduct.MainProduct   = parentProduct;
                csvProduct.MainProductId = parentProduct != null ? parentProduct.Id : null;

                if (string.IsNullOrEmpty(csvProduct.Code))
                {
                    csvProduct.Code = _skuGenerator.GenerateSku(csvProduct);
                }
                //Properties inheritance
                var inheritedProperties = (csvProduct.Category != null ? csvProduct.Category.Properties : csvProduct.Catalog.Properties).OrderBy(x => x.Name).ToList();

                foreach (var property in csvProduct.Properties.ToArray())
                {
                    //Try to find property for product
                    var inheritedProperty = inheritedProperties.FirstOrDefault(x => x.Name.EqualsInvariant(property.Name));
                    if (inheritedProperty != null)
                    {
                        property.ValueType  = inheritedProperty.ValueType;
                        property.Id         = inheritedProperty.Id;
                        property.Dictionary = inheritedProperty.Dictionary;
                        property.Multivalue = inheritedProperty.Multivalue;

                        foreach (var propertyValue in property.Values)
                        {
                            propertyValue.ValueType  = inheritedProperty.ValueType;
                            propertyValue.PropertyId = inheritedProperty.Id;
                        }

                        //Try to split the one value to multiple values for Multivalue properties
                        if (inheritedProperty.Multivalue)
                        {
                            var parsedValues = new List <PropertyValue>();

                            foreach (var propertyValue in property.Values)
                            {
                                parsedValues.AddRange(ParseValuesFromMultivalueString(propertyValue, importInfo.Configuration.Delimiter));
                            }

                            property.Values = parsedValues;
                        }
                    }
                }
            }
        }
        private void LoadProductDependencies(IEnumerable <CsvProduct> csvProducts, Catalog catalog, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback, CsvImportInfo importInfo)
        {
            var modifiedProperties = new List <Property>();
            var allCategoriesIds   = csvProducts.Select(x => x.CategoryId).Distinct().ToArray();
            var categoriesMap      = _categoryService.GetByIds(allCategoriesIds, CategoryResponseGroup.Full).ToDictionary(x => x.Id);

            foreach (var csvProduct in csvProducts)
            {
                csvProduct.Catalog   = catalog;
                csvProduct.CatalogId = catalog.Id;
                if (csvProduct.CategoryId != null)
                {
                    csvProduct.Category = categoriesMap[csvProduct.CategoryId];
                }

                //Try to set parent relations
                //By id or code reference
                var parentProduct = csvProducts.FirstOrDefault(x => !string.IsNullOrEmpty(csvProduct.MainProductId) && (x.Id.EqualsInvariant(csvProduct.MainProductId) || x.Code.EqualsInvariant(csvProduct.MainProductId)));
                csvProduct.MainProduct   = parentProduct;
                csvProduct.MainProductId = parentProduct != null ? parentProduct.Id : null;

                if (string.IsNullOrEmpty(csvProduct.Code))
                {
                    csvProduct.Code = _skuGenerator.GenerateSku(csvProduct);
                }
                //Properties inheritance
                csvProduct.Properties = (csvProduct.Category != null ? csvProduct.Category.Properties : csvProduct.Catalog.Properties).OrderBy(x => x.Name).ToList();

                foreach (var propertyValue in csvProduct.PropertyValues.ToArray())
                {
                    //Try to find property for product
                    propertyValue.Property = csvProduct.Properties.FirstOrDefault(x => x.Name.EqualsInvariant(propertyValue.PropertyName));
                    if (propertyValue.Property != null)
                    {
                        propertyValue.ValueType  = propertyValue.Property.ValueType;
                        propertyValue.PropertyId = propertyValue.Property.Id;
                        //Try to split the one value to multiple values for Multivalue properties
                        if (propertyValue.Property.Multivalue)
                        {
                            var multivalue = propertyValue.Value.ToString();
                            var chars      = new[] { ",", importInfo.Configuration.Delimiter };
                            var values     = multivalue.Split(chars, StringSplitOptions.RemoveEmptyEntries)
                                             .Select(x => x.Trim())
                                             .Where(x => !string.IsNullOrEmpty(x))
                                             .Distinct().ToArray();
                            propertyValue.Value = values.FirstOrDefault();
                            foreach (var value in values.Skip(1))
                            {
                                var newPropValue = propertyValue.Clone() as PropertyValue;
                                newPropValue.Value = value;
                                csvProduct.PropertyValues.Add(newPropValue);
                            }
                        }
                    }
                }
            }
        }
Example #6
0
        protected virtual async Task InnerLoadDependenciesAsync(IEnumerable <CatalogProduct> products, bool processVariations = true)
        {
            var catalogsByIdDict = (await _catalogService.GetCatalogsListAsync()).ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase)
                                   .WithDefaultValue(null);
            var productsCategoryIds = products.Select(x => x.CategoryId)
                                      .Where(x => x != null).Distinct()
                                      .ToArray();
            var productLinksCategoryIds = products.Any(p => !p.Links.IsNullOrEmpty()) ? products.SelectMany(p => p.Links)
                                          .Select(l => l.CategoryId).Distinct().ToArray() : new string[] { };

            var productCategoriesByIdDict      = (await _categoryService.GetByIdsAsync(productsCategoryIds, CategoryResponseGroup.Full.ToString())).ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase).WithDefaultValue(null);
            var productLinksCategoriesByIdDict = (await _categoryService.GetByIdsAsync(productLinksCategoryIds, (CategoryResponseGroup.WithProperties | CategoryResponseGroup.WithParents).ToString())).ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase).WithDefaultValue(null);

            foreach (var product in products)
            {
                if (string.IsNullOrEmpty(product.Code))
                {
                    product.Code = _skuGenerator.GenerateSku(product);
                }
                product.Catalog = catalogsByIdDict.GetValueOrThrow(product.CatalogId, $"catalog with key {product.CatalogId} doesn't exist");
                if (product.CategoryId != null)
                {
                    product.Category = productCategoriesByIdDict.GetValueOrThrow(product.CategoryId, $"category with key {product.CategoryId} doesn't exist");
                }

                if (product.Links != null)
                {
                    foreach (var link in product.Links)
                    {
                        link.Catalog  = catalogsByIdDict.GetValueOrThrow(link.CatalogId, $"link catalog with key {link.CatalogId} doesn't exist");
                        link.Category = productLinksCategoriesByIdDict.GetValueOrThrow(link.CategoryId, $"link category with key {link.CategoryId} doesn't exist");
                    }
                }

                if (product.MainProduct != null)
                {
                    await InnerLoadDependenciesAsync(new[] { product.MainProduct }, false);
                }
                if (processVariations && !product.Variations.IsNullOrEmpty())
                {
                    await InnerLoadDependenciesAsync(product.Variations.ToArray());
                }
                //Resolve relative urls for all product images
                if (!product.Images.IsNullOrEmpty())
                {
                    foreach (var image in product.Images.Where(x => !string.IsNullOrEmpty(x.Url)))
                    {
                        image.RelativeUrl = image.Url;
                        image.Url         = _blobUrlResolver.GetAbsoluteUrl(image.Url);
                    }
                }
            }
        }
Example #7
0
        public IHttpActionResult GetNewProductByCatalogAndCategory(string catalogId, string categoryId)
        {
            var retVal = new webModel.Product
            {
                CategoryId = categoryId,
                CatalogId  = catalogId,
                IsActive   = true,
                SeoInfos   = new SeoInfo[0]
            };

            CheckCurrentUserHasPermissionForObjects(CatalogPredefinedPermissions.Create, retVal.ToModuleModel(_blobUrlResolver));

            if (catalogId != null)
            {
                var catalog = _catalogService.GetById(catalogId);
                retVal.Catalog    = catalog.ToWebModel();
                retVal.Properties = catalog.Properties.Select(x => x.ToWebModel()).ToList();
            }

            if (categoryId != null)
            {
                var category = _categoryService.GetById(categoryId, coreModel.CategoryResponseGroup.WithProperties);
                retVal.Category   = category.ToWebModel();
                retVal.Properties = category.Properties.Select(x => x.ToWebModel()).ToList();
            }


            foreach (var property in retVal.Properties)
            {
                property.Values       = new List <webModel.PropertyValue>();
                property.IsManageable = true;
                property.IsReadOnly   = property.Type != coreModel.PropertyType.Product && property.Type != coreModel.PropertyType.Variation;
            }


            retVal.Code = _skuGenerator.GenerateSku(retVal.ToModuleModel(null));

            return(Ok(retVal));
        }
        public async Task <ActionResult <CatalogProduct> > GetNewProductByCatalogAndCategory(string catalogId, string categoryId)
        {
            var result = AbstractTypeFactory <CatalogProduct> .TryCreateInstance();

            result.CategoryId = categoryId;
            result.CatalogId  = catalogId;
            result.IsActive   = true;
            result.SeoInfos   = Array.Empty <SeoInfo>();

            Entity parent = null;

            if (catalogId != null)
            {
                parent = (await _catalogService.GetByIdsAsync(new[] { catalogId })).FirstOrDefault();
            }
            if (categoryId != null)
            {
                parent = (await _categoryService.GetByIdsAsync(new[] { categoryId }, CategoryResponseGroup.WithProperties.ToString())).FirstOrDefault();
            }
            if (parent != null)
            {
                result.TryInheritFrom(parent);
            }

            if (result.Properties != null)
            {
                foreach (var property in result.Properties)
                {
                    property.Values     = new List <PropertyValue>();
                    property.IsReadOnly = property.Type != PropertyType.Product && property.Type != PropertyType.Variation;
                }
            }
            result.Code = _skuGenerator.GenerateSku(result);

            return(Ok(result));
        }
Example #9
0
        protected virtual void InnerLoadDependencies(IEnumerable <CatalogProduct> products, bool processVariations = true)
        {
            var catalogsMap      = _catalogService.GetAllCatalogs().ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase);
            var allCategoriesIds = products.Select(x => x.CategoryId).Where(x => x != null).Distinct().ToArray();
            var categoriesMap    = _categoryService.GetByIds(allCategoriesIds).ToDictionary(x => x.Id, StringComparer.OrdinalIgnoreCase);

            foreach (var product in products)
            {
                if (string.IsNullOrEmpty(product.Code))
                {
                    product.Code = _skuGenerator.GenerateSku(product);
                }
                product.Catalog = catalogsMap.GetValueOrThrow(product.CatalogId, $"catalog with key {product.CatalogId} doesn't exist");
                if (product.CategoryId != null)
                {
                    product.Category = categoriesMap.GetValueOrThrow(product.CategoryId, $"category with key {product.CategoryId} doesn't exist");
                }

                if (product.Links != null)
                {
                    foreach (var link in product.Links)
                    {
                        link.Catalog  = catalogsMap.GetValueOrThrow(link.CatalogId, $"link catalog with key {link.CatalogId} doesn't exist");
                        link.Category = _categoryService.GetByIds(new[] { link.CategoryId }, (CategoryResponseGroup.WithProperties | CategoryResponseGroup.WithParents).ToString()).FirstOrDefault();
                    }
                }

                if (product.MainProduct != null)
                {
                    InnerLoadDependencies(new[] { product.MainProduct }, false);
                }
                if (processVariations && !product.Variations.IsNullOrEmpty())
                {
                    InnerLoadDependencies(product.Variations.ToArray());
                }
                //Resolve relative urls for all product assets
                if (product.AllAssets != null)
                {
                    foreach (var asset in product.AllAssets)
                    {
                        asset.Url = _blobUrlResolver.GetAbsoluteUrl(asset.RelativeUrl);
                    }
                }
            }
        }
        protected virtual void SetProductDependencies(CatalogProduct product, IDictionary <string, Catalog> catalogsByIdDict, IDictionary <string, Category> categoriesByIdDict)
        {
            //TOD: Refactor after cover by the unit tests
            if (string.IsNullOrEmpty(product.Code))
            {
                product.Code = _skuGenerator.GenerateSku(product);
            }
            product.Catalog = catalogsByIdDict.GetValueOrThrow(product.CatalogId, $"catalog with key {product.CatalogId} doesn't exist");
            if (product.CategoryId != null)
            {
                product.Category = categoriesByIdDict.GetValueOrThrow(product.CategoryId, $"category with key {product.CategoryId} doesn't exist");
            }

            foreach (var link in product.Links ?? Array.Empty <CategoryLink>())
            {
                link.Catalog = catalogsByIdDict.GetValueOrThrow(link.CatalogId, $"link catalog with key {link.CatalogId} doesn't exist");

                if (!string.IsNullOrEmpty(link.CategoryId))
                {
                    link.Category = categoriesByIdDict.GetValueOrThrow(link.CategoryId, $"link category with key {link.CategoryId} doesn't exist").Clone() as Category;
                    link.Category.ReduceDetails((CategoryResponseGroup.WithProperties | CategoryResponseGroup.WithParents).ToString());
                }
            }
        }
Example #11
0
        private void LoadProductDependencies(IEnumerable <CsvProduct> csvProducts, Catalog catalog, out ICollection <Property> modifiedProperties)
        {
            modifiedProperties = new List <Property>();
            var allCategoriesIds = csvProducts.Select(x => x.CategoryId).Distinct().ToArray();
            var categoriesMap    = _categoryService.GetByIds(allCategoriesIds, CategoryResponseGroup.Full).ToDictionary(x => x.Id);
            var defaultLanguge   = catalog.DefaultLanguage != null ? catalog.DefaultLanguage.LanguageCode : "en-US";

            foreach (var csvProduct in csvProducts)
            {
                csvProduct.Catalog   = catalog;
                csvProduct.CatalogId = catalog.Id;
                if (csvProduct.CategoryId != null)
                {
                    csvProduct.Category = categoriesMap[csvProduct.CategoryId];
                }

                //Try to set parent relations
                //By id or code reference
                var parentProduct = csvProducts.FirstOrDefault(x => csvProduct.MainProductId != null && (x.Id == csvProduct.MainProductId || x.Code == csvProduct.MainProductId));
                csvProduct.MainProduct   = parentProduct;
                csvProduct.MainProductId = parentProduct != null ? parentProduct.Id : null;

                if (string.IsNullOrEmpty(csvProduct.Code))
                {
                    csvProduct.Code = _skuGenerator.GenerateSku(csvProduct);
                }
                csvProduct.EditorialReview.LanguageCode = defaultLanguge;
                csvProduct.SeoInfo.LanguageCode         = defaultLanguge;
                csvProduct.SeoInfo.SemanticUrl          = string.IsNullOrEmpty(csvProduct.SeoInfo.SemanticUrl) ? csvProduct.Code : csvProduct.SeoInfo.SemanticUrl;

                //Properties inheritance
                csvProduct.Properties = (csvProduct.Category != null ? csvProduct.Category.Properties : csvProduct.Catalog.Properties).OrderBy(x => x.Name).ToList();
                foreach (var propertyValue in csvProduct.PropertyValues.ToArray())
                {
                    //Try to find property meta information
                    propertyValue.Property = csvProduct.Properties.FirstOrDefault(x => x.Name.EqualsInvariant(propertyValue.PropertyName));
                    if (propertyValue.Property != null)
                    {
                        propertyValue.ValueType = propertyValue.Property.ValueType;
                        if (propertyValue.Property.Dictionary)
                        {
                            var dicValue = propertyValue.Property.DictionaryValues.FirstOrDefault(x => Equals(x.Value, propertyValue.Value));
                            if (dicValue == null)
                            {
                                dicValue = new PropertyDictionaryValue
                                {
                                    Alias = propertyValue.Value.ToString(),
                                    Value = propertyValue.Value.ToString(),
                                    Id    = Guid.NewGuid().ToString()
                                };
                                //need to register modified property for future update
                                if (!modifiedProperties.Contains(propertyValue.Property))
                                {
                                    modifiedProperties.Add(propertyValue.Property);
                                }
                            }
                            propertyValue.ValueId = dicValue.Id;
                        }
                    }
                }
            }
        }
        private void SaveProducts(Catalog catalog, List <CsvProduct> csvProducts, ExportImportProgressInfo progressInfo, Action <ExportImportProgressInfo> progressCallback)
        {
            progressInfo.ProcessedCount = 0;
            progressInfo.TotalCount     = csvProducts.Count;

            var defaultFulfilmentCenter = _commerceService.GetAllFulfillmentCenters().FirstOrDefault();

            DetectParents(csvProducts);

            //Detect already exist product by Code
            using (var repository = _catalogRepositoryFactory())
            {
                var codes         = csvProducts.Where(x => x.IsTransient()).Select(x => x.Code).Where(x => x != null).Distinct().ToArray();
                var existProducts = repository.Items.Where(x => x.CatalogId == catalog.Id && codes.Contains(x.Code)).Select(x => new { Id = x.Id, Code = x.Code }).ToArray();
                foreach (var existProduct in existProducts)
                {
                    var product = csvProducts.FirstOrDefault(x => x.Code == existProduct.Code);
                    if (product != null)
                    {
                        product.Id = product.Id;
                    }
                }
            }

            var categoriesIds = csvProducts.Where(x => x.CategoryId != null).Select(x => x.CategoryId).Distinct().ToArray();
            var categpories   = _categoryService.GetByIds(categoriesIds, CategoryResponseGroup.WithProperties);

            var defaultLanguge    = catalog.DefaultLanguage != null ? catalog.DefaultLanguage.LanguageCode : "EN-US";
            var changedProperties = new List <Property>();

            foreach (var csvProduct in csvProducts)
            {
                csvProduct.CatalogId = catalog.Id;
                if (string.IsNullOrEmpty(csvProduct.Code))
                {
                    csvProduct.Code = _skuGenerator.GenerateSku(csvProduct);
                }
                //Set a parent relations
                if (csvProduct.MainProductId == null && csvProduct.MainProduct != null)
                {
                    csvProduct.MainProductId = csvProduct.MainProduct.Id;
                }
                csvProduct.EditorialReview.LanguageCode = defaultLanguge;
                csvProduct.SeoInfo.LanguageCode         = defaultLanguge;
                csvProduct.SeoInfo.SemanticUrl          = string.IsNullOrEmpty(csvProduct.SeoInfo.SemanticUrl) ? csvProduct.Code : csvProduct.SeoInfo.SemanticUrl;

                var properties = catalog.Properties;
                if (csvProduct.CategoryId != null)
                {
                    var category = categpories.FirstOrDefault(x => x.Id == csvProduct.CategoryId);
                    if (category != null)
                    {
                        properties = category.Properties;
                    }
                }

                //Try to fill properties meta information for values
                foreach (var propertyValue in csvProduct.PropertyValues)
                {
                    if (propertyValue.Value != null)
                    {
                        var property = properties.FirstOrDefault(x => string.Equals(x.Name, propertyValue.PropertyName));
                        if (property != null)
                        {
                            propertyValue.ValueType = property.ValueType;
                            if (property.Dictionary)
                            {
                                var dicValue = property.DictionaryValues.FirstOrDefault(x => Equals(x.Value, propertyValue.Value));
                                if (dicValue == null)
                                {
                                    dicValue = new PropertyDictionaryValue
                                    {
                                        Alias = propertyValue.Value.ToString(),
                                        Value = propertyValue.Value.ToString(),
                                        Id    = Guid.NewGuid().ToString()
                                    };
                                    property.DictionaryValues.Add(dicValue);
                                    if (!changedProperties.Contains(property))
                                    {
                                        changedProperties.Add(property);
                                    }
                                }
                                propertyValue.ValueId = dicValue.Id;
                            }
                        }
                    }
                }
            }

            progressInfo.Description = string.Format("Saving property dictionary values...");
            progressCallback(progressInfo);
            _propertyService.Update(changedProperties.ToArray());

            var options = new ParallelOptions
            {
                MaxDegreeOfParallelism = 10
            };

            foreach (var group in new[] { csvProducts.Where(x => x.MainProduct == null), csvProducts.Where(x => x.MainProduct != null) })
            {
                var partSize   = 25;
                var partsCount = Math.Max(1, group.Count() / partSize);
                var parts      = group.Select((x, i) => new { Index = i, Value = x })
                                 .GroupBy(x => x.Index % partsCount)
                                 .Select(x => x.Select(v => v.Value));

                Parallel.ForEach(parts, options, products =>
                {
                    try
                    {
                        //Save main products first and then variations
                        var toUpdateProducts = products.Where(x => !x.IsTransient());
                        //Need to additional  check that  product with id exist
                        using (var repository = _catalogRepositoryFactory())
                        {
                            var updateProductIds = toUpdateProducts.Select(x => x.Id).ToArray();
                            var existProductIds  = repository.Items.Where(x => updateProductIds.Contains(x.Id)).Select(x => x.Id).ToArray();
                            toUpdateProducts     = toUpdateProducts.Where(x => existProductIds.Contains(x.Id)).ToList();
                        }
                        var toCreateProducts = products.Except(toUpdateProducts);
                        if (!toCreateProducts.IsNullOrEmpty())
                        {
                            _productService.Create(toCreateProducts.ToArray());
                        }
                        if (!toUpdateProducts.IsNullOrEmpty())
                        {
                            _productService.Update(toUpdateProducts.ToArray());
                        }

                        //Set productId for dependent objects
                        foreach (var product in products)
                        {
                            product.Inventory.ProductId           = product.Id;
                            product.Inventory.FulfillmentCenterId = product.Inventory.FulfillmentCenterId ?? defaultFulfilmentCenter.Id;
                            product.Price.ProductId = product.Id;
                        }

                        var inventories = products.Where(x => x.Inventory != null).Select(x => x.Inventory).ToArray();
                        _inventoryService.UpsertInventories(inventories);

                        var prices = products.Where(x => x.Price != null && x.Price.EffectiveValue > 0).Select(x => x.Price).ToArray();
                        _pricingService.SavePrices(prices);
                    }
                    catch (Exception ex)
                    {
                        lock (_lockObject)
                        {
                            progressInfo.Errors.Add(ex.ToString());
                            progressCallback(progressInfo);
                        }
                    }
                    finally
                    {
                        lock (_lockObject)
                        {
                            //Raise notification
                            progressInfo.ProcessedCount += products.Count();
                            progressInfo.Description     = string.Format("Saving products: {0} of {1} created", progressInfo.ProcessedCount, progressInfo.TotalCount);
                            progressCallback(progressInfo);
                        }
                    }
                });
            }
        }
        private void SaveProduct(coreModel.Catalog catalog, FulfillmentCenter defaultFulfillmentCenter, CsvProduct csvProduct)
        {
            var defaultLanguge = catalog.DefaultLanguage != null ? catalog.DefaultLanguage.LanguageCode : "EN-US";

            coreModel.CatalogProduct alreadyExistProduct = null;
            //For new product try to find them by code
            if (csvProduct.IsTransient() && !String.IsNullOrEmpty(csvProduct.Code))
            {
                var criteria = new SearchCriteria
                {
                    CatalogId     = catalog.Id,
                    CategoryId    = csvProduct.CategoryId,
                    Code          = csvProduct.Code,
                    ResponseGroup = SearchResponseGroup.WithProducts | SearchResponseGroup.WithVariations
                };
                var result = _searchService.Search(criteria);
                alreadyExistProduct = result.Products.FirstOrDefault();
                csvProduct.Id       = alreadyExistProduct != null ? alreadyExistProduct.Id : csvProduct.Id;
            }
            else if (!csvProduct.IsTransient())
            {
                //If id specified need check that product really exist
                alreadyExistProduct = _productService.GetById(csvProduct.Id, ItemResponseGroup.ItemInfo);
            }
            var isNewProduct = alreadyExistProduct == null;

            csvProduct.CatalogId = catalog.Id;

            if (String.IsNullOrEmpty(csvProduct.Code))
            {
                csvProduct.Code = _skuGenerator.GenerateSku(csvProduct);
            }
            //Set a parent relations
            if (csvProduct.MainProductId == null && csvProduct.MainProduct != null)
            {
                csvProduct.MainProductId = csvProduct.MainProduct.Id;
            }
            csvProduct.EditorialReview.LanguageCode = defaultLanguge;
            csvProduct.SeoInfo.LanguageCode         = defaultLanguge;
            csvProduct.SeoInfo.SemanticUrl          = String.IsNullOrEmpty(csvProduct.SeoInfo.SemanticUrl) ? csvProduct.Code : csvProduct.SeoInfo.SemanticUrl;

            var properties = !String.IsNullOrEmpty(csvProduct.CategoryId) ? _categoryService.GetById(csvProduct.CategoryId, CategoryResponseGroup.WithProperties).Properties : _catalogService.GetById(csvProduct.CatalogId).Properties;

            if (csvProduct.PropertyValues != null)
            {
                //Try to fill properties meta information for values
                foreach (var propertyValue in csvProduct.PropertyValues)
                {
                    if (propertyValue.Value != null)
                    {
                        var property = properties.FirstOrDefault(x => String.Equals(x.Name, propertyValue.PropertyName));
                        if (property != null)
                        {
                            propertyValue.ValueType = property.ValueType;
                            if (property.Dictionary)
                            {
                                property = _propertyService.GetById(property.Id);
                                var dicValue = property.DictionaryValues.FirstOrDefault(x => String.Equals(x.Value, propertyValue.Value));
                                propertyValue.ValueId = dicValue != null ? dicValue.Id : null;
                            }
                        }
                    }
                }
            }

            if (!isNewProduct)
            {
                _productService.Update(new coreModel.CatalogProduct[] { csvProduct });
            }
            else
            {
                var newProduct = _productService.Create(csvProduct);
                csvProduct.Id = newProduct.Id;
            }

            //Create price in default price list

            if (csvProduct.Price.EffectiveValue > 0)
            {
                csvProduct.Price.ProductId = csvProduct.Id;

                if (csvProduct.Price.IsTransient() || _pricingService.GetPriceById(csvProduct.Price.Id) == null)
                {
                    _pricingService.CreatePrice(csvProduct.Price);
                }
                else
                {
                    _pricingService.UpdatePrices(new Price[] { csvProduct.Price });
                }
            }

            //Create inventory
            csvProduct.Inventory.ProductId           = csvProduct.Id;
            csvProduct.Inventory.FulfillmentCenterId = csvProduct.Inventory.FulfillmentCenterId ?? defaultFulfillmentCenter.Id;
            _inventoryService.UpsertInventory(csvProduct.Inventory);
        }