Exemple #1
0
        protected virtual int ProcessCustomerRoles(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Customer> > batch)
        {
            Dictionary <string, CustomerRole> allCustomerRoles = null;

            foreach (var row in batch)
            {
                var customer = row.Entity;
                var importRoleSystemNames = row.GetDataValue <List <string> >("CustomerRoleSystemNames");

                var assignedRoles = customer.CustomerRoleMappings
                                    .Where(x => !x.IsSystemMapping)
                                    .Select(x => x.CustomerRole)
                                    .ToDictionarySafe(x => x.SystemName, StringComparer.OrdinalIgnoreCase);

                // Roles to remove.
                foreach (var customerRole in assignedRoles)
                {
                    var systemName = customerRole.Key;
                    if (!systemName.IsCaseInsensitiveEqual(SystemCustomerRoleNames.Administrators) &&
                        !systemName.IsCaseInsensitiveEqual(SystemCustomerRoleNames.SuperAdministrators) &&
                        !importRoleSystemNames.Contains(systemName))
                    {
                        var mappings = customer.CustomerRoleMappings.Where(x => !x.IsSystemMapping && x.CustomerRoleId == customerRole.Value.Id).ToList();
                        mappings.Each(x => _customerService.DeleteCustomerRoleMapping(x));
                    }
                }

                // Roles to add.
                foreach (var systemName in importRoleSystemNames)
                {
                    if (systemName.IsCaseInsensitiveEqual(SystemCustomerRoleNames.Administrators) ||
                        systemName.IsCaseInsensitiveEqual(SystemCustomerRoleNames.SuperAdministrators))
                    {
                        context.Result.AddInfo("Security. Ignored administrator role.", row.GetRowInfo(), "CustomerRoleSystemNames");
                    }
                    else if (!assignedRoles.ContainsKey(systemName))
                    {
                        // Add role mapping, never insert roles.
                        // Be careful not to insert the roles several times!
                        if (allCustomerRoles == null)
                        {
                            allCustomerRoles = _customerRoleRepository.TableUntracked
                                               .Where(x => !string.IsNullOrEmpty(x.SystemName))
                                               .ToDictionarySafe(x => x.SystemName, StringComparer.OrdinalIgnoreCase);
                        }

                        if (allCustomerRoles.TryGetValue(systemName, out var role))
                        {
                            _customerService.InsertCustomerRoleMapping(new CustomerRoleMapping {
                                CustomerId = customer.Id, CustomerRoleId = role.Id
                            });
                        }
                    }
                }
            }

            return(_services.DbContext.SaveChanges());
        }
        protected virtual int ProcessParentMappings(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Category> > batch,
            Dictionary <int, ImportCategoryMapping> srcToDestId)
        {
            foreach (var row in batch)
            {
                var id          = row.GetDataValue <int>("Id");
                var rawParentId = row.GetDataValue <string>("ParentCategoryId");
                var parentId    = rawParentId.ToInt(-1);

                if (id != 0 && parentId != -1 && srcToDestId.ContainsKey(id) && srcToDestId.ContainsKey(parentId))
                {
                    // only touch hierarchical data if child and parent were inserted
                    if (srcToDestId[id].Inserted && srcToDestId[parentId].Inserted && srcToDestId[id].DestinationId != 0)
                    {
                        var category = _categoryRepository.GetById(srcToDestId[id].DestinationId);
                        if (category != null)
                        {
                            category.ParentCategoryId = srcToDestId[parentId].DestinationId;

                            _categoryRepository.Update(category);
                        }
                    }
                }
            }

            var num = _categoryRepository.Context.SaveChanges();

            return(num);
        }
Exemple #3
0
        protected virtual int ProcessProductMappings(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Product> > batch,
            Dictionary <int, ImportProductMapping> srcToDestId)
        {
            _productRepository.AutoCommitEnabled = false;

            foreach (var row in batch)
            {
                var id = row.GetDataValue <int>("Id");
                var parentGroupedProductId = row.GetDataValue <int>("ParentGroupedProductId");

                if (id != 0 && parentGroupedProductId != 0 && srcToDestId.ContainsKey(id) && srcToDestId.ContainsKey(parentGroupedProductId))
                {
                    // only touch relationship if child and parent were inserted
                    if (srcToDestId[id].Inserted && srcToDestId[parentGroupedProductId].Inserted && srcToDestId[id].DestinationId != 0)
                    {
                        var product = _productRepository.GetById(srcToDestId[id].DestinationId);
                        if (product != null)
                        {
                            product.ParentGroupedProductId = srcToDestId[parentGroupedProductId].DestinationId;
                            _productRepository.Update(product);
                        }
                    }
                }
            }

            var num = _productRepository.Context.SaveChanges();

            return(num);
        }
        protected virtual int ProcessAvatars(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Customer> > batch)
        {
            foreach (var row in batch)
            {
                var urlOrPath = row.GetDataValue <string>("AvatarPictureUrl");
                if (urlOrPath.IsEmpty())
                {
                    continue;
                }

                var image = CreateDownloadImage(context, urlOrPath, 1);
                if (image.Url.HasValue() && !image.Success.HasValue)
                {
                    AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, new FileDownloadManagerItem[] { image }));
                }

                if ((image.Success ?? false) && File.Exists(image.Path))
                {
                    Succeeded(image);
                    using (var stream = File.OpenRead(image.Path))
                    {
                        if ((stream?.Length ?? 0) > 0)
                        {
                            var currentFiles = new List <MediaFileInfo>();
                            var fileId       = row.Entity.GetAttribute <int>(SystemCustomerAttributeNames.AvatarPictureId);
                            var file         = _mediaService.GetFileById(fileId, MediaLoadFlags.AsNoTracking);
                            if (file != null)
                            {
                                currentFiles.Add(file);
                            }

                            if (!_mediaService.FindEqualFile(stream, currentFiles.Select(x => x.File), true, out var _))
                            {
                                // Don't manage avatar files. Just overwrite existing file.
                                var path = _mediaService.CombinePaths(SystemAlbumProvider.Customers, image.FileName.ToValidFileName());

                                var newFile = _mediaService.SaveFile(path, stream, false, DuplicateFileHandling.Overwrite);
                                if ((newFile?.Id ?? 0) != 0)
                                {
                                    SaveAttribute(row, SystemCustomerAttributeNames.AvatarPictureId, newFile.Id);
                                }
                            }
                            else
                            {
                                context.Result.AddInfo("Found equal image in data store. Skipping field.", row.GetRowInfo(), "AvatarPictureUrl");
                            }
                        }
                    }
                }
                else
                {
                    context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "AvatarPictureUrl");
                }
            }

            return(_services.DbContext.SaveChanges());
        }
Exemple #5
0
        public ImportBatchExecutedEvent(ImportExecuteContext context, IEnumerable <ImportRow <TEntity> > batch)
        {
            Guard.NotNull(context, nameof(context));
            Guard.NotNull(batch, nameof(batch));

            Context = context;
            Batch   = batch;
        }
Exemple #6
0
        public DataImporterContext(
            DataImportRequest request,
            CancellationToken cancellationToken,
            string progressInfo)
        {
            Request           = request;
            CancellationToken = cancellationToken;

            ExecuteContext = new ImportExecuteContext(CancellationToken, Request.ProgressValueSetter, progressInfo);
        }
