예제 #1
0
        private int ProcessProducts(ICollection<ImportRow<Product>> batch, ImportResult result)
        {
            _rsProduct.AutoCommitEnabled = true;

            Product lastInserted = null;
            Product lastUpdated = null;

            foreach (var row in batch)
            {
                if (row.Count == 0)
                    continue;

                Product product = null;

                object key;

                // try get by int ID
                if (row.TryGetValue("Id", out key) && key.ToString().ToInt() > 0)
                {
                    product = _productService.GetProductById(key.ToString().ToInt());
                }

                // try get by SKU
                if (product == null && row.TryGetValue("SKU", out key))
                {
                    product = _productService.GetProductBySku(key.ToString());
                }

                // try get by GTIN
                if (product == null && row.TryGetValue("Gtin", out key))
                {
                    product = _productService.GetProductByGtin(key.ToString());
                }

                if (product == null)
                {
                    // a Name is required with new products.
                    if (!row.ContainsKey("Name"))
                    {
                        result.AddError("The 'Name' field is required for new products. Skipping row.", row.GetRowInfo(), "Name");
                        continue;
                    }
                    product = new Product();
                }

                row.Initialize(product, row["Name"].ToString());

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

                row.SetProperty(result, product, (x) => x.Sku);
                row.SetProperty(result, product, (x) => x.Gtin);
                row.SetProperty(result, product, (x) => x.ManufacturerPartNumber);
                row.SetProperty(result, product, (x) => x.ProductTypeId, (int)ProductType.SimpleProduct);
                row.SetProperty(result, product, (x) => x.ParentGroupedProductId);
                row.SetProperty(result, product, (x) => x.VisibleIndividually, true);
                row.SetProperty(result, product, (x) => x.Name);
                row.SetProperty(result, product, (x) => x.ShortDescription);
                row.SetProperty(result, product, (x) => x.FullDescription);
                row.SetProperty(result, product, (x) => x.ProductTemplateId);
                row.SetProperty(result, product, (x) => x.ShowOnHomePage);
                row.SetProperty(result, product, (x) => x.HomePageDisplayOrder);
                row.SetProperty(result, product, (x) => x.MetaKeywords);
                row.SetProperty(result, product, (x) => x.MetaDescription);
                row.SetProperty(result, product, (x) => x.MetaTitle);
                row.SetProperty(result, product, (x) => x.AllowCustomerReviews, true);
                row.SetProperty(result, product, (x) => x.Published, true);
                row.SetProperty(result, product, (x) => x.IsGiftCard);
                row.SetProperty(result, product, (x) => x.GiftCardTypeId);
                row.SetProperty(result, product, (x) => x.RequireOtherProducts);
                row.SetProperty(result, product, (x) => x.RequiredProductIds);
                row.SetProperty(result, product, (x) => x.AutomaticallyAddRequiredProducts);
                row.SetProperty(result, product, (x) => x.IsDownload);
                row.SetProperty(result, product, (x) => x.DownloadId);
                row.SetProperty(result, product, (x) => x.UnlimitedDownloads, true);
                row.SetProperty(result, product, (x) => x.MaxNumberOfDownloads, 10);
                row.SetProperty(result, product, (x) => x.DownloadActivationTypeId, 1);
                row.SetProperty(result, product, (x) => x.HasSampleDownload);
                row.SetProperty(result, product, (x) => x.SampleDownloadId, (int?)null, ZeroToNull);
                row.SetProperty(result, product, (x) => x.HasUserAgreement);
                row.SetProperty(result, product, (x) => x.UserAgreementText);
                row.SetProperty(result, product, (x) => x.IsRecurring);
                row.SetProperty(result, product, (x) => x.RecurringCycleLength, 100);
                row.SetProperty(result, product, (x) => x.RecurringCyclePeriodId);
                row.SetProperty(result, product, (x) => x.RecurringTotalCycles, 10);
                row.SetProperty(result, product, (x) => x.IsShipEnabled, true);
                row.SetProperty(result, product, (x) => x.IsFreeShipping);
                row.SetProperty(result, product, (x) => x.AdditionalShippingCharge);
                row.SetProperty(result, product, (x) => x.IsEsd);
                row.SetProperty(result, product, (x) => x.IsTaxExempt);
                row.SetProperty(result, product, (x) => x.TaxCategoryId, 1);
                row.SetProperty(result, product, (x) => x.ManageInventoryMethodId);
                row.SetProperty(result, product, (x) => x.StockQuantity, 10000);
                row.SetProperty(result, product, (x) => x.DisplayStockAvailability);
                row.SetProperty(result, product, (x) => x.DisplayStockQuantity);
                row.SetProperty(result, product, (x) => x.MinStockQuantity);
                row.SetProperty(result, product, (x) => x.LowStockActivityId);
                row.SetProperty(result, product, (x) => x.NotifyAdminForQuantityBelow, 1);
                row.SetProperty(result, product, (x) => x.BackorderModeId);
                row.SetProperty(result, product, (x) => x.AllowBackInStockSubscriptions);
                row.SetProperty(result, product, (x) => x.OrderMinimumQuantity, 1);
                row.SetProperty(result, product, (x) => x.OrderMaximumQuantity, 10000);
                row.SetProperty(result, product, (x) => x.AllowedQuantities);
                row.SetProperty(result, product, (x) => x.DisableBuyButton);
                row.SetProperty(result, product, (x) => x.DisableWishlistButton);
                row.SetProperty(result, product, (x) => x.AvailableForPreOrder);
                row.SetProperty(result, product, (x) => x.CallForPrice);
                row.SetProperty(result, product, (x) => x.Price);
                row.SetProperty(result, product, (x) => x.OldPrice);
                row.SetProperty(result, product, (x) => x.ProductCost);
                row.SetProperty(result, product, (x) => x.SpecialPrice);
                row.SetProperty(result, product, (x) => x.SpecialPriceStartDateTimeUtc, null, OADateToUtcDate);
                row.SetProperty(result, product, (x) => x.SpecialPriceEndDateTimeUtc, null, OADateToUtcDate);
                row.SetProperty(result, product, (x) => x.CustomerEntersPrice);
                row.SetProperty(result, product, (x) => x.MinimumCustomerEnteredPrice);
                row.SetProperty(result, product, (x) => x.MaximumCustomerEnteredPrice, 1000);
                row.SetProperty(result, product, (x) => x.Weight);
                row.SetProperty(result, product, (x) => x.Length);
                row.SetProperty(result, product, (x) => x.Width);
                row.SetProperty(result, product, (x) => x.Height);
                row.SetProperty(result, product, (x) => x.DeliveryTimeId);
                row.SetProperty(result, product, (x) => x.QuantityUnitId);
                row.SetProperty(result, product, (x) => x.BasePriceEnabled);
                row.SetProperty(result, product, (x) => x.BasePriceMeasureUnit);
                row.SetProperty(result, product, (x) => x.BasePriceAmount);
                row.SetProperty(result, product, (x) => x.BasePriceBaseAmount);
                row.SetProperty(result, product, (x) => x.BundlePerItemPricing);
                row.SetProperty(result, product, (x) => x.BundlePerItemShipping);
                row.SetProperty(result, product, (x) => x.BundlePerItemShoppingCart);
                row.SetProperty(result, product, (x) => x.BundleTitleText);
                row.SetProperty(result, product, (x) => x.AvailableStartDateTimeUtc, null, OADateToUtcDate);
                row.SetProperty(result, product, (x) => x.AvailableEndDateTimeUtc, null, OADateToUtcDate);
                row.SetProperty(result, product, (x) => x.LimitedToStores);

                string storeIds = row.GetValue<string>("StoreIds");
                if (storeIds.HasValue())
                {
                    _storeMappingService.SaveStoreMappings(product,
                        row["StoreIds"].ToString()
                        .Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())).ToArray());
                }

                row.SetProperty(result, product, (x) => x.CreatedOnUtc, DateTime.UtcNow, OADateToUtcDate);

                product.UpdatedOnUtc = DateTime.UtcNow;

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

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

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

            return num;
        }
