Exemple #1
0
        /// <summary>
        /// Deletes a product category mapping
        /// </summary>
        /// <param name="productCategory">Product category</param>
        public virtual void DeleteProductCategory(ProductCategory productCategory)
        {
            if (productCategory == null)
                throw new ArgumentNullException("productCategory");

            _productCategoryRepository.Delete(productCategory);

            //cache
            _cacheManager.RemoveByPattern(CATEGORIES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTCATEGORIES_PATTERN_KEY);

            //event notification
            _eventPublisher.EntityDeleted(productCategory);
        }
        public void Can_save_and_load_productCategory()
        {
            var productCategory = new ProductCategory
                                     {
                                         IsFeaturedProduct = true,
                                         DisplayOrder = 1,
                                         Product = new Product()
                                                       {
                                                           Name = "Name 1",
                                                           Published = true,
                                                           Deleted = false,
                                                           CreatedOnUtc = new DateTime(2010, 01, 01),
                                                           UpdatedOnUtc = new DateTime(2010, 01, 02)
                                                       },
                                                       Category = new Category()
                                                                      {
                                                                          Name = "Books",
                                                                          Description = "Description 1",
                                                                          MetaKeywords = "Meta keywords",
                                                                          MetaDescription = "Meta description",
                                                                          MetaTitle = "Meta title",
                                                                          SeName = "SE name",
                                                                          ParentCategoryId = 2,
                                                                          PictureId = 3,
                                                                          PageSize = 4,
                                                                          PriceRanges = "1-3;",
                                                                          ShowOnHomePage = false,
                                                                          Published = true,
                                                                          Deleted = false,
                                                                          DisplayOrder = 5,
                                                                          CreatedOnUtc = new DateTime(2010, 01, 01),
                                                                          UpdatedOnUtc = new DateTime(2010, 01, 02),
                                                                      }
                                     };

            var fromDb = SaveAndLoadEntity(productCategory);
            fromDb.ShouldNotBeNull();
            fromDb.IsFeaturedProduct.ShouldEqual(true);
            fromDb.DisplayOrder.ShouldEqual(1);

            fromDb.Product.ShouldNotBeNull();
            fromDb.Product.Name.ShouldEqual("Name 1");

            fromDb.Category.ShouldNotBeNull();
            fromDb.Category.Name.ShouldEqual("Books");
        }