Exemple #7
0
        protected virtual int ProcessProductCategories(ImportExecuteContext context, IEnumerable <ImportRow <Product> > batch)
        {
            _productCategoryRepository.AutoCommitEnabled = false;

            ProductCategory lastInserted = null;

            foreach (var row in batch)
            {
                var categoryIds = row.GetDataValue <List <int> >("CategoryIds");
                if (!categoryIds.IsNullOrEmpty())
                {
                    try
                    {
                        foreach (var id in categoryIds)
                        {
                            if (_productCategoryRepository.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.CategoryId == id).FirstOrDefault() == null)
                            {
                                // ensure that category exists
                                var category = _categoryService.GetCategoryById(id);
                                if (category != null)
                                {
                                    var productCategory = new ProductCategory
                                    {
                                        ProductId         = row.Entity.Id,
                                        CategoryId        = category.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder      = 1
                                    };
                                    _productCategoryRepository.Insert(productCategory);
                                    lastInserted = productCategory;
                                }
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddWarning(exception.Message, row.GetRowInfo(), "CategoryIds");
                    }
                }
            }

            // commit whole batch at once
            var num = _productCategoryRepository.Context.SaveChanges();

            // Perf: notify only about LAST insertion and update
            if (lastInserted != null)
            {
                _services.EventPublisher.EntityInserted(lastInserted);
            }

            return(num);
        }
Exemple #8
0
        protected virtual int ProcessAddresses(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Customer> > batch,
            Dictionary <string, int> allCountries,
            Dictionary <Tuple <int, string>, int> allStateProvinces)
        {
            foreach (var row in batch)
            {
                ImportAddress("BillingAddress.", row, context, allCountries, allStateProvinces);
                ImportAddress("ShippingAddress.", row, context, allCountries, allStateProvinces);
            }

            return(_services.DbContext.SaveChanges());
        }
        public DataImporterContext(
            DataImportRequest request,
            CancellationToken cancellationToken,
            string progressInfo)
        {
            Request           = request;
            CancellationToken = cancellationToken;

            ExecuteContext = new ImportExecuteContext(CancellationToken, Request.ProgressValueSetter, progressInfo)
            {
                Request = request
            };

            ColumnMap = new ColumnMapConverter().ConvertFrom <ColumnMap>(Request.Profile.ColumnMapping) ?? new ColumnMap();
            Results   = new Dictionary <string, ImportResult>();
        }
Exemple #10
0
 private void AddInfoForDeprecatedFields(ImportExecuteContext context)
 {
     if (context.DataSegmenter.HasColumn("IsGuest"))
     {
         context.Result.AddInfo("Deprecated field. Use CustomerRoleSystemNames instead.", null, "IsGuest");
     }
     if (context.DataSegmenter.HasColumn("IsRegistered"))
     {
         context.Result.AddInfo("Deprecated field. Use CustomerRoleSystemNames instead.", null, "IsRegistered");
     }
     if (context.DataSegmenter.HasColumn("IsAdministrator"))
     {
         context.Result.AddInfo("Deprecated field. Use CustomerRoleSystemNames instead.", null, "IsAdministrator");
     }
     if (context.DataSegmenter.HasColumn("IsForumModerator"))
     {
         context.Result.AddInfo("Deprecated field. Use CustomerRoleSystemNames instead.", null, "IsForumModerator");
     }
 }
        protected virtual int ProcessProductManufacturers(ImportExecuteContext context, IEnumerable <ImportRow <Product> > batch)
        {
            _productManufacturerRepository.AutoCommitEnabled = false;

            foreach (var row in batch)
            {
                var manufacturerIds = row.GetDataValue <List <int> >("ManufacturerIds");
                if (!manufacturerIds.IsNullOrEmpty())
                {
                    try
                    {
                        foreach (var id in manufacturerIds)
                        {
                            if (_productManufacturerRepository.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.ManufacturerId == id).FirstOrDefault() == null)
                            {
                                // ensure that manufacturer exists
                                var manufacturer = _manufacturerService.GetManufacturerById(id);
                                if (manufacturer != null)
                                {
                                    var productManufacturer = new ProductManufacturer
                                    {
                                        ProductId         = row.Entity.Id,
                                        ManufacturerId    = manufacturer.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder      = 1
                                    };
                                    _productManufacturerRepository.Insert(productManufacturer);
                                }
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddWarning(exception.Message, row.GetRowInfo(), "ManufacturerIds");
                    }
                }
            }

            // commit whole batch at once
            var num = _productManufacturerRepository.Context.SaveChanges();

            return(num);
        }
        protected virtual int ProcessLocalizations(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Category> > batch,
            string[] localizedProperties)
        {
            if (localizedProperties.Length == 0)
            {
                return(0);
            }

            bool shouldSave = false;

            foreach (var row in batch)
            {
                foreach (var prop in localizedProperties)
                {
                    var lambda = _localizableProperties[prop];
                    foreach (var lang in context.Languages)
                    {
                        var    code = lang.UniqueSeoCode;
                        string value;

                        if (row.TryGetDataValue(prop /* ColumnName */, code, out value))
                        {
                            _localizedEntityService.SaveLocalizedValue(row.Entity, lambda, value, lang.Id);
                            shouldSave = true;
                        }
                    }
                }
            }

            if (shouldSave)
            {
                // commit whole batch at once
                return(context.Services.DbContext.SaveChanges());
            }

            return(0);
        }
        protected virtual int ProcessProductMappings(
			ImportExecuteContext context,
			IEnumerable<ImportRow<Product>> batch,
			Dictionary<int, ImportProductMapping> srcToDestId)
        {
            _productRepository.AutoCommitEnabled = false;

            foreach (var row in batch)
            {
                var id = row.GetDataValue<int>("Id");
                var parentGroupedProductId = row.GetDataValue<int>("ParentGroupedProductId");

                if (id != 0 && parentGroupedProductId != 0 && srcToDestId.ContainsKey(id) && srcToDestId.ContainsKey(parentGroupedProductId))
                {
                    // only touch relationship if child and parent were inserted
                    if (srcToDestId[id].Inserted && srcToDestId[parentGroupedProductId].Inserted && srcToDestId[id].DestinationId != 0)
                    {
                        var product = _productRepository.GetById(srcToDestId[id].DestinationId);
                        if (product != null)
                        {
                            product.ParentGroupedProductId = srcToDestId[parentGroupedProductId].DestinationId;
                            _productRepository.Update(product);
                        }
                    }
                }
            }

            var num = _productRepository.Context.SaveChanges();

            return num;
        }
Exemple #14
0
        protected override void Import(ImportExecuteContext context)
        {
            var srcToDestId = new Dictionary <int, ImportProductMapping>();

            var templateViewPaths = _productTemplateService.GetAllProductTemplates().ToDictionarySafe(x => x.ViewPath, x => x.Id);

            using (var scope = new DbContextScope(ctx: _productRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false))
            {
                var segmenter = context.DataSegmenter;

                Initialize(context);

                while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                {
                    var batch = segmenter.GetCurrentBatch <Product>();

                    // Perf: detach all entities
                    _productRepository.Context.DetachAll(false);

                    context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows);

                    // ===========================================================================
                    // 1.) Import products
                    // ===========================================================================
                    try
                    {
                        ProcessProducts(context, batch, templateViewPaths, srcToDestId);
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProducts");
                    }

                    // reduce batch to saved (valid) products.
                    // No need to perform import operations on errored products.
                    batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray();

                    // update result object
                    context.Result.NewRecords      += batch.Count(x => x.IsNew && !x.IsTransient);
                    context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient);

                    // ===========================================================================
                    // 2.) Import SEO Slugs
                    // IMPORTANT: Unlike with Products AutoCommitEnabled must be TRUE,
                    //            as Slugs are going to be validated against existing ones in DB.
                    // ===========================================================================
                    if (segmenter.HasColumn("SeName", true) || batch.Any(x => x.IsNew || x.NameChanged))
                    {
                        try
                        {
                            _productRepository.Context.AutoDetectChangesEnabled = true;
                            ProcessSlugs(context, batch, typeof(Product).Name);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessSlugs");
                        }
                        finally
                        {
                            _productRepository.Context.AutoDetectChangesEnabled = false;
                        }
                    }

                    // ===========================================================================
                    // 3.) Import StoreMappings
                    // ===========================================================================
                    if (segmenter.HasColumn("StoreIds"))
                    {
                        try
                        {
                            ProcessStoreMappings(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessStoreMappings");
                        }
                    }

                    // ===========================================================================
                    // 4.) Import Localizations
                    // ===========================================================================
                    try
                    {
                        ProcessLocalizations(context, batch, _localizableProperties);
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessLocalizations");
                    }

                    // ===========================================================================
                    // 5.) Import product category mappings
                    // ===========================================================================
                    if (segmenter.HasColumn("CategoryIds"))
                    {
                        try
                        {
                            ProcessProductCategories(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductCategories");
                        }
                    }

                    // ===========================================================================
                    // 6.) Import product manufacturer mappings
                    // ===========================================================================
                    if (segmenter.HasColumn("ManufacturerIds"))
                    {
                        try
                        {
                            ProcessProductManufacturers(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductManufacturers");
                        }
                    }

                    // ===========================================================================
                    // 7.) Import product picture mappings
                    // ===========================================================================
                    if (segmenter.HasColumn("ImageUrls"))
                    {
                        try
                        {
                            ProcessProductPictures(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductPictures");
                        }
                    }
                }

                // ===========================================================================
                // 8.) Map parent id of inserted products
                // ===========================================================================
                if (srcToDestId.Any() && segmenter.HasColumn("Id") && segmenter.HasColumn("ParentGroupedProductId") && !segmenter.IsIgnored("ParentGroupedProductId"))
                {
                    segmenter.Reset();

                    while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                    {
                        var batch = segmenter.GetCurrentBatch <Product>();

                        _productRepository.Context.DetachAll(false);

                        try
                        {
                            ProcessProductMappings(context, batch, srcToDestId);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessParentMappings");
                        }
                    }
                }
            }
        }
Exemple #15
0
        protected virtual int ProcessPictures(ImportExecuteContext context, IEnumerable <ImportRow <Category> > batch)
        {
            var allFileIds = batch
                             .Where(row => row.HasDataValue("ImageUrl") && row.Entity.MediaFileId > 0)
                             .Select(row => row.Entity.MediaFileId.Value)
                             .Distinct()
                             .ToArray();

            var allFiles       = _mediaService.GetFilesByIds(allFileIds).ToDictionary(x => x.Id, x => x.File);
            var catalogAlbumId = _folderService.GetNodeByPath(SystemAlbumProvider.Catalog).Value.Id;

            foreach (var row in batch)
            {
                try
                {
                    var imageUrl = row.GetDataValue <string>("ImageUrl");
                    if (imageUrl.IsEmpty())
                    {
                        continue;
                    }

                    var image = CreateDownloadImage(context, imageUrl, 1);
                    if (image == null)
                    {
                        continue;
                    }

                    if (image.Url.HasValue() && !image.Success.HasValue)
                    {
                        AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, new FileDownloadManagerItem[] { image }));
                    }

                    if ((image.Success ?? false) && File.Exists(image.Path))
                    {
                        Succeeded(image);
                        using (var stream = File.OpenRead(image.Path))
                        {
                            if ((stream?.Length ?? 0) > 0)
                            {
                                var       assignedFile = allFiles.Get(row.Entity.MediaFileId ?? 0);
                                MediaFile sourceFile   = null;

                                if (assignedFile != null && _mediaService.FindEqualFile(stream, new[] { assignedFile }, true, out var _))
                                {
                                    context.Result.AddInfo($"Found equal image in data store for '{image.FileName}'. Skipping file.", row.GetRowInfo(), "ImageUrl");
                                }
                                else if (_mediaService.FindEqualFile(stream, image.FileName, catalogAlbumId, true, out sourceFile))
                                {
                                    context.Result.AddInfo($"Found equal image in catalog album for '{image.FileName}'. Assigning existing file instead.", row.GetRowInfo(), "ImageUrl");
                                }
                                else
                                {
                                    var path = _mediaService.CombinePaths(SystemAlbumProvider.Catalog, image.FileName);
                                    sourceFile = _mediaService.SaveFile(path, stream, false, DuplicateFileHandling.Rename)?.File;
                                }

                                if (sourceFile?.Id > 0)
                                {
                                    row.Entity.MediaFileId = sourceFile.Id;
                                    _categoryRepository.Update(row.Entity);
                                }
                            }
                        }
                    }
                    else if (image.Url.HasValue())
                    {
                        context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "ImageUrls");
                    }
                }
                catch (Exception ex)
                {
                    context.Result.AddWarning(ex.ToAllMessages(), row.GetRowInfo(), "ImageUrls");
                }
            }

            var num = _categoryRepository.Context.SaveChanges();

            return(num);
        }
Exemple #16
0
        protected virtual void ProcessProductPictures(ImportExecuteContext context, IEnumerable <ImportRow <Product> > batch)
        {
            // true, cause pictures must be saved and assigned an id prior adding a mapping.
            _productPictureRepository.AutoCommitEnabled = true;

            ProductPicture lastInserted     = null;
            var            equalPictureId   = 0;
            var            numberOfPictures = (context.ExtraData.NumberOfPictures ?? int.MaxValue);

            foreach (var row in batch)
            {
                var imageUrls = row.GetDataValue <List <string> >("ImageUrls");
                if (imageUrls.IsNullOrEmpty())
                {
                    continue;
                }

                var imageNumber  = 0;
                var displayOrder = -1;
                var seoName      = _pictureService.GetPictureSeName(row.EntityDisplayName);
                var imageFiles   = new List <FileDownloadManagerItem>();

                // collect required image file infos
                foreach (var urlOrPath in imageUrls)
                {
                    var image = CreateDownloadImage(urlOrPath, seoName, ++imageNumber);

                    if (image != null)
                    {
                        imageFiles.Add(image);
                    }

                    if (imageFiles.Count >= numberOfPictures)
                    {
                        break;
                    }
                }

                // download images
                if (imageFiles.Any(x => x.Url.HasValue()))
                {
                    // async downloading in batch processing is inefficient cause only the image processing benefits from async,
                    // not the record processing itself. a per record processing may speed up the import.

                    AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, imageFiles.Where(x => x.Url.HasValue() && !x.Success.HasValue)));
                }

                // import images
                foreach (var image in imageFiles.OrderBy(x => x.DisplayOrder))
                {
                    try
                    {
                        if ((image.Success ?? false) && File.Exists(image.Path))
                        {
                            Succeeded(image);
                            var pictureBinary = File.ReadAllBytes(image.Path);

                            if (pictureBinary != null && pictureBinary.Length > 0)
                            {
                                var currentProductPictures = _productPictureRepository.TableUntracked.Expand(x => x.Picture)
                                                             .Where(x => x.ProductId == row.Entity.Id)
                                                             .ToList();

                                var currentPictures = currentProductPictures
                                                      .Select(x => x.Picture)
                                                      .ToList();

                                if (displayOrder == -1)
                                {
                                    displayOrder = (currentProductPictures.Any() ? currentProductPictures.Select(x => x.DisplayOrder).Max() : 0);
                                }

                                var size = Size.Empty;
                                pictureBinary = _pictureService.ValidatePicture(pictureBinary, out size);
                                pictureBinary = _pictureService.FindEqualPicture(pictureBinary, currentPictures, out equalPictureId);

                                if (pictureBinary != null && pictureBinary.Length > 0)
                                {
                                    // no equal picture found in sequence
                                    var newPicture = _pictureService.InsertPicture(pictureBinary, image.MimeType, seoName, true, size.Width, size.Height, false);
                                    if (newPicture != null)
                                    {
                                        var mapping = new ProductPicture
                                        {
                                            ProductId    = row.Entity.Id,
                                            PictureId    = newPicture.Id,
                                            DisplayOrder = ++displayOrder
                                        };

                                        _productPictureRepository.Insert(mapping);
                                        lastInserted = mapping;
                                    }
                                }
                                else
                                {
                                    context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString());
                                }
                            }
                        }
                        else if (image.Url.HasValue())
                        {
                            context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString());
                        }
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddWarning(exception.ToAllMessages(), row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString());
                    }
                }
            }

            // Perf: notify only about LAST insertion and update
            if (lastInserted != null)
            {
                _services.EventPublisher.EntityInserted(lastInserted);
            }
        }
        protected virtual void ProcessProductPictures(ImportExecuteContext context, IEnumerable<ImportRow<Product>> batch)
        {
            // true, cause pictures must be saved and assigned an id prior adding a mapping.
            _productPictureRepository.AutoCommitEnabled = true;

            ProductPicture lastInserted = null;
            var equalPictureId = 0;
            var numberOfPictures = (context.ExtraData.NumberOfPictures ?? int.MaxValue);

            foreach (var row in batch)
            {
                var imageUrls = row.GetDataValue<List<string>>("ImageUrls");
                if (imageUrls.IsNullOrEmpty())
                    continue;

                var imageNumber = 0;
                var displayOrder = -1;
                var seoName = _pictureService.GetPictureSeName(row.EntityDisplayName);
                var imageFiles = new List<FileDownloadManagerItem>();

                // collect required image file infos
                foreach (var urlOrPath in imageUrls)
                {
                    var image = CreateDownloadImage(urlOrPath, seoName, ++imageNumber);

                    if (image != null)
                        imageFiles.Add(image);

                    if (imageFiles.Count >= numberOfPictures)
                        break;
                }

                // download images
                if (imageFiles.Any(x => x.Url.HasValue()))
                {
                    // async downloading in batch processing is inefficient cause only the image processing benefits from async,
                    // not the record processing itself. a per record processing may speed up the import.

                    AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, imageFiles.Where(x => x.Url.HasValue() && !x.Success.HasValue)));
                }

                // import images
                foreach (var image in imageFiles.OrderBy(x => x.DisplayOrder))
                {
                    try
                    {
                        if ((image.Success ?? false) && File.Exists(image.Path))
                        {
                            Succeeded(image);
                            var pictureBinary = File.ReadAllBytes(image.Path);

                            if (pictureBinary != null && pictureBinary.Length > 0)
                            {
                                var currentProductPictures = _productPictureRepository.TableUntracked.Expand(x => x.Picture)
                                    .Where(x => x.ProductId == row.Entity.Id)
                                    .ToList();

                                var currentPictures = currentProductPictures
                                    .Select(x => x.Picture)
                                    .ToList();

                                if (displayOrder == -1)
                                {
                                    displayOrder = (currentProductPictures.Any() ? currentProductPictures.Select(x => x.DisplayOrder).Max() : 0);
                                }

                                pictureBinary = _pictureService.ValidatePicture(pictureBinary);
                                pictureBinary = _pictureService.FindEqualPicture(pictureBinary, currentPictures, out equalPictureId);

                                if (pictureBinary != null && pictureBinary.Length > 0)
                                {
                                    // no equal picture found in sequence
                                    var newPicture = _pictureService.InsertPicture(pictureBinary, image.MimeType, seoName, true, false, false);
                                    if (newPicture != null)
                                    {
                                        var mapping = new ProductPicture
                                        {
                                            ProductId = row.Entity.Id,
                                            PictureId = newPicture.Id,
                                            DisplayOrder = ++displayOrder
                                        };

                                        _productPictureRepository.Insert(mapping);
                                        lastInserted = mapping;
                                    }
                                }
                                else
                                {
                                    context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString());
                                }
                            }
                        }
                        else if (image.Url.HasValue())
                        {
                            context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString());
                        }
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddWarning(exception.ToAllMessages(), row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString());
                    }
                }
            }

            // Perf: notify only about LAST insertion and update
            if (lastInserted != null)
            {
                _services.EventPublisher.EntityInserted(lastInserted);
            }
        }