예제 #2
0
        /// <summary>
        /// Import products from XLSX file
        /// </summary>
        /// <param name="stream">Stream</param>
        public virtual ImportResult ImportProductsFromExcel(
			Stream stream,
			CancellationToken cancellationToken,
			IProgress<ImportProgressInfo> progress = null)
        {
            Guard.ArgumentNotNull(() => stream);

            var result = new ImportResult();
            int saved = 0;

            if (progress != null)
                progress.Report(new ImportProgressInfo { ElapsedTime = TimeSpan.Zero });

            using (var scope = new DbContextScope(ctx: _rsProduct.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false))
            {
                try {
                    using (var segmenter = new DataSegmenter<Product>(stream))
                    {
                        result.TotalRecords = segmenter.TotalRows;

                        while (segmenter.ReadNextBatch() && !cancellationToken.IsCancellationRequested)
                        {
                            var batch = segmenter.CurrentBatch;

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

                            // Update progress for calling thread
                            if (progress != null)
                            {
                                progress.Report(new ImportProgressInfo
                                {
                                    TotalRecords = result.TotalRecords,
                                    TotalProcessed = segmenter.CurrentSegmentFirstRowIndex - 1,
                                    NewRecords = result.NewRecords,
                                    ModifiedRecords = result.ModifiedRecords,
                                    ElapsedTime = DateTime.UtcNow - result.StartDateUtc,
                                    TotalWarnings = result.Messages.Count(x => x.MessageType == ImportMessageType.Warning),
                                    TotalErrors = result.Messages.Count(x => x.MessageType == ImportMessageType.Error),
                                });
                            }

                            // ===========================================================================
                            // 1.) Import products
                            // ===========================================================================
                            try
                            {
                                saved = ProcessProducts(batch, result);
                            }
                            catch (Exception ex)
                            {
                                result.AddError(ex, 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).AsReadOnly();

                            // update result object
                            result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient);
                            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 (batch.Any(x => x.IsNew || (x.ContainsKey("SeName") || x.NameChanged)))
                            {
                                try
                                {
                                    _rsProduct.Context.AutoDetectChangesEnabled = true;
                                    ProcessSlugs(batch, result);
                                }
                                catch (Exception ex)
                                {
                                    result.AddError(ex, segmenter.CurrentSegment, "ProcessSeoSlugs");
                                }
                                finally
                                {
                                    _rsProduct.Context.AutoDetectChangesEnabled = false;
                                }
                            }

                            // ===========================================================================
                            // 3.) Import Localizations
                            // ===========================================================================
                            try
                            {
                                ProcessLocalizations(batch, result);
                            }
                            catch (Exception ex)
                            {
                                result.AddError(ex, segmenter.CurrentSegment, "ProcessLocalizations");
                            }

                            // ===========================================================================
                            // 4.) Import product category mappings
                            // ===========================================================================
                            if (batch.Any(x => x.ContainsKey("CategoryIds")))
                            {
                                try
                                {
                                    ProcessProductCategories(batch, result);
                                }
                                catch (Exception ex)
                                {
                                    result.AddError(ex, segmenter.CurrentSegment, "ProcessProductCategories");
                                }
                            }

                            // ===========================================================================
                            // 5.) Import product manufacturer mappings
                            // ===========================================================================
                            if (batch.Any(x => x.ContainsKey("ManufacturerIds")))
                            {
                                try
                                {
                                    ProcessProductManufacturers(batch, result);
                                }
                                catch (Exception ex)
                                {
                                    result.AddError(ex, segmenter.CurrentSegment, "ProcessProductManufacturers");
                                }
                            }

                            // ===========================================================================
                            // 6.) Import product picture mappings
                            // ===========================================================================
                            if (batch.Any(x => x.ContainsKey("Picture1") || x.ContainsKey("Picture2") || x.ContainsKey("Picture3")))
                            {
                                try
                                {
                                    ProcessProductPictures(batch, result);
                                }
                                catch (Exception ex)
                                {
                                    result.AddError(ex, segmenter.CurrentSegment, "ProcessProductPictures");
                                }
                            }

                        }
                    }
                }
                catch (Exception ex)
                {
                    result.AddError(ex, null, "ReadFile");
                }
            }

            result.EndDateUtc = DateTime.UtcNow;

            if (cancellationToken.IsCancellationRequested)
            {
                result.Cancelled = true;
                result.AddInfo("Import task was cancelled by user");
            }

            return result;
        }