Exemple #3
0
        /// <summary>
        /// Import products from XLSX file
        /// </summary>
        /// <param name="stream">Stream</param>
        public virtual void ImportProductsFromXlsx(Stream stream)
        {
            //the columns
            var properties = new[]
            {
                    new PropertyByName<Product>("ProductTypeId"),
                    new PropertyByName<Product>("ParentGroupedProductId"),
                    new PropertyByName<Product>("VisibleIndividually"),
                    new PropertyByName<Product>("Name"),
                    new PropertyByName<Product>("ShortDescription"),
                    new PropertyByName<Product>("FullDescription"),
                    new PropertyByName<Product>("VendorId"),
                    new PropertyByName<Product>("ProductTemplateId"),
                    new PropertyByName<Product>("ShowOnHomePage"),
                    new PropertyByName<Product>("MetaKeywords"),
                    new PropertyByName<Product>("MetaDescription"),
                    new PropertyByName<Product>("MetaTitle"),
                    new PropertyByName<Product>("SeName"),
                    new PropertyByName<Product>("AllowCustomerReviews"),
                    new PropertyByName<Product>("Published"),
                    new PropertyByName<Product>("SKU"),
                    new PropertyByName<Product>("ManufacturerPartNumber"),
                    new PropertyByName<Product>("Gtin"),
                    new PropertyByName<Product>("IsGiftCard"),
                    new PropertyByName<Product>("GiftCardTypeId"),
                    new PropertyByName<Product>("OverriddenGiftCardAmount"),
                    new PropertyByName<Product>("RequireOtherProducts"),
                    new PropertyByName<Product>("RequiredProductIds"),
                    new PropertyByName<Product>("AutomaticallyAddRequiredProducts"),
                    new PropertyByName<Product>("IsDownload"),
                    new PropertyByName<Product>("DownloadId"),
                    new PropertyByName<Product>("UnlimitedDownloads"),
                    new PropertyByName<Product>("MaxNumberOfDownloads"),
                    new PropertyByName<Product>("DownloadActivationTypeId"),
                    new PropertyByName<Product>("HasSampleDownload"),
                    new PropertyByName<Product>("SampleDownloadId"),
                    new PropertyByName<Product>("HasUserAgreement"),
                    new PropertyByName<Product>("UserAgreementText"),
                    new PropertyByName<Product>("IsRecurring"),
                    new PropertyByName<Product>("RecurringCycleLength"),
                    new PropertyByName<Product>("RecurringCyclePeriodId"),
                    new PropertyByName<Product>("RecurringTotalCycles"),
                    new PropertyByName<Product>("IsRental"),
                    new PropertyByName<Product>("RentalPriceLength"),
                    new PropertyByName<Product>("RentalPricePeriodId"),
                    new PropertyByName<Product>("IsShipEnabled"),
                    new PropertyByName<Product>("IsFreeShipping"),
                    new PropertyByName<Product>("ShipSeparately"),
                    new PropertyByName<Product>("AdditionalShippingCharge"),
                    new PropertyByName<Product>("DeliveryDateId"),
                    new PropertyByName<Product>("IsTaxExempt"),
                    new PropertyByName<Product>("TaxCategoryId"),
                    new PropertyByName<Product>("IsTelecommunicationsOrBroadcastingOrElectronicServices"),
                    new PropertyByName<Product>("ManageInventoryMethodId"),
                    new PropertyByName<Product>("UseMultipleWarehouses"),
                    new PropertyByName<Product>("WarehouseId"),
                    new PropertyByName<Product>("StockQuantity"),
                    new PropertyByName<Product>("DisplayStockAvailability"),
                    new PropertyByName<Product>("DisplayStockQuantity"),
                    new PropertyByName<Product>("MinStockQuantity"),
                    new PropertyByName<Product>("LowStockActivityId"),
                    new PropertyByName<Product>("NotifyAdminForQuantityBelow"),
                    new PropertyByName<Product>("BackorderModeId"),
                    new PropertyByName<Product>("AllowBackInStockSubscriptions"),
                    new PropertyByName<Product>("OrderMinimumQuantity"),
                    new PropertyByName<Product>("OrderMaximumQuantity"),
                    new PropertyByName<Product>("AllowedQuantities"),
                    new PropertyByName<Product>("AllowAddingOnlyExistingAttributeCombinations"),
                    new PropertyByName<Product>("DisableBuyButton"),
                    new PropertyByName<Product>("DisableWishlistButton"),
                    new PropertyByName<Product>("AvailableForPreOrder"),
                    new PropertyByName<Product>("PreOrderAvailabilityStartDateTimeUtc"),
                    new PropertyByName<Product>("CallForPrice"),
                    new PropertyByName<Product>("Price"),
                    new PropertyByName<Product>("OldPrice"),
                    new PropertyByName<Product>("ProductCost"),
                    new PropertyByName<Product>("SpecialPrice"),
                    new PropertyByName<Product>("SpecialPriceStartDateTimeUtc"),
                    new PropertyByName<Product>("SpecialPriceEndDateTimeUtc"),
                    new PropertyByName<Product>("CustomerEntersPrice"),
                    new PropertyByName<Product>("MinimumCustomerEnteredPrice"),
                    new PropertyByName<Product>("MaximumCustomerEnteredPrice"),
                    new PropertyByName<Product>("BasepriceEnabled"),
                    new PropertyByName<Product>("BasepriceAmount"),
                    new PropertyByName<Product>("BasepriceUnitId"),
                    new PropertyByName<Product>("BasepriceBaseAmount"),
                    new PropertyByName<Product>("BasepriceBaseUnitId"),
                    new PropertyByName<Product>("MarkAsNew"),
                    new PropertyByName<Product>("MarkAsNewStartDateTimeUtc"),
                    new PropertyByName<Product>("MarkAsNewEndDateTimeUtc"),
                    new PropertyByName<Product>("Weight"),
                    new PropertyByName<Product>("Length"),
                    new PropertyByName<Product>("Width"),
                    new PropertyByName<Product>("Height"),
                    new PropertyByName<Product>("CategoryIds"),
                    new PropertyByName<Product>("ManufacturerIds"),
                    new PropertyByName<Product>("Picture1"),
                    new PropertyByName<Product>("Picture2"),
                    new PropertyByName<Product>("Picture3")
                };

            var manager = new PropertyManager<Product>(properties);

            // ok, we can run the real code of the sample now
            using (var xlPackage = new ExcelPackage(stream))
            {
                // get the first worksheet in the workbook
                var worksheet = xlPackage.Workbook.Worksheets.FirstOrDefault();
                if (worksheet == null)
                    throw new NopException("No worksheet found");

                int iRow = 2;
                while (true)
                {
                    var allColumnsAreEmpty = manager.GetProperties
                                            .Select(property => worksheet.Cells[iRow, property.PropertyOrderPosition])
                                            .All(cell => cell == null || cell.Value == null || String.IsNullOrEmpty(cell.Value.ToString()));

                    if (allColumnsAreEmpty)
                        break;

                    manager.ReadFromXlsx(worksheet, iRow);

                    var product = _productService.GetProductBySku(manager.GetProperty("SKU").StringValue);

                    var isNew = product == null;

                    product = product ?? new Product();

                    if (isNew)
                        product.CreatedOnUtc = DateTime.UtcNow;

                    product.ProductTypeId = manager.GetProperty("ProductTypeId").IntValue;
                    product.ParentGroupedProductId = manager.GetProperty("ParentGroupedProductId").IntValue;
                    product.VisibleIndividually = manager.GetProperty("VisibleIndividually").BooleanValue;
                    product.Name = manager.GetProperty("Name").StringValue;
                    product.ShortDescription = manager.GetProperty("ShortDescription").StringValue;
                    product.FullDescription = manager.GetProperty("FullDescription").StringValue;
                    product.VendorId = manager.GetProperty("VendorId").IntValue;
                    product.ProductTemplateId = manager.GetProperty("ProductTemplateId").IntValue;
                    product.ShowOnHomePage = manager.GetProperty("ShowOnHomePage").BooleanValue;
                    product.MetaKeywords = manager.GetProperty("MetaKeywords").StringValue;
                    product.MetaDescription = manager.GetProperty("MetaDescription").StringValue;
                    product.MetaTitle = manager.GetProperty("MetaTitle").StringValue;
                    var seName = manager.GetProperty("SeName").StringValue;
                    product.AllowCustomerReviews = manager.GetProperty("AllowCustomerReviews").BooleanValue;
                    product.Published = manager.GetProperty("Published").BooleanValue;
                    product.Sku = manager.GetProperty("SKU").StringValue;
                    product.ManufacturerPartNumber = manager.GetProperty("ManufacturerPartNumber").StringValue;
                    product.Gtin = manager.GetProperty("Gtin").StringValue;
                    product.IsGiftCard = manager.GetProperty("IsGiftCard").BooleanValue;
                    product.GiftCardTypeId = manager.GetProperty("GiftCardTypeId").IntValue;
                    product.OverriddenGiftCardAmount = manager.GetProperty("OverriddenGiftCardAmount").DecimalValue;
                    product.RequireOtherProducts = manager.GetProperty("RequireOtherProducts").BooleanValue;
                    product.RequiredProductIds = manager.GetProperty("RequiredProductIds").StringValue;
                    product.AutomaticallyAddRequiredProducts = manager.GetProperty("AutomaticallyAddRequiredProducts").BooleanValue;
                    product.IsDownload = manager.GetProperty("IsDownload").BooleanValue;
                    product.DownloadId = manager.GetProperty("DownloadId").IntValue;
                    product.UnlimitedDownloads = manager.GetProperty("UnlimitedDownloads").BooleanValue;
                    product.MaxNumberOfDownloads = manager.GetProperty("MaxNumberOfDownloads").IntValue;
                    product.DownloadActivationTypeId = manager.GetProperty("DownloadActivationTypeId").IntValue;
                    product.HasSampleDownload = manager.GetProperty("HasSampleDownload").BooleanValue;
                    product.SampleDownloadId = manager.GetProperty("SampleDownloadId").IntValue;
                    product.HasUserAgreement = manager.GetProperty("HasUserAgreement").BooleanValue;
                    product.UserAgreementText = manager.GetProperty("UserAgreementText").StringValue;
                    product.IsRecurring = manager.GetProperty("IsRecurring").BooleanValue;
                    product.RecurringCycleLength = manager.GetProperty("RecurringCycleLength").IntValue;
                    product.RecurringCyclePeriodId = manager.GetProperty("RecurringCyclePeriodId").IntValue;
                    product.RecurringTotalCycles = manager.GetProperty("RecurringTotalCycles").IntValue;
                    product.IsRental = manager.GetProperty("IsRental").BooleanValue;
                    product.RentalPriceLength = manager.GetProperty("RentalPriceLength").IntValue;
                    product.RentalPricePeriodId = manager.GetProperty("RentalPricePeriodId").IntValue;
                    product.IsShipEnabled = manager.GetProperty("IsShipEnabled").BooleanValue;
                    product.IsFreeShipping = manager.GetProperty("IsFreeShipping").BooleanValue;
                    product.ShipSeparately = manager.GetProperty("ShipSeparately").BooleanValue;
                    product.AdditionalShippingCharge = manager.GetProperty("AdditionalShippingCharge").DecimalValue;
                    product.DeliveryDateId = manager.GetProperty("DeliveryDateId").IntValue;
                    product.IsTaxExempt = manager.GetProperty("IsTaxExempt").BooleanValue;
                    product.TaxCategoryId = manager.GetProperty("TaxCategoryId").IntValue;
                    product.IsTelecommunicationsOrBroadcastingOrElectronicServices = manager.GetProperty("IsTelecommunicationsOrBroadcastingOrElectronicServices").BooleanValue;
                    product.ManageInventoryMethodId = manager.GetProperty("ManageInventoryMethodId").IntValue;
                    product.UseMultipleWarehouses = manager.GetProperty("UseMultipleWarehouses").BooleanValue;
                    product.WarehouseId = manager.GetProperty("WarehouseId").IntValue;
                    product.StockQuantity = manager.GetProperty("StockQuantity").IntValue;
                    product.DisplayStockAvailability = manager.GetProperty("DisplayStockAvailability").BooleanValue;
                    product.DisplayStockQuantity = manager.GetProperty("DisplayStockQuantity").BooleanValue;
                    product.MinStockQuantity = manager.GetProperty("MinStockQuantity").IntValue;
                    product.LowStockActivityId = manager.GetProperty("LowStockActivityId").IntValue;
                    product.NotifyAdminForQuantityBelow = manager.GetProperty("NotifyAdminForQuantityBelow").IntValue;
                    product.BackorderModeId = manager.GetProperty("BackorderModeId").IntValue;
                    product.AllowBackInStockSubscriptions = manager.GetProperty("AllowBackInStockSubscriptions").BooleanValue;
                    product.OrderMinimumQuantity = manager.GetProperty("OrderMinimumQuantity").IntValue;
                    product.OrderMaximumQuantity = manager.GetProperty("OrderMaximumQuantity").IntValue;
                    product.AllowedQuantities = manager.GetProperty("AllowedQuantities").StringValue;
                    product.AllowAddingOnlyExistingAttributeCombinations = manager.GetProperty("AllowAddingOnlyExistingAttributeCombinations").BooleanValue;
                    product.DisableBuyButton = manager.GetProperty("DisableBuyButton").BooleanValue;
                    product.DisableWishlistButton = manager.GetProperty("DisableWishlistButton").BooleanValue;
                    product.AvailableForPreOrder = manager.GetProperty("AvailableForPreOrder").BooleanValue;
                    product.PreOrderAvailabilityStartDateTimeUtc = manager.GetProperty("PreOrderAvailabilityStartDateTimeUtc").DateTimeNullable;
                    product.CallForPrice = manager.GetProperty("CallForPrice").BooleanValue;
                    product.Price = manager.GetProperty("Price").DecimalValue;
                    product.OldPrice = manager.GetProperty("OldPrice").DecimalValue;
                    product.ProductCost = manager.GetProperty("ProductCost").DecimalValue;
                    product.SpecialPrice = manager.GetProperty("SpecialPrice").DecimalValueNullable;
                    product.SpecialPriceStartDateTimeUtc = manager.GetProperty("SpecialPriceStartDateTimeUtc").DateTimeNullable;
                    product.SpecialPriceEndDateTimeUtc = manager.GetProperty("SpecialPriceEndDateTimeUtc").DateTimeNullable;
                    product.CustomerEntersPrice = manager.GetProperty("CustomerEntersPrice").BooleanValue;
                    product.MinimumCustomerEnteredPrice = manager.GetProperty("MinimumCustomerEnteredPrice").DecimalValue;
                    product.MaximumCustomerEnteredPrice = manager.GetProperty("MaximumCustomerEnteredPrice").DecimalValue;
                    product.BasepriceEnabled = manager.GetProperty("BasepriceEnabled").BooleanValue;
                    product.BasepriceAmount = manager.GetProperty("BasepriceAmount").DecimalValue;
                    product.BasepriceUnitId = manager.GetProperty("BasepriceUnitId").IntValue;
                    product.BasepriceBaseAmount = manager.GetProperty("BasepriceBaseAmount").DecimalValue;
                    product.BasepriceBaseUnitId = manager.GetProperty("BasepriceBaseUnitId").IntValue;
                    product.MarkAsNew = manager.GetProperty("MarkAsNew").BooleanValue;
                    product.MarkAsNewStartDateTimeUtc = manager.GetProperty("MarkAsNewStartDateTimeUtc").DateTimeNullable;
                    product.MarkAsNewEndDateTimeUtc = manager.GetProperty("MarkAsNewEndDateTimeUtc").DateTimeNullable;
                    product.Weight = manager.GetProperty("Weight").DecimalValue;
                    product.Length = manager.GetProperty("Length").DecimalValue;
                    product.Width = manager.GetProperty("Width").DecimalValue;
                    product.Height = manager.GetProperty("Height").DecimalValue;

                    var categoryIds = manager.GetProperty("CategoryIds").StringValue;
                    var manufacturerIds = manager.GetProperty("ManufacturerIds").StringValue;

                    var picture1 = manager.GetProperty("Picture1").StringValue;
                    var picture2 = manager.GetProperty("Picture2").StringValue;
                    var picture3 = manager.GetProperty("Picture3").StringValue;

                    product.UpdatedOnUtc = DateTime.UtcNow;

                    if (isNew)
                    {
                        _productService.InsertProduct(product);
                    }
                    else
                    {
                        _productService.UpdateProduct(product);
                    }

                    //search engine name
                    _urlRecordService.SaveSlug(product, product.ValidateSeName(seName, product.Name, true), 0);
                    var _seName = product.ValidateSeName(seName, product.Name, true);
                    //search engine name
                    _urlRecordService.SaveSlug(product, _seName, 0);
                    product.SeName = _seName;
                    _productService.UpdateProduct(product);
                    //category mappings
                    if (!String.IsNullOrEmpty(categoryIds))
                    {
                        foreach (var id in categoryIds.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())))
                        {
                            if (product.ProductCategories.FirstOrDefault(x => x.CategoryId == id) == null)
                            {
                                //ensure that category exists
                                var category = _categoryService.GetCategoryById(id);
                                if (category != null)
                                {
                                    var productCategory = new ProductCategory
                                    {
                                        _id = ObjectId.GenerateNewId().ToString(),
                                        Id = product.ProductCategories.Count > 0 ? product.ProductCategories.Max(x => x.Id) + 1 : 1,
                                        ProductId = product.Id,
                                        CategoryId = category.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _categoryService.InsertProductCategory(productCategory);
                                }
                            }
                        }
                    }

                    //manufacturer mappings
                    if (!String.IsNullOrEmpty(manufacturerIds))
                    {
                        foreach (var id in manufacturerIds.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())))
                        {
                            if (product.ProductManufacturers.FirstOrDefault(x => x.ManufacturerId == id) == null)
                            {
                                //ensure that manufacturer exists
                                var manufacturer = _manufacturerService.GetManufacturerById(id);
                                if (manufacturer != null)
                                {
                                    var productManufacturer = new ProductManufacturer
                                    {
                                        _id = ObjectId.GenerateNewId().ToString(),
                                        Id = product.ProductManufacturers.Count > 0 ? product.ProductManufacturers.Max(x => x.Id) + 1 : 1,
                                        ProductId = product.Id,
                                        ManufacturerId = manufacturer.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _manufacturerService.InsertProductManufacturer(productManufacturer);
                                }
                            }
                        }
                    }

                    //pictures
                    foreach (var picturePath in new[] { picture1, picture2, picture3 })
                    {
                        if (String.IsNullOrEmpty(picturePath))
                            continue;

                        var mimeType = GetMimeTypeFromFilePath(picturePath);
                        var newPictureBinary = File.ReadAllBytes(picturePath);
                        var pictureAlreadyExists = false;
                        if (!isNew)
                        {
                            //compare with existing product pictures
                            var existingPictures = product.ProductPictures;
                            foreach (var existingPicture in existingPictures)
                            {
                                var pp = _pictureService.GetPictureById(existingPicture.PictureId);
                                var existingBinary = _pictureService.LoadPictureBinary(pp);
                                //picture binary after validation (like in database)
                                var validatedPictureBinary = _pictureService.ValidatePicture(newPictureBinary, mimeType);
                                if (existingBinary.SequenceEqual(validatedPictureBinary) || existingBinary.SequenceEqual(newPictureBinary))
                                {
                                    //the same picture content
                                    pictureAlreadyExists = true;
                                    break;
                                }
                            }
                        }

                        if (!pictureAlreadyExists)
                        {
                            var picture = _pictureService.InsertPicture(newPictureBinary, mimeType, _pictureService.GetPictureSeName(product.Name));
                            var productPicture = new ProductPicture
                            {
                                Id = product.ProductPictures.Count > 0 ? product.ProductPictures.Max(x => x.Id) + 1 : 1,
                                _id = ObjectId.GenerateNewId().ToString(),
                                PictureId = picture.Id,
                                ProductId = product.Id,
                                DisplayOrder = 1,
                            };
                            //product.ProductPictures.Add(;
                            _productService.InsertProductPicture(productPicture);
                        }
                    }

                    //update "HasTierPrices" and "HasDiscountsApplied" properties
                    _productService.UpdateHasTierPricesProperty(product.Id);
                    _productService.UpdateHasDiscountsApplied(product.Id);

                    //next product
                    iRow++;
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Import products from XLSX file
        /// </summary>
        /// <param name="stream">Stream</param>
        public virtual void ImportProductsFromXlsx(Stream stream)
        {
            // ok, we can run the real code of the sample now
            using (var xlPackage = new ExcelPackage(stream))
            {
                // get the first worksheet in the workbook
                var worksheet = xlPackage.Workbook.Worksheets.FirstOrDefault();
                if (worksheet == null)
                    throw new NopException("No worksheet found");

                //the columns
                var properties = new []
                {
                    "ProductTypeId",
                    "ParentGroupedProductId",
                    "VisibleIndividually",
                    "Name",
                    "ShortDescription",
                    "FullDescription",
                    "VendorId",
                    "ProductTemplateId",
                    "ShowOnHomePage",
                    "MetaKeywords",
                    "MetaDescription",
                    "MetaTitle",
                    "SeName",
                    "AllowCustomerReviews",
                    "Published",
                    "SKU",
                    "ManufacturerPartNumber",
                    "Gtin",
                    "IsGiftCard",
                    "GiftCardTypeId",
                    "OverriddenGiftCardAmount",
                    "RequireOtherProducts",
                    "RequiredProductIds",
                    "AutomaticallyAddRequiredProducts",
                    "IsDownload",
                    "DownloadId",
                    "UnlimitedDownloads",
                    "MaxNumberOfDownloads",
                    "DownloadActivationTypeId",
                    "HasSampleDownload",
                    "SampleDownloadId",
                    "HasUserAgreement",
                    "UserAgreementText",
                    "IsRecurring",
                    "RecurringCycleLength",
                    "RecurringCyclePeriodId",
                    "RecurringTotalCycles",
                    "IsRental",
                    "RentalPriceLength",
                    "RentalPricePeriodId",
                    "IsShipEnabled",
                    "IsFreeShipping",
                    "ShipSeparately",
                    "AdditionalShippingCharge",
                    "DeliveryDateId",
                    "IsTaxExempt",
                    "TaxCategoryId",
                    "IsTelecommunicationsOrBroadcastingOrElectronicServices",
                    "ManageInventoryMethodId",
                    "UseMultipleWarehouses",
                    "WarehouseId",
                    "StockQuantity",
                    "DisplayStockAvailability",
                    "DisplayStockQuantity",
                    "MinStockQuantity",
                    "LowStockActivityId",
                    "NotifyAdminForQuantityBelow",
                    "BackorderModeId",
                    "AllowBackInStockSubscriptions",
                    "OrderMinimumQuantity",
                    "OrderMaximumQuantity",
                    "AllowedQuantities",
                    "AllowAddingOnlyExistingAttributeCombinations",
                    "DisableBuyButton",
                    "DisableWishlistButton",
                    "AvailableForPreOrder",
                    "PreOrderAvailabilityStartDateTimeUtc",
                    "CallForPrice",
                    "Price",
                    "OldPrice",
                    "ProductCost",
                    "SpecialPrice",
                    "SpecialPriceStartDateTimeUtc",
                    "SpecialPriceEndDateTimeUtc",
                    "CustomerEntersPrice",
                    "MinimumCustomerEnteredPrice",
                    "MaximumCustomerEnteredPrice",
                    "BasepriceEnabled",
                    "BasepriceAmount",
                    "BasepriceUnitId",
                    "BasepriceBaseAmount",
                    "BasepriceBaseUnitId",
                    "MarkAsNew",
                    "MarkAsNewStartDateTimeUtc",
                    "MarkAsNewEndDateTimeUtc",
                    "Weight",
                    "Length",
                    "Width",
                    "Height",
                    "CreatedOnUtc",
                    "CategoryIds",
                    "ManufacturerIds",
                    "Picture1",
                    "Picture2",
                    "Picture3"
                };


                int iRow = 2;
                while (true)
                {
                    bool allColumnsAreEmpty = true;
                    for (var i = 1; i <= properties.Length; i++)
                        if (worksheet.Cells[iRow, i].Value != null && !String.IsNullOrEmpty(worksheet.Cells[iRow, i].Value.ToString()))
                        {
                            allColumnsAreEmpty = false;
                            break;
                        }
                    if (allColumnsAreEmpty)
                        break;

                    int productTypeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ProductTypeId")].Value);
                    int parentGroupedProductId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ParentGroupedProductId")].Value);
                    bool visibleIndividually = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "VisibleIndividually")].Value);
                    string name = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Name")].Value);
                    string shortDescription = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ShortDescription")].Value);
                    string fullDescription = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "FullDescription")].Value);
                    int vendorId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "VendorId")].Value);
                    int productTemplateId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ProductTemplateId")].Value);
                    bool showOnHomePage = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "ShowOnHomePage")].Value);
                    string metaKeywords = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "MetaKeywords")].Value);
                    string metaDescription = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "MetaDescription")].Value);
                    string metaTitle = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "MetaTitle")].Value);
                    string seName = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "SeName")].Value);
                    bool allowCustomerReviews = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowCustomerReviews")].Value);
                    bool published = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "Published")].Value);
                    string sku = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "SKU")].Value);
                    string manufacturerPartNumber = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ManufacturerPartNumber")].Value);
                    string gtin = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Gtin")].Value);
                    bool isGiftCard = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsGiftCard")].Value);
                    int giftCardTypeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "GiftCardTypeId")].Value);
                    decimal? overriddenGiftCardAmount = null;
                    var overriddenGiftCardAmountExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "OverriddenGiftCardAmount")].Value;
                    if (overriddenGiftCardAmountExcel != null)
                        overriddenGiftCardAmount = Convert.ToDecimal(overriddenGiftCardAmountExcel);
                    bool requireOtherProducts = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "RequireOtherProducts")].Value);
                    string requiredProductIds = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "RequiredProductIds")].Value);
                    bool automaticallyAddRequiredProducts = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AutomaticallyAddRequiredProducts")].Value);
                    bool isDownload = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsDownload")].Value);
                    int downloadId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DownloadId")].Value);
                    bool unlimitedDownloads = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "UnlimitedDownloads")].Value);
                    int maxNumberOfDownloads = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "MaxNumberOfDownloads")].Value);
                    int downloadActivationTypeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DownloadActivationTypeId")].Value);
                    bool hasSampleDownload = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "HasSampleDownload")].Value);
                    int sampleDownloadId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "SampleDownloadId")].Value);
                    bool hasUserAgreement = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "HasUserAgreement")].Value);
                    string userAgreementText = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "UserAgreementText")].Value);
                    bool isRecurring = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsRecurring")].Value);
                    int recurringCycleLength = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringCycleLength")].Value);
                    int recurringCyclePeriodId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringCyclePeriodId")].Value);
                    int recurringTotalCycles = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringTotalCycles")].Value);
                    bool isRental = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsRental")].Value);
                    int rentalPriceLength = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RentalPriceLength")].Value);
                    int rentalPricePeriodId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RentalPricePeriodId")].Value);
                    bool isShipEnabled = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsShipEnabled")].Value);
                    bool isFreeShipping = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsFreeShipping")].Value);
                    bool shipSeparately = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "ShipSeparately")].Value);
                    decimal additionalShippingCharge = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "AdditionalShippingCharge")].Value);
                    int deliveryDateId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DeliveryDateId")].Value);
                    bool isTaxExempt = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsTaxExempt")].Value);
                    int taxCategoryId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "TaxCategoryId")].Value);
                    bool isTelecommunicationsOrBroadcastingOrElectronicServices = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsTelecommunicationsOrBroadcastingOrElectronicServices")].Value);
                    int manageInventoryMethodId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ManageInventoryMethodId")].Value);
                    bool useMultipleWarehouses = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "UseMultipleWarehouses")].Value);
                    int warehouseId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "WarehouseId")].Value);
                    int stockQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "StockQuantity")].Value);
                    bool displayStockAvailability = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisplayStockAvailability")].Value);
                    bool displayStockQuantity = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisplayStockQuantity")].Value);
                    int minStockQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "MinStockQuantity")].Value);
                    int lowStockActivityId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "LowStockActivityId")].Value);
                    int notifyAdminForQuantityBelow = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "NotifyAdminForQuantityBelow")].Value);
                    int backorderModeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "BackorderModeId")].Value);
                    bool allowBackInStockSubscriptions = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowBackInStockSubscriptions")].Value);
                    int orderMinimumQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "OrderMinimumQuantity")].Value);
                    int orderMaximumQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "OrderMaximumQuantity")].Value);
                    string allowedQuantities = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowedQuantities")].Value);
                    bool allowAddingOnlyExistingAttributeCombinations = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowAddingOnlyExistingAttributeCombinations")].Value);
                    bool disableBuyButton = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisableBuyButton")].Value);
                    bool disableWishlistButton = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisableWishlistButton")].Value);
                    bool availableForPreOrder = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AvailableForPreOrder")].Value);
                    DateTime? preOrderAvailabilityStartDateTimeUtc = null;
                    var preOrderAvailabilityStartDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "PreOrderAvailabilityStartDateTimeUtc")].Value;
                    if (preOrderAvailabilityStartDateTimeUtcExcel != null)
                        preOrderAvailabilityStartDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(preOrderAvailabilityStartDateTimeUtcExcel));
                    bool callForPrice = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "CallForPrice")].Value);
                    decimal price = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Price")].Value);
                    decimal oldPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "OldPrice")].Value);
                    decimal productCost = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "ProductCost")].Value);
                    decimal? specialPrice = null;
                    var specialPriceExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPrice")].Value;
                    if (specialPriceExcel != null)
                        specialPrice = Convert.ToDecimal(specialPriceExcel);
                    DateTime? specialPriceStartDateTimeUtc = null;
                    var specialPriceStartDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPriceStartDateTimeUtc")].Value;
                    if (specialPriceStartDateTimeUtcExcel != null)
                        specialPriceStartDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(specialPriceStartDateTimeUtcExcel));
                    DateTime? specialPriceEndDateTimeUtc = null;
                    var specialPriceEndDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPriceEndDateTimeUtc")].Value;
                    if (specialPriceEndDateTimeUtcExcel != null)
                        specialPriceEndDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(specialPriceEndDateTimeUtcExcel));

                    bool customerEntersPrice = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "CustomerEntersPrice")].Value);
                    decimal minimumCustomerEnteredPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "MinimumCustomerEnteredPrice")].Value);
                    decimal maximumCustomerEnteredPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "MaximumCustomerEnteredPrice")].Value);
                    bool basepriceEnabled = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "BasepriceEnabled")].Value);
                    decimal basepriceAmount = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "BasepriceAmount")].Value);
                    int basepriceUnitId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "BasepriceUnitId")].Value);
                    decimal basepriceBaseAmount = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "BasepriceBaseAmount")].Value);
                    int basepriceBaseUnitId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "BasepriceBaseUnitId")].Value);
                    bool markAsNew = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "MarkAsNew")].Value);
                    DateTime? markAsNewStartDateTimeUtc = null;
                    var markAsNewStartDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "MarkAsNewStartDateTimeUtc")].Value;
                    if (markAsNewStartDateTimeUtcExcel != null)
                        markAsNewStartDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(markAsNewStartDateTimeUtcExcel));
                    DateTime? markAsNewEndDateTimeUtc = null;
                    var markAsNewEndDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "MarkAsNewEndDateTimeUtc")].Value;
                    if (markAsNewEndDateTimeUtcExcel != null)
                        markAsNewEndDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(markAsNewEndDateTimeUtcExcel));
                    decimal weight = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Weight")].Value);
                    decimal length = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Length")].Value);
                    decimal width = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Width")].Value);
                    decimal height = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Height")].Value);
                    DateTime createdOnUtc = DateTime.FromOADate(Convert.ToDouble(worksheet.Cells[iRow, GetColumnIndex(properties, "CreatedOnUtc")].Value));
                    string categoryIds = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "CategoryIds")].Value);
                    string manufacturerIds = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ManufacturerIds")].Value);
                    string picture1 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Picture1")].Value);
                    string picture2 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Picture2")].Value);
                    string picture3 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Picture3")].Value);



                    var product = _productService.GetProductBySku(sku);
                    bool newProduct = false;
                    if (product == null)
                    {
                        product = new Product();
                        newProduct = true;
                    }
                    product.ProductTypeId = productTypeId;
                    product.ParentGroupedProductId = parentGroupedProductId;
                    product.VisibleIndividually = visibleIndividually;
                    product.Name = name;
                    product.ShortDescription = shortDescription;
                    product.FullDescription = fullDescription;
                    product.VendorId = vendorId;
                    product.ProductTemplateId = productTemplateId;
                    product.ShowOnHomePage = showOnHomePage;
                    product.MetaKeywords = metaKeywords;
                    product.MetaDescription = metaDescription;
                    product.MetaTitle = metaTitle;
                    product.AllowCustomerReviews = allowCustomerReviews;
                    product.Sku = sku;
                    product.ManufacturerPartNumber = manufacturerPartNumber;
                    product.Gtin = gtin;
                    product.IsGiftCard = isGiftCard;
                    product.GiftCardTypeId = giftCardTypeId;
                    product.OverriddenGiftCardAmount = overriddenGiftCardAmount;
                    product.RequireOtherProducts = requireOtherProducts;
                    product.RequiredProductIds = requiredProductIds;
                    product.AutomaticallyAddRequiredProducts = automaticallyAddRequiredProducts;
                    product.IsDownload = isDownload;
                    product.DownloadId = downloadId;
                    product.UnlimitedDownloads = unlimitedDownloads;
                    product.MaxNumberOfDownloads = maxNumberOfDownloads;
                    product.DownloadActivationTypeId = downloadActivationTypeId;
                    product.HasSampleDownload = hasSampleDownload;
                    product.SampleDownloadId = sampleDownloadId;
                    product.HasUserAgreement = hasUserAgreement;
                    product.UserAgreementText = userAgreementText;
                    product.IsRecurring = isRecurring;
                    product.RecurringCycleLength = recurringCycleLength;
                    product.RecurringCyclePeriodId = recurringCyclePeriodId;
                    product.RecurringTotalCycles = recurringTotalCycles;
                    product.IsRental = isRental;
                    product.RentalPriceLength = rentalPriceLength;
                    product.RentalPricePeriodId = rentalPricePeriodId;
                    product.IsShipEnabled = isShipEnabled;
                    product.IsFreeShipping = isFreeShipping;
                    product.ShipSeparately = shipSeparately;
                    product.AdditionalShippingCharge = additionalShippingCharge;
                    product.DeliveryDateId = deliveryDateId;
                    product.IsTaxExempt = isTaxExempt;
                    product.TaxCategoryId = taxCategoryId;
                    product.IsTelecommunicationsOrBroadcastingOrElectronicServices = isTelecommunicationsOrBroadcastingOrElectronicServices;
                    product.ManageInventoryMethodId = manageInventoryMethodId;
                    product.UseMultipleWarehouses = useMultipleWarehouses;
                    product.WarehouseId = warehouseId;
                    product.StockQuantity = stockQuantity;
                    product.DisplayStockAvailability = displayStockAvailability;
                    product.DisplayStockQuantity = displayStockQuantity;
                    product.MinStockQuantity = minStockQuantity;
                    product.LowStockActivityId = lowStockActivityId;
                    product.NotifyAdminForQuantityBelow = notifyAdminForQuantityBelow;
                    product.BackorderModeId = backorderModeId;
                    product.AllowBackInStockSubscriptions = allowBackInStockSubscriptions;
                    product.OrderMinimumQuantity = orderMinimumQuantity;
                    product.OrderMaximumQuantity = orderMaximumQuantity;
                    product.AllowedQuantities = allowedQuantities;
                    product.AllowAddingOnlyExistingAttributeCombinations = allowAddingOnlyExistingAttributeCombinations;
                    product.DisableBuyButton = disableBuyButton;
                    product.DisableWishlistButton = disableWishlistButton;
                    product.AvailableForPreOrder = availableForPreOrder;
                    product.PreOrderAvailabilityStartDateTimeUtc = preOrderAvailabilityStartDateTimeUtc;
                    product.CallForPrice = callForPrice;
                    product.Price = price;
                    product.OldPrice = oldPrice;
                    product.ProductCost = productCost;
                    product.SpecialPrice = specialPrice;
                    product.SpecialPriceStartDateTimeUtc = specialPriceStartDateTimeUtc;
                    product.SpecialPriceEndDateTimeUtc = specialPriceEndDateTimeUtc;
                    product.CustomerEntersPrice = customerEntersPrice;
                    product.MinimumCustomerEnteredPrice = minimumCustomerEnteredPrice;
                    product.MaximumCustomerEnteredPrice = maximumCustomerEnteredPrice;
                    product.BasepriceEnabled = basepriceEnabled;
                    product.BasepriceAmount = basepriceAmount;
                    product.BasepriceUnitId = basepriceUnitId;
                    product.BasepriceBaseAmount = basepriceBaseAmount;
                    product.BasepriceBaseUnitId = basepriceBaseUnitId;
                    product.MarkAsNew = markAsNew;
                    product.MarkAsNewStartDateTimeUtc = markAsNewStartDateTimeUtc;
                    product.MarkAsNewEndDateTimeUtc = markAsNewEndDateTimeUtc;
                    product.Weight = weight;
                    product.Length = length;
                    product.Width = width;
                    product.Height = height;
                    product.Published = published;
                    product.CreatedOnUtc = createdOnUtc;
                    product.UpdatedOnUtc = DateTime.UtcNow;
                    if (newProduct)
                    {
                        _productService.InsertProduct(product);
                    }
                    else
                    {
                        _productService.UpdateProduct(product);
                    }

                    //search engine name
                    _urlRecordService.SaveSlug(product, product.ValidateSeName(seName, product.Name, true), 0);

                    //category mappings
                    if (!String.IsNullOrEmpty(categoryIds))
                    {
                        foreach (var id in categoryIds.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())))
                        {
                            if (product.ProductCategories.FirstOrDefault(x => x.CategoryId == id) == null)
                            {
                                //ensure that category exists
                                var category = _categoryService.GetCategoryById(id);
                                if (category != null)
                                {
                                    var productCategory = new ProductCategory
                                    {
                                        ProductId = product.Id,
                                        CategoryId = category.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _categoryService.InsertProductCategory(productCategory);
                                }
                            }
                        }
                    }

                    //manufacturer mappings
                    if (!String.IsNullOrEmpty(manufacturerIds))
                    {
                        foreach (var id in manufacturerIds.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())))
                        {
                            if (product.ProductManufacturers.FirstOrDefault(x => x.ManufacturerId == id) == null)
                            {
                                //ensure that manufacturer exists
                                var manufacturer = _manufacturerService.GetManufacturerById(id);
                                if (manufacturer != null)
                                {
                                    var productManufacturer = new ProductManufacturer
                                    {
                                        ProductId = product.Id,
                                        ManufacturerId = manufacturer.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _manufacturerService.InsertProductManufacturer(productManufacturer);
                                }
                            }
                        }
                    }

                    //pictures
                    foreach (var picturePath in new [] { picture1, picture2, picture3 })
                    {
                        if (String.IsNullOrEmpty(picturePath))
                            continue;

                        var mimeType = GetMimeTypeFromFilePath(picturePath);
                        var newPictureBinary = File.ReadAllBytes(picturePath);
                        var pictureAlreadyExists = false;
                        if (!newProduct)
                        {
                            //compare with existing product pictures
                            var existingPictures = _pictureService.GetPicturesByProductId(product.Id);
                            foreach (var existingPicture in existingPictures)
                            {
                                var existingBinary = _pictureService.LoadPictureBinary(existingPicture);
                                //picture binary after validation (like in database)
                                var validatedPictureBinary = _pictureService.ValidatePicture(newPictureBinary, mimeType);
                                if (existingBinary.SequenceEqual(validatedPictureBinary) || existingBinary.SequenceEqual(newPictureBinary))
                                {
                                    //the same picture content
                                    pictureAlreadyExists = true;
                                    break;
                                }
                            }
                        }

                        if (!pictureAlreadyExists)
                        {
                            var newPicture = _pictureService.InsertPicture(newPictureBinary, mimeType , _pictureService.GetPictureSeName(name));
                            product.ProductPictures.Add(new ProductPicture
                            {
                                //EF has some weird issue if we set "Picture = newPicture" instead of "PictureId = newPicture.Id"
                                //pictures are duplicated
                                //maybe because entity size is too large
                                PictureId = newPicture.Id,
                                DisplayOrder = 1,
                            });
                            _productService.UpdateProduct(product);
                        }
                    }

                    //update "HasTierPrices" and "HasDiscountsApplied" properties
                    _productService.UpdateHasTierPricesProperty(product);
                    _productService.UpdateHasDiscountsApplied(product);



                    //next product
                    iRow++;
                }
            }
        }
        public ActionResult ProductCategoryInsert(GridCommand command, ProductModel.ProductCategoryModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageProducts))
                return AccessDeniedView();

            var productId = model.ProductId;
            var categoryId = Int32.Parse(model.Category); //use Category property (not CategoryId) because appropriate property is stored in it

            //a vendor should have access only to his products
            if (_workContext.CurrentVendor != null)
            {
                var product = _productService.GetProductById(productId);
                if (product != null && product.VendorId != _workContext.CurrentVendor.Id)
                {
                    return Content("This is not your product");
                }
            }

            var existingProductCategories = _categoryService.GetProductCategoriesByCategoryId(categoryId, 0, int.MaxValue, true);
            if (existingProductCategories.FindProductCategory(productId, categoryId) == null)
            {
                var productCategory = new ProductCategory()
                {
                    ProductId = productId,
                    CategoryId = categoryId,
                    DisplayOrder = model.DisplayOrder
                };
                //a vendor cannot edit "IsFeaturedProduct" property
                if (_workContext.CurrentVendor == null)
                {
                    productCategory.IsFeaturedProduct = model.IsFeaturedProduct;
                }
                _categoryService.InsertProductCategory(productCategory);
            }

            return ProductCategoryList(command, productId);
        }
        /// <summary>
        /// Creates a copy of product with all depended data
        /// </summary>
        /// <param name="productId">The product identifier</param>
        /// <param name="newName">The name of product duplicate</param>
        /// <param name="isPublished">A value indicating whether the product duplicate should be published</param>
        /// <param name="copyImages">A value indicating whether the product images should be copied</param>
        /// <returns>Product entity</returns>
        public Product CopyProduct(int productId, string newName, bool isPublished, bool copyImages)
        {
            var product = _productService.GetProductById(productId);
            if (product == null)
                throw new ArgumentException("No product found with the specified id", "productId");

            Product productCopy = null;
            //uncomment this line to support transactions
            //using (var scope = new System.Transactions.TransactionScope())
            {
                // product
                productCopy = new Product()
                {
                    Name = newName,
                    ShortDescription = product.ShortDescription,
                    FullDescription = product.FullDescription,
                    ProductTemplateId = product.ProductTemplateId,
                    AdminComment = product.AdminComment,
                    ShowOnHomePage = product.ShowOnHomePage,
                    MetaKeywords = product.MetaKeywords,
                    MetaDescription = product.MetaDescription,
                    MetaTitle = product.MetaTitle,
                    SeName = product.SeName,
                    AllowCustomerReviews = product.AllowCustomerReviews,
                    Published = isPublished,
                    Deleted = product.Deleted,
                    CreatedOnUtc = DateTime.UtcNow,
                    UpdatedOnUtc = DateTime.UtcNow
                };
                _productService.InsertProduct(productCopy);

                var languages = _languageService.GetAllLanguages(true);

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

                    var shortDescription = product.GetLocalized(x => x.ShortDescription, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(shortDescription))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.ShortDescription, shortDescription, lang.Id);

                    var fullDescription = product.GetLocalized(x => x.FullDescription, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(fullDescription))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.FullDescription, fullDescription, lang.Id);

                    var metaKeywords = product.GetLocalized(x => x.MetaKeywords, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(metaKeywords))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaKeywords, metaKeywords, lang.Id);

                    var metaDescription = product.GetLocalized(x => x.MetaDescription, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(metaDescription))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaDescription, metaDescription, lang.Id);

                    var metaTitle = product.GetLocalized(x => x.MetaTitle, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(metaTitle))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaTitle, metaTitle, lang.Id);

                    var seName = product.GetLocalized(x => x.SeName, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(seName))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.SeName, seName, lang.Id);
                }

                //product tags
                foreach (var productTag in product.ProductTags)
                {
                    productCopy.ProductTags.Add(productTag);
                }
                //ensure product is saved before updating totals
                _productService.UpdateProduct(product);
                foreach (var productTag in product.ProductTags)
                {
                    _productTagService.UpdateProductTagTotals(productTag);
                }

                // product pictures
                if (copyImages)
                {
                    foreach (var productPicture in product.ProductPictures)
                    {
                        var picture = productPicture.Picture;
                        var pictureCopy = _pictureService.InsertPicture(
                            _pictureService.LoadPictureBinary(picture),
                            picture.MimeType, 
                            _pictureService.GetPictureSeName(newName), 
                            true);
                        _productService.InsertProductPicture(new ProductPicture()
                        {
                            ProductId = productCopy.Id,
                            PictureId = pictureCopy.Id,
                            DisplayOrder = productPicture.DisplayOrder
                        });
                    }
                }

                // product <-> categories mappings
                foreach (var productCategory in product.ProductCategories)
                {
                    var productCategoryCopy = new ProductCategory()
                    {
                        ProductId = productCopy.Id,
                        CategoryId = productCategory.CategoryId,
                        IsFeaturedProduct = productCategory.IsFeaturedProduct,
                        DisplayOrder = productCategory.DisplayOrder
                    };

                    _categoryService.InsertProductCategory(productCategoryCopy);
                }

                // product <-> manufacturers mappings
                foreach (var productManufacturers in product.ProductManufacturers)
                {
                    var productManufacturerCopy = new ProductManufacturer()
                    {
                        ProductId = productCopy.Id,
                        ManufacturerId = productManufacturers.ManufacturerId,
                        IsFeaturedProduct = productManufacturers.IsFeaturedProduct,
                        DisplayOrder = productManufacturers.DisplayOrder
                    };

                    _manufacturerService.InsertProductManufacturer(productManufacturerCopy);
                }

                // product <-> releated products mappings
                foreach (var relatedProduct in _productService.GetRelatedProductsByProductId1(product.Id, true))
                {
                    _productService.InsertRelatedProduct(
                        new RelatedProduct()
                        {
                            ProductId1 = productCopy.Id,
                            ProductId2 = relatedProduct.ProductId2,
                            DisplayOrder = relatedProduct.DisplayOrder
                        });
                }

                // product <-> cross sells mappings
                foreach (var csProduct in _productService.GetCrossSellProductsByProductId1(product.Id, true))
                {
                    _productService.InsertCrossSellProduct(
                        new CrossSellProduct()
                        {
                            ProductId1 = productCopy.Id,
                            ProductId2 = csProduct.ProductId2,
                        });
                }

                // product specifications
                foreach (var productSpecificationAttribute in product.ProductSpecificationAttributes)
                {
                    var psaCopy = new ProductSpecificationAttribute()
                    {
                        ProductId = productCopy.Id,
                        SpecificationAttributeOptionId = productSpecificationAttribute.SpecificationAttributeOptionId,
                        AllowFiltering = productSpecificationAttribute.AllowFiltering,
                        ShowOnProductPage = productSpecificationAttribute.ShowOnProductPage,
                        DisplayOrder = productSpecificationAttribute.DisplayOrder
                    };
                    _specificationAttributeService.InsertProductSpecificationAttribute(psaCopy);
                }

                // product variants
                var productVariants = product.ProductVariants;
                foreach (var productVariant in productVariants)
                {
                    // product variant picture
                    int pictureId = 0;
                    if (copyImages)
                    {
                        var picture = _pictureService.GetPictureById(productVariant.PictureId);
                        if (picture != null)
                        {
                            var pictureCopy = _pictureService.InsertPicture(
                                _pictureService.LoadPictureBinary(picture), 
                                picture.MimeType, 
                                _pictureService.GetPictureSeName(productVariant.Name),
                                true);
                            pictureId = pictureCopy.Id;
                        }
                    }

                    // product variant download & sample download
                    int downloadId = productVariant.DownloadId;
                    int sampleDownloadId = productVariant.SampleDownloadId;
                    if (productVariant.IsDownload)
                    {
                        var download = _downloadService.GetDownloadById(productVariant.DownloadId);
                        if (download != null)
                        {
                            var downloadCopy = new Download()
                            {
                                DownloadGuid = Guid.NewGuid(),
                                UseDownloadUrl = download.UseDownloadUrl,
                                DownloadUrl = download.DownloadUrl,
                                DownloadBinary = download.DownloadBinary,
                                ContentType = download.ContentType,
                                Filename = download.Filename,
                                Extension = download.Extension,
                                IsNew = download.IsNew,
                            };
                            _downloadService.InsertDownload(downloadCopy);
                            downloadId = downloadCopy.Id;
                        }

                        if (productVariant.HasSampleDownload)
                        {
                            var sampleDownload = _downloadService.GetDownloadById(productVariant.SampleDownloadId);
                            if (sampleDownload != null)
                            {
                                var sampleDownloadCopy = new Download()
                                {
                                    DownloadGuid = Guid.NewGuid(),
                                    UseDownloadUrl = sampleDownload.UseDownloadUrl,
                                    DownloadUrl = sampleDownload.DownloadUrl,
                                    DownloadBinary = sampleDownload.DownloadBinary,
                                    ContentType = sampleDownload.ContentType,
                                    Filename = sampleDownload.Filename,
                                    Extension = sampleDownload.Extension,
                                    IsNew = sampleDownload.IsNew
                                };
                                _downloadService.InsertDownload(sampleDownloadCopy);
                                sampleDownloadId = sampleDownloadCopy.Id;
                            }
                        }
                    }

                    // product variant
                    var productVariantCopy = new ProductVariant()
                    {
                        ProductId = productCopy.Id,
                        Name = productVariant.Name,
                        Sku = productVariant.Sku,
                        Description = productVariant.Description,
                        AdminComment = productVariant.AdminComment,
                        ManufacturerPartNumber = productVariant.ManufacturerPartNumber,
                        Gtin = productVariant.Gtin,
                        IsGiftCard = productVariant.IsGiftCard,
                        GiftCardType = productVariant.GiftCardType,
                        RequireOtherProducts = productVariant.RequireOtherProducts,
                        RequiredProductVariantIds = productVariant.RequiredProductVariantIds,
                        AutomaticallyAddRequiredProductVariants = productVariant.AutomaticallyAddRequiredProductVariants,
                        IsDownload = productVariant.IsDownload,
                        DownloadId = downloadId,
                        UnlimitedDownloads = productVariant.UnlimitedDownloads,
                        MaxNumberOfDownloads = productVariant.MaxNumberOfDownloads,
                        DownloadExpirationDays = productVariant.DownloadExpirationDays,
                        DownloadActivationType = productVariant.DownloadActivationType,
                        HasSampleDownload = productVariant.HasSampleDownload,
                        SampleDownloadId = sampleDownloadId,
                        HasUserAgreement = productVariant.HasUserAgreement,
                        UserAgreementText = productVariant.UserAgreementText,
                        IsRecurring = productVariant.IsRecurring,
                        RecurringCycleLength = productVariant.RecurringCycleLength,
                        RecurringCyclePeriod = productVariant.RecurringCyclePeriod,
                        RecurringTotalCycles = productVariant.RecurringTotalCycles,
                        IsShipEnabled = productVariant.IsShipEnabled,
                        IsFreeShipping = productVariant.IsFreeShipping,
                        AdditionalShippingCharge = productVariant.AdditionalShippingCharge,
                        IsTaxExempt = productVariant.IsTaxExempt,
                        TaxCategoryId = productVariant.TaxCategoryId,
                        ManageInventoryMethod = productVariant.ManageInventoryMethod,
                        StockQuantity = productVariant.StockQuantity,
                        DisplayStockAvailability = productVariant.DisplayStockAvailability,
                        DisplayStockQuantity = productVariant.DisplayStockQuantity,
                        MinStockQuantity = productVariant.MinStockQuantity,
                        LowStockActivityId = productVariant.LowStockActivityId,
                        NotifyAdminForQuantityBelow = productVariant.NotifyAdminForQuantityBelow,
                        BackorderMode = productVariant.BackorderMode,
                        AllowBackInStockSubscriptions = productVariant.AllowBackInStockSubscriptions,
                        OrderMinimumQuantity = productVariant.OrderMinimumQuantity,
                        OrderMaximumQuantity = productVariant.OrderMaximumQuantity,
                        AllowedQuantities = productVariant.AllowedQuantities,
                        DisableBuyButton = productVariant.DisableBuyButton,
                        DisableWishlistButton = productVariant.DisableWishlistButton,
                        CallForPrice = productVariant.CallForPrice,
                        Price = productVariant.Price,
                        OldPrice = productVariant.OldPrice,
                        ProductCost = productVariant.ProductCost,
                        SpecialPrice = productVariant.SpecialPrice,
                        SpecialPriceStartDateTimeUtc = productVariant.SpecialPriceStartDateTimeUtc,
                        SpecialPriceEndDateTimeUtc = productVariant.SpecialPriceEndDateTimeUtc,
                        CustomerEntersPrice = productVariant.CustomerEntersPrice,
                        MinimumCustomerEnteredPrice = productVariant.MinimumCustomerEnteredPrice,
                        MaximumCustomerEnteredPrice = productVariant.MaximumCustomerEnteredPrice,
                        Weight = productVariant.Weight,
                        Length = productVariant.Length,
                        Width = productVariant.Width,
                        Height = productVariant.Height,
                        PictureId = pictureId,
                        AvailableStartDateTimeUtc = productVariant.AvailableStartDateTimeUtc,
                        AvailableEndDateTimeUtc = productVariant.AvailableEndDateTimeUtc,
                        Published = productVariant.Published,
                        Deleted = productVariant.Deleted,
                        DisplayOrder = productVariant.DisplayOrder,
                        CreatedOnUtc = DateTime.UtcNow,
                        UpdatedOnUtc = DateTime.UtcNow
                    };

                    _productService.InsertProductVariant(productVariantCopy);

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

                        var description = productVariant.GetLocalized(x => x.Description, lang.Id, false, false);
                        if (!String.IsNullOrEmpty(description))
                            _localizedEntityService.SaveLocalizedValue(productVariantCopy, x => x.Description, description, lang.Id);
                    }

                    // product variant <-> attributes mappings
                    var associatedAttributes = new Dictionary<int, int>();
                    var associatedAttributeValues = new Dictionary<int, int>();
                    foreach (var productVariantAttribute in _productAttributeService.GetProductVariantAttributesByProductVariantId(productVariant.Id))
                    {
                        var productVariantAttributeCopy = new ProductVariantAttribute()
                        {
                            ProductVariantId = productVariantCopy.Id,
                            ProductAttributeId = productVariantAttribute.ProductAttributeId,
                            TextPrompt = productVariantAttribute.TextPrompt,
                            IsRequired = productVariantAttribute.IsRequired,
                            AttributeControlTypeId = productVariantAttribute.AttributeControlTypeId,
                            DisplayOrder = productVariantAttribute.DisplayOrder
                        };
                        _productAttributeService.InsertProductVariantAttribute(productVariantAttributeCopy);
                        //save associated value (used for combinations copying)
                        associatedAttributes.Add(productVariantAttribute.Id, productVariantAttributeCopy.Id);

                        // product variant attribute values
                        var productVariantAttributeValues = _productAttributeService.GetProductVariantAttributeValues(productVariantAttribute.Id);
                        foreach (var productVariantAttributeValue in productVariantAttributeValues)
                        {
                            var pvavCopy = new ProductVariantAttributeValue()
                            {
                                ProductVariantAttributeId = productVariantAttributeCopy.Id,
                                Name = productVariantAttributeValue.Name,
                                PriceAdjustment = productVariantAttributeValue.PriceAdjustment,
                                WeightAdjustment = productVariantAttributeValue.WeightAdjustment,
                                IsPreSelected = productVariantAttributeValue.IsPreSelected,
                                DisplayOrder = productVariantAttributeValue.DisplayOrder
                            };
                            _productAttributeService.InsertProductVariantAttributeValue(pvavCopy);

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

                            //localization
                            foreach (var lang in languages)
                            {
                                var name = productVariantAttributeValue.GetLocalized(x => x.Name, lang.Id, false, false);
                                if (!String.IsNullOrEmpty(name))
                                    _localizedEntityService.SaveLocalizedValue(pvavCopy, x => x.Name, name, lang.Id);
                            }
                        }
                    }
                    foreach (var combination in _productAttributeService.GetAllProductVariantAttributeCombinations(productVariant.Id))
                    {
                        //generate new AttributesXml according to new value IDs
                        string newAttributesXml = "";
                        var parsedProductVariantAttributes = _productAttributeParser.ParseProductVariantAttributes(combination.AttributesXml);  
                        foreach (var oldPva in parsedProductVariantAttributes)
                        {
                            if (associatedAttributes.ContainsKey(oldPva.Id))
                            {
                                int newPvaId = associatedAttributes[oldPva.Id];
                                var newPva = _productAttributeService.GetProductVariantAttributeById(newPvaId);
                                if (newPva != null)
                                {
                                    var oldPvaValuesStr = _productAttributeParser.ParseValues(combination.AttributesXml, oldPva.Id);
                                    foreach (var oldPvaValueStr in oldPvaValuesStr)
                                    {
                                        if (newPva.ShouldHaveValues())
                                        {
                                            //attribute values
                                            int oldPvaValue = int.Parse(oldPvaValueStr);
                                            if (associatedAttributeValues.ContainsKey(oldPvaValue))
                                            {
                                                int newPvavId = associatedAttributeValues[oldPvaValue];
                                                var newPvav = _productAttributeService.GetProductVariantAttributeValueById(newPvavId);
                                                if (newPvav != null)
                                                {
                                                    newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml,
                                                        newPva, newPvav.Id.ToString());
                                                }
                                            }
                                        }
                                        else
                                        {
                                            //just a text
                                            newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, 
                                                newPva, oldPvaValueStr);
                                        }
                                    }
                                }
                            }
                        }
                        var combinationCopy = new ProductVariantAttributeCombination()
                        {
                            ProductVariantId = productVariantCopy.Id,
                            AttributesXml = newAttributesXml,
                            StockQuantity = combination.StockQuantity,
                            AllowOutOfStockOrders = combination.AllowOutOfStockOrders
                        };
                        _productAttributeService.InsertProductVariantAttributeCombination(combinationCopy);
                    }

                    // product variant tier prices
                    foreach (var tierPrice in productVariant.TierPrices)
                    {
                        _productService.InsertTierPrice(
                            new TierPrice()
                            {
                                ProductVariantId = productVariantCopy.Id,
                                CustomerRoleId = tierPrice.CustomerRoleId,
                                Quantity = tierPrice.Quantity,
                                Price = tierPrice.Price
                            });
                    }

                    // product variant <-> discounts mapping
                    foreach (var discount in productVariant.AppliedDiscounts)
                    {
                        productVariantCopy.AppliedDiscounts.Add(discount);
                        _productService.UpdateProductVariant(productVariantCopy);
                    }


                    //update "HasTierPrices" and "HasDiscountsApplied" properties
                    _productService.UpdateHasTierPricesProperty(productVariantCopy);
                    _productService.UpdateHasDiscountsApplied(productVariantCopy);
                }

                //uncomment this line to support transactions
                //scope.Complete();
            }

            return productCopy;
        }
        public ActionResult ProductCategoryInsert(GridCommand command, ProductModel.ProductCategoryModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
                return AccessDeniedView();

            var productId = model.ProductId;
            var categoryId = Int32.Parse(model.Category); //use Category property (not CategoryId) because appropriate property is stored in it

            var existingProductCategories = _categoryService.GetProductCategoriesByCategoryId(categoryId, 0, int.MaxValue, true);
            if (existingProductCategories.FindProductCategory(productId, categoryId) == null)
            {
                var productCategory = new ProductCategory()
                {
                    ProductId = productId,
                    CategoryId = categoryId,
                    IsFeaturedProduct = model.IsFeaturedProduct,
                    DisplayOrder = model.DisplayOrder
                };
                _categoryService.InsertProductCategory(productCategory);
            }

            return ProductCategoryList(command, productId);
        }
        public ActionResult EditIB(ProductModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageProducts))
                return AccessDeniedView();
            bool continueEditing = false;

            var product = _productService.GetProductById(model.Id);
            if (product == null || product.Deleted)
                //No product found with the specified id
                return RedirectToAction("List");

            model.ShowOnHomePage = true;
            model.ProductTypeId = 5;
            model.VisibleIndividually = true;
            model.ProductTemplateId = 1;
            model.Published = true;
            var catId = model.CategoryId;
            //a vendor should have access only to his products
            if (_workContext.CurrentVendor != null && product.VendorId != _workContext.CurrentVendor.Id)
                return RedirectToAction("List");

            if (ModelState.IsValid)
            {
                //a vendor should have access only to his products
                if (_workContext.CurrentVendor != null)
                {
                    model.VendorId = _workContext.CurrentVendor.Id;
                }

                var prevStockQuantity = product.GetTotalStockQuantity();

                //product
                product = model.ToEntity(product);
                product.UpdatedOnUtc = DateTime.UtcNow;
                _productService.UpdateProduct(product);
                //search engine name
                model.SeName = product.ValidateSeName(model.SeName, product.Name, true);
                _urlRecordService.SaveSlug(product, model.SeName, 0);
                //locales
                UpdateLocales(product, model);
                //tags
                SaveProductTags(product, ParseProductTags(model.ProductTags));
                //warehouses
                SaveProductWarehouseInventory(product, model);
                //ACL (customer roles)
                SaveProductAcl(product, model);
                //Stores
                SaveStoreMappings(product, model);
                //picture seo names
                UpdatePictureSeoNames(product);
                //discounts
                var allDiscounts = _discountService.GetAllDiscounts(DiscountType.AssignedToSkus, showHidden: true);
                foreach (var discount in allDiscounts)
                {
                    if (model.SelectedDiscountIds != null && model.SelectedDiscountIds.Contains(discount.Id))
                    {
                        //new discount
                        if (product.AppliedDiscounts.Count(d => d.Id == discount.Id) == 0)
                            product.AppliedDiscounts.Add(discount);
                    }
                    else
                    {
                        //remove discount
                        if (product.AppliedDiscounts.Count(d => d.Id == discount.Id) > 0)
                            product.AppliedDiscounts.Remove(discount);
                    }
                }
                if(catId>0)
                {
                    // delete existing category
                    var extCat = _categoryService.GetProductCategoriesByProductId(product.Id,true);
                    if(extCat.Count >0 && !extCat.Any(c=>c.CategoryId == catId))
                    {
                        foreach (var item in extCat)
                        {
                            _categoryService.DeleteProductCategory(item);
                        }

                    }
                    var categoryMapping = new ProductCategory();
                    categoryMapping.CategoryId = catId;
                    categoryMapping.ProductId = product.Id;
                    categoryMapping.DisplayOrder = 1;
                    _categoryService.InsertProductCategory(categoryMapping);

                }
                _productService.UpdateProduct(product);
                _productService.UpdateHasDiscountsApplied(product);
                //back in stock notifications
                if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock &&
                    product.BackorderMode == BackorderMode.NoBackorders &&
                    product.AllowBackInStockSubscriptions &&
                    product.GetTotalStockQuantity() > 0 &&
                    prevStockQuantity <= 0 &&
                    product.Published &&
                    !product.Deleted)
                {
                    _backInStockSubscriptionService.SendNotificationsToSubscribers(product);
                }

                //activity log
                _customerActivityService.InsertActivity("EditProduct", _localizationService.GetResource("ActivityLog.EditProduct"), product.Name);

                SuccessNotification(_localizationService.GetResource("Admin.Catalog.Products.Updated"));

                if (continueEditing)
                {
                    //selected tab
                    SaveSelectedTabIndex();

                    return RedirectToAction("Editib", new { id = product.Id });
                }
                if(_workContext.CurrentVendor != null )
                    return RedirectToAction("myhome", "vendor", new { id = product.VendorId });
                return RedirectToAction("List");
            }

            //If we got this far, something failed, redisplay form
            PrepareProductModel(model, product, false, true);
            PrepareAclModel(model, product, true);
            PrepareStoresMappingModel(model, product, true);
            return View(model);
        }
        /// <summary>
        /// Create a copy of product with all depended data
        /// </summary>
        /// <param name="product">The product to copy</param>
        /// <param name="newName">The name of product duplicate</param>
        /// <param name="isPublished">A value indicating whether the product duplicate should be published</param>
        /// <param name="copyImages">A value indicating whether the product images should be copied</param>
        /// <returns>Product copy</returns>
        public virtual Product CopyProduct(Product product, string newName, bool isPublished, bool copyImages)
        {
            if (product == null)
                throw new ArgumentNullException("product");

            if (String.IsNullOrEmpty(newName))
                throw new ArgumentException("Product name is required");

            Product productCopy = null;
            //uncomment this line to support transactions
            //using (var scope = new System.Transactions.TransactionScope())
            {
                // product
                productCopy = new Product()
                {
                    Name = newName,
                    ShortDescription = product.ShortDescription,
                    FullDescription = product.FullDescription,
                    VendorId = product.VendorId,
                    ProductTemplateId = product.ProductTemplateId,
                    AdminComment = product.AdminComment,
                    ShowOnHomePage = product.ShowOnHomePage,
                    MetaKeywords = product.MetaKeywords,
                    MetaDescription = product.MetaDescription,
                    MetaTitle = product.MetaTitle,
                    AllowCustomerReviews = product.AllowCustomerReviews,
                    LimitedToStores = product.LimitedToStores,
                    Published = isPublished,
                    Deleted = product.Deleted,
                    CreatedOnUtc = DateTime.UtcNow,
                    UpdatedOnUtc = DateTime.UtcNow
                };

                //validate search engine name
                _productService.InsertProduct(productCopy);

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

                var languages = _languageService.GetAllLanguages(true);

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

                    var shortDescription = product.GetLocalized(x => x.ShortDescription, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(shortDescription))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.ShortDescription, shortDescription, lang.Id);

                    var fullDescription = product.GetLocalized(x => x.FullDescription, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(fullDescription))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.FullDescription, fullDescription, lang.Id);

                    var metaKeywords = product.GetLocalized(x => x.MetaKeywords, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(metaKeywords))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaKeywords, metaKeywords, lang.Id);

                    var metaDescription = product.GetLocalized(x => x.MetaDescription, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(metaDescription))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaDescription, metaDescription, lang.Id);

                    var metaTitle = product.GetLocalized(x => x.MetaTitle, lang.Id, false, false);
                    if (!String.IsNullOrEmpty(metaTitle))
                        _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaTitle, metaTitle, lang.Id);

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

                //product tags
                foreach (var productTag in product.ProductTags)
                {
                    productCopy.ProductTags.Add(productTag);
                }
                _productService.UpdateProduct(product);

                // product pictures
                if (copyImages)
                {
                    foreach (var productPicture in product.ProductPictures)
                    {
                        var picture = productPicture.Picture;
                        var pictureCopy = _pictureService.InsertPicture(
                            _pictureService.LoadPictureBinary(picture),
                            picture.MimeType,
                            _pictureService.GetPictureSeName(newName),
                            true);
                        _productService.InsertProductPicture(new ProductPicture()
                        {
                            ProductId = productCopy.Id,
                            PictureId = pictureCopy.Id,
                            DisplayOrder = productPicture.DisplayOrder
                        });
                    }
                }

                // product <-> categories mappings
                foreach (var productCategory in product.ProductCategories)
                {
                    var productCategoryCopy = new ProductCategory()
                    {
                        ProductId = productCopy.Id,
                        CategoryId = productCategory.CategoryId,
                        IsFeaturedProduct = productCategory.IsFeaturedProduct,
                        DisplayOrder = productCategory.DisplayOrder
                    };

                    _categoryService.InsertProductCategory(productCategoryCopy);
                }

                // product <-> manufacturers mappings
                foreach (var productManufacturers in product.ProductManufacturers)
                {
                    var productManufacturerCopy = new ProductManufacturer()
                    {
                        ProductId = productCopy.Id,
                        ManufacturerId = productManufacturers.ManufacturerId,
                        IsFeaturedProduct = productManufacturers.IsFeaturedProduct,
                        DisplayOrder = productManufacturers.DisplayOrder
                    };

                    _manufacturerService.InsertProductManufacturer(productManufacturerCopy);
                }

                // product <-> releated products mappings
                foreach (var relatedProduct in _productService.GetRelatedProductsByProductId1(product.Id, true))
                {
                    _productService.InsertRelatedProduct(
                        new RelatedProduct()
                        {
                            ProductId1 = productCopy.Id,
                            ProductId2 = relatedProduct.ProductId2,
                            DisplayOrder = relatedProduct.DisplayOrder
                        });
                }

                // product <-> cross sells mappings
                foreach (var csProduct in _productService.GetCrossSellProductsByProductId1(product.Id, true))
                {
                    _productService.InsertCrossSellProduct(
                        new CrossSellProduct()
                        {
                            ProductId1 = productCopy.Id,
                            ProductId2 = csProduct.ProductId2,
                        });
                }

                // product specifications
                foreach (var productSpecificationAttribute in product.ProductSpecificationAttributes)
                {
                    var psaCopy = new ProductSpecificationAttribute()
                    {
                        ProductId = productCopy.Id,
                        SpecificationAttributeOptionId = productSpecificationAttribute.SpecificationAttributeOptionId,
                        AllowFiltering = productSpecificationAttribute.AllowFiltering,
                        ShowOnProductPage = productSpecificationAttribute.ShowOnProductPage,
                        DisplayOrder = productSpecificationAttribute.DisplayOrder
                    };
                    _specificationAttributeService.InsertProductSpecificationAttribute(psaCopy);
                }

                //store mapping
                var selectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(product);
                foreach (var id in selectedStoreIds)
                {
                    _storeMappingService.InsertStoreMapping(productCopy, id);
                }

                // product variants
                var productVariants = product.ProductVariants;
                foreach (var productVariant in productVariants)
                {
                    CopyProductVariant(productVariant, productCopy.Id, productVariant.Name, productVariant.Published, copyImages);
                }

                //uncomment this line to support transactions
                //scope.Complete();
            }

            return productCopy;
        }
        private void ResolveProductCategories(ProductResolveInput input, Product product)
        {
            List<Category> categories = ResolveCategories(input);
            IEnumerable<Category> filteredCategories = categories.Any(x => x.ParentCategoryId != 0)
                ? categories.Where(x => x.ParentCategoryId != 0)
                : categories;

            foreach (Category category in filteredCategories)
            {
                if (product.ProductCategories.FirstOrDefault(x => x.CategoryId == category.Id) == null)
                {
                    var productCategory = new ProductCategory
                    {
                        ProductId = product.Id,
                        CategoryId = category.Id,
                        IsFeaturedProduct = false,
                        DisplayOrder = 1,
                    };
                    _categoryService.InsertProductCategory(productCategory);
                }
            }
        }
        /// <summary>
        /// Updates the product category mapping 
        /// </summary>
        /// <param name="productCategory">>Product category mapping</param>
        public virtual void UpdateProductCategory(ProductCategory productCategory)
        {
            if (productCategory == null)
                throw new ArgumentNullException("productCategory");

            //_productCategoryRepository.Update(productCategory);

            var builder = Builders<Product>.Filter;
            var filter = builder.Eq(x => x.Id, productCategory.ProductId);
            filter = filter & builder.Where(x => x.ProductCategories.Any(y => y.Id == productCategory.Id));
            var update = Builders<Product>.Update
                .Set(x => x.ProductCategories.ElementAt(-1).CategoryId, productCategory.CategoryId)
                .Set(x => x.ProductCategories.ElementAt(-1).IsFeaturedProduct, productCategory.IsFeaturedProduct)
                .Set(x => x.ProductCategories.ElementAt(-1).DisplayOrder, productCategory.DisplayOrder);

            var result = _productRepository.Collection.UpdateManyAsync(filter, update).Result;

            //var result = collectionProduct.UpdateManyAsync(filter, update).Result;


            //cache
            _cacheManager.RemoveByPattern(CATEGORIES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTCATEGORIES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(string.Format(PRODUCTS_BY_ID_KEY, productCategory.ProductId));

            //event notification
            _eventPublisher.EntityUpdated(productCategory);
        }
        /// <summary>
        /// Inserts a product category mapping
        /// </summary>
        /// <param name="productCategory">>Product category mapping</param>
        public virtual void InsertProductCategory(ProductCategory productCategory)
        {
            if (productCategory == null)
                throw new ArgumentNullException("productCategory");

            var updatebuilder = Builders<Product>.Update;
            var update = updatebuilder.AddToSet(p => p.ProductCategories, productCategory);
            _productRepository.Collection.UpdateOneAsync(new BsonDocument("Id", productCategory.ProductId), update);

            //cache
            _cacheManager.RemoveByPattern(CATEGORIES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(PRODUCTCATEGORIES_PATTERN_KEY);
            _cacheManager.RemoveByPattern(string.Format(PRODUCTS_BY_ID_KEY, productCategory.ProductId));

            //event notification
            _eventPublisher.EntityInserted(productCategory);
        }
        public virtual void ImportPhilatelicProductsFromXlsx(Stream stream)
        {
            var CurrentCustomer = _authenticationService.GetAuthenticatedCustomer();
            string logError = string.Format("Lot Import: Beginning Lot Import by User: {0}.", CurrentCustomer.Username);
            _logger.InsertLog(LogLevel.Information, logError);
            
            //Get all of the specification attributes so you can get ids for spec attribute and option id later
            bool optionExists = false;
            bool specExists = false;

            int specMaterialType = 0;
            int specMaterialTypeDisplayOrder = 0;
            int specFormat = 0;
            int specFormatDisplayOrder = 0;
            int specFormFactor = 0;
            int specFormFactorDisplayOrder = 0;
            int specUsageState = 0;
            int specUsageStateDisplayOrder = 0;
            int specGrade = 0;
            int specGradeDisplayOrder = 0;
            int specSymbolSummary = 0;
            int specSymbolSummaryDisplayOrder = 0;

            // int saleErrorCnt = 0;
            //bool junctionExists = false;
            AUSaleLotRecord sl = null;
            AUSaleRecord csale = null;


            var specAttributes = _specificationAttributeRepo.Table.ToList();
                foreach (SpecificationAttribute sa in specAttributes)
            {
                //Names are kept with space between words for customer display purposes - internal fields remove space
                switch (sa.Name) {
                    case "Material Type":
                        specMaterialType = sa.Id;
                        specMaterialTypeDisplayOrder = sa.DisplayOrder;
                        break;
                    case "Format": 
                        specFormat = sa.Id;
                        specFormatDisplayOrder = sa.DisplayOrder;
                        break;
                    case "Form Factor": 
                        specFormFactor = sa.Id;
                        specFormFactorDisplayOrder = sa.DisplayOrder;
                        break;
                    case "Usage State": 
                        specUsageState = sa.Id;
                        specUsageStateDisplayOrder = sa.DisplayOrder;
                        break;
                    case "Grade": 
                        specGrade = sa.Id;
                        specGradeDisplayOrder = sa.DisplayOrder;
                        break;
                    case "Symbol Summary":
                        specSymbolSummary = sa.Id;
                        specSymbolSummaryDisplayOrder = sa.DisplayOrder;
                        break;
                    default: 
                        logError = string.Format("Lot Import: A product specification attribute was found that is not accounted for in the import: {0}/Id:{1}.", sa.Name, sa.Id);
                        _logger.InsertLog(LogLevel.Warning, logError);
                        break;
                }

            }


            // ok, we can run the real code of the sample now
            using (var xlPackage = new ExcelPackage(stream))
            {
                // get the first worksheet in the workbook
                var worksheet = xlPackage.Workbook.Worksheets.FirstOrDefault();
                if (worksheet == null)
                    throw new NopException("No Philatelic worksheet found");

                int totalerrors = 0;
                int recordsaddchanged = 0;
                int recordsignored = 0;

                //the columns
                var properties = new[]
                {
                    "ProductTypeId",
                    "ParentGroupedProductId",
                    "VisibleIndividually",
                    "Name",
                    "ShortDescription",
                    "FullDescription",
                    "VendorId",
                    "ProductTemplateId",
                    "ShowOnHomePage",
                    "MetaKeywords",
                    "MetaDescription",
                    "MetaTitle",
                    "SeName",
                    "AllowCustomerReviews",
                    "Published",
                    "SKU",
                    "ManufacturerPartNumber",
                    "Gtin",
                    "IsGiftCard",
                    "GiftCardTypeId",
                    "RequireOtherProducts",
                    "RequiredProductIds",
                    "AutomaticallyAddRequiredProducts",
                    "IsDownload",
                    "DownloadId",
                    "UnlimitedDownloads",
                    "MaxNumberOfDownloads",
                    "DownloadActivationTypeId",
                    "HasSampleDownload",
                    "SampleDownloadId",
                    "HasUserAgreement",
                    "UserAgreementText",
                    "IsRecurring",
                    "RecurringCycleLength",
                    "RecurringCyclePeriodId",
                    "RecurringTotalCycles",
                    "IsRental",
                    "RentalPriceLength",
                    "RentalPricePeriodId",
                    "IsShipEnabled",
                    "IsFreeShipping",
                    "ShipSeparately",
                    "AdditionalShippingCharge",
                    "DeliveryDateId",
                    "IsTaxExempt",
                    "TaxCategoryId",
                    "IsTelecommunicationsOrBroadcastingOrElectronicServices",
                    "ManageInventoryMethodId",
                    "UseMultipleWarehouses",
                    "WarehouseId",
                    "StockQuantity",
                    "DisplayStockAvailability",
                    "DisplayStockQuantity",
                    "MinStockQuantity",
                    "LowStockActivityId",
                    "NotifyAdminForQuantityBelow",
                    "BackorderModeId",
                    "AllowBackInStockSubscriptions",
                    "OrderMinimumQuantity",
                    "OrderMaximumQuantity",
                    "AllowedQuantities",
                    "AllowAddingOnlyExistingAttributeCombinations",
                    "DisableBuyButton",
                    "DisableWishlistButton",
                    "AvailableForPreOrder",
                    "PreOrderAvailabilityStartDateTimeUtc",
                    "CallForPrice",
                    "Price",
                    "OldPrice",
                    "ProductCost",
                    "SpecialPrice",
                    "SpecialPriceStartDateTimeUtc",
                    "SpecialPriceEndDateTimeUtc",
                    "CustomerEntersPrice",
                    "MinimumCustomerEnteredPrice",
                    "MaximumCustomerEnteredPrice",
                    "Weight",
                    "Length",
                    "Width",
                    "Height",
                    "CreatedOnUtc",
                    "CategoryIds",
                    "ManufacturerIds",
                    "Picture1",
                    "Picture2",
                    "Picture3",
                                                           
                    "SaleNbr",                  //NJM: BEGIN OF PHILATELIC PORTION
                    "LotNbr",
                    "DisplayOrder",
                    "ConsignmentId",
                    "MaterialType",
                    "Country1",
                    "StateProvince1",
                    "Country2",
                    "StateProvince2",
                    "Country3",
                    "StateProvince3",
                    "Format",
                    "FormFactor",
                    "UsageState",
                    "Grade",
                    "ReserveAmt",
                    "EstimatedLowBidAmt",
                    "EstimatedHighBidAmt",
                    "EstimatedRealizationAmt",
                    "OpeningBidAmt",
                    "SymbolSummary",
                    "ReferenceId1",
                    "ReferenceNbr1",
                    "ReferenceValue1",
                    "ReferenceId2",
                    "ReferenceNbr2",
                    "ReferenceValue2",
                    "ReferenceId3",
                    "ReferenceNbr3",
                    "ReferenceValue3"
                };

                
                //_logger.InsertLog(LogLevel.Information, "Finished Import mapping");

                int iRow = 2;
                while (true)
                {
                    totalerrors = 0; //reset initial edit-error count

                    bool allColumnsAreEmpty = true;
                    for (var i = 1; i <= properties.Length; i++)
                        if (worksheet.Cells[iRow, i].Value != null && !String.IsNullOrEmpty(worksheet.Cells[iRow, i].Value.ToString()))
                        {
                            allColumnsAreEmpty = false;
                            break;
                        }
                    if (allColumnsAreEmpty)
                    {
                       
                        logError = string.Format("Lot Import: Ignoring empty row#{0}.", iRow);
                        _logger.InsertLog(LogLevel.Information, logError);
                        break;
                    }

                   

                    //_logger.InsertLog(LogLevel.Information, "Import load data record:" + iRow.ToString());

                    int productTypeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ProductTypeId")].Value);
                    int parentGroupedProductId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ParentGroupedProductId")].Value);
                    bool visibleIndividually = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "VisibleIndividually")].Value);
                    string name = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Name")].Value);
                    string shortDescription = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ShortDescription")].Value);
                    string fullDescription = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "FullDescription")].Value);
                    int vendorId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "VendorId")].Value);
                    int productTemplateId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ProductTemplateId")].Value);
                    bool showOnHomePage = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "ShowOnHomePage")].Value);
                    string metaKeywords = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "MetaKeywords")].Value);
                    string metaDescription = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "MetaDescription")].Value);
                    string metaTitle = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "MetaTitle")].Value);
                    string seName = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "SeName")].Value);
                    bool allowCustomerReviews = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowCustomerReviews")].Value);
                    bool published = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "Published")].Value);
                    string sku = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "SKU")].Value);
                    string manufacturerPartNumber = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ManufacturerPartNumber")].Value);
                    string gtin = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Gtin")].Value);
                    bool isGiftCard = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsGiftCard")].Value);
                    int giftCardTypeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "GiftCardTypeId")].Value);
                    bool requireOtherProducts = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "RequireOtherProducts")].Value);
                    string requiredProductIds = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "RequiredProductIds")].Value);
                    bool automaticallyAddRequiredProducts = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AutomaticallyAddRequiredProducts")].Value);
                    bool isDownload = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsDownload")].Value);
                    int downloadId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DownloadId")].Value);
                    bool unlimitedDownloads = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "UnlimitedDownloads")].Value);
                    int maxNumberOfDownloads = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "MaxNumberOfDownloads")].Value);
                    int downloadActivationTypeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DownloadActivationTypeId")].Value);
                    bool hasSampleDownload = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "HasSampleDownload")].Value);
                    int sampleDownloadId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "SampleDownloadId")].Value);
                    bool hasUserAgreement = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "HasUserAgreement")].Value);
                    string userAgreementText = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "UserAgreementText")].Value);
                    bool isRecurring = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsRecurring")].Value);
                    int recurringCycleLength = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringCycleLength")].Value);
                    int recurringCyclePeriodId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringCyclePeriodId")].Value);
                    int recurringTotalCycles = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringTotalCycles")].Value);
                    bool isRental = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsRental")].Value);
                    int rentalPriceLength = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RentalPriceLength")].Value);
                    int rentalPricePeriodId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RentalPricePeriodId")].Value);
                    bool isShipEnabled = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsShipEnabled")].Value);
                    bool isFreeShipping = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsFreeShipping")].Value);
                    bool shipSeparately = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "ShipSeparately")].Value);
                    decimal additionalShippingCharge = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "AdditionalShippingCharge")].Value);
                    int deliveryDateId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DeliveryDateId")].Value);
                    bool isTaxExempt = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsTaxExempt")].Value);
                    int taxCategoryId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "TaxCategoryId")].Value);
                    bool isTelecommunicationsOrBroadcastingOrElectronicServices = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsTelecommunicationsOrBroadcastingOrElectronicServices")].Value);
                    int manageInventoryMethodId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ManageInventoryMethodId")].Value);
                    bool useMultipleWarehouses = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "UseMultipleWarehouses")].Value);
                    int warehouseId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "WarehouseId")].Value);
                    int stockQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "StockQuantity")].Value);
                    bool displayStockAvailability = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisplayStockAvailability")].Value);
                    bool displayStockQuantity = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisplayStockQuantity")].Value);
                    int minStockQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "MinStockQuantity")].Value);
                    int lowStockActivityId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "LowStockActivityId")].Value);
                    int notifyAdminForQuantityBelow = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "NotifyAdminForQuantityBelow")].Value);
                    int backorderModeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "BackorderModeId")].Value);
                    bool allowBackInStockSubscriptions = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowBackInStockSubscriptions")].Value);
                    int orderMinimumQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "OrderMinimumQuantity")].Value);
                    int orderMaximumQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "OrderMaximumQuantity")].Value);
                    string allowedQuantities = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowedQuantities")].Value);
                    bool allowAddingOnlyExistingAttributeCombinations = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowAddingOnlyExistingAttributeCombinations")].Value);
                    bool disableBuyButton = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisableBuyButton")].Value);
                    bool disableWishlistButton = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisableWishlistButton")].Value);
                    bool availableForPreOrder = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AvailableForPreOrder")].Value);
                    DateTime? preOrderAvailabilityStartDateTimeUtc = null;
                    var preOrderAvailabilityStartDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "PreOrderAvailabilityStartDateTimeUtc")].Value;
                    if (preOrderAvailabilityStartDateTimeUtcExcel != null)
                        preOrderAvailabilityStartDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(preOrderAvailabilityStartDateTimeUtcExcel));
                    bool callForPrice = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "CallForPrice")].Value);
                    decimal price = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Price")].Value);
                    decimal oldPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "OldPrice")].Value);
                    decimal productCost = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "ProductCost")].Value);
                    decimal? specialPrice = null;
                    var specialPriceExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPrice")].Value;
                    if (specialPriceExcel != null)
                        specialPrice = Convert.ToDecimal(specialPriceExcel);
                    DateTime? specialPriceStartDateTimeUtc = null;
                    var specialPriceStartDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPriceStartDateTimeUtc")].Value;
                    if (specialPriceStartDateTimeUtcExcel != null)
                        specialPriceStartDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(specialPriceStartDateTimeUtcExcel));
                    DateTime? specialPriceEndDateTimeUtc = null;
                    var specialPriceEndDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPriceEndDateTimeUtc")].Value;
                    if (specialPriceEndDateTimeUtcExcel != null)
                        specialPriceEndDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(specialPriceEndDateTimeUtcExcel));

                    bool customerEntersPrice = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "CustomerEntersPrice")].Value);
                    decimal minimumCustomerEnteredPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "MinimumCustomerEnteredPrice")].Value);
                    decimal maximumCustomerEnteredPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "MaximumCustomerEnteredPrice")].Value);
                    decimal weight = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Weight")].Value);
                    decimal length = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Length")].Value);
                    decimal width = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Width")].Value);
                    decimal height = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Height")].Value);
                    DateTime createdOnUtc = DateTime.FromOADate(Convert.ToDouble(worksheet.Cells[iRow, GetColumnIndex(properties, "CreatedOnUtc")].Value));
                    string categoryIds = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "CategoryIds")].Value);
                    string manufacturerIds = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ManufacturerIds")].Value);
                    string picture1 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Picture1")].Value);
                    string picture2 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Picture2")].Value);
                    string picture3 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Picture3")].Value);

                    //NJM: BEGIN OF PHILATELIC PORTION
                    string SaleNbr = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "SaleNbr")].Value);
                    int LotNbr = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "LotNbr")].Value);                //will only be processed if Sale present and found 
                    int DisplayOrder = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DisplayOrder")].Value);          //will only be processed if Sale present and found 

                    int ConsignmentId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ConsignmentId")].Value); //id field AUConsignmentID
                    string MaterialType = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "MaterialType")].Value);
                    string Country1 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Country1")].Value);
                    string StateProvince1 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "StateProvince1")].Value);
                    string Country2 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Country2")].Value);
                    string StateProvince2 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "StateProvince2")].Value);
                    string Country3 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Country3")].Value);
                    string StateProvince3 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "StateProvince3")].Value);
                    string Format = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Format")].Value);
                    string FormFactor = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "FormFactor")].Value);
                    string UsageState = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "UsageState")].Value);
                    string Grade = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "Grade")].Value);
                    decimal ReserveAmt = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "ReserveAmt")].Value);
                    decimal EstimatedLowBidAmt = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "EstimatedLowBidAmt")].Value);
                    decimal EstimatedHighBidAmt = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "EstimatedHighBidAmt")].Value);
                    decimal EstimatedRealizationAmt = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "EstimatedRealizationAmt")].Value);
                    decimal OpeningBidAmt = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "OpeningBidAmt")].Value);
                    string SymbolSummary = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "SymbolSummary")].Value);
                    int ReferenceId1 = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceId1")].Value); //id field AUConsignmentID
                    string ReferenceNbr1 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceNbr1")].Value);
                    decimal ReferenceValue1 = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceValue1")].Value);
                    int ReferenceId2 = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceId2")].Value); //id field AUConsignmentID
                    string ReferenceNbr2 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceNbr2")].Value);
                    decimal ReferenceValue2 = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceValue2")].Value);
                    int ReferenceId3 = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceId3")].Value); //id field AUConsignmentID
                    string ReferenceNbr3 = ConvertColumnToString(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceNbr3")].Value);
                    decimal ReferenceValue3 = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "ReferenceValue3")].Value);

                    #region Initial AUConsignor Edits

                    //It's ok if sale is not provided, but if it is provided it must already exist in the system and can't create a 1-lot-2-active-sale situation
                    sl = null; //init existing matching junction from previous record
                    csale = null;
                    var currTime = System.DateTime.UtcNow;

                    if (!String.IsNullOrEmpty(SaleNbr))
                    {
                        //ensure that the AUSale exists before you store any product/lot
                        csale = _consignorService.GetSaleByNbr(SaleNbr);
                        if (csale == null)
                        {
                            logError = string.Format("Lot Import: Ignoring row because Sale can not be found row# {0}/ Sale# {1}. Please store the sale in the system and re-import the row", iRow, SaleNbr);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                        else
                        {
                            if (csale.SaleIsAwarded)
                            {

                                logError = string.Format("Lot Import: This lot row#{0} can not be moved to a sale id/nbr: {1}/{2} that is awarded already.", iRow,  csale.AUSaleID, csale.AUSaleNbr);
                                _logger.InsertLog(LogLevel.Error, logError);
                                totalerrors++;
                            }
                            else
                            {
                                var l = _consignorService.GetLotBySku(sku);
                                if (l != null)
                                {
                                    if (l.IsLotSold)        //import changes can't be made to sold lots
                                    {
                                        logError = string.Format("Lot Import: This lot row#{0} is already sold in sale number {1}. Import changes can not be made to sold lots - row ignored", iRow, l.LotAwardSaleNbr);
                                        _logger.InsertLog(LogLevel.Error, logError);
                                        totalerrors++;
                                    }
                                    else 
                                    {   
                                       // get the one ausalelot record that is not history:
                                        var s = l.AUSaleRecords.FirstOrDefault(x => !x.IsHistory);
                                        if (s != null)
                                        {
                                            if (s.AUSaleID != csale.AUSaleID)  //trying to import to a different sale
                                            {
                                                //see if moving FROM an active or future sale and the lot has bids - No good
                                                //if (s.SaleIsActive && csale.SaleIsActive)    //imported lot can not be in 2 active sales. TODO: take sale is active out of junction
                                                if  ((!l.IsLotSold && s.SaleStartDateTime < currTime && s.SaleEndDateTime > currTime && l.LastBidAmt != 0) ||
                                                    (!l.IsLotSold && s.SaleStartDateTime > currTime && s.SaleEndDateTime > currTime && l.LastBidAmt != 0)
                                                    )
                                                {
                                                    logError = string.Format("Lot Import: This lot row#{0} already exists in active or future sale id {1} and has bids. A lot can not be moved if it has active bids. You should remove the bids in saleId {1} manually and then re-import to move this lot to the new sale id {2}.", iRow, s.AUSaleID, csale.AUSaleID);
                                                    _logger.InsertLog(LogLevel.Error, logError);
                                                    totalerrors++;
                                                }
                                                else if (csale.SaleIsAwarded)
                                                {

                                                    logError = string.Format("Lot Import: This lot row#{0} can not be moved to a sale id/nbr: {1}/{2} that is awarded already.", iRow,  csale.AUSaleID, csale.AUSaleNbr);
                                                    _logger.InsertLog(LogLevel.Error, logError);
                                                    totalerrors++;
                                                }
                                                else
                                                {
                                                    sl = s;     //capture the existing junction for this sale-lot (already exists in another sale but ok to move). It will be used when sale-lot junction to be created/updated
                                                }
                                            }
                                            else //(s.AUSaleID == csale.AUSaleID - lot already exixts in this sale so save the junction record
                                            {
                                                sl = s;     //capture the existing junction for this sale-lot (already exists in import sale). It will be used when sale-lot junction to be created/updated
                                            }
                                        } //leave sl null if existing "non-history" salelot junction not found - indicates lot exists but is not in any sale. Since you've already found the import sale you're good to go
                                    }
                                }  //lot specified in import does not exist and sale specified is not awarded yet, so ok to import. sl is null because not associated yet
                            }
                        }
                    }
                    else    //salenbr not specified in import - see if need to remove and if ok
                    {
                        var l = _consignorService.GetLotBySku(sku);
                        if (l != null)
                        {
                            if (l.IsLotSold)        //import changes can't be made to sold lots
                            {
                                logError = string.Format("Lot Import: This lot row#{0} is already sold in sale number {1}. Import changes can not be made to sold lots - row ignored", iRow, l.LotAwardSaleNbr);
                                _logger.InsertLog(LogLevel.Error, logError);
                                totalerrors++;
                            }
                            else
                            {
                                //need to check if lot is associated to an awarded sale or active/future sale with bids before you remove it
                                var s = l.AUSaleRecords.FirstOrDefault(x => !x.IsHistory);
                                if (s != null)
                                {
                                    if ((!l.IsLotSold && s.SaleStartDateTime < currTime && s.SaleEndDateTime > currTime && l.LastBidAmt != 0) ||
                                         (!l.IsLotSold && s.SaleStartDateTime > currTime && s.SaleEndDateTime > currTime && l.LastBidAmt != 0)
                                        )
                                    {
                                        logError = string.Format("Lot Import: This lot row#{0} already exists in active or future sale id {1} and has bids. A lot can not be removed from sale as specified in the import. You should remove the bids in saleId {1} manually and then re-import to remove this lot.", iRow, s.AUSaleID);
                                        _logger.InsertLog(LogLevel.Error, logError);
                                        totalerrors++;
                                    }
                                    else if (s.SaleIsAwarded)
                                    {

                                        logError = string.Format("Lot Import: This lot row#{0} can not be removed from a sale id/nbr: {1} that is awarded already.", iRow, s.AUSaleID, s.AUSaleRecord.AUSaleNbr);
                                        _logger.InsertLog(LogLevel.Error, logError);
                                        totalerrors++;
                                    }
                                    else
                                    {
                                        sl = s;     //capture the existing junction for this sale-lot (already exists in another sale but ok to move). It will be used when sale-lot junction to be created/updated
                                    }
                                } //ale number not provided in import lot exists but not associated to a sale so let it fly
                            }
                        }   //sale number not provided in import, and lot does not exist yet so let it fly
                    }
                

                    //Consignment must be present and exist in the system
                    if (ConsignmentId != 0)
                    {
                        //ensure that the AUSale exists
                        var cconsignment = _consignorService.GetConsignmentById(ConsignmentId);
                        if (cconsignment == null)
                        {
                            logError = string.Format("Lot Import: Ignoring row because Consignment ID can not be found in system row# {0}/ ConsignmentId# {1}. Please store the consignment in the system and re-import the row", iRow, ConsignmentId);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                    }
                    else
                    {
                        logError = string.Format("Lot Import: Consignment required - ignoring row because Consignment ID was not provided for row# {0}. Please record the consignment id and re-import the row", iRow);
                        _logger.InsertLog(LogLevel.Error, logError);
                        totalerrors++;
                        //break;
                    }

                    //Country1 must be present and exist in the system
                    if (!String.IsNullOrEmpty(Country1))
                    {
                        var ccountry1 = _consignorService.GetCountryByName(Country1.Trim());
                        if (ccountry1 == null)
                        {
                            logError = string.Format("Lot Import: Ignoring row because Country1 can not be found in system for row# {0}/ Country1: {1}. Please record the country and re-import the row", iRow, Country1);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                        else        //It's ok if StateProvince1 is not provided, but if it is provided it must already exist in the system for the Country1
                            if (!String.IsNullOrEmpty(StateProvince1))
                            {
                                //ensure that the StateProvince1 exists if it's given
                                var cstateprovince1 = _consignorService.GetStateProvinceByName(StateProvince1.Trim(), ccountry1.Id);
                                if (cstateprovince1 == null)
                                {
                                    logError = string.Format("Lot Import: Ignoring row because StateProvince1 not found in system for row# {0}/ Country1: {1} / StateProvince1 {2}. Please store the StateProvince1 in the system and record on row and re-import", iRow, Country1, StateProvince1);
                                    _logger.InsertLog(LogLevel.Error, logError);
                                    totalerrors++;
                                    //break;
                                }
                            }
                    }
                    else
                    {
                        logError = string.Format("Lot Import: Country1 required - Ignoring row because Country1 not present on row# {0}. Please store the country and record on row and re-import", iRow);
                        _logger.InsertLog(LogLevel.Error, logError);
                        totalerrors++;

                       if (!String.IsNullOrEmpty(StateProvince1))
                        {
                            logError = string.Format("Lot Import: Ignoring row because StateProvince1 provided for row with no Country1 row# {0}/ StateProvince1: {1}. Please provide Country1 and StateProvince1 on row and re-import", iRow, StateProvince1);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                        }
                       //break;
                    }

                    //Its ok if Country2 not present but if it is it must exist in the system
                    //if (!String.IsNullOrEmpty(Country2.Trim()))
                    if (!String.IsNullOrEmpty(Country2))
                    {
                        var ccountry2 = _consignorService.GetCountryByName(Country2.Trim());
                        if (ccountry2 == null)
                        {
                            logError = string.Format("Lot Import: Ignoring row because Country2 can not be found in system for row# {0}/ Country2: {1}. Please record the country in the system and re-import the row", iRow, Country2);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                        else        //It's ok if StateProvince2 is not provided, but if it is provided it must already exist in the system for Country2
                            if (!String.IsNullOrEmpty(StateProvince2))
                            {
                                //ensure that the StateProvince1 exists if it's given
                                var cstateprovince2 = _consignorService.GetStateProvinceByName(StateProvince2.Trim(), ccountry2.Id);
                                if (cstateprovince2 == null)
                                {
                                    logError = string.Format("Lot Import: Ignoring row because StateProvince2 not found in system for row# {0}/ Country2: {1} / StateProvince2 {2}. Please store the StateProvince3 in the system and record on row and re-import", iRow, Country2, StateProvince2);
                                    _logger.InsertLog(LogLevel.Error, logError);
                                    totalerrors++;
                                    //break;
                                }
                            }
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(StateProvince2))
                        {
                            logError = string.Format("Lot Import: Ignoring row because StateProvince2 provided for row with no Country2 row# {0}/ StateProvince2: {1}. Please provide Country2 and StateProvince2 on row and re-import", iRow, StateProvince2);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                    }


                    //Its ok if Country3 not present but if it is it must exist in the system
                    if (!String.IsNullOrEmpty(Country3))
                    {
                        var ccountry3 = _consignorService.GetCountryByName(Country2.Trim());
                        if (ccountry3 == null)
                        {
                            logError = string.Format("Lot Import: Ignoring row because Country3 can not be found in system for row# {0}/ Country3: {1}. Please record the country in the system and re-import the row", iRow, Country3);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                        else        //It's ok if StateProvince2 is not provided, but if it is provided it must already exist in the system for Country2
                            if (!String.IsNullOrEmpty(StateProvince3))
                            {
                                //ensure that the StateProvince1 exists if it's given
                                var cstateprovince3 = _consignorService.GetStateProvinceByName(StateProvince3.Trim(), ccountry3.Id);
                                if (cstateprovince3 == null)
                                {
                                    logError = string.Format("Lot Import: Ignoring row because StateProvince3 not found in system for row# {0}/ Country3: {1} / StateProvince3 {2}. Please store the StateProvince3 in the system and record on row and re-import", iRow, Country3, StateProvince3);
                                    _logger.InsertLog(LogLevel.Error, logError);
                                    totalerrors++;
                                    //break;
                                }
                            }
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(StateProvince3))
                        {
                            logError = string.Format("Lot Import: Ignoring row because StateProvince3 provided for row with no Country3 row# {0}/ StateProvince3: {1}. Please provide Country3 and StateProvince3 on row and re-import", iRow, StateProvince3);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                    }


                    //_logger.InsertLog(LogLevel.Information, "Import finished loading data record:" + iRow.ToString() + "now get product by sku");

                    var product = new Product();
                    var lot = new AULotRecord();

                    if (String.IsNullOrEmpty(sku))
                    {
                        logError = string.Format("Lot Import: Ignoring row because Product SKU not provided for row#{0}. Please update with the correct SKU and re-import", iRow);
                        _logger.InsertLog(LogLevel.Error, logError);
                        totalerrors++;
                        //break;
                    }
                    else
                    {
                        //TODO: SKU is mandatory - document in spreadsheet
                        product = _productService.GetProductBySku(sku);
                        lot = _consignorService.GetLotBySku(sku);

                        //Log as error when product already exists but lot doesn't and vica versa. This indicates one somehow got deleted when the other didn't. This is also logged in audit
                        //if (product != null && lot == null)  //don't do this check because it may be a brend new product
                        //{

                        //    logError = string.Format("Lot Import: Ignoring row because Product SKU was found but Lot SKU was not for row#{0}/SKU:{1}. Please notify the System Admin to research", iRow, sku);
                        //    _logger.InsertLog(LogLevel.Error, logError);
                        //    totalerrors++;
                        //    //break;
                        //}
                        //else if (product == null && lot != null)
                        if (product == null && lot != null)
                        {
                            logError = string.Format("Lot Import: Ignoring row because Lot SKU was found but Product SKU was not for row#{0}/SKU:{1}. Please notify the System Admin to research", iRow, sku);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                        else if (product != null && lot == null)
                        {
                            logError = string.Format("Lot Import: Ignoring row because Lot SKU was not found but Product SKU was found for row#{0}/SKU:{1}. Please notify the System Admin to research", iRow, sku);
                            _logger.InsertLog(LogLevel.Error, logError);
                            totalerrors++;
                            //break;
                        }
                    }
                    //TODO: If Error consignment id provided in file for a combined lot or a split lot

                    //if any errors from above edit-controls, stop this row and go to next. Count this record as ignored.
                    if (totalerrors > 0)
                    {
                        recordsignored++;

                        //next product
                        iRow++;
                        continue;   //skip record and go to next iteration 
                    }

                    #endregion 


                    bool newProduct = false;
                    if (product == null)
                    {
                        product = new Product();
                        lot = new AULotRecord();  //NJM
                        newProduct = true;
                    }
                    product.ProductTypeId = productTypeId;
                    product.ParentGroupedProductId = parentGroupedProductId;
                    product.VisibleIndividually = visibleIndividually;
                    product.Name = name;
                    product.ShortDescription = shortDescription;
                    product.FullDescription = fullDescription;
                    product.VendorId = vendorId;
                    product.ProductTemplateId = productTemplateId;
                    product.ShowOnHomePage = showOnHomePage;
                    product.MetaKeywords = metaKeywords;
                    product.MetaDescription = metaDescription;
                    product.MetaTitle = metaTitle;
                    product.AllowCustomerReviews = allowCustomerReviews;
                    product.Sku = sku;
                    product.ManufacturerPartNumber = manufacturerPartNumber;
                    product.Gtin = gtin;
                    product.IsGiftCard = isGiftCard;
                    product.GiftCardTypeId = giftCardTypeId;
                    product.RequireOtherProducts = requireOtherProducts;
                    product.RequiredProductIds = requiredProductIds;
                    product.AutomaticallyAddRequiredProducts = automaticallyAddRequiredProducts;
                    product.IsDownload = isDownload;
                    product.DownloadId = downloadId;
                    product.UnlimitedDownloads = unlimitedDownloads;
                    product.MaxNumberOfDownloads = maxNumberOfDownloads;
                    product.DownloadActivationTypeId = downloadActivationTypeId;
                    product.HasSampleDownload = hasSampleDownload;
                    product.SampleDownloadId = sampleDownloadId;
                    product.HasUserAgreement = hasUserAgreement;
                    product.UserAgreementText = userAgreementText;
                    product.IsRecurring = isRecurring;
                    product.RecurringCycleLength = recurringCycleLength;
                    product.RecurringCyclePeriodId = recurringCyclePeriodId;
                    product.RecurringTotalCycles = recurringTotalCycles;
                    product.IsRental = isRental;
                    product.RentalPriceLength = rentalPriceLength;
                    product.RentalPricePeriodId = rentalPricePeriodId;
                    product.IsShipEnabled = isShipEnabled;
                    product.IsFreeShipping = isFreeShipping;
                    product.ShipSeparately = shipSeparately;
                    product.AdditionalShippingCharge = additionalShippingCharge;
                    product.DeliveryDateId = deliveryDateId;
                    product.IsTaxExempt = isTaxExempt;
                    product.TaxCategoryId = taxCategoryId;
                    product.IsTelecommunicationsOrBroadcastingOrElectronicServices = isTelecommunicationsOrBroadcastingOrElectronicServices;
                    product.ManageInventoryMethodId = manageInventoryMethodId;
                    product.UseMultipleWarehouses = useMultipleWarehouses;
                    product.WarehouseId = warehouseId;
                    product.StockQuantity = stockQuantity;
                    product.DisplayStockAvailability = displayStockAvailability;
                    product.DisplayStockQuantity = displayStockQuantity;
                    product.MinStockQuantity = minStockQuantity;
                    product.LowStockActivityId = lowStockActivityId;
                    product.NotifyAdminForQuantityBelow = notifyAdminForQuantityBelow;
                    product.BackorderModeId = backorderModeId;
                    product.AllowBackInStockSubscriptions = allowBackInStockSubscriptions;
                    product.OrderMinimumQuantity = orderMinimumQuantity;
                    product.OrderMaximumQuantity = orderMaximumQuantity;
                    product.AllowedQuantities = allowedQuantities;
                    product.AllowAddingOnlyExistingAttributeCombinations = allowAddingOnlyExistingAttributeCombinations;
                    product.DisableBuyButton = disableBuyButton;
                    product.DisableWishlistButton = disableWishlistButton;
                    product.AvailableForPreOrder = availableForPreOrder;
                    product.PreOrderAvailabilityStartDateTimeUtc = preOrderAvailabilityStartDateTimeUtc;
                    product.CallForPrice = callForPrice;
                    product.Price = price;
                    product.OldPrice = oldPrice;
                    product.ProductCost = productCost;
                    product.SpecialPrice = specialPrice;
                    product.SpecialPriceStartDateTimeUtc = specialPriceStartDateTimeUtc;
                    product.SpecialPriceEndDateTimeUtc = specialPriceEndDateTimeUtc;
                    product.CustomerEntersPrice = customerEntersPrice;
                    product.MinimumCustomerEnteredPrice = minimumCustomerEnteredPrice;
                    product.MaximumCustomerEnteredPrice = maximumCustomerEnteredPrice;
                    product.Weight = weight;
                    product.Length = length;
                    product.Width = width;
                    product.Height = height;
                    product.Published = published;
                    product.CreatedOnUtc = createdOnUtc;
                    product.UpdatedOnUtc = DateTime.UtcNow;

                    //_logger.InsertLog(LogLevel.Information, "Import finished loading product info:" + iRow.ToString() + "now load lot info");


                    //NJM: start philatelic shit
                    lot.Sku = sku;   //this is sequence nbr
                    lot.EstimatedLowBidAmt = EstimatedLowBidAmt;
                    lot.EstimatedHighBidAmt = EstimatedHighBidAmt;
                    lot.EstimatedRealizationAmt = EstimatedRealizationAmt;
                    lot.OpeningBidAmt = OpeningBidAmt;
                    lot.ReserveAmt = ReserveAmt;


                    //TODO: Need to make this transactional
                    //TODO - need additionalShippingCharge try catch here that lets the rest of the import worksheet and hasSampleDownload a good message - also need to undo whatever done. Need ability to rerun import for failed records 
                    if (newProduct)
                    {
                        lot.CreatedByUsername = CurrentCustomer.Username;
                        lot.UpdatedByUsername = CurrentCustomer.Username;
                        lot.CreatedOnDateTime = System.DateTime.UtcNow;
                        lot.UpdatedOnDateTime = lot.CreatedOnDateTime;
                        lot.AUProductID = product.Id;   //very important to set the lot product id to match the product!!!
                        lot.IsLotSold = false;


                        //keep as little time between operations as possible

                       // _logger.InsertLog(LogLevel.Information, "Inserting product:" + iRow.ToString());
                        _productService.InsertProduct(product);

                        // _logger.InsertLog(LogLevel.Information, "Inserting lot:" + iRow.ToString());

                        lot.AUProductID = product.Id;
                        //TODO: Make AULotRecord a view model so not constantly stuffing consignmentid
                        lot.ConsignmentID = ConsignmentId;
                        lot.LastBidAmt = 0;     //do this to ensure nulls don't sneak in as used to determine if bids entered

                        lot.BidPostDateTime = new DateTime(1970, 01, 01);

                        _consignorService.InsertLot(lot);
                    }
                    else
                    {  
                        lot.UpdatedByUsername = CurrentCustomer.Username;
                        lot.UpdatedOnDateTime = System.DateTime.UtcNow;

                        //keep as little time between operations as possible
                        _productService.UpdateProduct(product);

                        //TODO: Make AULotRecord a view model so not constantly stuffing consignmentid
                        lot.ConsignmentID = ConsignmentId;
                        _consignorService.UpdateLot(lot);
                    }

                    //search engine name
                    _urlRecordService.SaveSlug(product, product.ValidateSeName(seName, product.Name, true), 0);

                    //category mappings
                    if (!String.IsNullOrEmpty(categoryIds))
                    {
                        foreach (var id in categoryIds.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())))
                        {
                            if (product.ProductCategories.FirstOrDefault(x => x.CategoryId == id) == null)
                            {
                                //ensure that category exists
                                var category = _categoryService.GetCategoryById(id);
                                if (category != null)
                                {
                                    var productCategory = new ProductCategory
                                    {
                                        ProductId = product.Id,
                                        CategoryId = category.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _categoryService.InsertProductCategory(productCategory);
                                }
                                else
                                {
                                    logError = string.Format("Lot Import: Category ID not found but storing lot anyway row#{0}/Id:{1}.", iRow, id);
                                    _logger.InsertLog(LogLevel.Information, logError);
                                }
                            }
                        }
                    }

                    //manufacturer mappings
                    if (!String.IsNullOrEmpty(manufacturerIds))
                    {
                        foreach (var id in manufacturerIds.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())))
                        {
                            if (product.ProductManufacturers.FirstOrDefault(x => x.ManufacturerId == id) == null)
                            {
                                //ensure that manufacturer exists
                                var manufacturer = _manufacturerService.GetManufacturerById(id);
                                if (manufacturer != null)
                                {
                                    var productManufacturer = new ProductManufacturer
                                    {
                                        ProductId = product.Id,
                                        ManufacturerId = manufacturer.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _manufacturerService.InsertProductManufacturer(productManufacturer);
                                }
                                else
                                {
                                    logError = string.Format("Lot Import: Manufacturer ID not found but storing lot anyway row#{0}/Id:{1}.", iRow, id);
                                    _logger.InsertLog(LogLevel.Information, logError);
                                }
                            }
                        }
                    }

                    //pictures
                    foreach (var picturePath in new[] { picture1, picture2, picture3 })
                    {
                        if (String.IsNullOrEmpty(picturePath))
                            continue;

                        var mimeType = GetMimeTypeFromFilePath(picturePath);
                        var newPictureBinary = File.ReadAllBytes(picturePath);
                        var pictureAlreadyExists = false;
                        if (!newProduct)
                        {
                            //compare with existing product pictures
                            var existingPictures = _pictureService.GetPicturesByProductId(product.Id);
                            foreach (var existingPicture in existingPictures)
                            {
                                var existingBinary = _pictureService.LoadPictureBinary(existingPicture);
                                //picture binary after validation (like in database)
                                var validatedPictureBinary = _pictureService.ValidatePicture(newPictureBinary, mimeType);
                                if (existingBinary.SequenceEqual(validatedPictureBinary))
                                {
                                    //the same picture content
                                    pictureAlreadyExists = true;
                                    break;
                                }
                            }
                        }


                        //OLD SIGNATURE FOR _pictureService.GetPictureSeName
                        //if (!pictureAlreadyExists)
                        //{
                        //    product.ProductPictures.Add(new ProductPicture
                        //    {
                        //        Picture = _pictureService.InsertPicture(newPictureBinary, mimeType, _pictureService.GetPictureSeName(name), true),
                        //        DisplayOrder = 1,
                        //    });
                        //    _productService.UpdateProduct(product);
                        //}


                        if (!pictureAlreadyExists)
                        {
                            product.ProductPictures.Add(new ProductPicture
                            {
                                Picture = _pictureService.InsertPicture(newPictureBinary, mimeType, _pictureService.GetPictureSeName(name)),
                                DisplayOrder = 1,
                            });
                            _productService.UpdateProduct(product);
                        }


                    }

                    //update "HasTierPrices" and "HasDiscountsApplied" properties
                    //NJM for performance - I think thiswill always default to 0 because there's nothing in the excel file
                    _productService.UpdateHasTierPricesProperty(product);
                    _productService.UpdateHasDiscountsApplied(product);

                    //*********************************************************************************************************************************
                    //NJM: AUConsignor begin philatelic lot relationships
                    //********************************************************************************************************************************

                    //TODO: REFACTOR SALE-LOT THIS SO CAN CALL FROMMANAGESALESPOPUP AS WELL
                    //For sale it looks like it ignores it if it can't find it. Need to implement auditlog of all imports
                    if (!String.IsNullOrEmpty(SaleNbr))
                    {
                        //ensure that the AUSale exists
                        //AUSaleLotRecord s1 = null;
                        //var sale = _consignorService.GetSaleByNbr(SaleNbr);
                        //TODO: PUT FOREIGN KEY CONSTRAINTS ON AUSALELOT
                        if (csale != null)  //sale specified on import already retrived in overall edits above. If it is null you have other problems
                        {                         
                            if (sl == null)  //no sale junction exists for this lot as determined in overall edits above. Just create a new salelot junction.
                                {
                                    var saleLot = new AUSaleLotRecord
                                    {
                                        AUSaleID = csale.AUSaleID,
                                        AULotID = lot.AULotID,
                                        LotNbr = LotNbr,                        //load up LotNbr from the spreadsheet
                                        Sku = sku,
                                        SaleStartDateTime = csale.SaleStartDateTime,
                                        SaleEndDateTime = csale.SaleEndDateTime,
                                        IsHistory = false,
                                        SaleIsAwarded  = csale.SaleIsAwarded,
                                        SaleIsActive = csale.SaleIsActive,       //pull this indicator from the Sale record - don't load from spreadsheet
                                        DisplayOrder = DisplayOrder             //load up DisplayOrder from the spreadsheet
                                    };

                                    _consignorService.InsertSaleLot(saleLot);
                                }
                            else    //Sale exists and the junction AUSaleLot record does as well. If juntion is to import sale (already exixts in sale), just update it with fresh sale info
                                    //If junction is to a different sale you'll need to move to the new (import sale)
                                {
                                    if (SaleNbr == sl.AUSaleRecord.AUSaleNbr)  //import sale number is the same as the currently assigned sale number
                                    {
                                        sl.AUSaleID = csale.AUSaleID;
                                        sl.AULotID = lot.AULotID;
                                        sl.LotNbr = LotNbr;
                                        sl.Sku = sku;
                                        sl.SaleStartDateTime = csale.SaleStartDateTime;
                                        sl.SaleEndDateTime = csale.SaleEndDateTime;
                                        //sl.IsHistory = false;     //don't touch this as whatever was there should remain there. Note: sl is only populated with the non-history junction for the lot
                                        sl.SaleIsAwarded = csale.SaleIsAwarded;
                                        sl.SaleIsActive = csale.SaleIsActive;
                                        sl.DisplayOrder = DisplayOrder;
                                        _consignorService.UpdateSaleLot(sl);
                                    }
                                    else     //existing "non-history" salelot is to different sale than import sale - "MOVE" the sale lot
                                    {
                                        AUSaleLotRecord newSaleLot = new AUSaleLotRecord()
                                        {
                                            AUSaleID = csale.AUSaleID,
                                            LotNbr = LotNbr,                        //load up LotNbr from the spreadsheet
                                            SaleIsActive = csale.SaleIsActive,       //pull this indicator from the Sale record - don't load from spreadsheet
                                            DisplayOrder = DisplayOrder,
                                            SaleStartDateTime = csale.SaleStartDateTime,
                                            SaleEndDateTime = csale.SaleEndDateTime,
                                            SaleIsAwarded = csale.SaleIsAwarded,
                                            IsHistory = false,
                                            AUProductId = lot.AUProductID,
                                            Sku = lot.Sku
                                        };

                                        _consignorService.MoveSaleLot(sl, newSaleLot);
                                    }
                                }
                        }   //SaleNbr not found (csale == null) -- this will have been logged as an error in top edits

                    }
                    else   //import sale number is null - need to see if need to remove lot
                    {
                        if (sl != null) //no import sale but lot exists in a sale, so remove it from the sale
                        {
                            _consignorService.DeleteSaleLotByLotId(lot.AULotID, sl.AUSaleID);
                        }
                    }


                        //%%%%%%%%%%%%%%need logic if in sale and removing sale


                    //NOTE: The above edits will stop process for this record if Consignment ID not found in system
                    //Consignment is required for an original lot. An original lot can only belong to one consignment. A combined lot can not belong to a consignment
                    //directly - it only belongs to consignments through it's relationship to the orginal lot.
                    if (ConsignmentId != 0)
                    {
                        //ensure that the AUSale exists
                        var consignment = _consignorService.GetConsignmentById(ConsignmentId);
                        if (consignment != null)
                        {
                            //TODO: mutiple imports that change the consignment between imports for a lot will not get rid of the old relationship
                            //if (lot.AUSaleRecords.FirstOrDefault(x => x.AUSaleID == sale.AUSaleID) == null) //%%%%Value cn not be null?????
                            
                            //see if this lot was already associated to another consignment
                            var lc = lot.AUConsignmentRecords.FirstOrDefault(x => x.AUConsignmentID != ConsignmentId);
                            //if it was associated to a different consignment, you'll change the consignment assignment but warn them as well
                            if (lc != null)
                            {
                                logError = string.Format("Lot Import: This lot belonged to a different consignment than in the import - row#{0} belonged to consignmentId:{1} but was changed to consignmentId {2}. You should review the lot fees (if any) or else fees will be inherited from the new consignment.", iRow, lc.AUConsignmentID, consignment.AUConsignmentID);
                                _logger.InsertLog(LogLevel.Warning, logError);

                                int origConsignmentId = lc.AUConsignmentID;
                                lc.AUConsignmentID = consignment.Id;
                                _consignorService.UpdateConsignmentLot(lc, origConsignmentId);
                            }
                            else //lot was not already assigned to a different consignment
                            {
                                var cl = consignment.AULotRecords.FirstOrDefault(x => x.AULotID == lot.AULotID);
                                if (cl == null) //Consignment exists but the junction AUConsignmentLot record doesn't
                                {
                                    var consignmentLot = new AUConsignmentLotRecord
                                    {
                                        AUConsignmentID = consignment.AUConsignmentID,
                                        AULotID = lot.AULotID,
                                        AULotRecord = lot,
                                        AUConsignmentRecord = consignment,

                                    };
                                    _consignorService.InsertConsignmentLot(consignmentLot);
                                }
                            }
                        }  //TODO: add abort here (and at Sale) because edit already determined consignment exists so something bad happened
                    }

                    //Junction Lot to Country1 (AUCountryLot)
                    if (!String.IsNullOrEmpty(Country1))
                    {
                        //ensure that the country1 exists, because you will add its relationship to lot as well as a specification attribute
                        var country = _consignorService.GetCountryByName(Country1.Trim());
                        if (country != null)
                        {
                           
                            var query = from cl in _countrylotRepo.Table
                                       where cl.AULotID == lot.AULotID && cl.AUCountryID == country.Id
                                       select cl;
                            var clot = query.FirstOrDefault();
                            if (clot == null) //Country exists exists but the junction AUCountryLot record doesn't
                            {
                                var countryLot = new AUCountryLotRecord
                                {
                                    AULotID = lot.AULotID,
                                    AUCountryID = country.Id,
                                };
                                _consignorService.InsertCountryLot(countryLot);
                            }
                        }

                        //Junction Lot to StateProvince1 (AUStateProvinceLot) - can only happen if you have Country1
                        if (!String.IsNullOrEmpty(StateProvince1))
                        {
                            //ensure that the AUSale exists
                            var stateprovince = _consignorService.GetStateProvinceByName(StateProvince1.Trim(), country.Id);
                            if (stateprovince != null)
                            {

                                var query = from spl in _stateprovincelotRepo.Table
                                            where spl.AULotID == lot.AULotID && spl.AUStateProvinceID == stateprovince.Id
                                            select spl;
                                var splot = query.FirstOrDefault();
                                if (splot == null) //StateProvince exists exists but the junction AUStateProvinceLot record doesn't
                                {
                                    var stateprovinceLot = new AUStateProvinceLotRecord
                                    {
                                        AULotID = lot.AULotID,
                                        AUStateProvinceID = stateprovince.Id,
                                    };
                                    _consignorService.InsertStateProvinceLot(stateprovinceLot);
                                }
                            }

                        }
                    } //end Country1

                    //Junction Lot to Country2 (AUCountryLot)
                    if (!String.IsNullOrEmpty(Country2))
                    {
                        //ensure that the AUSale exists
                        var country = _consignorService.GetCountryByName(Country2.Trim());
                        if (country != null)
                        {

                            var query = from cl in _countrylotRepo.Table
                                        where cl.AULotID == lot.AULotID && cl.AUCountryID == country.Id
                                        select cl;
                            var clot = query.FirstOrDefault();
                            if (clot == null) //Country exists exists but the junction AUCountryLot record doesn't
                            {
                                var countryLot = new AUCountryLotRecord
                                {
                                    AULotID = lot.AULotID,
                                    AUCountryID = country.Id,
                                };
                                _consignorService.InsertCountryLot(countryLot);
                            }
                        }

                        //Junction Lot to StateProvince (AUStateProvinceLot) - can only happen if you have Country1
                        if (!String.IsNullOrEmpty(StateProvince2))
                        {
                            //ensure that the AUSale exists
                            var stateprovince = _consignorService.GetStateProvinceByName(StateProvince2.Trim(), country.Id);
                            if (stateprovince != null)
                            {

                                var query = from spl in _stateprovincelotRepo.Table
                                            where spl.AULotID == lot.AULotID && spl.AUStateProvinceID == stateprovince.Id
                                            select spl;
                                var splot = query.FirstOrDefault();
                                if (splot == null) //StateProvince exists exists but the junction AUStateProvinceLot record doesn't
                                {
                                    var stateprovinceLot = new AUStateProvinceLotRecord
                                    {
                                        AULotID = lot.AULotID,
                                        AUStateProvinceID = stateprovince.Id,
                                    };
                                    _consignorService.InsertStateProvinceLot(stateprovinceLot);
                                }
                            }

                        }
                    } //end Country2



                    //Junction Lot to Country3 (AUCountryLot)
                    if (!String.IsNullOrEmpty(Country3))
                    {
                        //ensure that the AUSale exists
                        var country = _consignorService.GetCountryByName(Country3.Trim());
                        if (country != null)
                        {

                            var query = from cl in _countrylotRepo.Table
                                        where cl.AULotID == lot.AULotID && cl.AUCountryID == country.Id
                                        select cl;
                            var clot = query.FirstOrDefault();
                            if (clot == null) //Country exists exists but the junction AUCountryLot record doesn't
                            {
                                var countryLot = new AUCountryLotRecord
                                {
                                    AULotID = lot.AULotID,
                                    AUCountryID = country.Id,
                                };
                                _consignorService.InsertCountryLot(countryLot);
                            }
                        }

                        //Junction Lot to StateProvince1 (AUStateProvinceLot) - can only happen if you have Country1
                        if (!String.IsNullOrEmpty(StateProvince3))
                        {
                            //ensure that the AUSale exists
                            var stateprovince = _consignorService.GetStateProvinceByName(StateProvince3.Trim(), country.Id);
                            if (stateprovince != null)
                            {

                                var query = from spl in _stateprovincelotRepo.Table
                                            where spl.AULotID == lot.AULotID && spl.AUStateProvinceID == stateprovince.Id
                                            select spl;
                                var splot = query.FirstOrDefault();
                                if (splot == null) //StateProvince exists exists but the junction AUStateProvinceLot record doesn't
                                {
                                    var stateprovinceLot = new AUStateProvinceLotRecord
                                    {
                                        AULotID = lot.AULotID,
                                        AUStateProvinceID = stateprovince.Id,
                                    };
                                    _consignorService.InsertStateProvinceLot(stateprovinceLot);
                                }
                            }

                        }
                    } //end Country3

                    //Start of product specification attributes
                    //specAttributes
                    //int specFormat = 0;
                    //int specFormFactor = 0;
                    //int specUsageState = 0;
                    //int specGrade = 0;

                    //SymbolSummary

                    //TODO: For all spec attributes inquire for AllowFiltering and ShowOnProductPage (use same method as display order? but need to investigate where these are stored)
                    if ((!String.IsNullOrEmpty(MaterialType)) || (!String.IsNullOrEmpty(Format)) || (!String.IsNullOrEmpty(FormFactor)) || (!String.IsNullOrEmpty(UsageState)) || (!String.IsNullOrEmpty(Grade)) || (!String.IsNullOrEmpty(SymbolSummary)))
                    {
                        var productSpecs = _specificationAttributeService.GetProductSpecificationAttributes(product.Id);    //only get the produc specs one time if any of the spec attributes is filled in


                        //FormFactor
                        if (!String.IsNullOrEmpty(MaterialType))
                        {
                            optionExists = false;
                            specExists = false;
                            if (productSpecs.Count() > 0)
                            {
                                foreach (ProductSpecificationAttribute ps in productSpecs)
                                {
                                    if (ps.SpecificationAttributeOption.SpecificationAttributeId == specMaterialType)
                                    {
                                        specExists = true;
                                        if (ps.SpecificationAttributeOption.Name == MaterialType)   //Match on option name to the text in the SS. If the product spec attribute is "Format" and the option already is associated, don't create a duplicate association
                                        {
                                            optionExists = true;
                                            break;
                                        }
                                    }
                                }
                            }

                            if (!optionExists)
                            {

                                var specOption = GetSpecOptionByName(specMaterialType, MaterialType); //get the option id so can create products spec attribute below
                                if (specOption.Name != null)
                                {
                                    var psa = new ProductSpecificationAttribute
                                    {
                                        //AttributeTypeId = attributeTypeId,
                                        AttributeTypeId = (int)SpecificationAttributeType.Option,
                                        SpecificationAttributeOptionId = specOption.Id,
                                        ProductId = product.Id,
                                        CustomValue = null,
                                        AllowFiltering = true,  //can do this since it's an "Option" attribute type
                                        ShowOnProductPage = true,
                                        DisplayOrder = specMaterialTypeDisplayOrder   ////Proven that this needs to be the Spec Attribute display order - not the Option display order
                                        //DisplayOrder = specOption.DisplayOrder

                                    };
                                    _specificationAttributeService.InsertProductSpecificationAttribute(psa);
                                }
                                else
                                {
                                    logError = string.Format("Lot Import: This Specification Attribute {1} and/or Attribute Option {2} was not found for this row#{0}. The product/lot is added but not associated to this attribute/option", iRow, "Format", Format);
                                    _logger.InsertLog(LogLevel.Warning, logError);

                                }
                            }
                        }


                        
                        //Format
                        if (!String.IsNullOrEmpty(Format))
                        {
                            optionExists = false;
                            specExists = false;
                            if (productSpecs.Count() > 0)
                            {
                                foreach (ProductSpecificationAttribute ps in productSpecs)
                                {
                                    if (ps.SpecificationAttributeOption.SpecificationAttributeId == specFormat)
                                    {
                                        specExists = true;
                                        if (ps.SpecificationAttributeOption.Name == Format)   //Match on option name to the text in the SS. If the product spec attribute is "Format" and the option already is associated, don't create a duplicate association
                                        {
                                            optionExists = true;
                                            break;
                                        }
                                    }
                                }
                            }

                            if (!optionExists)  
                            {
                                var specOption = GetSpecOptionByName(specFormat, Format); //get the option id so can create products spec attribute below
                                if (specOption.Name != null)
                                {
                                    var psa = new ProductSpecificationAttribute
                                    {
                                        //AttributeTypeId = attributeTypeId,
                                        AttributeTypeId = (int)SpecificationAttributeType.Option,

                                        SpecificationAttributeOptionId = specOption.Id, 
                                        ProductId = product.Id,
                                        CustomValue = null,
                                        AllowFiltering = true,  //can do this since it's an "Option" attribute type
                                        ShowOnProductPage = true,
                                        DisplayOrder = specFormatDisplayOrder   ////Proven that this needs to be the Spec Attribute display order - not the Option display order
                                        //DisplayOrder = specOption.DisplayOrder
                                    };
                                    _specificationAttributeService.InsertProductSpecificationAttribute(psa);
                                }
                                else
                                {
                                    logError = string.Format("Lot Import: This Specification Attribute {1} and/or Attribute Option {2} was not found for this row#{0}. The product/lot is added but not associated to this attribute/option", iRow, "Format", Format);
                                    _logger.InsertLog(LogLevel.Warning, logError);

                                }
                            }
                        }

                        //FormFactor
                        if (!String.IsNullOrEmpty(FormFactor))
                        {
                            optionExists = false;
                            specExists = false;
                            if (productSpecs.Count() > 0)
                            {
                                foreach (ProductSpecificationAttribute ps in productSpecs)
                                {
                                    if (ps.SpecificationAttributeOption.SpecificationAttributeId == specFormFactor)
                                    {
                                        specExists = true;
                                        if (ps.SpecificationAttributeOption.Name == FormFactor)   //Match on option name to the text in the SS. If the product spec attribute is "Format" and the option already is associated, don't create a duplicate association
                                        {
                                            optionExists = true;
                                            break;
                                        }
                                    }
                                }
                            }

                            if (!optionExists)
                            {

                                var specOption = GetSpecOptionByName(specFormFactor, FormFactor); //get the option id so can create products spec attribute below
                                if (specOption.Name != null)
                                {
                                    var psa = new ProductSpecificationAttribute
                                    {
                                        //AttributeTypeId = attributeTypeId,
                                        AttributeTypeId = (int)SpecificationAttributeType.Option,
                                        SpecificationAttributeOptionId = specOption.Id,
                                        ProductId = product.Id,
                                        CustomValue = null,
                                        AllowFiltering = true,  //can do this since it's an "Option" attribute type
                                        ShowOnProductPage = true,
                                        DisplayOrder = specFormFactorDisplayOrder   ////Proven that this needs to be the Spec Attribute display order - not the Option display order
                                        //DisplayOrder = specOption.DisplayOrder

                                    };
                                    _specificationAttributeService.InsertProductSpecificationAttribute(psa);
                                }
                                else
                                {
                                    logError = string.Format("Lot Import: This Specification Attribute {1} and/or Attribute Option {2} was not found for this row#{0}. The product/lot is added but not associated to this attribute/option", iRow, "FormFactor", FormFactor);
                                    _logger.InsertLog(LogLevel.Warning, logError);

                                }
                            }
                        }


                        //UsageState
                        if (!String.IsNullOrEmpty(UsageState))
                        {
                            optionExists = false;
                            specExists = false;
                            if (productSpecs.Count() > 0)
                            {
                                foreach (ProductSpecificationAttribute ps in productSpecs)
                                {
                                    if (ps.SpecificationAttributeOption.SpecificationAttributeId == specUsageState)
                                    {
                                        specExists = true;
                                        if (ps.SpecificationAttributeOption.Name == UsageState)   //Match on option name to the text in the SS. If the product spec attribute is "Format" and the option already is associated, don't create a duplicate association
                                        {
                                            optionExists = true;
                                            break;
                                        }
                                    }
                                }
                            }

                            if (!optionExists)
                            {
                                var specOption = GetSpecOptionByName(specUsageState, UsageState); //get the option id so can create products spec attribute below
                                if (specOption.Name != null)
                                {
                                    var psa = new ProductSpecificationAttribute
                                    {
                                        //AttributeTypeId = attributeTypeId,
                                        AttributeTypeId = (int)SpecificationAttributeType.Option,

                                        SpecificationAttributeOptionId = specOption.Id, 
                                        ProductId = product.Id,
                                        CustomValue = null,
                                        AllowFiltering = true,  //can do this since it's an "Option" attribute type
                                        ShowOnProductPage = true,
                                        DisplayOrder = specUsageStateDisplayOrder   ////Proven that this needs to be the Spec Attribute display order - not the Option display order
                                        //DisplayOrder = specOption.DisplayOrder

                                    };
                                    _specificationAttributeService.InsertProductSpecificationAttribute(psa);
                                }
                                else
                                {
                                    logError = string.Format("Lot Import: This Specification Attribute {1} and/or Attribute Option {2} was not found for this row#{0}. The product/lot is added but not associated to this attribute/otion", iRow, "UsageState", UsageState);
                                    _logger.InsertLog(LogLevel.Warning, logError);

                                }
                            }
                        }

                        //Grade
                        if (!String.IsNullOrEmpty(Grade))
                        {
                            optionExists = false;
                            specExists = false;
                            if (productSpecs.Count() > 0)
                            {
                                foreach (ProductSpecificationAttribute ps in productSpecs)
                                {
                                    if (ps.SpecificationAttributeOption.SpecificationAttributeId == specGrade)
                                    {
                                        specExists = true;
                                        if (ps.SpecificationAttributeOption.Name == Grade)   //Match on option name to the text in the SS. If the product spec attribute is "Format" and the option already is associated, don't create a duplicate association
                                        {
                                            optionExists = true;
                                            break;
                                        }
                                    }
                                }
                            }

                            if (!optionExists)
                            {
                                var specOption = GetSpecOptionByName(specGrade, Grade); //get the option id so can create products spec attribute below
                                if (specOption.Name != null)
                                {
                                    var psa = new ProductSpecificationAttribute
                                    {
                                        //AttributeTypeId = attributeTypeId,
                                        AttributeTypeId = (int)SpecificationAttributeType.Option,

                                        SpecificationAttributeOptionId = specOption.Id,
                                        ProductId = product.Id,
                                        CustomValue = null,
                                        AllowFiltering = true,  //can do this since it's an "Option" attribute type
                                        ShowOnProductPage = true,
                                        DisplayOrder = specGradeDisplayOrder   ////Proven that this needs to be the Spec Attribute display order - not the Option display order
                                        //DisplayOrder = specOption.DisplayOrder

                                    };
                                    _specificationAttributeService.InsertProductSpecificationAttribute(psa);
                                }
                                else
                                {
                                    logError = string.Format("Lot Import: This Specification Attribute {1} and/or Attribute Option {2} was not found for this row#{0}. The product/lot is added but not associated to this attribute/otion", iRow, "Grade", Grade);
                                    _logger.InsertLog(LogLevel.Warning, logError);

                                }
                            }
                        }

                        //SymbolSummary
                        if (!String.IsNullOrEmpty(SymbolSummary))
                        {
                            optionExists = false;
                            specExists = false;
                            if (productSpecs.Count() > 0)
                            {
                                foreach (ProductSpecificationAttribute ps in productSpecs)
                                {
                                    if (ps.SpecificationAttributeOption.SpecificationAttributeId == specSymbolSummary)
                                    {
                                        specExists = true;
                                        if (ps.SpecificationAttributeOption.Name == SymbolSummary)   //Match on option name to the text in the SS. If the product spec attribute is "Format" and the option already is associated, don't create a duplicate association
                                        {
                                            optionExists = true;
                                            break;
                                        }
                                    }
                                }
                            }

                            if (!optionExists)
                            {
                                var specOption = GetSpecOptionByName(specSymbolSummary, SymbolSummary); //get the option id so can create products spec attribute below
                                if (specOption.Name != null)
                                {
                                    var psa = new ProductSpecificationAttribute
                                    {
                                        //AttributeTypeId = attributeTypeId,
                                        AttributeTypeId = (int)SpecificationAttributeType.Option,

                                        SpecificationAttributeOptionId = specOption.Id,
                                        ProductId = product.Id,
                                        CustomValue = null,
                                        AllowFiltering = true,  //can do this since it's an "Option" attribute type
                                        ShowOnProductPage = true,
                                        DisplayOrder = specSymbolSummaryDisplayOrder   ////Proven that this needs to be the Spec Attribute display order - not the Option display order
                                        //DisplayOrder = specOption.DisplayOrder

                                    };
                                    _specificationAttributeService.InsertProductSpecificationAttribute(psa);
                                }
                                else
                                {
                                    logError = string.Format("Lot Import: This Specification Attribute {1} and/or Attribute Option {2} was not found for this row#{0}. The product/lot is added but not associated to this attribute/otion", iRow, "SymbolSummary", SymbolSummary);
                                    _logger.InsertLog(LogLevel.Warning, logError);

                                }
                            }
                        }


                    }   //end of product spec attributes


                    //end of doing crap - count record as added or changed
                    recordsaddchanged++;

                    //next product
                    iRow++;
                }

                logError = string.Format("Lot Import: End Lot Import by User: {0}. #Records added or changed: {1}. #Records ignored due to errors in row: {2}", CurrentCustomer.Username, recordsaddchanged, recordsignored);
                _logger.InsertLog(LogLevel.Information, logError);

            } //end of using excel package
        } //end of class
        /// <summary>
        /// Import products from XLSX file
        /// </summary>
        /// <param name="stream">Stream</param>
        public virtual void ImportProductsFromXlsx(Stream stream)
        {
            //var start = DateTime.Now;
            using (var xlPackage = new ExcelPackage(stream))
            {
                // get the first worksheet in the workbook
                var worksheet = xlPackage.Workbook.Worksheets.FirstOrDefault();
                if (worksheet == null)
                    throw new NopException("No worksheet found");

                //the columns
                var properties = new List<PropertyByName<Product>>();
                var poz = 1;
                while (true)
                {
                    try
                    {
                        var cell = worksheet.Cells[1, poz];

                        if (cell == null || cell.Value == null || String.IsNullOrEmpty(cell.Value.ToString()))
                            break;

                        poz += 1;
                        properties.Add(new PropertyByName<Product>(cell.Value.ToString()));
                    }
                    catch
                    {
                       break;
                    }
                }

                var manager = new PropertyManager<Product>(properties.ToArray());

                var attributProperties = new[]
                   {
                        new PropertyByName<ExportProductAttribute>("AttributeId"),
                        new PropertyByName<ExportProductAttribute>("AttributeName"),
                        new PropertyByName<ExportProductAttribute>("AttributeTextPrompt"),
                        new PropertyByName<ExportProductAttribute>("AttributeIsRequired"),
                        new PropertyByName<ExportProductAttribute>("AttributeControlType")
                        {
                            DropDownElements = AttributeControlType.TextBox.ToSelectList(useLocalization: false)
                        },
                        new PropertyByName<ExportProductAttribute>("AttributeDisplayOrder"), 
                        new PropertyByName<ExportProductAttribute>("ProductAttributeValueId"),
                        new PropertyByName<ExportProductAttribute>("ValueName"),
                        new PropertyByName<ExportProductAttribute>("AttributeValueType")
                        {
                            DropDownElements = AttributeValueType.Simple.ToSelectList(useLocalization: false)
                        },
                        new PropertyByName<ExportProductAttribute>("AssociatedProductId"),
                        new PropertyByName<ExportProductAttribute>("ColorSquaresRgb"),
                        new PropertyByName<ExportProductAttribute>("ImageSquaresPictureId"),
                        new PropertyByName<ExportProductAttribute>("PriceAdjustment"),
                        new PropertyByName<ExportProductAttribute>("WeightAdjustment"),
                        new PropertyByName<ExportProductAttribute>("Cost"),
                        new PropertyByName<ExportProductAttribute>("Quantity"),
                        new PropertyByName<ExportProductAttribute>("IsPreSelected"),
                        new PropertyByName<ExportProductAttribute>("DisplayOrder"),
                        new PropertyByName<ExportProductAttribute>("PictureId")
                    };

                var managerProductAttribute = new PropertyManager<ExportProductAttribute>(attributProperties);

                var endRow = 2;
                var allCategoriesNames = new List<string>();
                var allSku = new List<string>();

                var tempProperty = manager.GetProperty("Categories");
                var categoryCellNum = tempProperty.Return(p => p.PropertyOrderPosition, -1);

                tempProperty = manager.GetProperty("SKU");
                var skuCellNum = tempProperty.Return(p => p.PropertyOrderPosition, -1);

                var allManufacturersNames = new List<string>();
                tempProperty = manager.GetProperty("Manufacturers");
                var manufacturerCellNum = tempProperty.Return(p => p.PropertyOrderPosition, -1);

                manager.SetSelectList("ProductType", ProductType.SimpleProduct.ToSelectList(useLocalization: false));
                manager.SetSelectList("GiftCardType", GiftCardType.Virtual.ToSelectList(useLocalization: false));
                manager.SetSelectList("DownloadActivationType", DownloadActivationType.Manually.ToSelectList(useLocalization: false));
                manager.SetSelectList("ManageInventoryMethod", ManageInventoryMethod.DontManageStock.ToSelectList(useLocalization: false));
                manager.SetSelectList("LowStockActivity", LowStockActivity.Nothing.ToSelectList(useLocalization: false));
                manager.SetSelectList("BackorderMode", BackorderMode.NoBackorders.ToSelectList(useLocalization: false));
                manager.SetSelectList("RecurringCyclePeriod", RecurringProductCyclePeriod.Days.ToSelectList(useLocalization: false));
                manager.SetSelectList("RentalPricePeriod", RentalPricePeriod.Days.ToSelectList(useLocalization: false));

                manager.SetSelectList("Vendor", _vendorService.GetAllVendors(showHidden: true).Select(v => v as BaseEntity).ToSelectList(p => (p as Vendor).Return(v => v.Name, String.Empty)));
                manager.SetSelectList("ProductTemplate", _productTemplateService.GetAllProductTemplates().Select(pt => pt as BaseEntity).ToSelectList(p => (p as ProductTemplate).Return(pt => pt.Name, String.Empty)));
                manager.SetSelectList("DeliveryDate", _shippingService.GetAllDeliveryDates().Select(dd => dd as BaseEntity).ToSelectList(p => (p as DeliveryDate).Return(dd => dd.Name, String.Empty)));
                manager.SetSelectList("TaxCategory", _taxCategoryService.GetAllTaxCategories().Select(tc => tc as BaseEntity).ToSelectList(p => (p as TaxCategory).Return(tc => tc.Name, String.Empty)));
                manager.SetSelectList("BasepriceUnit", _measureService.GetAllMeasureWeights().Select(mw => mw as BaseEntity).ToSelectList(p =>(p as MeasureWeight).Return(mw => mw.Name, String.Empty)));
                manager.SetSelectList("BasepriceBaseUnit", _measureService.GetAllMeasureWeights().Select(mw => mw as BaseEntity).ToSelectList(p => (p as MeasureWeight).Return(mw => mw.Name, String.Empty)));

                var allAttributeIds = new List<int>();
                var attributeIdCellNum = managerProductAttribute.GetProperty("AttributeId").PropertyOrderPosition + ExportProductAttribute.ProducAttributeCellOffset;
                
                //find end of data
                while (true)
                {
                    var allColumnsAreEmpty = manager.GetProperties
                        .Select(property => worksheet.Cells[endRow, property.PropertyOrderPosition])
                        .All(cell => cell == null || cell.Value == null || String.IsNullOrEmpty(cell.Value.ToString()));

                    if (allColumnsAreEmpty)
                        break;

                    if (new[] { 1, 2 }.Select(cellNum => worksheet.Cells[endRow, cellNum]).All(cell => cell == null || cell.Value == null || String.IsNullOrEmpty(cell.Value.ToString())) && worksheet.Row(endRow).OutlineLevel == 0)
                    {
                        var cellValue = worksheet.Cells[endRow, attributeIdCellNum].Value;
                        try
                        {
                            var aid = cellValue.Return(Convert.ToInt32, -1);

                            var productAttribute = _productAttributeService.GetProductAttributeById(aid);

                            if (productAttribute != null)
                                worksheet.Row(endRow).OutlineLevel = 1;
                        }
                        catch (FormatException)
                        {
                            if (cellValue.Return(cv => cv.ToString(), String.Empty) == "AttributeId")
                                worksheet.Row(endRow).OutlineLevel = 1;
                        }
                    }

                    if (worksheet.Row(endRow).OutlineLevel != 0)
                    {
                        managerProductAttribute.ReadFromXlsx(worksheet, endRow, ExportProductAttribute.ProducAttributeCellOffset);
                        if (!managerProductAttribute.IsCaption)
                        {
                            var aid = worksheet.Cells[endRow, attributeIdCellNum].Value.Return(Convert.ToInt32, -1);
                            allAttributeIds.Add(aid);
                        }

                        endRow++;
                        continue;
                    }

                    if (categoryCellNum > 0)
                    { 
                        var categoryIds = worksheet.Cells[endRow, categoryCellNum].Value.Return(p => p.ToString(), string.Empty);

                        if (!categoryIds.IsEmpty())
                            allCategoriesNames.AddRange(categoryIds.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()));
                    }

                    if (skuCellNum > 0)
                    {
                        var sku = worksheet.Cells[endRow, skuCellNum].Value.Return(p => p.ToString(), string.Empty);

                        if (!sku.IsEmpty())
                            allSku.Add(sku);
                    }

                    if (manufacturerCellNum > 0)
                    { 
                        var manufacturerIds = worksheet.Cells[endRow, manufacturerCellNum].Value.Return(p => p.ToString(), string.Empty);
                        if (!manufacturerIds.IsEmpty())
                            allManufacturersNames.AddRange(manufacturerIds.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()));
                    }

                    endRow++;
                }

                //performance optimization, the check for the existence of the categories in one SQL request
                var notExistingCategories = _categoryService.GetNotExistingCategories(allCategoriesNames.ToArray());
                if (notExistingCategories.Any())
                {
                    throw new ArgumentException(string.Format("The following category name(s) don't exist - {0}", string.Join(", ", notExistingCategories)));
                }

                //performance optimization, the check for the existence of the manufacturers in one SQL request
                var notExistingManufacturers = _manufacturerService.GetNotExistingManufacturers(allManufacturersNames.ToArray());
                if (notExistingManufacturers.Any())
                {
                    throw new ArgumentException(string.Format("The following manufacturer name(s) don't exist - {0}", string.Join(", ", notExistingManufacturers)));
                }

                //performance optimization, the check for the existence of the product attributes in one SQL request
                var notExistingProductAttributes = _productAttributeService.GetNotExistingAttributes(allAttributeIds.ToArray());
                if (notExistingProductAttributes.Any())
                {
                    throw new ArgumentException(string.Format("The following product attribute ID(s) don't exist - {0}", string.Join(", ", notExistingProductAttributes)));
                }

                //performance optimization, load all products by SKU in one SQL request
                var allProductsBySku = _productService.GetProductsBySku(allSku.ToArray());

                //performance optimization, load all categories IDs for products in one SQL request
                var allProductsCategoryIds = _categoryService.GetProductCategoryIds(allProductsBySku.Select(p => p.Id).ToArray());

                //performance optimization, load all categories in one SQL request
                var allCategories = _categoryService.GetAllCategories(showHidden: true);

                //performance optimization, load all manufacturers IDs for products in one SQL request
                var allProductsManufacturerIds = _manufacturerService.GetProductManufacturerIds(allProductsBySku.Select(p => p.Id).ToArray());

                //performance optimization, load all manufacturers in one SQL request
                var allManufacturers = _manufacturerService.GetAllManufacturers(showHidden: true);

                //product to import images
                var productPictureMetadata = new List<ProductPictureMetadata>();

                Product lastLoadedProduct = null;

                for (var iRow = 2; iRow < endRow; iRow++)
                {
                    //imports product attributes
                    if (worksheet.Row(iRow).OutlineLevel != 0)
                    {
                        if (_catalogSettings.ExportImportProductAttributes)
                        {
                            managerProductAttribute.ReadFromXlsx(worksheet, iRow,
                                ExportProductAttribute.ProducAttributeCellOffset);
                            if (lastLoadedProduct == null || managerProductAttribute.IsCaption)
                                continue;

                            var productAttributeId = managerProductAttribute.GetProperty("AttributeId").IntValue;
                            var attributeControlTypeId = managerProductAttribute.GetProperty("AttributeControlType").IntValue;
                            
                            var productAttributeValueId = managerProductAttribute.GetProperty("ProductAttributeValueId").IntValue;
                            var associatedProductId = managerProductAttribute.GetProperty("AssociatedProductId").IntValue;
                            var valueName = managerProductAttribute.GetProperty("ValueName").StringValue;
                            var attributeValueTypeId = managerProductAttribute.GetProperty("AttributeValueType").IntValue;
                            var colorSquaresRgb = managerProductAttribute.GetProperty("ColorSquaresRgb").StringValue;
                            var imageSquaresPictureId = managerProductAttribute.GetProperty("ImageSquaresPictureId").IntValue;
                            var priceAdjustment = managerProductAttribute.GetProperty("PriceAdjustment").DecimalValue;
                            var weightAdjustment = managerProductAttribute.GetProperty("WeightAdjustment").DecimalValue;
                            var cost = managerProductAttribute.GetProperty("Cost").DecimalValue;
                            var quantity = managerProductAttribute.GetProperty("Quantity").IntValue;
                            var isPreSelected = managerProductAttribute.GetProperty("IsPreSelected").BooleanValue;
                            var displayOrder = managerProductAttribute.GetProperty("DisplayOrder").IntValue;
                            var pictureId = managerProductAttribute.GetProperty("PictureId").IntValue;
                            var textPrompt = managerProductAttribute.GetProperty("AttributeTextPrompt").StringValue;
                            var isRequired = managerProductAttribute.GetProperty("AttributeIsRequired").BooleanValue;
                            var attributeDisplayOrder = managerProductAttribute.GetProperty("AttributeDisplayOrder").IntValue;

                            var productAttributeMapping = lastLoadedProduct.ProductAttributeMappings.FirstOrDefault(pam => pam.ProductAttributeId == productAttributeId);
                            
                            if (productAttributeMapping == null)
                            {
                                //insert mapping
                                productAttributeMapping = new ProductAttributeMapping
                                {
                                    ProductId = lastLoadedProduct.Id,
                                    ProductAttributeId = productAttributeId,
                                    TextPrompt = textPrompt,
                                    IsRequired = isRequired,
                                    AttributeControlTypeId = attributeControlTypeId,
                                    DisplayOrder = attributeDisplayOrder
                                };
                                _productAttributeService.InsertProductAttributeMapping(productAttributeMapping);
                            }
                            else
                            {
                                productAttributeMapping.AttributeControlTypeId = attributeControlTypeId;
                                productAttributeMapping.TextPrompt = textPrompt;
                                productAttributeMapping.IsRequired = isRequired;
                                productAttributeMapping.DisplayOrder = attributeDisplayOrder;
                                _productAttributeService.UpdateProductAttributeMapping(productAttributeMapping);
                            }

                            var pav = _productAttributeService.GetProductAttributeValueById(productAttributeValueId);

                            var attributeControlType = (AttributeControlType) attributeControlTypeId;

                            if (pav == null)
                            {
                                switch (attributeControlType)
                                {
                                    case AttributeControlType.Datepicker:
                                    case AttributeControlType.FileUpload:
                                    case AttributeControlType.MultilineTextbox:
                                    case AttributeControlType.TextBox:
                                        continue;
                                }

                                pav = new ProductAttributeValue
                                {
                                    ProductAttributeMappingId = productAttributeMapping.Id,
                                    AttributeValueType = (AttributeValueType) attributeValueTypeId,
                                    AssociatedProductId = associatedProductId,
                                    Name = valueName,
                                    PriceAdjustment = priceAdjustment,
                                    WeightAdjustment = weightAdjustment,
                                    Cost = cost,
                                    IsPreSelected = isPreSelected,
                                    DisplayOrder = displayOrder,
                                    ColorSquaresRgb = colorSquaresRgb,
                                    ImageSquaresPictureId = imageSquaresPictureId,
                                    Quantity = quantity,
                                    PictureId = pictureId
                                };

                                _productAttributeService.InsertProductAttributeValue(pav);
                            }
                            else
                            {
                                pav.AttributeValueTypeId = attributeValueTypeId;
                                pav.AssociatedProductId = associatedProductId;
                                pav.Name = valueName;
                                pav.ColorSquaresRgb = colorSquaresRgb;
                                pav.ImageSquaresPictureId = imageSquaresPictureId;
                                pav.PriceAdjustment = priceAdjustment;
                                pav.WeightAdjustment = weightAdjustment;
                                pav.Cost = cost;
                                pav.Quantity = quantity;
                                pav.IsPreSelected = isPreSelected;
                                pav.DisplayOrder = displayOrder;
                                pav.PictureId = pictureId;

                                _productAttributeService.UpdateProductAttributeValue(pav);
                            }
                        }
                        continue;
                    }

                    manager.ReadFromXlsx(worksheet, iRow);

                    var product = skuCellNum > 0 ? allProductsBySku.FirstOrDefault(p => p.Sku == manager.GetProperty("SKU").StringValue) : null;

                    var isNew = product == null;

                    product = product ?? new Product();

                    if (isNew)
                        product.CreatedOnUtc = DateTime.UtcNow;

                    foreach (var property in manager.GetProperties)
                    {
                        switch (property.PropertyName)
                        {
                            case "ProductType":
                                product.ProductTypeId = property.IntValue;
                                break;
                            case "ParentGroupedProductId":
                                product.ParentGroupedProductId = property.IntValue;
                                break;
                            case "VisibleIndividually":
                                product.VisibleIndividually = property.BooleanValue;
                                break;
                            case "Name":
                                product.Name = property.StringValue;
                                break;
                            case "ShortDescription":
                                product.ShortDescription = property.StringValue;
                                break;
                            case "FullDescription":
                                product.FullDescription = property.StringValue;
                                break;
                            case "Vendor":
                                product.VendorId = property.IntValue;
                                break;
                            case "ProductTemplate":
                                product.ProductTemplateId = property.IntValue;
                                break;
                            case "ShowOnHomePage":
                                product.ShowOnHomePage = property.BooleanValue;
                                break;
                            case "MetaKeywords":
                                product.MetaKeywords = property.StringValue;
                                break;
                            case "MetaDescription":
                                product.MetaDescription = property.StringValue;
                                break;
                            case "MetaTitle":
                                product.MetaTitle = property.StringValue;
                                break;
                            case "AllowCustomerReviews":
                                product.AllowCustomerReviews = property.BooleanValue;
                                break;
                            case "Published":
                                product.Published = property.BooleanValue;
                                break;
                            case "SKU":
                                product.Sku = property.StringValue;
                                break;
                            case "ManufacturerPartNumber":
                                product.ManufacturerPartNumber = property.StringValue;
                                break;
                            case "Gtin":
                                product.Gtin = property.StringValue;
                                break;
                            case "IsGiftCard":
                                product.IsGiftCard = property.BooleanValue;
                                break;
                            case "GiftCardType":
                                product.GiftCardTypeId = property.IntValue;
                                break;
                            case "OverriddenGiftCardAmount":
                                product.OverriddenGiftCardAmount = property.DecimalValue;
                                break;
                            case "RequireOtherProducts":
                                product.RequireOtherProducts = property.BooleanValue;
                                break;
                            case "RequiredProductIds":
                                product.RequiredProductIds = property.StringValue;
                                break;
                            case "AutomaticallyAddRequiredProducts":
                                product.AutomaticallyAddRequiredProducts = property.BooleanValue;
                                break;
                            case "IsDownload":
                                product.IsDownload = property.BooleanValue;
                                break;
                            case "DownloadId":
                                product.DownloadId = property.IntValue;
                                break;
                            case "UnlimitedDownloads":
                                product.UnlimitedDownloads = property.BooleanValue;
                                break;
                            case "MaxNumberOfDownloads":
                                product.MaxNumberOfDownloads = property.IntValue;
                                break;
                            case "DownloadActivationType":
                                product.DownloadActivationTypeId = property.IntValue;
                                break;
                            case "HasSampleDownload":
                                product.HasSampleDownload = property.BooleanValue;
                                break;
                            case "SampleDownloadId":
                                product.SampleDownloadId = property.IntValue;
                                break;
                            case "HasUserAgreement":
                                product.HasUserAgreement = property.BooleanValue;
                                break;
                            case "UserAgreementText":
                                product.UserAgreementText = property.StringValue;
                                break;
                            case "IsRecurring":
                                product.IsRecurring = property.BooleanValue;
                                break;
                            case "RecurringCycleLength":
                                product.RecurringCycleLength = property.IntValue;
                                break;
                            case "RecurringCyclePeriod":
                                product.RecurringCyclePeriodId = property.IntValue;
                                break;
                            case "RecurringTotalCycles":
                                product.RecurringTotalCycles = property.IntValue;
                                break;
                            case "IsRental":
                                product.IsRental = property.BooleanValue;
                                break;
                            case "RentalPriceLength":
                                product.RentalPriceLength = property.IntValue;
                                break;
                            case "RentalPricePeriod":
                                product.RentalPricePeriodId = property.IntValue;
                                break;
                            case "IsShipEnabled":
                                product.IsShipEnabled = property.BooleanValue;
                                break;
                            case "IsFreeShipping":
                                product.IsFreeShipping = property.BooleanValue;
                                break;
                            case "ShipSeparately":
                                product.ShipSeparately = property.BooleanValue;
                                break;
                            case "AdditionalShippingCharge":
                                product.AdditionalShippingCharge = property.DecimalValue;
                                break;
                            case "DeliveryDate":
                                product.DeliveryDateId = property.IntValue;
                                break;
                            case "IsTaxExempt":
                                product.IsTaxExempt = property.BooleanValue;
                                break;
                            case "TaxCategory":
                                product.TaxCategoryId = property.IntValue;
                                break;
                            case "IsTelecommunicationsOrBroadcastingOrElectronicServices":
                                product.IsTelecommunicationsOrBroadcastingOrElectronicServices = property.BooleanValue;
                                break;
                            case "ManageInventoryMethod":
                                product.ManageInventoryMethodId = property.IntValue;
                                break;
                            case "UseMultipleWarehouses":
                                product.UseMultipleWarehouses = property.BooleanValue;
                                break;
                            case "WarehouseId":
                                product.WarehouseId = property.IntValue;
                                break;
                            case "StockQuantity":
                                product.StockQuantity = property.IntValue;
                                break;
                            case "DisplayStockAvailability":
                                product.DisplayStockAvailability = property.BooleanValue;
                                break;
                            case "DisplayStockQuantity":
                                product.DisplayStockQuantity = property.BooleanValue;
                                break;
                            case "MinStockQuantity":
                                product.MinStockQuantity = property.IntValue;
                                break;
                            case "LowStockActivity":
                                product.LowStockActivityId = property.IntValue;
                                break;
                            case "NotifyAdminForQuantityBelow":
                                product.NotifyAdminForQuantityBelow = property.IntValue;
                                break;
                            case "BackorderModeId":
                                product.BackorderModeId = property.IntValue;
                                break;
                            case "AllowBackInStockSubscriptions":
                                product.AllowBackInStockSubscriptions = property.BooleanValue;
                                break;
                            case "OrderMinimumQuantity":
                                product.OrderMinimumQuantity = property.IntValue;
                                break;
                            case "OrderMaximumQuantity":
                                product.OrderMaximumQuantity = property.IntValue;
                                break;
                            case "AllowedQuantities":
                                product.AllowedQuantities = property.StringValue;
                                break;
                            case "AllowAddingOnlyExistingAttributeCombinations":
                                product.AllowAddingOnlyExistingAttributeCombinations = property.BooleanValue;
                                break;
                            case "NotReturnable":
                                product.NotReturnable = property.BooleanValue;
                                break;
                            case "DisableBuyButton":
                                product.DisableBuyButton = property.BooleanValue;
                                break;
                            case "DisableWishlistButton":
                                product.DisableWishlistButton = property.BooleanValue;
                                break;
                            case "AvailableForPreOrder":
                                product.AvailableForPreOrder = property.BooleanValue;
                                break;
                            case "PreOrderAvailabilityStartDateTimeUtc":
                                product.PreOrderAvailabilityStartDateTimeUtc = property.DateTimeNullable;
                                break;
                            case "CallForPrice":
                                product.CallForPrice = property.BooleanValue;
                                break;
                            case "Price":
                                product.Price = property.DecimalValue;
                                break;
                            case "OldPrice":
                                product.OldPrice = property.DecimalValue;
                                break;
                            case "ProductCost":
                                product.ProductCost = property.DecimalValue;
                                break;
                            case "SpecialPrice":
                                product.SpecialPrice = property.DecimalValueNullable;
                                break;
                            case "SpecialPriceStartDateTimeUtc":
                                product.SpecialPriceStartDateTimeUtc = property.DateTimeNullable;
                                break;
                            case "SpecialPriceEndDateTimeUtc":
                                product.SpecialPriceEndDateTimeUtc = property.DateTimeNullable;
                                break;
                            case "CustomerEntersPrice":
                                product.CustomerEntersPrice = property.BooleanValue;
                                break;
                            case "MinimumCustomerEnteredPrice":
                                product.MinimumCustomerEnteredPrice = property.DecimalValue;
                                break;
                            case "MaximumCustomerEnteredPrice":
                                product.MaximumCustomerEnteredPrice = property.DecimalValue;
                                break;
                            case "BasepriceEnabled":
                                product.BasepriceEnabled = property.BooleanValue;
                                break;
                            case "BasepriceAmount":
                                product.BasepriceAmount = property.DecimalValue;
                                break;
                            case "BasepriceUnit":
                                product.BasepriceUnitId = property.IntValue;
                                break;
                            case "BasepriceBaseAmount":
                                product.BasepriceBaseAmount = property.DecimalValue;
                                break;
                            case "BasepriceBaseUnit":
                                product.BasepriceBaseUnitId = property.IntValue;
                                break;
                            case "MarkAsNew":
                                product.MarkAsNew = property.BooleanValue;
                                break;
                            case "MarkAsNewStartDateTimeUtc":
                                product.MarkAsNewStartDateTimeUtc = property.DateTimeNullable;
                                break;
                            case "MarkAsNewEndDateTimeUtc":
                                product.MarkAsNewEndDateTimeUtc = property.DateTimeNullable;
                                break;
                            case "Weight":
                                product.Weight = property.DecimalValue;
                                break;
                            case "Length":
                                product.Length = property.DecimalValue;
                                break;
                            case "Width":
                                product.Width = property.DecimalValue;
                                break;
                            case "Height":
                                product.Height = property.DecimalValue;
                                break;
                        }
                    }

                    //set default product type id
                    if (isNew && properties.All(p => p.PropertyName != "ProductTypeId"))
                        product.ProductType = ProductType.SimpleProduct;

                    product.UpdatedOnUtc = DateTime.UtcNow;

                    if (isNew)
                    {
                        _productService.InsertProduct(product);
                    }
                    else
                    {
                        _productService.UpdateProduct(product);
                    }

                    tempProperty = manager.GetProperty("SeName");
                    if (tempProperty != null)
                    {
                        var seName = tempProperty.StringValue;
                        //search engine name
                        _urlRecordService.SaveSlug(product, product.ValidateSeName(seName, product.Name, true), 0);
                    }

                    tempProperty = manager.GetProperty("Categories");

                    if (tempProperty != null)
                    { 
                        var categoryNames = tempProperty.StringValue;

                        //category mappings
                        var categories = isNew || !allProductsCategoryIds.ContainsKey(product.Id) ? new int[0] : allProductsCategoryIds[product.Id];
                        foreach (var categoryId in categoryNames.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => allCategories.First(c => c.Name == x.Trim()).Id))
                        {
                            if (categories.Any(c => c == categoryId))
                                continue;
                       
                            var productCategory = new ProductCategory
                            {
                                ProductId = product.Id,
                                CategoryId = categoryId,
                                IsFeaturedProduct = false,
                                DisplayOrder = 1
                            };
                            _categoryService.InsertProductCategory(productCategory);
                        }
                    }

                    tempProperty = manager.GetProperty("Manufacturers");
                    if (tempProperty != null)
                    {
                        var manufacturerNames = tempProperty.StringValue;

                        //manufacturer mappings
                        var manufacturers = isNew || !allProductsManufacturerIds.ContainsKey(product.Id) ? new int[0] : allProductsManufacturerIds[product.Id];
                        foreach (var manufacturerId in manufacturerNames.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => allManufacturers.First(m => m.Name == x.Trim()).Id))
                        {
                            if (manufacturers.Any(c => c == manufacturerId))
                                continue;

                            var productManufacturer = new ProductManufacturer
                            {
                                ProductId = product.Id,
                                ManufacturerId = manufacturerId,
                                IsFeaturedProduct = false,
                                DisplayOrder = 1
                            };
                            _manufacturerService.InsertProductManufacturer(productManufacturer);
                        }
                    }
                    
                    var picture1 = manager.GetProperty("Picture1").Return(p => p.StringValue, String.Empty);
                    var picture2 = manager.GetProperty("Picture2").Return(p => p.StringValue, String.Empty);
                    var picture3 = manager.GetProperty("Picture3").Return(p => p.StringValue, String.Empty);

                    productPictureMetadata.Add(new ProductPictureMetadata
                    {
                        ProductItem = product,
                        Picture1Path = picture1,
                        Picture2Path = picture2,
                        Picture3Path = picture3,
                        IsNew = isNew
                    });

                    lastLoadedProduct = product;

                    //update "HasTierPrices" and "HasDiscountsApplied" properties
                    //_productService.UpdateHasTierPricesProperty(product);
                    //_productService.UpdateHasDiscountsApplied(product);
                }
               
                if (_mediaSettings.ImportProductImagesUsingHash && _pictureService.StoreInDb && _dataProvider.SupportedLengthOfBinaryHash() > 0)
                    ImportProductImagesUsingHash(productPictureMetadata, allProductsBySku);
                else
                    ImportProductImagesUsingServices(productPictureMetadata);
            }
            //Trace.WriteLine(DateTime.Now-start);
        }
        public ActionResult CreateIB(ProductModel model)
        {
            bool continueEditing = true;
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageProducts))
                return AccessDeniedView();
            model.ProductTypeId = 5;
            model.ProductTemplateId = 1;
            model.Published = true;
            model.VisibleIndividually = true;

            int minDisplayOrder = 999999;
            if (ModelState.IsValid)
            {
                //a vendor should have access only to his products
                if (_workContext.CurrentVendor != null)
                {
                    model.VendorId = _workContext.CurrentVendor.Id;

                    minDisplayOrder = _productService.GetMinDisplayOrder(model.VendorId);
                }

                model.ShowOnHomePage = true;

                //product
                var catId = model.CategoryId;
                var product = model.ToEntity();
                product.CreatedOnUtc = DateTime.UtcNow;
                product.UpdatedOnUtc = DateTime.UtcNow;
                product.DisplayOrder = minDisplayOrder - 1;
                _productService.InsertProduct(product);
                //search engine name
                model.SeName = product.ValidateSeName(model.SeName, product.Name, true);
                _urlRecordService.SaveSlug(product, model.SeName, 0);
                //locales
                UpdateLocales(product, model);
                //ACL (customer roles)
                SaveProductAcl(product, model);
                //Stores
                SaveStoreMappings(product, model);
                //tags
                SaveProductTags(product, ParseProductTags(model.ProductTags));
                //warehouses
                SaveProductWarehouseInventory(product, model);
                //discounts
                // category
                if(catId > 0)
                {
                    var categoryMapping = new ProductCategory();
                    categoryMapping.CategoryId = catId;
                    categoryMapping.ProductId = product.Id;
                    categoryMapping.DisplayOrder = 1;
                    _categoryService.InsertProductCategory(categoryMapping);
                }
                var allDiscounts = _discountService.GetAllDiscounts(DiscountType.AssignedToSkus, showHidden: true);
                foreach (var discount in allDiscounts)
                {
                    if (model.SelectedDiscountIds != null && model.SelectedDiscountIds.Contains(discount.Id))
                        product.AppliedDiscounts.Add(discount);
                }
                _productService.UpdateProduct(product);
                _productService.UpdateHasDiscountsApplied(product);

                // attributes
                //var attributes = _productAttributeService.GetAllProductAttributes();
                //var attribute = attributes.FirstOrDefault(a => a.Name == "Circa Date");

                //if (attribute != null && model.CircaDate.Year != 1)
                //    SaveAttribute(model, attribute);

                //attribute = attributes.FirstOrDefault(a => a.Name == "Materials");
                //if (attribute != null &&!string.IsNullOrWhiteSpace(model.Material))
                //    SaveAttribute(model, attribute);

                //attribute = attributes.FirstOrDefault(a => a.Name == "Country");
                //if (attribute != null && !string.IsNullOrWhiteSpace(model.Country))
                //    SaveAttribute(model, attribute);

                //attribute = attributes.FirstOrDefault(a => a.Name == "DesignBy");
                //if (attribute != null && !string.IsNullOrWhiteSpace(model.DesignBy))
                //    SaveAttribute(model, attribute);

                //attribute = attributes.FirstOrDefault(a => a.Name == "TermsCondtion");
                //if (attribute != null )
                //    SaveAttribute(model, attribute);

                //attribute = attributes.FirstOrDefault(a => a.Name == "Color");
                //if (attribute != null && !string.IsNullOrWhiteSpace(model.Color))
                //    SaveAttribute(model, attribute);

                //activity log
                _customerActivityService.InsertActivity("AddNewProduct", _localizationService.GetResource("ActivityLog.AddNewProduct"), product.Name);

                SuccessNotification(_localizationService.GetResource("Admin.Catalog.Products.Added"));
                if (_workContext.CurrentVendor != null)
                {

                    //return RedirectToAction("myhome", "vendor", new { id = _workContext.CurrentVendor.Id });
                    return RedirectToAction("EditIB", new { id = product.Id });
                }

                return continueEditing ? RedirectToAction("Edit", new { id = product.Id }) : RedirectToAction("List");
            }

            //If we got this far, something failed, redisplay form
            PrepareProductModel(model, null, false, true);
            PrepareAclModel(model, null, true);
            PrepareStoresMappingModel(model, null, true);
            return View(model);
        }
        public ActionResult ProductCategoryInsert(ProductModel.ProductCategoryModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageProducts))
                return AccessDeniedView();

            var productId = model.ProductId;
            var categoryId = model.CategoryId;

            //a vendor should have access only to his products
            if (_workContext.CurrentVendor != null)
            {
                var product = _productService.GetProductById(productId);
                if (product != null && product.VendorId != _workContext.CurrentVendor.Id)
                {
                    return Content("This is not your product");
                }
            }

            var existingProductCategories = _categoryService.GetProductCategoriesByCategoryId(categoryId, showHidden: true);
            if (existingProductCategories.FindProductCategory(productId, categoryId) == null)
            {
                var productCategory = new ProductCategory
                {
                    ProductId = productId,
                    CategoryId = categoryId,
                    DisplayOrder = model.DisplayOrder
                };
                //a vendor cannot edit "IsFeaturedProduct" property
                if (_workContext.CurrentVendor == null)
                {
                    productCategory.IsFeaturedProduct = model.IsFeaturedProduct;
                }
                _categoryService.InsertProductCategory(productCategory);
            }

            return new NullJsonResult();
        }