Exemple #18
0
        protected virtual int ProcessCustomers(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Customer> > batch,
            List <int> allAffiliateIds)
        {
            _customerRepository.AutoCommitEnabled = true;

            Customer lastInserted               = null;
            Customer lastUpdated                = null;
            var      currentCustomer            = _services.WorkContext.CurrentCustomer;
            var      customerQuery              = _customerRepository.Table.Expand(x => x.Addresses);
            var      hasCustomerRoleSystemNames = context.DataSegmenter.HasColumn("CustomerRoleSystemNames");

            foreach (var row in batch)
            {
                Customer customer = null;
                var      id       = row.GetDataValue <int>("Id");
                var      email    = row.GetDataValue <string>("Email");

                foreach (var keyName in context.KeyFieldNames)
                {
                    switch (keyName)
                    {
                    case "Id":
                        if (id != 0)
                        {
                            customer = customerQuery.FirstOrDefault(x => x.Id == id);
                        }
                        break;

                    case "CustomerGuid":
                        var customerGuid = row.GetDataValue <string>("CustomerGuid");
                        if (customerGuid.HasValue())
                        {
                            var guid = new Guid(customerGuid);
                            customer = customerQuery.FirstOrDefault(x => x.CustomerGuid == guid);
                        }
                        break;

                    case "Email":
                        if (email.HasValue())
                        {
                            customer = customerQuery.FirstOrDefault(x => x.Email == email);
                        }
                        break;

                    case "Username":
                        var userName = row.GetDataValue <string>("Username");
                        if (userName.HasValue())
                        {
                            customer = customerQuery.FirstOrDefault(x => x.Username == userName);
                        }
                        break;
                    }

                    if (customer != null)
                    {
                        break;
                    }
                }

                if (customer == null)
                {
                    if (context.UpdateOnly)
                    {
                        ++context.Result.SkippedRecords;
                        continue;
                    }

                    customer = new Customer
                    {
                        CustomerGuid = new Guid(),
                        AffiliateId  = 0,
                        Active       = true
                    };
                }
                else
                {
                    _customerRepository.Context.LoadCollection(customer, (Customer x) => x.CustomerRoles);
                }

                var affiliateId = row.GetDataValue <int>("AffiliateId");

                row.Initialize(customer, email ?? id.ToString());

                row.SetProperty(context.Result, (x) => x.CustomerGuid);
                row.SetProperty(context.Result, (x) => x.Username);
                row.SetProperty(context.Result, (x) => x.Email);

                if (email.HasValue() && currentCustomer.Email.IsCaseInsensitiveEqual(email))
                {
                    context.Result.AddInfo("Security. Ignored password of current customer (who started this import).", row.GetRowInfo(), "Password");
                }
                else
                {
                    row.SetProperty(context.Result, (x) => x.Password);
                    row.SetProperty(context.Result, (x) => x.PasswordFormatId);
                    row.SetProperty(context.Result, (x) => x.PasswordSalt);
                }

                row.SetProperty(context.Result, (x) => x.AdminComment);
                row.SetProperty(context.Result, (x) => x.IsTaxExempt);
                row.SetProperty(context.Result, (x) => x.Active);

                row.SetProperty(context.Result, (x) => x.CreatedOnUtc, UtcNow);
                row.SetProperty(context.Result, (x) => x.LastActivityDateUtc, UtcNow);

                if (affiliateId > 0 && allAffiliateIds.Contains(affiliateId))
                {
                    customer.AffiliateId = affiliateId;
                }

                if (row.IsTransient)
                {
                    _customerRepository.Insert(customer);
                    lastInserted = customer;
                }
                else
                {
                    _customerRepository.Update(customer);
                    lastUpdated = customer;
                }
            }

            var num = _customerRepository.Context.SaveChanges();

            if (lastInserted != null)
            {
                _services.EventPublisher.EntityInserted(lastInserted);
            }

            if (lastUpdated != null)
            {
                _services.EventPublisher.EntityUpdated(lastUpdated);
            }

            return(num);
        }
        protected virtual int ProcessProducts(
			ImportExecuteContext context,
			IEnumerable<ImportRow<Product>> batch,
			Dictionary<string, int> templateViewPaths,
			Dictionary<int, ImportProductMapping> srcToDestId)
        {
            _productRepository.AutoCommitEnabled = false;

            Product lastInserted = null;
            Product lastUpdated = null;
            var defaultTemplateId = templateViewPaths["ProductTemplate.Simple"];

            foreach (var row in batch)
            {
                Product product = null;
                var id = row.GetDataValue<int>("Id");

                foreach (var keyName in context.KeyFieldNames)
                {
                    var keyValue = row.GetDataValue<string>(keyName);

                    if (keyValue.HasValue() || id > 0)
                    {
                        switch (keyName)
                        {
                            case "Id":
                                product = _productService.GetProductById(id);
                                break;
                            case "Sku":
                                product = _productService.GetProductBySku(keyValue);
                                break;
                            case "Gtin":
                                product = _productService.GetProductByGtin(keyValue);
                                break;
                            case "ManufacturerPartNumber":
                                product = _productService.GetProductByManufacturerPartNumber(keyValue);
                                break;
                            case "Name":
                                product = _productService.GetProductByName(keyValue);
                                break;
                        }
                    }

                    if (product != null)
                        break;
                }

                if (product == null)
                {
                    if (context.UpdateOnly)
                    {
                        ++context.Result.SkippedRecords;
                        continue;
                    }

                    // a Name is required for new products.
                    if (!row.HasDataValue("Name"))
                    {
                        ++context.Result.SkippedRecords;
                        context.Result.AddError("The 'Name' field is required for new products. Skipping row.", row.GetRowInfo(), "Name");
                        continue;
                    }

                    product = new Product();
                }

                var name = row.GetDataValue<string>("Name");

                row.Initialize(product, name ?? product.Name);

                if (!row.IsNew)
                {
                    if (!product.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
                    {
                        // Perf: use this later for SeName updates.
                        row.NameChanged = true;
                    }
                }

                row.SetProperty(context.Result, (x) => x.ProductTypeId, (int)ProductType.SimpleProduct);
                row.SetProperty(context.Result, (x) => x.VisibleIndividually, true);
                row.SetProperty(context.Result, (x) => x.Name);
                row.SetProperty(context.Result, (x) => x.ShortDescription);
                row.SetProperty(context.Result, (x) => x.FullDescription);
                row.SetProperty(context.Result, (x) => x.AdminComment);
                row.SetProperty(context.Result, (x) => x.ShowOnHomePage);
                row.SetProperty(context.Result, (x) => x.HomePageDisplayOrder);
                row.SetProperty(context.Result, (x) => x.MetaKeywords);
                row.SetProperty(context.Result, (x) => x.MetaDescription);
                row.SetProperty(context.Result, (x) => x.MetaTitle);
                row.SetProperty(context.Result, (x) => x.AllowCustomerReviews, true);
                row.SetProperty(context.Result, (x) => x.ApprovedRatingSum);
                row.SetProperty(context.Result, (x) => x.NotApprovedRatingSum);
                row.SetProperty(context.Result, (x) => x.ApprovedTotalReviews);
                row.SetProperty(context.Result, (x) => x.NotApprovedTotalReviews);
                row.SetProperty(context.Result, (x) => x.Published, true);
                row.SetProperty(context.Result, (x) => x.Sku);
                row.SetProperty(context.Result, (x) => x.ManufacturerPartNumber);
                row.SetProperty(context.Result, (x) => x.Gtin);
                row.SetProperty(context.Result, (x) => x.IsGiftCard);
                row.SetProperty(context.Result, (x) => x.GiftCardTypeId);
                row.SetProperty(context.Result, (x) => x.RequireOtherProducts);
                row.SetProperty(context.Result, (x) => x.RequiredProductIds);	// TODO: global scope
                row.SetProperty(context.Result, (x) => x.AutomaticallyAddRequiredProducts);
                row.SetProperty(context.Result, (x) => x.IsDownload);
                row.SetProperty(context.Result, (x) => x.DownloadId);
                row.SetProperty(context.Result, (x) => x.UnlimitedDownloads, true);
                row.SetProperty(context.Result, (x) => x.MaxNumberOfDownloads, 10);
                row.SetProperty(context.Result, (x) => x.DownloadExpirationDays);
                row.SetProperty(context.Result, (x) => x.DownloadActivationTypeId, 1);
                row.SetProperty(context.Result, (x) => x.HasSampleDownload);
                row.SetProperty(context.Result, (x) => x.SampleDownloadId, (int?)null, ZeroToNull);    // TODO: global scope
                row.SetProperty(context.Result, (x) => x.HasUserAgreement);
                row.SetProperty(context.Result, (x) => x.UserAgreementText);
                row.SetProperty(context.Result, (x) => x.IsRecurring);
                row.SetProperty(context.Result, (x) => x.RecurringCycleLength, 100);
                row.SetProperty(context.Result, (x) => x.RecurringCyclePeriodId);
                row.SetProperty(context.Result, (x) => x.RecurringTotalCycles, 10);
                row.SetProperty(context.Result, (x) => x.IsShipEnabled, true);
                row.SetProperty(context.Result, (x) => x.IsFreeShipping);
                row.SetProperty(context.Result, (x) => x.AdditionalShippingCharge);
                row.SetProperty(context.Result, (x) => x.IsEsd);
                row.SetProperty(context.Result, (x) => x.IsTaxExempt);
                row.SetProperty(context.Result, (x) => x.TaxCategoryId, 1);    // TODO: global scope
                row.SetProperty(context.Result, (x) => x.ManageInventoryMethodId);
                row.SetProperty(context.Result, (x) => x.StockQuantity, 10000);
                row.SetProperty(context.Result, (x) => x.DisplayStockAvailability);
                row.SetProperty(context.Result, (x) => x.DisplayStockQuantity);
                row.SetProperty(context.Result, (x) => x.MinStockQuantity);
                row.SetProperty(context.Result, (x) => x.LowStockActivityId);
                row.SetProperty(context.Result, (x) => x.NotifyAdminForQuantityBelow, 1);
                row.SetProperty(context.Result, (x) => x.BackorderModeId);
                row.SetProperty(context.Result, (x) => x.AllowBackInStockSubscriptions);
                row.SetProperty(context.Result, (x) => x.OrderMinimumQuantity, 1);
                row.SetProperty(context.Result, (x) => x.OrderMaximumQuantity, 10000);
                row.SetProperty(context.Result, (x) => x.AllowedQuantities);
                row.SetProperty(context.Result, (x) => x.DisableBuyButton);
                row.SetProperty(context.Result, (x) => x.DisableWishlistButton);
                row.SetProperty(context.Result, (x) => x.AvailableForPreOrder);
                row.SetProperty(context.Result, (x) => x.CallForPrice);
                row.SetProperty(context.Result, (x) => x.Price);
                row.SetProperty(context.Result, (x) => x.OldPrice);
                row.SetProperty(context.Result, (x) => x.ProductCost);
                row.SetProperty(context.Result, (x) => x.SpecialPrice);
                row.SetProperty(context.Result, (x) => x.SpecialPriceStartDateTimeUtc);
                row.SetProperty(context.Result, (x) => x.SpecialPriceEndDateTimeUtc);
                row.SetProperty(context.Result, (x) => x.CustomerEntersPrice);
                row.SetProperty(context.Result, (x) => x.MinimumCustomerEnteredPrice);
                row.SetProperty(context.Result, (x) => x.MaximumCustomerEnteredPrice, 1000);
                // HasTierPrices... ignore as long as no tier prices are imported
                // LowestAttributeCombinationPrice... ignore as long as no combinations are imported
                row.SetProperty(context.Result, (x) => x.Weight);
                row.SetProperty(context.Result, (x) => x.Length);
                row.SetProperty(context.Result, (x) => x.Width);
                row.SetProperty(context.Result, (x) => x.Height);
                row.SetProperty(context.Result, (x) => x.DisplayOrder);
                row.SetProperty(context.Result, (x) => x.DeliveryTimeId);      // TODO: global scope
                row.SetProperty(context.Result, (x) => x.QuantityUnitId);      // TODO: global scope
                row.SetProperty(context.Result, (x) => x.BasePriceEnabled);
                row.SetProperty(context.Result, (x) => x.BasePriceMeasureUnit);
                row.SetProperty(context.Result, (x) => x.BasePriceAmount);
                row.SetProperty(context.Result, (x) => x.BasePriceBaseAmount);
                row.SetProperty(context.Result, (x) => x.BundleTitleText);
                row.SetProperty(context.Result, (x) => x.BundlePerItemShipping);
                row.SetProperty(context.Result, (x) => x.BundlePerItemPricing);
                row.SetProperty(context.Result, (x) => x.BundlePerItemShoppingCart);
                row.SetProperty(context.Result, (x) => x.AvailableStartDateTimeUtc);
                row.SetProperty(context.Result, (x) => x.AvailableEndDateTimeUtc);
                // With new entities, "LimitedToStores" is an implicit field, meaning
                // it has to be set to true by code if it's absent but "StoreIds" exists.
                row.SetProperty(context.Result, (x) => x.LimitedToStores, !row.GetDataValue<List<int>>("StoreIds").IsNullOrEmpty());

                string tvp;
                if (row.TryGetDataValue("ProductTemplateViewPath", out tvp, row.IsTransient))
                {
                    product.ProductTemplateId = (tvp.HasValue() && templateViewPaths.ContainsKey(tvp) ? templateViewPaths[tvp] : defaultTemplateId);
                }

                row.SetProperty(context.Result, (x) => x.CreatedOnUtc, UtcNow);
                product.UpdatedOnUtc = UtcNow;

                if (id != 0 && !srcToDestId.ContainsKey(id))
                {
                    srcToDestId.Add(id, new ImportProductMapping { Inserted = row.IsTransient });
                }

                if (row.IsTransient)
                {
                    _productRepository.Insert(product);
                    lastInserted = product;
                }
                else
                {
                    _productRepository.Update(product);
                    lastUpdated = product;
                }
            }

            // commit whole batch at once
            var num = _productRepository.Context.SaveChanges();

            // get new product ids
            foreach (var row in batch)
            {
                var id = row.GetDataValue<int>("Id");

                if (id != 0 && srcToDestId.ContainsKey(id))
                    srcToDestId[id].DestinationId = row.Entity.Id;
            }

            // Perf: notify only about LAST insertion and update
            if (lastInserted != null)
            {
                _services.EventPublisher.EntityInserted(lastInserted);
            }

            if (lastUpdated != null)
            {
                _services.EventPublisher.EntityUpdated(lastUpdated);
            }

            return num;
        }
Exemple #20
0
        protected override void Import(ImportExecuteContext context)
        {
            var customer = _services.WorkContext.CurrentCustomer;
            var allowManagingCustomerRoles = _services.Permissions.Authorize(StandardPermissionProvider.ManageCustomerRoles, customer);

            var allAffiliateIds = _affiliateService.GetAllAffiliates(true)
                                  .Select(x => x.Id)
                                  .ToList();

            var allCountries = new Dictionary <string, int>();

            foreach (var country in _countryService.GetAllCountries(true))
            {
                if (!allCountries.ContainsKey(country.TwoLetterIsoCode))
                {
                    allCountries.Add(country.TwoLetterIsoCode, country.Id);
                }

                if (!allCountries.ContainsKey(country.ThreeLetterIsoCode))
                {
                    allCountries.Add(country.ThreeLetterIsoCode, country.Id);
                }
            }

            var allStateProvinces = _stateProvinceService.GetAllStateProvinces(true)
                                    .ToDictionarySafe(x => new Tuple <int, string>(x.CountryId, x.Abbreviation), x => x.Id);

            var allCustomerNumbers = new HashSet <string>(
                _genericAttributeService.GetAttributes(SystemCustomerAttributeNames.CustomerNumber, _attributeKeyGroup).Select(x => x.Value),
                StringComparer.OrdinalIgnoreCase);

            var allCustomerRoles = _customerRoleRepository.Table.ToDictionarySafe(x => x.SystemName, StringComparer.OrdinalIgnoreCase);

            using (var scope = new DbContextScope(ctx: _services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                var segmenter = context.DataSegmenter;

                Initialize(context);
                AddInfoForDeprecatedFields(context);

                while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                {
                    var batch = segmenter.GetCurrentBatch <Customer>();

                    _customerRepository.Context.DetachAll(true);

                    context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows);

                    // ===========================================================================
                    // Process customers
                    // ===========================================================================
                    try
                    {
                        ProcessCustomers(context, batch, allAffiliateIds);
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessCustomers");
                    }

                    // reduce batch to saved (valid) records.
                    // No need to perform import operations on errored records.
                    batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray();

                    // update result object
                    context.Result.NewRecords      += batch.Count(x => x.IsNew && !x.IsTransient);
                    context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient);

                    // ===========================================================================
                    // Process customer roles
                    // ===========================================================================
                    try
                    {
                        _customerRepository.Context.AutoDetectChangesEnabled = true;
                        ProcessCustomerRoles(context, batch, allCustomerRoles);
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessCustomerRoles");
                    }
                    finally
                    {
                        _customerRepository.Context.AutoDetectChangesEnabled = false;
                    }

                    // ===========================================================================
                    // Process generic attributes
                    // ===========================================================================
                    try
                    {
                        ProcessGenericAttributes(context, batch, allCountries, allStateProvinces, allCustomerNumbers);
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessGenericAttributes");
                    }

                    // ===========================================================================
                    // Process avatars
                    // ===========================================================================
                    if (_customerSettings.AllowCustomersToUploadAvatars)
                    {
                        try
                        {
                            ProcessAvatars(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessAvatars");
                        }
                    }

                    // ===========================================================================
                    // Process addresses
                    // ===========================================================================
                    try
                    {
                        _services.DbContext.AutoDetectChangesEnabled = true;
                        ProcessAddresses(context, batch, allCountries, allStateProvinces);
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessAddresses");
                    }
                    finally
                    {
                        _services.DbContext.AutoDetectChangesEnabled = false;
                    }
                }
            }
        }
        public void Execute(ImportExecuteContext context)
        {
            var utcNow = DateTime.UtcNow;
            var currentStoreId = _services.StoreContext.CurrentStore.Id;

            using (var scope = new DbContextScope(ctx: _services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                var segmenter = context.DataSegmenter;

                context.Result.TotalRecords = segmenter.TotalRows;

                while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                {
                    var batch = segmenter.GetCurrentBatch<NewsLetterSubscription>();

                    // Perf: detach all entities
                    _subscriptionRepository.Context.DetachEntities<NewsLetterSubscription>(false);

                    context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows);

                    foreach (var row in batch)
                    {
                        try
                        {
                            var active = true;
                            var email = row.GetDataValue<string>("Email");
                            var storeId = row.GetDataValue<int>("StoreId");

                            if (storeId == 0)
                            {
                                storeId = currentStoreId;
                            }

                            if (row.HasDataValue("Active") && row.TryGetDataValue("Active", out active))
                            {
                            }
                            else
                            {
                                active = true;	// default
                            }

                            if (email.IsEmpty())
                            {
                                context.Result.AddWarning("Skipped empty email address", row.GetRowInfo(), "Email");
                                continue;
                            }

                            if (email.Length > 255)
                            {
                                context.Result.AddWarning("Skipped email address '{0}'. It exceeds the maximum allowed length of 255".FormatInvariant(email), row.GetRowInfo(), "Email");
                                continue;
                            }

                            if (!email.IsEmail())
                            {
                                context.Result.AddWarning("Skipped invalid email address '{0}'".FormatInvariant(email), row.GetRowInfo(), "Email");
                                continue;
                            }

                            NewsLetterSubscription subscription = null;

                            foreach (var keyName in context.KeyFieldNames)
                            {
                                switch (keyName)
                                {
                                    case "Email":
                                        subscription = _subscriptionRepository.Table
                                            .OrderBy(x => x.Id)
                                            .FirstOrDefault(x => x.Email == email && x.StoreId == storeId);
                                        break;
                                }

                                if (subscription != null)
                                    break;
                            }

                            if (subscription == null)
                            {
                                if (context.UpdateOnly)
                                {
                                    ++context.Result.SkippedRecords;
                                    continue;
                                }

                                subscription = new NewsLetterSubscription
                                {
                                    Active = active,
                                    CreatedOnUtc = utcNow,
                                    Email = email,
                                    NewsLetterSubscriptionGuid = Guid.NewGuid(),
                                    StoreId = storeId
                                };

                                _subscriptionRepository.Insert(subscription);
                                context.Result.NewRecords++;
                            }
                            else
                            {
                                subscription.Active = active;

                                _subscriptionRepository.Update(subscription);
                                context.Result.ModifiedRecords++;
                            }
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception.ToAllMessages(), row.GetRowInfo());
                        }
                    } // for

                    _subscriptionRepository.Context.SaveChanges();
                } // while
            }
        }
        protected override void Import(ImportExecuteContext context)
        {
            var srcToDestId = new Dictionary <int, ImportCategoryMapping>();

            var templateViewPaths = _categoryTemplateService.GetAllCategoryTemplates().ToDictionarySafe(x => x.ViewPath, x => x.Id);

            using (var scope = new DbContextScope(ctx: context.Services.DbContext, hooksEnabled: false, autoDetectChanges: false, proxyCreation: false, validateOnSave: false))
            {
                var segmenter = context.DataSegmenter;

                Initialize(context);

                while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                {
                    var batch = segmenter.GetCurrentBatch <Category>();

                    // Perf: detach all entities
                    _categoryRepository.Context.DetachAll(true);

                    context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows);

                    try
                    {
                        ProcessCategories(context, batch, templateViewPaths, srcToDestId);
                    }
                    catch (Exception ex)
                    {
                        context.Result.AddError(ex, segmenter.CurrentSegment, "ProcessCategories");
                    }

                    // Reduce batch to saved (valid) products.
                    // No need to perform import operations on errored products.
                    batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray();

                    // Update result object.
                    context.Result.NewRecords      += batch.Count(x => x.IsNew && !x.IsTransient);
                    context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient);

                    // Process slugs.
                    if (segmenter.HasColumn("SeName", true) || batch.Any(x => x.IsNew || x.NameChanged))
                    {
                        try
                        {
                            _categoryRepository.Context.AutoDetectChangesEnabled = true;
                            ProcessSlugs(context, batch, typeof(Category).Name);
                        }
                        catch (Exception ex)
                        {
                            context.Result.AddError(ex, segmenter.CurrentSegment, "ProcessSlugs");
                        }
                        finally
                        {
                            _categoryRepository.Context.AutoDetectChangesEnabled = false;
                        }
                    }

                    // Process store mappings.
                    if (segmenter.HasColumn("StoreIds"))
                    {
                        try
                        {
                            ProcessStoreMappings(context, batch);
                        }
                        catch (Exception ex)
                        {
                            context.Result.AddError(ex, segmenter.CurrentSegment, "ProcessStoreMappings");
                        }
                    }

                    // Localizations.
                    try
                    {
                        ProcessLocalizations(context, batch, _localizableProperties);
                    }
                    catch (Exception ex)
                    {
                        context.Result.AddError(ex, segmenter.CurrentSegment, "ProcessLocalizedProperties");
                    }

                    // Process pictures.
                    if (segmenter.HasColumn("ImageUrl") && !segmenter.IsIgnored("PictureId"))
                    {
                        try
                        {
                            _categoryRepository.Context.AutoDetectChangesEnabled = true;
                            ProcessPictures(context, batch);
                        }
                        catch (Exception ex)
                        {
                            context.Result.AddError(ex, segmenter.CurrentSegment, "ProcessPictures");
                        }
                        finally
                        {
                            _categoryRepository.Context.AutoDetectChangesEnabled = false;
                        }
                    }

                    context.Services.EventPublisher.Publish(new ImportBatchExecutedEvent <Category>(context, batch));
                }

                // Map parent id of inserted categories.
                if (srcToDestId.Any() && segmenter.HasColumn("Id") && segmenter.HasColumn("ParentCategoryId") && !segmenter.IsIgnored("ParentCategoryId"))
                {
                    segmenter.Reset();

                    while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                    {
                        var batch = segmenter.GetCurrentBatch <Category>();
                        _categoryRepository.Context.DetachAll(unchangedEntitiesOnly: false);

                        try
                        {
                            ProcessParentMappings(context, batch, srcToDestId);
                        }
                        catch (Exception ex)
                        {
                            context.Result.AddError(ex, segmenter.CurrentSegment, "ProcessParentMappings");
                        }
                    }
                }
            }
        }
        protected virtual int ProcessProductManufacturers(ImportExecuteContext context, IEnumerable<ImportRow<Product>> batch)
        {
            _productManufacturerRepository.AutoCommitEnabled = false;

            ProductManufacturer lastInserted = null;

            foreach (var row in batch)
            {
                var manufacturerIds = row.GetDataValue<List<int>>("ManufacturerIds");
                if (!manufacturerIds.IsNullOrEmpty())
                {
                    try
                    {
                        foreach (var id in manufacturerIds)
                        {
                            if (_productManufacturerRepository.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.ManufacturerId == id).FirstOrDefault() == null)
                            {
                                // ensure that manufacturer exists
                                var manufacturer = _manufacturerService.GetManufacturerById(id);
                                if (manufacturer != null)
                                {
                                    var productManufacturer = new ProductManufacturer
                                    {
                                        ProductId = row.Entity.Id,
                                        ManufacturerId = manufacturer.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _productManufacturerRepository.Insert(productManufacturer);
                                    lastInserted = productManufacturer;
                                }
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddWarning(exception.Message, row.GetRowInfo(), "ManufacturerIds");
                    }
                }
            }

            // commit whole batch at once
            var num = _productManufacturerRepository.Context.SaveChanges();

            // Perf: notify only about LAST insertion and update
            if (lastInserted != null)
                _services.EventPublisher.EntityInserted(lastInserted);

            return num;
        }
        protected virtual int ProcessPictures(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Category> > batch)
        {
            foreach (var row in batch)
            {
                try
                {
                    var srcId    = row.GetDataValue <int>("Id");
                    var imageUrl = row.GetDataValue <string>("ImageUrl");
                    if (imageUrl.IsEmpty())
                    {
                        continue;
                    }

                    var image = CreateDownloadImage(context, imageUrl, 1);
                    if (image.Url.HasValue() && !image.Success.HasValue)
                    {
                        AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, new FileDownloadManagerItem[] { image }));
                    }

                    if ((image.Success ?? false) && File.Exists(image.Path))
                    {
                        Succeeded(image);
                        using (var stream = File.OpenRead(image.Path))
                        {
                            if ((stream?.Length ?? 0) > 0)
                            {
                                var currentFiles = new List <MediaFileInfo>();
                                var file         = _mediaService.GetFileById(row.Entity.MediaFileId ?? 0, MediaLoadFlags.AsNoTracking);
                                if (file != null)
                                {
                                    currentFiles.Add(file);
                                }

                                if (!_mediaService.FindEqualFile(stream, currentFiles.Select(x => x.File), true, out var _))
                                {
                                    var path    = _mediaService.CombinePaths(SystemAlbumProvider.Catalog, image.FileName.ToValidFileName());
                                    var newFile = _mediaService.SaveFile(path, stream, false, DuplicateFileHandling.Rename);
                                    if ((newFile?.Id ?? 0) != 0)
                                    {
                                        row.Entity.MediaFileId = newFile.Id;
                                        _categoryRepository.Update(row.Entity);
                                    }
                                }
                                else
                                {
                                    context.Result.AddInfo("Found equal image in data store. Skipping field.", row.GetRowInfo(), "ImageUrls");
                                }
                            }
                        }
                    }
                    else if (image.Url.HasValue())
                    {
                        context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "ImageUrls");
                    }
                }
                catch (Exception ex)
                {
                    context.Result.AddWarning(ex.ToAllMessages(), row.GetRowInfo(), "ImageUrls");
                }
            }

            var num = _categoryRepository.Context.SaveChanges();

            return(num);
        }
        protected virtual int ProcessPictures(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Category> > batch)
        {
            foreach (var row in batch)
            {
                try
                {
                    var srcId    = row.GetDataValue <int>("Id");
                    var imageUrl = row.GetDataValue <string>("ImageUrl");
                    if (imageUrl.IsEmpty())
                    {
                        continue;
                    }

                    var seoName = _pictureService.GetPictureSeName(row.EntityDisplayName);
                    var image   = CreateDownloadImage(context, imageUrl, seoName, 1);

                    if (image.Url.HasValue() && !image.Success.HasValue)
                    {
                        AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, new FileDownloadManagerItem[] { image }));
                    }

                    if ((image.Success ?? false) && File.Exists(image.Path))
                    {
                        Succeeded(image);
                        var pictureBinary = File.ReadAllBytes(image.Path);

                        if (pictureBinary != null && pictureBinary.Length > 0)
                        {
                            var currentPictures = new List <MediaFile>();
                            var pictureId       = row.Entity.MediaFileId ?? 0;
                            if (pictureId != 0)
                            {
                                var picture = _pictureRepository.TableUntracked.Expand(x => x.MediaStorage).FirstOrDefault(x => x.Id == pictureId);
                                if (picture != null)
                                {
                                    currentPictures.Add(picture);
                                }
                            }

                            pictureBinary = _pictureService.FindEqualPicture(pictureBinary, currentPictures, out var equalPictureId);

                            if (pictureBinary != null && pictureBinary.Length > 0)
                            {
                                var picture = _pictureService.InsertPicture(pictureBinary, image.MimeType, seoName, false, false, "category");
                                if (picture != null)
                                {
                                    row.Entity.MediaFileId = picture.Id;
                                    _categoryRepository.Update(row.Entity);
                                }
                            }
                            else
                            {
                                context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "ImageUrls");
                            }
                        }
                    }
                    else if (image.Url.HasValue())
                    {
                        context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "ImageUrls");
                    }
                }
                catch (Exception ex)
                {
                    context.Result.AddWarning(ex.ToAllMessages(), row.GetRowInfo(), "ImageUrls");
                }
            }

            var num = _categoryRepository.Context.SaveChanges();

            return(num);
        }
