public static int DeleteAll <T>(this IRepository <T> rs, Expression <Func <T, bool> > predicate = null, bool cascade = false) where T : BaseEntity
        {
            var count = 0;

            using (var scope = new DbContextScope(ctx: rs.Context, autoDetectChanges: false, validateOnSave: false, hooksEnabled: false, autoCommit: false))
            {
                var query = rs.Table;
                if (predicate != null)
                {
                    query = query.Where(predicate);
                }

                if (cascade)
                {
                    var records = query.ToList();
                    foreach (var chunk in records.Slice(500))
                    {
                        rs.DeleteRange(chunk.ToList());
                        count += rs.Context.SaveChanges();
                    }
                }
                else
                {
                    var ids = query.Select(x => new { Id = x.Id }).ToList();
                    foreach (var chunk in ids.Slice(500))
                    {
                        rs.DeleteRange(chunk.Select(x => x.Id));
                        count += rs.Context.SaveChanges();
                    }
                }
            }

            return(count);
        }
        public void CalculateFutureSchedules(IEnumerable<ScheduleTask> tasks, bool isAppStart = false)
        {
            Guard.ArgumentNotNull(() => tasks);

            using (var scope = new DbContextScope(autoCommit: false))
            {
                var now = DateTime.UtcNow;
                foreach (var task in tasks)
                {
                    task.NextRunUtc = GetNextSchedule(task);
                    if (isAppStart)
                    {
                        task.ProgressPercent = null;
                        task.ProgressMessage = null;
                        if (task.LastEndUtc.GetValueOrDefault() < task.LastStartUtc)
                        {
                            task.LastEndUtc = task.LastStartUtc;
                            task.LastError = T("Admin.System.ScheduleTasks.AbnormalAbort");
                        }
                    }
                    this.UpdateTask(task);
                }

                scope.Commit();
            }
        }
		public void Migrate(IEnumerable<SettingEntry> entries)
		{
			Guard.ArgumentNotNull(() => entries);

			if (!entries.Any())
				return;

			using (var scope = new DbContextScope(_ctx, autoDetectChanges: false))
			{
				var toDelete = new List<Setting>();
				var toAdd = new List<Setting>();

				// First perform DELETE actions
				foreach (var entry in entries.Where(x => x.Value == null))
				{
					bool isPattern = entry.KeyIsGroup;
					if (!HasSettings(entry.Key, isPattern))
						continue; // nothing to delete

					var db = GetSettings(entry.Key, isPattern);
					_settings.RemoveRange(db);
				}

				_ctx.SaveChanges();

				// Then perform ADD actions
				foreach (var entry in entries.Where(x => x.Value.HasValue()))
				{
					var existing = toAdd.FirstOrDefault(x => x.Name.Equals(entry.Key, StringComparison.InvariantCultureIgnoreCase));
					if (existing != null)
					{
						existing.Value = entry.Value;
						continue;
					}

					if (HasSettings(entry.Key, false))
						continue; // skip existing (we don't perform updates)

					_settings.Add(new Setting { 
						Name = entry.Key,
						Value = entry.Value,
						StoreId = 0
					});
				}

				_ctx.SaveChanges();
			}
		}
        public void Generate(UrlHelper urlHelper, Stream stream)
        {
            using (var scope = new DbContextScope(autoDetectChanges: false, forceNoTracking: true))
            {
                _writer = new XmlTextWriter(stream, Encoding.UTF8);
                _writer.Formatting = Formatting.Indented;
                _writer.WriteStartDocument();
                _writer.WriteStartElement("urlset");
                _writer.WriteAttributeString("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");
                _writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
                _writer.WriteAttributeString("xsi:schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd");

                GenerateUrlNodes(urlHelper);

                _writer.WriteEndElement();
                _writer.Close();
            }
        }
        public void Execute(TaskExecutionContext ctx)
        {
            // delete all media records which are in transient state since at least 3 hours
            var olderThan = DateTime.UtcNow.AddHours(-3);

            // delete Downloads
            _downloadRepository.DeleteAll(x => x.IsTransient && x.UpdatedOnUtc < olderThan);

            // delete Pictures
            var autoCommit = _pictureRepository.AutoCommitEnabled;
            _pictureRepository.AutoCommitEnabled = false;

            try
            {
                using (var scope = new DbContextScope(autoDetectChanges: false, validateOnSave: false, hooksEnabled: false))
                {
                    var pictures = _pictureRepository.Where(x => x.IsTransient && x.UpdatedOnUtc < olderThan).ToList();
                    foreach (var picture in pictures)
                    {
                        _pictureService.DeletePicture(picture);
                    }

                    _pictureRepository.Context.SaveChanges();

                    if (DataSettings.Current.IsSqlServer)
                    {
                        try
                        {
                            _pictureRepository.Context.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true);
                        }
                        catch { }
                    }
                }
            }
            finally
            {
                _pictureRepository.AutoCommitEnabled = autoCommit;
            }
        }
        public virtual void DeleteThemeVariables(string themeName, int storeId)
        {
            Guard.ArgumentNotEmpty(themeName, "themeName");

            var query = from v in _rsVariables.Table
                        where v.StoreId == storeId && v.Theme.Equals(themeName, StringComparison.OrdinalIgnoreCase)
                        select v;

            if (query.Any())
            {
                using (var scope = new DbContextScope(ctx:  _rsVariables.Context, autoCommit: false))
                {
                    query.Each(v =>
                    {
                        _rsVariables.Delete(v);
                        _eventPublisher.EntityDeleted(v);
                    });

                    _cacheManager.Remove(THEMEVARS_BY_THEME_KEY.FormatInvariant(themeName, storeId));

                    _rsVariables.Context.SaveChanges();
                }
            }
        }
        public virtual IEnumerable<WidgetRouteInfo> GetWidgets(string widgetZone, object model)
        {
			string actionName;
            string controllerName;
            RouteValueDictionary routeValues;
			var storeId = _storeContext.CurrentStore.Id;

            #region Plugin Widgets

			var widgets = _widgetService.LoadActiveWidgetsByWidgetZone(widgetZone, storeId);
            foreach (var widget in widgets)
            {
                widget.Value.GetDisplayWidgetRoute(widgetZone, model, storeId, out actionName, out controllerName, out routeValues);

				if (actionName.HasValue() && controllerName.HasValue())
				{
					yield return new WidgetRouteInfo
					{
						ActionName = actionName,
						ControllerName = controllerName,
						RouteValues = routeValues
					};
				}
            }

            #endregion

            #region Topic Widgets

            // add special "topic widgets" to the list
			var allTopicsCacheKey = string.Format(ModelCacheEventConsumer.TOPIC_WIDGET_ALL_MODEL_KEY, storeId, _workContext.WorkingLanguage.Id);
            // get topic widgets from STATIC cache
			var topicWidgets = _services.Cache.Get(allTopicsCacheKey, () =>
            {
				using (var scope = new DbContextScope(forceNoTracking: true))
				{
					var allTopicWidgets = _topicService.GetAllTopics(storeId).Where(x => x.RenderAsWidget).ToList();
					var stubs = allTopicWidgets
						.Select(t => new TopicWidgetStub
						{
							Id = t.Id,
							Bordered = t.WidgetBordered,
							WrapContent = !t.WidgetWrapContent.HasValue || t.WidgetWrapContent.Value,
							ShowTitle = t.WidgetShowTitle,
							SystemName = t.SystemName.SanitizeHtmlId(),
							Title = t.GetLocalized(x => t.Title),
                            TitleTag = t.TitleTag,
							Body = t.GetLocalized(x => t.Body),
							WidgetZones = t.GetWidgetZones().ToArray(),
							Priority = t.Priority
						})
						.OrderBy(t => t.Priority)
						.ToList();
					return stubs;
				}
            });

            var byZoneTopicsCacheKey = "SmartStore.TopicWidgets.ZoneMapped";
            // save widgets to zones map in request cache
			var topicsByZone = _cacheManager.Get(byZoneTopicsCacheKey, () =>
            {
				var map = new Multimap<string, WidgetRouteInfo>();

				foreach (var widget in topicWidgets)
				{
					var zones = widget.WidgetZones;
					if (zones != null && zones.Any())
					{
						foreach (var zone in zones.Select(x => x.ToLower()))
						{
							var routeInfo = new WidgetRouteInfo
							{
								ControllerName = "Topic",
								ActionName = "TopicWidget",
								RouteValues = new RouteValueDictionary()
								{
									{"Namespaces", "SmartStore.Web.Controllers"},
									{"area", null},
									{"widgetZone", zone},
									{"model", new TopicWidgetModel 
									{ 
										Id = widget.Id,
										SystemName = widget.SystemName,
										WrapContent = widget.WrapContent,
										ShowTitle = widget.ShowTitle,
										IsBordered = widget.Bordered,
										Title = String.IsNullOrEmpty(widget.Title) ? "div" : widget.Title,
                                        TitleTag = widget.TitleTag ?? "h3",
										Html = widget.Body
									} }
								}
							};
							map.Add(zone, routeInfo);
						}
					}
				}

				return map;

				#region Obsolete
				//var result = from t in topicWidgets 
				//			 where t.WidgetZones.Contains(widgetZone, StringComparer.InvariantCultureIgnoreCase)
				//			 orderby t.Priority
				//			 select new WidgetRouteInfo
				//			 {
				//				 ControllerName = "Topic",
				//				 ActionName = "TopicWidget",
				//				 RouteValues = new RouteValueDictionary()
				//				 {
				//					{"Namespaces", "SmartStore.Web.Controllers"},
				//					{"area", null},
				//					{"widgetZone", widgetZone},
				//					{"model", new TopicWidgetModel 
				//					{ 
				//						Id = t.Id,
				//						SystemName = t.SystemName,
				//						ShowTitle = t.ShowTitle,
				//						IsBordered = t.Bordered,
				//						Title = t.Title,
				//						Html = t.Body
				//					} }
				//				 }
				//			 };

				//return result.ToList(); 
				#endregion
			});

			if (topicsByZone.ContainsKey(widgetZone.ToLower()))
			{
				var zoneWidgets = topicsByZone[widgetZone.ToLower()];
				foreach (var topicWidget in zoneWidgets)
				{
					yield return topicWidget;
				}
			}

            #endregion


			#region Request scoped widgets (provided by IWidgetProvider)

			var requestScopedWidgets = _widgetProvider.GetWidgets(widgetZone);
			if (requestScopedWidgets != null)
			{
				foreach (var widget in requestScopedWidgets)
				{
					yield return widget;
				}
			}

			#endregion
        }