Exemple #17
0
        /// <summary>
        /// Import products from XLSX file
        /// </summary>
        /// <param name="stream">Stream</param>
        public virtual void ImportProductsFromXlsx(Stream stream)
        {
            // ok, we can run the real code of the sample now
            using (var xlPackage = new ExcelPackage(stream))
            {
                // get the first worksheet in the workbook
                var worksheet = xlPackage.Workbook.Worksheets.FirstOrDefault();
                if (worksheet == null)
                    throw new NopException("No worksheet found");

                //the columns
                var properties = new string[]
                {
                    "Name",
                    "ShortDescription",
                    "FullDescription",
                    "VendorId",
                    "ProductTemplateId",
                    "ShowOnHomePage",
                    "MetaKeywords",
                    "MetaDescription",
                    "MetaTitle",
                    "SeName",
                    "AllowCustomerReviews",
                    "Published",
                    "ProductVariantName",
                    "SKU",
                    "ManufacturerPartNumber",
                    "Gtin",
                    "IsGiftCard",
                    "GiftCardTypeId",
                    "RequireOtherProducts",
                    "RequiredProductVariantIds",
                    "AutomaticallyAddRequiredProductVariants",
                    "IsDownload",
                    "DownloadId",
                    "UnlimitedDownloads",
                    "MaxNumberOfDownloads",
                    "DownloadActivationTypeId",
                    "HasSampleDownload",
                    "SampleDownloadId",
                    "HasUserAgreement",
                    "UserAgreementText",
                    "IsRecurring",
                    "RecurringCycleLength",
                    "RecurringCyclePeriodId",
                    "RecurringTotalCycles",
                    "IsShipEnabled",
                    "IsFreeShipping",
                    "AdditionalShippingCharge",
                    "IsTaxExempt",
                    "TaxCategoryId",
                    "ManageInventoryMethodId",
                    "StockQuantity",
                    "DisplayStockAvailability",
                    "DisplayStockQuantity",
                    "MinStockQuantity",
                    "LowStockActivityId",
                    "NotifyAdminForQuantityBelow",
                    "BackorderModeId",
                    "AllowBackInStockSubscriptions",
                    "OrderMinimumQuantity",
                    "OrderMaximumQuantity",
                    "AllowedQuantities",
                    "DisableBuyButton",
                    "DisableWishlistButton",
                    "CallForPrice",
                    "Price",
                    "OldPrice",
                    "ProductCost",
                    "SpecialPrice",
                    "SpecialPriceStartDateTimeUtc",
                    "SpecialPriceEndDateTimeUtc",
                    "CustomerEntersPrice",
                    "MinimumCustomerEnteredPrice",
                    "MaximumCustomerEnteredPrice",
                    "Weight",
                    "Length",
                    "Width",
                    "Height",
                    "CreatedOnUtc",
                    "CategoryIds",
                    "ManufacturerIds",
                    "Picture1",
                    "Picture2",
                    "Picture3",
                };

                int iRow = 2;
                while (true)
                {
                    bool allColumnsAreEmpty = true;
                    for (var i = 1; i <= properties.Length; i++)
                        if (worksheet.Cells[iRow, i].Value != null && !String.IsNullOrEmpty(worksheet.Cells[iRow, i].Value.ToString()))
                        {
                            allColumnsAreEmpty = false;
                            break;
                        }
                    if (allColumnsAreEmpty)
                        break;

                    string name = worksheet.Cells[iRow, GetColumnIndex(properties, "Name")].Value as string;
                    string shortDescription = worksheet.Cells[iRow, GetColumnIndex(properties, "ShortDescription")].Value as string;
                    string fullDescription = worksheet.Cells[iRow, GetColumnIndex(properties, "FullDescription")].Value as string;
                    int vendorId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "VendorId")].Value);
                    int productTemplateId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ProductTemplateId")].Value);
                    bool showOnHomePage = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "ShowOnHomePage")].Value);
                    string metaKeywords = worksheet.Cells[iRow, GetColumnIndex(properties, "MetaKeywords")].Value as string;
                    string metaDescription = worksheet.Cells[iRow, GetColumnIndex(properties, "MetaDescription")].Value as string;
                    string metaTitle = worksheet.Cells[iRow, GetColumnIndex(properties, "MetaTitle")].Value as string;
                    string seName = worksheet.Cells[iRow, GetColumnIndex(properties, "SeName")].Value as string;
                    bool allowCustomerReviews = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowCustomerReviews")].Value);
                    bool published = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "Published")].Value);
                    string productVariantName = worksheet.Cells[iRow, GetColumnIndex(properties, "ProductVariantName")].Value as string;
                    string sku = worksheet.Cells[iRow, GetColumnIndex(properties, "SKU")].Value as string;
                    string manufacturerPartNumber = worksheet.Cells[iRow, GetColumnIndex(properties, "ManufacturerPartNumber")].Value as string;
                    string gtin = worksheet.Cells[iRow, GetColumnIndex(properties, "Gtin")].Value as string;
                    bool isGiftCard = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsGiftCard")].Value);
                    int giftCardTypeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "GiftCardTypeId")].Value);
                    bool requireOtherProducts = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "RequireOtherProducts")].Value);
                    string requiredProductVariantIds = worksheet.Cells[iRow, GetColumnIndex(properties, "RequiredProductVariantIds")].Value as string;
                    bool automaticallyAddRequiredProductVariants = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AutomaticallyAddRequiredProductVariants")].Value);
                    bool isDownload = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsDownload")].Value);
                    int downloadId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DownloadId")].Value);
                    bool unlimitedDownloads = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "UnlimitedDownloads")].Value);
                    int maxNumberOfDownloads = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "MaxNumberOfDownloads")].Value);
                    int downloadActivationTypeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "DownloadActivationTypeId")].Value);
                    bool hasSampleDownload = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "HasSampleDownload")].Value);
                    int sampleDownloadId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "SampleDownloadId")].Value);
                    bool hasUserAgreement = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "HasUserAgreement")].Value);
                    string userAgreementText = worksheet.Cells[iRow, GetColumnIndex(properties, "UserAgreementText")].Value as string;
                    bool isRecurring = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsRecurring")].Value);
                    int recurringCycleLength = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringCycleLength")].Value);
                    int recurringCyclePeriodId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringCyclePeriodId")].Value);
                    int recurringTotalCycles = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "RecurringTotalCycles")].Value);
                    bool isShipEnabled = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsShipEnabled")].Value);
                    bool isFreeShipping = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsFreeShipping")].Value);
                    decimal additionalShippingCharge = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "AdditionalShippingCharge")].Value);
                    bool isTaxExempt = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "IsTaxExempt")].Value);
                    int taxCategoryId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "TaxCategoryId")].Value);
                    int manageInventoryMethodId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "ManageInventoryMethodId")].Value);
                    int stockQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "StockQuantity")].Value);
                    bool displayStockAvailability = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisplayStockAvailability")].Value);
                    bool displayStockQuantity = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisplayStockQuantity")].Value);
                    int minStockQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "MinStockQuantity")].Value);
                    int lowStockActivityId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "LowStockActivityId")].Value);
                    int notifyAdminForQuantityBelow = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "NotifyAdminForQuantityBelow")].Value);
                    int backorderModeId = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "BackorderModeId")].Value);
                    bool allowBackInStockSubscriptions = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "AllowBackInStockSubscriptions")].Value);
                    int orderMinimumQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "OrderMinimumQuantity")].Value);
                    int orderMaximumQuantity = Convert.ToInt32(worksheet.Cells[iRow, GetColumnIndex(properties, "OrderMaximumQuantity")].Value);
                    string allowedQuantities = worksheet.Cells[iRow, GetColumnIndex(properties, "AllowedQuantities")].Value as string;
                    bool disableBuyButton = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisableBuyButton")].Value);
                    bool disableWishlistButton = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "DisableWishlistButton")].Value);
                    bool callForPrice = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "CallForPrice")].Value);
                    decimal price = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Price")].Value);
                    decimal oldPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "OldPrice")].Value);
                    decimal productCost = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "ProductCost")].Value);
                    decimal? specialPrice = null;
                    var specialPriceExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPrice")].Value;
                    if (specialPriceExcel != null)
                        specialPrice = Convert.ToDecimal(specialPriceExcel);
                    DateTime? specialPriceStartDateTimeUtc = null;
                    var specialPriceStartDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPriceStartDateTimeUtc")].Value;
                    if (specialPriceStartDateTimeUtcExcel != null)
                        specialPriceStartDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(specialPriceStartDateTimeUtcExcel));
                    DateTime? specialPriceEndDateTimeUtc = null;
                    var specialPriceEndDateTimeUtcExcel = worksheet.Cells[iRow, GetColumnIndex(properties, "SpecialPriceEndDateTimeUtc")].Value;
                    if (specialPriceEndDateTimeUtcExcel != null)
                        specialPriceEndDateTimeUtc = DateTime.FromOADate(Convert.ToDouble(specialPriceEndDateTimeUtcExcel));

                    bool customerEntersPrice = Convert.ToBoolean(worksheet.Cells[iRow, GetColumnIndex(properties, "CustomerEntersPrice")].Value);
                    decimal minimumCustomerEnteredPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "MinimumCustomerEnteredPrice")].Value);
                    decimal maximumCustomerEnteredPrice = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "MaximumCustomerEnteredPrice")].Value);
                    decimal weight = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Weight")].Value);
                    decimal length = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Length")].Value);
                    decimal width = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Width")].Value);
                    decimal height = Convert.ToDecimal(worksheet.Cells[iRow, GetColumnIndex(properties, "Height")].Value);
                    DateTime createdOnUtc = DateTime.FromOADate(Convert.ToDouble(worksheet.Cells[iRow, GetColumnIndex(properties, "CreatedOnUtc")].Value));
                    string categoryIds = worksheet.Cells[iRow, GetColumnIndex(properties, "CategoryIds")].Value as string;
                    string manufacturerIds = worksheet.Cells[iRow, GetColumnIndex(properties, "ManufacturerIds")].Value as string;
                    string picture1 = worksheet.Cells[iRow, GetColumnIndex(properties, "Picture1")].Value as string;
                    string picture2 = worksheet.Cells[iRow, GetColumnIndex(properties, "Picture2")].Value as string;
                    string picture3 = worksheet.Cells[iRow, GetColumnIndex(properties, "Picture3")].Value as string;

                    var productVariant = _productService.GetProductVariantBySku(sku);
                    if (productVariant != null)
                    {
                        //product
                        var product = productVariant.Product;
                        product.Name = name;
                        product.ShortDescription = shortDescription;
                        product.FullDescription = fullDescription;
                        product.VendorId = vendorId;
                        product.ProductTemplateId = productTemplateId;
                        product.ShowOnHomePage = showOnHomePage;
                        product.MetaKeywords = metaKeywords;
                        product.MetaDescription = metaDescription;
                        product.MetaTitle = metaTitle;
                        product.AllowCustomerReviews = allowCustomerReviews;
                        product.Published = published;
                        product.CreatedOnUtc = createdOnUtc;
                        product.UpdatedOnUtc = DateTime.UtcNow;
                        _productService.UpdateProduct(product);

                        //search engine name
                        _urlRecordService.SaveSlug(product, product.ValidateSeName(seName, product.Name, true), 0);

                        //variant
                        productVariant.Name = productVariantName;
                        productVariant.Sku = sku;
                        productVariant.ManufacturerPartNumber = manufacturerPartNumber;
                        productVariant.Gtin = gtin;
                        productVariant.IsGiftCard = isGiftCard;
                        productVariant.GiftCardTypeId = giftCardTypeId;
                        productVariant.RequireOtherProducts = requireOtherProducts;
                        productVariant.RequiredProductVariantIds = requiredProductVariantIds;
                        productVariant.AutomaticallyAddRequiredProductVariants = automaticallyAddRequiredProductVariants;
                        productVariant.IsDownload = isDownload;
                        productVariant.DownloadId = downloadId;
                        productVariant.UnlimitedDownloads = unlimitedDownloads;
                        productVariant.MaxNumberOfDownloads = maxNumberOfDownloads;
                        productVariant.DownloadActivationTypeId = downloadActivationTypeId;
                        productVariant.HasSampleDownload = hasSampleDownload;
                        productVariant.SampleDownloadId = sampleDownloadId;
                        productVariant.HasUserAgreement = hasUserAgreement;
                        productVariant.UserAgreementText = userAgreementText;
                        productVariant.IsRecurring = isRecurring;
                        productVariant.RecurringCycleLength = recurringCycleLength;
                        productVariant.RecurringCyclePeriodId = recurringCyclePeriodId;
                        productVariant.RecurringTotalCycles = recurringTotalCycles;
                        productVariant.IsShipEnabled = isShipEnabled;
                        productVariant.IsFreeShipping = isFreeShipping;
                        productVariant.AdditionalShippingCharge = additionalShippingCharge;
                        productVariant.IsTaxExempt = isTaxExempt;
                        productVariant.TaxCategoryId = taxCategoryId;
                        productVariant.ManageInventoryMethodId = manageInventoryMethodId;
                        productVariant.StockQuantity = stockQuantity;
                        productVariant.DisplayStockAvailability = displayStockAvailability;
                        productVariant.DisplayStockQuantity = displayStockQuantity;
                        productVariant.MinStockQuantity = minStockQuantity;
                        productVariant.LowStockActivityId = lowStockActivityId;
                        productVariant.NotifyAdminForQuantityBelow = notifyAdminForQuantityBelow;
                        productVariant.BackorderModeId = backorderModeId;
                        productVariant.AllowBackInStockSubscriptions = allowBackInStockSubscriptions;
                        productVariant.OrderMinimumQuantity = orderMinimumQuantity;
                        productVariant.OrderMaximumQuantity = orderMaximumQuantity;
                        productVariant.AllowedQuantities = allowedQuantities;
                        productVariant.DisableBuyButton = disableBuyButton;
                        productVariant.DisableWishlistButton = disableWishlistButton;
                        productVariant.CallForPrice = callForPrice;
                        productVariant.Price = price;
                        productVariant.OldPrice = oldPrice;
                        productVariant.ProductCost = productCost;
                        productVariant.SpecialPrice = specialPrice;
                        productVariant.SpecialPriceStartDateTimeUtc = specialPriceStartDateTimeUtc;
                        productVariant.SpecialPriceEndDateTimeUtc = specialPriceEndDateTimeUtc;
                        productVariant.CustomerEntersPrice = customerEntersPrice;
                        productVariant.MinimumCustomerEnteredPrice = minimumCustomerEnteredPrice;
                        productVariant.MaximumCustomerEnteredPrice = maximumCustomerEnteredPrice;
                        productVariant.Weight = weight;
                        productVariant.Length = length;
                        productVariant.Width = width;
                        productVariant.Height = height;
                        productVariant.Published = published;
                        productVariant.CreatedOnUtc = createdOnUtc;
                        productVariant.UpdatedOnUtc = DateTime.UtcNow;

                        _productService.UpdateProductVariant(productVariant);
                    }
                    else
                    {
                        //product
                        var product = new Product()
                        {
                            Name = name,
                            ShortDescription = shortDescription,
                            FullDescription = fullDescription,
                            ShowOnHomePage = showOnHomePage,
                            MetaKeywords = metaKeywords,
                            MetaDescription = metaDescription,
                            MetaTitle = metaTitle,
                            AllowCustomerReviews = allowCustomerReviews,
                            Published = published,
                            CreatedOnUtc = createdOnUtc,
                            UpdatedOnUtc = DateTime.UtcNow
                        };
                        _productService.InsertProduct(product);

                        //search engine name
                        _urlRecordService.SaveSlug(product, product.ValidateSeName(seName, product.Name, true), 0);

                        //variant
                        productVariant = new ProductVariant()
                        {
                            ProductId = product.Id,
                            Name = productVariantName,
                            Sku = sku,
                            ManufacturerPartNumber = manufacturerPartNumber,
                            Gtin = gtin,
                            IsGiftCard = isGiftCard,
                            GiftCardTypeId = giftCardTypeId,
                            RequireOtherProducts = requireOtherProducts,
                            RequiredProductVariantIds = requiredProductVariantIds,
                            AutomaticallyAddRequiredProductVariants = automaticallyAddRequiredProductVariants,
                            IsDownload = isDownload,
                            DownloadId = downloadId,
                            UnlimitedDownloads = unlimitedDownloads,
                            MaxNumberOfDownloads = maxNumberOfDownloads,
                            DownloadActivationTypeId = downloadActivationTypeId,
                            HasSampleDownload = hasSampleDownload,
                            SampleDownloadId = sampleDownloadId,
                            HasUserAgreement = hasUserAgreement,
                            UserAgreementText = userAgreementText,
                            IsRecurring = isRecurring,
                            RecurringCycleLength = recurringCycleLength,
                            RecurringCyclePeriodId = recurringCyclePeriodId,
                            RecurringTotalCycles = recurringTotalCycles,
                            IsShipEnabled = isShipEnabled,
                            IsFreeShipping = isFreeShipping,
                            AdditionalShippingCharge = additionalShippingCharge,
                            IsTaxExempt = isTaxExempt,
                            TaxCategoryId = taxCategoryId,
                            ManageInventoryMethodId = manageInventoryMethodId,
                            StockQuantity = stockQuantity,
                            DisplayStockAvailability = displayStockAvailability,
                            DisplayStockQuantity = displayStockQuantity,
                            MinStockQuantity = minStockQuantity,
                            LowStockActivityId = lowStockActivityId,
                            NotifyAdminForQuantityBelow = notifyAdminForQuantityBelow,
                            BackorderModeId = backorderModeId,
                            AllowBackInStockSubscriptions = allowBackInStockSubscriptions,
                            OrderMinimumQuantity = orderMinimumQuantity,
                            OrderMaximumQuantity = orderMaximumQuantity,
                            AllowedQuantities = allowedQuantities,
                            DisableBuyButton = disableBuyButton,
                            CallForPrice = callForPrice,
                            Price = price,
                            OldPrice = oldPrice,
                            ProductCost = productCost,
                            SpecialPrice = specialPrice,
                            SpecialPriceStartDateTimeUtc = specialPriceStartDateTimeUtc,
                            SpecialPriceEndDateTimeUtc = specialPriceEndDateTimeUtc,
                            CustomerEntersPrice = customerEntersPrice,
                            MinimumCustomerEnteredPrice = minimumCustomerEnteredPrice,
                            MaximumCustomerEnteredPrice = maximumCustomerEnteredPrice,
                            Weight = weight,
                            Length = length,
                            Width = width,
                            Height = height,
                            Published = published,
                            CreatedOnUtc = createdOnUtc,
                            UpdatedOnUtc = DateTime.UtcNow
                        };

                        _productService.InsertProductVariant(productVariant);
                    }

                    //category mappings
                    if (!String.IsNullOrEmpty(categoryIds))
                    {
                        foreach (var id in categoryIds.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())))
                        {
                            if (productVariant.Product.ProductCategories.FirstOrDefault(x => x.CategoryId == id) == null)
                            {
                                //ensure that category exists
                                var category = _categoryService.GetCategoryById(id);
                                if (category != null)
                                {
                                    var productCategory = new ProductCategory()
                                    {
                                        ProductId = productVariant.Product.Id,
                                        CategoryId = category.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _categoryService.InsertProductCategory(productCategory);
                                }
                            }
                        }
                    }

                    //manufacturer mappings
                    if (!String.IsNullOrEmpty(manufacturerIds))
                    {
                        foreach (var id in manufacturerIds.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim())))
                        {
                            if (productVariant.Product.ProductManufacturers.FirstOrDefault(x => x.ManufacturerId == id) == null)
                            {
                                //ensure that manufacturer exists
                                var manufacturer = _manufacturerService.GetManufacturerById(id);
                                if (manufacturer != null)
                                {
                                    var productManufacturer = new ProductManufacturer()
                                    {
                                        ProductId = productVariant.Product.Id,
                                        ManufacturerId = manufacturer.Id,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 1
                                    };
                                    _manufacturerService.InsertProductManufacturer(productManufacturer);
                                }
                            }
                        }
                    }

                    //pictures
                    foreach (var picture in new string[] { picture1, picture2, picture3 })
                    {
                        if (String.IsNullOrEmpty(picture))
                            continue;

                        productVariant.Product.ProductPictures.Add(new ProductPicture()
                        {
                            Picture = _pictureService.InsertPicture(File.ReadAllBytes(picture), "image/jpeg", _pictureService.GetPictureSeName(name), true),
                            DisplayOrder = 1,
                        });
                        _productService.UpdateProduct(productVariant.Product);
                    }

                    //update "HasTierPrices" and "HasDiscountsApplied" properties
                    _productService.UpdateHasTierPricesProperty(productVariant);
                    _productService.UpdateHasDiscountsApplied(productVariant);

                    //next product
                    iRow++;
                }
            }
        }
        /// <summary>
        /// Create a copy of product with all depended data
        /// </summary>
        /// <param name="product">The product to copy</param>
        /// <param name="newName">The name of product duplicate</param>
        /// <param name="isPublished">A value indicating whether the product duplicate should be published</param>
        /// <param name="copyImages">A value indicating whether the product images should be copied</param>
        /// <param name="copyAssociatedProducts">A value indicating whether the copy associated products</param>
        /// <returns>Product copy</returns>
        public virtual Product CopyProduct(Product product, string newName,
            bool isPublished = true, bool copyImages = true, bool copyAssociatedProducts = true)
        {
            if (product == null)
                throw new ArgumentNullException("product");

            if (String.IsNullOrEmpty(newName))
                throw new ArgumentException("Product name is required");

            //product download & sample download
            int downloadId = product.DownloadId;
            int sampleDownloadId = product.SampleDownloadId;
            if (product.IsDownload)
            {
                var download = _downloadService.GetDownloadById(product.DownloadId);
                if (download != null)
                {
                    var downloadCopy = new Download
                    {
                        DownloadGuid = Guid.NewGuid(),
                        UseDownloadUrl = download.UseDownloadUrl,
                        DownloadUrl = download.DownloadUrl,
                        DownloadBinary = download.DownloadBinary,
                        ContentType = download.ContentType,
                        Filename = download.Filename,
                        Extension = download.Extension,
                        IsNew = download.IsNew,
                    };
                    _downloadService.InsertDownload(downloadCopy);
                    downloadId = downloadCopy.Id;
                }

                if (product.HasSampleDownload)
                {
                    var sampleDownload = _downloadService.GetDownloadById(product.SampleDownloadId);
                    if (sampleDownload != null)
                    {
                        var sampleDownloadCopy = new Download
                        {
                            DownloadGuid = Guid.NewGuid(),
                            UseDownloadUrl = sampleDownload.UseDownloadUrl,
                            DownloadUrl = sampleDownload.DownloadUrl,
                            DownloadBinary = sampleDownload.DownloadBinary,
                            ContentType = sampleDownload.ContentType,
                            Filename = sampleDownload.Filename,
                            Extension = sampleDownload.Extension,
                            IsNew = sampleDownload.IsNew
                        };
                        _downloadService.InsertDownload(sampleDownloadCopy);
                        sampleDownloadId = sampleDownloadCopy.Id;
                    }
                }
            }

            // product
            var productCopy = new Product
            {
                ProductTypeId = product.ProductTypeId,
                ParentGroupedProductId = product.ParentGroupedProductId,
                VisibleIndividually = product.VisibleIndividually,
                Name = newName,
                ShortDescription = product.ShortDescription,
                FullDescription = product.FullDescription,
                VendorId = product.VendorId,
                ProductTemplateId = product.ProductTemplateId,
                AdminComment = product.AdminComment,
                ShowOnHomePage = product.ShowOnHomePage,
                MetaKeywords = product.MetaKeywords,
                MetaDescription = product.MetaDescription,
                MetaTitle = product.MetaTitle,
                AllowCustomerReviews = product.AllowCustomerReviews,
                LimitedToStores = product.LimitedToStores,
                Sku = product.Sku,
                ManufacturerPartNumber = product.ManufacturerPartNumber,
                Gtin = product.Gtin,
                IsGiftCard = product.IsGiftCard,
                GiftCardType = product.GiftCardType,
                RequireOtherProducts = product.RequireOtherProducts,
                RequiredProductIds = product.RequiredProductIds,
                AutomaticallyAddRequiredProducts = product.AutomaticallyAddRequiredProducts,
                IsDownload = product.IsDownload,
                DownloadId = downloadId,
                UnlimitedDownloads = product.UnlimitedDownloads,
                MaxNumberOfDownloads = product.MaxNumberOfDownloads,
                DownloadExpirationDays = product.DownloadExpirationDays,
                DownloadActivationType = product.DownloadActivationType,
                HasSampleDownload = product.HasSampleDownload,
                SampleDownloadId = sampleDownloadId,
                HasUserAgreement = product.HasUserAgreement,
                UserAgreementText = product.UserAgreementText,
                IsRecurring = product.IsRecurring,
                RecurringCycleLength = product.RecurringCycleLength,
                RecurringCyclePeriod = product.RecurringCyclePeriod,
                RecurringTotalCycles = product.RecurringTotalCycles,
                IsRental = product.IsRental,
                RentalPriceLength = product.RentalPriceLength,
                RentalPricePeriod = product.RentalPricePeriod,
                IsShipEnabled = product.IsShipEnabled,
                IsFreeShipping = product.IsFreeShipping,
                ShipSeparately = product.ShipSeparately,
                AdditionalShippingCharge = product.AdditionalShippingCharge,
                DeliveryDateId = product.DeliveryDateId,
                IsTaxExempt = product.IsTaxExempt,
                TaxCategoryId = product.TaxCategoryId,
                IsTelecommunicationsOrBroadcastingOrElectronicServices = product.IsTelecommunicationsOrBroadcastingOrElectronicServices,
                ManageInventoryMethod = product.ManageInventoryMethod,
                UseMultipleWarehouses = product.UseMultipleWarehouses,
                WarehouseId = product.WarehouseId,
                StockQuantity = product.StockQuantity,
                DisplayStockAvailability = product.DisplayStockAvailability,
                DisplayStockQuantity = product.DisplayStockQuantity,
                MinStockQuantity = product.MinStockQuantity,
                LowStockActivityId = product.LowStockActivityId,
                NotifyAdminForQuantityBelow = product.NotifyAdminForQuantityBelow,
                BackorderMode = product.BackorderMode,
                AllowBackInStockSubscriptions = product.AllowBackInStockSubscriptions,
                OrderMinimumQuantity = product.OrderMinimumQuantity,
                OrderMaximumQuantity = product.OrderMaximumQuantity,
                AllowedQuantities = product.AllowedQuantities,
                AllowAddingOnlyExistingAttributeCombinations = product.AllowAddingOnlyExistingAttributeCombinations,
                DisableBuyButton = product.DisableBuyButton,
                DisableWishlistButton = product.DisableWishlistButton,
                AvailableForPreOrder = product.AvailableForPreOrder,
                PreOrderAvailabilityStartDateTimeUtc = product.PreOrderAvailabilityStartDateTimeUtc,
                CallForPrice = product.CallForPrice,
                Price = product.Price,
                OldPrice = product.OldPrice,
                ProductCost = product.ProductCost,
                SpecialPrice = product.SpecialPrice,
                SpecialPriceStartDateTimeUtc = product.SpecialPriceStartDateTimeUtc,
                SpecialPriceEndDateTimeUtc = product.SpecialPriceEndDateTimeUtc,
                CustomerEntersPrice = product.CustomerEntersPrice,
                MinimumCustomerEnteredPrice = product.MinimumCustomerEnteredPrice,
                MaximumCustomerEnteredPrice = product.MaximumCustomerEnteredPrice,
                BasepriceEnabled = product.BasepriceEnabled,
                BasepriceAmount = product.BasepriceAmount,
                BasepriceUnitId = product.BasepriceUnitId,
                BasepriceBaseAmount = product.BasepriceBaseAmount,
                BasepriceBaseUnitId = product.BasepriceBaseUnitId,
                Weight = product.Weight,
                Length = product.Length,
                Width = product.Width,
                Height = product.Height,
                AvailableStartDateTimeUtc = product.AvailableStartDateTimeUtc,
                AvailableEndDateTimeUtc = product.AvailableEndDateTimeUtc,
                DisplayOrder = product.DisplayOrder,
                Published = isPublished,
                Deleted = product.Deleted,
                CreatedOnUtc = DateTime.UtcNow,
                UpdatedOnUtc = DateTime.UtcNow
            };

            //validate search engine name
            _productService.InsertProduct(productCopy);

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

            var languages = _languageService.GetAllLanguages(true);

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

                var shortDescription = product.GetLocalized(x => x.ShortDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(shortDescription))
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.ShortDescription, shortDescription, lang.Id);

                var fullDescription = product.GetLocalized(x => x.FullDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(fullDescription))
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.FullDescription, fullDescription, lang.Id);

                var metaKeywords = product.GetLocalized(x => x.MetaKeywords, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaKeywords))
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaKeywords, metaKeywords, lang.Id);

                var metaDescription = product.GetLocalized(x => x.MetaDescription, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaDescription))
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaDescription, metaDescription, lang.Id);

                var metaTitle = product.GetLocalized(x => x.MetaTitle, lang.Id, false, false);
                if (!String.IsNullOrEmpty(metaTitle))
                    _localizedEntityService.SaveLocalizedValue(productCopy, x => x.MetaTitle, metaTitle, lang.Id);

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

            //product tags
            foreach (var productTag in product.ProductTags)
            {
                productCopy.ProductTags.Add(productTag);
            }
            _productService.UpdateProduct(productCopy);

            //product pictures
            //variable to store original and new picture identifiers
            var originalNewPictureIdentifiers = new Dictionary<int, int>();
            if (copyImages)
            {
                foreach (var productPicture in product.ProductPictures)
                {
                    var picture = productPicture.Picture;
                    var pictureCopy = _pictureService.InsertPicture(
                        _pictureService.LoadPictureBinary(picture),
                        picture.MimeType,
                        _pictureService.GetPictureSeName(newName),
                        picture.AltAttribute,
                        picture.TitleAttribute);
                    _productService.InsertProductPicture(new ProductPicture
                    {
                        ProductId = productCopy.Id,
                        PictureId = pictureCopy.Id,
                        DisplayOrder = productPicture.DisplayOrder
                    });
                    originalNewPictureIdentifiers.Add(picture.Id, pictureCopy.Id);
                }
            }

            // product <-> warehouses mappings
            foreach (var pwi in product.ProductWarehouseInventory)
            {
                var pwiCopy = new ProductWarehouseInventory
                {
                    ProductId = productCopy.Id,
                    WarehouseId = pwi.WarehouseId,
                    StockQuantity = pwi.StockQuantity,
                    ReservedQuantity = 0,
                };

                productCopy.ProductWarehouseInventory.Add(pwiCopy);
            }
            _productService.UpdateProduct(productCopy);

            // product <-> categories mappings
            foreach (var productCategory in product.ProductCategories)
            {
                var productCategoryCopy = new ProductCategory
                {
                    ProductId = productCopy.Id,
                    CategoryId = productCategory.CategoryId,
                    IsFeaturedProduct = productCategory.IsFeaturedProduct,
                    DisplayOrder = productCategory.DisplayOrder
                };

                _categoryService.InsertProductCategory(productCategoryCopy);
            }

            // product <-> manufacturers mappings
            foreach (var productManufacturers in product.ProductManufacturers)
            {
                var productManufacturerCopy = new ProductManufacturer
                {
                    ProductId = productCopy.Id,
                    ManufacturerId = productManufacturers.ManufacturerId,
                    IsFeaturedProduct = productManufacturers.IsFeaturedProduct,
                    DisplayOrder = productManufacturers.DisplayOrder
                };

                _manufacturerService.InsertProductManufacturer(productManufacturerCopy);
            }

            // product <-> releated products mappings
            foreach (var relatedProduct in _productService.GetRelatedProductsByProductId1(product.Id, true))
            {
                _productService.InsertRelatedProduct(
                    new RelatedProduct
                    {
                        ProductId1 = productCopy.Id,
                        ProductId2 = relatedProduct.ProductId2,
                        DisplayOrder = relatedProduct.DisplayOrder
                    });
            }

            // product <-> cross sells mappings
            foreach (var csProduct in _productService.GetCrossSellProductsByProductId1(product.Id, true))
            {
                _productService.InsertCrossSellProduct(
                    new CrossSellProduct
                    {
                        ProductId1 = productCopy.Id,
                        ProductId2 = csProduct.ProductId2,
                    });
            }

            // product specifications
            foreach (var productSpecificationAttribute in product.ProductSpecificationAttributes)
            {
                var psaCopy = new ProductSpecificationAttribute
                {
                    ProductId = productCopy.Id,
                    AttributeTypeId = productSpecificationAttribute.AttributeTypeId,
                    SpecificationAttributeOptionId = productSpecificationAttribute.SpecificationAttributeOptionId,
                    CustomValue = productSpecificationAttribute.CustomValue,
                    AllowFiltering = productSpecificationAttribute.AllowFiltering,
                    ShowOnProductPage = productSpecificationAttribute.ShowOnProductPage,
                    DisplayOrder = productSpecificationAttribute.DisplayOrder
                };
                _specificationAttributeService.InsertProductSpecificationAttribute(psaCopy);
            }

            //store mapping
            var selectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(product);
            foreach (var id in selectedStoreIds)
            {
                _storeMappingService.InsertStoreMapping(productCopy, id);
            }


            // product <-> attributes mappings
            var associatedAttributes = new Dictionary<int, int>();
            var associatedAttributeValues = new Dictionary<int, int>();
            foreach (var productAttributeMapping in _productAttributeService.GetProductAttributeMappingsByProductId(product.Id))
            {
                var productAttributeMappingCopy = new ProductAttributeMapping
                {
                    ProductId = productCopy.Id,
                    ProductAttributeId = productAttributeMapping.ProductAttributeId,
                    TextPrompt = productAttributeMapping.TextPrompt,
                    IsRequired = productAttributeMapping.IsRequired,
                    AttributeControlTypeId = productAttributeMapping.AttributeControlTypeId,
                    DisplayOrder = productAttributeMapping.DisplayOrder,
                    ValidationMinLength = productAttributeMapping.ValidationMinLength,
                    ValidationMaxLength = productAttributeMapping.ValidationMaxLength,
                    ValidationFileAllowedExtensions = productAttributeMapping.ValidationFileAllowedExtensions,
                    ValidationFileMaximumSize = productAttributeMapping.ValidationFileMaximumSize,
                    DefaultValue = productAttributeMapping.DefaultValue,
                };
                _productAttributeService.InsertProductAttributeMapping(productAttributeMappingCopy);
                //save associated value (used for combinations copying)
                associatedAttributes.Add(productAttributeMapping.Id, productAttributeMappingCopy.Id);

                // product attribute values
                var productAttributeValues = _productAttributeService.GetProductAttributeValues(productAttributeMapping.Id);
                foreach (var productAttributeValue in productAttributeValues)
                {
                    int attributeValuePictureId = 0;
                    if (originalNewPictureIdentifiers.ContainsKey(productAttributeValue.PictureId))
                    {
                        attributeValuePictureId = originalNewPictureIdentifiers[productAttributeValue.PictureId];
                    }
                    var attributeValueCopy = new ProductAttributeValue
                    {
                        ProductAttributeMappingId = productAttributeMappingCopy.Id,
                        AttributeValueTypeId = productAttributeValue.AttributeValueTypeId,
                        AssociatedProductId = productAttributeValue.AssociatedProductId,
                        Name = productAttributeValue.Name,
                        ColorSquaresRgb = productAttributeValue.ColorSquaresRgb,
                        PriceAdjustment = productAttributeValue.PriceAdjustment,
                        WeightAdjustment = productAttributeValue.WeightAdjustment,
                        Cost = productAttributeValue.Cost,
                        Quantity = productAttributeValue.Quantity,
                        IsPreSelected = productAttributeValue.IsPreSelected,
                        DisplayOrder = productAttributeValue.DisplayOrder,
                        PictureId = attributeValuePictureId,
                    };
                    _productAttributeService.InsertProductAttributeValue(attributeValueCopy);

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

                    //localization
                    foreach (var lang in languages)
                    {
                        var name = productAttributeValue.GetLocalized(x => x.Name, lang.Id, false, false);
                        if (!String.IsNullOrEmpty(name))
                            _localizedEntityService.SaveLocalizedValue(attributeValueCopy, x => x.Name, name, lang.Id);
                    }
                }
            }
            //attribute combinations
            foreach (var combination in _productAttributeService.GetAllProductAttributeCombinations(product.Id))
            {
                //generate new AttributesXml according to new value IDs
                string newAttributesXml = "";
                var parsedProductAttributes = _productAttributeParser.ParseProductAttributeMappings(combination.AttributesXml);
                foreach (var oldAttribute in parsedProductAttributes)
                {
                    if (associatedAttributes.ContainsKey(oldAttribute.Id))
                    {
                        var newAttribute = _productAttributeService.GetProductAttributeMappingById(associatedAttributes[oldAttribute.Id]);
                        if (newAttribute != null)
                        {
                            var oldAttributeValuesStr = _productAttributeParser.ParseValues(combination.AttributesXml, oldAttribute.Id);
                            foreach (var oldAttributeValueStr in oldAttributeValuesStr)
                            {
                                if (newAttribute.ShouldHaveValues())
                                {
                                    //attribute values
                                    int oldAttributeValue = int.Parse(oldAttributeValueStr);
                                    if (associatedAttributeValues.ContainsKey(oldAttributeValue))
                                    {
                                        var newAttributeValue = _productAttributeService.GetProductAttributeValueById(associatedAttributeValues[oldAttributeValue]);
                                        if (newAttributeValue != null)
                                        {
                                            newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml,
                                                newAttribute, newAttributeValue.Id.ToString());
                                        }
                                    }
                                }
                                else
                                {
                                    //just a text
                                    newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml,
                                        newAttribute, oldAttributeValueStr);
                                }
                            }
                        }
                    }
                }
                var combinationCopy = new ProductAttributeCombination
                {
                    ProductId = productCopy.Id,
                    AttributesXml = newAttributesXml,
                    StockQuantity = combination.StockQuantity,
                    AllowOutOfStockOrders = combination.AllowOutOfStockOrders,
                    Sku = combination.Sku,
                    ManufacturerPartNumber = combination.ManufacturerPartNumber,
                    Gtin = combination.Gtin,
                    OverriddenPrice = combination.OverriddenPrice,
                    NotifyAdminForQuantityBelow = combination.NotifyAdminForQuantityBelow
                };
                _productAttributeService.InsertProductAttributeCombination(combinationCopy);
            }

            //tier prices
            foreach (var tierPrice in product.TierPrices)
            {
                _productService.InsertTierPrice(
                    new TierPrice
                    {
                        ProductId = productCopy.Id,
                        StoreId = tierPrice.StoreId,
                        CustomerRoleId = tierPrice.CustomerRoleId,
                        Quantity = tierPrice.Quantity,
                        Price = tierPrice.Price
                    });
            }

            // product <-> discounts mapping
            foreach (var discount in product.AppliedDiscounts)
            {
                productCopy.AppliedDiscounts.Add(discount);
                _productService.UpdateProduct(productCopy);
            }


            //update "HasTierPrices" and "HasDiscountsApplied" properties
            _productService.UpdateHasTierPricesProperty(productCopy);
            _productService.UpdateHasDiscountsApplied(productCopy);


            //associated products
            if (copyAssociatedProducts)
            {
                var associatedProducts = _productService.GetAssociatedProducts(product.Id, showHidden: true);
                foreach (var associatedProduct in associatedProducts)
                {
                    var associatedProductCopy = CopyProduct(associatedProduct, string.Format("Copy of {0}", associatedProduct.Name),
                        isPublished, copyImages, false);
                    associatedProductCopy.ParentGroupedProductId = productCopy.Id;
                    _productService.UpdateProduct(productCopy);
                }
            }

            return productCopy;
        }
