Пример #1
0
        private void SetOptions(ProductImportDataTransferObject dataTransferObject, Product product)
        {
            List <string> optionsToAdd =
                dataTransferObject.Options.Where(
                    s => !product.Options.Select(option => option.Name).Contains(s, StringComparer.OrdinalIgnoreCase))
                .ToList();
            List <ProductOption> optionsToRemove =
                product.Options.Where(option => !dataTransferObject.Options.Contains(option.Name)).ToList();

            foreach (string option in optionsToAdd)
            {
                ProductOption existingOption =
                    _session.QueryOver <ProductOption>()
                    .Where(productOption => productOption.Name.IsInsensitiveLike(option, MatchMode.Exact))
                    .Take(1).SingleOrDefault();
                if (existingOption == null)
                {
                    existingOption = new ProductOption
                    {
                        Name = option,
                    };

                    _session.Transact(session => session.Save(existingOption));
                }
                product.Options.Add(existingOption);
                existingOption.Products.Add(product);
            }
            foreach (ProductOption option in optionsToRemove)
            {
                product.Options.Remove(option);
                option.Products.Remove(product);
            }
        }
Пример #2
0
        public IEnumerable <string> GetErrors(ProductImportDataTransferObject product)
        {
            var errors = new List <string>();

            try
            {
                foreach (var item in product.Images)
                {
                    Uri testUri;
                    var result = Uri.TryCreate(item, UriKind.Absolute, out testUri) &&
                                 (testUri.Scheme == Uri.UriSchemeHttps || testUri.Scheme == Uri.UriSchemeHttp);
                    if (!result)
                    {
                        errors.Add(string.Format(
                                       "{0} is not valid Url.",
                                       item));
                    }
                }
            }
            catch (Exception)
            {
                errors.Add("Some of Image Urls are not in correct format.");
            }

            return(errors);
        }
Пример #3
0
 private static void GetBasicData(Dictionary <string, List <string> > parseErrors, ExcelWorksheet worksheet, int rowId,
                                  ProductImportDataTransferObject product, string handle)
 {
     if (worksheet.GetValue <string>(rowId, 2).HasValue())
     {
         product.Name = worksheet.GetValue <string>(rowId, 2);
     }
     else
     {
         parseErrors[handle].Add("Product Name is required.");
     }
     product.Description    = worksheet.GetValue <string>(rowId, 3);
     product.SEOTitle       = worksheet.GetValue <string>(rowId, 4);
     product.SEODescription = worksheet.GetValue <string>(rowId, 5);
     product.SEOKeywords    = worksheet.GetValue <string>(rowId, 6);
     product.Abstract       = worksheet.GetValue <string>(rowId, 7);
     product.Brand          = worksheet.GetValue <string>(rowId, 8);
     if (worksheet.GetValue <string>(rowId, 32).HasValue())
     {
         if (!worksheet.GetValue <string>(rowId, 32).IsValidDateTime())
         {
             parseErrors[handle].Add("Publish Date is not a valid date.");
         }
         else
         {
             product.PublishDate = worksheet.GetValue <DateTime>(rowId, 32);
         }
     }
 }
Пример #4
0
        public void ImportProductsService_ImportProduct_ShouldSetProductPrimaryProperties()
        {
            var product = new ProductImportDataTransferObject
            {
                UrlSegment     = "test-url",
                Name           = "Test Product",
                Abstract       = "Test Abstract",
                Description    = "Test Description",
                SEODescription = "Test SEO Description",
                SEOKeywords    = "Test, Thought",
                SEOTitle       = "Test SEO Title"
            };

            ProductContainer container = new ProductContainer().PersistTo(Session);

            A.CallTo(() => _uniquePageService.GetUniquePage <ProductContainer>()).Returns(container);
            MediaCategory category = new MediaCategory().PersistTo(Session);

            A.CallTo(() => _documentService.GetDocumentByUrl <MediaCategory>("product-galleries")).Returns(category);

            Product result = _importProductsService.ImportProduct(product);

            result.UrlSegment.ShouldBeEquivalentTo("test-url");
            result.Name.ShouldBeEquivalentTo("Test Product");
            result.ProductAbstract.ShouldBeEquivalentTo("Test Abstract");
            result.BodyContent.ShouldBeEquivalentTo("Test Description");
            result.MetaDescription.ShouldBeEquivalentTo("Test SEO Description");
            result.MetaKeywords.ShouldBeEquivalentTo("Test, Thought");
            result.MetaTitle.ShouldBeEquivalentTo("Test SEO Title");
        }