Exemple #26
0
        protected virtual int ProcessCustomerRoles(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Customer> > batch,
            Dictionary <string, CustomerRole> allCustomerRoles)
        {
            CustomerRole role = null;
            var          hasCustomerRoleSystemNames = context.DataSegmenter.HasColumn("CustomerRoleSystemNames");

            // Deprecated fields. Still processed for backward compatibility. Use "CustomerRoleSystemNames" instead.
            var hasIsGuest          = context.DataSegmenter.HasColumn("IsGuest");
            var hasIsRegistered     = context.DataSegmenter.HasColumn("IsRegistered");
            var hasIsForumModerator = context.DataSegmenter.HasColumn("IsForumModerator");

            foreach (var row in batch)
            {
                var customer = row.Entity;

                // Deprecated customer role fields.
                if (hasIsGuest)
                {
                    UpsertRole(customer, row.GetDataValue <bool>("IsGuest"), allCustomerRoles, SystemCustomerRoleNames.Guests);
                }
                if (hasIsRegistered)
                {
                    UpsertRole(customer, row.GetDataValue <bool>("IsRegistered"), allCustomerRoles, SystemCustomerRoleNames.Registered);
                }
                if (hasIsForumModerator)
                {
                    UpsertRole(customer, row.GetDataValue <bool>("IsForumModerator"), allCustomerRoles, SystemCustomerRoleNames.ForumModerators);
                }

                // New customer role field.
                if (hasCustomerRoleSystemNames)
                {
                    var importRoleSystemNames = row.GetDataValue <List <string> >("CustomerRoleSystemNames");
                    var assignedRoles         = customer.CustomerRoles.ToDictionarySafe(x => x.SystemName, StringComparer.OrdinalIgnoreCase);

                    // Roles to remove.
                    foreach (var customerRole in assignedRoles)
                    {
                        var systemName = customerRole.Key;
                        if (!systemName.IsCaseInsensitiveEqual(SystemCustomerRoleNames.Administrators) &&
                            !systemName.IsCaseInsensitiveEqual(SystemCustomerRoleNames.SuperAdministrators) &&
                            !importRoleSystemNames.Contains(systemName))
                        {
                            customer.CustomerRoles.Remove(customerRole.Value);
                        }
                    }

                    // Roles to add.
                    foreach (var systemName in importRoleSystemNames)
                    {
                        if (systemName.IsCaseInsensitiveEqual(SystemCustomerRoleNames.Administrators) ||
                            systemName.IsCaseInsensitiveEqual(SystemCustomerRoleNames.SuperAdministrators))
                        {
                            context.Result.AddInfo("Security. Ignored administrator role.", row.GetRowInfo(), "CustomerRoleSystemNames");
                        }
                        else if (!assignedRoles.ContainsKey(systemName) && allCustomerRoles.TryGetValue(systemName, out role))
                        {
                            // Never insert roles!
                            context.Services.DbContext.SetToUnchanged(role);

                            customer.CustomerRoles.Add(role);
                        }
                    }
                }
            }

            return(context.Services.DbContext.SaveChanges());
        }
        protected virtual int ProcessPictures(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Category> > batch,
            Dictionary <int, ImportCategoryMapping> srcToDestId)
        {
            Picture picture        = null;
            var     equalPictureId = 0;

            foreach (var row in batch)
            {
                try
                {
                    var srcId     = row.GetDataValue <int>("Id");
                    var urlOrPath = row.GetDataValue <string>("ImageUrl");

                    if (srcId != 0 && srcToDestId.ContainsKey(srcId) && urlOrPath.HasValue())
                    {
                        var currentPictures = new List <Picture>();
                        var category        = _categoryRepository.GetById(srcToDestId[srcId].DestinationId);
                        var seoName         = _pictureService.GetPictureSeName(row.EntityDisplayName);
                        var image           = CreateDownloadImage(urlOrPath, seoName, 1);

                        if (category != null && image != null)
                        {
                            if (image.Url.HasValue() && !image.Success.HasValue)
                            {
                                AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, new FileDownloadManagerItem[] { image }));
                            }

                            if ((image.Success ?? false) && File.Exists(image.Path))
                            {
                                Succeeded(image);
                                var pictureBinary = File.ReadAllBytes(image.Path);

                                if (pictureBinary != null && pictureBinary.Length > 0)
                                {
                                    if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null)
                                    {
                                        currentPictures.Add(picture);
                                    }

                                    var size = Size.Empty;
                                    pictureBinary = _pictureService.ValidatePicture(pictureBinary, out size);
                                    pictureBinary = _pictureService.FindEqualPicture(pictureBinary, currentPictures, out equalPictureId);

                                    if (pictureBinary != null && pictureBinary.Length > 0)
                                    {
                                        if ((picture = _pictureService.InsertPicture(pictureBinary, image.MimeType, seoName, true, size.Width, size.Height, false)) != null)
                                        {
                                            category.PictureId = picture.Id;
                                            _categoryRepository.Update(category);
                                        }
                                    }
                                    else
                                    {
                                        context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "ImageUrls");
                                    }
                                }
                            }
                            else if (image.Url.HasValue())
                            {
                                context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "ImageUrls");
                            }
                        }
                    }
                }
                catch (Exception exception)
                {
                    context.Result.AddWarning(exception.ToAllMessages(), row.GetRowInfo(), "ImageUrls");
                }
            }

            var num = _categoryRepository.Context.SaveChanges();

            return(num);
        }