Exemple #19
0
        public ActionResult ProductCategoryInsert(GridCommand command, ProductModel.ProductCategoryModel model)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
                return AccessDeniedView();

            var productCategory = new ProductCategory()
            {
                ProductId = model.ProductId,
                CategoryId = Int32.Parse(model.Category), //use Category property (not CategoryId) because appropriate property is stored in it
                IsFeaturedProduct = model.IsFeaturedProduct,
                DisplayOrder = model.DisplayOrder
            };
            _categoryService.InsertProductCategory(productCategory);

            return ProductCategoryList(command, model.ProductId);
        }
        public ActionResult Register(VendorRegisterViewModel vrmodel, string returnUrl, bool captchaValid, FormCollection form)
        {
            if (vrmodel.CountryId == 0)
            {
                ModelState.AddModelError("CountryId", "This is a required field");
                if (vrmodel.StateProvinceId == 0)
                {
                    ModelState.AddModelError("StateProvinceId", "This is a required field");
                }                
                PrepareVendorRegisterModel(vrmodel);
                return View(vrmodel);
            }

            var dataSettingsManager = new DataSettingsManager();
            var dataProviderSettings = dataSettingsManager.LoadSettings();
            var context = new VendorMembershipContext(dataProviderSettings.DataConnectionString);
            using (var transaction = context.Database.BeginTransaction())
            {
                try
                {
                    if (ModelState.IsValid)
                    {
                        if (ValidateVendorModel(vrmodel))
                        {
                            Vendor vendor = new Vendor();
                            vendor.Name = vrmodel.AttentionTo;
                            vendor.Email = vrmodel.Email;
                            vendor.Active = true;
                            var vendorServiceCore = EngineContext.Current.Resolve<IVendorService>();
                            vendorServiceCore.InsertVendor(vendor);

                            var store = new Store
                            {
                                Name = vrmodel.ShopName,
                                Url = "http://" + vrmodel.ShopName + ".tameiontestsite.com/",
                                Hosts = vrmodel.ShopName + ".tameiontestsite.com,www." + vrmodel.ShopName + ".yourstore.com",
                                CompanyName = vrmodel.ShopName
                            };
                            _storeService.InsertStore(store);
                            vendor.setStore(store);

                            Address address = new Address
                            {
                                City = vrmodel.City,
                                CountryId = vrmodel.CountryId,
                                StateProvinceId = vrmodel.StateProvinceId,
                                PhoneNumber = vrmodel.PhoneNumber,
                                CreatedOnUtc = DateTime.UtcNow,
                                Email = vrmodel.Email,
                                ZipPostalCode = vrmodel.ZipPostalCode,
                                Address1 = vrmodel.Address1,
                                Address2 = vrmodel.Address2
                            };
                            _addressService.InsertAddress(address);
                            _vendorAddressService.InsertVendorAddress(new VendorAddress
                            {
                                VendorId = vendor.Id,
                                AddressId = address.Id,
                                AddressType = AddressType.Address
                            });

                            _genericAttributeService.SaveAttribute(
                                vendor,
                                Nop.Plugin.Misc.VendorMembership.Domain.VendorAttributes.ShopName,
                                vrmodel.ShopName);

                            _genericAttributeService.SaveAttribute(
                                vendor,
                                Nop.Plugin.Misc.VendorMembership.Domain.VendorAttributes.Password,
                                vrmodel.Password);

                            _genericAttributeService.SaveAttribute(
                                vendor,
                                Nop.Plugin.Misc.VendorMembership.Domain.VendorAttributes.EnableGoogleAnalytics,
                                vrmodel.EnableGoogleAnalytics);

                            _genericAttributeService.SaveAttribute(
                                vendor,
                                Nop.Plugin.Misc.VendorMembership.Domain.VendorAttributes.GoogleAnalyticsAccountNumber,
                                vrmodel.GoogleAnalyticsAccountNumber);

                            _genericAttributeService.SaveAttribute(
                                vendor,
                                Nop.Plugin.Misc.VendorMembership.Domain.VendorAttributes.LogoImage,
                                vrmodel.LogoImage);

                            //_genericAttributeService.SaveAttribute(
                            //    vendor,
                            //    Nop.Plugin.Misc.VendorMembership.Domain.VendorAttributes.PreferredShippingCarrier,
                            //    model.PreferredShippingCarrier);

                            _genericAttributeService.SaveAttribute(
                                vendor,
                                Nop.Plugin.Misc.VendorMembership.Domain.VendorAttributes.PreferredSubdomainName,
                                vrmodel.PreferredSubdomainName);

                            var productServiceCore = EngineContext.Current.Resolve<Nop.Services.Catalog.IProductService>();

                            foreach (var BusinessTypeId in vrmodel.BusinessTypeIds)
                            {
                                var vb = new VendorBusinessType();
                                //var vendorServiceExt = new VendorService(_vendorBusinessTypeRepository);
                                vb.VendorId = vendor.Id;
                                vb.BusinessTypeId = BusinessTypeId;
                                //vendorServiceExt.InsertVendorBusinessType(vb);
                            }

                            // create groupdeals
                            for (int i = 0; i < 10; i++)
                            {
                                int groupDealProductId = _groupDealService.CreateGroupDealProduct(vrmodel.ShopName + " register", 25m);
                                foreach (var categoryId in vrmodel.BusinessTypeIds)
                                {
                                    var productCategory = new ProductCategory
                                    {
                                        ProductId = groupDealProductId,
                                        CategoryId = categoryId,
                                        IsFeaturedProduct = false,
                                        DisplayOrder = 0
                                    };
                                    _categoryService.InsertProductCategory(productCategory);
                                }
                            }
                            vendor.SetHasPaidGroupDeals(true);

                            var model = new RegisterModel();
                            PrepareCustomerRegisterModel(model, false);
                            //enable newsletter by default
                            model.Newsletter = _customerSettings.NewsletterTickedByDefault;
                            model = vrmodel.ToRegisterModel(model);

                            // core code starts
                            //check whether registration is allowed
                            if (_customerSettings.UserRegistrationType == UserRegistrationType.Disabled)
                                return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.Disabled });

                            if (_workContext.CurrentCustomer.IsRegistered())
                            {
                                //Already registered customer. 
                                _authenticationService.SignOut();

                                //Save a new record
                                _workContext.CurrentCustomer = _customerService.InsertGuestCustomer();
                            }
                            var customer = _workContext.CurrentCustomer;

                            //add to 'Vendors' role
                            var vendorRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Vendors);
                            if (vendorRole == null)
                                throw new NopException("'Vendors' role could not be loaded");
                            customer.CustomerRoles.Add(vendorRole);
                            customer.VendorId = vendor.Id;

                            //custom customer attributes
                            var customerAttributesXml = ParseCustomCustomerAttributes(form);
                            var customerAttributeWarnings = _customerAttributeParser.GetAttributeWarnings(customerAttributesXml);
                            foreach (var error in customerAttributeWarnings)
                            {
                                ModelState.AddModelError("", error);
                            }

                            //validate CAPTCHA
                            if (_captchaSettings.Enabled && _captchaSettings.ShowOnRegistrationPage && !captchaValid)
                            {
                                ModelState.AddModelError("", _localizationService.GetResource("Common.WrongCaptcha"));
                            }


                            if (_customerSettings.UsernamesEnabled && model.Username != null)
                            {
                                model.Username = model.Username.Trim();
                            }

                            bool isApproved = _customerSettings.UserRegistrationType == UserRegistrationType.Standard;
                            var registrationRequest = new CustomerRegistrationRequest(customer, 
                                model.Email,
                                _customerSettings.UsernamesEnabled ? model.Username : model.Email, 
                                model.Password, 
                                _customerSettings.DefaultPasswordFormat, 
                                _storeContext.CurrentStore.Id,
                                isApproved);
                            var registrationResult = _customerRegistrationService.RegisterCustomer(registrationRequest);
                            if (registrationResult.Success)
                            {
                                //properties
                                if (_dateTimeSettings.AllowCustomersToSetTimeZone)
                                {
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.TimeZoneId, model.TimeZoneId);
                                }
                                //VAT number
                                if (_taxSettings.EuVatEnabled)
                                {
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.VatNumber, model.VatNumber);

                                    string vatName;
                                    string vatAddress;
                                    var vatNumberStatus = _taxService.GetVatNumberStatus(model.VatNumber, out vatName, out vatAddress);
                                    _genericAttributeService.SaveAttribute(customer,
                                        SystemCustomerAttributeNames.VatNumberStatusId,
                                        (int)vatNumberStatus);
                                    //send VAT number admin notification
                                    if (!String.IsNullOrEmpty(model.VatNumber) && _taxSettings.EuVatEmailAdminWhenNewVatSubmitted)
                                        _workflowMessageService.SendNewVatSubmittedStoreOwnerNotification(customer, model.VatNumber, vatAddress, _localizationSettings.DefaultAdminLanguageId);

                                }

                                //form fields
                                if (_customerSettings.GenderEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Gender, model.Gender);
                                _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.FirstName, model.FirstName);
                                _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastName, model.LastName);
                                if (_customerSettings.DateOfBirthEnabled)
                                {
                                    DateTime? dateOfBirth = model.ParseDateOfBirth();
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.DateOfBirth, dateOfBirth);
                                }
                                if (_customerSettings.CompanyEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Company, model.Company);
                                if (_customerSettings.StreetAddressEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StreetAddress, model.StreetAddress);
                                if (_customerSettings.StreetAddress2Enabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StreetAddress2, model.StreetAddress2);
                                if (_customerSettings.ZipPostalCodeEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.ZipPostalCode, model.ZipPostalCode);
                                if (_customerSettings.CityEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.City, model.City);
                                if (_customerSettings.CountryEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CountryId, model.CountryId);
                                if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StateProvinceId, model.StateProvinceId);
                                if (_customerSettings.PhoneEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Phone, model.Phone);
                                if (_customerSettings.FaxEnabled)
                                    _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Fax, model.Fax);

                                //newsletter
                                if (_customerSettings.NewsletterEnabled)
                                {
                                    //save newsletter value
                                    var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmailAndStoreId(model.Email, _storeContext.CurrentStore.Id);
                                    if (newsletter != null)
                                    {
                                        if (model.Newsletter)
                                        {
                                            newsletter.Active = true;
                                            _newsLetterSubscriptionService.UpdateNewsLetterSubscription(newsletter);
                                        }
                                        //else
                                        //{
                                        //When registering, not checking the newsletter check box should not take an existing email address off of the subscription list.
                                        //_newsLetterSubscriptionService.DeleteNewsLetterSubscription(newsletter);
                                        //}
                                    }
                                    else
                                    {
                                        if (model.Newsletter)
                                        {
                                            _newsLetterSubscriptionService.InsertNewsLetterSubscription(new NewsLetterSubscription
                                            {
                                                NewsLetterSubscriptionGuid = Guid.NewGuid(),
                                                Email = model.Email,
                                                Active = true,
                                                StoreId = _storeContext.CurrentStore.Id,
                                                CreatedOnUtc = DateTime.UtcNow
                                            });
                                        }
                                    }
                                }

                                //save customer attributes
                                _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CustomCustomerAttributes, customerAttributesXml);

                                //login customer now
                                if (isApproved)
                                    _authenticationService.SignIn(customer, true);

                                //associated with external account (if possible)
                                TryAssociateAccountWithExternalAccount(customer);

                                //insert default address (if possible)
                                var defaultAddress = new Address
                                {
                                    FirstName = customer.GetAttribute<string>(SystemCustomerAttributeNames.FirstName),
                                    LastName = customer.GetAttribute<string>(SystemCustomerAttributeNames.LastName),
                                    Email = customer.Email,
                                    Company = customer.GetAttribute<string>(SystemCustomerAttributeNames.Company),
                                    CountryId = customer.GetAttribute<int>(SystemCustomerAttributeNames.CountryId) > 0 ?
                                        (int?)customer.GetAttribute<int>(SystemCustomerAttributeNames.CountryId) : null,
                                    StateProvinceId = customer.GetAttribute<int>(SystemCustomerAttributeNames.StateProvinceId) > 0 ?
                                        (int?)customer.GetAttribute<int>(SystemCustomerAttributeNames.StateProvinceId) : null,
                                    City = customer.GetAttribute<string>(SystemCustomerAttributeNames.City),
                                    Address1 = customer.GetAttribute<string>(SystemCustomerAttributeNames.StreetAddress),
                                    Address2 = customer.GetAttribute<string>(SystemCustomerAttributeNames.StreetAddress2),
                                    ZipPostalCode = customer.GetAttribute<string>(SystemCustomerAttributeNames.ZipPostalCode),
                                    PhoneNumber = customer.GetAttribute<string>(SystemCustomerAttributeNames.Phone),
                                    FaxNumber = customer.GetAttribute<string>(SystemCustomerAttributeNames.Fax),
                                    CreatedOnUtc = customer.CreatedOnUtc
                                };
                                if (this._addressService.IsAddressValid(defaultAddress))
                                {
                                    //some validation
                                    if (defaultAddress.CountryId == 0)
                                        defaultAddress.CountryId = null;
                                    if (defaultAddress.StateProvinceId == 0)
                                        defaultAddress.StateProvinceId = null;
                                    //set default address
                                    customer.Addresses.Add(defaultAddress);
                                    customer.BillingAddress = defaultAddress;
                                    customer.ShippingAddress = defaultAddress;
                                    _customerService.UpdateCustomer(customer);
                                }

                                //notifications
                                if (_customerSettings.NotifyNewCustomerRegistration)
                                    _workflowMessageService.SendCustomerRegisteredNotificationMessage(customer, _localizationSettings.DefaultAdminLanguageId);

                                switch (_customerSettings.UserRegistrationType)
                                {
                                    case UserRegistrationType.EmailValidation:
                                        {
                                            //email validation message
                                            _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.AccountActivationToken, Guid.NewGuid().ToString());
                                            _workflowMessageService.SendCustomerEmailValidationMessage(customer, _workContext.WorkingLanguage.Id);

                                            //result
                                            //return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.EmailValidation });
                                            return RedirectToAction("Index", "Orders", new { area = "Vendor" });
                                        }
                                    case UserRegistrationType.AdminApproval:
                                        {
                                            //return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.AdminApproval });
                                            return RedirectToAction("Index", "Orders", new { area = "Vendor" });
                                        }
                                    case UserRegistrationType.Standard:
                                        {
                                            //send customer welcome message
                                            _workflowMessageService.SendCustomerWelcomeMessage(customer, _workContext.WorkingLanguage.Id);

                                            var redirectUrl = Url.RouteUrl("RegisterResult", new { resultId = (int)UserRegistrationType.Standard });
                                            if (!String.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
                                                redirectUrl = _webHelper.ModifyQueryString(redirectUrl, "returnurl=" + HttpUtility.UrlEncode(returnUrl), null);
                                            //return Redirect(redirectUrl);
                                            return RedirectToAction("Index", "Orders", new { area = "Vendor" });
                                        }
                                    default:
                                        {
                                            return RedirectToAction("Index", "Orders", new { area = "Vendor" });
                                        }
                                }
                            }

                            //errors
                            foreach (var error in registrationResult.Errors)
                                ModelState.AddModelError("", error);
                        }
                    }
                    transaction.Commit();

                    //If we got this far, something failed, redisplay form
                    PrepareVendorRegisterModel(vrmodel);
                    return View(vrmodel);
                }
                catch(Exception e)
                {
                    transaction.Rollback();
                    ModelState.AddModelError("", e.Message);
                    PrepareVendorRegisterModel(vrmodel);
                    return View(vrmodel);
                }
            }
        }