Пример #5
0
        private static void GetCategories(Dictionary <string, List <string> > parseErrors, ExcelWorksheet worksheet, int rowId,
                                          ProductImportDataTransferObject product, string handle)
        {
//Categories
            try
            {
                var value = worksheet.GetValue <string>(rowId, 9);
                if (!String.IsNullOrWhiteSpace(value))
                {
                    var Cats = value.Split(';');
                    foreach (var item in Cats)
                    {
                        if (!String.IsNullOrWhiteSpace(item))
                        {
                            if (!product.Categories.Any(x => x == item))
                            {
                                product.Categories.Add(item);
                            }
                            else
                            {
                                parseErrors[handle].Add(
                                    "Product Categories field value contains duplicate values.");
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                parseErrors[handle].Add(
                    "Product Categories field value contains illegal characters / not in correct format.");
            }
        }
Пример #6
0
        public void ImportProductsService_ImportProducts_ShouldSetCategoriesIfTheyExist()
        {
            var productDTO = new ProductImportDataTransferObject
            {
                UrlSegment = "test-url",
                Categories = new List <string> {
                    "test-category"
                }
            };

            var category = new Category {
                Id = 1, Name = "Test Category"
            };

            A.CallTo(() => _documentService.GetDocument <Category>(1)).Returns(category);

            var product = new Product {
                Name = "Test Product"
            };

            A.CallTo(() => _documentService.GetDocumentByUrl <Product>(productDTO.UrlSegment)).Returns(product);

            Product importProduct = _importProductsService.ImportProduct(productDTO);

            importProduct.Categories.Should().HaveCount(1);
        }
        public void ImportProductVariantsService_ImportVariants_ShouldSetProductVariantTaxRate()
        {
            var productVariantDTO = new ProductVariantImportDataTransferObject
            {
                SKU     = "123",
                TaxRate = 1
            };
            var productDTO = new ProductImportDataTransferObject
            {
                UrlSegment      = "test-url",
                ProductVariants = new List <ProductVariantImportDataTransferObject>()
                {
                    productVariantDTO
                }
            };

            var product = new Product {
                Name = "Test Product"
            };

            var taxRate = new TaxRate()
            {
                Id = 1, Name = "GLOBAL"
            };

            A.CallTo(() => _taxRateManager.Get(productVariantDTO.TaxRate.Value)).Returns(taxRate);

            var result = _importProductVariantsService.ImportVariants(productDTO, product);

            result.First().TaxRate.Name.ShouldBeEquivalentTo("GLOBAL");
        }
        public void ImportProductVariantsService_ImportVariants_ShouldCallImportVariantPriceBreaksOfImportProductVariantPriceBreaksService()
        {
            var productVariantDTO = new ProductVariantImportDataTransferObject
            {
                SKU         = "123",
                PriceBreaks = new Dictionary <int, decimal>()
                {
                    { 10, 299 }
                }
            };
            var productDTO = new ProductImportDataTransferObject
            {
                UrlSegment      = "test-url",
                ProductVariants = new List <ProductVariantImportDataTransferObject>()
                {
                    productVariantDTO
                }
            };

            var product = new Product();

            var productVariant = new ProductVariant()
            {
                Name = "Test Product Variant"
            };

            _importProductVariantsService.ImportVariants(productDTO, product);

            A.CallTo(() => _importProductVariantPriceBreaksService.ImportVariantPriceBreaks(productVariantDTO, productVariant)).MustHaveHappened();
        }
Пример #9
0
        private static void GetUrlHistory(Dictionary <string, List <string> > parseErrors, ExcelWorksheet worksheet, int rowId,
                                          ProductImportDataTransferObject product, string handle)
        {
//Url History
            try
            {
                var value = worksheet.GetValue <string>(rowId, 31);
                if (!String.IsNullOrWhiteSpace(value))
                {
                    var urlHistory = value.Split(',');
                    foreach (var item in urlHistory)
                    {
                        if (!String.IsNullOrWhiteSpace(item))
                        {
                            product.UrlHistory.Add(item);
                        }
                    }
                }
            }
            catch (Exception)
            {
                parseErrors[handle].Add(
                    "Product Url History field value contains illegal characters / not in correct format.");
            }
        }
Пример #10
0
        public void ImportProductsService_ImportProduct_ShouldCallGetGetDocumentByUrlOfDocumentService()
        {
            var product = new ProductImportDataTransferObject
            {
                UrlSegment = "test-url",
            };

            _importProductsService.ImportProduct(product);

            A.CallTo(() => _documentService.GetDocumentByUrl <Product>(product.UrlSegment)).MustHaveHappened();
        }
Пример #11
0
        public void ImportProductsService_ImportProducts_ShouldSetTheBrandToOneWithTheCorrectNameIfItDoesNotExist()
        {
            var product = new ProductImportDataTransferObject
            {
                UrlSegment = "test-url",
                Brand      = "Test Brand"
            };

            Product importProduct = _importProductsService.ImportProduct(product);

            importProduct.BrandPage.Name.Should().Be("Test Brand");
        }
Пример #12
0
        public IEnumerable <ProductSpecificationValue> ImportSpecifications(
            ProductImportDataTransferObject dataTransferObject, Product product)
        {
            List <KeyValuePair <string, string> > specificationsToAdd =
                dataTransferObject.Specifications.Where(
                    s =>
                    !product.SpecificationValues.Select(value => value.SpecificationName)
                    .Contains(s.Key, StringComparer.InvariantCultureIgnoreCase)).ToList();
            List <ProductSpecificationValue> specificationsToRemove =
                product.SpecificationValues.Where(
                    value =>
                    !dataTransferObject.Specifications.Keys.Contains(value.SpecificationName,
                                                                     StringComparer.InvariantCultureIgnoreCase))
                .ToList();
            List <ProductSpecificationValue> specificationsToUpdate =
                product.SpecificationValues.Where(value => !specificationsToRemove.Contains(value)).ToList();

            foreach (var item in specificationsToAdd)
            {
                ProductSpecificationAttribute attribute =
                    _session.QueryOver <ProductSpecificationAttribute>()
                    .Where(
                        specificationAttribute =>
                        specificationAttribute.Name.IsInsensitiveLike(item.Key, MatchMode.Exact))
                    .Take(1)
                    .SingleOrDefault();
                if (attribute == null)
                {
                    attribute = new ProductSpecificationAttribute {
                        Name = item.Key
                    };
                    _session.Transact(session => session.Save(attribute));
                }

                SetValue(product, attribute, item.Value);
            }

            foreach (ProductSpecificationValue value in specificationsToRemove)
            {
                RemoveValue(product, value);
            }
            foreach (ProductSpecificationValue value in specificationsToUpdate)
            {
                ProductSpecificationAttribute attribute =
                    value.ProductSpecificationAttributeOption.ProductSpecificationAttribute;
                RemoveValue(product, value);

                SetValue(product, attribute, dataTransferObject.Specifications[value.SpecificationName]);
            }

            return(dataTransferObject.Specifications.Any() ? product.SpecificationValues : null);
        }
Пример #13
0
        public void ImportProductsService_ImportProduct_ShouldTryToLoadTheCategoryFromTheDocumentService()
        {
            var product = new ProductImportDataTransferObject
            {
                UrlSegment = "test-url",
                Categories = new List <string> {
                    "test-category"
                }
            };

            _importProductsService.ImportProduct(product);

            A.CallTo(() => _documentService.GetDocumentByUrl <Category>("test-category")).MustHaveHappened();
        }
Пример #14
0
        public IEnumerable <string> GetErrors(ProductImportDataTransferObject product)
        {
            var value = Selector(product);

            if (!String.IsNullOrWhiteSpace(value))
            {
                if (value.Length > Length)
                {
                    yield return
                        (string.Format(
                             "{0} is too long - max length is {1} characters and your value is {2} characters in length.",
                             DisplayName, Length, value.Length));
                }
            }
        }
Пример #15
0
        private static void GetImages(ExcelWorksheet worksheet, int rowId, ProductImportDataTransferObject product)
        {
//Images
            if (worksheet.GetValue <string>(rowId, 27).HasValue())
            {
                product.Images.Add(worksheet.GetValue <string>(rowId, 27));
            }
            if (worksheet.GetValue <string>(rowId, 28).HasValue())
            {
                product.Images.Add(worksheet.GetValue <string>(rowId, 28));
            }
            if (worksheet.GetValue <string>(rowId, 29).HasValue())
            {
                product.Images.Add(worksheet.GetValue <string>(rowId, 29));
            }
        }
Пример #16
0
        public void ImportProductsService_ImportProducts_ShouldSetProductBrandIfItAlreadyExists()
        {
            var product = new ProductImportDataTransferObject
            {
                UrlSegment = "test-url",
                Brand      = "Test Brand"
            };

            var brand = new Brand {
                Name = "Test BrandPage"
            };

            Product importProduct = _importProductsService.ImportProduct(product);

            importProduct.BrandPage.Should().Be(brand);
        }
Пример #17
0
        public void ImportSpecificationsService_ImportSpecifications_ShouldCallGetSpecificationAttributeByNameOfProductOptionManager()
        {
            var productDTO = new ProductImportDataTransferObject()
            {
                UrlSegment     = "test-url",
                Specifications = new Dictionary <string, string>()
                {
                    { "Storage", "16GB" }
                }
            };

            var product = new Product();

            _importSpecificationsService.ImportSpecifications(productDTO, product);

            Session.Query <ProductSpecificationAttribute>().First().Options.First().Name.Should().Be("16GB");
        }
        public void ImportProductVariantsService_ImportVariants_ShouldCallGetProductVariantBySKUOfProductVariantService()
        {
            var productVariant = new ProductVariantImportDataTransferObject
            {
                SKU = "123"
            };
            var productDTO = new ProductImportDataTransferObject
            {
                UrlSegment      = "test-url",
                ProductVariants = new List <ProductVariantImportDataTransferObject>()
                {
                    productVariant
                }
            };

            var product = new Product();

            _importProductVariantsService.ImportVariants(productDTO, product);
        }
Пример #19
0
 private void SetBrand(ProductImportDataTransferObject dataTransferObject, Product product)
 {
     //Brand
     if (!String.IsNullOrWhiteSpace(dataTransferObject.Brand))
     {
         string dtoBrand = dataTransferObject.Brand.Trim();
         Brand  brand    =
             _session.QueryOver <Brand>()
             .Where(b => b.Name.IsInsensitiveLike(dtoBrand, MatchMode.Exact))
             .Take(1)
             .SingleOrDefault();
         if (brand == null)
         {
             brand = _getNewBrandPage.Get(dtoBrand);
             _session.Transact(session => session.Save(brand));
         }
         product.BrandPage = brand;
     }
 }
Пример #20
0
        private static void GetSpecifications(Dictionary <string, List <string> > parseErrors, ExcelWorksheet worksheet, int rowId, string handle,
                                              ProductImportDataTransferObject product)
        {
//Specifications
            var specificationsValue = worksheet.GetValue <string>(rowId, 10);

            if (!String.IsNullOrWhiteSpace(specificationsValue))
            {
                try
                {
                    if (!String.IsNullOrWhiteSpace(specificationsValue))
                    {
                        if (!specificationsValue.Contains(":"))
                        {
                            parseErrors[handle].Add(
                                "Product Specifications field value contains illegal characters / not in correct format. Names and Values (Item) must be split with :, and items must be split by ;");
                        }
                        var specs = specificationsValue.Split(';');
                        foreach (var item in specs)
                        {
                            if (!String.IsNullOrWhiteSpace(item))
                            {
                                string[] specificationValue = item.Split(':');
                                if (!String.IsNullOrWhiteSpace(specificationValue[0]) &&
                                    !String.IsNullOrWhiteSpace(specificationValue[1]) &&
                                    !product.Specifications.ContainsKey(
                                        specificationValue[0]))
                                {
                                    product.Specifications.Add(specificationValue[0],
                                                               specificationValue[1]);
                                }
                            }
                        }
                    }
                }
                catch (Exception)
                {
                    parseErrors[handle].Add(
                        "Product Specifications field value contains illegal characters / not in correct format. Names and Values (Item) must be split with :, and items must be split by ;");
                }
            }
        }
Пример #21
0
        public void ImportProductService_ImportProducts_ShouldCallImportUrlHistoryOfImportProductUrlHistoryService()
        {
            var productDTO = new ProductImportDataTransferObject
            {
                UrlSegment = "test-url",
                UrlHistory = new List <string> {
                    "test-url-old"
                }
            };

            var product = new Product {
                Name = "Test Product"
            };

            A.CallTo(() => _documentService.GetDocumentByUrl <Product>(productDTO.UrlSegment)).Returns(product);

            _importProductsService.ImportProduct(productDTO);

            A.CallTo(() => _importProductUrlHistoryService.ImportUrlHistory(productDTO, product)).MustHaveHappened();
        }
Пример #22
0
        public void ImportSpecificationsService_ImportSpecifications_ShouldAddANewSpecificationAttributeIfItDoesntExist()
        {
            var productDTO = new ProductImportDataTransferObject()
            {
                UrlSegment     = "test-url",
                Specifications = new Dictionary <string, string>()
                {
                    { "Storage", "16GB" }
                }
            };

            var product = new Product()
            {
                Name = "Test Product"
            };

            _importSpecificationsService.ImportSpecifications(productDTO, product);

            Session.Query <ProductSpecificationAttribute>().First().Options.Should().HaveCount(1);
        }
Пример #23
0
        public void ImportSpecificationsService_ImportSpecifications_ShouldSetSpecifications()
        {
            var productDTO = new ProductImportDataTransferObject()
            {
                UrlSegment     = "test-url",
                Specifications = new Dictionary <string, string>()
                {
                    { "Storage", "16GB" }
                }
            };

            var product = new Product()
            {
                Name = "Test Product"
            };

            _importSpecificationsService.ImportSpecifications(productDTO, product);

            product.SpecificationValues.Should().HaveCount(1);
        }
Пример #24
0
        public IEnumerable <string> GetErrors(ProductImportDataTransferObject product)
        {
            var errors       = new List <string>();
            var mrCmsProduct = _productService.GetByUrl(product.UrlSegment);

            foreach (var pv in product.ProductVariants)
            {
                var mrCmsVariant = _productVariantService.GetProductVariantBySKU(pv.SKU);

                if (mrCmsVariant != null)
                {
                    if (mrCmsProduct == null || (mrCmsVariant.Product.Id != mrCmsProduct.Id))
                    {
                        errors.Add(string.Format("Product Variant with SKU {0} already exists on product with Url Segment {1}", pv.SKU, mrCmsVariant.Product.UrlSegment));
                    }
                }
            }

            return(errors);
        }
Пример #25
0
        public void SetCategories(ProductImportDataTransferObject dataTransferObject, Product product)
        {
            //Categories
            List <string> categoriesToAdd =
                dataTransferObject.Categories.Where(
                    s =>
                    !product.Categories.Select(category => category.UrlSegment)
                    .Contains(s, StringComparer.OrdinalIgnoreCase)).ToList();
            List <Category> categoriesToRemove =
                product.Categories.Where(
                    category =>
                    !dataTransferObject.Categories.Contains(category.UrlSegment, StringComparer.OrdinalIgnoreCase))
                .ToList();

            foreach (string item in categoriesToAdd)
            {
                Category category =
                    _session.QueryOver <Category>()
                    .Where(c => c.UrlSegment.IsInsensitiveLike(item, MatchMode.Exact))
                    .Take(1)
                    .SingleOrDefault();
                if (category != null)
                {
                    product.Categories.Add(category);
                    if (!category.Products.Contains(product))
                    {
                        category.Products.Add(product);
                    }
                }
            }
            foreach (Category category in categoriesToRemove)
            {
                product.Categories.Remove(category);
                if (category.Products.Contains(product))
                {
                    category.Products.Remove(product);
                }
            }
        }
        public void ImportProductVariantsService_ImportVariants_ShouldSetProductVariantPrimaryProperties()
        {
            var productVariantDTO = new ProductVariantImportDataTransferObject
            {
                PreviousPrice  = 2,
                Price          = 1,
                SKU            = "123",
                Name           = "Test Product Variant",
                TrackingPolicy = TrackingPolicy.Track,
                Weight         = 0,
                Barcode        = "456",
                Stock          = 5
            };
            var productDTO = new ProductImportDataTransferObject
            {
                UrlSegment      = "test-url",
                ProductVariants = new List <ProductVariantImportDataTransferObject>()
                {
                    productVariantDTO
                }
            };

            var product = new Product()
            {
                Name = "Test Product"
            };

            var result = _importProductVariantsService.ImportVariants(productDTO, product);

            result.First().PreviousPrice.ShouldBeEquivalentTo(2);
            result.First().BasePrice.ShouldBeEquivalentTo(1);
            result.First().SKU.ShouldBeEquivalentTo("123");
            result.First().Name.ShouldBeEquivalentTo("Test Product Variant");
            result.First().TrackingPolicy.ShouldBeEquivalentTo(TrackingPolicy.Track);
            result.First().Weight.ShouldBeEquivalentTo(0);
            result.First().Barcode.ShouldBeEquivalentTo("456");
            result.First().StockRemaining.ShouldBeEquivalentTo(5);
        }
        public void ImportUrlHistory(ProductImportDataTransferObject productDto, Product product)
        {
            List<string> urlsToAdd =
                 productDto.UrlHistory.Where(
                     s =>
                         !product.Urls.Select(history => history.UrlSegment)
                             .Contains(s, StringComparer.InvariantCultureIgnoreCase)).ToList();
            //List<UrlHistory> urlsToRemove =
            //    product.Urls.Where(
            //        history =>
            //            !productDto.UrlHistory.Contains(history.UrlSegment, StringComparer.InvariantCultureIgnoreCase))
            //        .ToList();
            foreach (string item in urlsToAdd)
            {
                UrlHistory history =
                    _session.Query<UrlHistory>().FirstOrDefault(urlHistory => urlHistory.UrlSegment == item);
                bool isNew = history == null;
                if (isNew)
                {
                    history = new UrlHistory { UrlSegment = item, Webpage = product };
                    _session.Transact(session => session.Save(history));
                }
                else
                    history.Webpage = product;
                if (!product.Urls.Contains(history))
                    product.Urls.Add(history);
                _session.Transact(session => session.Update(history));
            }

            //foreach (UrlHistory history in urlsToRemove)
            //{
            //    product.Urls.Remove(history);
            //    history.Webpage = null;
            //    UrlHistory closureHistory = history;
            //    _session.Transact(session => session.Update(closureHistory));
            //}
        }
        public void ImportProductVariantsService_ImportVariants_ShouldAddVariantsToProduct()
        {
            var productVariantDTO = new ProductVariantImportDataTransferObject
            {
                SKU = "123"
            };
            var productDTO = new ProductImportDataTransferObject
            {
                UrlSegment      = "test-url",
                ProductVariants = new List <ProductVariantImportDataTransferObject>()
                {
                    productVariantDTO
                }
            };

            var product = new Product()
            {
                Name = "Test Product"
            };

            _importProductVariantsService.ImportVariants(productDTO, product);

            product.Variants.Should().HaveCount(1);
        }
Пример #29
0
 public IEnumerable <string> GetErrors(ProductImportDataTransferObject product)
 {
     return((from item in product.Categories
             where _documentService.GetDocumentByUrl <Category>(item) == null
             select string.Format("Category with url: {0} is not present within the system.", item)).ToList());
 }
Пример #30
0
        /// <summary>
        /// Validate And Import Products With Variants
        /// </summary>
        /// <param name="spreadsheet"></param>
        /// <param name="parseErrors"></param>
        /// <returns></returns>
        public HashSet <ProductImportDataTransferObject> ValidateAndImportProductsWithVariants(ExcelPackage spreadsheet, ref Dictionary <string, List <string> > parseErrors)
        {
            var productsToImport = new HashSet <ProductImportDataTransferObject>();

            if (!parseErrors.Any())
            {
                if (spreadsheet != null)
                {
                    if (spreadsheet.Workbook != null)
                    {
                        var worksheet = spreadsheet.Workbook.Worksheets.SingleOrDefault(x => x.Name == "Items");
                        if (worksheet != null)
                        {
                            var totalRows = worksheet.Dimension.End.Row;
                            for (var rowId = 2; rowId <= totalRows; rowId++)
                            {
                                if (!worksheet.GetValue <string>(rowId, 1).HasValue() &&
                                    !worksheet.GetValue <string>(rowId, 2).HasValue() &&
                                    !worksheet.GetValue <string>(rowId, 3).HasValue())
                                {
                                    continue;
                                }

                                var product = new ProductImportDataTransferObject();

                                //Prepare handle name for storing and grouping errors
                                string url  = worksheet.GetValue <string>(rowId, 1),
                                       name = worksheet.GetValue <string>(rowId, 2);
                                var handle  = url.HasValue() ? url : SeoHelper.TidyUrl(name);

                                if (!productsToImport.Any(x => x.Name == name || x.UrlSegment == url))
                                {
                                    if (parseErrors.All(x => x.Key != handle))
                                    {
                                        parseErrors.Add(handle, new List <string>());
                                    }

                                    product.UrlSegment = worksheet.GetValue <string>(rowId, 1).HasValue()
                                        ? worksheet.GetValue <string>(rowId, 1)
                                        : _urlService.Suggest(null,
                                                              new SuggestParams
                                    {
                                        PageName     = name,
                                        DocumentType = typeof(Product).FullName
                                    });
                                    //skip duplicate url
                                    if (productsToImport.Any(x => x.UrlSegment == product.UrlSegment))
                                    {
                                        continue;
                                    }

                                    GetBasicData(parseErrors, worksheet, rowId, product, handle);

                                    GetCategories(parseErrors, worksheet, rowId, product, handle);

                                    GetSpecifications(parseErrors, worksheet, rowId, handle, product);

                                    GetImages(worksheet, rowId, product);

                                    GetUrlHistory(parseErrors, worksheet, rowId, product, handle);

                                    productsToImport.Add(product);
                                }
                                else
                                {
                                    product = !string.IsNullOrWhiteSpace(url) ?
                                              productsToImport.SingleOrDefault(x => x.Name == name && x.UrlSegment == url)
                                        : productsToImport.SingleOrDefault(x => x.Name == name);
                                }

                                //Variants
                                if (product != null)
                                {
                                    var productVariant = GetProductVariant(parseErrors, worksheet, rowId, handle);
                                    if (productVariant != null)
                                    {
                                        //Options
                                        GetProductVariantOptions(worksheet, rowId, productVariant);

                                        //Price Breaks
                                        GetPriceBreaks(parseErrors, worksheet, rowId, handle, productVariant);

                                        product.ProductVariants.Add(productVariant);
                                    }
                                }
                            }
                        }
                    }
                }

                //Remove handles with no errors
                parseErrors = parseErrors.Where(x => x.Value.Any()).ToDictionary(pair => pair.Key, pair => pair.Value);
            }
            var i = productsToImport.Where(x => x.ProductVariants.Count == 0).ToList();

            return(productsToImport);
        }