Exemple #28
0
        protected virtual int ProcessProducts(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Product> > batch,
            Dictionary <string, int> templateViewPaths,
            Dictionary <int, ImportProductMapping> srcToDestId)
        {
            _productRepository.AutoCommitEnabled = false;

            Product lastInserted      = null;
            Product lastUpdated       = null;
            var     defaultTemplateId = templateViewPaths["Product"];

            foreach (var row in batch)
            {
                Product product = null;
                var     id      = row.GetDataValue <int>("Id");

                foreach (var keyName in context.KeyFieldNames)
                {
                    var keyValue = row.GetDataValue <string>(keyName);

                    if (keyValue.HasValue() || id > 0)
                    {
                        switch (keyName)
                        {
                        case "Id":
                            product = _productRepository.GetById(id);                                     // get it uncached
                            break;

                        case "Sku":
                            product = _productService.GetProductBySku(keyValue);
                            break;

                        case "Gtin":
                            product = _productService.GetProductByGtin(keyValue);
                            break;

                        case "ManufacturerPartNumber":
                            product = _productService.GetProductByManufacturerPartNumber(keyValue);
                            break;

                        case "Name":
                            product = _productService.GetProductByName(keyValue);
                            break;
                        }
                    }

                    if (product != null)
                    {
                        break;
                    }
                }

                if (product == null)
                {
                    if (context.UpdateOnly)
                    {
                        ++context.Result.SkippedRecords;
                        continue;
                    }

                    // a Name is required for new products.
                    if (!row.HasDataValue("Name"))
                    {
                        ++context.Result.SkippedRecords;
                        context.Result.AddError("The 'Name' field is required for new products. Skipping row.", row.GetRowInfo(), "Name");
                        continue;
                    }

                    product = new Product();
                }

                var name = row.GetDataValue <string>("Name");

                row.Initialize(product, name ?? product.Name);

                if (!row.IsNew)
                {
                    if (!product.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
                    {
                        // Perf: use this later for SeName updates.
                        row.NameChanged = true;
                    }
                }

                row.SetProperty(context.Result, (x) => x.ProductTypeId, (int)ProductType.SimpleProduct);
                row.SetProperty(context.Result, (x) => x.VisibleIndividually, true);
                row.SetProperty(context.Result, (x) => x.Name);
                row.SetProperty(context.Result, (x) => x.ShortDescription);
                row.SetProperty(context.Result, (x) => x.FullDescription);
                row.SetProperty(context.Result, (x) => x.AdminComment);
                row.SetProperty(context.Result, (x) => x.ShowOnHomePage);
                row.SetProperty(context.Result, (x) => x.HomePageDisplayOrder);
                row.SetProperty(context.Result, (x) => x.MetaKeywords);
                row.SetProperty(context.Result, (x) => x.MetaDescription);
                row.SetProperty(context.Result, (x) => x.MetaTitle);
                row.SetProperty(context.Result, (x) => x.AllowCustomerReviews, true);
                row.SetProperty(context.Result, (x) => x.ApprovedRatingSum);
                row.SetProperty(context.Result, (x) => x.NotApprovedRatingSum);
                row.SetProperty(context.Result, (x) => x.ApprovedTotalReviews);
                row.SetProperty(context.Result, (x) => x.NotApprovedTotalReviews);
                row.SetProperty(context.Result, (x) => x.Published, true);
                row.SetProperty(context.Result, (x) => x.Sku);
                row.SetProperty(context.Result, (x) => x.ManufacturerPartNumber);
                row.SetProperty(context.Result, (x) => x.Gtin);
                row.SetProperty(context.Result, (x) => x.IsGiftCard);
                row.SetProperty(context.Result, (x) => x.GiftCardTypeId);
                row.SetProperty(context.Result, (x) => x.RequireOtherProducts);
                row.SetProperty(context.Result, (x) => x.RequiredProductIds);                   // TODO: global scope
                row.SetProperty(context.Result, (x) => x.AutomaticallyAddRequiredProducts);
                row.SetProperty(context.Result, (x) => x.IsDownload);
                row.SetProperty(context.Result, (x) => x.DownloadId);
                row.SetProperty(context.Result, (x) => x.UnlimitedDownloads, true);
                row.SetProperty(context.Result, (x) => x.MaxNumberOfDownloads, 10);
                row.SetProperty(context.Result, (x) => x.DownloadExpirationDays);
                row.SetProperty(context.Result, (x) => x.DownloadActivationTypeId, 1);
                row.SetProperty(context.Result, (x) => x.HasSampleDownload);
                row.SetProperty(context.Result, (x) => x.SampleDownloadId, (int?)null, ZeroToNull);                    // TODO: global scope
                row.SetProperty(context.Result, (x) => x.HasUserAgreement);
                row.SetProperty(context.Result, (x) => x.UserAgreementText);
                row.SetProperty(context.Result, (x) => x.IsRecurring);
                row.SetProperty(context.Result, (x) => x.RecurringCycleLength, 100);
                row.SetProperty(context.Result, (x) => x.RecurringCyclePeriodId);
                row.SetProperty(context.Result, (x) => x.RecurringTotalCycles, 10);
                row.SetProperty(context.Result, (x) => x.IsShipEnabled, true);
                row.SetProperty(context.Result, (x) => x.IsFreeShipping);
                row.SetProperty(context.Result, (x) => x.AdditionalShippingCharge);
                row.SetProperty(context.Result, (x) => x.IsEsd);
                row.SetProperty(context.Result, (x) => x.IsTaxExempt);
                row.SetProperty(context.Result, (x) => x.TaxCategoryId, 1);                    // TODO: global scope
                row.SetProperty(context.Result, (x) => x.ManageInventoryMethodId);
                row.SetProperty(context.Result, (x) => x.StockQuantity, 10000);
                row.SetProperty(context.Result, (x) => x.DisplayStockAvailability);
                row.SetProperty(context.Result, (x) => x.DisplayStockQuantity);
                row.SetProperty(context.Result, (x) => x.MinStockQuantity);
                row.SetProperty(context.Result, (x) => x.LowStockActivityId);
                row.SetProperty(context.Result, (x) => x.NotifyAdminForQuantityBelow, 1);
                row.SetProperty(context.Result, (x) => x.BackorderModeId);
                row.SetProperty(context.Result, (x) => x.AllowBackInStockSubscriptions);
                row.SetProperty(context.Result, (x) => x.OrderMinimumQuantity, 1);
                row.SetProperty(context.Result, (x) => x.OrderMaximumQuantity, 100);
                row.SetProperty(context.Result, (x) => x.HideQuantityControl);
                row.SetProperty(context.Result, (x) => x.AllowedQuantities);
                row.SetProperty(context.Result, (x) => x.DisableBuyButton);
                row.SetProperty(context.Result, (x) => x.DisableWishlistButton);
                row.SetProperty(context.Result, (x) => x.AvailableForPreOrder);
                row.SetProperty(context.Result, (x) => x.CallForPrice);
                row.SetProperty(context.Result, (x) => x.Price);
                row.SetProperty(context.Result, (x) => x.OldPrice);
                row.SetProperty(context.Result, (x) => x.ProductCost);
                row.SetProperty(context.Result, (x) => x.SpecialPrice);
                row.SetProperty(context.Result, (x) => x.SpecialPriceStartDateTimeUtc);
                row.SetProperty(context.Result, (x) => x.SpecialPriceEndDateTimeUtc);
                row.SetProperty(context.Result, (x) => x.CustomerEntersPrice);
                row.SetProperty(context.Result, (x) => x.MinimumCustomerEnteredPrice);
                row.SetProperty(context.Result, (x) => x.MaximumCustomerEnteredPrice, 1000);
                // HasTierPrices... ignore as long as no tier prices are imported
                // LowestAttributeCombinationPrice... ignore as long as no combinations are imported
                row.SetProperty(context.Result, (x) => x.Weight);
                row.SetProperty(context.Result, (x) => x.Length);
                row.SetProperty(context.Result, (x) => x.Width);
                row.SetProperty(context.Result, (x) => x.Height);
                row.SetProperty(context.Result, (x) => x.DisplayOrder);
                row.SetProperty(context.Result, (x) => x.DeliveryTimeId);                      // TODO: global scope
                row.SetProperty(context.Result, (x) => x.QuantityUnitId);                      // TODO: global scope
                row.SetProperty(context.Result, (x) => x.BasePriceEnabled);
                row.SetProperty(context.Result, (x) => x.BasePriceMeasureUnit);
                row.SetProperty(context.Result, (x) => x.BasePriceAmount);
                row.SetProperty(context.Result, (x) => x.BasePriceBaseAmount);
                row.SetProperty(context.Result, (x) => x.BundleTitleText);
                row.SetProperty(context.Result, (x) => x.BundlePerItemShipping);
                row.SetProperty(context.Result, (x) => x.BundlePerItemPricing);
                row.SetProperty(context.Result, (x) => x.BundlePerItemShoppingCart);
                row.SetProperty(context.Result, (x) => x.AvailableStartDateTimeUtc);
                row.SetProperty(context.Result, (x) => x.AvailableEndDateTimeUtc);
                // With new entities, "LimitedToStores" is an implicit field, meaning
                // it has to be set to true by code if it's absent but "StoreIds" exists.
                row.SetProperty(context.Result, (x) => x.LimitedToStores, !row.GetDataValue <List <int> >("StoreIds").IsNullOrEmpty());
                row.SetProperty(context.Result, (x) => x.CustomsTariffNumber);
                row.SetProperty(context.Result, (x) => x.CountryOfOriginId);

                string tvp;
                if (row.TryGetDataValue("ProductTemplateViewPath", out tvp, row.IsTransient))
                {
                    product.ProductTemplateId = (tvp.HasValue() && templateViewPaths.ContainsKey(tvp) ? templateViewPaths[tvp] : defaultTemplateId);
                }

                if (id != 0 && !srcToDestId.ContainsKey(id))
                {
                    srcToDestId.Add(id, new ImportProductMapping {
                        Inserted = row.IsTransient
                    });
                }

                if (row.IsTransient)
                {
                    _productRepository.Insert(product);
                    lastInserted = product;
                }
                else
                {
                    _productRepository.Update(product);
                    lastUpdated = product;
                }
            }

            // commit whole batch at once
            var num = _productRepository.Context.SaveChanges();

            // get new product ids
            foreach (var row in batch)
            {
                var id = row.GetDataValue <int>("Id");

                if (id != 0 && srcToDestId.ContainsKey(id))
                {
                    srcToDestId[id].DestinationId = row.Entity.Id;
                }
            }

            // Perf: notify only about LAST insertion and update
            if (lastInserted != null)
            {
                _services.EventPublisher.EntityInserted(lastInserted);
            }

            if (lastUpdated != null)
            {
                _services.EventPublisher.EntityUpdated(lastUpdated);
            }

            return(num);
        }
Exemple #29
0
        public void Execute(ImportExecuteContext context)
        {
            var utcNow         = DateTime.UtcNow;
            var currentStoreId = _services.StoreContext.CurrentStore.Id;

            using (var scope = new DbContextScope(ctx: _services.DbContext, hooksEnabled: false, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                var segmenter = context.DataSegmenter;

                context.Result.TotalRecords = segmenter.TotalRows;

                while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                {
                    var batch = segmenter.GetCurrentBatch <NewsLetterSubscription>();

                    // Perf: detach all entities
                    _subscriptionRepository.Context.DetachEntities <NewsLetterSubscription>(false);

                    context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows);

                    foreach (var row in batch)
                    {
                        try
                        {
                            var active  = true;
                            var email   = row.GetDataValue <string>("Email");
                            var storeId = row.GetDataValue <int>("StoreId");

                            if (storeId == 0)
                            {
                                storeId = currentStoreId;
                            }

                            if (row.HasDataValue("Active") && row.TryGetDataValue("Active", out active))
                            {
                            }
                            else
                            {
                                active = true;                                  // default
                            }

                            if (email.IsEmpty())
                            {
                                context.Result.AddWarning("Skipped empty email address", row.GetRowInfo(), "Email");
                                continue;
                            }

                            if (email.Length > 255)
                            {
                                context.Result.AddWarning("Skipped email address '{0}'. It exceeds the maximum allowed length of 255".FormatInvariant(email), row.GetRowInfo(), "Email");
                                continue;
                            }

                            if (!email.IsEmail())
                            {
                                context.Result.AddWarning("Skipped invalid email address '{0}'".FormatInvariant(email), row.GetRowInfo(), "Email");
                                continue;
                            }

                            NewsLetterSubscription subscription = null;

                            foreach (var keyName in context.KeyFieldNames)
                            {
                                switch (keyName)
                                {
                                case "Email":
                                    subscription = _subscriptionRepository.Table
                                                   .OrderBy(x => x.Id)
                                                   .FirstOrDefault(x => x.Email == email && x.StoreId == storeId);
                                    break;
                                }

                                if (subscription != null)
                                {
                                    break;
                                }
                            }

                            if (subscription == null)
                            {
                                if (context.UpdateOnly)
                                {
                                    ++context.Result.SkippedRecords;
                                    continue;
                                }

                                subscription = new NewsLetterSubscription
                                {
                                    Active       = active,
                                    CreatedOnUtc = utcNow,
                                    Email        = email,
                                    NewsLetterSubscriptionGuid = Guid.NewGuid(),
                                    StoreId = storeId
                                };

                                _subscriptionRepository.Insert(subscription);
                                context.Result.NewRecords++;
                            }
                            else
                            {
                                subscription.Active = active;

                                _subscriptionRepository.Update(subscription);
                                context.Result.ModifiedRecords++;
                            }
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception.ToAllMessages(), row.GetRowInfo());
                        }
                    }                     // for

                    _subscriptionRepository.Context.SaveChanges();
                }                 // while
            }
        }