Exemple #8
0
        public void Flush()
        {
            if (_entries.Count == 0)
                return;

            string ipAddress = "";
            string pageUrl = "";
            string referrerUrl = "";
            var currentCustomer = _workContext.CurrentCustomer;

            try
            {
                ipAddress = _webHelper.GetCurrentIpAddress();
                pageUrl = _webHelper.GetThisPageUrl(true);
                referrerUrl = _webHelper.GetUrlReferrer();
            }
            catch { }

            using (var scope = new DbContextScope(autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                foreach (var context in _entries)
                {
                    if (context.ShortMessage.IsEmpty() && context.FullMessage.IsEmpty())
                        continue;

                    Log log = null;

                    try
                    {
                        string shortMessage = context.ShortMessage.NaIfEmpty();
                        string fullMessage = context.FullMessage.EmptyNull();
                        string contentHash = null;

                        if (context.HashNotFullMessage || context.HashIpAddress)
                        {
                            contentHash = (shortMessage
                                + (context.HashNotFullMessage ? "" : fullMessage)
                                + (context.HashIpAddress ? ipAddress.EmptyNull() : "")
                            ).Hash(Encoding.Unicode, true);
                        }
                        else
                        {
                            contentHash = (shortMessage + fullMessage).Hash(Encoding.Unicode, true);
                        }

                        log = _logRepository.Table.OrderByDescending(x => x.CreatedOnUtc).FirstOrDefault(x => x.ContentHash == contentHash);

                        if (log == null)
                        {
                            log = new Log
                            {
                                Frequency = 1,
                                LogLevel = context.LogLevel,
                                ShortMessage = shortMessage,
                                FullMessage = fullMessage,
                                IpAddress = ipAddress,
                                Customer = context.Customer ?? currentCustomer,
                                PageUrl = pageUrl,
                                ReferrerUrl = referrerUrl,
                                CreatedOnUtc = DateTime.UtcNow,
                                ContentHash = contentHash
                            };

                            _logRepository.Insert(log);
                        }
                        else
                        {
                            if (log.Frequency < 2147483647)
                                log.Frequency = log.Frequency + 1;

                            log.LogLevel = context.LogLevel;
                            log.IpAddress = ipAddress;
                            log.Customer = context.Customer ?? currentCustomer;
                            log.PageUrl = pageUrl;
                            log.ReferrerUrl = referrerUrl;
                            log.UpdatedOnUtc = DateTime.UtcNow;

                            _logRepository.Update(log);
                        }
                    }
                    catch (Exception ex)
                    {
                        ex.Dump();
                    }
                }

                try
                {
                    // FIRE!
                    _logRepository.Context.SaveChanges();
                }
                catch { }
            }

            _entries.Clear();
        }
        public ActionResult EntityPicker(EntityPickerModel model, FormCollection form)
        {
            model.PageSize = 48; // _commonSettings.EntityPickerPageSize;
            model.PublishedString = T("Common.Published");
            model.UnpublishedString = T("Common.Unpublished");

            try
            {
                var disableIf = model.DisableIf.SplitSafe(",").Select(x => x.ToLower().Trim()).ToList();
                var disableIds = model.DisableIds.SplitSafe(",").Select(x => x.ToInt()).ToList();

                using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, proxyCreation: true, validateOnSave: false, forceNoTracking: true))
                {
                    if (model.Entity.IsCaseInsensitiveEqual("product"))
                    {
                        #region Product

                        model.SearchTerm = model.ProductName.TrimSafe();

                        var hasPermission = _services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog);
                        var storeLocation = _services.WebHelper.GetStoreLocation(false);
                        var disableIfNotSimpleProduct = disableIf.Contains("notsimpleproduct");
                        var labelTextGrouped = T("Admin.Catalog.Products.ProductType.GroupedProduct.Label").Text;
                        var labelTextBundled = T("Admin.Catalog.Products.ProductType.BundledProduct.Label").Text;
                        var sku = T("Products.Sku").Text;

                        var searchContext = new ProductSearchContext
                        {
                            CategoryIds = (model.CategoryId == 0 ? null : new List<int> { model.CategoryId }),
                            ManufacturerId = model.ManufacturerId,
                            StoreId = model.StoreId,
                            Keywords = model.SearchTerm,
                            ProductType = model.ProductTypeId > 0 ? (ProductType?)model.ProductTypeId : null,
                            SearchSku = !_catalogSettings.SuppressSkuSearch,
                            ShowHidden = hasPermission
                        };

                        var query = _productService.Value.PrepareProductSearchQuery(searchContext, x => new { x.Id, x.Sku, x.Name, x.Published, x.ProductTypeId });

                        query = from x in query
                                group x by x.Id into grp
                                orderby grp.Key
                                select grp.FirstOrDefault();

                        var products = query
                            .OrderBy(x => x.Name)
                            .Skip(model.PageIndex * model.PageSize)
                            .Take(model.PageSize)
                            .ToList();

                        var productIds = products.Select(x => x.Id).ToArray();
                        var pictures = _productService.Value.GetProductPicturesByProductIds(productIds, true);

                        model.SearchResult = products
                            .Select(x =>
                            {
                                var item = new EntityPickerModel.SearchResultModel
                                {
                                    Id = x.Id,
                                    ReturnValue = (model.ReturnField.IsCaseInsensitiveEqual("sku") ? x.Sku : x.Id.ToString()),
                                    Title = x.Name,
                                    Summary = x.Sku,
                                    SummaryTitle = "{0}: {1}".FormatInvariant(sku, x.Sku.NaIfEmpty()),
                                    Published = (hasPermission ? x.Published : (bool?)null)
                                };

                                if (disableIfNotSimpleProduct)
                                {
                                    item.Disable = (x.ProductTypeId != (int)ProductType.SimpleProduct);
                                }

                                if (!item.Disable && disableIds.Contains(x.Id))
                                {
                                    item.Disable = true;
                                }

                                if (x.ProductTypeId == (int)ProductType.GroupedProduct)
                                {
                                    item.LabelText = labelTextGrouped;
                                    item.LabelClassName = "label-success";
                                }
                                else if (x.ProductTypeId == (int)ProductType.BundledProduct)
                                {
                                    item.LabelText = labelTextBundled;
                                    item.LabelClassName = "label-info";
                                }

                                var productPicture = pictures.FirstOrDefault(y => y.Key == x.Id);
                                if (productPicture.Value != null)
                                {
                                    var picture = productPicture.Value.FirstOrDefault();
                                    if (picture != null)
                                    {
                                        item.ImageUrl = _pictureService.Value.GetPictureUrl(picture.Picture, _mediaSettings.Value.ProductThumbPictureSizeOnProductDetailsPage,
                                            !_catalogSettings.HideProductDefaultPictures, storeLocation);
                                    }
                                }

                                return item;
                            })
                            .ToList();

                        #endregion
                    }
                }
            }
            catch (Exception exception)
            {
                NotifyError(exception.ToAllMessages());
            }

            return PartialView("EntityPickerList", model);
        }
        public ActionResult PdfPackagingSlips(bool all, string selectedIds = null)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageOrders))
                return AccessDeniedView();

            if (!all && selectedIds.IsEmpty())
            {
                NotifyInfo(_localizationService.GetResource("Admin.Common.ExportNoData"));
                return RedirectToReferrer();
            }

            IList<Shipment> shipments;

            using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, forceNoTracking: true))
            {
                if (all)
                {
                    shipments = _shipmentService.GetAllShipments(null, null, null, 0, int.MaxValue);
                }
                else
                {
                    var ids = selectedIds.ToIntArray();
                    shipments = _shipmentService.GetShipmentsByIds(ids);
                }
            }

            if (shipments.Count == 0)
            {
                NotifyInfo(_localizationService.GetResource("Admin.Common.ExportNoData"));
                return RedirectToReferrer();
            }

            if (shipments.Count > 500)
            {
                NotifyWarning(_localizationService.GetResource("Admin.Common.ExportToPdf.TooManyItems"));
                return RedirectToReferrer();
            }

            string pdfFileName = "PackagingSlips.pdf";
            if (shipments.Count == 1)
            {
                pdfFileName = "PackagingSlip-{0}.pdf".FormatInvariant(shipments[0].Id);
            }

            var model = shipments.Select(x => PrepareShipmentModel(x, true, true)).ToList();

            // TODO: (mc) this is bad for multi-document processing, where orders can originate from different stores.
            var storeId = model[0].StoreId;
            var routeValues = new RouteValueDictionary(new { storeId = storeId, area = "" });
            var pdfSettings = _services.Settings.LoadSetting<PdfSettings>(storeId);

            var settings = new PdfConvertSettings
            {
                Size = pdfSettings.LetterPageSizeEnabled ? PdfPageSize.Letter : PdfPageSize.A4,
                Margins = new PdfPageMargins { Top = 35, Bottom = 35 },
                Page = new PdfViewContent("ShipmentDetails.Print", model, this.ControllerContext),
                Header = new PdfRouteContent("PdfReceiptHeader", "Common", routeValues, this.ControllerContext),
                Footer = new PdfRouteContent("PdfReceiptFooter", "Common", routeValues, this.ControllerContext)
            };

            return new PdfResult(_pdfConverter, settings) { FileName = pdfFileName };
        }
        public ImportResult ImportSubscribers(Stream stream)
        {
            Guard.ArgumentNotNull(() => stream);

            var result = new ImportResult();
            var toAdd = new List<NewsLetterSubscription>();
            var toUpdate = new List<NewsLetterSubscription>();

            using (var scope = new DbContextScope(ctx: _context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                using (var reader = new StreamReader(stream))
                {
                    while (!reader.EndOfStream)
                    {
                        string line = reader.ReadLine();
                        if (line.IsEmpty())
                        {
                            continue;
                        }
                        string[] tmp = line.Split(',');

                        var email = "";
                        bool isActive = true;
                        int storeId = 0;

                        // parse
                        if (tmp.Length == 1)
                        {
                            // "email" only
                            email = tmp[0].Trim();
                        }
                        else if (tmp.Length == 2)
                        {
                            // "email" and "active" fields specified
                            email = tmp[0].Trim();
                            isActive = Boolean.Parse(tmp[1].Trim());
                        }
                        else if (tmp.Length == 3)
                        {
                            email = tmp[0].Trim();
                            isActive = Boolean.Parse(tmp[1].Trim());
                            storeId = int.Parse(tmp[2].Trim());
                        }
                        else
                        {
                            throw new SmartException("Wrong file format (expected comma separated entries 'Email' and optionally 'IsActive')");
                        }

                        result.TotalRecords++;

                        if (email.Length > 255)
                        {
                            result.AddWarning("The emal address '{0}' exceeds the maximun allowed length of 255.".FormatInvariant(email));
                            continue;
                        }

                        if (!email.IsEmail())
                        {
                            result.AddWarning("'{0}' is not a valid email address.".FormatInvariant(email));
                            continue;
                        }

                        if (storeId == 0)
                        {
                            storeId = _storeService.GetAllStores().First().Id;
                        }

                        // import
                        var subscription = (from nls in _subscriptionRepository.Table
                                            where nls.Email == email && nls.StoreId == storeId
                                            orderby nls.Id
                                            select nls).FirstOrDefault();

                        if (subscription != null)
                        {
                            subscription.Active = isActive;

                            toUpdate.Add(subscription);
                            result.ModifiedRecords++;
                        }
                        else
                        {
                            subscription = new NewsLetterSubscription
                            {
                                Active = isActive,
                                CreatedOnUtc = DateTime.UtcNow,
                                Email = email,
                                NewsLetterSubscriptionGuid = Guid.NewGuid(),
                                StoreId = storeId
                            };

                            toAdd.Add(subscription);
                            result.NewRecords++;
                        }
                    }
                }

                // insert new subscribers
                _subscriptionRepository.AutoCommitEnabled = true;
                _subscriptionRepository.InsertRange(toAdd, 500);
                toAdd.Clear();

                // update modified subscribers
                _subscriptionRepository.AutoCommitEnabled = null;
                toUpdate.Each(x =>
                {
                    _subscriptionRepository.Update(x);
                });
                _subscriptionRepository.Context.SaveChanges();
                toUpdate.Clear();
            }

            return result;
        }
        /// <summary>
        /// Create a copy of product with all depended data
        /// </summary>
        /// <param name="product">The product</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 entity</returns>
        public virtual Product CopyProduct(Product product, string newName, bool isPublished, bool copyImages, bool copyAssociatedProducts = true)
        {
            if (product == null)
                throw new ArgumentNullException("product");

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

            Product productCopy = null;
            var utcNow = DateTime.UtcNow;

            // product download & sample download
            int downloadId = 0;
            int? sampleDownloadId = null;

            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.GetValueOrDefault());
                    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
            productCopy = new Product
            {
                ProductTypeId = product.ProductTypeId,
                ParentGroupedProductId = product.ParentGroupedProductId,
                VisibleIndividually = product.VisibleIndividually,
                Name = newName,
                ShortDescription = product.ShortDescription,
                FullDescription = product.FullDescription,
                ProductTemplateId = product.ProductTemplateId,
                AdminComment = product.AdminComment,
                ShowOnHomePage = product.ShowOnHomePage,
                HomePageDisplayOrder = product.HomePageDisplayOrder,
                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,
                IsShipEnabled = product.IsShipEnabled,
                IsFreeShipping = product.IsFreeShipping,
                AdditionalShippingCharge = product.AdditionalShippingCharge,
                IsEsd = product.IsEsd,
                IsTaxExempt = product.IsTaxExempt,
                TaxCategoryId = product.TaxCategoryId,
                ManageInventoryMethod = product.ManageInventoryMethod,
                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,
                DisableBuyButton = product.DisableBuyButton,
                DisableWishlistButton = product.DisableWishlistButton,
                AvailableForPreOrder = product.AvailableForPreOrder,
                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,
                LowestAttributeCombinationPrice = product.LowestAttributeCombinationPrice,
                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 = utcNow,
                UpdatedOnUtc = utcNow,
                DeliveryTimeId = product.DeliveryTimeId,
                QuantityUnitId = product.QuantityUnitId,
                BasePriceEnabled = product.BasePriceEnabled,
                BasePriceMeasureUnit = product.BasePriceMeasureUnit,
                BasePriceAmount = product.BasePriceAmount,
                BasePriceBaseAmount = product.BasePriceBaseAmount,
                BundleTitleText = product.BundleTitleText,
                BundlePerItemShipping = product.BundlePerItemShipping,
                BundlePerItemPricing = product.BundlePerItemPricing,
                BundlePerItemShoppingCart = product.BundlePerItemShoppingCart
            };

            _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);

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

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

            }

            // 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,
                        false,
                        false);

                    _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 <-> attributes mappings
            var associatedAttributes = new Dictionary<int, int>();
            var associatedAttributeValues = new Dictionary<int, int>();

            foreach (var productVariantAttribute in _productAttributeService.GetProductVariantAttributesByProductId(product.Id))
            {
                var productVariantAttributeCopy = new ProductVariantAttribute
                {
                    ProductId = productCopy.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,
                        ColorSquaresRgb = productVariantAttributeValue.ColorSquaresRgb,
                        PriceAdjustment = productVariantAttributeValue.PriceAdjustment,
                        WeightAdjustment = productVariantAttributeValue.WeightAdjustment,
                        IsPreSelected = productVariantAttributeValue.IsPreSelected,
                        DisplayOrder = productVariantAttributeValue.DisplayOrder,
                        ValueTypeId = productVariantAttributeValue.ValueTypeId,
                        LinkedProductId = productVariantAttributeValue.LinkedProductId,
                        Quantity = productVariantAttributeValue.Quantity,
                    };

                    _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);
                    }
                }
            }

            // attribute combinations
            using (var scope = new DbContextScope(lazyLoading: false, forceNoTracking: false))
            {
                scope.LoadCollection(product, (Product p) => p.ProductVariantAttributeCombinations);
            }

            foreach (var combination in product.ProductVariantAttributeCombinations)
            {
                //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
                {
                    ProductId = productCopy.Id,
                    AttributesXml = newAttributesXml,
                    StockQuantity = combination.StockQuantity,
                    AllowOutOfStockOrders = combination.AllowOutOfStockOrders,

                    // SmartStore extension
                    Sku = combination.Sku,
                    Gtin = combination.Gtin,
                    ManufacturerPartNumber = combination.ManufacturerPartNumber,
                    Price = combination.Price,
                    AssignedPictureIds = copyImages ? combination.AssignedPictureIds : null,
                    Length = combination.Length,
                    Width = combination.Width,
                    Height = combination.Height,
                    BasePriceAmount = combination.BasePriceAmount,
                    BasePriceBaseAmount = combination.BasePriceBaseAmount,
                    DeliveryTimeId = combination.DeliveryTimeId,
                    QuantityUnitId = combination.QuantityUnitId,
                    IsActive = combination.IsActive
                    //IsDefaultCombination = combination.IsDefaultCombination
                };
                _productAttributeService.InsertProductVariantAttributeCombination(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.UpdateLowestAttributeCombinationPriceProperty(productCopy);
            _productService.UpdateHasDiscountsApplied(productCopy);

            // associated products
            if (copyAssociatedProducts && product.ProductType != ProductType.BundledProduct)
            {
                var searchContext = new ProductSearchContext
                {
                    OrderBy = ProductSortingEnum.Position,
                    ParentGroupedProductId = product.Id,
                    PageSize = int.MaxValue,
                    ShowHidden = true
                };

                string copyOf = _localizationService.GetResource("Admin.Common.CopyOf");
                var associatedProducts = _productService.SearchProducts(searchContext);

                foreach (var associatedProduct in associatedProducts)
                {
                    var associatedProductCopy = CopyProduct(associatedProduct, string.Format("{0} {1}", copyOf, associatedProduct.Name), isPublished, copyImages, false);
                    associatedProductCopy.ParentGroupedProductId = productCopy.Id;

                    _productService.UpdateProduct(productCopy);
                }
            }

            // bundled products
            var bundledItems = _productService.GetBundleItems(product.Id, true);

            foreach (var bundleItem in bundledItems)
            {
                var newBundleItem = bundleItem.Item.Clone();
                newBundleItem.BundleProductId = productCopy.Id;
                newBundleItem.CreatedOnUtc = utcNow;
                newBundleItem.UpdatedOnUtc = utcNow;

                _productService.InsertBundleItem(newBundleItem);

                foreach (var itemFilter in bundleItem.Item.AttributeFilters)
                {
                    var newItemFilter = itemFilter.Clone();
                    newItemFilter.BundleItemId = newBundleItem.Id;

                    _productAttributeService.InsertProductBundleItemAttributeFilter(newItemFilter);
                }
            }

            return productCopy;
        }
        public virtual int SaveThemeVariables(string themeName, int storeId, IDictionary<string, object> variables)
        {
            Guard.ArgumentNotEmpty(themeName, "themeName");
            Guard.Against<ArgumentException>(!_themeRegistry.ThemeManifestExists(themeName), "The theme '{0}' does not exist in the registry.".FormatInvariant(themeName));
            Guard.ArgumentNotNull(variables, "variables");

            if (!variables.Any())
                return 0;

            var count = 0;
            var infos = _themeRegistry.GetThemeManifest(themeName).Variables;

            using (var scope = new DbContextScope(ctx: _rsVariables.Context, autoCommit: false))
            {
                var unsavedVars = new List<string>();
                var savedThemeVars = _rsVariables.Table.Where(v => v.StoreId == storeId && v.Theme.Equals(themeName, StringComparison.OrdinalIgnoreCase)).ToList();
                bool touched = false;

                foreach (var v in variables)
                {
                    ThemeVariableInfo info;
                    if (!infos.TryGetValue(v.Key, out info))
                    {
                        // var not specified in metadata so don't save
                        // TODO: (MC) delete from db also if it exists
                        continue;
                    }

                    var value = v.Value == null ? string.Empty : v.Value.ToString();

                    var savedThemeVar = savedThemeVars.FirstOrDefault(x => x.Name == v.Key);
                    if (savedThemeVar != null)
                    {
                        if (value.IsEmpty() || String.Equals(info.DefaultValue, value, StringComparison.CurrentCultureIgnoreCase))
                        {
                            // it's either null or the default value, so delete
                            _rsVariables.Delete(savedThemeVar);
                            _eventPublisher.EntityDeleted(savedThemeVar);
                            touched = true;
                            count++;
                        }
                        else
                        {
                            // update entity
                            if (!savedThemeVar.Value.Equals(value, StringComparison.OrdinalIgnoreCase))
                            {
                                savedThemeVar.Value = value;
                                _eventPublisher.EntityUpdated(savedThemeVar);
                                touched = true;
                                count++;
                            }
                        }
                    }
                    else
                    {
                        if (value.HasValue() && !String.Equals(info.DefaultValue, value, StringComparison.CurrentCultureIgnoreCase))
                        {
                            // insert entity (only when not default value)
                            unsavedVars.Add(v.Key);
                            savedThemeVar = new ThemeVariable
                            {
                                Theme = themeName,
                                Name = v.Key,
                                Value = value,
                                StoreId = storeId
                            };
                            _rsVariables.Insert(savedThemeVar);
                            _eventPublisher.EntityInserted(savedThemeVar);
                            touched = true;
                            count++;
                        }
                    }
                }

                if (touched)
                {
                    _rsVariables.Context.SaveChanges();
                }
            }

            return count;
        }
        public virtual void InheritStoresIntoChildren(int categoryId, 
            bool touchProductsWithMultipleCategories = false,
            bool touchExistingAcls = false,
            bool categoriesOnly = false)
        {

            var category = GetCategoryById(categoryId);
            var subcategories = GetAllCategoriesByParentCategoryId(categoryId, true);
            var context = new ProductSearchContext { PageSize = int.MaxValue , ShowHidden = true };
            context.CategoryIds.AddRange(subcategories.Select(x => x.Id));
            context.CategoryIds.Add(categoryId);
            var products = _productService.SearchProducts(context);

            var allStores = _storeService.GetAllStores();
            var categoryStoreMappings = _storeMappingService.GetStoresIdsWithAccess(category);

            using (var scope = new DbContextScope(ctx: _storeMappingRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false))
            {
                _storeMappingRepository.AutoCommitEnabled = false;

                foreach (var subcategory in subcategories)
                {
                    if (subcategory.LimitedToStores != category.LimitedToStores)
                    {
                        subcategory.LimitedToStores = category.LimitedToStores;
                        _categoryRepository.Update(subcategory);
                    }

                    var existingStoreMappingsRecords = _storeMappingService.GetStoreMappings(subcategory).ToDictionary(x => x.StoreId);

                    foreach (var store in allStores)
                    {
                        if (categoryStoreMappings.Contains(store.Id))
                        {
                            if (!existingStoreMappingsRecords.ContainsKey(store.Id))
                            {
                                _storeMappingRepository.Insert(new StoreMapping { StoreId = store.Id, EntityId = subcategory.Id, EntityName = "Category" });
                            }
                        }
                        else
                        {
                            StoreMapping storeMappingToDelete;
                            if (existingStoreMappingsRecords.TryGetValue(store.Id, out storeMappingToDelete))
                            {
                                _storeMappingRepository.Delete(storeMappingToDelete);
                            }
                        }
                    }
                }

                _storeMappingRepository.Context.SaveChanges();

                foreach (var product in products)
                {
                    if (product.LimitedToStores != category.LimitedToStores)
                    {
                        product.LimitedToStores = category.LimitedToStores;
                        _productRepository.Update(product);
                    }

                    var existingStoreMappingsRecords = _storeMappingService.GetStoreMappings(product).ToDictionary(x => x.StoreId);

                    foreach (var store in allStores)
                    {
                        if (categoryStoreMappings.Contains(store.Id))
                        {
                            if (!existingStoreMappingsRecords.ContainsKey(store.Id))
                            {
                                _storeMappingRepository.Insert(new StoreMapping { StoreId = store.Id, EntityId = product.Id, EntityName = "Product" });
                            }
                        }
                        else
                        {
                            StoreMapping storeMappingToDelete;
                            if (existingStoreMappingsRecords.TryGetValue(store.Id, out storeMappingToDelete))
                            {
                                _storeMappingRepository.Delete(storeMappingToDelete);
                            }
                        }
                    }
                }

                _storeMappingRepository.Context.SaveChanges();
            }
        }
Exemple #15
0
		/// <summary>
		/// Writes a single product
		/// </summary>
		/// <param name="writer">The XML writer</param>
		/// <param name="product">The product</param>
		/// <param name="context">Context objects</param>
		public virtual void WriteProductToXml(XmlWriter writer, Product product, XmlExportContext context)
		{
			var culture = CultureInfo.InvariantCulture;
			var productTemplate = context.ProductTemplates.FirstOrDefault(x => x.Id == product.ProductTemplateId);

			writer.Write("Id", product.Id.ToString());
			writer.Write("Name", product.Name);
			writer.Write("SeName", product.GetSeName(0, true, false));

			writer.Write("ShortDescription", product.ShortDescription, null, true);
			writer.Write("FullDescription", product.FullDescription, null, true);

			writer.Write("AdminComment", product.AdminComment);
			writer.Write("ProductTemplateId", product.ProductTemplateId.ToString());
			writer.Write("ProductTemplateViewPath", productTemplate == null ? "" : productTemplate.ViewPath);
			writer.Write("ShowOnHomePage", product.ShowOnHomePage.ToString());
			writer.Write("HomePageDisplayOrder", product.HomePageDisplayOrder.ToString());
			writer.Write("MetaKeywords", product.MetaKeywords);
			writer.Write("MetaDescription", product.MetaDescription);
			writer.Write("MetaTitle", product.MetaTitle);
			writer.Write("AllowCustomerReviews", product.AllowCustomerReviews.ToString());
			writer.Write("ApprovedRatingSum", product.ApprovedRatingSum.ToString());
			writer.Write("NotApprovedRatingSum", product.NotApprovedRatingSum.ToString());
			writer.Write("ApprovedTotalReviews", product.ApprovedTotalReviews.ToString());
			writer.Write("NotApprovedTotalReviews", product.NotApprovedTotalReviews.ToString());
			writer.Write("Published", product.Published.ToString());
			writer.Write("CreatedOnUtc", product.CreatedOnUtc.ToString(culture));
			writer.Write("UpdatedOnUtc", product.UpdatedOnUtc.ToString(culture));
			writer.Write("SubjectToAcl", product.SubjectToAcl.ToString());
			writer.Write("LimitedToStores", product.LimitedToStores.ToString());
			writer.Write("ProductTypeId", product.ProductTypeId.ToString());
			writer.Write("ParentGroupedProductId", product.ParentGroupedProductId.ToString());
			writer.Write("Sku", product.Sku);
			writer.Write("ManufacturerPartNumber", product.ManufacturerPartNumber);
			writer.Write("Gtin", product.Gtin);
			writer.Write("IsGiftCard", product.IsGiftCard.ToString());
			writer.Write("GiftCardTypeId", product.GiftCardTypeId.ToString());
			writer.Write("RequireOtherProducts", product.RequireOtherProducts.ToString());
			writer.Write("RequiredProductIds", product.RequiredProductIds);
			writer.Write("AutomaticallyAddRequiredProducts", product.AutomaticallyAddRequiredProducts.ToString());
			writer.Write("IsDownload", product.IsDownload.ToString());
			writer.Write("DownloadId", product.DownloadId.ToString());
			writer.Write("UnlimitedDownloads", product.UnlimitedDownloads.ToString());
			writer.Write("MaxNumberOfDownloads", product.MaxNumberOfDownloads.ToString());
			writer.Write("DownloadExpirationDays", product.DownloadExpirationDays.HasValue ? product.DownloadExpirationDays.ToString() : "");
			writer.Write("DownloadActivationType", product.DownloadActivationType.ToString());
			writer.Write("HasSampleDownload", product.HasSampleDownload.ToString());
			writer.Write("SampleDownloadId", product.SampleDownloadId.ToString());
			writer.Write("HasUserAgreement", product.HasUserAgreement.ToString());
			writer.Write("UserAgreementText", product.UserAgreementText);
			writer.Write("IsRecurring", product.IsRecurring.ToString());
			writer.Write("RecurringCycleLength", product.RecurringCycleLength.ToString());
			writer.Write("RecurringCyclePeriodId", product.RecurringCyclePeriodId.ToString());
			writer.Write("RecurringTotalCycles", product.RecurringTotalCycles.ToString());
			writer.Write("IsShipEnabled", product.IsShipEnabled.ToString());
			writer.Write("IsFreeShipping", product.IsFreeShipping.ToString());
			writer.Write("AdditionalShippingCharge", product.AdditionalShippingCharge.ToString(culture));
			writer.Write("IsTaxExempt", product.IsTaxExempt.ToString());
			writer.Write("TaxCategoryId", product.TaxCategoryId.ToString());
			writer.Write("ManageInventoryMethodId", product.ManageInventoryMethodId.ToString());
			writer.Write("StockQuantity", product.StockQuantity.ToString());
			writer.Write("DisplayStockAvailability", product.DisplayStockAvailability.ToString());
			writer.Write("DisplayStockQuantity", product.DisplayStockQuantity.ToString());
			writer.Write("MinStockQuantity", product.MinStockQuantity.ToString());
			writer.Write("LowStockActivityId", product.LowStockActivityId.ToString());
			writer.Write("NotifyAdminForQuantityBelow", product.NotifyAdminForQuantityBelow.ToString());
			writer.Write("BackorderModeId", product.BackorderModeId.ToString());
			writer.Write("AllowBackInStockSubscriptions", product.AllowBackInStockSubscriptions.ToString());
			writer.Write("OrderMinimumQuantity", product.OrderMinimumQuantity.ToString());
			writer.Write("OrderMaximumQuantity", product.OrderMaximumQuantity.ToString());
			writer.Write("AllowedQuantities", product.AllowedQuantities);
			writer.Write("DisableBuyButton", product.DisableBuyButton.ToString());
			writer.Write("DisableWishlistButton", product.DisableWishlistButton.ToString());
			writer.Write("AvailableForPreOrder", product.AvailableForPreOrder.ToString());
			writer.Write("CallForPrice", product.CallForPrice.ToString());
			writer.Write("Price", product.Price.ToString(culture));
			writer.Write("OldPrice", product.OldPrice.ToString(culture));
			writer.Write("ProductCost", product.ProductCost.ToString(culture));
			writer.Write("SpecialPrice", product.SpecialPrice.HasValue ? product.SpecialPrice.Value.ToString(culture) : "");
			writer.Write("SpecialPriceStartDateTimeUtc", product.SpecialPriceStartDateTimeUtc.HasValue ? product.SpecialPriceStartDateTimeUtc.Value.ToString(culture) : "");
			writer.Write("SpecialPriceEndDateTimeUtc", product.SpecialPriceEndDateTimeUtc.HasValue ? product.SpecialPriceEndDateTimeUtc.Value.ToString(culture) : "");
			writer.Write("CustomerEntersPrice", product.CustomerEntersPrice.ToString());
			writer.Write("MinimumCustomerEnteredPrice", product.MinimumCustomerEnteredPrice.ToString(culture));
			writer.Write("MaximumCustomerEnteredPrice", product.MaximumCustomerEnteredPrice.ToString(culture));
			writer.Write("HasTierPrices", product.HasTierPrices.ToString());
			writer.Write("HasDiscountsApplied", product.HasDiscountsApplied.ToString());
			writer.Write("Weight", product.Weight.ToString(culture));
			writer.Write("Length", product.Length.ToString(culture));
			writer.Write("Width", product.Width.ToString(culture));
			writer.Write("Height", product.Height.ToString(culture));
			writer.Write("AvailableStartDateTimeUtc", product.AvailableStartDateTimeUtc.HasValue ? product.AvailableStartDateTimeUtc.Value.ToString(culture) : "");
			writer.Write("AvailableEndDateTimeUtc", product.AvailableEndDateTimeUtc.HasValue ? product.AvailableEndDateTimeUtc.Value.ToString(culture) : "");
			writer.Write("BasePriceEnabled", product.BasePriceEnabled.ToString());
			writer.Write("BasePriceMeasureUnit", product.BasePriceMeasureUnit);
			writer.Write("BasePriceAmount", product.BasePriceAmount.HasValue ? product.BasePriceAmount.Value.ToString(culture) : "");
			writer.Write("BasePriceBaseAmount", product.BasePriceBaseAmount.HasValue ? product.BasePriceBaseAmount.Value.ToString() : "");
			writer.Write("VisibleIndividually", product.VisibleIndividually.ToString());
			writer.Write("DisplayOrder", product.DisplayOrder.ToString());
			writer.Write("BundleTitleText", product.BundleTitleText);
			writer.Write("BundlePerItemPricing", product.BundlePerItemPricing.ToString());
			writer.Write("BundlePerItemShipping", product.BundlePerItemShipping.ToString());
			writer.Write("BundlePerItemShoppingCart", product.BundlePerItemShoppingCart.ToString());
			writer.Write("LowestAttributeCombinationPrice", product.LowestAttributeCombinationPrice.HasValue ? product.LowestAttributeCombinationPrice.Value.ToString(culture) : "");
			writer.Write("IsEsd", product.IsEsd.ToString());

			WriteLocalized(writer, context, lang =>
			{
				writer.Write("Name", product.GetLocalized(x => x.Name, lang.Id, false, false), lang);
				writer.Write("SeName", product.GetSeName(lang.Id, false, false), lang);
				writer.Write("ShortDescription", product.GetLocalized(x => x.ShortDescription, lang.Id, false, false), lang, true);
				writer.Write("FullDescription", product.GetLocalized(x => x.FullDescription, lang.Id, false, false), lang, true);
				writer.Write("MetaKeywords", product.GetLocalized(x => x.MetaKeywords, lang.Id, false, false), lang);
				writer.Write("MetaDescription", product.GetLocalized(x => x.MetaDescription, lang.Id, false, false), lang);
				writer.Write("MetaTitle", product.GetLocalized(x => x.MetaTitle, lang.Id, false, false), lang);
				writer.Write("BundleTitleText", product.GetLocalized(x => x.BundleTitleText, lang.Id, false, false), lang);
			});

			if (product.DeliveryTime != null)
			{
				writer.WriteStartElement("DeliveryTime");
				writer.Write("Id", product.DeliveryTime.Id.ToString());
				writer.Write("Name", product.DeliveryTime.Name);
				writer.Write("DisplayLocale", product.DeliveryTime.DisplayLocale);
				writer.Write("ColorHexValue", product.DeliveryTime.ColorHexValue);
				writer.Write("DisplayOrder", product.DeliveryTime.DisplayOrder.ToString());
				WriteLocalized(writer, context, lang =>
				{
					writer.Write("Name", product.DeliveryTime.GetLocalized(x => x.Name, lang.Id, false, false), lang);
				});
				writer.WriteEndElement();
			}

			WriteQuantityUnit(writer, context, product.QuantityUnit);

			writer.WriteStartElement("ProductTags");
			foreach (var tag in product.ProductTags)
			{
				writer.WriteStartElement("ProductTag");
				writer.Write("Id", tag.Id.ToString());
				writer.Write("Name", tag.Name);

				WriteLocalized(writer, context, lang =>
				{
					writer.Write("Name", tag.GetLocalized(x => x.Name, lang.Id, false, false), lang);
				});

				writer.WriteEndElement();
			}
			writer.WriteEndElement();

			writer.WriteStartElement("ProductDiscounts");
			foreach (var discount in product.AppliedDiscounts)
			{
				writer.WriteStartElement("ProductDiscount");
				writer.Write("DiscountId", discount.Id.ToString());
				writer.WriteEndElement();
			}
			writer.WriteEndElement();

			writer.WriteStartElement("TierPrices");
			foreach (var tierPrice in product.TierPrices)
			{
				writer.WriteStartElement("TierPrice");
				writer.Write("Id", tierPrice.Id.ToString());
				writer.Write("StoreId", tierPrice.StoreId.ToString());
				writer.Write("CustomerRoleId", tierPrice.CustomerRoleId.HasValue ? tierPrice.CustomerRoleId.ToString() : "0");
				writer.Write("Quantity", tierPrice.Quantity.ToString());
				writer.Write("Price", tierPrice.Price.ToString(culture));
				writer.WriteEndElement();
			}
			writer.WriteEndElement();

			writer.WriteStartElement("ProductAttributes");
			foreach (var pva in product.ProductVariantAttributes.OrderBy(x => x.DisplayOrder))
			{
				writer.WriteStartElement("ProductAttribute");

				writer.Write("Id", pva.Id.ToString());
				writer.Write("TextPrompt", pva.TextPrompt);
				writer.Write("IsRequired", pva.IsRequired.ToString());
				writer.Write("AttributeControlTypeId", pva.AttributeControlTypeId.ToString());
				writer.Write("DisplayOrder", pva.DisplayOrder.ToString());

				writer.WriteStartElement("Attribute");
				writer.Write("Id", pva.ProductAttribute.Id.ToString());
				writer.Write("Alias", pva.ProductAttribute.Alias);
				writer.Write("Name", pva.ProductAttribute.Name);
				writer.Write("Description", pva.ProductAttribute.Description);
				WriteLocalized(writer, context, lang =>
				{
					writer.Write("Name", pva.ProductAttribute.GetLocalized(x => x.Name, lang.Id, false, false), lang);
					writer.Write("Description", pva.ProductAttribute.GetLocalized(x => x.Description, lang.Id, false, false), lang);
				});
				writer.WriteEndElement();	// Attribute

				writer.WriteStartElement("AttributeValues");
				foreach (var value in pva.ProductVariantAttributeValues.OrderBy(x => x.DisplayOrder))
				{
					writer.WriteStartElement("AttributeValue");
					writer.Write("Id", value.Id.ToString());
					writer.Write("Alias", value.Alias);
					writer.Write("Name", value.Name);
					writer.Write("ColorSquaresRgb", value.ColorSquaresRgb);
					writer.Write("PriceAdjustment", value.PriceAdjustment.ToString(culture));
					writer.Write("WeightAdjustment", value.WeightAdjustment.ToString(culture));
					writer.Write("IsPreSelected", value.IsPreSelected.ToString());
					writer.Write("DisplayOrder", value.DisplayOrder.ToString());
					writer.Write("ValueTypeId", value.ValueTypeId.ToString());
					writer.Write("LinkedProductId", value.LinkedProductId.ToString());
					writer.Write("Quantity", value.Quantity.ToString());
					WriteLocalized(writer, context, lang =>
					{
						writer.Write("Name", value.GetLocalized(x => x.Name, lang.Id, false, false), lang);
					});
					writer.WriteEndElement();	// AttributeValue
				}
				writer.WriteEndElement();	// AttributeValues

				writer.WriteEndElement();	// ProductAttribute
			}
			writer.WriteEndElement();   // ProductAttributes

			using (var scope = new DbContextScope(proxyCreation: false, forceNoTracking: true))
			{
				var allCombinations = product.ProductVariantAttributeCombinations;

				writer.WriteStartElement("ProductAttributeCombinations");
				foreach (var combination in allCombinations)
				{
					writer.WriteStartElement("ProductAttributeCombination");

					writer.Write("Id", combination.Id.ToString());
					writer.Write("StockQuantity", combination.StockQuantity.ToString());
					writer.Write("AllowOutOfStockOrders", combination.AllowOutOfStockOrders.ToString());
					writer.Write("AttributesXml", combination.AttributesXml, null, true);
					writer.Write("Sku", combination.Sku);
					writer.Write("Gtin", combination.Gtin);
					writer.Write("ManufacturerPartNumber", combination.ManufacturerPartNumber);
					writer.Write("Price", combination.Price.HasValue ? combination.Price.Value.ToString(culture) : "");
					writer.Write("Length", combination.Length.HasValue ? combination.Length.Value.ToString(culture) : "");
					writer.Write("Width", combination.Width.HasValue ? combination.Width.Value.ToString(culture) : "");
					writer.Write("Height", combination.Height.HasValue ? combination.Height.Value.ToString(culture) : "");
					writer.Write("BasePriceAmount", combination.BasePriceAmount.HasValue ? combination.BasePriceAmount.Value.ToString(culture) : "");
					writer.Write("BasePriceBaseAmount", combination.BasePriceBaseAmount.HasValue ? combination.BasePriceBaseAmount.Value.ToString() : "");
					writer.Write("DeliveryTimeId", combination.DeliveryTimeId.HasValue ? combination.DeliveryTimeId.Value.ToString() : "");
					writer.Write("IsActive", combination.IsActive.ToString());

					WriteQuantityUnit(writer, context, combination.QuantityUnit);

					writer.WriteStartElement("Pictures");
					foreach (int pictureId in combination.GetAssignedPictureIds())
					{
						WritePicture(writer, context, _pictureService.GetPictureById(pictureId), _mediaSettings.ProductThumbPictureSize, _mediaSettings.ProductDetailsPictureSize);
					}
					writer.WriteEndElement();   // Pictures

					writer.WriteEndElement();   // ProductAttributeCombination
				}
				writer.WriteEndElement(); // ProductAttributeCombinations
			}

			writer.WriteStartElement("ProductPictures");
			foreach (var productPicture in product.ProductPictures.OrderBy(x => x.DisplayOrder))
			{
				writer.WriteStartElement("ProductPicture");
				writer.Write("Id", productPicture.Id.ToString());
				writer.Write("DisplayOrder", productPicture.DisplayOrder.ToString());

				WritePicture(writer, context, productPicture.Picture, _mediaSettings.ProductThumbPictureSize, _mediaSettings.ProductDetailsPictureSize);

				writer.WriteEndElement();
			}
			writer.WriteEndElement();

			writer.WriteStartElement("ProductCategories");
			var productCategories = _categoryService.GetProductCategoriesByProductId(product.Id);
			if (productCategories != null)
			{
				foreach (var productCategory in productCategories.OrderBy(x => x.DisplayOrder))
				{
					var category = productCategory.Category;
					writer.WriteStartElement("ProductCategory");
					writer.Write("IsFeaturedProduct", productCategory.IsFeaturedProduct.ToString());
					writer.Write("DisplayOrder", productCategory.DisplayOrder.ToString());
					
					writer.WriteStartElement("Category");
					writer.Write("Id", category.Id.ToString());
					writer.Write("Name", category.Name);
					writer.Write("FullName", category.FullName);
					writer.Write("Description", category.Description);
					writer.Write("BottomDescription", category.BottomDescription);
					writer.Write("CategoryTemplateId", category.CategoryTemplateId.ToString());
					writer.Write("MetaKeywords", category.MetaKeywords);
					writer.Write("MetaDescription", category.MetaDescription);
					writer.Write("MetaTitle", category.MetaTitle);
					writer.Write("SeName", category.GetSeName(0));
					writer.Write("ParentCategoryId", category.ParentCategoryId.ToString());
					writer.Write("PageSize", category.PageSize.ToString());
					writer.Write("AllowCustomersToSelectPageSize", category.AllowCustomersToSelectPageSize.ToString());
					writer.Write("PageSizeOptions", category.PageSizeOptions);
					writer.Write("PriceRanges", category.PriceRanges);
					writer.Write("ShowOnHomePage", category.ShowOnHomePage.ToString());
					writer.Write("HasDiscountsApplied", category.HasDiscountsApplied.ToString());
					writer.Write("Published", category.Published.ToString());
					writer.Write("Deleted", category.Deleted.ToString());
					writer.Write("DisplayOrder", category.DisplayOrder.ToString());
					writer.Write("CreatedOnUtc", category.CreatedOnUtc.ToString(culture));
					writer.Write("UpdatedOnUtc", category.UpdatedOnUtc.ToString(culture));
					writer.Write("SubjectToAcl", category.SubjectToAcl.ToString());
					writer.Write("LimitedToStores", category.LimitedToStores.ToString());
					writer.Write("Alias", category.Alias);
					writer.Write("DefaultViewMode", category.DefaultViewMode);

					WritePicture(writer, context, category.Picture, _mediaSettings.CategoryThumbPictureSize, _mediaSettings.CategoryThumbPictureSize);

					WriteLocalized(writer, context, lang =>
					{
						writer.Write("Name", category.GetLocalized(x => x.Name, lang.Id, false, false), lang);
						writer.Write("FullName", category.GetLocalized(x => x.FullName, lang.Id, false, false), lang);
						writer.Write("Description", category.GetLocalized(x => x.Description, lang.Id, false, false), lang);
						writer.Write("BottomDescription", category.GetLocalized(x => x.BottomDescription, lang.Id, false, false), lang);
						writer.Write("MetaKeywords", category.GetLocalized(x => x.MetaKeywords, lang.Id, false, false), lang);
						writer.Write("MetaDescription", category.GetLocalized(x => x.MetaDescription, lang.Id, false, false), lang);
						writer.Write("MetaTitle", category.GetLocalized(x => x.MetaTitle, lang.Id, false, false), lang);
						writer.Write("SeName", category.GetSeName(lang.Id, false, false));
					});

					writer.WriteEndElement();
					
					writer.WriteEndElement();
				}
			}
			writer.WriteEndElement();

			writer.WriteStartElement("ProductManufacturers");
			var productManufacturers = _manufacturerService.GetProductManufacturersByProductId(product.Id);
			if (productManufacturers != null)
			{
				foreach (var productManufacturer in productManufacturers.OrderBy(x => x.DisplayOrder))
				{
					var manu = productManufacturer.Manufacturer;
					writer.WriteStartElement("ProductManufacturer");

					writer.Write("Id", productManufacturer.Id.ToString());
					writer.Write("IsFeaturedProduct", productManufacturer.IsFeaturedProduct.ToString());
					writer.Write("DisplayOrder", productManufacturer.DisplayOrder.ToString());

					writer.WriteStartElement("Manufacturer");
					writer.Write("Id", manu.Id.ToString());
					writer.Write("Name", manu.Name);
					writer.Write("SeName", manu.GetSeName(0, true, false));
					writer.Write("Description", manu.Description);
					writer.Write("MetaKeywords", manu.MetaKeywords);
					writer.Write("MetaDescription", manu.MetaDescription);
					writer.Write("MetaTitle", manu.MetaTitle);

					WritePicture(writer, context, manu.Picture, _mediaSettings.ManufacturerThumbPictureSize, _mediaSettings.ManufacturerThumbPictureSize);

					WriteLocalized(writer, context, lang =>
					{
						writer.Write("Name", manu.GetLocalized(x => x.Name, lang.Id, false, false), lang);
						writer.Write("SeName", manu.GetSeName(lang.Id, false, false), lang);
						writer.Write("Description", manu.GetLocalized(x => x.Description, lang.Id, false, false), lang);
						writer.Write("MetaKeywords", manu.GetLocalized(x => x.MetaKeywords, lang.Id, false, false), lang);
						writer.Write("MetaDescription", manu.GetLocalized(x => x.MetaDescription, lang.Id, false, false), lang);
						writer.Write("MetaTitle", manu.GetLocalized(x => x.MetaTitle, lang.Id, false, false), lang);
					});

					writer.WriteEndElement();

					writer.WriteEndElement();
				}
			}
			writer.WriteEndElement();

			writer.WriteStartElement("ProductSpecificationAttributes");
			foreach (var pca in product.ProductSpecificationAttributes.OrderBy(x => x.DisplayOrder))
			{
				writer.WriteStartElement("ProductSpecificationAttribute");
				writer.Write("Id", pca.Id.ToString());
				writer.Write("AllowFiltering", pca.AllowFiltering.ToString());
				writer.Write("ShowOnProductPage", pca.ShowOnProductPage.ToString());
				writer.Write("DisplayOrder", pca.DisplayOrder.ToString());

				writer.WriteStartElement("SpecificationAttributeOption");
				writer.Write("Id", pca.SpecificationAttributeOption.Id.ToString());
				writer.Write("DisplayOrder", pca.SpecificationAttributeOption.DisplayOrder.ToString());
				writer.Write("Name", pca.SpecificationAttributeOption.Name);
				WriteLocalized(writer, context, lang =>
				{
					writer.Write("Name", pca.SpecificationAttributeOption.GetLocalized(x => x.Name, lang.Id, false, false), lang);
				});

				writer.WriteStartElement("SpecificationAttribute");
				writer.Write("Id", pca.SpecificationAttributeOption.SpecificationAttribute.Id.ToString());
				writer.Write("DisplayOrder", pca.SpecificationAttributeOption.SpecificationAttribute.DisplayOrder.ToString());
				writer.Write("Name", pca.SpecificationAttributeOption.SpecificationAttribute.Name);
				WriteLocalized(writer, context, lang =>
				{
					writer.Write("Name", pca.SpecificationAttributeOption.SpecificationAttribute.GetLocalized(x => x.Name, lang.Id, false, false), lang);
				});
				writer.WriteEndElement();	// SpecificationAttribute

				writer.WriteEndElement();	// SpecificationAttributeOption

				writer.WriteEndElement();	// ProductSpecificationAttribute
			}
			writer.WriteEndElement();

			writer.WriteStartElement("ProductBundleItems");
			var bundleItems = _productService.GetBundleItems(product.Id, true);
			foreach (var bundleItem in bundleItems.Select(x => x.Item).OrderBy(x => x.DisplayOrder))
			{
				writer.WriteStartElement("ProductBundleItem");
				writer.Write("ProductId", bundleItem.ProductId.ToString());
				writer.Write("BundleProductId", bundleItem.BundleProductId.ToString());
				writer.Write("Quantity", bundleItem.Quantity.ToString());
				writer.Write("Discount", bundleItem.Discount.HasValue ? bundleItem.Discount.Value.ToString(culture) : "");
				writer.Write("DiscountPercentage", bundleItem.DiscountPercentage.ToString());
				writer.Write("Name", bundleItem.GetLocalizedName());
				writer.Write("ShortDescription", bundleItem.ShortDescription);
				writer.Write("FilterAttributes", bundleItem.FilterAttributes.ToString());
				writer.Write("HideThumbnail", bundleItem.HideThumbnail.ToString());
				writer.Write("Visible", bundleItem.Visible.ToString());
				writer.Write("Published", bundleItem.Published.ToString());
				writer.Write("DisplayOrder", bundleItem.DisplayOrder.ToString());
				writer.Write("CreatedOnUtc", bundleItem.CreatedOnUtc.ToString(culture));
				writer.Write("UpdatedOnUtc", bundleItem.UpdatedOnUtc.ToString(culture));
				writer.WriteEndElement();
			}
			writer.WriteEndElement();
		}
        public void Migrate(IEnumerable<LocaleResourceEntry> entries, bool updateTouchedResources = false)
        {
            Guard.ArgumentNotNull(() => entries);

            if (!entries.Any() || !_languages.Any())
                return;

            using (var scope = new DbContextScope(_ctx, autoDetectChanges: false))
            {
                var langMap = _languages.ToDictionarySafe(x => x.UniqueSeoCode.EmptyNull().ToLower());

                var toDelete = new List<LocaleStringResource>();
                var toUpdate = new List<LocaleStringResource>();
                var toAdd = new List<LocaleStringResource>();

                // remove all entries with invalid lang identifier
                var invalidEntries = entries.Where(x => x.Lang != null && !langMap.ContainsKey(x.Lang.ToLower()));
                if (invalidEntries.Any())
                {
                    entries = entries.Except(invalidEntries);
                }

                foreach (var lang in langMap)
                {
                    foreach (var entry in entries.Where(x => x.Lang == null || langMap[x.Lang.ToLower()].Id == lang.Value.Id))
                    {
                        bool isLocal;
                        var db = GetResource(entry.Key, lang.Value.Id, toAdd, out isLocal);

                        if (db == null && entry.Value.HasValue() && !entry.UpdateOnly)
                        {
                            // ADD action
                            toAdd.Add(new LocaleStringResource { LanguageId = lang.Value.Id, ResourceName = entry.Key, ResourceValue = entry.Value });
                        }

                        if (db == null)
                            continue;

                        if (entry.Value == null)
                        {
                            // DELETE action
                            if (isLocal)
                                toAdd.Remove(db);
                            else
                                toDelete.Add(db);
                        }
                        else
                        {
                            if (isLocal)
                            {
                                db.ResourceValue = entry.Value;
                                continue;
                            }

                            // UPDATE action
                            if (updateTouchedResources || !db.IsTouched.GetValueOrDefault())
                            {
                                db.ResourceValue = entry.Value;
                                toUpdate.Add(db);
                                if (toDelete.Contains(db))
                                    toDelete.Remove(db);
                            }
                        }
                    }
                }

                // add new resources to context
                _resources.AddRange(toAdd);

                // remove deleted resources
                _resources.RemoveRange(toDelete);

                // update modified resources
                toUpdate.Each(x => _ctx.Entry(x).State = System.Data.Entity.EntityState.Modified);

                // save now
                int affectedRows = _ctx.SaveChanges();
            }
        }
        public void Execute(ImportExecuteContext context)
        {
            var utcNow = DateTime.UtcNow;
            var currentStoreId = _services.StoreContext.CurrentStore.Id;

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

                context.Result.TotalRecords = segmenter.TotalRows;

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

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

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

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

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

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

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

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

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

                            NewsLetterSubscription subscription = null;

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

                                if (subscription != null)
                                    break;
                            }

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

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

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

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

                    _subscriptionRepository.Context.SaveChanges();
                } // while
            }
        }
		public ActionResult PrintMany(string ids = null, bool pdf = false)
		{
			if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageOrders))
				return new HttpUnauthorizedResult();

			IList<Order> orders;

			using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, forceNoTracking: true))
			{
				if (ids != null)
				{
					int[] intIds = ids.ToIntArray();
					orders = _orderService.GetOrdersByIds(intIds);
				}
				else
				{
					orders = _orderService.SearchOrders(0, 0, null, null, null, null, null, null, null, null, 0, int.MaxValue);
				}
			}

			if (orders.Count == 0)
			{
				NotifyInfo(T("Admin.Common.ExportNoData"));
				return RedirectToReferrer();
			}

			if (orders.Count > 500)
			{
				NotifyWarning(T("Admin.Common.ExportToPdf.TooManyItems"));
				return RedirectToReferrer();
			}

			var listModel = orders.Select(x => PrepareOrderDetailsModel(x)).ToList();

			return PrintCore(listModel, pdf, "orders.pdf");
		}
        private void ExportCoreOuter(DataExporterContext ctx)
        {
            if (ctx.Request.Profile == null || !ctx.Request.Profile.Enabled)
                return;

            var logPath = ctx.Request.Profile.GetExportLogPath();
            var zipPath = ctx.Request.Profile.GetExportZipPath();

            FileSystemHelper.Delete(logPath);
            FileSystemHelper.Delete(zipPath);
            FileSystemHelper.ClearDirectory(ctx.FolderContent, false);

            using (var logger = new TraceLogger(logPath))
            {
                try
                {
                    ctx.Log = logger;
                    ctx.ExecuteContext.Log = logger;
                    ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo");

                    if (!ctx.Request.Provider.IsValid())
                        throw new SmartException("Export aborted because the export provider is not valid.");

                    if (!HasPermission(ctx))
                        throw new SmartException("You do not have permission to perform the selected export.");

                    foreach (var item in ctx.Request.CustomData)
                    {
                        ctx.ExecuteContext.CustomProperties.Add(item.Key, item.Value);
                    }

                    if (ctx.Request.Profile.ProviderConfigData.HasValue())
                    {
                        var configInfo = ctx.Request.Provider.Value.ConfigurationInfo;
                        if (configInfo != null)
                        {
                            ctx.ExecuteContext.ConfigurationData = XmlHelper.Deserialize(ctx.Request.Profile.ProviderConfigData, configInfo.ModelType);
                        }
                    }

                    // lazyLoading: false, proxyCreation: false impossible. how to identify all properties of all data levels of all entities
                    // that require manual resolving for now and for future? fragile, susceptible to faults (e.g. price calculation)...
                    using (var scope = new DbContextScope(_dbContext, autoDetectChanges: false, proxyCreation: true, validateOnSave: false, forceNoTracking: true))
                    {
                        ctx.DeliveryTimes = _deliveryTimeService.Value.GetAllDeliveryTimes().ToDictionary(x => x.Id);
                        ctx.QuantityUnits = _quantityUnitService.Value.GetAllQuantityUnits().ToDictionary(x => x.Id);
                        ctx.ProductTemplates = _productTemplateService.Value.GetAllProductTemplates().ToDictionary(x => x.Id, x => x.ViewPath);
                        ctx.CategoryTemplates = _categoryTemplateService.Value.GetAllCategoryTemplates().ToDictionary(x => x.Id, x => x.ViewPath);

                        if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Product)
                        {
                            var allCategories = _categoryService.Value.GetAllCategories(showHidden: true, applyNavigationFilters: false);
                            ctx.Categories = allCategories.ToDictionary(x => x.Id);
                        }

                        if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Order)
                        {
                            ctx.Countries = _countryService.Value.GetAllCountries(true).ToDictionary(x => x.Id, x => x);
                        }

                        if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Customer)
                        {
                            var subscriptionEmails = _subscriptionRepository.Value.TableUntracked
                                .Where(x => x.Active)
                                .Select(x => x.Email)
                                .Distinct()
                                .ToList();

                            ctx.NewsletterSubscriptions = new HashSet<string>(subscriptionEmails, StringComparer.OrdinalIgnoreCase);
                        }

                        var stores = Init(ctx);

                        ctx.ExecuteContext.Language = ToDynamic(ctx, ctx.ContextLanguage);
                        ctx.ExecuteContext.Customer = ToDynamic(ctx, ctx.ContextCustomer);
                        ctx.ExecuteContext.Currency = ToDynamic(ctx, ctx.ContextCurrency);

                        stores.ForEach(x => ExportCoreInner(ctx, x));
                    }

                    if (!ctx.IsPreview && ctx.ExecuteContext.Abort != DataExchangeAbortion.Hard)
                    {
                        if (ctx.IsFileBasedExport)
                        {
                            if (ctx.Request.Profile.CreateZipArchive)
                            {
                                ZipFile.CreateFromDirectory(ctx.FolderContent, zipPath, CompressionLevel.Fastest, false);
                            }

                            if (ctx.Request.Profile.Deployments.Any(x => x.Enabled))
                            {
                                SetProgress(ctx, T("Common.Publishing"));

                                var allDeploymentsSucceeded = Deploy(ctx, zipPath);

                                if (allDeploymentsSucceeded && ctx.Request.Profile.Cleanup)
                                {
                                    logger.Information("Cleaning up export folder");

                                    FileSystemHelper.ClearDirectory(ctx.FolderContent, false);
                                }
                            }
                        }

                        if (ctx.Request.Profile.EmailAccountId != 0 && ctx.Request.Profile.CompletedEmailAddresses.HasValue())
                        {
                            SendCompletionEmail(ctx, zipPath);
                        }
                        else if (ctx.Request.Profile.IsSystemProfile && !ctx.Supports(ExportFeatures.CanOmitCompletionMail))
                        {
                            SendCompletionEmail(ctx, zipPath);
                        }
                    }
                }
                catch (Exception exception)
                {
                    logger.ErrorsAll(exception);
                    ctx.Result.LastError = exception.ToString();
                }
                finally
                {
                    try
                    {
                        if (!ctx.IsPreview && ctx.Request.Profile.Id != 0)
                        {
                            ctx.Request.Profile.ResultInfo = XmlHelper.Serialize(ctx.Result);

                            _exportProfileService.Value.UpdateExportProfile(ctx.Request.Profile);
                        }
                    }
                    catch (Exception exception)
                    {
                        logger.ErrorsAll(exception);
                    }

                    DetachAllEntitiesAndClear(ctx);

                    try
                    {
                        ctx.NewsletterSubscriptions.Clear();
                        ctx.ProductTemplates.Clear();
                        ctx.CategoryTemplates.Clear();
                        ctx.Countries.Clear();
                        ctx.Languages.Clear();
                        ctx.QuantityUnits.Clear();
                        ctx.DeliveryTimes.Clear();
                        ctx.CategoryPathes.Clear();
                        ctx.Categories.Clear();
                        ctx.Stores.Clear();

                        ctx.Request.CustomData.Clear();

                        ctx.ExecuteContext.CustomProperties.Clear();
                        ctx.ExecuteContext.Log = null;
                        ctx.Log = null;
                    }
                    catch (Exception exception)
                    {
                        logger.ErrorsAll(exception);
                    }
                }
            }

            if (ctx.IsPreview || ctx.ExecuteContext.Abort == DataExchangeAbortion.Hard)
                return;

            // post process order entities
            if (ctx.EntityIdsLoaded.Any() && ctx.Request.Provider.Value.EntityType == ExportEntityType.Order && ctx.Projection.OrderStatusChange != ExportOrderStatusChange.None)
            {
                using (var logger = new TraceLogger(logPath))
                {
                    try
                    {
                        int? orderStatusId = null;

                        if (ctx.Projection.OrderStatusChange == ExportOrderStatusChange.Processing)
                            orderStatusId = (int)OrderStatus.Processing;
                        else if (ctx.Projection.OrderStatusChange == ExportOrderStatusChange.Complete)
                            orderStatusId = (int)OrderStatus.Complete;

                        using (var scope = new DbContextScope(_dbContext, false, null, false, false, false, false))
                        {
                            foreach (var chunk in ctx.EntityIdsLoaded.Chunk())
                            {
                                var entities = _orderRepository.Value.Table.Where(x => chunk.Contains(x.Id)).ToList();

                                entities.ForEach(x => x.OrderStatusId = (orderStatusId ?? x.OrderStatusId));

                                _dbContext.SaveChanges();
                            }
                        }

                        logger.Information("Updated order status for {0} order(s).".FormatInvariant(ctx.EntityIdsLoaded.Count()));
                    }
                    catch (Exception exception)
                    {
                        logger.ErrorsAll(exception);
                        ctx.Result.LastError = exception.ToString();
                    }
                }
            }
        }