Exemple #30
0
        protected virtual int ProcessGenericAttributes(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Customer> > batch,
            Dictionary <string, int> allCountries,
            Dictionary <Tuple <int, string>, int> allStateProvinces)
        {
            foreach (var row in batch)
            {
                if (_dateTimeSettings.AllowCustomersToSetTimeZone)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.TimeZoneId);
                }

                if (_customerSettings.GenderEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Gender);
                }

                if (_customerSettings.StreetAddressEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.StreetAddress);
                }

                if (_customerSettings.StreetAddress2Enabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.StreetAddress2);
                }

                if (_customerSettings.ZipPostalCodeEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.ZipPostalCode);
                }

                if (_customerSettings.CityEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.City);
                }

                if (_customerSettings.CountryEnabled)
                {
                    SaveAttribute <int>(row, SystemCustomerAttributeNames.CountryId);
                }

                if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled)
                {
                    SaveAttribute <int>(row, SystemCustomerAttributeNames.StateProvinceId);
                }

                if (_customerSettings.PhoneEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Phone);
                }

                if (_customerSettings.FaxEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Fax);
                }

                if (_forumSettings.ForumsEnabled)
                {
                    SaveAttribute <int>(row, SystemCustomerAttributeNames.ForumPostCount);
                }

                if (_forumSettings.SignaturesEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Signature);
                }

                var countryId = CountryCodeToId(allCountries, row.GetDataValue <string>("CountryCode"));
                var stateId   = StateAbbreviationToId(allStateProvinces, countryId, row.GetDataValue <string>("StateAbbreviation"));

                if (countryId.HasValue)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.CountryId, countryId.Value);
                }

                if (stateId.HasValue)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.StateProvinceId, stateId.Value);
                }
            }

            return(_services.DbContext.SaveChanges());
        }
Exemple #31
0
        private void ImportAddress(
            string fieldPrefix,
            ImportRow <Customer> row,
            ImportExecuteContext context,
            Dictionary <string, int> allCountries,
            Dictionary <Tuple <int, string>, int> allStateProvinces)
        {
            // last name is mandatory for an address to be imported or updated
            if (!row.HasDataValue(fieldPrefix + "LastName"))
            {
                return;
            }

            var address = new Address
            {
                CreatedOnUtc = UtcNow
            };

            var childRow = new ImportRow <Address>(row.Segmenter, row.DataRow, row.Position);

            childRow.Initialize(address, row.EntityDisplayName);

            childRow.SetProperty(context.Result, fieldPrefix + "LastName", x => x.LastName);
            childRow.SetProperty(context.Result, fieldPrefix + "FirstName", x => x.FirstName);
            childRow.SetProperty(context.Result, fieldPrefix + "Email", x => x.Email);
            childRow.SetProperty(context.Result, fieldPrefix + "Company", x => x.Company);
            childRow.SetProperty(context.Result, fieldPrefix + "City", x => x.City);
            childRow.SetProperty(context.Result, fieldPrefix + "Address1", x => x.Address1);
            childRow.SetProperty(context.Result, fieldPrefix + "Address2", x => x.Address2);
            childRow.SetProperty(context.Result, fieldPrefix + "ZipPostalCode", x => x.ZipPostalCode);
            childRow.SetProperty(context.Result, fieldPrefix + "PhoneNumber", x => x.PhoneNumber);
            childRow.SetProperty(context.Result, fieldPrefix + "FaxNumber", x => x.FaxNumber);

            childRow.SetProperty(context.Result, fieldPrefix + "CountryId", x => x.CountryId);
            if (childRow.Entity.CountryId == null)
            {
                // try with country code
                childRow.SetProperty(context.Result, fieldPrefix + "CountryCode", x => x.CountryId, converter: (val, ci) => CountryCodeToId(allCountries, val.ToString()));
            }

            var countryId = childRow.Entity.CountryId;

            if (countryId.HasValue)
            {
                childRow.SetProperty(context.Result, fieldPrefix + "StateProvinceId", x => x.StateProvinceId);
                if (childRow.Entity.StateProvinceId == null)
                {
                    // try with state abbreviation
                    childRow.SetProperty(context.Result, fieldPrefix + "StateAbbreviation", x => x.StateProvinceId, converter: (val, ci) => StateAbbreviationToId(allStateProvinces, countryId, val.ToString()));
                }
            }

            if (!childRow.IsDirty)
            {
                // Not one single property could be set. Get out!
                return;
            }

            var appliedAddress = row.Entity.Addresses.FindAddress(address);

            if (appliedAddress == null)
            {
                appliedAddress = address;
                row.Entity.Addresses.Add(appliedAddress);
            }

            if (fieldPrefix == "BillingAddress.")
            {
                row.Entity.BillingAddress = appliedAddress;
            }
            else if (fieldPrefix == "ShippingAddress.")
            {
                row.Entity.ShippingAddress = appliedAddress;
            }

            _customerRepository.Update(row.Entity);
        }