Exemple #20
0
        /// <summary>
        /// Import products from XLSX file
        /// </summary>
        /// <param name="stream">Stream</param>
        public virtual ImportResult ImportProductsFromExcel(
			Stream stream,
			CancellationToken cancellationToken,
			IProgress<ImportProgressInfo> progress = null)
        {
            Guard.ArgumentNotNull(() => stream);

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

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

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

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

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

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

                            // ===========================================================================
                            // 1.) Import products
                            // ===========================================================================
                            try
                            {
                                saved = ProcessProducts(batch, result);
                            }
                            catch (Exception ex)
                            {
                                result.AddError(ex, segmenter.CurrentSegment, "ProcessProducts");
                            }

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

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

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

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

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

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

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

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

            result.EndDateUtc = DateTime.UtcNow;

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

            return result;
        }
        /// <summary>
        /// Install permissions
        /// </summary>
        /// <param name="permissionProvider">Permission provider</param>
        public virtual void InstallPermissions(IPermissionProvider permissionProvider)
        {
            using (var scope = new DbContextScope(_permissionRecordRepository.Context, autoDetectChanges: false, autoCommit: false))
            {
                //install new permissions
                var permissions = permissionProvider.GetPermissions();
                foreach (var permission in permissions)
                {
                    var permission1 = GetPermissionRecordBySystemName(permission.SystemName);
                    if (permission1 == null)
                    {
                        //new permission (install it)
                        permission1 = new PermissionRecord()
                        {
                            Name = permission.Name,
                            SystemName = permission.SystemName,
                            Category = permission.Category,
                        };

                        // default customer role mappings
                        var defaultPermissions = permissionProvider.GetDefaultPermissions();
                        foreach (var defaultPermission in defaultPermissions)
                        {
                            var customerRole = _customerService.GetCustomerRoleBySystemName(defaultPermission.CustomerRoleSystemName);
                            if (customerRole == null)
                            {
                                //new role (save it)
                                customerRole = new CustomerRole()
                                {
                                    Name = defaultPermission.CustomerRoleSystemName,
                                    Active = true,
                                    SystemName = defaultPermission.CustomerRoleSystemName
                                };
                                _customerService.InsertCustomerRole(customerRole);
                            }

                            var defaultMappingProvided = (from p in defaultPermission.PermissionRecords
                                                            where p.SystemName == permission1.SystemName
                                                            select p).Any();
                            var mappingExists = (from p in customerRole.PermissionRecords
                                                    where p.SystemName == permission1.SystemName
                                                    select p).Any();
                            if (defaultMappingProvided && !mappingExists)
                            {
                                permission1.CustomerRoles.Add(customerRole);
                            }
                        }

                        //save new permission
                        InsertPermissionRecord(permission1);
                    }
                }

                scope.Commit();
            }
        }
        public virtual void InheritAclIntoChildren(int categoryId, 
            bool touchProductsWithMultipleCategories = false,
            bool touchExistingAcls = false,
            bool categoriesOnly = false)
        {

            var category = GetCategoryById(categoryId);
            var subcategories = GetAllCategoriesByParentCategoryId(categoryId, true);
            var context = new ProductSearchContext { PageSize = int.MaxValue, ShowHidden = true };
            context.CategoryIds.AddRange(subcategories.Select(x => x.Id));
            context.CategoryIds.Add(categoryId);
            var products = _productService.SearchProducts(context);
            var allCustomerRoles = _customerService.GetAllCustomerRoles(true);
            var categoryCustomerRoles = _aclService.GetCustomerRoleIdsWithAccess(category);

            using (var scope = new DbContextScope(ctx: _aclRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false))
            {
                _aclRepository.AutoCommitEnabled = false;

                foreach (var subcategory in subcategories)
                {
                    if (subcategory.SubjectToAcl != category.SubjectToAcl)
                    {
                        subcategory.SubjectToAcl = category.SubjectToAcl;
                        _categoryRepository.Update(subcategory);
                    }

                    var existingAclRecords = _aclService.GetAclRecords(subcategory).ToDictionary(x => x.CustomerRoleId);

                    foreach (var customerRole in allCustomerRoles)
                    {
                        if (categoryCustomerRoles.Contains(customerRole.Id))
                        {
                            if (!existingAclRecords.ContainsKey(customerRole.Id))
                            {
                                _aclRepository.Insert(new AclRecord { CustomerRole = customerRole, CustomerRoleId = customerRole.Id, EntityId = subcategory.Id, EntityName = "Category" });
                            }
                        }
                        else
                        {
                            AclRecord aclRecordToDelete;
                            if (existingAclRecords.TryGetValue(customerRole.Id, out aclRecordToDelete))
                            {
                                _aclRepository.Delete(aclRecordToDelete);
                            }
                        }
                    }
                }
                
                _aclRepository.Context.SaveChanges();

                foreach (var product in products)
                {
                    if (product.SubjectToAcl != category.SubjectToAcl)
                    {
                        product.SubjectToAcl = category.SubjectToAcl;
                        _productRepository.Update(product);
                    }

                    var existingAclRecords = _aclService.GetAclRecords(product).ToDictionary(x => x.CustomerRoleId);

                    foreach (var customerRole in allCustomerRoles)
                    {
                        if (categoryCustomerRoles.Contains(customerRole.Id))
                        {
                            if (!existingAclRecords.ContainsKey(customerRole.Id))
                            {
                                _aclRepository.Insert(new AclRecord { CustomerRole = customerRole, CustomerRoleId = customerRole.Id, EntityId = product.Id, EntityName = "Product" });
                            }
                        }
                        else
                        {
                            AclRecord aclRecordToDelete;
                            if (existingAclRecords.TryGetValue(customerRole.Id, out aclRecordToDelete))
                            {
                                _aclRepository.Delete(aclRecordToDelete);
                            }
                        }
                    }
                }

                _aclRepository.Context.SaveChanges();
            }
        }
        public void StartCreatingFeeds(Func<FeedFileCreationContext, bool> createFeed, string secondFileName = null)
        {
            try
            {
                using (var scope = new DbContextScope(autoDetectChanges: false, validateOnSave: false, forceNoTracking: true))
                {
                    _cachedPathes = null;
                    _cachedCategories = null;

                    var storeService = _ctx.Resolve<IStoreService>();
                    var stores = new List<Store>();

                    if (BaseSettings.StoreId != 0)
                    {
                        var storeById = storeService.GetStoreById(BaseSettings.StoreId);
                        if (storeById != null)
                            stores.Add(storeById);
                    }

                    if (stores.Count == 0)
                    {
                        stores.AddRange(storeService.GetAllStores());
                    }

                    var context = new FeedFileCreationContext
                    {
                        StoreCount = stores.Count,
                        Progress = new Progress<FeedFileCreationProgress>(x =>
                        {
                            AsyncState.Current.Set(x, SystemName);
                        })
                    };

                    foreach (var store in stores)
                    {
                        var feedFile = GetFeedFileByStore(store, secondFileName);
                        if (feedFile != null)
                        {
                            FileSystemHelper.Delete(feedFile.FileTempPath);

                            if (secondFileName.HasValue())
                                FileSystemHelper.Delete(feedFile.CustomProperties["SecondFileTempPath"] as string);

                            using (var stream = new FileStream(feedFile.FileTempPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                            using (var logger = new TraceLogger(feedFile.LogPath))
                            {
                                context.Stream = stream;
                                context.Logger = logger;
                                context.Store = store;
                                context.FeedFileUrl = feedFile.FileUrl;

                                if (secondFileName.HasValue())
                                    context.SecondFilePath = feedFile.CustomProperties["SecondFileTempPath"] as string;

                                if (!createFeed(context))
                                    break;
                            }

                            FileSystemHelper.Copy(feedFile.FileTempPath, feedFile.FilePath);

                            if (secondFileName.HasValue())
                                FileSystemHelper.Copy(context.SecondFilePath, feedFile.CustomProperties["SecondFilePath"] as string);
                        }
                    }
                }
            }
            finally
            {
                AsyncState.Current.Remove<FeedFileCreationProgress>(SystemName);
            }
        }
        protected int MovePictures(bool toDb)
        {
            // long running operation, therefore some code chunks are redundant here in order to boost performance

            // a list of ALL file paths that were either deleted or created
            var affectedFiles = new List<string>(1000);

            var ctx = _pictureRepository.Context;
            var failed = false;
            int i = 0;

            using (var scope = new DbContextScope(ctx: ctx, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                using (var tx = ctx.BeginTransaction())
                {
                    // we are about to process data in chunks but want to commit ALL at once when ALL chunks have been processed successfully.
                    try
                    {
                        int pageIndex = 0;
                        IPagedList<Picture> pictures = null;

                        do
                        {
                            if (pictures != null)
                            {
                                // detach all entities from previous page to save memory
                                ctx.DetachEntities(pictures);

                                // breathe
                                pictures.Clear();
                                pictures = null;
                            }

                            // load max 500 picture entities at once
                            pictures = this.GetPictures(pageIndex, 500);
                            pageIndex++;

                            foreach (var picture in pictures)
                            {
                                string filePath = null;

                                if (!toDb)
                                {
                                    if (picture.PictureBinary != null && picture.PictureBinary.Length > 0)
                                    {
                                        // save picture as file
                                        SavePictureInFile(picture.Id, picture.PictureBinary, picture.MimeType, out filePath);
                                    }
                                    // remove picture binary from DB
                                    picture.PictureBinary = new byte[0];
                                }
                                else
                                {
                                    // load picture binary from file and set in DB
                                    var picBinary = LoadPictureFromFile(picture.Id, picture.MimeType, out filePath);
                                    if (picBinary.Length > 0)
                                    {
                                        picture.PictureBinary = picBinary;
                                    }
                                }

                                // remember file path: we must be able to rollback IO operations on transaction failure
                                if (filePath.HasValue())
                                {
                                    affectedFiles.Add(filePath);
                                    //picture.IsNew = true;
                                }

                                // explicitly attach modified entity to context, because we disabled AutoCommit
                                picture.UpdatedOnUtc = DateTime.UtcNow;
                                _pictureRepository.Update(picture);

                                i++;
                            }

                            // save the current batch to DB
                            ctx.SaveChanges();

                        } while (pictures.HasNextPage);

                        // FIRE!
                        tx.Commit();
                    }
                    catch (Exception ex)
                    {
                        failed = true;
                        tx.Rollback();
                        _settingService.SetSetting<bool>("Media.Images.StoreInDB", !toDb);
                        _notifier.Error(ex.Message);
                        _logger.Error(ex);
                    }
                }
            }

            if (affectedFiles.Count > 0)
            {
                if ((toDb && !failed) || (!toDb && failed))
                {
                    // FS > DB sucessful OR DB > FS failed: delete all physical files
                    // run a background task for the deletion of files (fire & forget)
                    Task.Factory.StartNew(state =>
                    {
                        var files = state as string[];
                        foreach (var path in files)
                        {
                            if (File.Exists(path))
                                File.Delete(path);
                        }
                    }, affectedFiles.ToArray()).ConfigureAwait(false);
                }

                // shrink database (only when DB > FS and success)
                if (!toDb && !failed)
                {
                    ctx.ShrinkDatabase();
                }
            }

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

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

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

                Initialize(context);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        _productRepository.Context.DetachAll(false);

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