Exemple #32
0
        protected virtual int ProcessGenericAttributes(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Customer> > batch,
            Dictionary <string, int> allCountries,
            Dictionary <Tuple <int, string>, int> allStateProvinces,
            HashSet <string> allCustomerNumbers)
        {
            foreach (var row in batch)
            {
                SaveAttribute(row, SystemCustomerAttributeNames.FirstName);
                SaveAttribute(row, SystemCustomerAttributeNames.LastName);

                if (_dateTimeSettings.AllowCustomersToSetTimeZone)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.TimeZoneId);
                }

                if (_customerSettings.GenderEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Gender);
                }

                if (_customerSettings.DateOfBirthEnabled)
                {
                    SaveAttribute <DateTime?>(row, SystemCustomerAttributeNames.DateOfBirth);
                }

                if (_customerSettings.CompanyEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Company);
                }

                if (_customerSettings.StreetAddressEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.StreetAddress);
                }

                if (_customerSettings.StreetAddress2Enabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.StreetAddress2);
                }

                if (_customerSettings.ZipPostalCodeEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.ZipPostalCode);
                }

                if (_customerSettings.CityEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.City);
                }

                if (_customerSettings.CountryEnabled)
                {
                    SaveAttribute <int>(row, SystemCustomerAttributeNames.CountryId);
                }

                if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled)
                {
                    SaveAttribute <int>(row, SystemCustomerAttributeNames.StateProvinceId);
                }

                if (_customerSettings.PhoneEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Phone);
                }

                if (_customerSettings.FaxEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Fax);
                }

                if (_forumSettings.ForumsEnabled)
                {
                    SaveAttribute <int>(row, SystemCustomerAttributeNames.ForumPostCount);
                }

                if (_forumSettings.SignaturesEnabled)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.Signature);
                }

                var countryId = CountryCodeToId(allCountries, row.GetDataValue <string>("CountryCode"));
                var stateId   = StateAbbreviationToId(allStateProvinces, countryId, row.GetDataValue <string>("StateAbbreviation"));

                if (countryId.HasValue)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.CountryId, countryId.Value);
                }

                if (stateId.HasValue)
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.StateProvinceId, stateId.Value);
                }

                string customerNumber = null;

                if (_customerSettings.CustomerNumberMethod == CustomerNumberMethod.AutomaticallySet)
                {
                    customerNumber = row.Entity.Id.ToString();
                }
                else
                {
                    customerNumber = row.GetDataValue <string>("CustomerNumber");
                }

                if (customerNumber.IsEmpty() || !allCustomerNumbers.Contains(customerNumber))
                {
                    SaveAttribute(row, SystemCustomerAttributeNames.CustomerNumber, customerNumber);

                    if (!customerNumber.IsEmpty())
                    {
                        allCustomerNumbers.Add(customerNumber);
                    }
                }
            }

            return(_services.DbContext.SaveChanges());
        }
        protected virtual int ProcessCategories(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Category> > batch,
            Dictionary <string, int> templateViewPaths,
            Dictionary <int, ImportCategoryMapping> srcToDestId)
        {
            _categoryRepository.AutoCommitEnabled = true;

            var defaultTemplateId = templateViewPaths["CategoryTemplate.ProductsInGridOrLines"];
            var hasNameColumn     = context.DataSegmenter.HasColumn("Name");

            foreach (var row in batch)
            {
                Category category = null;
                var      id       = row.GetDataValue <int>("Id");
                var      name     = row.GetDataValue <string>("Name");

                foreach (var keyName in context.KeyFieldNames)
                {
                    switch (keyName)
                    {
                    case "Id":
                        if (id != 0)
                        {
                            category = _categoryRepository.GetById(id);
                        }
                        break;

                    case "Name":
                        if (name.HasValue())
                        {
                            category = _categoryRepository.Table.FirstOrDefault(x => x.Name == name);
                        }
                        break;
                    }

                    if (category != null)
                    {
                        break;
                    }
                }

                if (category == null)
                {
                    if (context.UpdateOnly)
                    {
                        ++context.Result.SkippedRecords;
                        continue;
                    }

                    // A name is required for new categories.
                    if (!row.HasDataValue("Name"))
                    {
                        ++context.Result.SkippedRecords;
                        context.Result.AddError("The 'Name' field is required for new categories. Skipping row.", row.GetRowInfo(), "Name");
                        continue;
                    }

                    category = new Category();
                }

                row.Initialize(category, name ?? category.Name);

                if (!row.IsNew && hasNameColumn && !category.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
                {
                    // Perf: use this later for SeName updates.
                    row.NameChanged = true;
                }

                row.SetProperty(context.Result, (x) => x.Name);
                row.SetProperty(context.Result, (x) => x.FullName);
                row.SetProperty(context.Result, (x) => x.Description);
                row.SetProperty(context.Result, (x) => x.BottomDescription);
                row.SetProperty(context.Result, (x) => x.MetaKeywords);
                row.SetProperty(context.Result, (x) => x.MetaDescription);
                row.SetProperty(context.Result, (x) => x.MetaTitle);
                row.SetProperty(context.Result, (x) => x.PageSize);
                row.SetProperty(context.Result, (x) => x.AllowCustomersToSelectPageSize);
                row.SetProperty(context.Result, (x) => x.PageSizeOptions);
                row.SetProperty(context.Result, (x) => x.ShowOnHomePage);
                row.SetProperty(context.Result, (x) => x.HasDiscountsApplied);
                row.SetProperty(context.Result, (x) => x.Published, true);
                row.SetProperty(context.Result, (x) => x.DisplayOrder);
                row.SetProperty(context.Result, (x) => x.Alias);
                row.SetProperty(context.Result, (x) => x.DefaultViewMode);
                // With new entities, "LimitedToStores" is an implicit field, meaning
                // it has to be set to true by code if it's absent but "StoreIds" exists.
                row.SetProperty(context.Result, (x) => x.LimitedToStores, !row.GetDataValue <List <int> >("StoreIds").IsNullOrEmpty());

                string tvp;
                if (row.TryGetDataValue("CategoryTemplateViewPath", out tvp, row.IsTransient))
                {
                    category.CategoryTemplateId = (tvp.HasValue() && templateViewPaths.ContainsKey(tvp) ? templateViewPaths[tvp] : defaultTemplateId);
                }

                if (id != 0 && !srcToDestId.ContainsKey(id))
                {
                    srcToDestId.Add(id, new ImportCategoryMapping {
                        Inserted = row.IsTransient
                    });
                }

                if (row.IsTransient)
                {
                    _categoryRepository.Insert(category);
                }
                else
                {
                    _categoryRepository.Update(category);
                }
            }

            // Commit whole batch at once.
            var num = _categoryRepository.Context.SaveChanges();

            // Get new category ids.
            foreach (var row in batch)
            {
                var id = row.GetDataValue <int>("Id");
                if (id != 0 && srcToDestId.ContainsKey(id))
                {
                    srcToDestId[id].DestinationId = row.Entity.Id;
                }
            }

            return(num);
        }
Exemple #34
0
        protected virtual int ProcessAvatars(
            ImportExecuteContext context,
            IEnumerable <ImportRow <Customer> > batch)
        {
            foreach (var row in batch)
            {
                var urlOrPath = row.GetDataValue <string>("AvatarPictureUrl");
                if (urlOrPath.IsEmpty())
                {
                    continue;
                }

                var equalPictureId  = 0;
                var currentPictures = new List <Picture>();
                var seoName         = _pictureService.GetPictureSeName(row.EntityDisplayName);

                var image = CreateDownloadImage(urlOrPath, seoName, 1);
                if (image == null)
                {
                    continue;
                }

                if (image.Url.HasValue() && !image.Success.HasValue)
                {
                    AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, new FileDownloadManagerItem[] { image }));
                }

                if ((image.Success ?? false) && File.Exists(image.Path))
                {
                    Succeeded(image);
                    var pictureBinary = File.ReadAllBytes(image.Path);

                    if (pictureBinary != null && pictureBinary.Length > 0)
                    {
                        var pictureId = row.Entity.GetAttribute <int>(SystemCustomerAttributeNames.AvatarPictureId);
                        if (pictureId != 0)
                        {
                            var picture = _pictureRepository.TableUntracked.Expand(x => x.MediaStorage).FirstOrDefault(x => x.Id == pictureId);
                            if (picture != null)
                            {
                                currentPictures.Add(picture);
                            }
                        }

                        var size = Size.Empty;
                        pictureBinary = _pictureService.ValidatePicture(pictureBinary, out size);
                        pictureBinary = _pictureService.FindEqualPicture(pictureBinary, currentPictures, out equalPictureId);

                        if (pictureBinary != null && pictureBinary.Length > 0)
                        {
                            var picture = _pictureService.InsertPicture(pictureBinary, image.MimeType, seoName, true, size.Width, size.Height, false);
                            if (picture != null)
                            {
                                SaveAttribute(row, SystemCustomerAttributeNames.AvatarPictureId, picture.Id);
                            }
                        }
                        else
                        {
                            context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "AvatarPictureUrl");
                        }
                    }
                }
                else
                {
                    context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "AvatarPictureUrl");
                }
            }

            return(_services.DbContext.SaveChanges());
        }
        public ImportExecutedEvent(ImportExecuteContext context)
        {
            Guard.NotNull(context, nameof(context));

            Context = context;
        }
        protected override void Import(ImportExecuteContext context)
        {
            var srcToDestId = new Dictionary<int, ImportProductMapping>();

            var templateViewPaths = _productTemplateService.GetAllProductTemplates().ToDictionarySafe(x => x.ViewPath, x => x.Id);

            using (var scope = new DbContextScope(ctx: _productRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false))
            {
                var segmenter = context.DataSegmenter;

                Initialize(context);

                while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                {
                    var batch = segmenter.GetCurrentBatch<Product>();

                    // Perf: detach all entities
                    _productRepository.Context.DetachAll(false);

                    context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows);

                    // ===========================================================================
                    // 1.) Import products
                    // ===========================================================================
                    try
                    {
                        ProcessProducts(context, batch, templateViewPaths, srcToDestId);
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProducts");
                    }

                    // reduce batch to saved (valid) products.
                    // No need to perform import operations on errored products.
                    batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray();

                    // update result object
                    context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient);
                    context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient);

                    // ===========================================================================
                    // 2.) Import SEO Slugs
                    // IMPORTANT: Unlike with Products AutoCommitEnabled must be TRUE,
                    //            as Slugs are going to be validated against existing ones in DB.
                    // ===========================================================================
                    if (segmenter.HasColumn("SeName", true) || batch.Any(x => x.IsNew || x.NameChanged))
                    {
                        try
                        {
                            _productRepository.Context.AutoDetectChangesEnabled = true;
                            ProcessSlugs(context, batch, typeof(Product).Name);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessSlugs");
                        }
                        finally
                        {
                            _productRepository.Context.AutoDetectChangesEnabled = false;
                        }
                    }

                    // ===========================================================================
                    // 3.) Import StoreMappings
                    // ===========================================================================
                    if (segmenter.HasColumn("StoreIds"))
                    {
                        try
                        {
                            ProcessStoreMappings(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessStoreMappings");
                        }
                    }

                    // ===========================================================================
                    // 4.) Import Localizations
                    // ===========================================================================
                    try
                    {
                        ProcessLocalizations(context, batch, _localizableProperties);
                    }
                    catch (Exception exception)
                    {
                        context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessLocalizations");
                    }

                    // ===========================================================================
                    // 5.) Import product category mappings
                    // ===========================================================================
                    if (segmenter.HasColumn("CategoryIds"))
                    {
                        try
                        {
                            ProcessProductCategories(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductCategories");
                        }
                    }

                    // ===========================================================================
                    // 6.) Import product manufacturer mappings
                    // ===========================================================================
                    if (segmenter.HasColumn("ManufacturerIds"))
                    {
                        try
                        {
                            ProcessProductManufacturers(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductManufacturers");
                        }
                    }

                    // ===========================================================================
                    // 7.) Import product picture mappings
                    // ===========================================================================
                    if (segmenter.HasColumn("ImageUrls"))
                    {
                        try
                        {
                            ProcessProductPictures(context, batch);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductPictures");
                        }
                    }
                }

                // ===========================================================================
                // 8.) Map parent id of inserted products
                // ===========================================================================
                if (srcToDestId.Any() && segmenter.HasColumn("Id") && segmenter.HasColumn("ParentGroupedProductId") && !segmenter.IsIgnored("ParentGroupedProductId"))
                {
                    segmenter.Reset();

                    while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch())
                    {
                        var batch = segmenter.GetCurrentBatch<Product>();

                        _productRepository.Context.DetachAll(false);

                        try
                        {
                            ProcessProductMappings(context, batch, srcToDestId);
                        }
                        catch (Exception exception)
                        {
                            context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessParentMappings");
                        }
                    }
                }
            }
        }