From e006494117e318db6c9e5a05d83206d53159b122 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 13 Jun 2015 13:03:44 +0200 Subject: [PATCH 0001/1074] New payment method entity and stand-alone page for editing a payment method (no popup window anymore) --- .../Domain/Payments/PaymentMethod.cs | 35 +++++ .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../Mapping/Payments/PaymentMethodMap.cs | 20 +++ ...62_PaymentShippingRestrictions.Designer.cs | 29 ++++ ...06130926062_PaymentShippingRestrictions.cs | 29 ++++ ...130926062_PaymentShippingRestrictions.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 8 ++ .../DependencyRegistrar.cs | 42 +++--- .../Mvc/ProviderModel.cs | 14 +- .../Plugins/PluginMediator.cs | 1 + .../Controllers/PaymentController.cs | 14 ++ .../Models/Payments/PaymentMethodEditModel.cs | 13 ++ .../Administration/SmartStore.Admin.csproj | 2 + .../Administration/Views/Payment/Edit.cshtml | 21 +++ .../Views/Shared/_Providers.cshtml | 18 ++- 15 files changed, 345 insertions(+), 28 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs create mode 100644 src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.resx create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs new file mode 100644 index 0000000000..dae3e3dddd --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs @@ -0,0 +1,35 @@ +using System.Runtime.Serialization; + +namespace SmartStore.Core.Domain.Payments +{ + /// + /// Represents a payment method + /// + [DataContract] + public partial class PaymentMethod : BaseEntity + { + /// + /// Gets or sets the payment method system name + /// + [DataMember] + public string PaymentMethodSystemName { get; set; } + + /// + /// Gets or sets identifiers of customer roles (comma separated) to be excluded in checkout + /// + [DataMember] + public string ExcludedCustomerRoleIds { get; set; } + + /// + /// Gets or sets identifiers of countries (comma separated) to be excluded in checkout + /// + [DataMember] + public string ExcludedCountryIds { get; set; } + + /// + /// Gets or sets identifiers of shipping methods (comma separated) to be excluded in checkout + /// + [DataMember] + public string ExcludedShippingMethodIds { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 367040dc86..d9418948fb 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -157,6 +157,7 @@ + diff --git a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs new file mode 100644 index 0000000000..3544292bef --- /dev/null +++ b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs @@ -0,0 +1,20 @@ +using System.Data.Entity.ModelConfiguration; +using SmartStore.Core.Domain.Payments; + +namespace SmartStore.Data.Mapping.Payments +{ + public partial class PaymentMethodMap : EntityTypeConfiguration + { + public PaymentMethodMap() + { + this.ToTable("PaymentMethod"); + this.HasKey(x => x.Id); + + this.Property(x => x.PaymentMethodSystemName).IsRequired().HasMaxLength(4000); + + this.Property(x => x.ExcludedCustomerRoleIds).IsMaxLength(); + this.Property(x => x.ExcludedCountryIds).IsMaxLength(); + this.Property(x => x.ExcludedShippingMethodIds).IsMaxLength(); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.Designer.cs new file mode 100644 index 0000000000..1432d4c15b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class PaymentShippingRestrictions : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(PaymentShippingRestrictions)); + + string IMigrationMetadata.Id + { + get { return "201506130926062_PaymentShippingRestrictions"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs new file mode 100644 index 0000000000..dad5d45220 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs @@ -0,0 +1,29 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class PaymentShippingRestrictions : DbMigration + { + public override void Up() + { + CreateTable( + "dbo.PaymentMethod", + c => new + { + Id = c.Int(nullable: false, identity: true), + PaymentMethodSystemName = c.String(nullable: false, maxLength: 4000), + ExcludedCustomerRoleIds = c.String(), + ExcludedCountryIds = c.String(), + ExcludedShippingMethodIds = c.String(), + }) + .PrimaryKey(t => t.Id) + .Index(t => t.PaymentMethodSystemName); + } + + public override void Down() + { + DropTable("dbo.PaymentMethod"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.resx new file mode 100644 index 0000000000..621557bdf4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 0eeab2be55..103589f9cc 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -116,6 +116,7 @@ Properties\AssemblyVersionInfo.cs + 201403112331027_Initial.cs @@ -272,6 +273,10 @@ 201505272236124_V222.cs + + + 201506130926062_PaymentShippingRestrictions.cs + @@ -529,6 +534,9 @@ 201505272236124_V222.cs + + 201506130926062_PaymentShippingRestrictions.cs + diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 839a8fd01e..549ad459a9 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -13,12 +13,22 @@ using SmartStore.Core.Caching; using SmartStore.Core.Configuration; using SmartStore.Core.Data; +using SmartStore.Core.Data.Hooks; +using SmartStore.Core.Email; using SmartStore.Core.Events; using SmartStore.Core.Fakes; using SmartStore.Core.Infrastructure; using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.Core.IO.Media; +using SmartStore.Core.IO.VirtualPath; +using SmartStore.Core.IO.WebSite; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Core.Packaging; using SmartStore.Core.Plugins; +using SmartStore.Core.Themes; using SmartStore.Data; +using SmartStore.Services; using SmartStore.Services.Affiliates; using SmartStore.Services.Authentication; using SmartStore.Services.Authentication.External; @@ -30,49 +40,39 @@ using SmartStore.Services.Customers; using SmartStore.Services.Directory; using SmartStore.Services.Discounts; +using SmartStore.Services.Events; using SmartStore.Services.ExportImport; +using SmartStore.Services.Filter; using SmartStore.Services.Forums; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; +using SmartStore.Services.Logging; using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.News; using SmartStore.Services.Orders; using SmartStore.Services.Payments; +using SmartStore.Services.Pdf; using SmartStore.Services.Polls; using SmartStore.Services.Security; using SmartStore.Services.Seo; using SmartStore.Services.Shipping; +using SmartStore.Services.Stores; using SmartStore.Services.Tasks; using SmartStore.Services.Tax; +using SmartStore.Services.Themes; using SmartStore.Services.Topics; -using SmartStore.Web.Framework.Mvc.Routes; +using SmartStore.Utilities; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Localization; using SmartStore.Web.Framework.Mvc.Bundles; +using SmartStore.Web.Framework.Mvc.Routes; +using SmartStore.Web.Framework.Plugins; using SmartStore.Web.Framework.Themes; using SmartStore.Web.Framework.UI; using SmartStore.Web.Framework.WebApi; -using SmartStore.Web.Framework.Plugins; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Services.Filter; -using SmartStore.Core.Data.Hooks; -using SmartStore.Core.Themes; -using SmartStore.Services.Themes; -using SmartStore.Services.Stores; using SmartStore.Web.Framework.WebApi.Configuration; -using SmartStore.Services; using Module = Autofac.Module; -using SmartStore.Core.Localization; -using SmartStore.Web.Framework.Localization; -using SmartStore.Core.Email; -using SmartStore.Services.Events; -using SmartStore.Services.Logging; -using SmartStore.Core.Packaging; -using SmartStore.Core.IO.Media; -using SmartStore.Core.IO.VirtualPath; -using SmartStore.Core.IO.WebSite; -using SmartStore.Utilities; -using SmartStore.Services.Pdf; namespace SmartStore.Web.Framework { diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/ProviderModel.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/ProviderModel.cs index bcef0c17b5..5b1d1ecfc7 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/ProviderModel.cs +++ b/src/Presentation/SmartStore.Web.Framework/Mvc/ProviderModel.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Web; using System.Web.Mvc; -using System.Web.Routing; using SmartStore.Core.Plugins; +using SmartStore.Services.Payments; using SmartStore.Web.Framework.Localization; namespace SmartStore.Web.Framework.Mvc @@ -12,6 +10,8 @@ namespace SmartStore.Web.Framework.Mvc public class ProviderModel : ModelBase, ILocalizedModel { private IList _locales; + + public Type ProviderType { get; set; } [SmartResourceDisplayName("Common.SystemName")] public string SystemName { get; set; } @@ -61,6 +61,14 @@ public IList Locales _locales = value; } } + + public bool IsPaymentMethod + { + get + { + return ProviderType.Equals(typeof(IPaymentMethod)); + } + } } public class ProviderLocalizedModel : ILocalizedModelLocal diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginMediator.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginMediator.cs index 312c587703..5e19ca26c8 100644 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginMediator.cs +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginMediator.cs @@ -153,6 +153,7 @@ public TModel ToProviderModel(Provider provider, b var metadata = provider.Metadata; var model = new TModel(); + model.ProviderType = typeof(TProvider); model.SystemName = metadata.SystemName; model.FriendlyName = forEdit ? metadata.FriendlyName : GetLocalizedFriendlyName(metadata); model.Description = forEdit ? metadata.Description : GetLocalizedDescription(metadata); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs index 9a8fa7de43..4f5069d636 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs @@ -93,6 +93,20 @@ public ActionResult ActivateProvider(string systemName, bool activate) return RedirectToAction("Providers"); } + public ActionResult Edit(string systemName) + { + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) + return AccessDeniedView(); + + var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(systemName); + + var model = _pluginMediator.ToProviderModel(paymentMethod); + + model.IconUrl = _pluginMediator.GetIconUrl(model.PluginDescriptor); + + return View(model); + } + #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs new file mode 100644 index 0000000000..2bd13383ca --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using SmartStore.Web.Framework.Mvc; + +namespace SmartStore.Admin.Models.Payments +{ + public class PaymentMethodEditModel : ProviderModel + { + public string IconUrl { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index fd2aa999ac..51dabda6e7 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -251,6 +251,7 @@ + @@ -493,6 +494,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml new file mode 100644 index 0000000000..dce17feea7 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml @@ -0,0 +1,21 @@ +@model PaymentMethodEditModel + +@{ + ViewBag.Title = T("Common.Edit").Text + " - " + Model.FriendlyName; +} + +@using (Html.BeginForm()) +{ +
+
+ @Model.FriendlyName + @ViewBag.Title (@(Model.SystemName)) + (@T("Admin.Common.BackToList")) +
+
+ + +
+
+ +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shared/_Providers.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shared/_Providers.cshtml index fa393778d5..c0907267c1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shared/_Providers.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shared/_Providers.cshtml @@ -84,10 +84,20 @@
@if (item.IsEditable) { - - - @T("Admin.Common.Edit") - + if (item.IsPaymentMethod) + { + + + @T("Admin.Common.Edit") + + } + else + { + + + @T("Admin.Common.Edit") + + } } @if (item.IsConfigurable) { From 2548956e15d3770dbb3433cc063aca0ce82e77a8 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 15 Jun 2015 14:35:23 +0200 Subject: [PATCH 0002/1074] Editing of payment method restrictions --- ...06130926062_PaymentShippingRestrictions.cs | 26 ++- .../Payments/IPaymentService.cs | 21 +++ .../Payments/PaymentService.cs | 52 +++++- .../Administration/Content/admin.less | 23 +++ .../Controllers/PaymentController.cs | 147 +++++++++++++++- .../Models/Payments/PaymentMethodEditModel.cs | 10 +- .../Administration/Views/Payment/Edit.cshtml | 159 +++++++++++++++++- .../Payments/PaymentServiceTests.cs | 12 +- 8 files changed, 429 insertions(+), 21 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs index dad5d45220..175f4ea9ce 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs @@ -2,8 +2,9 @@ namespace SmartStore.Data.Migrations { using System; using System.Data.Entity.Migrations; - - public partial class PaymentShippingRestrictions : DbMigration + using SmartStore.Data.Setup; + + public partial class PaymentShippingRestrictions : DbMigration, ILocaleResourcesProvider, IDataSeeder { public override void Up() { @@ -25,5 +26,26 @@ public override void Down() { DropTable("dbo.PaymentMethod"); } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.Restrictions", + "Restrictions", + "Einschrnkungen"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", + "Select customer roles, shipping methods and countries for which you do not want to offer this payment method.", + "Whlen Sie Kundengruppen, Versandarten und Lnder, bei denen sie diese Zahlungsmethode nicht anbieten mchten."); + } } } diff --git a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs index 0d56507652..3757dcb42d 100644 --- a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; using SmartStore.Core.Plugins; namespace SmartStore.Services.Payments @@ -37,6 +38,26 @@ public partial interface IPaymentService IEnumerable> LoadAllPaymentMethods(int storeId = 0); + /// + /// Gets a payment method by system name + /// + /// Provider system name + /// Payment method entity + PaymentMethod GetPaymentMethodBySystemName(string systemName); + + /// + /// Insert a payment method + /// + /// Payment method + void InsertPaymentMethod(PaymentMethod paymentMethod); + + /// + /// Updates a payment method + /// + /// Payment method + void UpdatePaymentMethod(PaymentMethod paymentMethod); + + /// /// Pre process a payment diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index 69f2d391de..ea0d560fce 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -4,6 +4,7 @@ using SmartStore.Core.Data; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Events; using SmartStore.Core.Plugins; using SmartStore.Services.Configuration; using SmartStore.Services.Localization; @@ -17,12 +18,14 @@ public partial class PaymentService : IPaymentService { #region Fields + private readonly IRepository _paymentMethodRepository; private readonly PaymentSettings _paymentSettings; private readonly IPluginFinder _pluginFinder; private readonly ShoppingCartSettings _shoppingCartSettings; private readonly ISettingService _settingService; private readonly ILocalizationService _localizationService; private readonly IProviderManager _providerManager; + private readonly IEventPublisher _eventPublisher; #endregion @@ -36,19 +39,23 @@ public partial class PaymentService : IPaymentService /// Shopping cart settings /// Plugin service public PaymentService( + IRepository paymentMethodRepository, PaymentSettings paymentSettings, IPluginFinder pluginFinder, ShoppingCartSettings shoppingCartSettings, ISettingService settingService, ILocalizationService localizationService, - IProviderManager providerManager) + IProviderManager providerManager, + IEventPublisher eventPublisher) { + this._paymentMethodRepository = paymentMethodRepository; this._paymentSettings = paymentSettings; this._pluginFinder = pluginFinder; this._shoppingCartSettings = shoppingCartSettings; this._settingService = settingService; this._localizationService = localizationService; this._providerManager = providerManager; + this._eventPublisher = eventPublisher; } #endregion @@ -122,6 +129,49 @@ public virtual IEnumerable> LoadAllPaymentMethods(int s } + /// + /// Gets a payment method by system name + /// + /// Provider system name + /// Payment method entity + public virtual PaymentMethod GetPaymentMethodBySystemName(string systemName) + { + if (systemName.HasValue()) + { + return _paymentMethodRepository.Table.FirstOrDefault(x => x.PaymentMethodSystemName == systemName); + } + return null; + } + + /// + /// Insert a payment method + /// + /// Payment method + public virtual void InsertPaymentMethod(PaymentMethod paymentMethod) + { + if (paymentMethod == null) + throw new ArgumentNullException("paymentMethod"); + + _paymentMethodRepository.Insert(paymentMethod); + + _eventPublisher.EntityInserted(paymentMethod); + } + + /// + /// Updates a payment method + /// + /// Payment method + public virtual void UpdatePaymentMethod(PaymentMethod paymentMethod) + { + if (paymentMethod == null) + throw new ArgumentNullException("paymentMethod"); + + _paymentMethodRepository.Update(paymentMethod); + + _eventPublisher.EntityUpdated(paymentMethod); + } + + /// /// Pre process a payment /// diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index c743cf9e3f..20f7c1f835 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -1197,6 +1197,29 @@ table.payment-method-features td { font-size: 12px; } +/* payment methods restrictions +-------------------------------------------------------------- */ +.payment-restrictions th label { + margin: 0; +} +.payment-restrictions .column-customerroles, +.payment-restrictions .column-shippingmethods { + width: 18%; +} +.payment-restrictions .column-countries { + width: 64%; + + > div { + display: table-row; + } + + .country-countainer { + display: table-cell; + width: 25%; + padding-right: 10px; + } +} + /* Special icons */ .icon-active-true { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs index 4f5069d636..2f725737b7 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs @@ -1,14 +1,19 @@ -using System.Collections.Generic; +using System.Linq; +using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Admin.Models.Payments; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Plugins; using SmartStore.Services; +using SmartStore.Services.Customers; +using SmartStore.Services.Directory; using SmartStore.Services.Localization; using SmartStore.Services.Payments; using SmartStore.Services.Security; +using SmartStore.Services.Shipping; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Plugins; +using SmartStore.Web.Framework.Mvc; namespace SmartStore.Admin.Controllers { @@ -22,6 +27,10 @@ public partial class PaymentController : AdminControllerBase private readonly PaymentSettings _paymentSettings; private readonly IPluginFinder _pluginFinder; private readonly PluginMediator _pluginMediator; + private readonly ILanguageService _languageService; + private readonly ICustomerService _customerService; + private readonly IShippingService _shippingService; + private readonly ICountryService _countryService; #endregion @@ -32,20 +41,80 @@ public PaymentController( IPaymentService paymentService, PaymentSettings paymentSettings, IPluginFinder pluginFinder, - PluginMediator pluginMediator) + PluginMediator pluginMediator, + ILanguageService languageService, + ICustomerService customerService, + IShippingService shippingService, + ICountryService countryService) { this._commonServices = commonServices; this._paymentService = paymentService; this._paymentSettings = paymentSettings; this._pluginFinder = pluginFinder; this._pluginMediator = pluginMediator; + this._languageService = languageService; + this._customerService = customerService; + this._shippingService = shippingService; + this._countryService = countryService; } - #endregion  + #endregion + + #region Utilities + + private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, PaymentMethod paymentMethod) + { + SelectListItem item = null; + var customerRoles = _customerService.GetAllCustomerRoles(true); + var shippingMethods = _shippingService.GetAllShippingMethods(); + var countries = _countryService.GetAllCountries(true); - #region Methods + model.AvailableCustomerRoles = new List(); + model.AvailableShippingMethods = new List(); + model.AvaliableCountries = new List(); - public ActionResult Providers() + foreach (var role in customerRoles.OrderBy(x => x.Name)) + { + model.AvailableCustomerRoles.Add(new SelectListItem { Text = role.Name, Value = role.Id.ToString() }); + } + + foreach (var shippingMethod in shippingMethods.OrderBy(x => x.Name)) + { + model.AvailableShippingMethods.Add(new SelectListItem { Text = shippingMethod.GetLocalized(x => x.Name), Value = shippingMethod.Id.ToString() }); + } + + foreach (var country in countries.OrderBy(x => x.Name)) + { + model.AvaliableCountries.Add(new SelectListItem { Text = country.GetLocalized(x => x.Name), Value = country.Id.ToString() }); + } + + if (paymentMethod != null) + { + foreach (var id in paymentMethod.ExcludedCustomerRoleIds.SplitSafe(",")) + { + if ((item = model.AvailableCustomerRoles.FirstOrDefault(x => x.Value == id)) != null) + item.Selected = true; + } + + foreach (var id in paymentMethod.ExcludedShippingMethodIds.SplitSafe(",")) + { + if ((item = model.AvailableShippingMethods.FirstOrDefault(x => x.Value == id)) != null) + item.Selected = true; + } + + foreach (var id in paymentMethod.ExcludedCountryIds.SplitSafe(",")) + { + if ((item = model.AvaliableCountries.FirstOrDefault(x => x.Value == id)) != null) + item.Selected = true; + } + } + } + + #endregion + + #region Methods + + public ActionResult Providers() { if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) return AccessDeniedView(); @@ -98,15 +167,77 @@ public ActionResult Edit(string systemName) if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) return AccessDeniedView(); - var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(systemName); + var provider = _paymentService.LoadPaymentMethodBySystemName(systemName); + var paymentMethod = _paymentService.GetPaymentMethodBySystemName(systemName); + + var model = _pluginMediator.ToProviderModel(provider, true); - var model = _pluginMediator.ToProviderModel(paymentMethod); + AddLocales(_languageService, model.Locales, (locale, languageId) => + { + locale.FriendlyName = _pluginMediator.GetLocalizedFriendlyName(provider.Metadata, languageId, false); + locale.Description = _pluginMediator.GetLocalizedDescription(provider.Metadata, languageId, false); + }); - model.IconUrl = _pluginMediator.GetIconUrl(model.PluginDescriptor); + PreparePaymentMethodEditModel(model, paymentMethod); return View(model); } + [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] + public ActionResult Edit(string systemName, bool continueEditing, ProviderModel model) + { + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) + return AccessDeniedView(); + + var provider = _paymentService.LoadPaymentMethodBySystemName(systemName); + if (provider == null) + return HttpNotFound(); + + _pluginMediator.SetSetting(provider.Metadata, "FriendlyName", model.FriendlyName); + _pluginMediator.SetSetting(provider.Metadata, "Description", model.Description); + + foreach (var localized in model.Locales) + { + _pluginMediator.SaveLocalizedValue(provider.Metadata, localized.LanguageId, "FriendlyName", localized.FriendlyName); + _pluginMediator.SaveLocalizedValue(provider.Metadata, localized.LanguageId, "Description", localized.Description); + } + + var paymentMethod = _paymentService.GetPaymentMethodBySystemName(systemName); + + if (paymentMethod == null) + paymentMethod = new PaymentMethod { PaymentMethodSystemName = systemName }; + + var customerRoleIds = Request.Form.AllKeys + .Where(x => x.StartsWith("CustomerRole_")) + .Select(x => x.Replace("CustomerRole_", "")) + .ToList(); + + var shippingMethodIds = Request.Form.AllKeys + .Where(x => x.StartsWith("ShippingMethod_")) + .Select(x => x.Replace("ShippingMethod_", "")) + .ToList(); + + var countryIds = Request.Form.AllKeys + .Where(x => x.StartsWith("Country_")) + .Select(x => x.Replace("Country_", "")) + .ToList(); + + paymentMethod.ExcludedCustomerRoleIds = string.Join(",", customerRoleIds); + paymentMethod.ExcludedShippingMethodIds = string.Join(",", shippingMethodIds); + paymentMethod.ExcludedCountryIds = string.Join(",", countryIds); + + if (paymentMethod.Id == 0) + _paymentService.InsertPaymentMethod(paymentMethod); + else + _paymentService.UpdatePaymentMethod(paymentMethod); + + NotifySuccess(_commonServices.Localization.GetResource("Admin.Common.DataEditSuccess")); + + return (continueEditing ? + RedirectToAction("Edit", "Payment", new { systemName = systemName }) : + RedirectToAction("Providers", "Payment")); + } + #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs index 2bd13383ca..e2f2f40437 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs @@ -1,13 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; +using System.Collections.Generic; +using System.Web.Mvc; using SmartStore.Web.Framework.Mvc; namespace SmartStore.Admin.Models.Payments { public class PaymentMethodEditModel : ProviderModel { - public string IconUrl { get; set; } + public List AvailableCustomerRoles { get; set; } + public List AvailableShippingMethods { get; set; } + public List AvaliableCountries { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml index dce17feea7..df02bbbd14 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml @@ -4,7 +4,7 @@ ViewBag.Title = T("Common.Edit").Text + " - " + Model.FriendlyName; } -@using (Html.BeginForm()) +@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "paymentmethod-form" })) {
@@ -17,5 +17,160 @@
+ + @Html.ValidationSummary(false) + @Html.HiddenFor(model => model.SystemName) -} \ No newline at end of file + + @Html.SmartStore().TabStrip().Name("paymentmethod-edit").Items(x => + { + x.Add().Text(T("Admin.Common.General").Text).Content(TabGeneral()).Selected(true); + x.Add().Text(T("Admin.Common.Restrictions").Text).Content(TabRestrictions()); + + EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "paymentmethod-edit", this.Html, this.Model)); + }) +} + +@helper TabGeneral() +{ + @(Html.LocalizedEditor("paymentmethod-general-localized", + @ + + + + + + + + + + + +
+ @Html.SmartLabelFor(model => model.Locales[item].FriendlyName) + + @Html.EditorFor(model => Model.Locales[item].FriendlyName) + @Html.ValidationMessageFor(model => model.Locales[item].FriendlyName) +
+ @Html.SmartLabelFor(model => model.Locales[item].Description) + + @Html.TextAreaFor(model => Model.Locales[item].Description, new { @class = "input-large" }) + @Html.ValidationMessageFor(model => model.Locales[item].Description) +
+ @Html.HiddenFor(model => model.Locales[item].LanguageId) +
+ , + @ + + + + + + + + +
+ @Html.SmartLabelFor(model => model.FriendlyName) + + @Html.EditorFor(model => model.FriendlyName) + @Html.ValidationMessageFor(model => model.FriendlyName) +
+ @Html.SmartLabelFor(model => model.Description) + + @Html.TextAreaFor(model => model.Description, new { @class = "input-large" }) + @Html.ValidationMessageFor(model => model.Description) +
+ )) +} + +@helper TabRestrictions() +{ +
+ @Html.Raw(T("Admin.Configuration.Payment.Methods.RestrictionNote")) +
+ +
+ + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+ +
+
+ @foreach (var item in Model.AvailableCustomerRoles) + { + @RenderCheckbox(item, "CustomerRole_") + } + + @foreach (var item in Model.AvailableShippingMethods) + { + @RenderCheckbox(item, "ShippingMethod_") + } + + + @foreach (var grp in Model.AvaliableCountries.Select((x, i) => new { Key = i / 4, Value = x }).GroupBy(x => x.Key, x => x.Value)) + { +
+ @foreach (var item in grp) + { +
+ @RenderCheckbox(item, "Country_") +
+ } +
+ } + +
+
+} + + +@helper RenderCheckbox(SelectListItem item, string prefix) +{ +
+ +
+} + + \ No newline at end of file diff --git a/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs index 8abc5990ff..329cf092bd 100644 --- a/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs @@ -1,10 +1,11 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Rhino.Mocks; +using SmartStore.Core.Data; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Events; using SmartStore.Core.Plugins; using SmartStore.Services.Configuration; using SmartStore.Services.Localization; @@ -16,10 +17,12 @@ namespace SmartStore.Services.Tests.Payments [TestFixture] public class PaymentServiceTests : ServiceTest { + IRepository _paymentMethodRepository; PaymentSettings _paymentSettings; ShoppingCartSettings _shoppingCartSettings; IPaymentService _paymentService; ISettingService _settingService; + IEventPublisher _eventPublisher; [SetUp] public new void SetUp() @@ -31,12 +34,15 @@ public class PaymentServiceTests : ServiceTest var pluginFinder = new PluginFinder(); _shoppingCartSettings = new ShoppingCartSettings(); + _paymentMethodRepository = MockRepository.GenerateMock>(); _settingService = MockRepository.GenerateMock(); + _eventPublisher = MockRepository.GenerateMock(); var localizationService = MockRepository.GenerateMock(); localizationService.Expect(ls => ls.GetResource(null)).IgnoreArguments().Return("NotSupported").Repeat.Any(); - _paymentService = new PaymentService(_paymentSettings, pluginFinder, _shoppingCartSettings, _settingService, localizationService, this.ProviderManager); + _paymentService = new PaymentService(_paymentMethodRepository, _paymentSettings, pluginFinder, _shoppingCartSettings, + _settingService, localizationService, this.ProviderManager, _eventPublisher); } [Test] From 7fa48e659fc1a8fd4001d3fd0cc8347ceccffd0d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 16 Jun 2015 13:53:49 +0200 Subject: [PATCH 0003/1074] Resolves #141 Payment methods by customer roles Resolves #67 Restrict payment methods to certain countries Resolves #94 Restrict payment methods to certain shipping methods --- changelog.md | 3 + .../Domain/Payments/PaymentMethod.cs | 2 +- .../Domain/Shipping/ShippingOption.cs | 5 + .../Payments/IPaymentService.cs | 24 +++- .../Payments/PaymentService.cs | 131 +++++++++++++++--- .../Providers/ByTotalProvider.cs | 1 + .../Providers/FixedRateProvider.cs | 1 + .../ByWeightShippingComputationMethod.cs | 1 + .../Controllers/CheckoutController.cs | 16 ++- .../Controllers/ShoppingCartController.cs | 9 +- .../Checkout/CheckoutShippingMethodModel.cs | 1 + .../ShoppingCart/EstimateShippingModel.cs | 2 + .../SmartStore.Core.Tests/ConversionTests.cs | 19 ++- .../ShippingOptionListTypeConverterTests.cs | 4 + .../ShippingOptionTypeConverterTests.cs | 2 + .../Payments/PaymentServiceTests.cs | 5 +- ...edRateTestShippingRateComputationMethod.cs | 2 + 17 files changed, 192 insertions(+), 36 deletions(-) diff --git a/changelog.md b/changelog.md index 649abc4e24..3c5e567274 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,9 @@ ### New Features * #210 Implement multi-store support for import/export +* #141 Payment methods by customer roles +* #67 Restrict payment methods to certain countries +* #94 Restrict payment methods to certain shipping methods ### Improvements * License checker now supports IDN mapping for domain names diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs index dae3e3dddd..e85e14bf9d 100644 --- a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs +++ b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs @@ -27,7 +27,7 @@ public partial class PaymentMethod : BaseEntity public string ExcludedCountryIds { get; set; } /// - /// Gets or sets identifiers of shipping methods (comma separated) to be excluded in checkout + /// Gets or sets shipping methods (comma separated) to be excluded in checkout /// [DataMember] public string ExcludedShippingMethodIds { get; set; } diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingOption.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingOption.cs index d059f630b7..ad29aba1aa 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingOption.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingOption.cs @@ -13,6 +13,11 @@ namespace SmartStore.Core.Domain.Shipping ///
public partial class ShippingOption { + /// + /// Shipping method identifier + /// + public int ShippingMethodId { get; set; } + /// /// Gets or sets the system name of shipping rate computation method /// diff --git a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs index 3757dcb42d..1013a7bae5 100644 --- a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Plugins; @@ -13,10 +14,10 @@ public partial interface IPaymentService /// /// Load active payment methods /// - /// Filter payment methods by customer; null to load all records - /// Load records allows only in specified store; pass 0 to load all records + /// Filter payment methods by customer and apply payment method restrictions; null to load all records + /// Filter payment methods by store identifier; pass 0 to load all records /// Payment methods - IEnumerable> LoadActivePaymentMethods(int? filterByCustomerId = null, int storeId = 0); + IEnumerable> LoadActivePaymentMethods(Customer customer = null, int storeId = 0); /// /// Determines whether a payment method is active\enabled for a shop @@ -39,24 +40,35 @@ public partial interface IPaymentService /// - /// Gets a payment method by system name + /// Gets all payment method extra data + /// + /// List of payment method objects + IList GetAllPaymentMethods(); + + /// + /// Gets payment method extra data by system name /// /// Provider system name /// Payment method entity PaymentMethod GetPaymentMethodBySystemName(string systemName); /// - /// Insert a payment method + /// Insert payment method extra data /// /// Payment method void InsertPaymentMethod(PaymentMethod paymentMethod); /// - /// Updates a payment method + /// Updates payment method extra data /// /// Payment method void UpdatePaymentMethod(PaymentMethod paymentMethod); + /// + /// Delete payment method extra data + /// + /// Payment method + void DeletePaymentMethod(PaymentMethod paymentMethod); /// diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index ea0d560fce..bae549304a 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -1,11 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Core.Caching; using SmartStore.Core.Data; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Events; using SmartStore.Core.Plugins; +using SmartStore.Services.Common; using SmartStore.Services.Configuration; using SmartStore.Services.Localization; @@ -16,6 +20,12 @@ namespace SmartStore.Services.Payments /// public partial class PaymentService : IPaymentService { + #region Constants + + private const string PAYMENTMETHOD_ALL_KEY = "SmartStore.paymentmethod.all"; + + #endregion + #region Fields private readonly IRepository _paymentMethodRepository; @@ -26,6 +36,7 @@ public partial class PaymentService : IPaymentService private readonly ILocalizationService _localizationService; private readonly IProviderManager _providerManager; private readonly IEventPublisher _eventPublisher; + private readonly ICacheManager _cacheManager; #endregion @@ -46,7 +57,8 @@ public PaymentService( ISettingService settingService, ILocalizationService localizationService, IProviderManager providerManager, - IEventPublisher eventPublisher) + IEventPublisher eventPublisher, + ICacheManager cacheManager) { this._paymentMethodRepository = paymentMethodRepository; this._paymentSettings = paymentSettings; @@ -56,32 +68,83 @@ public PaymentService( this._localizationService = localizationService; this._providerManager = providerManager; this._eventPublisher = eventPublisher; + this._cacheManager = cacheManager; } #endregion - #region Methods + #region Methods - /// + /// /// Load active payment methods /// - /// Filter payment methods by customer; null to load all records - /// Load records allows only in specified store; pass 0 to load all records + /// Filter payment methods by customer and apply payment method restrictions; null to load all records + /// Filter payment methods by store identifier; pass 0 to load all records /// Payment methods - public virtual IEnumerable> LoadActivePaymentMethods(int? filterByCustomerId = null, int storeId = 0) + public virtual IEnumerable> LoadActivePaymentMethods(Customer customer = null, int storeId = 0) { - var allMethods = LoadAllPaymentMethods(storeId); - var activeMethods = allMethods - .Where(p => p.Value.IsActive && _paymentSettings.ActivePaymentMethodSystemNames.Contains(p.Metadata.SystemName, StringComparer.InvariantCultureIgnoreCase)); + List customerRoleIds = null; + int? selectedShippingMethodId = null; - if (!activeMethods.Any()) + var allProviders = LoadAllPaymentMethods(storeId); + + var activeProviders = allProviders + .Where(p => + { + if (!p.Value.IsActive || !_paymentSettings.ActivePaymentMethodSystemNames.Contains(p.Metadata.SystemName, StringComparer.InvariantCultureIgnoreCase)) + return false; + + if (customer != null) + { + var method = GetPaymentMethodBySystemName(p.Metadata.SystemName); + if (method != null) + { + // method restricted by customer role id? + var excludedRoleIds = method.ExcludedCustomerRoleIds.ToIntArray(); + if (excludedRoleIds.Any()) + { + if (customerRoleIds == null) + customerRoleIds = customer.CustomerRoles.Where(r => r.Active).Select(r => r.Id).ToList(); + + if (customerRoleIds != null && !customerRoleIds.Except(excludedRoleIds).Any()) + return false; + } + + // method restricted by selected shipping method? + var excludedShippingMethodIds = method.ExcludedShippingMethodIds.ToIntArray(); + if (excludedShippingMethodIds.Any()) + { + if (!selectedShippingMethodId.HasValue) + { + var selectedShipping = customer.GetAttribute(SystemCustomerAttributeNames.SelectedShippingOption, storeId); + selectedShippingMethodId = (selectedShipping == null ? 0 : selectedShipping.ShippingMethodId); + } + + if ((selectedShippingMethodId ?? 0) != 0 && excludedShippingMethodIds.Contains(selectedShippingMethodId.Value)) + return false; + } + + // method restricted by country of selected billing address? + var excludedCountryIds = method.ExcludedCountryIds.ToIntArray(); + if (excludedCountryIds.Any() && customer.BillingAddress != null && (customer.BillingAddress.CountryId ?? 0) != 0) + { + if (excludedCountryIds.Contains(customer.BillingAddress.CountryId.Value)) + return false; + } + } + } + return true; + }); + + if (!activeProviders.Any()) { - var fallbackMethod = allMethods.FirstOrDefault(); + var fallbackMethod = allProviders.FirstOrDefault(); if (fallbackMethod != null) { _paymentSettings.ActivePaymentMethodSystemNames.Clear(); _paymentSettings.ActivePaymentMethodSystemNames.Add(fallbackMethod.Metadata.SystemName); _settingService.SaveSetting(_paymentSettings); + return new Provider[] { fallbackMethod }; } else @@ -91,7 +154,7 @@ public virtual IEnumerable> LoadActivePaymentMethods(in } } - return activeMethods; + return activeProviders; } /// @@ -130,7 +193,21 @@ public virtual IEnumerable> LoadAllPaymentMethods(int s /// - /// Gets a payment method by system name + /// Gets all payment method extra data + /// + /// List of payment method objects + public virtual IList GetAllPaymentMethods() + { + var paymentMethods = _cacheManager.Get(PAYMENTMETHOD_ALL_KEY, () => + { + return _paymentMethodRepository.Table.ToList(); + }); + + return paymentMethods; + } + + /// + /// Gets payment method extra data by system name /// /// Provider system name /// Payment method entity @@ -138,13 +215,15 @@ public virtual PaymentMethod GetPaymentMethodBySystemName(string systemName) { if (systemName.HasValue()) { - return _paymentMethodRepository.Table.FirstOrDefault(x => x.PaymentMethodSystemName == systemName); + var allPaymentMethods = GetAllPaymentMethods(); + + return allPaymentMethods.FirstOrDefault(x => x.PaymentMethodSystemName.IsCaseInsensitiveEqual(systemName)); } return null; } /// - /// Insert a payment method + /// Insert payment method extra data /// /// Payment method public virtual void InsertPaymentMethod(PaymentMethod paymentMethod) @@ -154,11 +233,13 @@ public virtual void InsertPaymentMethod(PaymentMethod paymentMethod) _paymentMethodRepository.Insert(paymentMethod); + _cacheManager.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + _eventPublisher.EntityInserted(paymentMethod); } /// - /// Updates a payment method + /// Updates payment method extra data /// /// Payment method public virtual void UpdatePaymentMethod(PaymentMethod paymentMethod) @@ -168,9 +249,27 @@ public virtual void UpdatePaymentMethod(PaymentMethod paymentMethod) _paymentMethodRepository.Update(paymentMethod); + _cacheManager.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + _eventPublisher.EntityUpdated(paymentMethod); } + /// + /// Delete payment method extra data + /// + /// Payment method + public virtual void DeletePaymentMethod(PaymentMethod paymentMethod) + { + if (paymentMethod == null) + throw new ArgumentNullException("paymentMethod"); + + _paymentMethodRepository.Delete(paymentMethod); + + _cacheManager.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + + _eventPublisher.EntityDeleted(paymentMethod); + } + /// /// Pre process a payment diff --git a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs index a4eb6d3def..1f4113e071 100644 --- a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs +++ b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs @@ -200,6 +200,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get } var shippingOption = new ShippingOption(); + shippingOption.ShippingMethodId = shippingMethod.Id; shippingOption.Name = shippingMethod.Name; shippingOption.Description = shippingMethod.Description; shippingOption.Rate = rate.Value; diff --git a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs index fc73a0c460..1f273a0a45 100644 --- a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs +++ b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs @@ -60,6 +60,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get foreach (var shippingMethod in shippingMethods) { var shippingOption = new ShippingOption(); + shippingOption.ShippingMethodId = shippingMethod.Id; shippingOption.Name = shippingMethod.GetLocalized(x => x.Name); shippingOption.Description = shippingMethod.GetLocalized(x => x.Description); shippingOption.Rate = GetRate(shippingMethod.Id); diff --git a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs index 48d3ef8851..2b59cf5ff7 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs @@ -150,6 +150,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get if (rate.HasValue) { var shippingOption = new ShippingOption(); + shippingOption.ShippingMethodId = shippingMethod.Id; shippingOption.Name = shippingMethod.GetLocalized(x => x.Name); if (record != null && record.SmallQuantityThreshold > subTotal) diff --git a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs index 8b1e37d65e..e2e5bfd066 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs @@ -205,6 +205,7 @@ protected CheckoutShippingMethodModel PrepareShippingMethodModel(IList decimal.Zero) { model.DisplayRewardPoints = true; @@ -277,8 +279,10 @@ protected CheckoutPaymentMethodModel PreparePaymentMethodModel(IList pm.Value.PaymentMethodType == PaymentMethodType.Standard || pm.Value.PaymentMethodType == PaymentMethodType.Redirection || + .LoadActivePaymentMethods(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id) + .Where(pm => + pm.Value.PaymentMethodType == PaymentMethodType.Standard || + pm.Value.PaymentMethodType == PaymentMethodType.Redirection || pm.Value.PaymentMethodType == PaymentMethodType.StandardAndRedirection) .ToList(); @@ -619,9 +623,11 @@ public ActionResult SelectShippingMethod(string shippingoption) //parse selected method if (String.IsNullOrEmpty(shippingoption)) return ShippingMethod(); - var splittedOption = shippingoption.Split(new string[] { "___" }, StringSplitOptions.RemoveEmptyEntries); + + var splittedOption = shippingoption.Split(new string[] { "___" }, StringSplitOptions.RemoveEmptyEntries); if (splittedOption.Length != 2) return ShippingMethod(); + string selectedName = splittedOption[0]; string shippingRateComputationMethodSystemName = splittedOption[1]; @@ -643,8 +649,8 @@ public ActionResult SelectShippingMethod(string shippingoption) .ToList(); } - var shippingOption = shippingOptions - .Find(so => !String.IsNullOrEmpty(so.Name) && so.Name.Equals(selectedName, StringComparison.InvariantCultureIgnoreCase)); + var shippingOption = shippingOptions.Find(so => !String.IsNullOrEmpty(so.Name) && so.Name.Equals(selectedName, StringComparison.InvariantCultureIgnoreCase)); + if (shippingOption == null) return ShippingMethod(); diff --git a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs index 9229462276..c2385539c6 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs @@ -546,8 +546,10 @@ private void PrepareButtonPaymentMethodModel(ButtonPaymentMethodModel model, ILi model.Items.Clear(); var boundPaymentMethods = _paymentService - .LoadActivePaymentMethods(_workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id) - .Where(pm => pm.Value.PaymentMethodType == PaymentMethodType.Button || pm.Value.PaymentMethodType == PaymentMethodType.StandardAndButton) + .LoadActivePaymentMethods(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id) + .Where(pm => + pm.Value.PaymentMethodType == PaymentMethodType.Button || + pm.Value.PaymentMethodType == PaymentMethodType.StandardAndButton) .ToList(); foreach (var pm in boundPaymentMethods) @@ -560,7 +562,7 @@ private void PrepareButtonPaymentMethodModel(ButtonPaymentMethodModel model, ILi RouteValueDictionary routeValues; pm.Value.GetPaymentInfoRoute(out actionName, out controllerName, out routeValues); - model.Items.Add(new ButtonPaymentMethodModel.ButtonPaymentMethodItem() + model.Items.Add(new ButtonPaymentMethodModel.ButtonPaymentMethodItem { ActionName = actionName, ControllerName = controllerName, @@ -1845,6 +1847,7 @@ public ActionResult GetEstimateShipping(EstimateShippingModel shippingModel, For { var soModel = new EstimateShippingModel.ShippingOptionModel() { + ShippingMethodId = shippingOption.ShippingMethodId, Name = shippingOption.Name, Description = shippingOption.Description, diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingMethodModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingMethodModel.cs index bb81c51809..ab1ab0f69a 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingMethodModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingMethodModel.cs @@ -19,6 +19,7 @@ public CheckoutShippingMethodModel() public partial class ShippingMethodModel : ModelBase { + public int ShippingMethodId { get; set; } public string ShippingRateComputationMethodSystemName { get; set; } public string Name { get; set; } public string BrandUrl { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/ShoppingCart/EstimateShippingModel.cs b/src/Presentation/SmartStore.Web/Models/ShoppingCart/EstimateShippingModel.cs index aed18dadf1..c540bf5709 100644 --- a/src/Presentation/SmartStore.Web/Models/ShoppingCart/EstimateShippingModel.cs +++ b/src/Presentation/SmartStore.Web/Models/ShoppingCart/EstimateShippingModel.cs @@ -36,6 +36,8 @@ public EstimateShippingModel() public partial class ShippingOptionModel : ModelBase { + public int ShippingMethodId { get; set; } + public string Name { get; set; } public string Description { get; set; } diff --git a/src/Tests/SmartStore.Core.Tests/ConversionTests.cs b/src/Tests/SmartStore.Core.Tests/ConversionTests.cs index 89d548e348..8899b041ee 100644 --- a/src/Tests/SmartStore.Core.Tests/ConversionTests.cs +++ b/src/Tests/SmartStore.Core.Tests/ConversionTests.cs @@ -32,30 +32,41 @@ public void Can_get_typed_value() r1.ShouldBe(); Assert.AreEqual(r1.Value, 3); - var shippingOption = new ShippingOption { Name = "Name", Description = "Desc", Rate = 1, ShippingRateComputationMethodSystemName = "SystemName" }; + var shippingOption = new ShippingOption + { + ShippingMethodId = 2, + Name = "Name", + Description = "Desc", + Rate = 1, + ShippingRateComputationMethodSystemName = "SystemName" + }; var soStr = shippingOption.Convert(); Assert.IsNotEmpty(soStr); shippingOption = soStr.Convert(); Assert.IsNotNull(shippingOption); + Assert.AreEqual(shippingOption.ShippingMethodId, 2); Assert.AreEqual(shippingOption.Name, "Name"); Assert.AreEqual(shippingOption.Description, "Desc"); Assert.AreEqual(shippingOption.Rate, 1); Assert.AreEqual(shippingOption.ShippingRateComputationMethodSystemName, "SystemName"); - var shippingOptions = new List { - new ShippingOption { Name = "Name1", Description = "Desc1" }, - new ShippingOption { Name = "Name2", Description = "Desc2" } + var shippingOptions = new List + { + new ShippingOption { ShippingMethodId = 1, Name = "Name1", Description = "Desc1" }, + new ShippingOption { ShippingMethodId = 2, Name = "Name2", Description = "Desc2" } }; soStr = shippingOptions.Convert(); Assert.IsNotEmpty(soStr); shippingOptions = soStr.Convert>(); Assert.AreEqual(shippingOptions.Count, 2); + Assert.AreEqual(shippingOptions[1].ShippingMethodId, 2); Assert.AreEqual(shippingOptions[1].Description, "Desc2"); var shippingOptions2 = soStr.Convert>(); Assert.AreEqual(shippingOptions2.Count, 2); + Assert.AreEqual(shippingOptions[1].ShippingMethodId, 2); Assert.AreEqual(shippingOptions2[1].Description, "Desc2"); var enu = SmartStore.Core.Domain.Catalog.AttributeControlType.FileUpload; diff --git a/src/Tests/SmartStore.Core.Tests/Domain/Shipping/ShippingOptionListTypeConverterTests.cs b/src/Tests/SmartStore.Core.Tests/Domain/Shipping/ShippingOptionListTypeConverterTests.cs index c86b955de7..653b851dda 100644 --- a/src/Tests/SmartStore.Core.Tests/Domain/Shipping/ShippingOptionListTypeConverterTests.cs +++ b/src/Tests/SmartStore.Core.Tests/Domain/Shipping/ShippingOptionListTypeConverterTests.cs @@ -28,6 +28,7 @@ public void Can_convert_shippingOptionList_to_string_and_back() var shippingOptionsInput = new List(); shippingOptionsInput.Add(new ShippingOption() { + ShippingMethodId = 1, Name = "a1", Description = "a2", Rate = 3.57M, @@ -35,6 +36,7 @@ public void Can_convert_shippingOptionList_to_string_and_back() }); shippingOptionsInput.Add(new ShippingOption() { + ShippingMethodId = 2, Name = "b1", Description = "b2", Rate = 7.00M, @@ -47,11 +49,13 @@ public void Can_convert_shippingOptionList_to_string_and_back() var shippingOptionsOutput = converter.ConvertFrom(result) as List; shippingOptionsOutput.ShouldNotBeNull(); shippingOptionsOutput.Count.ShouldEqual(2); + shippingOptionsOutput[0].ShippingMethodId.ShouldEqual(1); shippingOptionsOutput[0].Name.ShouldEqual("a1"); shippingOptionsOutput[0].Description.ShouldEqual("a2"); shippingOptionsOutput[0].Rate.ShouldEqual(3.57M); shippingOptionsOutput[0].ShippingRateComputationMethodSystemName.ShouldEqual("a4"); + shippingOptionsOutput[1].ShippingMethodId.ShouldEqual(2); shippingOptionsOutput[1].Name.ShouldEqual("b1"); shippingOptionsOutput[1].Description.ShouldEqual("b2"); shippingOptionsOutput[1].Rate.ShouldEqual(7.00M); diff --git a/src/Tests/SmartStore.Core.Tests/Domain/Shipping/ShippingOptionTypeConverterTests.cs b/src/Tests/SmartStore.Core.Tests/Domain/Shipping/ShippingOptionTypeConverterTests.cs index f51e8981f3..5f40a3b0aa 100644 --- a/src/Tests/SmartStore.Core.Tests/Domain/Shipping/ShippingOptionTypeConverterTests.cs +++ b/src/Tests/SmartStore.Core.Tests/Domain/Shipping/ShippingOptionTypeConverterTests.cs @@ -26,6 +26,7 @@ public void Can_convert_shippingOption_to_string_and_back() { var shippingOptionInput = new ShippingOption() { + ShippingMethodId = 1, Name = "1", Description = "2", Rate = 3.57M, @@ -36,6 +37,7 @@ public void Can_convert_shippingOption_to_string_and_back() var shippingOptionOutput = converter.ConvertFrom(result) as ShippingOption; shippingOptionOutput.ShouldNotBeNull(); + shippingOptionInput.ShippingMethodId.ShouldEqual(1); shippingOptionOutput.Name.ShouldEqual("1"); shippingOptionOutput.Description.ShouldEqual("2"); shippingOptionOutput.Rate.ShouldEqual(3.57M); diff --git a/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs index 329cf092bd..1e5a74de19 100644 --- a/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs @@ -2,6 +2,7 @@ using System.Linq; using NUnit.Framework; using Rhino.Mocks; +using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; @@ -23,6 +24,7 @@ public class PaymentServiceTests : ServiceTest IPaymentService _paymentService; ISettingService _settingService; IEventPublisher _eventPublisher; + ICacheManager _cacheManager; [SetUp] public new void SetUp() @@ -37,12 +39,13 @@ public class PaymentServiceTests : ServiceTest _paymentMethodRepository = MockRepository.GenerateMock>(); _settingService = MockRepository.GenerateMock(); _eventPublisher = MockRepository.GenerateMock(); + _cacheManager = MockRepository.GenerateMock(); var localizationService = MockRepository.GenerateMock(); localizationService.Expect(ls => ls.GetResource(null)).IgnoreArguments().Return("NotSupported").Repeat.Any(); _paymentService = new PaymentService(_paymentMethodRepository, _paymentSettings, pluginFinder, _shoppingCartSettings, - _settingService, localizationService, this.ProviderManager, _eventPublisher); + _settingService, localizationService, this.ProviderManager, _eventPublisher, _cacheManager); } [Test] diff --git a/src/Tests/SmartStore.Services.Tests/Shipping/FixedRateTestShippingRateComputationMethod.cs b/src/Tests/SmartStore.Services.Tests/Shipping/FixedRateTestShippingRateComputationMethod.cs index e42e2ac094..5848b454e5 100644 --- a/src/Tests/SmartStore.Services.Tests/Shipping/FixedRateTestShippingRateComputationMethod.cs +++ b/src/Tests/SmartStore.Services.Tests/Shipping/FixedRateTestShippingRateComputationMethod.cs @@ -28,12 +28,14 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get var response = new GetShippingOptionResponse(); response.ShippingOptions.Add(new ShippingOption() { + ShippingMethodId = 1, Name = "Shipping option 1", Description = "", Rate = GetRate() }); response.ShippingOptions.Add(new ShippingOption() { + ShippingMethodId = 2, Name = "Shipping option 2", Description = "", Rate = GetRate() From 68bc18da22e6ce28ee7b3f7d17c18b1f904297c3 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 16 Jun 2015 16:32:49 +0200 Subject: [PATCH 0004/1074] Added a country exclusion context type (billing versus shipping address) --- .../Payments/CountryExclusionContextType.cs | 9 ++ .../Domain/Payments/PaymentMethod.cs | 22 +++ .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../Mapping/Payments/PaymentMethodMap.cs | 2 + ...130926062_PaymentShippingRestrictions.resx | 126 ------------------ ...5_PaymentShippingRestrictions.Designer.cs} | 2 +- ...6161226375_PaymentShippingRestrictions.cs} | 37 +++-- ...161226375_PaymentShippingRestrictions.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../Payments/PaymentService.cs | 10 +- .../Administration/Content/admin.less | 44 +++--- .../Controllers/PaymentController.cs | 12 +- .../Models/Payments/PaymentMethodEditModel.cs | 5 +- .../Administration/Views/Payment/Edit.cshtml | 19 ++- 14 files changed, 257 insertions(+), 168 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/Payments/CountryExclusionContextType.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.resx rename src/Libraries/SmartStore.Data/Migrations/{201506130926062_PaymentShippingRestrictions.Designer.cs => 201506161226375_PaymentShippingRestrictions.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201506130926062_PaymentShippingRestrictions.cs => 201506161226375_PaymentShippingRestrictions.cs} (56%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.resx diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/CountryExclusionContextType.cs b/src/Libraries/SmartStore.Core/Domain/Payments/CountryExclusionContextType.cs new file mode 100644 index 0000000000..d629d01a36 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Payments/CountryExclusionContextType.cs @@ -0,0 +1,9 @@ + +namespace SmartStore.Core.Domain.Payments +{ + public enum CountryExclusionContextType + { + BillingAddress = 0, + ShippingAddress + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs index e85e14bf9d..8be069bc96 100644 --- a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs +++ b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs @@ -31,5 +31,27 @@ public partial class PaymentMethod : BaseEntity /// [DataMember] public string ExcludedShippingMethodIds { get; set; } + + /// + /// Gets or sets the context identifier for country exclusion + /// + [DataMember] + public int CountryExclusionContextId { get; set; } + + /// + /// Gets or sets the country exclusion context + /// + [DataMember] + public CountryExclusionContextType CountryExclusionContext + { + get + { + return (CountryExclusionContextType)this.CountryExclusionContextId; + } + set + { + this.CountryExclusionContextId = (int)value; + } + } } } diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index d9418948fb..d389e35e66 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -157,6 +157,7 @@ + diff --git a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs index 3544292bef..86073bffc7 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs @@ -15,6 +15,8 @@ public PaymentMethodMap() this.Property(x => x.ExcludedCustomerRoleIds).IsMaxLength(); this.Property(x => x.ExcludedCountryIds).IsMaxLength(); this.Property(x => x.ExcludedShippingMethodIds).IsMaxLength(); + + this.Ignore(x => x.CountryExclusionContext); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.resx deleted file mode 100644 index 621557bdf4..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.Designer.cs index 1432d4c15b..eec91358a2 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class PaymentShippingRestrictions : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201506130926062_PaymentShippingRestrictions"; } + get { return "201506161226375_PaymentShippingRestrictions"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.cs similarity index 56% rename from src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs rename to src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.cs index 175f4ea9ce..ac1308c4c6 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506130926062_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.cs @@ -8,18 +8,19 @@ public partial class PaymentShippingRestrictions : DbMigration, ILocaleResources { public override void Up() { - CreateTable( - "dbo.PaymentMethod", - c => new - { - Id = c.Int(nullable: false, identity: true), - PaymentMethodSystemName = c.String(nullable: false, maxLength: 4000), - ExcludedCustomerRoleIds = c.String(), - ExcludedCountryIds = c.String(), - ExcludedShippingMethodIds = c.String(), - }) - .PrimaryKey(t => t.Id) - .Index(t => t.PaymentMethodSystemName); + CreateTable( + "dbo.PaymentMethod", + c => new + { + Id = c.Int(nullable: false, identity: true), + PaymentMethodSystemName = c.String(nullable: false, maxLength: 4000), + ExcludedCustomerRoleIds = c.String(), + ExcludedCountryIds = c.String(), + ExcludedShippingMethodIds = c.String(), + CountryExclusionContextId = c.Int(nullable: false), + }) + .PrimaryKey(t => t.Id) + .Index(t => t.PaymentMethodSystemName); } public override void Down() @@ -43,9 +44,21 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Restrictions", "Einschrnkungen"); + builder.AddOrUpdate("Admin.Common.AppliedTo", + "applied to", + "bezogen auf"); + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", "Select customer roles, shipping methods and countries for which you do not want to offer this payment method.", "Whlen Sie Kundengruppen, Versandarten und Lnder, bei denen sie diese Zahlungsmethode nicht anbieten mchten."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.CountryExclusionContextType.BillingAddress", + "Billing address", + "Rechnungsadresse"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.CountryExclusionContextType.ShippingAddress", + "Shipping address", + "Versandadresse"); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.resx new file mode 100644 index 0000000000..2761a39c37 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 103589f9cc..c6eeba74f5 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -273,9 +273,9 @@ 201505272236124_V222.cs - - - 201506130926062_PaymentShippingRestrictions.cs + + + 201506161226375_PaymentShippingRestrictions.cs @@ -534,8 +534,8 @@ 201505272236124_V222.cs - - 201506130926062_PaymentShippingRestrictions.cs + + 201506161226375_PaymentShippingRestrictions.cs diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index bae549304a..f2e02400f5 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -126,9 +126,15 @@ public virtual IEnumerable> LoadActivePaymentMethods(Cu // method restricted by country of selected billing address? var excludedCountryIds = method.ExcludedCountryIds.ToIntArray(); - if (excludedCountryIds.Any() && customer.BillingAddress != null && (customer.BillingAddress.CountryId ?? 0) != 0) + if (excludedCountryIds.Any()) { - if (excludedCountryIds.Contains(customer.BillingAddress.CountryId.Value)) + int countryId = 0; + if (method.CountryExclusionContext == CountryExclusionContextType.ShippingAddress) + countryId = (customer.ShippingAddress != null ? (customer.ShippingAddress.CountryId ?? 0) : 0); + else + countryId = (customer.BillingAddress != null ? (customer.BillingAddress.CountryId ?? 0) : 0); + + if (countryId != 0 && excludedCountryIds.Contains(countryId)) return false; } } diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index 20f7c1f835..0828ff57e8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -1199,25 +1199,39 @@ table.payment-method-features td { /* payment methods restrictions -------------------------------------------------------------- */ -.payment-restrictions th label { - margin: 0; -} -.payment-restrictions .column-customerroles, -.payment-restrictions .column-shippingmethods { - width: 18%; -} -.payment-restrictions .column-countries { - width: 64%; - - > div { - display: table-row; +.payment-restrictions { + th label { + margin: 0 10px 0 0; + display: inline-block; } - .country-countainer { - display: table-cell; - width: 25%; + th > div { + display: inline-block; padding-right: 10px; } + + .normal-font { + font-weight: normal; + } + + .column-customerroles, + .column-shippingmethods { + width: 18%; + } + + .column-countries { + width: 64%; + + > div { + display: table-row; + } + + .country-countainer { + display: table-cell; + width: 25%; + padding-right: 10px; + } + } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs index 2f725737b7..df69321ffa 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs @@ -71,7 +71,7 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment model.AvailableCustomerRoles = new List(); model.AvailableShippingMethods = new List(); - model.AvaliableCountries = new List(); + model.AvailableCountries = new List(); foreach (var role in customerRoles.OrderBy(x => x.Name)) { @@ -85,11 +85,13 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment foreach (var country in countries.OrderBy(x => x.Name)) { - model.AvaliableCountries.Add(new SelectListItem { Text = country.GetLocalized(x => x.Name), Value = country.Id.ToString() }); + model.AvailableCountries.Add(new SelectListItem { Text = country.GetLocalized(x => x.Name), Value = country.Id.ToString() }); } if (paymentMethod != null) { + model.CountryExclusionContext = paymentMethod.CountryExclusionContext; + foreach (var id in paymentMethod.ExcludedCustomerRoleIds.SplitSafe(",")) { if ((item = model.AvailableCustomerRoles.FirstOrDefault(x => x.Value == id)) != null) @@ -104,7 +106,7 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment foreach (var id in paymentMethod.ExcludedCountryIds.SplitSafe(",")) { - if ((item = model.AvaliableCountries.FirstOrDefault(x => x.Value == id)) != null) + if ((item = model.AvailableCountries.FirstOrDefault(x => x.Value == id)) != null) item.Selected = true; } } @@ -184,7 +186,7 @@ public ActionResult Edit(string systemName) } [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] - public ActionResult Edit(string systemName, bool continueEditing, ProviderModel model) + public ActionResult Edit(string systemName, bool continueEditing, PaymentMethodEditModel model) { if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) return AccessDeniedView(); @@ -226,6 +228,8 @@ public ActionResult Edit(string systemName, bool continueEditing, ProviderModel paymentMethod.ExcludedShippingMethodIds = string.Join(",", shippingMethodIds); paymentMethod.ExcludedCountryIds = string.Join(",", countryIds); + paymentMethod.CountryExclusionContext = model.CountryExclusionContext; + if (paymentMethod.Id == 0) _paymentService.InsertPaymentMethod(paymentMethod); else diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs index e2f2f40437..180d7c756b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Web.Mvc; +using SmartStore.Core.Domain.Payments; using SmartStore.Web.Framework.Mvc; namespace SmartStore.Admin.Models.Payments @@ -8,6 +9,8 @@ public class PaymentMethodEditModel : ProviderModel { public List AvailableCustomerRoles { get; set; } public List AvailableShippingMethods { get; set; } - public List AvaliableCountries { get; set; } + public List AvailableCountries { get; set; } + + public CountryExclusionContextType CountryExclusionContext { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml index df02bbbd14..61283a2345 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml @@ -1,4 +1,6 @@ -@model PaymentMethodEditModel +@using SmartStore.Core.Domain.Payments; + +@model PaymentMethodEditModel @{ ViewBag.Title = T("Common.Edit").Text + " - " + Model.FriendlyName; @@ -115,6 +117,19 @@ @T("Admin.Configuration.Countries")
+
+ @T("Admin.Common.AppliedTo") +
+
+ + +
@@ -132,7 +147,7 @@ - @foreach (var grp in Model.AvaliableCountries.Select((x, i) => new { Key = i / 4, Value = x }).GroupBy(x => x.Key, x => x.Value)) + @foreach (var grp in Model.AvailableCountries.Select((x, i) => new { Key = i / 4, Value = x }).GroupBy(x => x.Key, x => x.Value)) {
@foreach (var item in grp) From 65a1e3ebf4bfdadd4acc60d7b0bc3529fbd5d6bb Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 17 Jun 2015 14:51:42 +0200 Subject: [PATCH 0005/1074] Resolves #141 Shipping methods by customer roles --- .../Domain/Shipping/ShippingMethod.cs | 6 + .../Mapping/Shipping/ShippingMethodMap.cs | 2 + ...161226375_PaymentShippingRestrictions.resx | 126 ----------- ...7_PaymentShippingRestrictions.Designer.cs} | 2 +- ...6170941137_PaymentShippingRestrictions.cs} | 31 +-- ...170941137_PaymentShippingRestrictions.resx | 126 +++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../Shipping/IShippingService.cs | 4 +- .../Shipping/ShippingService.cs | 66 ++++-- .../SmartStore.Shipping/Description.txt | 2 +- .../Providers/ByTotalProvider.cs | 2 +- .../Providers/FixedRateProvider.cs | 12 +- .../ByWeightShippingComputationMethod.cs | 2 +- .../Description.txt | 2 +- .../Administration/Content/admin.less | 6 +- .../Controllers/ShippingController.cs | 46 +++- .../Models/Shipping/ShippingMethodModel.cs | 4 +- .../Administration/Views/Payment/Edit.cshtml | 14 +- .../Views/Shipping/Methods.cshtml | 15 +- .../Shipping/_CreateOrUpdateMethod.cshtml | 204 ++++++++++++------ .../Controllers/CheckoutController.cs | 13 +- 21 files changed, 425 insertions(+), 270 deletions(-) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.resx rename src/Libraries/SmartStore.Data/Migrations/{201506161226375_PaymentShippingRestrictions.Designer.cs => 201506170941137_PaymentShippingRestrictions.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201506161226375_PaymentShippingRestrictions.cs => 201506170941137_PaymentShippingRestrictions.cs} (60%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.resx diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs index 527dbbb655..9651718a85 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs @@ -34,6 +34,12 @@ public partial class ShippingMethod : BaseEntity, ILocalizedEntity [DataMember] public bool IgnoreCharges { get; set; } + /// + /// Gets or sets identifiers of customer roles (comma separated) to be excluded in checkout + /// + [DataMember] + public string ExcludedCustomerRoleIds { get; set; } + /// /// Gets or sets the restricted countries /// diff --git a/src/Libraries/SmartStore.Data/Mapping/Shipping/ShippingMethodMap.cs b/src/Libraries/SmartStore.Data/Mapping/Shipping/ShippingMethodMap.cs index dc37957d85..947070d588 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Shipping/ShippingMethodMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Shipping/ShippingMethodMap.cs @@ -9,7 +9,9 @@ public ShippingMethodMap() { this.ToTable("ShippingMethod"); this.HasKey(sm => sm.Id); + this.Property(sm => sm.Name).IsRequired().HasMaxLength(400); + this.Property(sm => sm.ExcludedCustomerRoleIds).IsMaxLength(); this.HasMany(sm => sm.RestrictedCountries) .WithMany(c => c.RestrictedShippingMethods) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.resx deleted file mode 100644 index 2761a39c37..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.Designer.cs index eec91358a2..2093e737e1 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class PaymentShippingRestrictions : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201506161226375_PaymentShippingRestrictions"; } + get { return "201506170941137_PaymentShippingRestrictions"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.cs similarity index 60% rename from src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.cs rename to src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.cs index ac1308c4c6..c9398dc915 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506161226375_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.cs @@ -8,23 +8,26 @@ public partial class PaymentShippingRestrictions : DbMigration, ILocaleResources { public override void Up() { - CreateTable( - "dbo.PaymentMethod", - c => new - { - Id = c.Int(nullable: false, identity: true), - PaymentMethodSystemName = c.String(nullable: false, maxLength: 4000), - ExcludedCustomerRoleIds = c.String(), - ExcludedCountryIds = c.String(), - ExcludedShippingMethodIds = c.String(), - CountryExclusionContextId = c.Int(nullable: false), - }) - .PrimaryKey(t => t.Id) + CreateTable( + "dbo.PaymentMethod", + c => new + { + Id = c.Int(nullable: false, identity: true), + PaymentMethodSystemName = c.String(nullable: false, maxLength: 4000), + ExcludedCustomerRoleIds = c.String(), + ExcludedCountryIds = c.String(), + ExcludedShippingMethodIds = c.String(), + CountryExclusionContextId = c.Int(nullable: false), + }) + .PrimaryKey(t => t.Id) .Index(t => t.PaymentMethodSystemName); + + AddColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds", c => c.String()); } public override void Down() { + DropColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds"); DropTable("dbo.PaymentMethod"); } @@ -59,6 +62,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.CountryExclusionContextType.ShippingAddress", "Shipping address", "Versandadresse"); + + builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.RestrictionNote", + "Select customer roles for which you do not want to offer this shipping method.", + "Whlen Sie Kundengruppen, bei denen sie diese Versandart nicht anbieten mchten."); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.resx new file mode 100644 index 0000000000..f332ef3c76 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index c6eeba74f5..e82f356741 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -273,9 +273,9 @@ 201505272236124_V222.cs - - - 201506161226375_PaymentShippingRestrictions.cs + + + 201506170941137_PaymentShippingRestrictions.cs @@ -534,8 +534,8 @@ 201505272236124_V222.cs - - 201506161226375_PaymentShippingRestrictions.cs + + 201506170941137_PaymentShippingRestrictions.cs diff --git a/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs index a8fccc065b..501c236c22 100644 --- a/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Plugins; @@ -53,8 +54,9 @@ public partial interface IShippingService /// Gets all shipping methods /// /// The country indentifier to filter by + /// Filter methods by roles of a customer /// Shipping method collection - IList GetAllShippingMethods(int? filterByCountryId = null); + IList GetAllShippingMethods(int? filterByCountryId = null, Customer customer = null); /// /// Inserts a shipping method diff --git a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs index 2b834b4194..857aabdc54 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs @@ -103,6 +103,7 @@ public ShippingService(ICacheManager cacheManager, public virtual IEnumerable> LoadActiveShippingRateComputationMethods(int storeId = 0) { var allMethods = LoadAllShippingRateComputationMethods(storeId); + var activeMethods = allMethods .Where(p => p.Value.IsActive && _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Contains(p.Metadata.SystemName, StringComparer.InvariantCultureIgnoreCase)); @@ -114,6 +115,7 @@ public virtual IEnumerable> LoadActiveS _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Clear(); _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Add(fallbackMethod.Metadata.SystemName); _settingService.SaveSetting(_shippingSettings); + return new Provider[] { fallbackMethod }; } else @@ -182,32 +184,57 @@ public virtual ShippingMethod GetShippingMethodById(int shippingMethodId) /// Gets all shipping methods /// /// The country indentifier to filter by + /// Filter methods by roles of a customer /// Shipping method collection - public virtual IList GetAllShippingMethods(int? filterByCountryId = null) + public virtual IList GetAllShippingMethods(int? filterByCountryId = null, Customer customer = null) { + IQueryable query = null; + if (filterByCountryId.HasValue && filterByCountryId.Value > 0) { - var query1 = from sm in _shippingMethodRepository.Table - where - sm.RestrictedCountries.Select(c => c.Id).Contains(filterByCountryId.Value) - select sm.Id; - - var query2 = from sm in _shippingMethodRepository.Table - where !query1.Contains(sm.Id) - orderby sm.DisplayOrder - select sm; - - var shippingMethods = query2.ToList(); - return shippingMethods; + var query1 = + from sm in _shippingMethodRepository.Table + where sm.RestrictedCountries.Select(c => c.Id).Contains(filterByCountryId.Value) + select sm.Id; + + query = + from sm in _shippingMethodRepository.Table + where !query1.Contains(sm.Id) + orderby sm.DisplayOrder + select sm; } else { - var query = from sm in _shippingMethodRepository.Table - orderby sm.DisplayOrder - select sm; - var shippingMethods = query.ToList(); - return shippingMethods; + query = + from sm in _shippingMethodRepository.Table + orderby sm.DisplayOrder + select sm; } + + var shippingMethods = query.ToList(); + + if (customer != null) + { + List customerRoleIds = null; + + for (int i = shippingMethods.Count - 1; i >= 0; --i) + { + var method = shippingMethods[i]; + + // method restricted by customer role id? + var excludedRoleIds = method.ExcludedCustomerRoleIds.ToIntArray(); + if (excludedRoleIds.Any()) + { + if (customerRoleIds == null) + customerRoleIds = customer.CustomerRoles.Where(r => r.Active).Select(r => r.Id).ToList(); + + if (customerRoleIds != null && !customerRoleIds.Except(excludedRoleIds).Any()) + shippingMethods.Remove(method); + } + } + } + + return shippingMethods; } /// @@ -357,7 +384,8 @@ public virtual GetShippingOptionRequest CreateShippingOptionRequest(IListFilter by shipping rate computation method identifier; null to load shipping options of all shipping rate computation methods /// Load records allows only in specified store; pass 0 to load all records /// Shipping options - public virtual GetShippingOptionResponse GetShippingOptions(IList cart, Address shippingAddress, string allowedShippingRateComputationMethodSystemName = "", int storeId = 0) + public virtual GetShippingOptionResponse GetShippingOptions(IList cart, Address shippingAddress, + string allowedShippingRateComputationMethodSystemName = "", int storeId = 0) { if (cart == null) throw new ArgumentNullException("cart"); diff --git a/src/Plugins/SmartStore.Shipping/Description.txt b/src/Plugins/SmartStore.Shipping/Description.txt index e4b70d8120..533761599a 100644 --- a/src/Plugins/SmartStore.Shipping/Description.txt +++ b/src/Plugins/SmartStore.Shipping/Description.txt @@ -2,7 +2,7 @@ Description: Provides shipping methods for fixed rate shipping and computation based on weight. SystemName: SmartStore.Shipping Group: Shipping -Version: 2.2.0 +Version: 2.2.0.1 MinAppVersion: 2.2.0 DisplayOrder: 1 FileName: SmartStore.Shipping.dll diff --git a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs index 1f4113e071..44926d497c 100644 --- a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs +++ b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs @@ -187,7 +187,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get decimal sqThreshold = _shippingByTotalSettings.SmallQuantityThreshold; decimal sqSurcharge = _shippingByTotalSettings.SmallQuantitySurcharge; - var shippingMethods = _shippingService.GetAllShippingMethods(countryId); + var shippingMethods = _shippingService.GetAllShippingMethods(countryId, getShippingOptionRequest.Customer); foreach (var shippingMethod in shippingMethods) { decimal? rate = GetRate(subTotal, shippingMethod.Id, storeId, countryId, stateProvinceId, zip); diff --git a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs index 1f273a0a45..673f3b5c85 100644 --- a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs +++ b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs @@ -55,8 +55,10 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get return response; } - int? restrictByCountryId = (getShippingOptionRequest.ShippingAddress != null && getShippingOptionRequest.ShippingAddress.Country != null) ? (int?)getShippingOptionRequest.ShippingAddress.Country.Id : null; - var shippingMethods = this._shippingService.GetAllShippingMethods(restrictByCountryId); + int? restrictByCountryId = (getShippingOptionRequest.ShippingAddress != null && getShippingOptionRequest.ShippingAddress.Country != null) + ? (int?)getShippingOptionRequest.ShippingAddress.Country.Id : null; + + var shippingMethods = this._shippingService.GetAllShippingMethods(restrictByCountryId, getShippingOptionRequest.Customer); foreach (var shippingMethod in shippingMethods) { var shippingOption = new ShippingOption(); @@ -80,8 +82,10 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get if (getShippingOptionRequest == null) throw new ArgumentNullException("getShippingOptionRequest"); - int? restrictByCountryId = (getShippingOptionRequest.ShippingAddress != null && getShippingOptionRequest.ShippingAddress.Country != null) ? (int?)getShippingOptionRequest.ShippingAddress.Country.Id : null; - var shippingMethods = this._shippingService.GetAllShippingMethods(restrictByCountryId); + int? restrictByCountryId = (getShippingOptionRequest.ShippingAddress != null && getShippingOptionRequest.ShippingAddress.Country != null) + ? (int?)getShippingOptionRequest.ShippingAddress.Country.Id : null; + + var shippingMethods = this._shippingService.GetAllShippingMethods(restrictByCountryId, getShippingOptionRequest.Customer); var rates = new List(); foreach (var shippingMethod in shippingMethods) diff --git a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs index 2b59cf5ff7..9c9d9d69f6 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs @@ -141,7 +141,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get } decimal weight = _shippingService.GetShoppingCartTotalWeight(getShippingOptionRequest.Items); - var shippingMethods = _shippingService.GetAllShippingMethods(countryId); + var shippingMethods = _shippingService.GetAllShippingMethods(countryId, getShippingOptionRequest.Customer); foreach (var shippingMethod in shippingMethods) { var record = _shippingByWeightService.FindRecord(shippingMethod.Id, storeId, countryId, weight); diff --git a/src/Plugins/SmartStore.ShippingByWeight/Description.txt b/src/Plugins/SmartStore.ShippingByWeight/Description.txt index 9dd67c0819..65f72e227d 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/Description.txt +++ b/src/Plugins/SmartStore.ShippingByWeight/Description.txt @@ -1,7 +1,7 @@ FriendlyName: Shipping by weight SystemName: SmartStore.ShippingByWeight Group: Shipping -Version: 2.2.0 +Version: 2.2.0.1 MinAppVersion: 2.2.0 DisplayOrder: 1 FileName: SmartStore.ShippingByWeight.dll diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index 0828ff57e8..7c7a6017d3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -1197,9 +1197,9 @@ table.payment-method-features td { font-size: 12px; } -/* payment methods restrictions +/* payment and shipping restrictions -------------------------------------------------------------- */ -.payment-restrictions { +.restriction-container { th label { margin: 0 10px 0 0; display: inline-block; @@ -1226,7 +1226,7 @@ table.payment-method-features td { display: table-row; } - .country-countainer { + .country-container { display: table-cell; width: 25%; padding-right: 10px; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs index e554dbdf20..996f0af0a5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs @@ -7,6 +7,7 @@ using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Plugins; using SmartStore.Services; +using SmartStore.Services.Customers; using SmartStore.Services.Directory; using SmartStore.Services.Localization; using SmartStore.Services.Security; @@ -31,6 +32,7 @@ public partial class ShippingController : AdminControllerBase private readonly IPluginFinder _pluginFinder; private readonly PluginMediator _pluginMediator; private readonly ICommonServices _commonServices; + private readonly ICustomerService _customerService; #endregion @@ -43,7 +45,8 @@ public ShippingController(IShippingService shippingService, ILanguageService languageService, IPluginFinder pluginFinder, PluginMediator pluginMediator, - ICommonServices commonServices) + ICommonServices commonServices, + ICustomerService customerService) { this._shippingService = shippingService; this._shippingSettings = shippingSettings; @@ -53,6 +56,7 @@ public ShippingController(IShippingService shippingService, this._pluginFinder = pluginFinder; this._pluginMediator = pluginMediator; this._commonServices = commonServices; + this._customerService = customerService; } #endregion  @@ -76,6 +80,38 @@ protected void UpdateLocales(ShippingMethod shippingMethod, ShippingMethodModel } } + private void PrepareShippingMethodModel(ShippingMethodModel model, ShippingMethod shippingMethod) + { + SelectListItem item = null; + var customerRoles = _customerService.GetAllCustomerRoles(true); + + model.AvailableCustomerRoles = new List(); + + foreach (var role in customerRoles.OrderBy(x => x.Name)) + { + model.AvailableCustomerRoles.Add(new SelectListItem { Text = role.Name, Value = role.Id.ToString() }); + } + + if (shippingMethod != null) + { + foreach (var id in shippingMethod.ExcludedCustomerRoleIds.SplitSafe(",")) + { + if ((item = model.AvailableCustomerRoles.FirstOrDefault(x => x.Value == id)) != null) + item.Selected = true; + } + } + } + + private void ApplyRestrictions(ShippingMethod shippingMethod) + { + var customerRoleIds = Request.Form.AllKeys + .Where(x => x.StartsWith("CustomerRole_")) + .Select(x => x.Replace("CustomerRole_", "")) + .ToList(); + + shippingMethod.ExcludedCustomerRoleIds = string.Join(",", customerRoleIds); + } + #endregion #region Shipping rate computation methods @@ -173,6 +209,7 @@ public ActionResult CreateMethod() return AccessDeniedView(); var model = new ShippingMethodModel(); + PrepareShippingMethodModel(model, null); //locales AddLocales(_languageService, model.Locales); @@ -188,6 +225,8 @@ public ActionResult CreateMethod(ShippingMethodModel model, bool continueEditing if (ModelState.IsValid) { var sm = model.ToEntity(); + ApplyRestrictions(sm); + _shippingService.InsertShippingMethod(sm); //locales @@ -209,10 +248,11 @@ public ActionResult EditMethod(int id) var sm = _shippingService.GetShippingMethodById(id); if (sm == null) - //No shipping method found with the specified id return RedirectToAction("Methods"); var model = sm.ToModel(); + PrepareShippingMethodModel(model, sm); + //locales AddLocales(_languageService, model.Locales, (locale, languageId) => { @@ -236,6 +276,8 @@ public ActionResult EditMethod(ShippingMethodModel model, bool continueEditing) if (ModelState.IsValid) { sm = model.ToEntity(sm); + ApplyRestrictions(sm); + _shippingService.UpdateShippingMethod(sm); //locales diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodModel.cs index 134d4af1ea..c9690b4695 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodModel.cs @@ -15,6 +15,7 @@ public ShippingMethodModel() { Locales = new List(); } + [SmartResourceDisplayName("Admin.Configuration.Shipping.Methods.Fields.Name")] [AllowHtml] public string Name { get; set; } @@ -30,6 +31,8 @@ public ShippingMethodModel() public bool IgnoreCharges { get; set; } public IList Locales { get; set; } + + public List AvailableCustomerRoles { get; set; } } public class ShippingMethodLocalizedModel : ILocalizedModelLocal @@ -43,6 +46,5 @@ public class ShippingMethodLocalizedModel : ILocalizedModelLocal [SmartResourceDisplayName("Admin.Configuration.Shipping.Methods.Fields.Description")] [AllowHtml] public string Description { get; set; } - } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml index 61283a2345..51d94abb2e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml @@ -6,7 +6,7 @@ ViewBag.Title = T("Common.Edit").Text + " - " + Model.FriendlyName; } -@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "paymentmethod-form" })) +@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "payment-method-form" })) {
@@ -24,12 +24,12 @@ @Html.HiddenFor(model => model.SystemName) - @Html.SmartStore().TabStrip().Name("paymentmethod-edit").Items(x => + @Html.SmartStore().TabStrip().Name("payment-method-edit").Items(x => { x.Add().Text(T("Admin.Common.General").Text).Content(TabGeneral()).Selected(true); x.Add().Text(T("Admin.Common.Restrictions").Text).Content(TabRestrictions()); - EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "paymentmethod-edit", this.Html, this.Model)); + EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "payment-method-edit", this.Html, this.Model)); }) } @@ -91,7 +91,7 @@ @Html.Raw(T("Admin.Configuration.Payment.Methods.RestrictionNote"))
-
+
} + + + + + + + +
@@ -152,7 +152,7 @@
@foreach (var item in grp) { -
+
@RenderCheckbox(item, "Country_")
} @@ -180,11 +180,11 @@ jQuery(document).ready(function () { // restictions column header checkbox clicked - $('.payment-restrictions th input[type="checkbox"]').change(function () { + $('.restriction-container th input[type="checkbox"]').change(function () { var id = $(this).attr('id').replace('Master', ''), isChecked = $(this).is(':checked'); - $('.payment-restrictions td input[name^="' + id + '"]').attr('checked', isChecked); + $('.restriction-container td input[name^="' + id + '"]').attr('checked', isChecked); }); }); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Methods.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Methods.cshtml index 494932317a..f74ed89677 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Methods.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Methods.cshtml @@ -2,9 +2,9 @@ @using Telerik.Web.Mvc.UI; @using System.Linq; @{ - //page title ViewBag.Title = T("Admin.Configuration.Shipping.Methods").Text; } +
@@ -14,6 +14,7 @@  @T("Admin.Common.AddNew")
+ + +
@@ -25,22 +26,18 @@ }) .Columns(columns => { - columns.Bound(x => x.Name); + columns.Bound(x => x.Name) + .Template(x => Html.ActionLink(x.Name, "EditMethod", new { id = x.Id })) + .ClientTemplate("\"><#= Name #>"); columns.Bound(x => x.Description); columns.Bound(x => x.IgnoreCharges) .Template(item => @Html.SymbolForBool(item.IgnoreCharges)) .ClientTemplate(@Html.SymbolForBool("IgnoreCharges")) - .Width(160) + .Width(250) .Centered(); columns.Bound(x => x.DisplayOrder) .Width(160) .Centered(); - columns.Bound(x => x.Id) - .Template(x => Html.ActionLink(T("Admin.Common.Edit").Text, "EditMethod", new { id = x.Id })) - .ClientTemplate("\">" + T("Admin.Common.Edit").Text + "") - .Width(160) - .Centered() - .HeaderTemplate(T("Admin.Common.Edit").Text); }) .DataBinding(dataBinding => dataBinding.Ajax().Select("Methods", "Shipping")) .EnableCustomBinding(true)) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml index dbd129ab13..9033b3beb7 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml @@ -1,72 +1,140 @@ @model ShippingMethodModel @using Telerik.Web.Mvc.UI; + @Html.ValidationSummary(true) @Html.HiddenFor(model => model.Id) -@(Html.LocalizedEditor("shipping-method-localized", - @ - - - - - - - - - - - -
- @Html.SmartLabelFor(model => model.Locales[item].Name) - - @Html.EditorFor(model => Model.Locales[item].Name) - @Html.ValidationMessageFor(model => model.Locales[item].Name) -
- @Html.SmartLabelFor(model => model.Locales[item].Description) - - @Html.TextAreaFor(model => model.Locales[item].Description) - @Html.ValidationMessageFor(model => model.Locales[item].Description) -
- @Html.HiddenFor(model => model.Locales[item].LanguageId) -
- , - @ - - - - - - - - -
- @Html.SmartLabelFor(model => model.Name) - - @Html.EditorFor(model => model.Name) - @Html.ValidationMessageFor(model => model.Name) -
- @Html.SmartLabelFor(model => model.Description) - - @Html.TextAreaFor(model => model.Description) - @Html.ValidationMessageFor(model => model.Description) -
- )) - - - - - - - - - -
- @Html.SmartLabelFor(model => model.DisplayOrder) - - @Html.EditorFor(model => model.DisplayOrder) - @Html.ValidationMessageFor(model => model.DisplayOrder) -
- @Html.SmartLabelFor(model => model.IgnoreCharges) - - @Html.EditorFor(model => model.IgnoreCharges) - @Html.ValidationMessageFor(model => model.IgnoreCharges) -
+ +@Html.SmartStore().TabStrip().Name("shipping-method-edit").Items(x => +{ + x.Add().Text(T("Admin.Common.General").Text).Content(TabGeneral()).Selected(true); + x.Add().Text(T("Admin.Common.Restrictions").Text).Content(TabRestrictions()); + + EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "shipping-method-edit", this.Html, this.Model)); +}) + +@helper TabGeneral() +{ + @(Html.LocalizedEditor("shipping-method-localized", + @ + + + + + + + + + + + +
+ @Html.SmartLabelFor(model => model.Locales[item].Name) + + @Html.EditorFor(model => Model.Locales[item].Name) + @Html.ValidationMessageFor(model => model.Locales[item].Name) +
+ @Html.SmartLabelFor(model => model.Locales[item].Description) + + @Html.TextAreaFor(model => model.Locales[item].Description) + @Html.ValidationMessageFor(model => model.Locales[item].Description) +
+ @Html.HiddenFor(model => model.Locales[item].LanguageId) +
+ , + @ + + + + + + + + +
+ @Html.SmartLabelFor(model => model.Name) + + @Html.EditorFor(model => model.Name) + @Html.ValidationMessageFor(model => model.Name) +
+ @Html.SmartLabelFor(model => model.Description) + + @Html.TextAreaFor(model => model.Description) + @Html.ValidationMessageFor(model => model.Description) +
+ )) + + + + + + + + + + +
+ @Html.SmartLabelFor(model => model.DisplayOrder) + + @Html.EditorFor(model => model.DisplayOrder) + @Html.ValidationMessageFor(model => model.DisplayOrder) +
+ @Html.SmartLabelFor(model => model.IgnoreCharges) + + @Html.EditorFor(model => model.IgnoreCharges) + @Html.ValidationMessageFor(model => model.IgnoreCharges) +
+} + +@helper TabRestrictions() +{ +
+ @Html.Raw(T("Admin.Configuration.Shipping.Methods.RestrictionNote")) +
+ +
+ + + + + + + +
+
+ +
+
+ @foreach (var item in Model.AvailableCustomerRoles) + { + @RenderCheckbox(item, "CustomerRole_") + } +
+
+} + +@helper RenderCheckbox(SelectListItem item, string prefix) +{ +
+ +
+} + + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs index e2e5bfd066..f155909a21 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Web; using System.Web.Mvc; -using System.Web.Routing; using SmartStore.Core; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; @@ -11,24 +10,22 @@ using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Shipping; -using SmartStore.Core.Plugins; +using SmartStore.Core.Logging; using SmartStore.Services.Catalog; using SmartStore.Services.Common; +using SmartStore.Services.Configuration; using SmartStore.Services.Customers; using SmartStore.Services.Directory; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Orders; using SmartStore.Services.Payments; using SmartStore.Services.Shipping; using SmartStore.Services.Tax; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Plugins; using SmartStore.Web.Framework.Security; using SmartStore.Web.Models.Checkout; using SmartStore.Web.Models.Common; -using SmartStore.Services.Configuration; -using SmartStore.Web.Framework.Plugins; -using SmartStore.Web.Models.ShoppingCart; namespace SmartStore.Web.Controllers { @@ -238,6 +235,7 @@ protected CheckoutShippingMethodModel PrepareShippingMethodModel(IList !String.IsNullOrEmpty(so.Name) && so.Name.Equals(selectedShippingOption.Name, StringComparison.InvariantCultureIgnoreCase) && !String.IsNullOrEmpty(so.ShippingRateComputationMethodSystemName) && so.ShippingRateComputationMethodSystemName.Equals(selectedShippingOption.ShippingRateComputationMethodSystemName, StringComparison.InvariantCultureIgnoreCase)); + if (shippingOptionToSelect != null) shippingOptionToSelect.Selected = true; } @@ -592,8 +590,7 @@ public ActionResult ShippingMethod() { _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.SelectedShippingOption, null, _storeContext.CurrentStore.Id); return RedirectToAction("PaymentMethod"); - } - + } //model var model = PrepareShippingMethodModel(cart); From 99057824e87d3bd3030eebc23198d9ea5bc3ba7f Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 17 Jun 2015 18:08:11 +0200 Subject: [PATCH 0006/1074] A frontend request should not revoke merchant settings (like provider activation). Improved fallback for payment and shipping method. --- .../Payments/IPaymentService.cs | 4 +++- .../Payments/PaymentService.cs | 23 ++++++++++++------- .../Shipping/ShippingService.cs | 16 +++++++++---- .../Controllers/CheckoutController.cs | 8 +++---- .../Controllers/ShoppingCartController.cs | 7 +++--- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs index 1013a7bae5..709c6eafc2 100644 --- a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs @@ -16,8 +16,10 @@ public partial interface IPaymentService /// /// Filter payment methods by customer and apply payment method restrictions; null to load all records /// Filter payment methods by store identifier; pass 0 to load all records + /// Filter payment methods by payment method types + /// Provide a fallback payment method if none is active /// Payment methods - IEnumerable> LoadActivePaymentMethods(Customer customer = null, int storeId = 0); + IEnumerable> LoadActivePaymentMethods(Customer customer = null, int storeId = 0, PaymentMethodType[] types = null, bool provideFallbackMethod = true); /// /// Determines whether a payment method is active\enabled for a shop diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index f2e02400f5..7923546540 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -80,13 +80,20 @@ public PaymentService( /// /// Filter payment methods by customer and apply payment method restrictions; null to load all records /// Filter payment methods by store identifier; pass 0 to load all records + /// Filter payment methods by payment method types + /// Provide a fallback payment method if none is active /// Payment methods - public virtual IEnumerable> LoadActivePaymentMethods(Customer customer = null, int storeId = 0) + public virtual IEnumerable> LoadActivePaymentMethods(Customer customer = null, int storeId = 0, PaymentMethodType[] types = null, + bool provideFallbackMethod = true) { List customerRoleIds = null; int? selectedShippingMethodId = null; + IEnumerable> allProviders = null; - var allProviders = LoadAllPaymentMethods(storeId); + if (types != null && types.Any()) + allProviders = LoadAllPaymentMethods(storeId).Where(x => types.Contains(x.Value.PaymentMethodType)); + else + allProviders = LoadAllPaymentMethods(storeId); var activeProviders = allProviders .Where(p => @@ -142,15 +149,15 @@ public virtual IEnumerable> LoadActivePaymentMethods(Cu return true; }); - if (!activeProviders.Any()) + if (!activeProviders.Any() && provideFallbackMethod) { - var fallbackMethod = allProviders.FirstOrDefault(); + var fallbackMethod = allProviders.FirstOrDefault(x => x.IsPaymentMethodActive(_paymentSettings)); + + if (fallbackMethod == null) + fallbackMethod = allProviders.FirstOrDefault(); + if (fallbackMethod != null) { - _paymentSettings.ActivePaymentMethodSystemNames.Clear(); - _paymentSettings.ActivePaymentMethodSystemNames.Add(fallbackMethod.Metadata.SystemName); - _settingService.SaveSetting(_paymentSettings); - return new Provider[] { fallbackMethod }; } else diff --git a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs index 857aabdc54..d29ce01907 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs @@ -109,18 +109,24 @@ public virtual IEnumerable> LoadActiveS if (!activeMethods.Any()) { - var fallbackMethod = allMethods.FirstOrDefault(); + var fallbackMethod = allMethods.FirstOrDefault(x => x.IsShippingRateComputationMethodActive(_shippingSettings)); + + if (fallbackMethod == null) + fallbackMethod = allMethods.FirstOrDefault(); + if (fallbackMethod != null) { - _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Clear(); - _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Add(fallbackMethod.Metadata.SystemName); - _settingService.SaveSetting(_shippingSettings); + // a frontend request should not revoke merchant settings + //_shippingSettings.ActiveShippingRateComputationMethodSystemNames.Clear(); + //_shippingSettings.ActiveShippingRateComputationMethodSystemNames.Add(fallbackMethod.Metadata.SystemName); + //_settingService.SaveSetting(_shippingSettings); return new Provider[] { fallbackMethod }; } else { - throw Error.Application("At least one shipping method provider is required to be active."); + if (DataSettings.DatabaseIsInstalled()) + throw Error.Application("At least one shipping method provider is required to be active."); } } diff --git a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs index f155909a21..bb52c695f7 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs @@ -276,12 +276,10 @@ protected CheckoutPaymentMethodModel PreparePaymentMethodModel(IList - pm.Value.PaymentMethodType == PaymentMethodType.Standard || - pm.Value.PaymentMethodType == PaymentMethodType.Redirection || - pm.Value.PaymentMethodType == PaymentMethodType.StandardAndRedirection) + .LoadActivePaymentMethods(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id, paymentTypes) .ToList(); foreach (var pm in boundPaymentMethods) diff --git a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs index c2385539c6..e0a06c16c6 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs @@ -545,11 +545,10 @@ private void PrepareButtonPaymentMethodModel(ButtonPaymentMethodModel model, ILi { model.Items.Clear(); + var paymentTypes = new PaymentMethodType[] { PaymentMethodType.Button, PaymentMethodType.StandardAndButton }; + var boundPaymentMethods = _paymentService - .LoadActivePaymentMethods(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id) - .Where(pm => - pm.Value.PaymentMethodType == PaymentMethodType.Button || - pm.Value.PaymentMethodType == PaymentMethodType.StandardAndButton) + .LoadActivePaymentMethods(_workContext.CurrentCustomer, _storeContext.CurrentStore.Id, paymentTypes, false) .ToList(); foreach (var pm in boundPaymentMethods) From 9b80c504202111821169351a633d36f3afe49d0c Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 18 Jun 2015 11:02:47 +0200 Subject: [PATCH 0007/1074] Updated changelog --- changelog.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 3c5e567274..2810999e98 100644 --- a/changelog.md +++ b/changelog.md @@ -1,13 +1,17 @@ # Release Notes -## SmartStore.NET 2.2.2 +## SmartStore.NET 2.5 ### New Features -* #210 Implement multi-store support for import/export -* #141 Payment methods by customer roles +* #141 Payment and shipping methods by customer roles * #67 Restrict payment methods to certain countries * #94 Restrict payment methods to certain shipping methods +## SmartStore.NET 2.2.2 + +### New Features +* #210 Implement multi-store support for import/export + ### Improvements * License checker now supports IDN mapping for domain names From 93629326c72920bbd0053a0ac21f90e7e8c835ed Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 18 Jun 2015 19:15:44 +0200 Subject: [PATCH 0008/1074] Resolves #526 Min\max amount option for which the payment method should be offered during checkout --- changelog.md | 1 + .../Domain/Payments/PaymentMethod.cs | 34 +++++ ...textType.cs => RestrictionContextTypes.cs} | 6 + .../SmartStore.Core/SmartStore.Core.csproj | 2 +- .../Mapping/Payments/PaymentMethodMap.cs | 4 + ...170941137_PaymentShippingRestrictions.resx | 126 ------------------ ...0_PaymentShippingRestrictions.Designer.cs} | 2 +- ...6181501470_PaymentShippingRestrictions.cs} | 37 ++++- ...181501470_PaymentShippingRestrictions.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../Payments/IPaymentService.cs | 8 +- .../Payments/PaymentService.cs | 103 ++++++++++---- .../Shipping/ShippingService.cs | 7 +- .../Controllers/PaymentController.cs | 13 +- .../Models/Payments/PaymentMethodEditModel.cs | 11 ++ .../Administration/Views/Payment/Edit.cshtml | 36 ++++- .../Controllers/CheckoutController.cs | 2 +- .../Controllers/ShoppingCartController.cs | 2 +- .../Payments/PaymentServiceTests.cs | 16 +-- 19 files changed, 359 insertions(+), 187 deletions(-) rename src/Libraries/SmartStore.Core/Domain/Payments/{CountryExclusionContextType.cs => RestrictionContextTypes.cs} (61%) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.resx rename src/Libraries/SmartStore.Data/Migrations/{201506170941137_PaymentShippingRestrictions.Designer.cs => 201506181501470_PaymentShippingRestrictions.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201506170941137_PaymentShippingRestrictions.cs => 201506181501470_PaymentShippingRestrictions.cs} (58%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.resx diff --git a/changelog.md b/changelog.md index 2810999e98..65879024c7 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,7 @@ * #141 Payment and shipping methods by customer roles * #67 Restrict payment methods to certain countries * #94 Restrict payment methods to certain shipping methods +* #526 Min\max amount option for which the payment method should be offered during checkout ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs index 8be069bc96..28fa9f66a0 100644 --- a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs +++ b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs @@ -53,5 +53,39 @@ public CountryExclusionContextType CountryExclusionContext this.CountryExclusionContextId = (int)value; } } + + /// + /// Gets or sets the minimum order amount for which to offer the payment method + /// + [DataMember] + public decimal? MinimumOrderAmount { get; set; } + + /// + /// Gets or sets the maximum order amount for which to offer the payment method + /// + [DataMember] + public decimal? MaximumOrderAmount { get; set; } + + /// + /// Gets or sets the context identifier for amount restriction + /// + [DataMember] + public int AmountRestrictionContextId { get; set; } + + /// + /// Gets or sets the amount restriction context + /// + [DataMember] + public AmountRestrictionContextType AmountRestrictionContext + { + get + { + return (AmountRestrictionContextType)this.AmountRestrictionContextId; + } + set + { + this.AmountRestrictionContextId = (int)value; + } + } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/CountryExclusionContextType.cs b/src/Libraries/SmartStore.Core/Domain/Payments/RestrictionContextTypes.cs similarity index 61% rename from src/Libraries/SmartStore.Core/Domain/Payments/CountryExclusionContextType.cs rename to src/Libraries/SmartStore.Core/Domain/Payments/RestrictionContextTypes.cs index d629d01a36..be4756574b 100644 --- a/src/Libraries/SmartStore.Core/Domain/Payments/CountryExclusionContextType.cs +++ b/src/Libraries/SmartStore.Core/Domain/Payments/RestrictionContextTypes.cs @@ -6,4 +6,10 @@ public enum CountryExclusionContextType BillingAddress = 0, ShippingAddress } + + public enum AmountRestrictionContextType + { + SubtotalAmount = 0, + TotalAmount + } } diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index d389e35e66..4a9d7bc280 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -157,7 +157,7 @@ - + diff --git a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs index 86073bffc7..d222942dad 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs @@ -16,7 +16,11 @@ public PaymentMethodMap() this.Property(x => x.ExcludedCountryIds).IsMaxLength(); this.Property(x => x.ExcludedShippingMethodIds).IsMaxLength(); + this.Property(x => x.MinimumOrderAmount).HasPrecision(18, 4); + this.Property(x => x.MaximumOrderAmount).HasPrecision(18, 4); + this.Ignore(x => x.CountryExclusionContext); + this.Ignore(x => x.AmountRestrictionContext); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.resx deleted file mode 100644 index f332ef3c76..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.Designer.cs index 2093e737e1..97d631de8c 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class PaymentShippingRestrictions : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201506170941137_PaymentShippingRestrictions"; } + get { return "201506181501470_PaymentShippingRestrictions"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.cs similarity index 58% rename from src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.cs rename to src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.cs index c9398dc915..e957c22ff7 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506170941137_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.cs @@ -18,6 +18,9 @@ public override void Up() ExcludedCountryIds = c.String(), ExcludedShippingMethodIds = c.String(), CountryExclusionContextId = c.Int(nullable: false), + MinimumOrderAmount = c.Decimal(precision: 18, scale: 4), + MaximumOrderAmount = c.Decimal(precision: 18, scale: 4), + AmountRestrictionContextId = c.Int(nullable: false), }) .PrimaryKey(t => t.Id) .Index(t => t.PaymentMethodSystemName); @@ -47,13 +50,13 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Restrictions", "Einschrnkungen"); - builder.AddOrUpdate("Admin.Common.AppliedTo", - "applied to", + builder.AddOrUpdate("Admin.Common.RelatedTo", + "related to", "bezogen auf"); builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", "Select customer roles, shipping methods and countries for which you do not want to offer this payment method.", - "Whlen Sie Kundengruppen, Versandarten und Lnder, bei denen sie diese Zahlungsmethode nicht anbieten mchten."); + "Whlen Sie Kundengruppen, Versandarten und Lnder, bei denen Sie diese Zahlungsmethode nicht anbieten mchten."); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.CountryExclusionContextType.BillingAddress", "Billing address", @@ -65,7 +68,33 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.RestrictionNote", "Select customer roles for which you do not want to offer this shipping method.", - "Whlen Sie Kundengruppen, bei denen sie diese Versandart nicht anbieten mchten."); + "Whlen Sie Kundengruppen, bei denen Sie diese Versandart nicht anbieten mchten."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.MinimumOrderAmount", + "Minimum order amount", + "Mindestbestellwert", + "Specifies the minimum order amount from which on the payment method should be offered.", + "Legt den Mindestbestellwert fest, ab dem die Zahlungsmethode angeboten werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.MaximumOrderAmount", + "Maximum amount", + "Maximalbestellwert", + "Specifies the maximum order amount up to which the payment methods should be offered.", + "Legt den maximalen Bestellwert fest, bis zu dem die Zahlungsmethode angeboten werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.AmountRestrictionContext", + "Amount related to", + "Betrag bezieht sich auf", + "Specifies the amount to which the minimum and maximum order amounts are related to.", + "Legt den Betrag fest, auf den sich die Minimal- und Maximalbestellwerte beziehen."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.AmountRestrictionContextType.SubtotalAmount", + "Subtotal", + "Zwischensumme"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.AmountRestrictionContextType.TotalAmount", + "Order total", + "Gesamtsumme"); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.resx new file mode 100644 index 0000000000..4ac037f18e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index e82f356741..cd96c73f3a 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -273,9 +273,9 @@ 201505272236124_V222.cs - - - 201506170941137_PaymentShippingRestrictions.cs + + + 201506181501470_PaymentShippingRestrictions.cs @@ -534,8 +534,8 @@ 201505272236124_V222.cs - - 201506170941137_PaymentShippingRestrictions.cs + + 201506181501470_PaymentShippingRestrictions.cs diff --git a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs index 709c6eafc2..6e45d3d0e2 100644 --- a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs @@ -15,11 +15,17 @@ public partial interface IPaymentService /// Load active payment methods /// /// Filter payment methods by customer and apply payment method restrictions; null to load all records + /// Filter payment methods by cart amount; null to load all records /// Filter payment methods by store identifier; pass 0 to load all records /// Filter payment methods by payment method types /// Provide a fallback payment method if none is active /// Payment methods - IEnumerable> LoadActivePaymentMethods(Customer customer = null, int storeId = 0, PaymentMethodType[] types = null, bool provideFallbackMethod = true); + IEnumerable> LoadActivePaymentMethods( + Customer customer = null, + IList cart = null, + int storeId = 0, + PaymentMethodType[] types = null, + bool provideFallbackMethod = true); /// /// Determines whether a payment method is active\enabled for a shop diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index 7923546540..4e7137c764 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -1,17 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; -using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Events; +using SmartStore.Core.Infrastructure; using SmartStore.Core.Plugins; using SmartStore.Services.Common; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; +using SmartStore.Services.Directory; +using SmartStore.Services.Orders; namespace SmartStore.Services.Payments { @@ -32,11 +33,9 @@ public partial class PaymentService : IPaymentService private readonly PaymentSettings _paymentSettings; private readonly IPluginFinder _pluginFinder; private readonly ShoppingCartSettings _shoppingCartSettings; - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; private readonly IProviderManager _providerManager; - private readonly IEventPublisher _eventPublisher; - private readonly ICacheManager _cacheManager; + private readonly ICurrencyService _currencyService; + private readonly ICommonServices _commonServices; #endregion @@ -54,21 +53,17 @@ public PaymentService( PaymentSettings paymentSettings, IPluginFinder pluginFinder, ShoppingCartSettings shoppingCartSettings, - ISettingService settingService, - ILocalizationService localizationService, IProviderManager providerManager, - IEventPublisher eventPublisher, - ICacheManager cacheManager) + ICurrencyService currencyService, + ICommonServices commonServices) { this._paymentMethodRepository = paymentMethodRepository; this._paymentSettings = paymentSettings; this._pluginFinder = pluginFinder; this._shoppingCartSettings = shoppingCartSettings; - this._settingService = settingService; - this._localizationService = localizationService; this._providerManager = providerManager; - this._eventPublisher = eventPublisher; - this._cacheManager = cacheManager; + this._currencyService = currencyService; + this._commonServices = commonServices; } #endregion @@ -79,15 +74,22 @@ public PaymentService( /// Load active payment methods /// /// Filter payment methods by customer and apply payment method restrictions; null to load all records + /// Filter payment methods by cart amount; null to load all records /// Filter payment methods by store identifier; pass 0 to load all records /// Filter payment methods by payment method types /// Provide a fallback payment method if none is active /// Payment methods - public virtual IEnumerable> LoadActivePaymentMethods(Customer customer = null, int storeId = 0, PaymentMethodType[] types = null, + public virtual IEnumerable> LoadActivePaymentMethods( + Customer customer = null, + IList cart = null, + int storeId = 0, + PaymentMethodType[] types = null, bool provideFallbackMethod = true) { List customerRoleIds = null; int? selectedShippingMethodId = null; + decimal? orderSubTotal = null; + decimal? orderTotal = null; IEnumerable> allProviders = null; if (types != null && types.Any()) @@ -143,7 +145,50 @@ public virtual IEnumerable> LoadActivePaymentMethods(Cu if (countryId != 0 && excludedCountryIds.Contains(countryId)) return false; - } + } + + // method restricted by min\max order amount? + if ((method.MinimumOrderAmount.HasValue || method.MaximumOrderAmount.HasValue) && cart != null) + { + decimal compareAmount = decimal.Zero; + // TODO: resolve circular object dependencies + var orderTotalCalculationService = EngineContext.Current.Resolve(); + + if (method.AmountRestrictionContext == AmountRestrictionContextType.SubtotalAmount) + { + if (!orderSubTotal.HasValue) + { + decimal orderSubTotalDiscountAmountBase = decimal.Zero; + Discount orderSubTotalAppliedDiscount = null; + decimal subTotalWithoutDiscountBase = decimal.Zero; + decimal subTotalWithDiscountBase = decimal.Zero; + + orderTotalCalculationService.GetShoppingCartSubTotal(cart, out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount, + out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); + + orderSubTotal = _currencyService.ConvertFromPrimaryStoreCurrency(subTotalWithoutDiscountBase, _commonServices.WorkContext.WorkingCurrency); + } + + compareAmount = orderSubTotal.Value; + } + else if (method.AmountRestrictionContext == AmountRestrictionContextType.TotalAmount) + { + if (!orderTotal.HasValue) + { + orderTotal = orderTotalCalculationService.GetShoppingCartTotal(cart) ?? decimal.Zero; + + orderTotal = _currencyService.ConvertFromPrimaryStoreCurrency(orderTotal.Value, _commonServices.WorkContext.WorkingCurrency); + } + + compareAmount = orderTotal.Value; + } + + if (method.MinimumOrderAmount.HasValue && compareAmount < method.MinimumOrderAmount.Value) + return false; + + if (method.MaximumOrderAmount.HasValue && compareAmount > method.MaximumOrderAmount.Value) + return false; + } } } return true; @@ -211,7 +256,7 @@ public virtual IEnumerable> LoadAllPaymentMethods(int s /// List of payment method objects public virtual IList GetAllPaymentMethods() { - var paymentMethods = _cacheManager.Get(PAYMENTMETHOD_ALL_KEY, () => + var paymentMethods = _commonServices.Cache.Get(PAYMENTMETHOD_ALL_KEY, () => { return _paymentMethodRepository.Table.ToList(); }); @@ -246,9 +291,9 @@ public virtual void InsertPaymentMethod(PaymentMethod paymentMethod) _paymentMethodRepository.Insert(paymentMethod); - _cacheManager.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + _commonServices.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); - _eventPublisher.EntityInserted(paymentMethod); + _commonServices.EventPublisher.EntityInserted(paymentMethod); } /// @@ -262,9 +307,9 @@ public virtual void UpdatePaymentMethod(PaymentMethod paymentMethod) _paymentMethodRepository.Update(paymentMethod); - _cacheManager.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + _commonServices.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); - _eventPublisher.EntityUpdated(paymentMethod); + _commonServices.EventPublisher.EntityUpdated(paymentMethod); } /// @@ -278,9 +323,9 @@ public virtual void DeletePaymentMethod(PaymentMethod paymentMethod) _paymentMethodRepository.Delete(paymentMethod); - _cacheManager.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + _commonServices.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); - _eventPublisher.EntityDeleted(paymentMethod); + _commonServices.EventPublisher.EntityDeleted(paymentMethod); } @@ -436,7 +481,7 @@ public virtual CapturePaymentResult Capture(CapturePaymentRequest capturePayment catch (NotSupportedException) { var result = new CapturePaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoCaptureSupport")); + result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoCaptureSupport")); return result; } catch @@ -491,7 +536,7 @@ public virtual RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequ catch (NotSupportedException) { var result = new RefundPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRefundSupport")); + result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoRefundSupport")); return result; } catch @@ -533,7 +578,7 @@ public virtual VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) catch (NotSupportedException) { var result = new VoidPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoVoidSupport")); + result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoVoidSupport")); return result; } catch @@ -585,7 +630,7 @@ public virtual ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentReques catch (NotSupportedException) { var result = new ProcessPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); + result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoRecurringPaymentSupport")); return result; } catch @@ -616,7 +661,7 @@ public virtual CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurri catch (NotSupportedException) { var result = new CancelRecurringPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); + result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoRecurringPaymentSupport")); return result; } catch diff --git a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs index d29ce01907..74d78b69e9 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs @@ -116,10 +116,9 @@ public virtual IEnumerable> LoadActiveS if (fallbackMethod != null) { - // a frontend request should not revoke merchant settings - //_shippingSettings.ActiveShippingRateComputationMethodSystemNames.Clear(); - //_shippingSettings.ActiveShippingRateComputationMethodSystemNames.Add(fallbackMethod.Metadata.SystemName); - //_settingService.SaveSetting(_shippingSettings); + _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Clear(); + _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Add(fallbackMethod.Metadata.SystemName); + _settingService.SaveSetting(_shippingSettings); return new Provider[] { fallbackMethod }; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs index df69321ffa..7b81ffd118 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs @@ -1,5 +1,5 @@ -using System.Linq; -using System.Collections.Generic; +using System.Collections.Generic; +using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Payments; using SmartStore.Core.Domain.Payments; @@ -11,9 +11,9 @@ using SmartStore.Services.Payments; using SmartStore.Services.Security; using SmartStore.Services.Shipping; +using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Plugins; -using SmartStore.Web.Framework.Mvc; namespace SmartStore.Admin.Controllers { @@ -72,6 +72,7 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment model.AvailableCustomerRoles = new List(); model.AvailableShippingMethods = new List(); model.AvailableCountries = new List(); + model.AvailableAmountRestrictionContextTypes = AmountRestrictionContextType.SubtotalAmount.ToSelectList(false).ToList(); foreach (var role in customerRoles.OrderBy(x => x.Name)) { @@ -91,6 +92,9 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment if (paymentMethod != null) { model.CountryExclusionContext = paymentMethod.CountryExclusionContext; + model.AmountRestrictionContext = paymentMethod.AmountRestrictionContext; + model.MinimumOrderAmount = paymentMethod.MinimumOrderAmount; + model.MaximumOrderAmount = paymentMethod.MaximumOrderAmount; foreach (var id in paymentMethod.ExcludedCustomerRoleIds.SplitSafe(",")) { @@ -229,6 +233,9 @@ public ActionResult Edit(string systemName, bool continueEditing, PaymentMethodE paymentMethod.ExcludedCountryIds = string.Join(",", countryIds); paymentMethod.CountryExclusionContext = model.CountryExclusionContext; + paymentMethod.AmountRestrictionContext = model.AmountRestrictionContext; + paymentMethod.MinimumOrderAmount = model.MinimumOrderAmount; + paymentMethod.MaximumOrderAmount = model.MaximumOrderAmount; if (paymentMethod.Id == 0) _paymentService.InsertPaymentMethod(paymentMethod); diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs index 180d7c756b..9857d0f0e3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Core.Domain.Payments; +using SmartStore.Web.Framework; using SmartStore.Web.Framework.Mvc; namespace SmartStore.Admin.Models.Payments @@ -10,7 +11,17 @@ public class PaymentMethodEditModel : ProviderModel public List AvailableCustomerRoles { get; set; } public List AvailableShippingMethods { get; set; } public List AvailableCountries { get; set; } + public List AvailableAmountRestrictionContextTypes { get; set; } public CountryExclusionContextType CountryExclusionContext { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.AmountRestrictionContext")] + public AmountRestrictionContextType AmountRestrictionContext { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.MinimumOrderAmount")] + public decimal? MinimumOrderAmount { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.MaximumOrderAmount")] + public decimal? MaximumOrderAmount { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml index 51d94abb2e..ef2d508ae3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml @@ -87,6 +87,40 @@ @helper TabRestrictions() { +
+ + + + + + + + + + + + + +
+ @Html.SmartLabelFor(model => model.MinimumOrderAmount) + + @Html.EditorFor(model => model.MinimumOrderAmount) + @Html.ValidationMessageFor(model => model.MinimumOrderAmount) +
+ @Html.SmartLabelFor(model => model.MaximumOrderAmount) + + @Html.EditorFor(model => model.MaximumOrderAmount) + @Html.ValidationMessageFor(model => model.MaximumOrderAmount) +
+ @Html.SmartLabelFor(model => model.AmountRestrictionContext) + + @Html.DropDownListFor(model => model.AmountRestrictionContext, Model.AvailableAmountRestrictionContextTypes) + @Html.ValidationMessageFor(model => model.AmountRestrictionContext) +
+
+ +

 

+
@Html.Raw(T("Admin.Configuration.Payment.Methods.RestrictionNote"))
@@ -118,7 +152,7 @@
- @T("Admin.Common.AppliedTo") + @T("Admin.Common.RelatedTo")
/// SmartStore.Email.Message /// System.Net.Mail.Message - protected virtual net.MailMessage BuildMailMessage(EmailMessage original) + protected virtual MailMessage BuildMailMessage(EmailMessage original) { - net.MailMessage msg = new net.MailMessage(); + MailMessage msg = new MailMessage(); if (String.IsNullOrEmpty(original.Subject)) { @@ -37,15 +37,15 @@ protected virtual net.MailMessage BuildMailMessage(EmailMessage original) if (original.AltText.HasValue()) { - msg.AlternateViews.Add(net.AlternateView.CreateAlternateViewFromString(original.AltText, new ContentType("text/html"))); - msg.AlternateViews.Add(net.AlternateView.CreateAlternateViewFromString(original.Body, new ContentType("text/plain"))); + msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(original.AltText, new ContentType("text/html"))); + msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(original.Body, new ContentType("text/plain"))); } else { msg.Body = original.Body; } - msg.DeliveryNotificationOptions = net.DeliveryNotificationOptions.None; + msg.DeliveryNotificationOptions = DeliveryNotificationOptions.None; msg.From = original.From.ToMailAddress(); @@ -54,30 +54,9 @@ protected virtual net.MailMessage BuildMailMessage(EmailMessage original) msg.Bcc.AddRange(original.Bcc.Where(x => x.Address.HasValue()).Select(x => x.ToMailAddress())); msg.ReplyToList.AddRange(original.ReplyTo.Where(x => x.Address.HasValue()).Select(x => x.ToMailAddress())); - foreach (Attachment attachment in original.Attachments) + foreach (var attachment in original.Attachments) { - byte[] byteData; - - if (attachment.ContentTransferEncoding == TransferEncoding.Base64) - { - using (var sr = new StreamReader(attachment.Stream)) - { - byteData = Convert.FromBase64String(sr.ReadToEnd()); - } - } - else - { - byteData = attachment.Stream.ToByteArray(); - } - - MemoryStream s = new MemoryStream(byteData); - net.Attachment att = new net.Attachment(s, attachment.Name, attachment.ContentType.MediaType); - - att.ContentType.MediaType = attachment.MediaType; - att.TransferEncoding = attachment.ContentTransferEncoding; - att.ContentDisposition.DispositionType = attachment.ContentDisposition.DispositionType; - - msg.Attachments.Add(att); + msg.Attachments.Add(attachment); } if (original.Headers != null) diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 4a9d7bc280..55a91b1f35 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -224,7 +224,6 @@ - diff --git a/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs index 08c82ec8cd..e01c330ba0 100644 --- a/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs @@ -53,9 +53,10 @@ public partial interface IQueuedEmailService /// Page size /// A value indicating whether to load manually send emails /// Email item collection - IPagedList SearchEmails(string fromEmail, - string toEmail, DateTime? startTime, DateTime? endTime, - bool loadNotSentItemsOnly, int maxSendTries, + IPagedList SearchEmails( + string fromEmail, string toEmail, + DateTime? startTime, DateTime? endTime, + bool loadUnsentItemsOnly, int maxSendTries, bool loadNewest, int pageIndex, int pageSize, bool? sendManually = null); diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index fb53c2aa04..4dc57c2c83 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -133,7 +133,7 @@ where queuedEmailIds.Contains(qe.Id) /// To Email /// The start time /// The end time - /// A value indicating whether to load only not sent emails + /// A value indicating whether to load only not sent emails /// Maximum send tries /// A value indicating whether we should sort queued email descending; otherwise, ascending. /// Page index @@ -142,7 +142,7 @@ where queuedEmailIds.Contains(qe.Id) /// Email item list public virtual IPagedList SearchEmails(string fromEmail, string toEmail, DateTime? startTime, DateTime? endTime, - bool loadNotSentItemsOnly, int maxSendTries, + bool loadUnsentItemsOnly, int maxSendTries, bool loadNewest, int pageIndex, int pageSize, bool? sendManually = null) { @@ -163,7 +163,7 @@ public virtual IPagedList SearchEmails(string fromEmail, if (endTime.HasValue) query = query.Where(qe => qe.CreatedOnUtc <= endTime); - if (loadNotSentItemsOnly) + if (loadUnsentItemsOnly) query = query.Where(qe => !qe.SentOnUtc.HasValue); if (sendManually.HasValue) diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs index cd3110c81d..3223633b5f 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs @@ -9,8 +9,7 @@ public partial class QueuedMessagesSendTask : ITask { private readonly IQueuedEmailService _queuedEmailService; - public QueuedMessagesSendTask( - IQueuedEmailService queuedEmailService) + public QueuedMessagesSendTask(IQueuedEmailService queuedEmailService) { _queuedEmailService = queuedEmailService; } From eb36a083f6d75542ccc72b44739812741c1213af Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 22 Jun 2015 10:44:34 +0200 Subject: [PATCH 0012/1074] Review payment and shipping method restrictions --- .../RestrictionContextTypes.cs | 4 +- .../Domain/Payments/PaymentMethod.cs | 5 +- .../Domain/Shipping/ShippingMethod.cs | 23 +++ .../SmartStore.Core/SmartStore.Core.csproj | 2 +- .../Mapping/Payments/PaymentMethodMap.cs | 6 +- .../Mapping/Shipping/ShippingMethodMap.cs | 4 +- ...06181501470_PaymentShippingRestrictions.cs | 100 ----------- ...181501470_PaymentShippingRestrictions.resx | 126 -------------- ...3_PaymentShippingRestrictions.Designer.cs} | 2 +- ...06211043073_PaymentShippingRestrictions.cs | 143 ++++++++++++++++ ...211043073_PaymentShippingRestrictions.resx | 126 ++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../Payments/PaymentService.cs | 11 +- .../Shipping/IShippingService.cs | 5 +- .../Shipping/ShippingService.cs | 75 ++++----- .../Providers/ByTotalProvider.cs | 2 +- .../Providers/FixedRateProvider.cs | 10 +- .../ByWeightShippingComputationMethod.cs | 2 +- .../Administration/Content/admin.less | 46 +---- .../Controllers/PaymentController.cs | 53 ++---- .../Controllers/ShippingController.cs | 150 +++++------------ .../Infrastructure/AutoMapperStartupTask.cs | 4 +- .../Models/Payments/PaymentMethodEditModel.cs | 22 ++- .../Models/Shipping/ShippingMethodModel.cs | 11 ++ .../ShippingMethodRestrictionModel.cs | 21 --- .../Administration/SmartStore.Admin.csproj | 4 - .../Administration/Views/Payment/Edit.cshtml | 150 +++++------------ .../Views/Shipping/Restrictions.cshtml | 91 ---------- .../Shipping/_CreateOrUpdateMethod.cshtml | 159 ++++++++---------- .../Administration/sitemap.config | 1 - 30 files changed, 574 insertions(+), 794 deletions(-) rename src/Libraries/SmartStore.Core/Domain/{Payments => Common}/RestrictionContextTypes.cs (62%) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.resx rename src/Libraries/SmartStore.Data/Migrations/{201506181501470_PaymentShippingRestrictions.Designer.cs => 201506211043073_PaymentShippingRestrictions.Designer.cs} (92%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.resx delete mode 100644 src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodRestrictionModel.cs delete mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Shipping/Restrictions.cshtml diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/RestrictionContextTypes.cs b/src/Libraries/SmartStore.Core/Domain/Common/RestrictionContextTypes.cs similarity index 62% rename from src/Libraries/SmartStore.Core/Domain/Payments/RestrictionContextTypes.cs rename to src/Libraries/SmartStore.Core/Domain/Common/RestrictionContextTypes.cs index be4756574b..98a1590c7e 100644 --- a/src/Libraries/SmartStore.Core/Domain/Payments/RestrictionContextTypes.cs +++ b/src/Libraries/SmartStore.Core/Domain/Common/RestrictionContextTypes.cs @@ -1,7 +1,7 @@  -namespace SmartStore.Core.Domain.Payments +namespace SmartStore.Core.Domain.Common { - public enum CountryExclusionContextType + public enum CountryRestrictionContextType { BillingAddress = 0, ShippingAddress diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs index 28fa9f66a0..0567ad5dfe 100644 --- a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs +++ b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs @@ -1,4 +1,5 @@ using System.Runtime.Serialization; +using SmartStore.Core.Domain.Common; namespace SmartStore.Core.Domain.Payments { @@ -42,11 +43,11 @@ public partial class PaymentMethod : BaseEntity /// Gets or sets the country exclusion context ///
[DataMember] - public CountryExclusionContextType CountryExclusionContext + public CountryRestrictionContextType CountryExclusionContext { get { - return (CountryExclusionContextType)this.CountryExclusionContextId; + return (CountryRestrictionContextType)this.CountryExclusionContextId; } set { diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs index 9651718a85..86d5390e85 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Runtime.Serialization; +using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Localization; @@ -40,6 +41,28 @@ public partial class ShippingMethod : BaseEntity, ILocalizedEntity [DataMember] public string ExcludedCustomerRoleIds { get; set; } + /// + /// Gets or sets the context identifier for country exclusion + /// + [DataMember] + public int CountryExclusionContextId { get; set; } + + /// + /// Gets or sets the country exclusion context + /// + [DataMember] + public CountryRestrictionContextType CountryExclusionContext + { + get + { + return (CountryRestrictionContextType)this.CountryExclusionContextId; + } + set + { + this.CountryExclusionContextId = (int)value; + } + } + /// /// Gets or sets the restricted countries /// diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 4a9d7bc280..9502cdf6c9 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -157,7 +157,7 @@ - + diff --git a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs index d222942dad..c009204c13 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs @@ -12,9 +12,9 @@ public PaymentMethodMap() this.Property(x => x.PaymentMethodSystemName).IsRequired().HasMaxLength(4000); - this.Property(x => x.ExcludedCustomerRoleIds).IsMaxLength(); - this.Property(x => x.ExcludedCountryIds).IsMaxLength(); - this.Property(x => x.ExcludedShippingMethodIds).IsMaxLength(); + this.Property(x => x.ExcludedCustomerRoleIds).HasMaxLength(500); + this.Property(x => x.ExcludedCountryIds).HasMaxLength(2000); + this.Property(x => x.ExcludedShippingMethodIds).HasMaxLength(500); this.Property(x => x.MinimumOrderAmount).HasPrecision(18, 4); this.Property(x => x.MaximumOrderAmount).HasPrecision(18, 4); diff --git a/src/Libraries/SmartStore.Data/Mapping/Shipping/ShippingMethodMap.cs b/src/Libraries/SmartStore.Data/Mapping/Shipping/ShippingMethodMap.cs index 947070d588..e1c566088a 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Shipping/ShippingMethodMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Shipping/ShippingMethodMap.cs @@ -11,11 +11,13 @@ public ShippingMethodMap() this.HasKey(sm => sm.Id); this.Property(sm => sm.Name).IsRequired().HasMaxLength(400); - this.Property(sm => sm.ExcludedCustomerRoleIds).IsMaxLength(); + this.Property(sm => sm.ExcludedCustomerRoleIds).HasMaxLength(500); this.HasMany(sm => sm.RestrictedCountries) .WithMany(c => c.RestrictedShippingMethods) .Map(m => m.ToTable("ShippingMethodRestrictions")); + + this.Ignore(sm => sm.CountryExclusionContext); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.cs deleted file mode 100644 index e957c22ff7..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.cs +++ /dev/null @@ -1,100 +0,0 @@ -namespace SmartStore.Data.Migrations -{ - using System; - using System.Data.Entity.Migrations; - using SmartStore.Data.Setup; - - public partial class PaymentShippingRestrictions : DbMigration, ILocaleResourcesProvider, IDataSeeder - { - public override void Up() - { - CreateTable( - "dbo.PaymentMethod", - c => new - { - Id = c.Int(nullable: false, identity: true), - PaymentMethodSystemName = c.String(nullable: false, maxLength: 4000), - ExcludedCustomerRoleIds = c.String(), - ExcludedCountryIds = c.String(), - ExcludedShippingMethodIds = c.String(), - CountryExclusionContextId = c.Int(nullable: false), - MinimumOrderAmount = c.Decimal(precision: 18, scale: 4), - MaximumOrderAmount = c.Decimal(precision: 18, scale: 4), - AmountRestrictionContextId = c.Int(nullable: false), - }) - .PrimaryKey(t => t.Id) - .Index(t => t.PaymentMethodSystemName); - - AddColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds", c => c.String()); - } - - public override void Down() - { - DropColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds"); - DropTable("dbo.PaymentMethod"); - } - - public bool RollbackOnFailure - { - get { return false; } - } - - public void Seed(SmartObjectContext context) - { - context.MigrateLocaleResources(MigrateLocaleResources); - } - - public void MigrateLocaleResources(LocaleResourcesBuilder builder) - { - builder.AddOrUpdate("Admin.Common.Restrictions", - "Restrictions", - "Einschrnkungen"); - - builder.AddOrUpdate("Admin.Common.RelatedTo", - "related to", - "bezogen auf"); - - builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", - "Select customer roles, shipping methods and countries for which you do not want to offer this payment method.", - "Whlen Sie Kundengruppen, Versandarten und Lnder, bei denen Sie diese Zahlungsmethode nicht anbieten mchten."); - - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.CountryExclusionContextType.BillingAddress", - "Billing address", - "Rechnungsadresse"); - - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.CountryExclusionContextType.ShippingAddress", - "Shipping address", - "Versandadresse"); - - builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.RestrictionNote", - "Select customer roles for which you do not want to offer this shipping method.", - "Whlen Sie Kundengruppen, bei denen Sie diese Versandart nicht anbieten mchten."); - - builder.AddOrUpdate("Admin.Configuration.Payment.Methods.MinimumOrderAmount", - "Minimum order amount", - "Mindestbestellwert", - "Specifies the minimum order amount from which on the payment method should be offered.", - "Legt den Mindestbestellwert fest, ab dem die Zahlungsmethode angeboten werden soll."); - - builder.AddOrUpdate("Admin.Configuration.Payment.Methods.MaximumOrderAmount", - "Maximum amount", - "Maximalbestellwert", - "Specifies the maximum order amount up to which the payment methods should be offered.", - "Legt den maximalen Bestellwert fest, bis zu dem die Zahlungsmethode angeboten werden soll."); - - builder.AddOrUpdate("Admin.Configuration.Payment.Methods.AmountRestrictionContext", - "Amount related to", - "Betrag bezieht sich auf", - "Specifies the amount to which the minimum and maximum order amounts are related to.", - "Legt den Betrag fest, auf den sich die Minimal- und Maximalbestellwerte beziehen."); - - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.AmountRestrictionContextType.SubtotalAmount", - "Subtotal", - "Zwischensumme"); - - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Payments.AmountRestrictionContextType.TotalAmount", - "Order total", - "Gesamtsumme"); - } - } -} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.resx deleted file mode 100644 index 4ac037f18e..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.Designer.cs index 97d631de8c..e5e31c1659 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506181501470_PaymentShippingRestrictions.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class PaymentShippingRestrictions : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201506181501470_PaymentShippingRestrictions"; } + get { return "201506211043073_PaymentShippingRestrictions"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs new file mode 100644 index 0000000000..bd0333f18d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs @@ -0,0 +1,143 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class PaymentShippingRestrictions : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.PaymentMethod", + c => new + { + Id = c.Int(nullable: false, identity: true), + PaymentMethodSystemName = c.String(nullable: false, maxLength: 4000), + ExcludedCustomerRoleIds = c.String(maxLength: 500), + ExcludedCountryIds = c.String(maxLength: 2000), + ExcludedShippingMethodIds = c.String(maxLength: 500), + CountryExclusionContextId = c.Int(nullable: false), + MinimumOrderAmount = c.Decimal(precision: 18, scale: 4), + MaximumOrderAmount = c.Decimal(precision: 18, scale: 4), + AmountRestrictionContextId = c.Int(nullable: false), + }) + .PrimaryKey(t => t.Id) + .Index(t => t.PaymentMethodSystemName); + + AddColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds", c => c.String(maxLength: 500)); + AddColumn("dbo.ShippingMethod", "CountryExclusionContextId", c => c.Int(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.ShippingMethod", "CountryExclusionContextId"); + DropColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds"); + DropTable("dbo.PaymentMethod"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.Restrictions", + "Restrictions", + "Einschrnkungen"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", + "Select customer roles, shipping methods, countries and order amounts for which you do not want to offer this payment method.", + "Whlen Sie Kundengruppen, Versandarten, Lnder und Bestellwerte, bei denen Sie diese Zahlungsmethode nicht anbieten mchten."); + + builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.RestrictionNote", + "Select customer roles and countries for which you do not want to offer this shipping method.", + "Whlen Sie Kundengruppen und Lnder, bei denen Sie diese Versandart nicht anbieten mchten."); + + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.ExcludedCustomerRole", + "Customer roles", + "Kundengruppen", + "Specifies customer roles for which the payment method should not be offered.", + "Legt Kundengruppen fest, fr die die Zahlungsmethode nicht angeboten werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.ExcludedShippingMethod", + "Shipping method", + "Versandarten", + "Specifies shipping methods for which the payment method should not be offered.", + "Legt Versandarten fest, fr die die Zahlungsmethode nicht angeboten werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.ExcludedCountry", + "Countries", + "Lnder", + "Specifies countries for which the payment method should not be offered.", + "Legt Lnder fest, fr die die Zahlungsmethode nicht angeboten werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.MinimumOrderAmount", + "Minimum order amount", + "Mindestbestellwert", + "Specifies the minimum order amount from which on the payment method should be offered.", + "Legt den Mindestbestellwert fest, ab dem die Zahlungsmethode angeboten werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.MaximumOrderAmount", + "Maximum amount", + "Maximalbestellwert", + "Specifies the maximum order amount up to which the payment methods should be offered.", + "Legt den maximalen Bestellwert fest, bis zu dem die Zahlungsmethode angeboten werden soll."); + + + builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.ExcludedCustomerRole", + "Customer roles", + "Kundengruppen", + "Specifies customer roles for which the shipping method should not be offered.", + "Legt Kundengruppen fest, fr die die Versandart nicht angeboten werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.ExcludedCountry", + "Countries", + "Lnder", + "Specifies countries for which the shipping method should not be offered.", + "Legt Lnder fest, fr die die Versandart nicht angeboten werden soll."); + + + builder.AddOrUpdate("Admin.Configuration.Restrictions.AmountRestrictionContext", + "Amount related to", + "Betrag bezieht sich auf", + "Specifies the amount to which the minimum and maximum order amounts are related to.", + "Legt den Betrag fest, auf den sich die Mindest- und Maximalbestellwerte beziehen."); + + builder.AddOrUpdate("Admin.Configuration.Restrictions.CountryExclusionContext", + "Countries related to", + "Lnder beziehen sich auf", + "Specifies the address to which the selected countries are related to.", + "Legt die Adresse fest, auf den sich die gewhlten Lnder beziehen."); + + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Common.CountryRestrictionContextType.BillingAddress", + "Billing address", + "Rechnungsadresse"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Common.CountryRestrictionContextType.ShippingAddress", + "Shipping address", + "Versandadresse"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Common.AmountRestrictionContextType.SubtotalAmount", + "Subtotal", + "Zwischensumme"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Common.AmountRestrictionContextType.TotalAmount", + "Order total", + "Gesamtsumme"); + + builder.Delete("Admin.Configuration.Shipping.Restrictions.Updated"); + builder.Delete("Admin.Configuration.Shipping.Restrictions.Description"); + builder.Delete("Admin.Configuration.Shipping.Restrictions.Country"); + builder.Delete("Admin.Configuration.Shipping.Restrictions"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.resx new file mode 100644 index 0000000000..43c6122456 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index cd96c73f3a..25b190e056 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -273,9 +273,9 @@ 201505272236124_V222.cs - - - 201506181501470_PaymentShippingRestrictions.cs + + + 201506211043073_PaymentShippingRestrictions.cs @@ -534,8 +534,8 @@ 201505272236124_V222.cs - - 201506181501470_PaymentShippingRestrictions.cs + + 201506211043073_PaymentShippingRestrictions.cs diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index 3b6a3f66b8..24e39c2d32 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using SmartStore.Core.Data; +using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Orders; @@ -139,12 +140,12 @@ public virtual IEnumerable> LoadActivePaymentMethods( return false; } - // method restricted by country of selected billing address? + // method restricted by country of selected billing or shipping address? var excludedCountryIds = method.ExcludedCountryIds.ToIntArray(); if (excludedCountryIds.Any()) { int countryId = 0; - if (method.CountryExclusionContext == CountryExclusionContextType.ShippingAddress) + if (method.CountryExclusionContext == CountryRestrictionContextType.ShippingAddress) countryId = (customer.ShippingAddress != null ? (customer.ShippingAddress.CountryId ?? 0) : 0); else countryId = (customer.BillingAddress != null ? (customer.BillingAddress.CountryId ?? 0) : 0); @@ -262,7 +263,11 @@ public virtual IList GetAllPaymentMethods() { var paymentMethods = _commonServices.Cache.Get(PAYMENTMETHOD_ALL_KEY, () => { - return _paymentMethodRepository.Table.ToList(); + var methods = _paymentMethodRepository.TableUntracked.ToList(); + + methods.Each(x => _paymentMethodRepository.Context.DetachEntity(x)); + + return methods; }); return paymentMethods; diff --git a/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs index 501c236c22..8ec9c19c40 100644 --- a/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs @@ -53,10 +53,9 @@ public partial interface IShippingService /// /// Gets all shipping methods /// - /// The country indentifier to filter by - /// Filter methods by roles of a customer + /// Filter shipping methods by customer and apply payment method restrictions; null to load all records /// Shipping method collection - IList GetAllShippingMethods(int? filterByCountryId = null, Customer customer = null); + IList GetAllShippingMethods(Customer customer = null); /// /// Inserts a shipping method diff --git a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs index 74d78b69e9..553156b912 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs @@ -188,58 +188,49 @@ public virtual ShippingMethod GetShippingMethodById(int shippingMethodId) /// /// Gets all shipping methods /// - /// The country indentifier to filter by - /// Filter methods by roles of a customer + /// Filter shipping methods by customer and apply payment method restrictions; null to load all records /// Shipping method collection - public virtual IList GetAllShippingMethods(int? filterByCountryId = null, Customer customer = null) + public virtual IList GetAllShippingMethods(Customer customer = null) { - IQueryable query = null; + List customerRoleIds = null; - if (filterByCountryId.HasValue && filterByCountryId.Value > 0) - { - var query1 = - from sm in _shippingMethodRepository.Table - where sm.RestrictedCountries.Select(c => c.Id).Contains(filterByCountryId.Value) - select sm.Id; - - query = - from sm in _shippingMethodRepository.Table - where !query1.Contains(sm.Id) - orderby sm.DisplayOrder - select sm; - } - else - { - query = - from sm in _shippingMethodRepository.Table - orderby sm.DisplayOrder - select sm; - } + var query = + from sm in _shippingMethodRepository.Table + orderby sm.DisplayOrder + select sm; - var shippingMethods = query.ToList(); + var allMethods = query.ToList(); - if (customer != null) - { - List customerRoleIds = null; + if (customer == null) + return allMethods; - for (int i = shippingMethods.Count - 1; i >= 0; --i) + var activeShippingMethods = allMethods.Where(x => + { + // method restricted by customer role id? + var excludedRoleIds = x.ExcludedCustomerRoleIds.ToIntArray(); + if (excludedRoleIds.Any()) { - var method = shippingMethods[i]; - - // method restricted by customer role id? - var excludedRoleIds = method.ExcludedCustomerRoleIds.ToIntArray(); - if (excludedRoleIds.Any()) - { - if (customerRoleIds == null) - customerRoleIds = customer.CustomerRoles.Where(r => r.Active).Select(r => r.Id).ToList(); + if (customerRoleIds == null) + customerRoleIds = customer.CustomerRoles.Where(r => r.Active).Select(r => r.Id).ToList(); - if (customerRoleIds != null && !customerRoleIds.Except(excludedRoleIds).Any()) - shippingMethods.Remove(method); - } + if (customerRoleIds != null && !customerRoleIds.Except(excludedRoleIds).Any()) + return false; } - } - return shippingMethods; + // method restricted by country of selected billing or shipping address? + int countryId = 0; + if (x.CountryExclusionContext == CountryRestrictionContextType.ShippingAddress) + countryId = (customer.ShippingAddress != null ? (customer.ShippingAddress.CountryId ?? 0) : 0); + else + countryId = (customer.BillingAddress != null ? (customer.BillingAddress.CountryId ?? 0) : 0); + + if (countryId != 0 && x.CountryRestrictionExists(countryId)) + return false; + + return true; + }); + + return activeShippingMethods.ToList(); } /// diff --git a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs index 44926d497c..9ca91fdca8 100644 --- a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs +++ b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs @@ -187,7 +187,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get decimal sqThreshold = _shippingByTotalSettings.SmallQuantityThreshold; decimal sqSurcharge = _shippingByTotalSettings.SmallQuantitySurcharge; - var shippingMethods = _shippingService.GetAllShippingMethods(countryId, getShippingOptionRequest.Customer); + var shippingMethods = _shippingService.GetAllShippingMethods(getShippingOptionRequest.Customer); foreach (var shippingMethod in shippingMethods) { decimal? rate = GetRate(subTotal, shippingMethod.Id, storeId, countryId, stateProvinceId, zip); diff --git a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs index 673f3b5c85..3f51635f18 100644 --- a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs +++ b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs @@ -55,10 +55,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get return response; } - int? restrictByCountryId = (getShippingOptionRequest.ShippingAddress != null && getShippingOptionRequest.ShippingAddress.Country != null) - ? (int?)getShippingOptionRequest.ShippingAddress.Country.Id : null; - - var shippingMethods = this._shippingService.GetAllShippingMethods(restrictByCountryId, getShippingOptionRequest.Customer); + var shippingMethods = this._shippingService.GetAllShippingMethods(getShippingOptionRequest.Customer); foreach (var shippingMethod in shippingMethods) { var shippingOption = new ShippingOption(); @@ -82,10 +79,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get if (getShippingOptionRequest == null) throw new ArgumentNullException("getShippingOptionRequest"); - int? restrictByCountryId = (getShippingOptionRequest.ShippingAddress != null && getShippingOptionRequest.ShippingAddress.Country != null) - ? (int?)getShippingOptionRequest.ShippingAddress.Country.Id : null; - - var shippingMethods = this._shippingService.GetAllShippingMethods(restrictByCountryId, getShippingOptionRequest.Customer); + var shippingMethods = this._shippingService.GetAllShippingMethods(getShippingOptionRequest.Customer); var rates = new List(); foreach (var shippingMethod in shippingMethods) diff --git a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs index 9c9d9d69f6..bc94c7a947 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs @@ -141,7 +141,7 @@ public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest get } decimal weight = _shippingService.GetShoppingCartTotalWeight(getShippingOptionRequest.Items); - var shippingMethods = _shippingService.GetAllShippingMethods(countryId, getShippingOptionRequest.Customer); + var shippingMethods = _shippingService.GetAllShippingMethods(getShippingOptionRequest.Customer); foreach (var shippingMethod in shippingMethods) { var record = _shippingByWeightService.FindRecord(shippingMethod.Id, storeId, countryId, weight); diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index 7c7a6017d3..c3bf87312d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -748,9 +748,16 @@ td.adminData .text-box.single-line { width: 300px; } td.adminData input[type=text].input-large, -td.adminData textarea.input-large { +td.adminData textarea.input-large, +td.adminData .control-large { width: 500px; } +td.adminData input[type=text].input-xlarge, +td.adminData textarea.input-xlarge, +td.adminData .control-xlarge { + width: 800px; +} + .t-grid .text-box.single-line { /* ... */ @@ -1197,43 +1204,6 @@ table.payment-method-features td { font-size: 12px; } -/* payment and shipping restrictions --------------------------------------------------------------- */ -.restriction-container { - th label { - margin: 0 10px 0 0; - display: inline-block; - } - - th > div { - display: inline-block; - padding-right: 10px; - } - - .normal-font { - font-weight: normal; - } - - .column-customerroles, - .column-shippingmethods { - width: 18%; - } - - .column-countries { - width: 64%; - - > div { - display: table-row; - } - - .country-container { - display: table-cell; - width: 25%; - padding-right: 10px; - } - } -} - /* Special icons */ .icon-active-true { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs index 7b81ffd118..d66429e90d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Payments; +using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Plugins; using SmartStore.Services; @@ -64,7 +65,6 @@ public PaymentController( private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, PaymentMethod paymentMethod) { - SelectListItem item = null; var customerRoles = _customerService.GetAllCustomerRoles(true); var shippingMethods = _shippingService.GetAllShippingMethods(); var countries = _countryService.GetAllCountries(true); @@ -72,6 +72,8 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment model.AvailableCustomerRoles = new List(); model.AvailableShippingMethods = new List(); model.AvailableCountries = new List(); + + model.AvailableCountryExclusionContextTypes = CountryRestrictionContextType.BillingAddress.ToSelectList(false).ToList(); model.AvailableAmountRestrictionContextTypes = AmountRestrictionContextType.SubtotalAmount.ToSelectList(false).ToList(); foreach (var role in customerRoles.OrderBy(x => x.Name)) @@ -91,28 +93,15 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment if (paymentMethod != null) { - model.CountryExclusionContext = paymentMethod.CountryExclusionContext; - model.AmountRestrictionContext = paymentMethod.AmountRestrictionContext; + model.ExcludedCustomerRoleIds = paymentMethod.ExcludedCustomerRoleIds.SplitSafe(","); + model.ExcludedShippingMethodIds = paymentMethod.ExcludedShippingMethodIds.SplitSafe(","); + model.ExcludedCountryIds = paymentMethod.ExcludedCountryIds.SplitSafe(","); + model.MinimumOrderAmount = paymentMethod.MinimumOrderAmount; model.MaximumOrderAmount = paymentMethod.MaximumOrderAmount; - foreach (var id in paymentMethod.ExcludedCustomerRoleIds.SplitSafe(",")) - { - if ((item = model.AvailableCustomerRoles.FirstOrDefault(x => x.Value == id)) != null) - item.Selected = true; - } - - foreach (var id in paymentMethod.ExcludedShippingMethodIds.SplitSafe(",")) - { - if ((item = model.AvailableShippingMethods.FirstOrDefault(x => x.Value == id)) != null) - item.Selected = true; - } - - foreach (var id in paymentMethod.ExcludedCountryIds.SplitSafe(",")) - { - if ((item = model.AvailableCountries.FirstOrDefault(x => x.Value == id)) != null) - item.Selected = true; - } + model.CountryExclusionContext = paymentMethod.CountryExclusionContext; + model.AmountRestrictionContext = paymentMethod.AmountRestrictionContext; } } @@ -213,29 +202,15 @@ public ActionResult Edit(string systemName, bool continueEditing, PaymentMethodE if (paymentMethod == null) paymentMethod = new PaymentMethod { PaymentMethodSystemName = systemName }; - var customerRoleIds = Request.Form.AllKeys - .Where(x => x.StartsWith("CustomerRole_")) - .Select(x => x.Replace("CustomerRole_", "")) - .ToList(); + paymentMethod.ExcludedCustomerRoleIds = Request.Form["ExcludedCustomerRoleIds"]; + paymentMethod.ExcludedShippingMethodIds = Request.Form["ExcludedShippingMethodIds"]; + paymentMethod.ExcludedCountryIds = Request.Form["ExcludedCountryIds"]; - var shippingMethodIds = Request.Form.AllKeys - .Where(x => x.StartsWith("ShippingMethod_")) - .Select(x => x.Replace("ShippingMethod_", "")) - .ToList(); - - var countryIds = Request.Form.AllKeys - .Where(x => x.StartsWith("Country_")) - .Select(x => x.Replace("Country_", "")) - .ToList(); - - paymentMethod.ExcludedCustomerRoleIds = string.Join(",", customerRoleIds); - paymentMethod.ExcludedShippingMethodIds = string.Join(",", shippingMethodIds); - paymentMethod.ExcludedCountryIds = string.Join(",", countryIds); + paymentMethod.MinimumOrderAmount = model.MinimumOrderAmount; + paymentMethod.MaximumOrderAmount = model.MaximumOrderAmount; paymentMethod.CountryExclusionContext = model.CountryExclusionContext; paymentMethod.AmountRestrictionContext = model.AmountRestrictionContext; - paymentMethod.MinimumOrderAmount = model.MinimumOrderAmount; - paymentMethod.MaximumOrderAmount = model.MaximumOrderAmount; if (paymentMethod.Id == 0) _paymentService.InsertPaymentMethod(paymentMethod); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs index 996f0af0a5..4dd03455e0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs @@ -1,11 +1,9 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Web.Mvc; -using SmartStore.Admin.Models.Directory; using SmartStore.Admin.Models.Shipping; +using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Shipping; -using SmartStore.Core.Plugins; using SmartStore.Services; using SmartStore.Services.Customers; using SmartStore.Services.Directory; @@ -29,7 +27,6 @@ public partial class ShippingController : AdminControllerBase private readonly ICountryService _countryService; private readonly ILocalizedEntityService _localizedEntityService; private readonly ILanguageService _languageService; - private readonly IPluginFinder _pluginFinder; private readonly PluginMediator _pluginMediator; private readonly ICommonServices _commonServices; private readonly ICustomerService _customerService; @@ -43,7 +40,6 @@ public ShippingController(IShippingService shippingService, ICountryService countryService, ILocalizedEntityService localizedEntityService, ILanguageService languageService, - IPluginFinder pluginFinder, PluginMediator pluginMediator, ICommonServices commonServices, ICustomerService customerService) @@ -53,7 +49,6 @@ public ShippingController(IShippingService shippingService, this._countryService = countryService; this._localizedEntityService = localizedEntityService; this._languageService = languageService; - this._pluginFinder = pluginFinder; this._pluginMediator = pluginMediator; this._commonServices = commonServices; this._customerService = customerService; @@ -82,34 +77,61 @@ protected void UpdateLocales(ShippingMethod shippingMethod, ShippingMethodModel private void PrepareShippingMethodModel(ShippingMethodModel model, ShippingMethod shippingMethod) { - SelectListItem item = null; var customerRoles = _customerService.GetAllCustomerRoles(true); + var countries = _countryService.GetAllCountries(true); model.AvailableCustomerRoles = new List(); + model.AvailableCountries = new List(); + + model.AvailableCountryExclusionContextTypes = CountryRestrictionContextType.BillingAddress.ToSelectList(false).ToList(); foreach (var role in customerRoles.OrderBy(x => x.Name)) { model.AvailableCustomerRoles.Add(new SelectListItem { Text = role.Name, Value = role.Id.ToString() }); } + foreach (var country in countries.OrderBy(x => x.Name)) + { + model.AvailableCountries.Add(new SelectListItem { Text = country.GetLocalized(x => x.Name), Value = country.Id.ToString() }); + } + if (shippingMethod != null) { - foreach (var id in shippingMethod.ExcludedCustomerRoleIds.SplitSafe(",")) - { - if ((item = model.AvailableCustomerRoles.FirstOrDefault(x => x.Value == id)) != null) - item.Selected = true; - } + model.ExcludedCustomerRoleIds = shippingMethod.ExcludedCustomerRoleIds.SplitSafe(","); + model.ExcludedCountryIds = shippingMethod.RestrictedCountries.Select(x => x.Id.ToString()).ToArray(); + + model.CountryExclusionContext = shippingMethod.CountryExclusionContext; } } - private void ApplyRestrictions(ShippingMethod shippingMethod) + private void ApplyRestrictions(ShippingMethod shippingMethod, ShippingMethodModel model) { - var customerRoleIds = Request.Form.AllKeys - .Where(x => x.StartsWith("CustomerRole_")) - .Select(x => x.Replace("CustomerRole_", "")) - .ToList(); + var countries = _countryService.GetAllCountries(true); + + shippingMethod.ExcludedCustomerRoleIds = Request.Form["ExcludedCustomerRoleIds"]; + shippingMethod.CountryExclusionContext = model.CountryExclusionContext; + + string[] excludedCountryIds = Request.Form["ExcludedCountryIds"].SplitSafe(","); - shippingMethod.ExcludedCustomerRoleIds = string.Join(",", customerRoleIds); + foreach (var country in countries) + { + if (excludedCountryIds.Contains(country.Id.ToString())) + { + if (shippingMethod.RestrictedCountries.Where(c => c.Id == country.Id).FirstOrDefault() == null) + { + shippingMethod.RestrictedCountries.Add(country); + _shippingService.UpdateShippingMethod(shippingMethod); + } + } + else + { + if (shippingMethod.RestrictedCountries.Where(c => c.Id == country.Id).FirstOrDefault() != null) + { + shippingMethod.RestrictedCountries.Remove(country); + _shippingService.UpdateShippingMethod(shippingMethod); + } + } + } } #endregion @@ -225,7 +247,7 @@ public ActionResult CreateMethod(ShippingMethodModel model, bool continueEditing if (ModelState.IsValid) { var sm = model.ToEntity(); - ApplyRestrictions(sm); + ApplyRestrictions(sm, model); _shippingService.InsertShippingMethod(sm); @@ -276,12 +298,13 @@ public ActionResult EditMethod(ShippingMethodModel model, bool continueEditing) if (ModelState.IsValid) { sm = model.ToEntity(sm); - ApplyRestrictions(sm); + ApplyRestrictions(sm, model); _shippingService.UpdateShippingMethod(sm); //locales UpdateLocales(sm, model); + NotifySuccess(_commonServices.Localization.GetResource("Admin.Configuration.Shipping.Methods.Updated")); return continueEditing ? RedirectToAction("EditMethod", sm.Id) : RedirectToAction("Methods"); @@ -307,89 +330,6 @@ public ActionResult DeleteMethod(int id) return RedirectToAction("Methods"); } - #endregion - - #region Restrictions - - public ActionResult Restrictions() - { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) - return AccessDeniedView(); - - var model = new ShippingMethodRestrictionModel(); - - var countries = _countryService.GetAllCountries(true); - var shippingMethods = _shippingService.GetAllShippingMethods(); - foreach (var country in countries) - { - model.AvailableCountries.Add(new CountryModel() - { - Id = country.Id, - Name = country.Name - }); - } - foreach (var sm in shippingMethods) - { - model.AvailableShippingMethods.Add(new ShippingMethodModel() - { - Id = sm.Id, - Name = sm.Name - }); - } - foreach (var country in countries) - foreach (var shippingMethod in shippingMethods) - { - bool restricted = shippingMethod.CountryRestrictionExists(country.Id); - if (!model.Restricted.ContainsKey(country.Id)) - model.Restricted[country.Id] = new Dictionary(); - model.Restricted[country.Id][shippingMethod.Id] = restricted; - } - - return View(model); - } - - [HttpPost, ActionName("Restrictions")] - public ActionResult RestrictionSave(FormCollection form) - { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) - return AccessDeniedView(); - - var countries = _countryService.GetAllCountries(true); - var shippingMethods = _shippingService.GetAllShippingMethods(); - - - foreach (var shippingMethod in shippingMethods) - { - string formKey = "restrict_" + shippingMethod.Id; - var countryIdsToRestrict = form[formKey] != null ? form[formKey].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => int.Parse(x)).ToList() : new List(); - - foreach (var country in countries) - { - - bool restrict = countryIdsToRestrict.Contains(country.Id); - if (restrict) - { - if (shippingMethod.RestrictedCountries.Where(c => c.Id == country.Id).FirstOrDefault() == null) - { - shippingMethod.RestrictedCountries.Add(country); - _shippingService.UpdateShippingMethod(shippingMethod); - } - } - else - { - if (shippingMethod.RestrictedCountries.Where(c => c.Id == country.Id).FirstOrDefault() != null) - { - shippingMethod.RestrictedCountries.Remove(country); - _shippingService.UpdateShippingMethod(shippingMethod); - } - } - } - } - - NotifySuccess(_commonServices.Localization.GetResource("Admin.Configuration.Shipping.Restrictions.Updated")); - return RedirectToAction("Restrictions"); - } - - #endregion + #endregion } } diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index cd06725772..958b035003 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -387,7 +387,9 @@ public void Execute() //shipping methods Mapper.CreateMap() .ForMember(dest => dest.Locales, mo => mo.Ignore()) - .ForMember(dest => dest.AvailableCustomerRoles, mo => mo.Ignore()); + .ForMember(dest => dest.AvailableCustomerRoles, mo => mo.Ignore()) + .ForMember(dest => dest.AvailableCountries, mo => mo.Ignore()) + .ForMember(dest => dest.AvailableCountryExclusionContextTypes, mo => mo.Ignore()); Mapper.CreateMap() .ForMember(dest => dest.RestrictedCountries, mo => mo.Ignore()) .ForMember(dest => dest.ExcludedCustomerRoleIds, mo => mo.Ignore()); diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs index 9857d0f0e3..12abe357ea 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Web.Mvc; -using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Common; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Mvc; @@ -8,20 +8,30 @@ namespace SmartStore.Admin.Models.Payments { public class PaymentMethodEditModel : ProviderModel { + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.ExcludedCustomerRole")] + public string[] ExcludedCustomerRoleIds { get; set; } public List AvailableCustomerRoles { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.ExcludedShippingMethod")] + public string[] ExcludedShippingMethodIds { get; set; } public List AvailableShippingMethods { get; set; } - public List AvailableCountries { get; set; } - public List AvailableAmountRestrictionContextTypes { get; set; } - public CountryExclusionContextType CountryExclusionContext { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.ExcludedCountry")] + public string[] ExcludedCountryIds { get; set; } + public List AvailableCountries { get; set; } - [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.AmountRestrictionContext")] - public AmountRestrictionContextType AmountRestrictionContext { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Restrictions.CountryExclusionContext")] + public CountryRestrictionContextType CountryExclusionContext { get; set; } + public List AvailableCountryExclusionContextTypes { get; set; } [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.MinimumOrderAmount")] public decimal? MinimumOrderAmount { get; set; } [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.MaximumOrderAmount")] public decimal? MaximumOrderAmount { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Restrictions.AmountRestrictionContext")] + public AmountRestrictionContextType AmountRestrictionContext { get; set; } + public List AvailableAmountRestrictionContextTypes { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodModel.cs index c9690b4695..4a8e380e73 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodModel.cs @@ -2,6 +2,7 @@ using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Admin.Validators.Shipping; +using SmartStore.Core.Domain.Common; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Localization; using SmartStore.Web.Framework.Mvc; @@ -32,7 +33,17 @@ public ShippingMethodModel() public IList Locales { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Shipping.Methods.ExcludedCustomerRole")] + public string[] ExcludedCustomerRoleIds { get; set; } public List AvailableCustomerRoles { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Shipping.Methods.ExcludedCountry")] + public string[] ExcludedCountryIds { get; set; } + public List AvailableCountries { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Restrictions.CountryExclusionContext")] + public CountryRestrictionContextType CountryExclusionContext { get; set; } + public List AvailableCountryExclusionContextTypes { get; set; } } public class ShippingMethodLocalizedModel : ILocalizedModelLocal diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodRestrictionModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodRestrictionModel.cs deleted file mode 100644 index 1fa24bac73..0000000000 --- a/src/Presentation/SmartStore.Web/Administration/Models/Shipping/ShippingMethodRestrictionModel.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using SmartStore.Admin.Models.Directory; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Admin.Models.Shipping -{ - public class ShippingMethodRestrictionModel : ModelBase - { - public ShippingMethodRestrictionModel() - { - AvailableShippingMethods = new List(); - AvailableCountries = new List(); - Restricted = new Dictionary>(); - } - public IList AvailableShippingMethods { get; set; } - public IList AvailableCountries { get; set; } - - //[country id] / [shipping method id] / [restricted] - public IDictionary> Restricted { get; set; } - } -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 51dabda6e7..60c5ff77f0 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -309,7 +309,6 @@ - @@ -893,9 +892,6 @@ - - - diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml index ef2d508ae3..c891471a5d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml @@ -87,8 +87,54 @@ @helper TabRestrictions() { +
+ @Html.Raw(T("Admin.Configuration.Payment.Methods.RestrictionNote")) +
+
+ + + + + + + + + + + + + + + +
+ @Html.SmartLabelFor(model => model.ExcludedCustomerRoleIds) + + @Html.ListBoxFor(model => model.ExcludedCustomerRoleIds, + new MultiSelectList(Model.AvailableCustomerRoles, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ExcludedCustomerRoleIds) +
+ @Html.SmartLabelFor(model => model.ExcludedShippingMethodIds) + + @Html.ListBoxFor(model => model.ExcludedShippingMethodIds, + new MultiSelectList(Model.AvailableShippingMethods, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ExcludedShippingMethodIds) +
+ @Html.SmartLabelFor(model => model.ExcludedCountryIds) + + @Html.ListBoxFor(model => model.ExcludedCountryIds, + new MultiSelectList(Model.AvailableCountries, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ExcludedCountryIds) +
+ @Html.SmartLabelFor(model => model.CountryExclusionContext) + + @Html.DropDownListFor(model => model.CountryExclusionContext, Model.AvailableCountryExclusionContextTypes) + @Html.ValidationMessageFor(model => model.CountryExclusionContext) +
@Html.SmartLabelFor(model => model.MinimumOrderAmount) @@ -118,108 +164,4 @@
- -

 

- -
- @Html.Raw(T("Admin.Configuration.Payment.Methods.RestrictionNote")) -
- -
- - - - - - - - - - - -
-
- -
-
-
- -
-
-
- -
-
- @T("Admin.Common.RelatedTo") -
-
- - -
-
- @foreach (var item in Model.AvailableCustomerRoles) - { - @RenderCheckbox(item, "CustomerRole_") - } - - @foreach (var item in Model.AvailableShippingMethods) - { - @RenderCheckbox(item, "ShippingMethod_") - } - - - @foreach (var grp in Model.AvailableCountries.Select((x, i) => new { Key = i / 4, Value = x }).GroupBy(x => x.Key, x => x.Value)) - { -
- @foreach (var item in grp) - { -
- @RenderCheckbox(item, "Country_") -
- } -
- } - -
-
} - - -@helper RenderCheckbox(SelectListItem item, string prefix) -{ -
- -
-} - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Restrictions.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Restrictions.cshtml deleted file mode 100644 index e13f1fe8e5..0000000000 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Restrictions.cshtml +++ /dev/null @@ -1,91 +0,0 @@ -@model ShippingMethodRestrictionModel -@{ - ViewBag.Title = T("Admin.Configuration.Shipping.Restrictions").Text; -} -@using (Html.BeginForm()) -{ -
-
- - @T("Admin.Configuration.Shipping.Restrictions") -
-
- -
-
- -
- - @T("Admin.Configuration.Shipping.Restrictions.Description") -
- - - - - -
- @if (Model.AvailableCountries.Count == 0) - { - No countries defined - } - else if (Model.AvailableShippingMethods.Count == 0) - { - No shipping methods available - } - else - { - - -
- - - - - @foreach (var sm in Model.AvailableShippingMethods) - { - - } - - - - @foreach (var c in Model.AvailableCountries) - { - - - @foreach (var sm in Model.AvailableShippingMethods) - { - var restricted = Model.Restricted.ContainsKey(c.Id) && Model.Restricted[c.Id][sm.Id]; - - } - - } - -
- @T("Admin.Configuration.Shipping.Restrictions.Country") - - - -
- @c.Name - - -
-
- } -
-} diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml index 9033b3beb7..9163a2f8db 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml @@ -15,52 +15,52 @@ @helper TabGeneral() { @(Html.LocalizedEditor("shipping-method-localized", - @ - - - - - - - - - - - -
- @Html.SmartLabelFor(model => model.Locales[item].Name) - - @Html.EditorFor(model => Model.Locales[item].Name) - @Html.ValidationMessageFor(model => model.Locales[item].Name) -
- @Html.SmartLabelFor(model => model.Locales[item].Description) - - @Html.TextAreaFor(model => model.Locales[item].Description) - @Html.ValidationMessageFor(model => model.Locales[item].Description) -
- @Html.HiddenFor(model => model.Locales[item].LanguageId) -
- , - @ - - - - - - - - -
- @Html.SmartLabelFor(model => model.Name) - - @Html.EditorFor(model => model.Name) - @Html.ValidationMessageFor(model => model.Name) -
- @Html.SmartLabelFor(model => model.Description) - - @Html.TextAreaFor(model => model.Description) - @Html.ValidationMessageFor(model => model.Description) -
+ @ + + + + + + + + + + + +
+ @Html.SmartLabelFor(model => model.Locales[item].Name) + + @Html.EditorFor(model => Model.Locales[item].Name) + @Html.ValidationMessageFor(model => model.Locales[item].Name) +
+ @Html.SmartLabelFor(model => model.Locales[item].Description) + + @Html.TextAreaFor(model => model.Locales[item].Description) + @Html.ValidationMessageFor(model => model.Locales[item].Description) +
+ @Html.HiddenFor(model => model.Locales[item].LanguageId) +
+ , + @ + + + + + + + + +
+ @Html.SmartLabelFor(model => model.Name) + + @Html.EditorFor(model => model.Name) + @Html.ValidationMessageFor(model => model.Name) +
+ @Html.SmartLabelFor(model => model.Description) + + @Html.TextAreaFor(model => model.Description) + @Html.ValidationMessageFor(model => model.Description) +
)) @@ -91,50 +91,39 @@ @Html.Raw(T("Admin.Configuration.Shipping.Methods.RestrictionNote")) -
-
+
+
- + + - + + + + +
-
- -
-
+ @Html.SmartLabelFor(model => model.ExcludedCustomerRoleIds) + + @Html.ListBoxFor(model => model.ExcludedCustomerRoleIds, + new MultiSelectList(Model.AvailableCustomerRoles, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ExcludedCustomerRoleIds) +
- @foreach (var item in Model.AvailableCustomerRoles) - { - @RenderCheckbox(item, "CustomerRole_") - } + + @Html.SmartLabelFor(model => model.ExcludedCountryIds) + + @Html.ListBoxFor(model => model.ExcludedCountryIds, + new MultiSelectList(Model.AvailableCountries, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ExcludedCountryIds) +
+ @Html.SmartLabelFor(model => model.CountryExclusionContext) + + @Html.DropDownListFor(model => model.CountryExclusionContext, Model.AvailableCountryExclusionContextTypes) + @Html.ValidationMessageFor(model => model.CountryExclusionContext)
} - -@helper RenderCheckbox(SelectListItem item, string prefix) -{ -
- -
-} - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/sitemap.config b/src/Presentation/SmartStore.Web/Administration/sitemap.config index 0035df8219..33a9fd264f 100644 --- a/src/Presentation/SmartStore.Web/Administration/sitemap.config +++ b/src/Presentation/SmartStore.Web/Administration/sitemap.config @@ -107,7 +107,6 @@ - From 2e03fd56976bfdccd0d886d21a5e3aef5d2eabf4 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 22 Jun 2015 11:02:30 +0200 Subject: [PATCH 0013/1074] Resolved merging conflict --- src/Libraries/SmartStore.Data/SmartStore.Data.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 1854f65f2c..4d60239cc6 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -277,9 +277,9 @@ 201506181858349_AclRecordCustomerRole.cs - - - 201506181501470_PaymentShippingRestrictions.cs + + + 201506211043073_PaymentShippingRestrictions.cs @@ -541,8 +541,8 @@ 201506181858349_AclRecordCustomerRole.cs - - 201506181501470_PaymentShippingRestrictions.cs + + 201506211043073_PaymentShippingRestrictions.cs From 60736d649f200399fb6849ac782df1472251e030 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 23 Jun 2015 20:09:03 +0200 Subject: [PATCH 0014/1074] Updated changelog --- changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.md b/changelog.md index 2ef9701964..c3d2d7762e 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,8 @@ * #67 Restrict payment methods to certain countries * #94 Restrict payment methods to certain shipping methods * #526 Min\max amount option for which the payment method should be offered during checkout +* #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" + ## SmartStore.NET 2.2.2 From fd2b1f799548470ef8df420eae4248ee32443b92 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 24 Jun 2015 11:18:38 +0200 Subject: [PATCH 0015/1074] Resolves #705 Methods like PasswordRecoveryConfirm should not make home page redirects without any notification --- ...06211043073_PaymentShippingRestrictions.cs | 4 +++ .../Controllers/SmartController.cs | 22 +++++++------ .../Controllers/CustomerController.cs | 31 +++++++++---------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs index bd0333f18d..99a1467c9d 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs @@ -52,6 +52,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Restrictions", "Einschrnkungen"); + builder.AddOrUpdate("Common.RequestProcessingFailed", + "The request could not be processed.
Controller: {0}, Action: {1}, Reason: {2}.", + "Die Anfrage konnte nicht ausgefhrt werden.
Controller: {0}, Action: {1}, Grund: {2}."); + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", "Select customer roles, shipping methods, countries and order amounts for which you do not want to offer this payment method.", "Whlen Sie Kundengruppen, Versandarten, Lnder und Bestellwerte, bei denen Sie diese Zahlungsmethode nicht anbieten mchten."); diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs index 455f4c5e8a..5e69151979 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs @@ -1,16 +1,9 @@ using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; -using System.Web; using System.Web.Mvc; -using System.Web.Routing; using SmartStore.Core; using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; using SmartStore.Core.Logging; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Web.Framework.Security; -using SmartStore.Web.Framework.UI; namespace SmartStore.Web.Framework.Controllers { @@ -23,11 +16,13 @@ public abstract partial class SmartController : Controller protected SmartController() { this.Logger = NullLogger.Instance; + this.T = NullLocalizer.Instance; + this._notifier = EngineContext.Current.Resolve>(); } - public ILogger Logger { get; set; } + public Localizer T { get; set; } /// /// Pushes an info message to the notification queue @@ -95,6 +90,15 @@ protected virtual ActionResult RedirectToReferrer() return RedirectToRoute("HomePage"); } + protected virtual ActionResult RedirectToHomePageWithError(string reason, bool durable = true) + { + string message = T("Common.RequestProcessingFailed", this.RouteData.Values["controller"], this.RouteData.Values["action"], reason.NaIfEmpty()); + + _notifier.Value.Error(message, durable); + + return RedirectToRoute("HomePage"); + } + /// /// On exception /// diff --git a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs index 52d7118d68..c070f2dd37 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs @@ -1,18 +1,17 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Forums; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Logging; using SmartStore.Services.Authentication; using SmartStore.Services.Authentication.External; using SmartStore.Services.Catalog; @@ -27,14 +26,13 @@ using SmartStore.Services.Orders; using SmartStore.Services.Seo; using SmartStore.Services.Tax; +using SmartStore.Utilities; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Plugins; using SmartStore.Web.Framework.Security; using SmartStore.Web.Framework.UI.Captcha; using SmartStore.Web.Models.Common; using SmartStore.Web.Models.Customer; -using SmartStore.Core.Logging; -using SmartStore.Web.Framework.Plugins; -using SmartStore.Utilities; namespace SmartStore.Web.Controllers { @@ -393,7 +391,6 @@ public ActionResult Login(bool? checkoutAsGuest) model.CheckoutAsGuest = checkoutAsGuest.HasValue ? checkoutAsGuest.Value : false; model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage; - // codehint: sm-add if (_customerSettings.PrefillLoginUsername.HasValue()) { if (model.UsernamesEnabled) @@ -875,14 +872,14 @@ public ActionResult AccountActivation(string token, string email) { var customer = _customerService.GetCustomerByEmail(email); if (customer == null) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Email"); var cToken = customer.GetAttribute(SystemCustomerAttributeNames.AccountActivationToken); if (String.IsNullOrEmpty(cToken)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); if (!cToken.Equals(token, StringComparison.InvariantCultureIgnoreCase)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); //activate user account customer.Active = true; @@ -1381,11 +1378,11 @@ public ActionResult UserAgreement(Guid id /* orderItemId */) var orderItem = _orderService.GetOrderItemByGuid(id); if (orderItem == null) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Guid"); var product = orderItem.Product; if (product == null || !product.HasUserAgreement) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Product"); var model = new UserAgreementModel(); model.UserAgreementText = product.UserAgreementText; @@ -1637,14 +1634,14 @@ public ActionResult PasswordRecoveryConfirm(string token, string email) { var customer = _customerService.GetCustomerByEmail(email); if (customer == null ) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Email"); var cPrt = customer.GetAttribute(SystemCustomerAttributeNames.PasswordRecoveryToken); if (String.IsNullOrEmpty(cPrt)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); if (!cPrt.Equals(token, StringComparison.InvariantCultureIgnoreCase)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); var model = new PasswordRecoveryConfirmModel(); return View(model); @@ -1656,14 +1653,14 @@ public ActionResult PasswordRecoveryConfirmPOST(string token, string email, Pass { var customer = _customerService.GetCustomerByEmail(email); if (customer == null) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Email"); var cPrt = customer.GetAttribute(SystemCustomerAttributeNames.PasswordRecoveryToken); if (String.IsNullOrEmpty(cPrt)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); if (!cPrt.Equals(token, StringComparison.InvariantCultureIgnoreCase)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); if (ModelState.IsValid) { From 48d44f149117a63c8aae516998e452a44648c952 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 24 Jun 2015 13:05:27 +0200 Subject: [PATCH 0016/1074] #702 Facebook external authentication suitable for multi-stores --- changelog.md | 1 + .../ExternalAuthFacebookController.cs | 67 +++++++++++-------- .../Core/FacebookProviderAuthorizer.cs | 38 ++++++++--- .../DependencyRegistrar.cs | 3 - .../SmartStore.FacebookAuth/Description.txt | 2 +- .../FacebookExternalAuthMethod.cs | 8 ++- .../Models/ConfigurationModel.cs | 1 + .../SmartStore.FacebookAuth/RouteProvider.cs | 3 +- .../ExternalAuthFacebook/Configure.cshtml | 27 +++++--- 9 files changed, 92 insertions(+), 58 deletions(-) diff --git a/changelog.md b/changelog.md index c3d2d7762e..d393151d15 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ * #94 Restrict payment methods to certain shipping methods * #526 Min\max amount option for which the payment method should be offered during checkout * #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" +* #702 Facebook external authentication suitable for multi-stores ## SmartStore.NET 2.2.2 diff --git a/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs b/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs index 386027e411..e0d41c6e42 100644 --- a/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs @@ -1,54 +1,52 @@ using System.Web.Mvc; -using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.FacebookAuth.Core; using SmartStore.FacebookAuth.Models; +using SmartStore.Services; using SmartStore.Services.Authentication.External; -using SmartStore.Services.Configuration; using SmartStore.Services.Security; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Settings; namespace SmartStore.FacebookAuth.Controllers { //[UnitOfWork] public class ExternalAuthFacebookController : PluginControllerBase { - private readonly ISettingService _settingService; - private readonly FacebookExternalAuthSettings _facebookExternalAuthSettings; private readonly IOAuthProviderFacebookAuthorizer _oAuthProviderFacebookAuthorizer; private readonly IOpenAuthenticationService _openAuthenticationService; private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; - private readonly IStoreContext _storeContext; - private readonly IPermissionService _permissionService; + private readonly ICommonServices _commonServices; - public ExternalAuthFacebookController(ISettingService settingService, - FacebookExternalAuthSettings facebookExternalAuthSettings, + public ExternalAuthFacebookController( IOAuthProviderFacebookAuthorizer oAuthProviderFacebookAuthorizer, IOpenAuthenticationService openAuthenticationService, ExternalAuthenticationSettings externalAuthenticationSettings, - IStoreContext storeContext, - IPermissionService permissionService) + ICommonServices commonServices) { - this._settingService = settingService; - this._facebookExternalAuthSettings = facebookExternalAuthSettings; this._oAuthProviderFacebookAuthorizer = oAuthProviderFacebookAuthorizer; this._openAuthenticationService = openAuthenticationService; this._externalAuthenticationSettings = externalAuthenticationSettings; - this._storeContext = storeContext; - this._permissionService = permissionService; + this._commonServices = commonServices; } [AdminAuthorize] [ChildActionOnly] public ActionResult Configure() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods)) return Content("Access denied"); var model = new ConfigurationModel(); - model.ClientKeyIdentifier = _facebookExternalAuthSettings.ClientKeyIdentifier; - model.ClientSecret = _facebookExternalAuthSettings.ClientSecret; + int storeScope = this.GetActiveStoreScopeConfiguration(_commonServices.StoreService, _commonServices.WorkContext); + var settings = _commonServices.Settings.LoadSetting(storeScope); + + model.ClientKeyIdentifier = settings.ClientKeyIdentifier; + model.ClientSecret = settings.ClientSecret; + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, _commonServices.Settings); return View(model); } @@ -56,20 +54,27 @@ public ActionResult Configure() [HttpPost] [AdminAuthorize] [ChildActionOnly] - public ActionResult Configure(ConfigurationModel model) + public ActionResult Configure(ConfigurationModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods)) return Content("Access denied"); if (!ModelState.IsValid) return Configure(); - - //save settings - _facebookExternalAuthSettings.ClientKeyIdentifier = model.ClientKeyIdentifier; - _facebookExternalAuthSettings.ClientSecret = model.ClientSecret; - _settingService.SaveSetting(_facebookExternalAuthSettings); - - return View(model); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + int storeScope = this.GetActiveStoreScopeConfiguration(_commonServices.StoreService, _commonServices.WorkContext); + var settings = _commonServices.Settings.LoadSetting(storeScope); + + settings.ClientKeyIdentifier = model.ClientKeyIdentifier; + settings.ClientSecret = model.ClientSecret; + + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, _commonServices.Settings); + _commonServices.Settings.ClearCache(); + + NotifySuccess(_commonServices.Localization.GetResource("Admin.Common.DataSuccessfullySaved")); + + return Configure(); } [ChildActionOnly] @@ -81,7 +86,7 @@ public ActionResult PublicInfo() [NonAction] private ActionResult LoginInternal(string returnUrl, bool verifyResponse) { - var processor = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName("SmartStore.FacebookAuth", _storeContext.CurrentStore.Id); + var processor = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName(Provider.SystemName, _commonServices.StoreContext.CurrentStore.Id); if (processor == null || !processor.IsMethodActive(_externalAuthenticationSettings)) { throw new SmartException("Facebook module cannot be loaded"); @@ -122,8 +127,12 @@ private ActionResult LoginInternal(string returnUrl, bool verifyResponse) break; } - if (result.Result != null) return result.Result; - return HttpContext.Request.IsAuthenticated ? new RedirectResult(!string.IsNullOrEmpty(returnUrl) ? returnUrl : "~/") : new RedirectResult(Url.LogOn(returnUrl)); + if (result.Result != null) + return result.Result; + + return HttpContext.Request.IsAuthenticated ? + new RedirectResult(!string.IsNullOrEmpty(returnUrl) ? returnUrl : "~/") : + new RedirectResult(Url.LogOn(returnUrl)); } public ActionResult Login(string returnUrl) diff --git a/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs b/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs index 6da9e37086..34eabdbffc 100644 --- a/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs @@ -8,8 +8,8 @@ using System.Web.Mvc; using DotNetOpenAuth.AspNet; using DotNetOpenAuth.AspNet.Clients; -using SmartStore.Core; using SmartStore.Core.Domain.Customers; +using SmartStore.Services; using SmartStore.Services.Authentication.External; namespace SmartStore.FacebookAuth.Core @@ -21,9 +21,9 @@ public class FacebookProviderAuthorizer : IOAuthProviderFacebookAuthorizer private readonly IExternalAuthorizer _authorizer; private readonly IOpenAuthenticationService _openAuthenticationService; private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; - private readonly FacebookExternalAuthSettings _facebookExternalAuthSettings; private readonly HttpContextBase _httpContext; - private readonly IWebHelper _webHelper; + private readonly ICommonServices _commonServices; + private FacebookClient _facebookApplication; #endregion @@ -33,16 +33,14 @@ public class FacebookProviderAuthorizer : IOAuthProviderFacebookAuthorizer public FacebookProviderAuthorizer(IExternalAuthorizer authorizer, IOpenAuthenticationService openAuthenticationService, ExternalAuthenticationSettings externalAuthenticationSettings, - FacebookExternalAuthSettings facebookExternalAuthSettings, HttpContextBase httpContext, - IWebHelper webHelper) + ICommonServices commonServices) { this._authorizer = authorizer; this._openAuthenticationService = openAuthenticationService; this._externalAuthenticationSettings = externalAuthenticationSettings; - this._facebookExternalAuthSettings = facebookExternalAuthSettings; this._httpContext = httpContext; - this._webHelper = webHelper; + this._commonServices = commonServices; } #endregion @@ -51,7 +49,17 @@ public FacebookProviderAuthorizer(IExternalAuthorizer authorizer, private FacebookClient FacebookApplication { - get { return _facebookApplication ?? (_facebookApplication = new FacebookClient(_facebookExternalAuthSettings.ClientKeyIdentifier, _facebookExternalAuthSettings.ClientSecret)); } + get + { + if (_facebookApplication == null) + { + var settings = _commonServices.Settings.LoadSetting(_commonServices.StoreContext.CurrentStore.Id); + + _facebookApplication = new FacebookClient(settings.ClientKeyIdentifier, settings.ClientSecret); + } + + return _facebookApplication; + } } private AuthorizeState VerifyAuthentication(string returnUrl) @@ -91,9 +99,12 @@ private void ParseClaims(AuthenticationResult authenticationResult, OAuthAuthent { var claims = new UserClaims(); claims.Contact = new ContactClaims(); + if (authenticationResult.ExtraData.ContainsKey("username")) claims.Contact.Email = authenticationResult.ExtraData["username"]; + claims.Name = new NameClaims(); + if (authenticationResult.ExtraData.ContainsKey("name")) { var name = authenticationResult.ExtraData["name"]; @@ -122,7 +133,7 @@ private AuthorizeState RequestAuthentication(string returnUrl) private Uri GenerateLocalCallbackUri() { - string url = string.Format("{0}Plugins/SmartStore.FacebookAuth/logincallback/", _webHelper.GetStoreLocation()); + string url = string.Format("{0}Plugins/SmartStore.FacebookAuth/logincallback/", _commonServices.WebHelper.GetStoreLocation()); return new Uri(url); } @@ -131,10 +142,14 @@ private Uri GenerateServiceLoginUrl() //code copied from DotNetOpenAuth.AspNet.Clients.FacebookClient file var builder = new UriBuilder("https://www.facebook.com/dialog/oauth"); var args = new Dictionary(); - args.Add("client_id", _facebookExternalAuthSettings.ClientKeyIdentifier); + var settings = _commonServices.Settings.LoadSetting(_commonServices.StoreContext.CurrentStore.Id); + + args.Add("client_id", settings.ClientKeyIdentifier); args.Add("redirect_uri", GenerateLocalCallbackUri().AbsoluteUri); args.Add("scope", "email"); + AppendQueryArgs(builder, args); + return builder.Uri; } @@ -152,6 +167,7 @@ private void AppendQueryArgs(UriBuilder builder, IEnumerable> args) { if (!args.Any>()) @@ -169,7 +185,9 @@ private string CreateQueryString(IEnumerable> args) builder.Length--; return builder.ToString(); } + private readonly string[] UriRfc3986CharsToEscape = new string[] { "!", "*", "'", "(", ")" }; + private string EscapeUriDataStringRfc3986(string value) { StringBuilder builder = new StringBuilder(Uri.EscapeDataString(value)); diff --git a/src/Plugins/SmartStore.FacebookAuth/DependencyRegistrar.cs b/src/Plugins/SmartStore.FacebookAuth/DependencyRegistrar.cs index 69f5a94064..ef4c32cf34 100644 --- a/src/Plugins/SmartStore.FacebookAuth/DependencyRegistrar.cs +++ b/src/Plugins/SmartStore.FacebookAuth/DependencyRegistrar.cs @@ -1,7 +1,4 @@ -using System; -using System.Linq.Expressions; using Autofac; -using Autofac.Integration.Mvc; using SmartStore.Core.Infrastructure; using SmartStore.Core.Infrastructure.DependencyManagement; using SmartStore.FacebookAuth.Core; diff --git a/src/Plugins/SmartStore.FacebookAuth/Description.txt b/src/Plugins/SmartStore.FacebookAuth/Description.txt index 081bf95dd1..f7cc05d671 100644 --- a/src/Plugins/SmartStore.FacebookAuth/Description.txt +++ b/src/Plugins/SmartStore.FacebookAuth/Description.txt @@ -1,7 +1,7 @@ FriendlyName: Facebook SystemName: SmartStore.FacebookAuth Group: Security -Version: 2.2.0 +Version: 2.2.0.1 MinAppVersion: 2.2.0 DisplayOrder: 5 FileName: SmartStore.FacebookAuth.dll diff --git a/src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthMethod.cs b/src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthMethod.cs index 2c4c183c76..d3a0ea7b26 100644 --- a/src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthMethod.cs +++ b/src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthMethod.cs @@ -1,5 +1,6 @@ using System.Web.Routing; using SmartStore.Core.Plugins; +using SmartStore.FacebookAuth.Core; using SmartStore.Services.Authentication.External; using SmartStore.Services.Localization; @@ -11,8 +12,10 @@ namespace SmartStore.FacebookAuth public class FacebookExternalAuthMethod : BasePlugin, IExternalAuthenticationMethod, IConfigurable { #region Fields + private readonly FacebookExternalAuthSettings _facebookExternalAuthSettings; private readonly ILocalizationService _localizationService; + #endregion #region Ctor @@ -37,7 +40,7 @@ public void GetConfigurationRoute(out string actionName, out string controllerNa { actionName = "Configure"; controllerName = "ExternalAuthFacebook"; - routeValues = new RouteValueDictionary(new { Namespaces = "SmartStore.FacebookAuth.Controllers", area = "SmartStore.FacebookAuth" }); + routeValues = new RouteValueDictionary(new { Namespaces = "SmartStore.FacebookAuth.Controllers", area = Provider.SystemName }); } /// @@ -50,7 +53,7 @@ public void GetPublicInfoRoute(out string actionName, out string controllerName, { actionName = "PublicInfo"; controllerName = "ExternalAuthFacebook"; - routeValues = new RouteValueDictionary(new { Namespaces = "SmartStore.FacebookAuth.Controllers", area = "SmartStore.FacebookAuth" }); + routeValues = new RouteValueDictionary(new { Namespaces = "SmartStore.FacebookAuth.Controllers", area = Provider.SystemName }); } /// @@ -68,7 +71,6 @@ public override void Uninstall() { //locales _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.ExternalAuth.Facebook", false); base.Uninstall(); } diff --git a/src/Plugins/SmartStore.FacebookAuth/Models/ConfigurationModel.cs b/src/Plugins/SmartStore.FacebookAuth/Models/ConfigurationModel.cs index 5c78e61896..4676db9b6b 100644 --- a/src/Plugins/SmartStore.FacebookAuth/Models/ConfigurationModel.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Models/ConfigurationModel.cs @@ -7,6 +7,7 @@ public class ConfigurationModel : ModelBase { [SmartResourceDisplayName("Plugins.ExternalAuth.Facebook.ClientKeyIdentifier")] public string ClientKeyIdentifier { get; set; } + [SmartResourceDisplayName("Plugins.ExternalAuth.Facebook.ClientSecret")] public string ClientSecret { get; set; } } diff --git a/src/Plugins/SmartStore.FacebookAuth/RouteProvider.cs b/src/Plugins/SmartStore.FacebookAuth/RouteProvider.cs index 1326663260..0353105d2b 100644 --- a/src/Plugins/SmartStore.FacebookAuth/RouteProvider.cs +++ b/src/Plugins/SmartStore.FacebookAuth/RouteProvider.cs @@ -1,5 +1,6 @@ using System.Web.Mvc; using System.Web.Routing; +using SmartStore.FacebookAuth.Core; using SmartStore.Web.Framework.Mvc.Routes; namespace SmartStore.FacebookAuth @@ -13,7 +14,7 @@ public void RegisterRoutes(RouteCollection routes) new { controller = "ExternalAuthFacebook" }, new[] { "SmartStore.FacebookAuth.Controllers" } ) - .DataTokens["area"] = "SmartStore.FacebookAuth"; + .DataTokens["area"] = Provider.SystemName; } public int Priority { diff --git a/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/Configure.cshtml b/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/Configure.cshtml index 94d69f5d8a..60dc28cea5 100644 --- a/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/Configure.cshtml +++ b/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/Configure.cshtml @@ -3,23 +3,29 @@ } @model SmartStore.FacebookAuth.Models.ConfigurationModel @using SmartStore.Web.Framework; + +
+ + @Html.Raw(T("Plugins.ExternalAuth.Facebook.AdminInstruction")) +
+ +
+ +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@Html.ValidationSummary(false) + +
+ @using (Html.BeginForm()) { - - - @@ -28,7 +34,7 @@ @Html.SmartLabelFor(model => model.ClientSecret) @@ -43,5 +49,4 @@
-
- - @Html.Raw(T("Plugins.ExternalAuth.Facebook.AdminInstruction")) -
-
@Html.SmartLabelFor(model => model.ClientKeyIdentifier) - @Html.EditorFor(model => model.ClientKeyIdentifier) + @Html.SettingEditorFor(model => model.ClientKeyIdentifier) @Html.ValidationMessageFor(model => model.ClientKeyIdentifier)
- @Html.EditorFor(model => model.ClientSecret) + @Html.SettingEditorFor(model => model.ClientSecret) @Html.ValidationMessageFor(model => model.ClientSecret)
- } \ No newline at end of file From 4ce968c0df4a7d96adb8649152084a3302546f5a Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 24 Jun 2015 13:48:08 +0200 Subject: [PATCH 0017/1074] Minor change --- changelog.md | 2 +- .../ExternalAuthFacebookController.cs | 25 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/changelog.md b/changelog.md index d393151d15..6bc68c22a9 100644 --- a/changelog.md +++ b/changelog.md @@ -8,7 +8,7 @@ * #94 Restrict payment methods to certain shipping methods * #526 Min\max amount option for which the payment method should be offered during checkout * #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" -* #702 Facebook external authentication suitable for multi-stores +* #702 Facebook and Twitter external authentication suitable for multi-stores ## SmartStore.NET 2.2.2 diff --git a/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs b/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs index e0d41c6e42..1ed000f3bb 100644 --- a/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs @@ -30,13 +30,22 @@ public ExternalAuthFacebookController( this._externalAuthenticationSettings = externalAuthenticationSettings; this._commonServices = commonServices; } + + private bool HasPermission(bool notify = true) + { + bool hasPermission = _commonServices.Permissions.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods); + + if (notify && !hasPermission) + NotifyError(_commonServices.Localization.GetResource("Admin.AccessDenied.Description")); + + return hasPermission; + } - [AdminAuthorize] - [ChildActionOnly] + [AdminAuthorize, ChildActionOnly] public ActionResult Configure() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods)) - return Content("Access denied"); + if (!HasPermission(false)) + return AccessDeniedPartialView(); var model = new ConfigurationModel(); int storeScope = this.GetActiveStoreScopeConfiguration(_commonServices.StoreService, _commonServices.WorkContext); @@ -51,13 +60,11 @@ public ActionResult Configure() return View(model); } - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] + [HttpPost, AdminAuthorize, ChildActionOnly] public ActionResult Configure(ConfigurationModel model, FormCollection form) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods)) - return Content("Access denied"); + if (!HasPermission(false)) + return Configure(); if (!ModelState.IsValid) return Configure(); From 35f0b3a610979d93f942e42e711276698493f898 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 24 Jun 2015 14:49:49 +0200 Subject: [PATCH 0018/1074] Resolves #692 System warnings: Add test for sitemap reachability --- ...06211043073_PaymentShippingRestrictions.cs | 9 + .../Controllers/CommonController.cs | 321 ++++++++++-------- 2 files changed, 196 insertions(+), 134 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs index 99a1467c9d..cc83f0e114 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs @@ -56,6 +56,15 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "The request could not be processed.
Controller: {0}, Action: {1}, Reason: {2}.", "Die Anfrage konnte nicht ausgefhrt werden.
Controller: {0}, Action: {1}, Grund: {2}."); + builder.AddOrUpdate("Admin.System.Warnings.SitemapReachable.OK", + "The sitemap for the store is reachable.", + "Die Sitemap fr den Shop ist erreichbar."); + + builder.AddOrUpdate("Admin.System.Warnings.SitemapReachable.Wrong", + "The sitemap for the store is not reachable.", + "Die Sitemap fr den Shop ist nicht erreichbar."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", "Select customer roles, shipping methods, countries and order amounts for which you do not want to offer this payment method.", "Whlen Sie Kundengruppen, Versandarten, Lnder und Bestellwerte, bei denen Sie diese Zahlungsmethode nicht anbieten mchten."); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs index 3b070a3d9b..82b4cffdee 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs @@ -68,7 +68,7 @@ public class CommonController : AdminControllerBase private readonly Lazy _menuPublisher; private readonly Lazy _pluginFinder; private readonly IGenericAttributeService _genericAttributeService; - private readonly ICommonServices _services; + private readonly ICommonServices _commonServices; private readonly Func _cache; private readonly static object s_lock = new object(); @@ -95,7 +95,7 @@ public CommonController( Lazy menuPublisher, Lazy pluginFinder, IGenericAttributeService genericAttributeService, - ICommonServices services, + ICommonServices commonServices, Func cache) { this._paymentService = paymentService; @@ -115,7 +115,7 @@ public CommonController( this._menuPublisher = menuPublisher; this._pluginFinder = pluginFinder; this._genericAttributeService = genericAttributeService; - this._services = services; + this._commonServices = commonServices; this._cache = cache; } @@ -128,11 +128,11 @@ public CommonController( [ChildActionOnly] public ActionResult Navbar() { - var currentCustomer = _services.WorkContext.CurrentCustomer; + var currentCustomer = _commonServices.WorkContext.CurrentCustomer; - ViewBag.UserName = _services.Settings.LoadSetting().UsernamesEnabled ? currentCustomer.Username : currentCustomer.Email; - ViewBag.Stores = _services.StoreService.GetAllStores(); - if (_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + ViewBag.UserName = _commonServices.Settings.LoadSetting().UsernamesEnabled ? currentCustomer.Username : currentCustomer.Email; + ViewBag.Stores = _commonServices.StoreService.GetAllStores(); + if (_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) { ViewBag.CheckUpdateResult = AsyncRunner.RunSync(() => CheckUpdateAsync(false)); } @@ -143,10 +143,10 @@ public ActionResult Navbar() [ChildActionOnly] public ActionResult Menu() { - var cacheManager = _services.Cache; + var cacheManager = _commonServices.Cache; - var customerRolesIds = _services.WorkContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); - string cacheKey = string.Format("smartstore.pres.adminmenu.navigation-{0}-{1}", _services.WorkContext.WorkingLanguage.Id, string.Join(",", customerRolesIds)); + var customerRolesIds = _commonServices.WorkContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); + string cacheKey = string.Format("smartstore.pres.adminmenu.navigation-{0}-{1}", _commonServices.WorkContext.WorkingLanguage.Id, string.Join(",", customerRolesIds)); var rootNode = cacheManager.Get(cacheKey, () => { @@ -255,7 +255,7 @@ private bool MenuItemAccessPermitted(MenuItem item) if (_securitySettings.Value.HideAdminMenuItemsBasedOnPermissions && item.PermissionNames.HasValue()) { - var permitted = item.PermissionNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Any(x => _services.Permissions.Authorize(x.Trim())); + var permitted = item.PermissionNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Any(x => _commonServices.Permissions.Authorize(x.Trim())); if (!permitted) { result = false; @@ -284,24 +284,24 @@ public ActionResult CheckUpdateSuppress(string myVersion, string newVersion) public void CheckUpdateSuppressInternal(string myVersion, string newVersion) { var suppressKey = "SuppressUpdateMessage.{0}.{1}".FormatInvariant(myVersion, newVersion); - _genericAttributeService.SaveAttribute(_services.WorkContext.CurrentCustomer, suppressKey, true); - _services.Cache.RemoveByPattern("Common.CheckUpdateResult"); + _genericAttributeService.SaveAttribute(_commonServices.WorkContext.CurrentCustomer, suppressKey, true); + _commonServices.Cache.RemoveByPattern("Common.CheckUpdateResult"); } [NonAction] private async Task CheckUpdateAsync(bool enforce = false, bool forSuppress = false) { var curVersion = SmartStoreVersion.CurrentFullVersion; - var lang = _services.WorkContext.WorkingLanguage.UniqueSeoCode; + var lang = _commonServices.WorkContext.WorkingLanguage.UniqueSeoCode; var cacheKeyPattern = "Common.CheckUpdateResult"; var cacheKey = "{0}.{1}".FormatInvariant(cacheKeyPattern, lang); if (enforce) { - _services.Cache.RemoveByPattern(cacheKeyPattern); + _commonServices.Cache.RemoveByPattern(cacheKeyPattern); } - var result = await _services.Cache.Get(cacheKey, async () => + var result = await _commonServices.Cache.Get(cacheKey, async () => { var noUpdateResult = new CheckUpdateResult { UpdateAvailable = false, LanguageCode = lang, CurrentVersion = curVersion }; @@ -315,7 +315,7 @@ private async Task CheckUpdateAsync(bool enforce = false, boo client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.UserAgent.ParseAdd("SmartStore.NET {0}".FormatInvariant(curVersion)); - client.DefaultRequestHeaders.Add("Authorization-Key", _services.StoreContext.CurrentStore.Url.TrimEnd('/')); + client.DefaultRequestHeaders.Add("Authorization-Key", _commonServices.StoreContext.CurrentStore.Url.TrimEnd('/')); HttpResponseMessage response = await client.GetAsync(url); @@ -331,7 +331,7 @@ private async Task CheckUpdateAsync(bool enforce = false, boo model.CurrentVersion = curVersion; model.LanguageCode = lang; - if (CommonHelper.IsDevEnvironment || !_commonSettings.Value.AutoUpdateEnabled || !_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (CommonHelper.IsDevEnvironment || !_commonSettings.Value.AutoUpdateEnabled || !_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) { model.AutoUpdatePossible = false; } @@ -341,9 +341,9 @@ private async Task CheckUpdateAsync(bool enforce = false, boo if (enforce) { // but ignore user's decision if 'enforce' - _genericAttributeService.SaveAttribute(_services.WorkContext.CurrentCustomer, suppressKey, null); + _genericAttributeService.SaveAttribute(_commonServices.WorkContext.CurrentCustomer, suppressKey, null); } - var showMessage = enforce || _services.WorkContext.CurrentCustomer.GetAttribute(suppressKey, _genericAttributeService).GetValueOrDefault() == false; + var showMessage = enforce || _commonServices.WorkContext.CurrentCustomer.GetAttribute(suppressKey, _genericAttributeService).GetValueOrDefault() == false; if (!showMessage) { return noUpdateResult; @@ -364,7 +364,7 @@ private async Task CheckUpdateAsync(bool enforce = false, boo public ActionResult InstallUpdate(string packageUrl) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); try @@ -385,7 +385,7 @@ public ActionResult InstallUpdate(string packageUrl) } else { - _services.WebHelper.RestartAppDomain(); + _commonServices.WebHelper.RestartAppDomain(); } } @@ -453,12 +453,12 @@ public ActionResult SystemInfo() model.ServerTimeZone = TimeZone.CurrentTimeZone.StandardName; model.ServerLocalTime = DateTime.Now; model.UtcTime = DateTime.UtcNow; - model.HttpHost = _services.WebHelper.ServerVariables("HTTP_HOST"); + model.HttpHost = _commonServices.WebHelper.ServerVariables("HTTP_HOST"); //Environment.GetEnvironmentVariable("USERNAME"); try { - var mbSize = _services.DbContext.SqlQuery("Select Sum(size)/128.0 From sysfiles").FirstOrDefault(); + var mbSize = _commonServices.DbContext.SqlQuery("Select Sum(size)/128.0 From sysfiles").FirstOrDefault(); model.DatabaseSize = Convert.ToDouble(mbSize); } catch (Exception) { } @@ -468,7 +468,7 @@ public ActionResult SystemInfo() if (DataSettings.Current.IsValid()) { model.DataProviderFriendlyName = DataSettings.Current.ProviderFriendlyName; - model.ShrinkDatabaseEnabled = _services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance) && DataSettings.Current.IsSqlServer; + model.ShrinkDatabaseEnabled = _commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance) && DataSettings.Current.IsSqlServer; } } catch (Exception) { } @@ -498,33 +498,70 @@ public ActionResult Warnings() var model = new List(); //store URL - var currentStoreUrl = _services.StoreContext.CurrentStore.Url.EnsureEndsWith("/"); - if (currentStoreUrl.HasValue() && (currentStoreUrl.IsCaseInsensitiveEqual(_services.WebHelper.GetStoreLocation(false)) || currentStoreUrl.IsCaseInsensitiveEqual(_services.WebHelper.GetStoreLocation(true)))) - model.Add(new SystemWarningModel() - { - Level = SystemWarningLevel.Pass, - Text = _localizationService.GetResource("Admin.System.Warnings.URL.Match") - }); - else - model.Add(new SystemWarningModel() - { - Level = SystemWarningLevel.Warning, - Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.URL.NoMatch"), currentStoreUrl, _services.WebHelper.GetStoreLocation(false)) - }); + var storeUrl = _commonServices.StoreContext.CurrentStore.Url.EnsureEndsWith("/"); + if (storeUrl.HasValue() && (storeUrl.IsCaseInsensitiveEqual(_commonServices.WebHelper.GetStoreLocation(false)) || storeUrl.IsCaseInsensitiveEqual(_commonServices.WebHelper.GetStoreLocation(true)))) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Pass, + Text = _localizationService.GetResource("Admin.System.Warnings.URL.Match") + }); + } + else + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Warning, + Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.URL.NoMatch"), storeUrl, _commonServices.WebHelper.GetStoreLocation(false)) + }); + } + + // sitemap reachability + var sitemapReachable = false; + try + { + var sitemapUrl = Url.RouteUrl("SitemapSEO", (object)null, _securitySettings.Value.ForceSslForAllPages ? "https" : "http"); + var request = (HttpWebRequest)WebRequest.Create(sitemapUrl); + request.Method = "HEAD"; + request.Timeout = 15000; + + using (var response = (HttpWebResponse)request.GetResponse()) + { + sitemapReachable = (response.StatusCode == HttpStatusCode.OK); + } + } + catch (WebException) { } + if (sitemapReachable) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Pass, + Text = _localizationService.GetResource("Admin.System.Warnings.SitemapReachable.OK") + }); + } + else + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Warning, + Text = _localizationService.GetResource("Admin.System.Warnings.SitemapReachable.Wrong") + }); + } //primary exchange rate currency var perCurrency = _currencyService.Value.GetCurrencyById(_currencySettings.Value.PrimaryExchangeRateCurrencyId); if (perCurrency != null) { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Pass, Text = _localizationService.GetResource("Admin.System.Warnings.ExchangeCurrency.Set"), }); + if (perCurrency.Rate != 1) { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Fail, Text = _localizationService.GetResource("Admin.System.Warnings.ExchangeCurrency.Rate1") @@ -533,7 +570,7 @@ public ActionResult Warnings() } else { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Fail, Text = _localizationService.GetResource("Admin.System.Warnings.ExchangeCurrency.NotSet") @@ -544,7 +581,7 @@ public ActionResult Warnings() var pscCurrency = _currencyService.Value.GetCurrencyById(_currencySettings.Value.PrimaryStoreCurrencyId); if (pscCurrency != null) { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Pass, Text = _localizationService.GetResource("Admin.System.Warnings.PrimaryCurrency.Set"), @@ -552,7 +589,7 @@ public ActionResult Warnings() } else { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Fail, Text = _localizationService.GetResource("Admin.System.Warnings.PrimaryCurrency.NotSet") @@ -564,7 +601,7 @@ public ActionResult Warnings() var bWeight = _measureService.Value.GetMeasureWeightById(_measureSettings.Value.BaseWeightId); if (bWeight != null) { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Pass, Text = _localizationService.GetResource("Admin.System.Warnings.DefaultWeight.Set"), @@ -572,7 +609,7 @@ public ActionResult Warnings() if (bWeight.Ratio != 1) { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Fail, Text = _localizationService.GetResource("Admin.System.Warnings.DefaultWeight.Ratio1") @@ -581,7 +618,7 @@ public ActionResult Warnings() } else { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Fail, Text = _localizationService.GetResource("Admin.System.Warnings.DefaultWeight.NotSet") @@ -593,7 +630,7 @@ public ActionResult Warnings() var bDimension = _measureService.Value.GetMeasureDimensionById(_measureSettings.Value.BaseDimensionId); if (bDimension != null) { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Pass, Text = _localizationService.GetResource("Admin.System.Warnings.DefaultDimension.Set"), @@ -601,7 +638,7 @@ public ActionResult Warnings() if (bDimension.Ratio != 1) { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Fail, Text = _localizationService.GetResource("Admin.System.Warnings.DefaultDimension.Ratio1") @@ -610,7 +647,7 @@ public ActionResult Warnings() } else { - model.Add(new SystemWarningModel() + model.Add(new SystemWarningModel { Level = SystemWarningLevel.Fail, Text = _localizationService.GetResource("Admin.System.Warnings.DefaultDimension.NotSet") @@ -619,91 +656,107 @@ public ActionResult Warnings() // shipping rate coputation methods if (_shippingService.Value.LoadActiveShippingRateComputationMethods() - .Where(x => x.Value.ShippingRateComputationMethodType == ShippingRateComputationMethodType.Offline) - .Count() > 1) - model.Add(new SystemWarningModel() - { - Level = SystemWarningLevel.Warning, - Text = _localizationService.GetResource("Admin.System.Warnings.Shipping.OnlyOneOffline") - }); + .Where(x => x.Value.ShippingRateComputationMethodType == ShippingRateComputationMethodType.Offline) + .Count() > 1) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Warning, + Text = _localizationService.GetResource("Admin.System.Warnings.Shipping.OnlyOneOffline") + }); + } //payment methods - if (_paymentService.Value.LoadActivePaymentMethods() - .Count() > 0) - model.Add(new SystemWarningModel() - { - Level = SystemWarningLevel.Pass, - Text = _localizationService.GetResource("Admin.System.Warnings.PaymentMethods.OK") - }); - else - model.Add(new SystemWarningModel() - { - Level = SystemWarningLevel.Fail, - Text = _localizationService.GetResource("Admin.System.Warnings.PaymentMethods.NoActive") - }); + if (_paymentService.Value.LoadActivePaymentMethods().Count() > 0) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Pass, + Text = _localizationService.GetResource("Admin.System.Warnings.PaymentMethods.OK") + }); + } + else + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Fail, + Text = _localizationService.GetResource("Admin.System.Warnings.PaymentMethods.NoActive") + }); + } //incompatible plugins - if (PluginManager.IncompatiblePlugins != null) - foreach (var pluginName in PluginManager.IncompatiblePlugins) - model.Add(new SystemWarningModel() - { - Level = SystemWarningLevel.Warning, - Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.IncompatiblePlugin"), pluginName ) - }); + if (PluginManager.IncompatiblePlugins != null) + { + foreach (var pluginName in PluginManager.IncompatiblePlugins) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Warning, + Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.IncompatiblePlugin"), pluginName) + }); + } + } //validate write permissions (the same procedure like during installation) var dirPermissionsOk = true; - var dirsToCheck = FilePermissionHelper.GetDirectoriesWrite(_services.WebHelper); - foreach (string dir in dirsToCheck) - if (!FilePermissionHelper.CheckPermissions(dir, false, true, true, false)) - { - model.Add(new SystemWarningModel() - { - Level = SystemWarningLevel.Warning, - Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.DirectoryPermission.Wrong"), WindowsIdentity.GetCurrent().Name, dir) - }); - dirPermissionsOk = false; - } - if (dirPermissionsOk) - model.Add(new SystemWarningModel() - { - Level = SystemWarningLevel.Pass, - Text = _localizationService.GetResource("Admin.System.Warnings.DirectoryPermission.OK") - }); + var dirsToCheck = FilePermissionHelper.GetDirectoriesWrite(_commonServices.WebHelper); + foreach (string dir in dirsToCheck) + { + if (!FilePermissionHelper.CheckPermissions(dir, false, true, true, false)) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Warning, + Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.DirectoryPermission.Wrong"), WindowsIdentity.GetCurrent().Name, dir) + }); + dirPermissionsOk = false; + } + } + if (dirPermissionsOk) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Pass, + Text = _localizationService.GetResource("Admin.System.Warnings.DirectoryPermission.OK") + }); + } var filePermissionsOk = true; - var filesToCheck = FilePermissionHelper.GetFilesWrite(_services.WebHelper); - foreach (string file in filesToCheck) - if (!FilePermissionHelper.CheckPermissions(file, false, true, true, true)) - { - model.Add(new SystemWarningModel - { - Level = SystemWarningLevel.Warning, - Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.FilePermission.Wrong"), WindowsIdentity.GetCurrent().Name, file) - }); - filePermissionsOk = false; - } - if (filePermissionsOk) - model.Add(new SystemWarningModel - { - Level = SystemWarningLevel.Pass, - Text = _localizationService.GetResource("Admin.System.Warnings.FilePermission.OK") - }); - + var filesToCheck = FilePermissionHelper.GetFilesWrite(_commonServices.WebHelper); + foreach (string file in filesToCheck) + { + if (!FilePermissionHelper.CheckPermissions(file, false, true, true, true)) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Warning, + Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.FilePermission.Wrong"), WindowsIdentity.GetCurrent().Name, file) + }); + filePermissionsOk = false; + } + } + if (filePermissionsOk) + { + model.Add(new SystemWarningModel + { + Level = SystemWarningLevel.Pass, + Text = _localizationService.GetResource("Admin.System.Warnings.FilePermission.OK") + }); + } return View(model); } public ActionResult ShrinkDatabase() { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); try { if (DataSettings.Current.IsSqlServer) { - _services.DbContext.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); + _commonServices.DbContext.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); NotifySuccess(_localizationService.GetResource("Common.ShrinkDatabaseSuccessful")); } } @@ -717,7 +770,7 @@ public ActionResult ShrinkDatabase() public ActionResult Maintenance() { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); var model = new MaintenanceModel(); @@ -738,7 +791,7 @@ public ActionResult Maintenance() [FormValueRequired("delete-image-cache")] public ActionResult MaintenanceDeleteImageCache() { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); _imageCache.Value.DeleteCachedImages(); @@ -750,7 +803,7 @@ public ActionResult MaintenanceDeleteImageCache() [FormValueRequired("delete-guests")] public ActionResult MaintenanceDeleteGuests(MaintenanceModel model) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); DateTime? startDateValue = (model.DeleteGuests.StartDate == null) ? null @@ -768,7 +821,7 @@ public ActionResult MaintenanceDeleteGuests(MaintenanceModel model) [FormValueRequired("delete-exported-files")] public ActionResult MaintenanceDeleteFiles(MaintenanceModel model) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); DateTime? startDateValue = (model.DeleteExportedFiles.StartDate == null) ? null @@ -812,7 +865,7 @@ public ActionResult MaintenanceDeleteFiles(MaintenanceModel model) [FormValueRequired("execute-sql-query")] public ActionResult MaintenanceExecuteSql(MaintenanceModel model) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); if (model.SqlQuery.HasValue()) @@ -837,9 +890,9 @@ public ActionResult MaintenanceExecuteSql(MaintenanceModel model) public ActionResult LanguageSelector() { var model = new LanguageSelectorModel(); - model.CurrentLanguage = _services.WorkContext.WorkingLanguage.ToModel(); + model.CurrentLanguage = _commonServices.WorkContext.WorkingLanguage.ToModel(); model.AvailableLanguages = _languageService - .GetAllLanguages(storeId: _services.StoreContext.CurrentStore.Id) + .GetAllLanguages(storeId: _commonServices.StoreContext.CurrentStore.Id) .Select(x => x.ToModel()) .ToList(); return PartialView(model); @@ -849,14 +902,14 @@ public ActionResult LanguageSelected(int customerlanguage) var language = _languageService.GetLanguageById(customerlanguage); if (language != null) { - _services.WorkContext.WorkingLanguage = language; + _commonServices.WorkContext.WorkingLanguage = language; } return Content(_localizationService.GetResource("Admin.Common.DataEditSuccess")); } public ActionResult ClearCache(string previousUrl) { - var cacheManager = _services.Cache; + var cacheManager = _commonServices.Cache; cacheManager.Clear(); cacheManager = _cache("aspnet"); @@ -872,10 +925,10 @@ public ActionResult ClearCache(string previousUrl) public ActionResult RestartApplication(string previousUrl) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); - _services.WebHelper.RestartAppDomain(); + _commonServices.WebHelper.RestartAppDomain(); if (previousUrl.HasValue()) return Redirect(previousUrl); @@ -889,7 +942,7 @@ public ActionResult RestartApplication(string previousUrl) public ActionResult SeNames() { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); var model = new UrlRecordListModel(); @@ -899,7 +952,7 @@ public ActionResult SeNames() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult SeNames(GridCommand command, UrlRecordListModel model) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); var urlRecords = _urlRecordService.GetAllUrlRecords(model.SeName, command.Page - 1, command.PageSize); @@ -938,7 +991,7 @@ public ActionResult SeNames(GridCommand command, UrlRecordListModel model) [HttpPost] public ActionResult DeleteSelectedSeNames(ICollection selectedIds) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); if (selectedIds != null) @@ -973,10 +1026,10 @@ public ActionResult GenericAttributes(string entityName, int entityId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributesSelect(string entityName, int entityId, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) return AccessDeniedView(); - var storeId = _services.StoreContext.CurrentStore.Id; + var storeId = _commonServices.StoreContext.CurrentStore.Id; ViewBag.StoreId = storeId; var model = new List(); @@ -1011,7 +1064,7 @@ public ActionResult GenericAttributesSelect(string entityName, int entityId, Gri [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeAdd(GenericAttributeModel model, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) return AccessDeniedView(); model.Key = model.Key.TrimSafe(); @@ -1024,7 +1077,7 @@ public ActionResult GenericAttributeAdd(GenericAttributeModel model, GridCommand return Content(modelStateErrorMessages.FirstOrDefault()); } - var storeId = _services.StoreContext.CurrentStore.Id; + var storeId = _commonServices.StoreContext.CurrentStore.Id; var attr = _genericAttributeService.GetAttribute(model.EntityName, model.EntityId, model.Key, storeId); if (attr == null) @@ -1050,7 +1103,7 @@ public ActionResult GenericAttributeAdd(GenericAttributeModel model, GridCommand [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeUpdate(GenericAttributeModel model, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) return AccessDeniedView(); model.Key = model.Key.TrimSafe(); @@ -1063,7 +1116,7 @@ public ActionResult GenericAttributeUpdate(GenericAttributeModel model, GridComm return Content(modelStateErrorMessages.FirstOrDefault()); } - var storeId = _services.StoreContext.CurrentStore.Id; + var storeId = _commonServices.StoreContext.CurrentStore.Id; var attr = _genericAttributeService.GetAttributeById(model.Id); // if the key changed, ensure it isn't being used by another attribute @@ -1089,7 +1142,7 @@ public ActionResult GenericAttributeUpdate(GenericAttributeModel model, GridComm [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeDelete(int id, GridCommand command) { - if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) return AccessDeniedView(); var attr = _genericAttributeService.GetAttributeById(id); From 618dd48eaf3f75320286ca4ef845d24c830b7cdf Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 24 Jun 2015 20:59:55 +0200 Subject: [PATCH 0019/1074] Fixed compiler warnings --- .../Controllers/DiscountRulesController.cs | 5 ----- .../Controllers/FeedFroogleController.cs | 4 ---- .../Controllers/OfflinePaymentController.cs | 4 ---- .../Controllers/PayPalExpressController.cs | 8 -------- .../Controllers/PackagingController.cs | 2 -- .../Administration/Controllers/PluginController.cs | 4 ---- .../Administration/Controllers/ProductController.cs | 4 ---- .../Controllers/ScheduleTaskController.cs | 3 --- .../Administration/Controllers/ThemeController.cs | 4 ---- .../SmartStore.Web/Controllers/CatalogController.cs | 12 ------------ .../SmartStore.Web/Controllers/CommonController.cs | 4 ---- .../SmartStore.Web/Controllers/HomeController.cs | 4 ---- .../SmartStore.Web/Controllers/OrderController.cs | 3 --- .../SmartStore.Web/Controllers/ProductController.cs | 5 ----- 14 files changed, 66 deletions(-) diff --git a/src/Plugins/SmartStore.DiscountRules/Controllers/DiscountRulesController.cs b/src/Plugins/SmartStore.DiscountRules/Controllers/DiscountRulesController.cs index c004670e23..2892c3c0b3 100644 --- a/src/Plugins/SmartStore.DiscountRules/Controllers/DiscountRulesController.cs +++ b/src/Plugins/SmartStore.DiscountRules/Controllers/DiscountRulesController.cs @@ -31,13 +31,8 @@ public DiscountRulesController( this._customerService = customerService; this._countryService = countryService; this._storeService = storeService; - - T = NullLocalizer.Instance; } - public Localizer T { get; set; } - - #region Global [NonAction] diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedFroogleController.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedFroogleController.cs index 312ff89ff7..92ac370330 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedFroogleController.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedFroogleController.cs @@ -30,12 +30,8 @@ public FeedFroogleController( _googleService = googleService; _settingService = settingService; _permissionService = permissionService; - - T = NullLocalizer.Instance; } - public Localizer T { get; set; } - private ActionResult RedirectToConfig() { return RedirectToAction("ConfigurePlugin", "Plugin", new { systemName = _googleService.Helper.SystemName, area = "Admin" }); diff --git a/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs b/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs index 468940bc74..d1c5369d54 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs +++ b/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs @@ -33,12 +33,8 @@ public OfflinePaymentController( this._services = services; this._storeService = storeService; this._ctx = ctx; - - T = NullLocalizer.Instance; } - public Localizer T { get; set; } - #region Global [NonAction] diff --git a/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs b/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs index a1e1b10db2..b3af94a0b9 100644 --- a/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs +++ b/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs @@ -78,14 +78,6 @@ public PayPalExpressController( _storeService = storeService; _helper = new PluginHelper(ctx, "SmartStore.PayPal", "Plugins.Payments.PayPalExpress"); - - T = NullLocalizer.Instance; - } - - public Localizer T - { - get; - set; } public SelectList TransactModeValues(TransactMode selected) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PackagingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PackagingController.cs index 65a0c4b1a8..ac947d3c8c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PackagingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PackagingController.cs @@ -30,8 +30,6 @@ public PackagingController(ICommonServices services, IPackageManager packageMana this._themeRegistry = themeRegistry; } - public Localizer T { get; set; } - [ChildActionOnly] public ActionResult UploadPackage(bool isTheme) { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PluginController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PluginController.cs index a997a2cb46..bc697dc796 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PluginController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PluginController.cs @@ -71,16 +71,12 @@ public PluginController(IPluginFinder pluginFinder, this._providerManager = providerManager; this._pluginMediator = pluginMediator; this._commonService = commonService; - - T = NullLocalizer.Instance; } #endregion  #region Utilities - public Localizer T { get; set; } - [NonAction] protected PluginModel PreparePluginModel(PluginDescriptor pluginDescriptor, bool forList = true) { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 3c323b9686..c5fe38faec 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -193,14 +193,10 @@ public ProductController( this._genericAttributeService = genericAttributeService; _pdfConverter = pdfConverter; _services = services; - - T = NullLocalizer.Instance; } #endregion - public Localizer T { get; set; } - #region Update[...] [NonAction] diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs index 16745ce28f..d5d6110dee 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs @@ -42,13 +42,10 @@ public ScheduleTaskController(IScheduleTaskService scheduleTaskService, IPermiss this._scheduleTaskService = scheduleTaskService; this._permissionService = permissionService; this._dateTimeHelper = dateTimeHelper; - T = NullLocalizer.Instance; } #endregion - public Localizer T { get; set; } - #region Utility private bool IsTaskInstalled(ScheduleTask task) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs index 7d376c349f..55c6cee336 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs @@ -62,12 +62,8 @@ public ThemeController( this._services = services; this._themeContext = themeContext; this._themeFileResolver = themeFileResolver; - - this.T = NullLocalizer.Instance; } - public Localizer T { get; set; } - #endregion  #region Methods diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs index 191bdc64fc..ab0236bc10 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs @@ -105,22 +105,10 @@ public CatalogController( this._catalogSettings = catalogSettings; this._helper = helper; - - T = NullLocalizer.Instance; } #endregion - #region Properties - - public Localizer T - { - get; - set; - } - - #endregion - #region Categories [RequireHttpsByConfigAttribute(SslRequirement.No)] diff --git a/src/Presentation/SmartStore.Web/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Controllers/CommonController.cs index ba7a63234c..b7db4b2f44 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CommonController.cs @@ -133,12 +133,8 @@ public CommonController( this._pageAssetsBuilder = pageAssetsBuilder; this._pictureService = pictureService; this._services = services; - - T = NullLocalizer.Instance; } - public Localizer T { get; set; } - #endregion #region Utilities diff --git a/src/Presentation/SmartStore.Web/Controllers/HomeController.cs b/src/Presentation/SmartStore.Web/Controllers/HomeController.cs index 745da0006d..cd16a058b6 100644 --- a/src/Presentation/SmartStore.Web/Controllers/HomeController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/HomeController.cs @@ -68,14 +68,10 @@ public HomeController( this._sitemapGenerator = sitemapGenerator; this._captchaSettings = captchaSettings; this._commonSettings = commonSettings; - - T = NullLocalizer.Instance; } #endregion - public Localizer T { get; set; } - [RequireHttpsByConfigAttribute(SslRequirement.No)] public ActionResult Index() { diff --git a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs index 57c7c32649..b1217ad312 100644 --- a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs @@ -95,11 +95,8 @@ public OrderController( this._pluginMediator = pluginMediator; this._services = services; this._quantityUnitService = quantityUnitService; - T = NullLocalizer.Instance; } - public Localizer T { get; set; } - #endregion #region Utilities diff --git a/src/Presentation/SmartStore.Web/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Controllers/ProductController.cs index d778b741b5..e899772842 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ProductController.cs @@ -118,15 +118,10 @@ public ProductController( this._localizationSettings = localizationSettings; this._captchaSettings = captchaSettings; this._helper = helper; - - T = NullLocalizer.Instance; } #endregion - public Localizer T { get; set; } - - #region Products [RequireHttpsByConfigAttribute(SslRequirement.No)] From 7eb8b8de05cbe12b18a824f4126b637687416ba5 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 24 Jun 2015 22:22:30 +0200 Subject: [PATCH 0020/1074] Added EF6 profiling to MiniProfiler --- .../Filters/ProfilerFilter.cs | 24 ++++++++------ .../SmartStore.DevTools/ProfilerHttpModule.cs | 14 --------- .../SmartStore.DevTools.csproj | 6 ++++ src/Plugins/SmartStore.DevTools/Starter.cs | 31 +++++++++++++++++++ src/Plugins/SmartStore.DevTools/Web.config | 4 +++ .../SmartStore.DevTools/packages.config | 1 + src/Presentation/SmartStore.Web/Web.config | 2 +- 7 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 src/Plugins/SmartStore.DevTools/Starter.cs diff --git a/src/Plugins/SmartStore.DevTools/Filters/ProfilerFilter.cs b/src/Plugins/SmartStore.DevTools/Filters/ProfilerFilter.cs index 85a252e7f1..2971dabe08 100644 --- a/src/Plugins/SmartStore.DevTools/Filters/ProfilerFilter.cs +++ b/src/Plugins/SmartStore.DevTools/Filters/ProfilerFilter.cs @@ -54,7 +54,10 @@ public void OnActionExecuted(ActionExecutedContext filterContext) if (!_profilerSettings.EnableMiniProfilerInPublicStore) return; - this._profiler.Value.StepStop("ActionFilter"); + if (!(filterContext.Result is ViewResultBase)) + { + this._profiler.Value.StepStop("ActionFilter"); + } } public void OnResultExecuting(ResultExecutingContext filterContext) @@ -74,15 +77,6 @@ public void OnResultExecuting(ResultExecutingContext filterContext) return; } - if (!filterContext.IsChildAction) - { - _widgetProvider.Value.RegisterAction( - "head_html_tag", - "MiniProfiler", - "DevTools", - new { area = "SmartStore.DevTools" }); - } - var viewName = result.ViewName; if (viewName.IsEmpty()) { @@ -91,6 +85,15 @@ public void OnResultExecuting(ResultExecutingContext filterContext) } this._profiler.Value.StepStart("ResultFilter", string.Format("{0}: {1}", result is PartialViewResult ? "Partial" : "View", viewName)); + + if (!filterContext.IsChildAction) + { + _widgetProvider.Value.RegisterAction( + "head_html_tag", + "MiniProfiler", + "DevTools", + new { area = "SmartStore.DevTools" }); + } } public void OnResultExecuted(ResultExecutedContext filterContext) @@ -110,6 +113,7 @@ public void OnResultExecuted(ResultExecutedContext filterContext) } this._profiler.Value.StepStop("ResultFilter"); + this._profiler.Value.StepStop("ActionFilter"); } private bool ShouldProfile(HttpContextBase ctx) diff --git a/src/Plugins/SmartStore.DevTools/ProfilerHttpModule.cs b/src/Plugins/SmartStore.DevTools/ProfilerHttpModule.cs index 1cbc8981b3..e1c5693558 100644 --- a/src/Plugins/SmartStore.DevTools/ProfilerHttpModule.cs +++ b/src/Plugins/SmartStore.DevTools/ProfilerHttpModule.cs @@ -1,25 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Web; -using Microsoft.Web.Infrastructure.DynamicModuleHelper; using SmartStore.Core.Infrastructure; -using SmartStore.Core.Plugins; -using SmartStore.Web.Framework; using StackExchange.Profiling; namespace SmartStore.DevTools { - public class ProfilerStarter : IPreApplicationStart - { - public void Start() - { - DynamicModuleUtility.RegisterModule(typeof(ProfilerHttpModule)); - SmartUrlRoutingModule.RegisterRoutablePath("/mini-profiler-resources/(.*)"); - } - } - public class ProfilerHttpModule : IHttpModule { private const string MP_KEY = "sm.miniprofiler.started"; diff --git a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj index e1c88f8d2c..7b08208219 100644 --- a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj +++ b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj @@ -96,6 +96,11 @@ ..\..\packages\MiniProfiler.3.1.1.140\lib\net40\MiniProfiler.dll True + + False + ..\..\packages\MiniProfiler.EF6.3.0.11\lib\net40\MiniProfiler.EntityFramework6.dll + True + @@ -155,6 +160,7 @@ + diff --git a/src/Plugins/SmartStore.DevTools/Starter.cs b/src/Plugins/SmartStore.DevTools/Starter.cs new file mode 100644 index 0000000000..b8b9d3c97c --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Starter.cs @@ -0,0 +1,31 @@ +using Microsoft.Web.Infrastructure.DynamicModuleHelper; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Plugins; +using SmartStore.Web.Framework; + +namespace SmartStore.DevTools +{ + + public class ProfilerPreApplicationStart : IPreApplicationStart + { + public void Start() + { + DynamicModuleUtility.RegisterModule(typeof(ProfilerHttpModule)); + SmartUrlRoutingModule.RegisterRoutablePath("/mini-profiler-resources/(.*)"); + } + } + + public class ProfilerStartupTask : IStartupTask + { + public void Execute() + { + StackExchange.Profiling.EntityFramework6.MiniProfilerEF6.Initialize(); + } + + public int Order + { + get { return int.MinValue; } + } + } + +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DevTools/Web.config b/src/Plugins/SmartStore.DevTools/Web.config index 4f2a281983..e0593e522a 100644 --- a/src/Plugins/SmartStore.DevTools/Web.config +++ b/src/Plugins/SmartStore.DevTools/Web.config @@ -120,6 +120,10 @@ + + + + diff --git a/src/Plugins/SmartStore.DevTools/packages.config b/src/Plugins/SmartStore.DevTools/packages.config index 63f26d3792..5fb210cfc1 100644 --- a/src/Plugins/SmartStore.DevTools/packages.config +++ b/src/Plugins/SmartStore.DevTools/packages.config @@ -8,4 +8,5 @@ + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index 4cf9b75964..084e63fb0f 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -229,7 +229,7 @@ - + From bf90e329dec59e20e9d548b7fcf81090d59ae7aa Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 24 Jun 2015 23:39:23 +0200 Subject: [PATCH 0021/1074] (Perf) Minor enhancement in WorkContext.WorkingCurrency --- .../WebWorkContext.cs | 33 ++++++++++++------- src/Presentation/SmartStore.Web/Web.config | 2 +- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs b/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs index 9d33ae5f24..bb717b809f 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs @@ -255,6 +255,7 @@ public Language WorkingLanguage } #region Get language from URL (if possible) + if (_localizationSettings.SeoFriendlyUrlsForLanguagesEnabled && _httpContext != null && _httpContext.Request != null) { var helper = new LocalizedUrlHelper(_httpContext.Request, true); @@ -265,6 +266,7 @@ public Language WorkingLanguage { // the language is found. now we need to save it var langBySeoCode = _languageService.GetLanguageBySeoCode(seoCode); + if (this.CurrentCustomer != null && customerLangId != langBySeoCode.Id) { customerLangId = langBySeoCode.Id; @@ -275,6 +277,7 @@ public Language WorkingLanguage } } } + #endregion if (_localizationSettings.DetectBrowserUserLanguage && (customerLangId == 0 || !_languageService.IsPublishedLanguage(customerLangId, storeId))) @@ -363,7 +366,7 @@ public Currency WorkingCurrency { // find current customer language var customer = this.CurrentCustomer; - var currentStoreCurrencies = _currencyService.GetAllCurrencies(storeId: _storeContext.CurrentStore.Id); + var storeCurrenciesMap = _currencyService.GetAllCurrencies(storeId: _storeContext.CurrentStore.Id).ToDictionary(x => x.Id); if (customer != null && !customer.IsSearchEngineAccount()) { @@ -371,37 +374,43 @@ public Currency WorkingCurrency var customerCurrencyId = customer.GetAttribute(SystemCustomerAttributeNames.CurrencyId, _attrService, _storeContext.CurrentStore.Id); if (customerCurrencyId.GetValueOrDefault() > 0) { - currency = VerifyCurrency(_currencyService.GetCurrencyById(customerCurrencyId.Value)); - if (currency == null) - { - _attrService.SaveAttribute(customer, SystemCustomerAttributeNames.CurrencyId, null, _storeContext.CurrentStore.Id); - } + if (storeCurrenciesMap.TryGetValue(customerCurrencyId.Value, out currency)) + { + currency = VerifyCurrency(currency); + if (currency == null) + { + _attrService.SaveAttribute(customer, SystemCustomerAttributeNames.CurrencyId, null, _storeContext.CurrentStore.Id); + } + } } } // find currency by domain ending if (currency == null && _httpContext != null && _httpContext.Request != null && _httpContext.Request.Url != null) { - currency = currentStoreCurrencies.GetByDomainEnding(_httpContext.Request.Url.Authority); + currency = storeCurrenciesMap.Values.GetByDomainEnding(_httpContext.Request.Url.Authority); } // if there's only one currency for current store it dominates the primary currency - if (currentStoreCurrencies.Count == 1) + if (storeCurrenciesMap.Count == 1) { - currency = currentStoreCurrencies.First(); + currency = storeCurrenciesMap[0]; } // get PrimaryStoreCurrency if (currency == null) { - currency = VerifyCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)); - fixPrimaryStoreCurrency = (currency == null); + if (storeCurrenciesMap.TryGetValue(_currencySettings.PrimaryStoreCurrencyId, out currency)) + { + currency = VerifyCurrency(currency); + fixPrimaryStoreCurrency = (currency == null); + } } // get the first published currency for current store if (currency == null) { - currency = currentStoreCurrencies.FirstOrDefault(); + currency = storeCurrenciesMap.Values.FirstOrDefault(); } } diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index 084e63fb0f..32291a4cfb 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -42,7 +42,7 @@ - + From f8c5d8bbf70b890f0d7e1447ec2c6673bf4950e8 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 25 Jun 2015 01:32:39 +0200 Subject: [PATCH 0022/1074] (Perf) implemented static cache for localized properties, which are all loaded on app startup now. To disable this feature, set 'LocalizationSettings.LoadAllLocalizedPropertiesOnStartup' to false (true by default) --- .../Localization/LocalizationSettings.cs | 6 ++ .../Migrations/201504171629262_V22Final.cs | 2 +- ...06211043073_PaymentShippingRestrictions.cs | 5 ++ .../Localization/LocalizedEntityService.cs | 64 +++++++++++++------ 4 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Domain/Localization/LocalizationSettings.cs b/src/Libraries/SmartStore.Core/Domain/Localization/LocalizationSettings.cs index 4cd7889fee..b02a4ad2a2 100644 --- a/src/Libraries/SmartStore.Core/Domain/Localization/LocalizationSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Localization/LocalizationSettings.cs @@ -9,6 +9,7 @@ public LocalizationSettings() UseImagesForLanguageSelection = true; DefaultLanguageRedirectBehaviour = DefaultLanguageRedirectBehaviour.StripSeoCode; InvalidLanguageRedirectBehaviour = InvalidLanguageRedirectBehaviour.ReturnHttp404; + LoadAllLocalizedPropertiesOnStartup = true; } /// @@ -26,6 +27,11 @@ public LocalizationSettings() /// public bool LoadAllLocaleRecordsOnStartup { get; set; } + /// + /// A value indicating whether to load all localized entity properties on application startup + /// + public bool LoadAllLocalizedPropertiesOnStartup { get; set; } + /// /// A value indicating whether the browser user lannguage should be detected /// diff --git a/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.cs b/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.cs index 3f28263a18..23b0f56a14 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.cs @@ -90,7 +90,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Common.UnknownError", "An unknown error has occurred.", "Es ist ein unbekannter Fehler aufgetreten."); - + builder.AddOrUpdate("Plugins.Feed.FreeShippingThreshold", "Free shipping threshold", "Kostenloser Versand ab", diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs index cc83f0e114..2199b00670 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs @@ -44,6 +44,11 @@ public bool RollbackOnFailure public void Seed(SmartObjectContext context) { context.MigrateLocaleResources(MigrateLocaleResources); + + context.MigrateSettings(x => + { + x.Add("localizationsettings.loadalllocalizedpropertiesonstartup", true); + }); } public void MigrateLocaleResources(LocaleResourcesBuilder builder) diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizedEntityService.cs b/src/Libraries/SmartStore.Services/Localization/LocalizedEntityService.cs index 0aad0675e5..fd48d2a7c6 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizedEntityService.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizedEntityService.cs @@ -7,6 +7,7 @@ using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Infrastructure; namespace SmartStore.Services.Localization { @@ -18,7 +19,7 @@ public partial class LocalizedEntityService : ILocalizedEntityService #region Constants private const string LOCALIZEDPROPERTY_KEY = "SmartStore.localizedproperty.value-{0}-{1}-{2}-{3}"; - private const string LOCALIZEDPROPERTY_ENTITYID_KEY = "SmartStore.localizedproperty.entityid-{0}-{1}-{2}"; + private const string LOCALIZEDPROPERTY_ALL_KEY = "SmartStore.localizedproperty.all"; private const string LOCALIZEDPROPERTY_PATTERN_KEY = "SmartStore.localizedproperty."; #endregion @@ -27,6 +28,7 @@ public partial class LocalizedEntityService : ILocalizedEntityService private readonly IRepository _localizedPropertyRepository; private readonly ICacheManager _cacheManager; + private readonly LocalizationSettings _localizationSettings; #endregion @@ -37,11 +39,11 @@ public partial class LocalizedEntityService : ILocalizedEntityService ///
/// Cache manager /// Localized property repository - public LocalizedEntityService(ICacheManager cacheManager, - IRepository localizedPropertyRepository) + public LocalizedEntityService(ICacheManager cacheManager, IRepository localizedPropertyRepository, LocalizationSettings localizationSettings) { this._cacheManager = cacheManager; this._localizedPropertyRepository = localizedPropertyRepository; + this._localizationSettings = localizationSettings; } #endregion @@ -87,21 +89,42 @@ public virtual LocalizedProperty GetLocalizedPropertyById(int localizedPropertyI /// Found localized value public virtual string GetLocalizedValue(int languageId, int entityId, string localeKeyGroup, string localeKey) { - string key = string.Format(LOCALIZEDPROPERTY_KEY, languageId, entityId, localeKeyGroup, localeKey); - return _cacheManager.Get(key, () => - { - var query = from lp in _localizedPropertyRepository.Table - where lp.EntityId == entityId && - lp.LocaleKey == localeKey && - lp.LocaleKeyGroup == localeKeyGroup && - lp.LanguageId == languageId - select lp.LocaleValue; - var localeValue = query.FirstOrDefault(); - //little hack here. nulls aren't cacheable so set it to "" - if (localeValue == null) - localeValue = ""; - return localeValue; - }); + string val = null; + + if (_localizationSettings.LoadAllLocalizedPropertiesOnStartup) + { + var allValues = _cacheManager.Get(LOCALIZEDPROPERTY_ALL_KEY, () => + { + var result = _localizedPropertyRepository.TableUntracked.ToDictionary( + x => GenerateKey(x.LanguageId, x.LocaleKeyGroup, x.LocaleKey, x.EntityId), + x => x.LocaleValue); + return result; + }); + + string key = GenerateKey(languageId, localeKeyGroup, localeKey, entityId); + + if (!allValues.TryGetValue(key, out val)) + { + return string.Empty; + } + } + else + { + string cacheKey = string.Format(LOCALIZEDPROPERTY_KEY, languageId, entityId, localeKeyGroup, localeKey); + val = _cacheManager.Get(cacheKey, () => + { + var query = from lp in _localizedPropertyRepository.TableUntracked + where lp.EntityId == entityId && + lp.LocaleKey == localeKey && + lp.LocaleKeyGroup == localeKeyGroup && + lp.LanguageId == languageId + select lp.LocaleValue; + + return query.FirstOrDefault().EmptyNull(); + }); + } + + return val; } /// @@ -238,6 +261,11 @@ public virtual void SaveLocalizedValue(T entity, } } + private string GenerateKey(int languageId, string localeKeyGroup, string localeKey, int entityId) + { + return "{0}.{1}.{2}.{3}".FormatInvariant(languageId, localeKeyGroup, localeKey, entityId); + } + #endregion } } \ No newline at end of file From fe1117bdb599086ca99a3527cf9c858daeb7785b Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 25 Jun 2015 11:19:40 +0200 Subject: [PATCH 0023/1074] _commonServices becomes _services --- .../Catalog/PriceCalculationService.cs | 20 ++-- .../ExportImport/ExportManager.cs | 8 +- .../Filter/FilterService.cs | 10 +- .../Payments/PaymentService.cs | 34 +++--- .../ExternalAuthFacebookController.cs | 28 ++--- .../Core/FacebookProviderAuthorizer.cs | 12 +- .../Providers/PayPalStandardProvider.cs | 20 ++-- .../ByWeightShippingComputationMethod.cs | 6 +- .../Controllers/WebApiController.cs | 20 ++-- .../Controllers/CommonController.cs | 106 +++++++++--------- .../Controllers/ForumController.cs | 42 +++---- .../Controllers/PaymentController.cs | 22 ++-- .../Controllers/PluginController.cs | 38 +++---- .../Controllers/ShippingController.cs | 34 +++--- .../Catalog/PriceCalculationServiceTests.cs | 8 +- .../ExportImport/ExportManagerTests.cs | 6 +- .../Orders/OrderProcessingServiceTests.cs | 6 +- .../OrderTotalCalculationServiceTests.cs | 6 +- .../Payments/PaymentServiceTests.cs | 6 +- 19 files changed, 216 insertions(+), 216 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index e7d0550cde..e61c60cc35 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -26,7 +26,7 @@ public partial class PriceCalculationService : IPriceCalculationService private readonly CatalogSettings _catalogSettings; private readonly IProductAttributeService _productAttributeService; private readonly IDownloadService _downloadService; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private readonly HttpRequestBase _httpRequestBase; private readonly ITaxService _taxService; @@ -39,7 +39,7 @@ public PriceCalculationService( CatalogSettings catalogSettings, IProductAttributeService productAttributeService, IDownloadService downloadService, - ICommonServices commonServices, + ICommonServices services, HttpRequestBase httpRequestBase, ITaxService taxService) { @@ -51,7 +51,7 @@ public PriceCalculationService( this._catalogSettings = catalogSettings; this._productAttributeService = productAttributeService; this._downloadService = downloadService; - this._commonServices = commonServices; + this._services = services; this._httpRequestBase = httpRequestBase; this._taxService = taxService; } @@ -129,7 +129,7 @@ protected virtual IList GetAllowedDiscounts(Product product, Customer var tierPrices = product.TierPrices .OrderBy(tp => tp.Quantity) - .FilterByStore(_commonServices.StoreContext.CurrentStore.Id) + .FilterByStore(_services.StoreContext.CurrentStore.Id) .FilterForCustomer(customer) .ToList() .RemoveDuplicatedQuantities(); @@ -212,7 +212,7 @@ protected virtual decimal GetPreselectedPrice(Product product, ProductBundleItem if (!isBundle && selectedAttributes.Count > 0) { - string attributeXml = selectedAttributes.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _commonServices.Localization, + string attributeXml = selectedAttributes.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _services.Localization, _downloadService, _catalogSettings, _httpRequestBase, new List(), true, bundleItemId); selectedAttributeValues = _productAttributeParser.ParseProductVariantAttributeValues(attributeXml).ToList(); @@ -242,7 +242,7 @@ protected virtual decimal GetPreselectedPrice(Product product, ProductBundleItem bundleItem.AdditionalCharge = attributesTotalPriceBase; } - var result = GetFinalPrice(product, bundleItems, _commonServices.WorkContext.CurrentCustomer, attributesTotalPriceBase, true, 1, bundleItem); + var result = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, attributesTotalPriceBase, true, 1, bundleItem); return result; } @@ -290,7 +290,7 @@ protected virtual decimal GetPreselectedPrice(Product product, ProductBundleItem public virtual decimal GetFinalPrice(Product product, bool includeDiscounts) { - var customer = _commonServices.WorkContext.CurrentCustomer; + var customer = _services.WorkContext.CurrentCustomer; return GetFinalPrice(product, customer, includeDiscounts); } @@ -456,7 +456,7 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa } } - decimal lowestPrice = GetFinalPrice(product, bundleItems, _commonServices.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); + decimal lowestPrice = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); if (product.LowestAttributeCombinationPrice.HasValue && product.LowestAttributeCombinationPrice.Value < lowestPrice) { @@ -502,7 +502,7 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa foreach (var associatedProduct in associatedProducts) { - var tmpPrice = GetFinalPrice(associatedProduct, _commonServices.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); + var tmpPrice = GetFinalPrice(associatedProduct, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); if (associatedProduct.LowestAttributeCombinationPrice.HasValue && associatedProduct.LowestAttributeCombinationPrice.Value < tmpPrice) { @@ -583,7 +583,7 @@ public virtual decimal GetProductCost(Product product, string attributesXml) /// Discount amount public virtual decimal GetDiscountAmount(Product product) { - var customer = _commonServices.WorkContext.CurrentCustomer; + var customer = _services.WorkContext.CurrentCustomer; return GetDiscountAmount(product, customer, decimal.Zero); } diff --git a/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs b/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs index 21cb3055a1..0bd5599fd9 100644 --- a/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs +++ b/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs @@ -43,7 +43,7 @@ public partial class ExportManager : IExportManager private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService; private readonly ILanguageService _languageService; private readonly MediaSettings _mediaSettings; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private readonly IStoreMappingService _storeMappingService; #endregion @@ -58,7 +58,7 @@ public ExportManager(ICategoryService categoryService, INewsLetterSubscriptionService newsLetterSubscriptionService, ILanguageService languageService, MediaSettings mediaSettings, - ICommonServices commonServices, + ICommonServices services, IStoreMappingService storeMappingService) { this._categoryService = categoryService; @@ -69,7 +69,7 @@ public ExportManager(ICategoryService categoryService, this._newsLetterSubscriptionService = newsLetterSubscriptionService; this._languageService = languageService; this._mediaSettings = mediaSettings; - this._commonServices = commonServices; + this._services = services; this._storeMappingService = storeMappingService; Logger = NullLogger.Instance; @@ -728,7 +728,7 @@ public virtual void ExportProductsToXml(Stream stream, ProductSearchContext sear { ProductTemplates = _productTemplateService.GetAllProductTemplates(), Languages = _languageService.GetAllLanguages(true), - Store = _commonServices.StoreContext.CurrentStore + Store = _services.StoreContext.CurrentStore }; using (var writer = XmlWriter.Create(stream, settings)) diff --git a/src/Libraries/SmartStore.Services/Filter/FilterService.cs b/src/Libraries/SmartStore.Services/Filter/FilterService.cs index 66eaf99627..c96a3f23bf 100644 --- a/src/Libraries/SmartStore.Services/Filter/FilterService.cs +++ b/src/Libraries/SmartStore.Services/Filter/FilterService.cs @@ -24,7 +24,7 @@ public partial class FilterService : IFilterService private readonly IRepository _productRepository; private readonly IRepository _productCategoryRepository; private readonly ILocalizedEntityService _localizedEntityService; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private IQueryable _products; @@ -34,7 +34,7 @@ public FilterService(IProductService productService, IRepository productRepository, IRepository productCategoryRepository, ILocalizedEntityService localizedEntityService, - ICommonServices commonServices) + ICommonServices services) { _productService = productService; _categoryService = categoryService; @@ -42,7 +42,7 @@ public FilterService(IProductService productService, _productRepository = productRepository; _productCategoryRepository = productCategoryRepository; _localizedEntityService = localizedEntityService; - _commonServices = commonServices; + _services = services; } public static string ShortcutPrice { get { return "_Price"; } } @@ -166,7 +166,7 @@ private IQueryable AllProducts(List categoryIds) var searchContext = new ProductSearchContext() { FeaturedProducts = (_catalogSettings.IncludeFeaturedProductsInNormalLists ? null : (bool?)false), - StoreId = _commonServices.StoreContext.CurrentStoreIdIfMultiStoreMode, + StoreId = _services.StoreContext.CurrentStoreIdIfMultiStoreMode, VisibleIndividuallyOnly = true }; @@ -316,7 +316,7 @@ from a in attributes var lst = grouped.OrderByDescending(a => a.MatchCount).ToList(); - int languageId = _commonServices.WorkContext.WorkingLanguage.Id; + int languageId = _services.WorkContext.WorkingLanguage.Id; lst.ForEach(c => { diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index 24e39c2d32..f599e0e62f 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -35,7 +35,7 @@ public partial class PaymentService : IPaymentService private readonly ShoppingCartSettings _shoppingCartSettings; private readonly IProviderManager _providerManager; private readonly ICurrencyService _currencyService; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private readonly IOrderTotalCalculationService _orderTotalCalculationService; #endregion @@ -56,7 +56,7 @@ public PaymentService( ShoppingCartSettings shoppingCartSettings, IProviderManager providerManager, ICurrencyService currencyService, - ICommonServices commonServices, + ICommonServices services, IOrderTotalCalculationService orderTotalCalculationService) { this._paymentMethodRepository = paymentMethodRepository; @@ -65,7 +65,7 @@ public PaymentService( this._shoppingCartSettings = shoppingCartSettings; this._providerManager = providerManager; this._currencyService = currencyService; - this._commonServices = commonServices; + this._services = services; this._orderTotalCalculationService = orderTotalCalculationService; } @@ -171,7 +171,7 @@ public virtual IEnumerable> LoadActivePaymentMethods( _orderTotalCalculationService.GetShoppingCartSubTotal(cart, out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); - orderSubTotal = _currencyService.ConvertFromPrimaryStoreCurrency(subTotalWithoutDiscountBase, _commonServices.WorkContext.WorkingCurrency); + orderSubTotal = _currencyService.ConvertFromPrimaryStoreCurrency(subTotalWithoutDiscountBase, _services.WorkContext.WorkingCurrency); } compareAmount = orderSubTotal.Value; @@ -182,7 +182,7 @@ public virtual IEnumerable> LoadActivePaymentMethods( { orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart) ?? decimal.Zero; - orderTotal = _currencyService.ConvertFromPrimaryStoreCurrency(orderTotal.Value, _commonServices.WorkContext.WorkingCurrency); + orderTotal = _currencyService.ConvertFromPrimaryStoreCurrency(orderTotal.Value, _services.WorkContext.WorkingCurrency); } compareAmount = orderTotal.Value; @@ -261,7 +261,7 @@ public virtual IEnumerable> LoadAllPaymentMethods(int s /// List of payment method objects public virtual IList GetAllPaymentMethods() { - var paymentMethods = _commonServices.Cache.Get(PAYMENTMETHOD_ALL_KEY, () => + var paymentMethods = _services.Cache.Get(PAYMENTMETHOD_ALL_KEY, () => { var methods = _paymentMethodRepository.TableUntracked.ToList(); @@ -298,9 +298,9 @@ public virtual void InsertPaymentMethod(PaymentMethod paymentMethod) _paymentMethodRepository.Insert(paymentMethod); - _commonServices.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + _services.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); - _commonServices.EventPublisher.EntityInserted(paymentMethod); + _services.EventPublisher.EntityInserted(paymentMethod); } /// @@ -314,9 +314,9 @@ public virtual void UpdatePaymentMethod(PaymentMethod paymentMethod) _paymentMethodRepository.Update(paymentMethod); - _commonServices.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + _services.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); - _commonServices.EventPublisher.EntityUpdated(paymentMethod); + _services.EventPublisher.EntityUpdated(paymentMethod); } /// @@ -330,9 +330,9 @@ public virtual void DeletePaymentMethod(PaymentMethod paymentMethod) _paymentMethodRepository.Delete(paymentMethod); - _commonServices.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); + _services.Cache.RemoveByPattern(PAYMENTMETHOD_ALL_KEY); - _commonServices.EventPublisher.EntityDeleted(paymentMethod); + _services.EventPublisher.EntityDeleted(paymentMethod); } @@ -481,7 +481,7 @@ public virtual CapturePaymentResult Capture(CapturePaymentRequest capturePayment catch (NotSupportedException) { var result = new CapturePaymentResult(); - result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoCaptureSupport")); + result.AddError(_services.Localization.GetResource("Common.Payment.NoCaptureSupport")); return result; } catch @@ -536,7 +536,7 @@ public virtual RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequ catch (NotSupportedException) { var result = new RefundPaymentResult(); - result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoRefundSupport")); + result.AddError(_services.Localization.GetResource("Common.Payment.NoRefundSupport")); return result; } catch @@ -578,7 +578,7 @@ public virtual VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) catch (NotSupportedException) { var result = new VoidPaymentResult(); - result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoVoidSupport")); + result.AddError(_services.Localization.GetResource("Common.Payment.NoVoidSupport")); return result; } catch @@ -630,7 +630,7 @@ public virtual ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentReques catch (NotSupportedException) { var result = new ProcessPaymentResult(); - result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoRecurringPaymentSupport")); + result.AddError(_services.Localization.GetResource("Common.Payment.NoRecurringPaymentSupport")); return result; } catch @@ -661,7 +661,7 @@ public virtual CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurri catch (NotSupportedException) { var result = new CancelRecurringPaymentResult(); - result.AddError(_commonServices.Localization.GetResource("Common.Payment.NoRecurringPaymentSupport")); + result.AddError(_services.Localization.GetResource("Common.Payment.NoRecurringPaymentSupport")); return result; } catch diff --git a/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs b/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs index 1ed000f3bb..9ac4d52308 100644 --- a/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs @@ -17,26 +17,26 @@ public class ExternalAuthFacebookController : PluginControllerBase private readonly IOAuthProviderFacebookAuthorizer _oAuthProviderFacebookAuthorizer; private readonly IOpenAuthenticationService _openAuthenticationService; private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; public ExternalAuthFacebookController( IOAuthProviderFacebookAuthorizer oAuthProviderFacebookAuthorizer, IOpenAuthenticationService openAuthenticationService, ExternalAuthenticationSettings externalAuthenticationSettings, - ICommonServices commonServices) + ICommonServices services) { this._oAuthProviderFacebookAuthorizer = oAuthProviderFacebookAuthorizer; this._openAuthenticationService = openAuthenticationService; this._externalAuthenticationSettings = externalAuthenticationSettings; - this._commonServices = commonServices; + this._services = services; } private bool HasPermission(bool notify = true) { - bool hasPermission = _commonServices.Permissions.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods); + bool hasPermission = _services.Permissions.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods); if (notify && !hasPermission) - NotifyError(_commonServices.Localization.GetResource("Admin.AccessDenied.Description")); + NotifyError(_services.Localization.GetResource("Admin.AccessDenied.Description")); return hasPermission; } @@ -48,14 +48,14 @@ public ActionResult Configure() return AccessDeniedPartialView(); var model = new ConfigurationModel(); - int storeScope = this.GetActiveStoreScopeConfiguration(_commonServices.StoreService, _commonServices.WorkContext); - var settings = _commonServices.Settings.LoadSetting(storeScope); + int storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); model.ClientKeyIdentifier = settings.ClientKeyIdentifier; model.ClientSecret = settings.ClientSecret; var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); - storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, _commonServices.Settings); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, _services.Settings); return View(model); } @@ -70,16 +70,16 @@ public ActionResult Configure(ConfigurationModel model, FormCollection form) return Configure(); var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); - int storeScope = this.GetActiveStoreScopeConfiguration(_commonServices.StoreService, _commonServices.WorkContext); - var settings = _commonServices.Settings.LoadSetting(storeScope); + int storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); settings.ClientKeyIdentifier = model.ClientKeyIdentifier; settings.ClientSecret = model.ClientSecret; - storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, _commonServices.Settings); - _commonServices.Settings.ClearCache(); + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, _services.Settings); + _services.Settings.ClearCache(); - NotifySuccess(_commonServices.Localization.GetResource("Admin.Common.DataSuccessfullySaved")); + NotifySuccess(_services.Localization.GetResource("Admin.Common.DataSuccessfullySaved")); return Configure(); } @@ -93,7 +93,7 @@ public ActionResult PublicInfo() [NonAction] private ActionResult LoginInternal(string returnUrl, bool verifyResponse) { - var processor = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName(Provider.SystemName, _commonServices.StoreContext.CurrentStore.Id); + var processor = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName(Provider.SystemName, _services.StoreContext.CurrentStore.Id); if (processor == null || !processor.IsMethodActive(_externalAuthenticationSettings)) { throw new SmartException("Facebook module cannot be loaded"); diff --git a/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs b/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs index 34eabdbffc..7bb6234362 100644 --- a/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs @@ -22,7 +22,7 @@ public class FacebookProviderAuthorizer : IOAuthProviderFacebookAuthorizer private readonly IOpenAuthenticationService _openAuthenticationService; private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; private readonly HttpContextBase _httpContext; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private FacebookClient _facebookApplication; @@ -34,13 +34,13 @@ public FacebookProviderAuthorizer(IExternalAuthorizer authorizer, IOpenAuthenticationService openAuthenticationService, ExternalAuthenticationSettings externalAuthenticationSettings, HttpContextBase httpContext, - ICommonServices commonServices) + ICommonServices services) { this._authorizer = authorizer; this._openAuthenticationService = openAuthenticationService; this._externalAuthenticationSettings = externalAuthenticationSettings; this._httpContext = httpContext; - this._commonServices = commonServices; + this._services = services; } #endregion @@ -53,7 +53,7 @@ private FacebookClient FacebookApplication { if (_facebookApplication == null) { - var settings = _commonServices.Settings.LoadSetting(_commonServices.StoreContext.CurrentStore.Id); + var settings = _services.Settings.LoadSetting(_services.StoreContext.CurrentStore.Id); _facebookApplication = new FacebookClient(settings.ClientKeyIdentifier, settings.ClientSecret); } @@ -133,7 +133,7 @@ private AuthorizeState RequestAuthentication(string returnUrl) private Uri GenerateLocalCallbackUri() { - string url = string.Format("{0}Plugins/SmartStore.FacebookAuth/logincallback/", _commonServices.WebHelper.GetStoreLocation()); + string url = string.Format("{0}Plugins/SmartStore.FacebookAuth/logincallback/", _services.WebHelper.GetStoreLocation()); return new Uri(url); } @@ -142,7 +142,7 @@ private Uri GenerateServiceLoginUrl() //code copied from DotNetOpenAuth.AspNet.Clients.FacebookClient file var builder = new UriBuilder("https://www.facebook.com/dialog/oauth"); var args = new Dictionary(); - var settings = _commonServices.Settings.LoadSetting(_commonServices.StoreContext.CurrentStore.Id); + var settings = _services.Settings.LoadSetting(_services.StoreContext.CurrentStore.Id); args.Add("client_id", settings.ClientKeyIdentifier); args.Add("redirect_uri", GenerateLocalCallbackUri().AbsoluteUri); diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs index f2e2331ce6..c009c24d3c 100644 --- a/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs @@ -38,21 +38,21 @@ public partial class PayPalStandardProvider : PaymentPluginBase, IConfigurable private readonly CurrencySettings _currencySettings; private readonly IOrderTotalCalculationService _orderTotalCalculationService; private readonly HttpContextBase _httpContext; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private readonly ILogger _logger; public PayPalStandardProvider(ICurrencyService currencyService, HttpContextBase httpContext, CurrencySettings currencySettings, IOrderTotalCalculationService orderTotalCalculationService, - ICommonServices commonServices, + ICommonServices services, ILogger logger) { _currencyService = currencyService; _currencySettings = currencySettings; _orderTotalCalculationService = orderTotalCalculationService; _httpContext = httpContext; - _commonServices = commonServices; + _services = services; _logger = logger; } @@ -66,7 +66,7 @@ public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest proces var result = new ProcessPaymentResult(); result.NewPaymentStatus = PaymentStatus.Pending; - var settings = _commonServices.Settings.LoadSetting(processPaymentRequest.StoreId); + var settings = _services.Settings.LoadSetting(processPaymentRequest.StoreId); if (settings.BusinessEmail.IsEmpty() || settings.PdtToken.IsEmpty()) { @@ -85,7 +85,7 @@ public override void PostProcessPayment(PostProcessPaymentRequest postProcessPay if (postProcessPaymentRequest.Order.PaymentStatus == PaymentStatus.Paid) return; - var settings = _commonServices.Settings.LoadSetting(postProcessPaymentRequest.Order.StoreId); + var settings = _services.Settings.LoadSetting(postProcessPaymentRequest.Order.StoreId); var builder = new StringBuilder(); builder.Append(PayPalHelper.GetPaypalUrl(settings)); @@ -239,8 +239,8 @@ public override void PostProcessPayment(PostProcessPaymentRequest postProcessPay builder.AppendFormat("&no_shipping=1", new object[0]); } - string returnUrl = _commonServices.WebHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/PDTHandler"; - string cancelReturnUrl = _commonServices.WebHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/CancelOrder"; + string returnUrl = _services.WebHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/PDTHandler"; + string cancelReturnUrl = _services.WebHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/CancelOrder"; builder.AppendFormat("&return={0}&cancel_return={1}", HttpUtility.UrlEncode(returnUrl), HttpUtility.UrlEncode(cancelReturnUrl)); //Instant Payment Notification (server to server message) @@ -248,7 +248,7 @@ public override void PostProcessPayment(PostProcessPaymentRequest postProcessPay { string ipnUrl; if (String.IsNullOrWhiteSpace(settings.IpnUrl)) - ipnUrl = _commonServices.WebHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/IPNHandler"; + ipnUrl = _services.WebHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/IPNHandler"; else ipnUrl = settings.IpnUrl; builder.AppendFormat("¬ify_url={0}", ipnUrl); @@ -315,7 +315,7 @@ public override decimal GetAdditionalHandlingFee(IList(_commonServices.StoreContext.CurrentStore.Id); + var settings = _services.Settings.LoadSetting(_services.StoreContext.CurrentStore.Id); result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, settings.AdditionalFee, settings.AdditionalFeePercentage); } @@ -569,7 +569,7 @@ public void AdjustLineItemAmounts(List paypalItems, PostProcessP public bool VerifyIPN(string formString, out Dictionary values) { // settings: multistore context not possible here. we need the custom value to determine what store it is. - var settings = _commonServices.Settings.LoadSetting(); + var settings = _services.Settings.LoadSetting(); var req = (HttpWebRequest)WebRequest.Create(PayPalHelper.GetPaypalUrl(settings)); req.Method = "POST"; diff --git a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs index bc94c7a947..6682416683 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs @@ -27,7 +27,7 @@ public class ByWeightShippingComputationMethod : BasePlugin, IShippingRateComput private readonly ShippingByWeightObjectContext _objectContext; private readonly ILocalizationService _localizationService; private readonly IPriceFormatter _priceFormatter; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; #endregion @@ -40,7 +40,7 @@ public ByWeightShippingComputationMethod(IShippingService shippingService, ShippingByWeightObjectContext objectContext, ILocalizationService localizationService, IPriceFormatter priceFormatter, - ICommonServices commonServices) + ICommonServices services) { this._shippingService = shippingService; this._storeContext = storeContext; @@ -50,7 +50,7 @@ public ByWeightShippingComputationMethod(IShippingService shippingService, this._objectContext = objectContext; this._localizationService = localizationService; this._priceFormatter = priceFormatter; - this._commonServices = commonServices; + this._services = services; } #endregion diff --git a/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs b/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs index 30c9c98295..58e3d49117 100644 --- a/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs @@ -19,36 +19,36 @@ public class WebApiController : PluginControllerBase private readonly WebApiSettings _webApiSettings; private readonly IWebApiPluginService _webApiPluginService; private readonly AdminAreaSettings _adminAreaSettings; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; public WebApiController( WebApiSettings settings, IWebApiPluginService webApiPluginService, AdminAreaSettings adminAreaSettings, - ICommonServices commonServices) + ICommonServices services) { _webApiSettings = settings; _webApiPluginService = webApiPluginService; _adminAreaSettings = adminAreaSettings; - _commonServices = commonServices; + _services = services; } private bool HasPermission(bool notify = true) { - bool hasPermission = _commonServices.Permissions.Authorize(WebApiPermissionProvider.ManageWebApi); + bool hasPermission = _services.Permissions.Authorize(WebApiPermissionProvider.ManageWebApi); if (notify && !hasPermission) - NotifyError(_commonServices.Localization.GetResource("Admin.AccessDenied.Description")); + NotifyError(_services.Localization.GetResource("Admin.AccessDenied.Description")); return hasPermission; } private void AddButtonText() { - ViewData["ButtonTextEnable"] = _commonServices.Localization.GetResource("Plugins.Api.WebApi.Activate"); - ViewData["ButtonTextDisable"] = _commonServices.Localization.GetResource("Plugins.Api.WebApi.Deactivate"); - ViewData["ButtonTextRemoveKeys"] = _commonServices.Localization.GetResource("Plugins.Api.WebApi.RemoveKeys"); - ViewData["ButtonTextCreateKeys"] = _commonServices.Localization.GetResource("Plugins.Api.WebApi.CreateKeys"); + ViewData["ButtonTextEnable"] = _services.Localization.GetResource("Plugins.Api.WebApi.Activate"); + ViewData["ButtonTextDisable"] = _services.Localization.GetResource("Plugins.Api.WebApi.Deactivate"); + ViewData["ButtonTextRemoveKeys"] = _services.Localization.GetResource("Plugins.Api.WebApi.RemoveKeys"); + ViewData["ButtonTextCreateKeys"] = _services.Localization.GetResource("Plugins.Api.WebApi.CreateKeys"); } public ActionResult Configure() @@ -84,7 +84,7 @@ public ActionResult SaveGeneralSettings(WebApiConfigModel model) return AccessDeniedPartialView(); model.Copy(_webApiSettings, false); - _commonServices.Settings.SaveSetting(_webApiSettings); + _services.Settings.SaveSetting(_webApiSettings); WebApiCachingControllingData.Remove(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs index 82b4cffdee..d9424d8fe0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs @@ -68,7 +68,7 @@ public class CommonController : AdminControllerBase private readonly Lazy _menuPublisher; private readonly Lazy _pluginFinder; private readonly IGenericAttributeService _genericAttributeService; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private readonly Func _cache; private readonly static object s_lock = new object(); @@ -95,7 +95,7 @@ public CommonController( Lazy menuPublisher, Lazy pluginFinder, IGenericAttributeService genericAttributeService, - ICommonServices commonServices, + ICommonServices services, Func cache) { this._paymentService = paymentService; @@ -115,7 +115,7 @@ public CommonController( this._menuPublisher = menuPublisher; this._pluginFinder = pluginFinder; this._genericAttributeService = genericAttributeService; - this._commonServices = commonServices; + this._services = services; this._cache = cache; } @@ -128,11 +128,11 @@ public CommonController( [ChildActionOnly] public ActionResult Navbar() { - var currentCustomer = _commonServices.WorkContext.CurrentCustomer; + var currentCustomer = _services.WorkContext.CurrentCustomer; - ViewBag.UserName = _commonServices.Settings.LoadSetting().UsernamesEnabled ? currentCustomer.Username : currentCustomer.Email; - ViewBag.Stores = _commonServices.StoreService.GetAllStores(); - if (_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + ViewBag.UserName = _services.Settings.LoadSetting().UsernamesEnabled ? currentCustomer.Username : currentCustomer.Email; + ViewBag.Stores = _services.StoreService.GetAllStores(); + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) { ViewBag.CheckUpdateResult = AsyncRunner.RunSync(() => CheckUpdateAsync(false)); } @@ -143,10 +143,10 @@ public ActionResult Navbar() [ChildActionOnly] public ActionResult Menu() { - var cacheManager = _commonServices.Cache; + var cacheManager = _services.Cache; - var customerRolesIds = _commonServices.WorkContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); - string cacheKey = string.Format("smartstore.pres.adminmenu.navigation-{0}-{1}", _commonServices.WorkContext.WorkingLanguage.Id, string.Join(",", customerRolesIds)); + var customerRolesIds = _services.WorkContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); + string cacheKey = string.Format("smartstore.pres.adminmenu.navigation-{0}-{1}", _services.WorkContext.WorkingLanguage.Id, string.Join(",", customerRolesIds)); var rootNode = cacheManager.Get(cacheKey, () => { @@ -255,7 +255,7 @@ private bool MenuItemAccessPermitted(MenuItem item) if (_securitySettings.Value.HideAdminMenuItemsBasedOnPermissions && item.PermissionNames.HasValue()) { - var permitted = item.PermissionNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Any(x => _commonServices.Permissions.Authorize(x.Trim())); + var permitted = item.PermissionNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Any(x => _services.Permissions.Authorize(x.Trim())); if (!permitted) { result = false; @@ -284,24 +284,24 @@ public ActionResult CheckUpdateSuppress(string myVersion, string newVersion) public void CheckUpdateSuppressInternal(string myVersion, string newVersion) { var suppressKey = "SuppressUpdateMessage.{0}.{1}".FormatInvariant(myVersion, newVersion); - _genericAttributeService.SaveAttribute(_commonServices.WorkContext.CurrentCustomer, suppressKey, true); - _commonServices.Cache.RemoveByPattern("Common.CheckUpdateResult"); + _genericAttributeService.SaveAttribute(_services.WorkContext.CurrentCustomer, suppressKey, true); + _services.Cache.RemoveByPattern("Common.CheckUpdateResult"); } [NonAction] private async Task CheckUpdateAsync(bool enforce = false, bool forSuppress = false) { var curVersion = SmartStoreVersion.CurrentFullVersion; - var lang = _commonServices.WorkContext.WorkingLanguage.UniqueSeoCode; + var lang = _services.WorkContext.WorkingLanguage.UniqueSeoCode; var cacheKeyPattern = "Common.CheckUpdateResult"; var cacheKey = "{0}.{1}".FormatInvariant(cacheKeyPattern, lang); if (enforce) { - _commonServices.Cache.RemoveByPattern(cacheKeyPattern); + _services.Cache.RemoveByPattern(cacheKeyPattern); } - var result = await _commonServices.Cache.Get(cacheKey, async () => + var result = await _services.Cache.Get(cacheKey, async () => { var noUpdateResult = new CheckUpdateResult { UpdateAvailable = false, LanguageCode = lang, CurrentVersion = curVersion }; @@ -315,7 +315,7 @@ private async Task CheckUpdateAsync(bool enforce = false, boo client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.UserAgent.ParseAdd("SmartStore.NET {0}".FormatInvariant(curVersion)); - client.DefaultRequestHeaders.Add("Authorization-Key", _commonServices.StoreContext.CurrentStore.Url.TrimEnd('/')); + client.DefaultRequestHeaders.Add("Authorization-Key", _services.StoreContext.CurrentStore.Url.TrimEnd('/')); HttpResponseMessage response = await client.GetAsync(url); @@ -331,7 +331,7 @@ private async Task CheckUpdateAsync(bool enforce = false, boo model.CurrentVersion = curVersion; model.LanguageCode = lang; - if (CommonHelper.IsDevEnvironment || !_commonSettings.Value.AutoUpdateEnabled || !_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (CommonHelper.IsDevEnvironment || !_commonSettings.Value.AutoUpdateEnabled || !_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) { model.AutoUpdatePossible = false; } @@ -341,9 +341,9 @@ private async Task CheckUpdateAsync(bool enforce = false, boo if (enforce) { // but ignore user's decision if 'enforce' - _genericAttributeService.SaveAttribute(_commonServices.WorkContext.CurrentCustomer, suppressKey, null); + _genericAttributeService.SaveAttribute(_services.WorkContext.CurrentCustomer, suppressKey, null); } - var showMessage = enforce || _commonServices.WorkContext.CurrentCustomer.GetAttribute(suppressKey, _genericAttributeService).GetValueOrDefault() == false; + var showMessage = enforce || _services.WorkContext.CurrentCustomer.GetAttribute(suppressKey, _genericAttributeService).GetValueOrDefault() == false; if (!showMessage) { return noUpdateResult; @@ -364,7 +364,7 @@ private async Task CheckUpdateAsync(bool enforce = false, boo public ActionResult InstallUpdate(string packageUrl) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); try @@ -385,7 +385,7 @@ public ActionResult InstallUpdate(string packageUrl) } else { - _commonServices.WebHelper.RestartAppDomain(); + _services.WebHelper.RestartAppDomain(); } } @@ -453,12 +453,12 @@ public ActionResult SystemInfo() model.ServerTimeZone = TimeZone.CurrentTimeZone.StandardName; model.ServerLocalTime = DateTime.Now; model.UtcTime = DateTime.UtcNow; - model.HttpHost = _commonServices.WebHelper.ServerVariables("HTTP_HOST"); + model.HttpHost = _services.WebHelper.ServerVariables("HTTP_HOST"); //Environment.GetEnvironmentVariable("USERNAME"); try { - var mbSize = _commonServices.DbContext.SqlQuery("Select Sum(size)/128.0 From sysfiles").FirstOrDefault(); + var mbSize = _services.DbContext.SqlQuery("Select Sum(size)/128.0 From sysfiles").FirstOrDefault(); model.DatabaseSize = Convert.ToDouble(mbSize); } catch (Exception) { } @@ -468,7 +468,7 @@ public ActionResult SystemInfo() if (DataSettings.Current.IsValid()) { model.DataProviderFriendlyName = DataSettings.Current.ProviderFriendlyName; - model.ShrinkDatabaseEnabled = _commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance) && DataSettings.Current.IsSqlServer; + model.ShrinkDatabaseEnabled = _services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance) && DataSettings.Current.IsSqlServer; } } catch (Exception) { } @@ -498,8 +498,8 @@ public ActionResult Warnings() var model = new List(); //store URL - var storeUrl = _commonServices.StoreContext.CurrentStore.Url.EnsureEndsWith("/"); - if (storeUrl.HasValue() && (storeUrl.IsCaseInsensitiveEqual(_commonServices.WebHelper.GetStoreLocation(false)) || storeUrl.IsCaseInsensitiveEqual(_commonServices.WebHelper.GetStoreLocation(true)))) + var storeUrl = _services.StoreContext.CurrentStore.Url.EnsureEndsWith("/"); + if (storeUrl.HasValue() && (storeUrl.IsCaseInsensitiveEqual(_services.WebHelper.GetStoreLocation(false)) || storeUrl.IsCaseInsensitiveEqual(_services.WebHelper.GetStoreLocation(true)))) { model.Add(new SystemWarningModel { @@ -512,7 +512,7 @@ public ActionResult Warnings() model.Add(new SystemWarningModel { Level = SystemWarningLevel.Warning, - Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.URL.NoMatch"), storeUrl, _commonServices.WebHelper.GetStoreLocation(false)) + Text = string.Format(_localizationService.GetResource("Admin.System.Warnings.URL.NoMatch"), storeUrl, _services.WebHelper.GetStoreLocation(false)) }); } @@ -699,7 +699,7 @@ public ActionResult Warnings() //validate write permissions (the same procedure like during installation) var dirPermissionsOk = true; - var dirsToCheck = FilePermissionHelper.GetDirectoriesWrite(_commonServices.WebHelper); + var dirsToCheck = FilePermissionHelper.GetDirectoriesWrite(_services.WebHelper); foreach (string dir in dirsToCheck) { if (!FilePermissionHelper.CheckPermissions(dir, false, true, true, false)) @@ -722,7 +722,7 @@ public ActionResult Warnings() } var filePermissionsOk = true; - var filesToCheck = FilePermissionHelper.GetFilesWrite(_commonServices.WebHelper); + var filesToCheck = FilePermissionHelper.GetFilesWrite(_services.WebHelper); foreach (string file in filesToCheck) { if (!FilePermissionHelper.CheckPermissions(file, false, true, true, true)) @@ -749,14 +749,14 @@ public ActionResult Warnings() public ActionResult ShrinkDatabase() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); try { if (DataSettings.Current.IsSqlServer) { - _commonServices.DbContext.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); + _services.DbContext.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); NotifySuccess(_localizationService.GetResource("Common.ShrinkDatabaseSuccessful")); } } @@ -770,7 +770,7 @@ public ActionResult ShrinkDatabase() public ActionResult Maintenance() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); var model = new MaintenanceModel(); @@ -791,7 +791,7 @@ public ActionResult Maintenance() [FormValueRequired("delete-image-cache")] public ActionResult MaintenanceDeleteImageCache() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); _imageCache.Value.DeleteCachedImages(); @@ -803,7 +803,7 @@ public ActionResult MaintenanceDeleteImageCache() [FormValueRequired("delete-guests")] public ActionResult MaintenanceDeleteGuests(MaintenanceModel model) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); DateTime? startDateValue = (model.DeleteGuests.StartDate == null) ? null @@ -821,7 +821,7 @@ public ActionResult MaintenanceDeleteGuests(MaintenanceModel model) [FormValueRequired("delete-exported-files")] public ActionResult MaintenanceDeleteFiles(MaintenanceModel model) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); DateTime? startDateValue = (model.DeleteExportedFiles.StartDate == null) ? null @@ -865,7 +865,7 @@ public ActionResult MaintenanceDeleteFiles(MaintenanceModel model) [FormValueRequired("execute-sql-query")] public ActionResult MaintenanceExecuteSql(MaintenanceModel model) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); if (model.SqlQuery.HasValue()) @@ -890,9 +890,9 @@ public ActionResult MaintenanceExecuteSql(MaintenanceModel model) public ActionResult LanguageSelector() { var model = new LanguageSelectorModel(); - model.CurrentLanguage = _commonServices.WorkContext.WorkingLanguage.ToModel(); + model.CurrentLanguage = _services.WorkContext.WorkingLanguage.ToModel(); model.AvailableLanguages = _languageService - .GetAllLanguages(storeId: _commonServices.StoreContext.CurrentStore.Id) + .GetAllLanguages(storeId: _services.StoreContext.CurrentStore.Id) .Select(x => x.ToModel()) .ToList(); return PartialView(model); @@ -902,14 +902,14 @@ public ActionResult LanguageSelected(int customerlanguage) var language = _languageService.GetLanguageById(customerlanguage); if (language != null) { - _commonServices.WorkContext.WorkingLanguage = language; + _services.WorkContext.WorkingLanguage = language; } return Content(_localizationService.GetResource("Admin.Common.DataEditSuccess")); } public ActionResult ClearCache(string previousUrl) { - var cacheManager = _commonServices.Cache; + var cacheManager = _services.Cache; cacheManager.Clear(); cacheManager = _cache("aspnet"); @@ -925,10 +925,10 @@ public ActionResult ClearCache(string previousUrl) public ActionResult RestartApplication(string previousUrl) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); - _commonServices.WebHelper.RestartAppDomain(); + _services.WebHelper.RestartAppDomain(); if (previousUrl.HasValue()) return Redirect(previousUrl); @@ -942,7 +942,7 @@ public ActionResult RestartApplication(string previousUrl) public ActionResult SeNames() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); var model = new UrlRecordListModel(); @@ -952,7 +952,7 @@ public ActionResult SeNames() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult SeNames(GridCommand command, UrlRecordListModel model) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); var urlRecords = _urlRecordService.GetAllUrlRecords(model.SeName, command.Page - 1, command.PageSize); @@ -991,7 +991,7 @@ public ActionResult SeNames(GridCommand command, UrlRecordListModel model) [HttpPost] public ActionResult DeleteSelectedSeNames(ICollection selectedIds) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageMaintenance)) return AccessDeniedView(); if (selectedIds != null) @@ -1026,10 +1026,10 @@ public ActionResult GenericAttributes(string entityName, int entityId) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributesSelect(string entityName, int entityId, GridCommand command) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) return AccessDeniedView(); - var storeId = _commonServices.StoreContext.CurrentStore.Id; + var storeId = _services.StoreContext.CurrentStore.Id; ViewBag.StoreId = storeId; var model = new List(); @@ -1064,7 +1064,7 @@ public ActionResult GenericAttributesSelect(string entityName, int entityId, Gri [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeAdd(GenericAttributeModel model, GridCommand command) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) return AccessDeniedView(); model.Key = model.Key.TrimSafe(); @@ -1077,7 +1077,7 @@ public ActionResult GenericAttributeAdd(GenericAttributeModel model, GridCommand return Content(modelStateErrorMessages.FirstOrDefault()); } - var storeId = _commonServices.StoreContext.CurrentStore.Id; + var storeId = _services.StoreContext.CurrentStore.Id; var attr = _genericAttributeService.GetAttribute(model.EntityName, model.EntityId, model.Key, storeId); if (attr == null) @@ -1103,7 +1103,7 @@ public ActionResult GenericAttributeAdd(GenericAttributeModel model, GridCommand [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeUpdate(GenericAttributeModel model, GridCommand command) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) return AccessDeniedView(); model.Key = model.Key.TrimSafe(); @@ -1116,7 +1116,7 @@ public ActionResult GenericAttributeUpdate(GenericAttributeModel model, GridComm return Content(modelStateErrorMessages.FirstOrDefault()); } - var storeId = _commonServices.StoreContext.CurrentStore.Id; + var storeId = _services.StoreContext.CurrentStore.Id; var attr = _genericAttributeService.GetAttributeById(model.Id); // if the key changed, ensure it isn't being used by another attribute @@ -1142,7 +1142,7 @@ public ActionResult GenericAttributeUpdate(GenericAttributeModel model, GridComm [GridAction(EnableCustomBinding = true)] public ActionResult GenericAttributeDelete(int id, GridCommand command) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel)) return AccessDeniedView(); var attr = _genericAttributeService.GetAttributeById(id); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ForumController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ForumController.cs index 988c4164de..5b113525ed 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ForumController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ForumController.cs @@ -18,7 +18,7 @@ namespace SmartStore.Admin.Controllers public class ForumController : AdminControllerBase { private readonly IForumService _forumService; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private readonly IDateTimeHelper _dateTimeHelper; private readonly IStoreMappingService _storeMappingService; private readonly ILanguageService _languageService; @@ -26,7 +26,7 @@ public class ForumController : AdminControllerBase private readonly IUrlRecordService _urlRecordService; public ForumController(IForumService forumService, - ICommonServices commonServices, + ICommonServices services, IDateTimeHelper dateTimeHelper, IStoreMappingService storeMappingService, ILanguageService languageService, @@ -34,7 +34,7 @@ public ForumController(IForumService forumService, IUrlRecordService urlRecordService) { _forumService = forumService; - _commonServices = commonServices; + _services = services; _dateTimeHelper = dateTimeHelper; _storeMappingService = storeMappingService; _languageService = languageService; @@ -50,7 +50,7 @@ private void PrepareForumGroupModel(ForumGroupModel model, ForumGroup forumGroup if (model == null) throw new ArgumentNullException("model"); - var allStores = _commonServices.StoreService.GetAllStores(); + var allStores = _services.StoreService.GetAllStores(); model.AvailableStores = allStores.Select(s => s.ToModel()).ToList(); @@ -107,7 +107,7 @@ public ActionResult Index() public ActionResult List() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var forumGroupsModel = _forumService.GetAllForumGroups(true) @@ -137,7 +137,7 @@ public ActionResult List() public ActionResult CreateForumGroup() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var model = new ForumGroupModel { DisplayOrder = 1 }; @@ -152,7 +152,7 @@ public ActionResult CreateForumGroup() [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult CreateForumGroup(ForumGroupModel model, bool continueEditing) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); if (ModelState.IsValid) @@ -171,7 +171,7 @@ public ActionResult CreateForumGroup(ForumGroupModel model, bool continueEditing _storeMappingService.SaveStoreMappings(forumGroup, model.SelectedStoreIds); - NotifySuccess(_commonServices.Localization.GetResource("Admin.ContentManagement.Forums.ForumGroup.Added")); + NotifySuccess(_services.Localization.GetResource("Admin.ContentManagement.Forums.ForumGroup.Added")); return continueEditing ? RedirectToAction("EditForumGroup", new { forumGroup.Id }) : RedirectToAction("List"); } @@ -185,7 +185,7 @@ public ActionResult CreateForumGroup(ForumGroupModel model, bool continueEditing public ActionResult CreateForum() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var model = new ForumModel { DisplayOrder = 1 }; @@ -204,7 +204,7 @@ public ActionResult CreateForum() [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult CreateForum(ForumModel model, bool continueEditing) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); if (ModelState.IsValid) @@ -219,7 +219,7 @@ public ActionResult CreateForum(ForumModel model, bool continueEditing) model.SeName = forum.ValidateSeName(model.SeName, forum.Name, true); _urlRecordService.SaveSlug(forum, model.SeName, 0); - NotifySuccess(_commonServices.Localization.GetResource("Admin.ContentManagement.Forums.Forum.Added")); + NotifySuccess(_services.Localization.GetResource("Admin.ContentManagement.Forums.Forum.Added")); return continueEditing ? RedirectToAction("EditForum", new { forum.Id }) : RedirectToAction("List"); } @@ -239,7 +239,7 @@ public ActionResult CreateForum(ForumModel model, bool continueEditing) public ActionResult EditForumGroup(int id) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var forumGroup = _forumService.GetForumGroupById(id); @@ -263,7 +263,7 @@ public ActionResult EditForumGroup(int id) [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult EditForumGroup(ForumGroupModel model, bool continueEditing) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var forumGroup = _forumService.GetForumGroupById(model.Id); @@ -284,7 +284,7 @@ public ActionResult EditForumGroup(ForumGroupModel model, bool continueEditing) _storeMappingService.SaveStoreMappings(forumGroup, model.SelectedStoreIds); - NotifySuccess(_commonServices.Localization.GetResource("Admin.ContentManagement.Forums.ForumGroup.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.ContentManagement.Forums.ForumGroup.Updated")); return continueEditing ? RedirectToAction("EditForumGroup", forumGroup.Id) : RedirectToAction("List"); } @@ -298,7 +298,7 @@ public ActionResult EditForumGroup(ForumGroupModel model, bool continueEditing) public ActionResult EditForum(int id) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var forum = _forumService.GetForumById(id); @@ -325,7 +325,7 @@ public ActionResult EditForum(int id) [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult EditForum(ForumModel model, bool continueEditing) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var forum = _forumService.GetForumById(model.Id); @@ -344,7 +344,7 @@ public ActionResult EditForum(ForumModel model, bool continueEditing) UpdateLocales(model, forum); - NotifySuccess(_commonServices.Localization.GetResource("Admin.ContentManagement.Forums.Forum.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.ContentManagement.Forums.Forum.Updated")); return continueEditing ? RedirectToAction("EditForum", forum.Id) : RedirectToAction("List"); } @@ -365,7 +365,7 @@ public ActionResult EditForum(ForumModel model, bool continueEditing) [HttpPost] public ActionResult DeleteForumGroup(int id) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var forumGroup = _forumService.GetForumGroupById(id); @@ -374,14 +374,14 @@ public ActionResult DeleteForumGroup(int id) _forumService.DeleteForumGroup(forumGroup); - NotifySuccess(_commonServices.Localization.GetResource("Admin.ContentManagement.Forums.ForumGroup.Deleted")); + NotifySuccess(_services.Localization.GetResource("Admin.ContentManagement.Forums.ForumGroup.Deleted")); return RedirectToAction("List"); } [HttpPost] public ActionResult DeleteForum(int id) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageForums)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageForums)) return AccessDeniedView(); var forum = _forumService.GetForumById(id); @@ -390,7 +390,7 @@ public ActionResult DeleteForum(int id) _forumService.DeleteForum(forum); - NotifySuccess(_commonServices.Localization.GetResource("Admin.ContentManagement.Forums.Forum.Deleted")); + NotifySuccess(_services.Localization.GetResource("Admin.ContentManagement.Forums.Forum.Deleted")); return RedirectToAction("List"); } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs index d66429e90d..f0bc5d51cd 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs @@ -23,7 +23,7 @@ public partial class PaymentController : AdminControllerBase { #region Fields - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private readonly IPaymentService _paymentService; private readonly PaymentSettings _paymentSettings; private readonly IPluginFinder _pluginFinder; @@ -38,7 +38,7 @@ public partial class PaymentController : AdminControllerBase #region Constructors public PaymentController( - ICommonServices commonServices, + ICommonServices services, IPaymentService paymentService, PaymentSettings paymentSettings, IPluginFinder pluginFinder, @@ -48,7 +48,7 @@ public PaymentController( IShippingService shippingService, ICountryService countryService) { - this._commonServices = commonServices; + this._services = services; this._paymentService = paymentService; this._paymentSettings = paymentSettings; this._pluginFinder = pluginFinder; @@ -111,7 +111,7 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment public ActionResult Providers() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) return AccessDeniedView(); var paymentMethodsModel = new List(); @@ -125,7 +125,7 @@ public ActionResult Providers() model.SupportPartiallyRefund = instance.SupportPartiallyRefund; model.SupportRefund = instance.SupportRefund; model.SupportVoid = instance.SupportVoid; - model.RecurringPaymentType = instance.RecurringPaymentType.GetLocalizedEnum(_commonServices.Localization); + model.RecurringPaymentType = instance.RecurringPaymentType.GetLocalizedEnum(_services.Localization); paymentMethodsModel.Add(model); } @@ -134,14 +134,14 @@ public ActionResult Providers() public ActionResult ActivateProvider(string systemName, bool activate) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) return AccessDeniedView(); var pm = _paymentService.LoadPaymentMethodBySystemName(systemName); if (activate && !pm.Value.IsActive) { - NotifyWarning(_commonServices.Localization.GetResource("Admin.Configuration.Payment.CannotActivatePaymentMethod")); + NotifyWarning(_services.Localization.GetResource("Admin.Configuration.Payment.CannotActivatePaymentMethod")); } else { @@ -150,7 +150,7 @@ public ActionResult ActivateProvider(string systemName, bool activate) else _paymentSettings.ActivePaymentMethodSystemNames.Add(pm.Metadata.SystemName); - _commonServices.Settings.SaveSetting(_paymentSettings); + _services.Settings.SaveSetting(_paymentSettings); _pluginMediator.ActivateDependentWidgets(pm.Metadata, activate); } @@ -159,7 +159,7 @@ public ActionResult ActivateProvider(string systemName, bool activate) public ActionResult Edit(string systemName) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) return AccessDeniedView(); var provider = _paymentService.LoadPaymentMethodBySystemName(systemName); @@ -181,7 +181,7 @@ public ActionResult Edit(string systemName) [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Edit(string systemName, bool continueEditing, PaymentMethodEditModel model) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManagePaymentMethods)) return AccessDeniedView(); var provider = _paymentService.LoadPaymentMethodBySystemName(systemName); @@ -217,7 +217,7 @@ public ActionResult Edit(string systemName, bool continueEditing, PaymentMethodE else _paymentService.UpdatePaymentMethod(paymentMethod); - NotifySuccess(_commonServices.Localization.GetResource("Admin.Common.DataEditSuccess")); + NotifySuccess(_services.Localization.GetResource("Admin.Common.DataEditSuccess")); return (continueEditing ? RedirectToAction("Edit", "Payment", new { systemName = systemName }) : diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PluginController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PluginController.cs index bc697dc796..3511fb4d48 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PluginController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PluginController.cs @@ -42,7 +42,7 @@ public partial class PluginController : AdminControllerBase private readonly WidgetSettings _widgetSettings; private readonly IProviderManager _providerManager; private readonly PluginMediator _pluginMediator; - private readonly ICommonServices _commonService; + private readonly ICommonServices _services; #endregion @@ -58,7 +58,7 @@ public PluginController(IPluginFinder pluginFinder, WidgetSettings widgetSettings, IProviderManager providerManager, PluginMediator pluginMediator, - ICommonServices commonService) + ICommonServices services) { this._pluginFinder = pluginFinder; this._permissionService = permissionService; @@ -70,7 +70,7 @@ public PluginController(IPluginFinder pluginFinder, this._widgetSettings = widgetSettings; this._providerManager = providerManager; this._pluginMediator = pluginMediator; - this._commonService = commonService; + this._services = services; } #endregion  @@ -86,19 +86,19 @@ protected PluginModel PreparePluginModel(PluginDescriptor pluginDescriptor, bool if (forList) { - model.FriendlyName = pluginDescriptor.GetLocalizedValue(_commonService.Localization, "FriendlyName"); - model.Description = pluginDescriptor.GetLocalizedValue(_commonService.Localization, "Description"); + model.FriendlyName = pluginDescriptor.GetLocalizedValue(_services.Localization, "FriendlyName"); + model.Description = pluginDescriptor.GetLocalizedValue(_services.Localization, "Description"); } //locales AddLocales(_languageService, model.Locales, (locale, languageId) => { - locale.FriendlyName = pluginDescriptor.GetLocalizedValue(_commonService.Localization, "FriendlyName", languageId, false); - locale.Description = pluginDescriptor.GetLocalizedValue(_commonService.Localization, "Description", languageId, false); + locale.FriendlyName = pluginDescriptor.GetLocalizedValue(_services.Localization, "FriendlyName", languageId, false); + locale.Description = pluginDescriptor.GetLocalizedValue(_services.Localization, "Description", languageId, false); }); // Stores - model.SelectedStoreIds = _commonService.Settings.GetSettingByKey(pluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArray(); + model.SelectedStoreIds = _services.Settings.GetSettingByKey(pluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArray(); // Icon model.IconUrl = _pluginMediator.GetIconUrl(pluginDescriptor); @@ -159,7 +159,7 @@ protected LocalPluginsModel PrepareLocalPluginsModel() IsLocalhost = LicenseChecker.IsLocalhost }; - model.AvailableStores = _commonService.StoreService + model.AvailableStores = _services.StoreService .GetAllStores() .Select(s => s.ToModel()) .ToList(); @@ -239,7 +239,7 @@ public ActionResult ExecuteTasks(IEnumerable pluginsToInstall, IEnumerab // restart application if (tasksCount > 0) { - _commonService.WebHelper.RestartAppDomain(aggressive: true); + _services.WebHelper.RestartAppDomain(aggressive: true); } } catch (Exception exc) @@ -256,7 +256,7 @@ public ActionResult ReloadList() return AccessDeniedView(); //restart application - _commonService.WebHelper.RestartAppDomain(); + _services.WebHelper.RestartAppDomain(); return RedirectToAction("List"); } @@ -271,7 +271,7 @@ public ActionResult ConfigurePlugin(string systemName) return HttpNotFound(); var model = PreparePluginModel(descriptor, false); - model.FriendlyName = descriptor.GetLocalizedValue(_commonService.Localization, "FriendlyName"); + model.FriendlyName = descriptor.GetLocalizedValue(_services.Localization, "FriendlyName"); return View(model); } @@ -343,7 +343,7 @@ public ActionResult LicensePlugin(string systemName, string licenseKey) if (!isLicensable) return Content(T("Admin.Common.ResourceNotFound")); - var stores = _commonService.StoreService.GetAllStores(); + var stores = _services.StoreService.GetAllStores(); var model = new LicensePluginModel { SystemName = systemName, @@ -353,7 +353,7 @@ public ActionResult LicensePlugin(string systemName, string licenseKey) // validate store url foreach (var store in stores) { - if (!_commonService.StoreService.IsStoreDataValid(store)) + if (!_services.StoreService.IsStoreDataValid(store)) { model.InvalidDataStoreId = store.Id; return View(model); @@ -511,11 +511,11 @@ public ActionResult SetSelectedStores(string pk /* SystemName */, string name, F var storeIds = (form["value[]"] ?? "0").Split(',').Select(x => x.ToInt()).Where(x => x > 0).ToList(); if (storeIds.Count > 0) { - _commonService.Settings.SetSetting(settingKey, string.Join(",", storeIds)); + _services.Settings.SetSetting(settingKey, string.Join(",", storeIds)); } else { - _commonService.Settings.DeleteSetting(settingKey); + _services.Settings.DeleteSetting(settingKey); } } catch (Exception ex) @@ -570,7 +570,7 @@ public ActionResult UpdateStringResources(string systemName, string returnUrl = } else { - _commonService.Localization.ImportPluginResourcesFromXml(pluginDescriptor, null, false); + _services.Localization.ImportPluginResourcesFromXml(pluginDescriptor, null, false); NotifySuccess(T("Admin.Configuration.Plugins.Resources.UpdateSuccess")); } @@ -594,11 +594,11 @@ public ActionResult UpdateAllStringResources() { if (plugin.Installed) { - _commonService.Localization.ImportPluginResourcesFromXml(plugin, null, false); + _services.Localization.ImportPluginResourcesFromXml(plugin, null, false); } else { - _commonService.Localization.DeleteLocaleStringResources(plugin.ResourceRootKey); + _services.Localization.DeleteLocaleStringResources(plugin.ResourceRootKey); } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs index 4dd03455e0..05ee6e911d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ShippingController.cs @@ -28,7 +28,7 @@ public partial class ShippingController : AdminControllerBase private readonly ILocalizedEntityService _localizedEntityService; private readonly ILanguageService _languageService; private readonly PluginMediator _pluginMediator; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; private readonly ICustomerService _customerService; #endregion @@ -41,7 +41,7 @@ public ShippingController(IShippingService shippingService, ILocalizedEntityService localizedEntityService, ILanguageService languageService, PluginMediator pluginMediator, - ICommonServices commonServices, + ICommonServices services, ICustomerService customerService) { this._shippingService = shippingService; @@ -50,7 +50,7 @@ public ShippingController(IShippingService shippingService, this._localizedEntityService = localizedEntityService; this._languageService = languageService; this._pluginMediator = pluginMediator; - this._commonServices = commonServices; + this._services = services; this._customerService = customerService; } @@ -140,7 +140,7 @@ private void ApplyRestrictions(ShippingMethod shippingMethod, ShippingMethodMode public ActionResult Providers() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); var shippingProvidersModel = new List(); @@ -157,14 +157,14 @@ public ActionResult Providers() public ActionResult ActivateProvider(string systemName, bool activate) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); var srcm = _shippingService.LoadShippingRateComputationMethodBySystemName(systemName); if (activate && !srcm.Value.IsActive) { - NotifyWarning(_commonServices.Localization.GetResource("Admin.Configuration.Payment.CannotActivateShippingRateComputationMethod")); + NotifyWarning(_services.Localization.GetResource("Admin.Configuration.Payment.CannotActivateShippingRateComputationMethod")); } else { @@ -173,7 +173,7 @@ public ActionResult ActivateProvider(string systemName, bool activate) else _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Add(srcm.Metadata.SystemName); - _commonServices.Settings.SaveSetting(_shippingSettings); + _services.Settings.SaveSetting(_shippingSettings); _pluginMediator.ActivateDependentWidgets(srcm.Metadata, activate); } @@ -186,7 +186,7 @@ public ActionResult ActivateProvider(string systemName, bool activate) public ActionResult Methods() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); var shippingMethodsModel = _shippingService.GetAllShippingMethods() @@ -204,7 +204,7 @@ public ActionResult Methods() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult Methods(GridCommand command) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); var shippingMethodsModel = _shippingService.GetAllShippingMethods() @@ -227,7 +227,7 @@ public ActionResult Methods(GridCommand command) public ActionResult CreateMethod() { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); var model = new ShippingMethodModel(); @@ -241,7 +241,7 @@ public ActionResult CreateMethod() [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult CreateMethod(ShippingMethodModel model, bool continueEditing) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); if (ModelState.IsValid) @@ -254,7 +254,7 @@ public ActionResult CreateMethod(ShippingMethodModel model, bool continueEditing //locales UpdateLocales(sm, model); - NotifySuccess(_commonServices.Localization.GetResource("Admin.Configuration.Shipping.Methods.Added")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Shipping.Methods.Added")); return continueEditing ? RedirectToAction("EditMethod", new { id = sm.Id }) : RedirectToAction("Methods"); } @@ -265,7 +265,7 @@ public ActionResult CreateMethod(ShippingMethodModel model, bool continueEditing public ActionResult EditMethod(int id) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); var sm = _shippingService.GetShippingMethodById(id); @@ -288,7 +288,7 @@ public ActionResult EditMethod(int id) [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult EditMethod(ShippingMethodModel model, bool continueEditing) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); var sm = _shippingService.GetShippingMethodById(model.Id); @@ -305,7 +305,7 @@ public ActionResult EditMethod(ShippingMethodModel model, bool continueEditing) //locales UpdateLocales(sm, model); - NotifySuccess(_commonServices.Localization.GetResource("Admin.Configuration.Shipping.Methods.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Shipping.Methods.Updated")); return continueEditing ? RedirectToAction("EditMethod", sm.Id) : RedirectToAction("Methods"); } @@ -317,7 +317,7 @@ public ActionResult EditMethod(ShippingMethodModel model, bool continueEditing) [HttpPost] public ActionResult DeleteMethod(int id) { - if (!_commonServices.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageShippingSettings)) return AccessDeniedView(); var sm = _shippingService.GetShippingMethodById(id); @@ -326,7 +326,7 @@ public ActionResult DeleteMethod(int id) _shippingService.DeleteShippingMethod(sm); - NotifySuccess(_commonServices.Localization.GetResource("Admin.Configuration.Shipping.Methods.Deleted")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Shipping.Methods.Deleted")); return RedirectToAction("Methods"); } diff --git a/src/Tests/SmartStore.Services.Tests/Catalog/PriceCalculationServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Catalog/PriceCalculationServiceTests.cs index c22aa2c35b..cbcd650019 100644 --- a/src/Tests/SmartStore.Services.Tests/Catalog/PriceCalculationServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Catalog/PriceCalculationServiceTests.cs @@ -28,7 +28,7 @@ public class PriceCalculationServiceTests : ServiceTest IProductAttributeService _productAttributeService; IPriceCalculationService _priceCalcService; IDownloadService _downloadService; - ICommonServices _commonServices; + ICommonServices _services; HttpRequestBase _httpRequestBase; ITaxService _taxService; ShoppingCartSettings _shoppingCartSettings; @@ -52,8 +52,8 @@ public class PriceCalculationServiceTests : ServiceTest _productAttributeService = MockRepository.GenerateMock(); _downloadService = MockRepository.GenerateMock(); - _commonServices = MockRepository.GenerateMock(); - _commonServices.Expect(x => x.StoreContext).Return(_storeContext); + _services = MockRepository.GenerateMock(); + _services.Expect(x => x.StoreContext).Return(_storeContext); _httpRequestBase = MockRepository.GenerateMock(); _taxService = MockRepository.GenerateMock(); @@ -61,7 +61,7 @@ public class PriceCalculationServiceTests : ServiceTest _catalogSettings = new CatalogSettings(); _priceCalcService = new PriceCalculationService(_discountService, _categoryService, _productAttributeParser, _productService, _shoppingCartSettings, _catalogSettings, - _productAttributeService, _downloadService, _commonServices, _httpRequestBase, _taxService); + _productAttributeService, _downloadService, _services, _httpRequestBase, _taxService); } [Test] diff --git a/src/Tests/SmartStore.Services.Tests/ExportImport/ExportManagerTests.cs b/src/Tests/SmartStore.Services.Tests/ExportImport/ExportManagerTests.cs index 19f85f9865..dcdd328196 100644 --- a/src/Tests/SmartStore.Services.Tests/ExportImport/ExportManagerTests.cs +++ b/src/Tests/SmartStore.Services.Tests/ExportImport/ExportManagerTests.cs @@ -35,7 +35,7 @@ public class ExportManagerTests : ServiceTest IExportManager _exportManager; ILanguageService _languageService; MediaSettings _mediaSettings; - ICommonServices _commonServices; + ICommonServices _services; IStoreMappingService _storeMapping; [SetUp] @@ -49,11 +49,11 @@ public class ExportManagerTests : ServiceTest _newsLetterSubscriptionService = MockRepository.GenerateMock(); _languageService = MockRepository.GenerateMock(); _mediaSettings = MockRepository.GenerateMock(); - _commonServices = MockRepository.GenerateMock(); + _services = MockRepository.GenerateMock(); _storeMapping = MockRepository.GenerateMock(); _exportManager = new ExportManager(_categoryService, _manufacturerService, _productService, _productTemplateService, _pictureService, - _newsLetterSubscriptionService, _languageService, _mediaSettings, _commonServices, _storeMapping); + _newsLetterSubscriptionService, _languageService, _mediaSettings, _services, _storeMapping); } //[Test] diff --git a/src/Tests/SmartStore.Services.Tests/Orders/OrderProcessingServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Orders/OrderProcessingServiceTests.cs index aee2f5fb64..10f30b2fe8 100644 --- a/src/Tests/SmartStore.Services.Tests/Orders/OrderProcessingServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Orders/OrderProcessingServiceTests.cs @@ -88,7 +88,7 @@ public class OrderProcessingServiceTests : ServiceTest IAffiliateService _affiliateService; ISettingService _settingService; IDownloadService _downloadService; - ICommonServices _commonServices; + ICommonServices _services; HttpRequestBase _httpRequestBase; IGeoCountryLookup _geoCountryLookup; @@ -155,7 +155,7 @@ public class OrderProcessingServiceTests : ServiceTest _addressService = MockRepository.GenerateMock(); _addressService.Expect(x => x.GetAddressById(_taxSettings.DefaultTaxAddressId)).Return(new Address() { Id = _taxSettings.DefaultTaxAddressId }); _downloadService = MockRepository.GenerateMock(); - _commonServices = MockRepository.GenerateMock(); + _services = MockRepository.GenerateMock(); _httpRequestBase = MockRepository.GenerateMock(); _geoCountryLookup = MockRepository.GenerateMock(); @@ -164,7 +164,7 @@ public class OrderProcessingServiceTests : ServiceTest _rewardPointsSettings = new RewardPointsSettings(); _priceCalcService = new PriceCalculationService(_discountService, _categoryService, _productAttributeParser, _productService, _shoppingCartSettings, _catalogSettings, - _productAttributeService, _downloadService, _commonServices, _httpRequestBase, _taxService); + _productAttributeService, _downloadService, _services, _httpRequestBase, _taxService); _orderTotalCalcService = new OrderTotalCalculationService(_workContext, _storeContext, _priceCalcService, _taxService, _shippingService, _providerManager, diff --git a/src/Tests/SmartStore.Services.Tests/Orders/OrderTotalCalculationServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Orders/OrderTotalCalculationServiceTests.cs index a422832c9a..21affac7fe 100644 --- a/src/Tests/SmartStore.Services.Tests/Orders/OrderTotalCalculationServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Orders/OrderTotalCalculationServiceTests.cs @@ -62,7 +62,7 @@ public class OrderTotalCalculationServiceTests : ServiceTest IEventPublisher _eventPublisher; ISettingService _settingService; IDownloadService _downloadService; - ICommonServices _commonServices; + ICommonServices _services; HttpRequestBase _httpRequestBase; IGeoCountryLookup _geoCountryLookup; Store _store; @@ -129,7 +129,7 @@ public class OrderTotalCalculationServiceTests : ServiceTest _addressService = MockRepository.GenerateMock(); _addressService.Expect(x => x.GetAddressById(_taxSettings.DefaultTaxAddressId)).Return(new Address { Id = _taxSettings.DefaultTaxAddressId }); _downloadService = MockRepository.GenerateMock(); - _commonServices = MockRepository.GenerateMock(); + _services = MockRepository.GenerateMock(); _httpRequestBase = MockRepository.GenerateMock(); _geoCountryLookup = MockRepository.GenerateMock(); @@ -138,7 +138,7 @@ public class OrderTotalCalculationServiceTests : ServiceTest _rewardPointsSettings = new RewardPointsSettings(); _priceCalcService = new PriceCalculationService(_discountService, _categoryService, _productAttributeParser, _productService, _shoppingCartSettings, _catalogSettings, - _productAttributeService, _downloadService, _commonServices, _httpRequestBase, _taxService); + _productAttributeService, _downloadService, _services, _httpRequestBase, _taxService); _orderTotalCalcService = new OrderTotalCalculationService(_workContext, _storeContext, _priceCalcService, _taxService, _shippingService, _providerManager, diff --git a/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs index c323239484..2a4a4499af 100644 --- a/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Payments/PaymentServiceTests.cs @@ -22,7 +22,7 @@ public class PaymentServiceTests : ServiceTest ShoppingCartSettings _shoppingCartSettings; IPaymentService _paymentService; ICurrencyService _currencyService; - ICommonServices _commonServices; + ICommonServices _services; IOrderTotalCalculationService _orderTotalCalculationService; [SetUp] @@ -37,14 +37,14 @@ public class PaymentServiceTests : ServiceTest _shoppingCartSettings = new ShoppingCartSettings(); _paymentMethodRepository = MockRepository.GenerateMock>(); _currencyService = MockRepository.GenerateMock(); - _commonServices = MockRepository.GenerateMock(); + _services = MockRepository.GenerateMock(); _orderTotalCalculationService = MockRepository.GenerateMock(); var localizationService = MockRepository.GenerateMock(); localizationService.Expect(ls => ls.GetResource(null)).IgnoreArguments().Return("NotSupported").Repeat.Any(); _paymentService = new PaymentService(_paymentMethodRepository, _paymentSettings, pluginFinder, _shoppingCartSettings, - this.ProviderManager, _currencyService, _commonServices, _orderTotalCalculationService); + this.ProviderManager, _currencyService, _services, _orderTotalCalculationService); } [Test] From acc3f2f7ef8fa51e70ea40d62c5385a5d08ab371 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 25 Jun 2015 17:55:17 +0200 Subject: [PATCH 0024/1074] Resolves #721 Message Queue: implement "Delete all" --- changelog.md | 3 + ...06211043073_PaymentShippingRestrictions.cs | 8 + .../Controllers/QueuedEmailController.cs | 27 ++++ .../Views/QueuedEmail/List.cshtml | 142 +++++++++--------- 4 files changed, 112 insertions(+), 68 deletions(-) diff --git a/changelog.md b/changelog.md index 6bc68c22a9..21fa3d453a 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,9 @@ * #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" * #702 Facebook and Twitter external authentication suitable for multi-stores +### Improvements +* #721 Message Queue: implement "Delete all" + ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs index 2199b00670..a419e7a9c7 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs @@ -57,6 +57,14 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Restrictions", "Einschrnkungen"); + builder.AddOrUpdate("Admin.Common.DeleteAll", + "Delete all", + "Alle lschen"); + + builder.AddOrUpdate("Admin.Common.RecordsDeleted", + "{0} records were deleted.", + "Es wurden {0} Datenstze gelscht."); + builder.AddOrUpdate("Common.RequestProcessingFailed", "The request could not be processed.
Controller: {0}, Action: {1}, Reason: {2}.", "Die Anfrage konnte nicht ausgefhrt werden.
Controller: {0}, Action: {1}, Grund: {2}."); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs index 685ccf12ae..b152c898fd 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs @@ -223,5 +223,32 @@ public ActionResult DeleteSelected(ICollection selectedIds) return Json(new { Result = true }); } + + [HttpPost, ActionName("List"), FormValueRequired("delete-all")] + public ActionResult DeleteAll() + { + if (!_permissionService.Authorize(StandardPermissionProvider.ManageMessageQueue)) + return AccessDeniedView(); + + int count = 0; + + for (int i = 0; i < 9999999; ++i) + { + var queuedEmails = _queuedEmailService.SearchEmails(null, null, null, null, false, int.MaxValue, false, i, 100, null); + + foreach (var email in queuedEmails) + { + _queuedEmailService.DeleteQueuedEmail(email); + ++count; + } + + if (!queuedEmails.HasNextPage) + break; + } + + NotifySuccess(T("Admin.Common.RecordsDeleted", count)); + + return RedirectToAction("List"); + } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml index 6da45a0a2a..d4497b7a7a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml @@ -12,51 +12,56 @@ @T("Admin.System.QueuedEmails")
- + +
- - - - - - - - - - - - - - - - - - - - - + +
- @Html.SmartLabelFor(model => model.SearchStartDate) - - @Html.EditorFor(model => model.SearchStartDate) -
- @Html.SmartLabelFor(model => model.SearchEndDate) - - @Html.EditorFor(model => Model.SearchEndDate) -
- @Html.SmartLabelFor(model => model.SearchFromEmail) - - @Html.EditorFor(model => Model.SearchFromEmail) -
- @Html.SmartLabelFor(model => model.SearchToEmail) - - @Html.EditorFor(model => Model.SearchToEmail) -
- @Html.SmartLabelFor(model => model.SearchLoadNotSent) - - @Html.EditorFor(model => Model.SearchLoadNotSent) -
+ + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + - - - + + + - -
+ @Html.SmartLabelFor(model => model.SearchStartDate) + + @Html.EditorFor(model => model.SearchStartDate) +
+ @Html.SmartLabelFor(model => model.SearchEndDate) + + @Html.EditorFor(model => Model.SearchEndDate) +
+ @Html.SmartLabelFor(model => model.SearchFromEmail) + + @Html.EditorFor(model => Model.SearchFromEmail) +
+ @Html.SmartLabelFor(model => model.SearchToEmail) + + @Html.EditorFor(model => Model.SearchToEmail) +
+ @Html.SmartLabelFor(model => model.SearchLoadNotSent) + + @Html.EditorFor(model => Model.SearchLoadNotSent) +
@Html.SmartLabelFor(model => model.SearchSendManually) @@ -70,36 +75,37 @@ })
- @Html.SmartLabelFor(model => model.SearchMaxSentTries) - - @Html.EditorFor(model => Model.SearchMaxSentTries) -
- @Html.SmartLabelFor(model => model.GoDirectlyToNumber) - - @Html.EditorFor(model => Model.GoDirectlyToNumber) -
+ @Html.SmartLabelFor(model => model.SearchMaxSentTries) + + @Html.EditorFor(model => Model.SearchMaxSentTries) +
+ @Html.SmartLabelFor(model => model.GoDirectlyToNumber) + + @Html.EditorFor(model => Model.GoDirectlyToNumber) + -
+
  - -
-

-

+ +
+ +

+ + + + + + + + +
From c4a816b929a92561b082c99c02618e1c3e855edf Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 25 Jun 2015 19:55:49 +0200 Subject: [PATCH 0025/1074] (Perf) implemented static cache for active url slugs, which are all loaded on app startup now. Boosts app startup perf up to 30%. To disable this feature, set 'SeoSettings.LoadAllUrlAliasesOnStartup' to false (true by default). --- changelog.md | 1 + .../SmartStore.Core/Domain/Seo/SeoSettings.cs | 6 ++ ...06211043073_PaymentShippingRestrictions.cs | 1 + .../Seo/UrlRecordService.cs | 98 +++++++++++++------ .../Controllers/CatalogController.cs | 6 +- .../Installation/InstallDataSeeder.cs | 4 +- 6 files changed, 83 insertions(+), 33 deletions(-) diff --git a/changelog.md b/changelog.md index 21fa3d453a..96936ed74e 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ * #702 Facebook and Twitter external authentication suitable for multi-stores ### Improvements +* (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. * #721 Message Queue: implement "Delete all" diff --git a/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs b/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs index 6dacb605a6..2479662974 100644 --- a/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs @@ -17,6 +17,7 @@ public SeoSettings() CanonicalHostNameRule = Seo.CanonicalHostNameRule.NoRule; ReservedUrlRecordSlugs = new List() { "admin", "install", "recentlyviewedproducts", "newproducts", "compareproducts", "clearcomparelist", "setproductreviewhelpfulness", "login", "register", "logout", "cart", "wishlist", "emailwishlist", "checkout", "contactus", "passwordrecovery", "subscribenewsletter", "blog", "boards", "inboxupdate", "sentupdate", "news", "sitemap", "sitemapseo", "search", "config", "api", "odata" }; ExtraRobotsDisallows = new List(); + LoadAllUrlAliasesOnStartup = true; } public string PageTitleSeparator { get; set; } @@ -37,5 +38,10 @@ public SeoSettings() public List ReservedUrlRecordSlugs { get; set; } public List ExtraRobotsDisallows { get; set; } + + /// + /// A value indicating whether to load all URL records and active slugs on application startup + /// + public bool LoadAllUrlAliasesOnStartup { get; set; } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs index a419e7a9c7..1f5f6223e8 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs @@ -48,6 +48,7 @@ public void Seed(SmartObjectContext context) context.MigrateSettings(x => { x.Add("localizationsettings.loadalllocalizedpropertiesonstartup", true); + x.Add("seosettings.loadallurlaliasesonstartup", true); }); } diff --git a/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs b/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs index b49a0044e1..a3bc57d68e 100644 --- a/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs +++ b/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs @@ -16,8 +16,11 @@ public partial class UrlRecordService : IUrlRecordService { #region Constants - private const string URLRECORD_ACTIVE_BY_ID_NAME_LANGUAGE_KEY = "SmartStore.urlrecord.active.id-name-language-{0}-{1}-{2}"; - private const string URLRECORD_PATTERN_KEY = "SmartStore.urlrecord."; + // {0} = id, {1} = name, {2} = language + private const string URLRECORD_KEY = "SmartStore.urlrecord.{0}-{1}-{2}"; + private const string URLRECORD_ALL_ACTIVESLUGS_KEY = "SmartStore.urlrecord.all-active-slugs"; + private const string URLRECORD_ALL_KEY = "SmartStore.urlrecord.all"; + private const string URLRECORD_PATTERN_KEY = "SmartStore.urlrecord."; #endregion @@ -25,15 +28,17 @@ public partial class UrlRecordService : IUrlRecordService private readonly IRepository _urlRecordRepository; private readonly ICacheManager _cacheManager; + private readonly SeoSettings _seoSettings; #endregion #region Ctor - public UrlRecordService(ICacheManager cacheManager, IRepository urlRecordRepository) + public UrlRecordService(ICacheManager cacheManager, IRepository urlRecordRepository, SeoSettings seoSettings) { this._cacheManager = cacheManager; this._urlRecordRepository = urlRecordRepository; + this._seoSettings = seoSettings; } #endregion @@ -81,18 +86,6 @@ public virtual void UpdateUrlRecord(UrlRecord urlRecord) _cacheManager.RemoveByPattern(URLRECORD_PATTERN_KEY); } - public virtual UrlRecord GetBySlug(string slug) - { - if (String.IsNullOrEmpty(slug)) - return null; - - var query = from ur in _urlRecordRepository.Table - where ur.Slug == slug - select ur; - var urlRecord = query.FirstOrDefault(); - return urlRecord; - } - public virtual IPagedList GetAllUrlRecords(string slug, int pageIndex, int pageSize) { var query = _urlRecordRepository.Table; @@ -121,21 +114,63 @@ public virtual IList GetUrlRecordsFor(string entityName, int entityId return query.ToList(); } + public virtual UrlRecord GetBySlug(string slug) + { + // INFO: (mc) Caching unnecessary here. This is not a 'bottleneck' function. + if (String.IsNullOrEmpty(slug)) + return null; + + var query = from ur in _urlRecordRepository.Table + where ur.Slug == slug + select ur; + var urlRecord = query.FirstOrDefault(); + return urlRecord; + } + public virtual string GetActiveSlug(int entityId, string entityName, int languageId) - { - string key = string.Format(URLRECORD_ACTIVE_BY_ID_NAME_LANGUAGE_KEY, entityId, entityName, languageId); - return _cacheManager.Get(key, () => - { - var query = from ur in _urlRecordRepository.Table - where ur.EntityId == entityId && - ur.EntityName == entityName && - ur.LanguageId == languageId && - ur.IsActive - orderby ur.Id descending - select ur.Slug; - var slug = query.FirstOrDefault(); - return slug ?? ""; - }); + { + string slug = null; + + if (_seoSettings.LoadAllUrlAliasesOnStartup) + { + var allActiveSlugs = _cacheManager.Get(URLRECORD_ALL_ACTIVESLUGS_KEY, () => + { + var query = from x in _urlRecordRepository.TableUntracked + where x.IsActive + orderby x.Id descending + select x; + + var result = query.ToDictionary( + x => GenerateKey(x.EntityId, x.EntityName, x.LanguageId), // Key + x => x.Slug, // Value + StringComparer.OrdinalIgnoreCase); + + return result; + }); + + var key = GenerateKey(entityId, entityName, languageId); + if (!allActiveSlugs.TryGetValue(key, out slug)) + { + return string.Empty; + } + } + else + { + string cacheKey = string.Format(URLRECORD_KEY, entityId, entityName, languageId); + slug = _cacheManager.Get(cacheKey, () => + { + var query = from ur in _urlRecordRepository.Table + where ur.EntityId == entityId && + ur.EntityName == entityName && + ur.LanguageId == languageId && + ur.IsActive + orderby ur.Id descending + select ur.Slug; + return query.FirstOrDefault() ?? string.Empty; + }); + } + + return slug; } public virtual UrlRecord SaveSlug(T entity, string slug, int languageId) where T : BaseEntity, ISlugSupported @@ -265,6 +300,11 @@ public virtual UrlRecord SaveSlug(T entity, Expression> nameP return SaveSlug(entity, existingSeName, 0); } + private string GenerateKey(int entityId, string entityName, int languageId) + { + return "{0}.{1}.{2}".FormatInvariant(entityId, entityName, languageId); + } + #endregion } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs index ab0236bc10..7c210cee70 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs @@ -181,13 +181,13 @@ public ActionResult Category(int categoryId, CatalogPagingFilteringModel command var customerRolesIds = _services.WorkContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); - //subcategories + // subcategories model.SubCategories = _categoryService .GetAllCategoriesByParentCategoryId(categoryId) .Select(x => { var subCatName = x.GetLocalized(y => y.Name); - var subCatModel = new CategoryModel.SubCategoryModel() + var subCatModel = new CategoryModel.SubCategoryModel { Id = x.Id, Name = subCatName, @@ -610,7 +610,7 @@ public ActionResult ManufacturerNavigation(int currentManufacturerId) foreach (var manufacturer in manufacturers.Take(_catalogSettings.ManufacturersBlockItemsToDisplay)) { - var modelMan = new ManufacturerBriefInfoModel() + var modelMan = new ManufacturerBriefInfoModel { Id = manufacturer.Id, Name = manufacturer.GetLocalized(x => x.Name), diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs index 60107decb1..597a33ef39 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs @@ -614,9 +614,11 @@ private void SetModified(TEntity entity) private string ValidateSeName(TEntity entity, string name) where TEntity : BaseEntity, ISlugSupported { + var seoSettings = new SeoSettings { LoadAllUrlAliasesOnStartup = false }; + if (_urlRecordService == null) { - _urlRecordService = new UrlRecordService(NullCache.Instance, new EfRepository(_ctx) { AutoCommitEnabled = false }); + _urlRecordService = new UrlRecordService(NullCache.Instance, new EfRepository(_ctx) { AutoCommitEnabled = false }, seoSettings); } return entity.ValidateSeName("", name, true, _urlRecordService, new SeoSettings()); From 468b0f9e034f86ac7e32a009d35005e3637ce788 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 25 Jun 2015 21:12:45 +0200 Subject: [PATCH 0026/1074] Web.config cleanup --- src/Presentation/SmartStore.Web/Web.Release.config | 3 +-- src/Presentation/SmartStore.Web/Web.config | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Web.Release.config b/src/Presentation/SmartStore.Web/Web.Release.config index f4b9a73aaa..49f9b30567 100644 --- a/src/Presentation/SmartStore.Web/Web.Release.config +++ b/src/Presentation/SmartStore.Web/Web.Release.config @@ -14,8 +14,7 @@ - - + diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index 32291a4cfb..cf1a8fedd3 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -86,7 +86,7 @@ - + From 3bc8a235a23a162ef82ccb15a9a9a5aeddd242b6 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 25 Jun 2015 23:32:43 +0200 Subject: [PATCH 0027/1074] * Added method IEmailAccountService.GetDefaultEmailAccount() * (Perf) added request caching to EmailAccountService --- .../SmartStore.Core/Email/EmailMessage.cs | 5 -- .../Messages/EmailAccountService.cs | 87 ++++++++++--------- .../Messages/IEmailAccountService.cs | 6 ++ .../Messages/MessageTokenProvider.cs | 6 +- .../Messages/QueuedEmailService.cs | 6 +- .../Messages/WorkflowMessageService.cs | 4 +- .../Seo/UrlRecordService.cs | 1 - .../Controllers/CampaignController.cs | 6 +- .../Controllers/CustomerController.cs | 6 +- .../Controllers/HomeController.cs | 4 +- 10 files changed, 64 insertions(+), 67 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Email/EmailMessage.cs b/src/Libraries/SmartStore.Core/Email/EmailMessage.cs index 58a8508c07..426f83e100 100644 --- a/src/Libraries/SmartStore.Core/Email/EmailMessage.cs +++ b/src/Libraries/SmartStore.Core/Email/EmailMessage.cs @@ -78,11 +78,6 @@ public EmailMessage(EmailAddress to, string subject, string body, EmailAddress f public NameValueCollection Headers { get; private set; } - public void AddAttachment(Attachment attachment) - { - this.Attachments.Add(attachment); - } - public async void BodyFromFile(string filePathOrUrl) { StreamReader sr = null; diff --git a/src/Libraries/SmartStore.Services/Messages/EmailAccountService.cs b/src/Libraries/SmartStore.Services/Messages/EmailAccountService.cs index ebf71742dc..639c0391cb 100644 --- a/src/Libraries/SmartStore.Services/Messages/EmailAccountService.cs +++ b/src/Libraries/SmartStore.Services/Messages/EmailAccountService.cs @@ -2,36 +2,37 @@ using System.Collections.Generic; using System.Linq; using SmartStore.Core; +using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Events; namespace SmartStore.Services.Messages { - public partial class EmailAccountService:IEmailAccountService + public partial class EmailAccountService : IEmailAccountService { - private readonly IRepository _emailAccountRepository; + private const string EMAILACCOUNT_BY_ID_KEY = "SmartStore.emailaccount.id-{0}"; + private const string EMAILACCOUNT_PATTERN_KEY = "SmartStore.emailaccount."; + + private readonly IRepository _emailAccountRepository; private readonly EmailAccountSettings _emailAccountSettings; private readonly IEventPublisher _eventPublisher; + private readonly ICacheManager _cacheManager; - /// - /// Ctor - /// - /// Email account repository - /// - /// Event published - public EmailAccountService(IRepository emailAccountRepository, - EmailAccountSettings emailAccountSettings, IEventPublisher eventPublisher) + private EmailAccount _defaultEmailAccount; + + public EmailAccountService( + IRepository emailAccountRepository, + EmailAccountSettings emailAccountSettings, + IEventPublisher eventPublisher, + ICacheManager cacheManager /* request */) { - _emailAccountRepository = emailAccountRepository; - _emailAccountSettings = emailAccountSettings; - _eventPublisher = eventPublisher; + this._emailAccountRepository = emailAccountRepository; + this._emailAccountSettings = emailAccountSettings; + this._eventPublisher = eventPublisher; + this._cacheManager = cacheManager; } - /// - /// Inserts an email account - /// - /// Email account public virtual void InsertEmailAccount(EmailAccount emailAccount) { if (emailAccount == null) @@ -57,14 +58,12 @@ public virtual void InsertEmailAccount(EmailAccount emailAccount) _emailAccountRepository.Insert(emailAccount); - //event notification + _cacheManager.RemoveByPattern(EMAILACCOUNT_PATTERN_KEY); + _defaultEmailAccount = null; + _eventPublisher.EntityInserted(emailAccount); } - /// - /// Updates an email account - /// - /// Email account public virtual void UpdateEmailAccount(EmailAccount emailAccount) { if (emailAccount == null) @@ -90,14 +89,12 @@ public virtual void UpdateEmailAccount(EmailAccount emailAccount) _emailAccountRepository.Update(emailAccount); - //event notification + _cacheManager.RemoveByPattern(EMAILACCOUNT_PATTERN_KEY); + _defaultEmailAccount = null; + _eventPublisher.EntityUpdated(emailAccount); } - /// - /// Deletes an email account - /// - /// Email account public virtual void DeleteEmailAccount(EmailAccount emailAccount) { if (emailAccount == null) @@ -108,28 +105,38 @@ public virtual void DeleteEmailAccount(EmailAccount emailAccount) _emailAccountRepository.Delete(emailAccount); - //event notification + _cacheManager.RemoveByPattern(EMAILACCOUNT_PATTERN_KEY); + _defaultEmailAccount = null; + _eventPublisher.EntityDeleted(emailAccount); } - /// - /// Gets an email account by identifier - /// - /// The email account identifier - /// Email account public virtual EmailAccount GetEmailAccountById(int emailAccountId) { if (emailAccountId == 0) return null; - - var emailAccount = _emailAccountRepository.GetById(emailAccountId); - return emailAccount; + + string key = string.Format(EMAILACCOUNT_BY_ID_KEY, emailAccountId); + return _cacheManager.Get(key, () => + { + return _emailAccountRepository.GetById(emailAccountId); + }); } - /// - /// Gets all email accounts - /// - /// Email accounts list + public virtual EmailAccount GetDefaultEmailAccount() + { + if (_defaultEmailAccount == null) + { + _defaultEmailAccount = GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); + if (_defaultEmailAccount == null) + { + _defaultEmailAccount = GetAllEmailAccounts().FirstOrDefault(); + } + } + + return _defaultEmailAccount; + } + public virtual IList GetAllEmailAccounts() { var query = from ea in _emailAccountRepository.Table diff --git a/src/Libraries/SmartStore.Services/Messages/IEmailAccountService.cs b/src/Libraries/SmartStore.Services/Messages/IEmailAccountService.cs index 5f03d721bd..6b3df6f6eb 100644 --- a/src/Libraries/SmartStore.Services/Messages/IEmailAccountService.cs +++ b/src/Libraries/SmartStore.Services/Messages/IEmailAccountService.cs @@ -30,6 +30,12 @@ public partial interface IEmailAccountService /// Email account EmailAccount GetEmailAccountById(int emailAccountId); + /// + /// Gets the default email account + /// + /// Emil account + EmailAccount GetDefaultEmailAccount(); + /// /// Gets all email accounts /// diff --git a/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs b/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs index e2f7ad3cac..ed4c1ea719 100644 --- a/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs +++ b/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs @@ -669,15 +669,11 @@ public virtual void AddStoreTokens(IList tokens, Store store) { tokens.Add(new Token("Store.Name", store.Name)); tokens.Add(new Token("Store.URL", store.Url, true)); - var defaultEmailAccount = _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); - if (defaultEmailAccount == null) - defaultEmailAccount = _emailAccountService.GetAllEmailAccounts().FirstOrDefault(); + var defaultEmailAccount = _emailAccountService.GetDefaultEmailAccount(); tokens.Add(new Token("Store.SupplierIdentification", GetSupplierIdentification(), true)); tokens.Add(new Token("Store.Email", defaultEmailAccount.Email)); } - //codehint: sm-add begin - public virtual void AddCompanyTokens(IList tokens) { tokens.Add(new Token("Company.CompanyName", _companyInfoSettings.CompanyName)); diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 4dc57c2c83..5e72bca45a 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -108,13 +108,13 @@ public virtual IList GetQueuedEmailsByIds(int[] queuedEmailIds) if (queuedEmailIds == null || queuedEmailIds.Length == 0) return new List(); - var query = from qe in _queuedEmailRepository.Table + var query = from qe in _queuedEmailRepository.Table.Expand(x => x.EmailAccount) where queuedEmailIds.Contains(qe.Id) select qe; var queuedEmails = query.ToList(); - //sort by passed identifiers + // sort by passed identifiers var sortedQueuedEmails = new List(); foreach (int id in queuedEmailIds) @@ -149,7 +149,7 @@ public virtual IPagedList SearchEmails(string fromEmail, fromEmail = (fromEmail ?? String.Empty).Trim(); toEmail = (toEmail ?? String.Empty).Trim(); - var query = _queuedEmailRepository.Table; + var query = _queuedEmailRepository.Table.Expand(x => x.EmailAccount); if (!String.IsNullOrEmpty(fromEmail)) query = query.Where(qe => qe.From.Contains(fromEmail)); diff --git a/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs b/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs index bbad203299..b194690096 100644 --- a/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs +++ b/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs @@ -135,9 +135,7 @@ protected EmailAccount GetEmailAccountOfMessageTemplate(MessageTemplate messageT var emailAccounId = messageTemplate.GetLocalized(mt => mt.EmailAccountId, languageId); var emailAccount = _emailAccountService.GetEmailAccountById(emailAccounId); if (emailAccount == null) - emailAccount = _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); - if (emailAccount == null) - emailAccount = _emailAccountService.GetAllEmailAccounts().FirstOrDefault(); + emailAccount = _emailAccountService.GetDefaultEmailAccount(); return emailAccount; } diff --git a/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs b/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs index a3bc57d68e..dc5950affa 100644 --- a/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs +++ b/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs @@ -19,7 +19,6 @@ public partial class UrlRecordService : IUrlRecordService // {0} = id, {1} = name, {2} = language private const string URLRECORD_KEY = "SmartStore.urlrecord.{0}-{1}-{2}"; private const string URLRECORD_ALL_ACTIVESLUGS_KEY = "SmartStore.urlrecord.all-active-slugs"; - private const string URLRECORD_ALL_KEY = "SmartStore.urlrecord.all"; private const string URLRECORD_PATTERN_KEY = "SmartStore.urlrecord."; #endregion diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CampaignController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CampaignController.cs index ade2d40e53..ae1a1ff375 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CampaignController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CampaignController.cs @@ -200,14 +200,14 @@ public ActionResult SendTestEmail(CampaignModel model) try { - var emailAccount = _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); + var emailAccount = _emailAccountService.GetDefaultEmailAccount(); if (emailAccount == null) throw new SmartException("Email account could not be loaded"); var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(model.TestEmail); if (subscription != null) { - //there's a subscription. let's use it + // there's a subscription. let's use it var subscriptions = new List(); subscriptions.Add(subscription); _campaignService.SendCampaign(campaign, emailAccount, subscriptions); @@ -245,7 +245,7 @@ public ActionResult SendMassEmail(CampaignModel model) try { - var emailAccount = _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); + var emailAccount = _emailAccountService.GetDefaultEmailAccount(); if (emailAccount == null) throw new SmartException("Email account could not be loaded"); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs index 0a8e0c6858..90194daeb2 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs @@ -1035,13 +1035,11 @@ public ActionResult SendEmail(CustomerModel model) if (String.IsNullOrWhiteSpace(model.SendEmail.Body)) throw new SmartException("Email body is empty"); - var emailAccount = _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); - if (emailAccount == null) - emailAccount = _emailAccountService.GetAllEmailAccounts().FirstOrDefault(); + var emailAccount = _emailAccountService.GetDefaultEmailAccount(); if (emailAccount == null) throw new SmartException("Email account can't be loaded"); - var email = new QueuedEmail() + var email = new QueuedEmail { EmailAccountId = emailAccount.Id, FromName = emailAccount.DisplayName, diff --git a/src/Presentation/SmartStore.Web/Controllers/HomeController.cs b/src/Presentation/SmartStore.Web/Controllers/HomeController.cs index cd16a058b6..8c1f8fc125 100644 --- a/src/Presentation/SmartStore.Web/Controllers/HomeController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/HomeController.cs @@ -141,9 +141,7 @@ public ActionResult ContactUsSend(ContactUsModel model, bool captchaValid) string fullName = model.FullName; string subject = T("ContactUs.EmailSubject", _services.StoreContext.CurrentStore.Name); - var emailAccount = _emailAccountService.Value.GetEmailAccountById(EngineContext.Current.Resolve().DefaultEmailAccountId); - if (emailAccount == null) - emailAccount = _emailAccountService.Value.GetAllEmailAccounts().FirstOrDefault(); + var emailAccount = _emailAccountService.Value.GetDefaultEmailAccount(); string from = null; string fromName = null; From 3be7136a59c9aacc0b77d401f88eb99ddf06b410 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 26 Jun 2015 19:25:07 +0200 Subject: [PATCH 0028/1074] Refactored 'DeleteAllQueuedEmails()': did not operate reliably and was too slow --- .../Messages/IQueuedEmailService.cs | 6 ++ .../Messages/QueuedEmailService.cs | 72 +++++++------------ .../Controllers/QueuedEmailController.cs | 25 ++----- 3 files changed, 38 insertions(+), 65 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs index e01c330ba0..6b1db9e52c 100644 --- a/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs @@ -25,6 +25,12 @@ public partial interface IQueuedEmailService /// Queued email void DeleteQueuedEmail(QueuedEmail queuedEmail); + /// + /// Deletes all queued emails + /// + /// The count of deleted entries + int DeleteAllQueuedEmails(); + /// /// Gets a queued email by identifier /// diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 5e72bca45a..2bd191bede 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -19,11 +19,6 @@ public partial class QueuedEmailService : IQueuedEmailService private readonly ILogger _logger; private readonly ILocalizationService _localizationService; - /// - /// Ctor - /// - /// Queued email repository - /// Event published public QueuedEmailService( IRepository queuedEmailRepository, IEventPublisher eventPublisher, @@ -37,11 +32,7 @@ public QueuedEmailService( _logger = logger; _localizationService = localizationService; } - - /// - /// Inserts a queued email - /// - /// Queued email + public virtual void InsertQueuedEmail(QueuedEmail queuedEmail) { if (queuedEmail == null) @@ -53,10 +44,6 @@ public virtual void InsertQueuedEmail(QueuedEmail queuedEmail) _eventPublisher.EntityInserted(queuedEmail); } - /// - /// Updates a queued email - /// - /// Queued email public virtual void UpdateQueuedEmail(QueuedEmail queuedEmail) { if (queuedEmail == null) @@ -68,10 +55,6 @@ public virtual void UpdateQueuedEmail(QueuedEmail queuedEmail) _eventPublisher.EntityUpdated(queuedEmail); } - /// - /// Deleted a queued email - /// - /// Queued email public virtual void DeleteQueuedEmail(QueuedEmail queuedEmail) { if (queuedEmail == null) @@ -83,11 +66,30 @@ public virtual void DeleteQueuedEmail(QueuedEmail queuedEmail) _eventPublisher.EntityDeleted(queuedEmail); } - /// - /// Gets a queued email by identifier - /// - /// Queued email identifier - /// Queued email + public virtual int DeleteAllQueuedEmails() + { + var autoCommit = _queuedEmailRepository.AutoCommitEnabled; + _queuedEmailRepository.AutoCommitEnabled = false; + + var count = 0; + + using (var scope = new DbContextScope(autoDetectChanges: false, validateOnSave: false, hooksEnabled: false)) + { + var queuedEmails = _queuedEmailRepository.Table.ToList(); + foreach (var chunk in queuedEmails.Chunk(500)) + { + _queuedEmailRepository.DeleteRange(chunk.ToList()); + _queuedEmailRepository.Context.SaveChanges(); + } + + count = queuedEmails.Count; + } + + _queuedEmailRepository.AutoCommitEnabled = autoCommit; + + return count; + } + public virtual QueuedEmail GetQueuedEmailById(int queuedEmailId) { if (queuedEmailId == 0) @@ -98,11 +100,6 @@ public virtual QueuedEmail GetQueuedEmailById(int queuedEmailId) } - /// - /// Get queued emails by identifiers - /// - /// queued email identifiers - /// Queued emails public virtual IList GetQueuedEmailsByIds(int[] queuedEmailIds) { if (queuedEmailIds == null || queuedEmailIds.Length == 0) @@ -126,20 +123,6 @@ where queuedEmailIds.Contains(qe.Id) return sortedQueuedEmails; } - /// - /// Gets all queued emails - /// - /// From Email - /// To Email - /// The start time - /// The end time - /// A value indicating whether to load only not sent emails - /// Maximum send tries - /// A value indicating whether we should sort queued email descending; otherwise, ascending. - /// Page index - /// Page size - /// A value indicating whether to load manually send emails - /// Email item list public virtual IPagedList SearchEmails(string fromEmail, string toEmail, DateTime? startTime, DateTime? endTime, bool loadUnsentItemsOnly, int maxSendTries, @@ -181,11 +164,6 @@ public virtual IPagedList SearchEmails(string fromEmail, return queuedEmails; } - /// - /// Sends a queued email - /// - /// Queued email - /// Whether the operation succeeded public virtual bool SendEmail(QueuedEmail queuedEmail) { var result = false; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs index b152c898fd..2b6f9fce31 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs @@ -21,7 +21,8 @@ public class QueuedEmailController : AdminControllerBase private readonly ILocalizationService _localizationService; private readonly IPermissionService _permissionService; - public QueuedEmailController(IQueuedEmailService queuedEmailService, + public QueuedEmailController( + IQueuedEmailService queuedEmailService, IDateTimeHelper dateTimeHelper, ILocalizationService localizationService, IPermissionService permissionService) { @@ -217,8 +218,10 @@ public ActionResult DeleteSelected(ICollection selectedIds) { var queuedEmails = _queuedEmailService.GetQueuedEmailsByIds(selectedIds.ToArray()); - foreach (var queuedEmail in queuedEmails) - _queuedEmailService.DeleteQueuedEmail(queuedEmail); + foreach (var queuedEmail in queuedEmails) + { + _queuedEmailService.DeleteQueuedEmail(queuedEmail); + } } return Json(new { Result = true }); @@ -230,21 +233,7 @@ public ActionResult DeleteAll() if (!_permissionService.Authorize(StandardPermissionProvider.ManageMessageQueue)) return AccessDeniedView(); - int count = 0; - - for (int i = 0; i < 9999999; ++i) - { - var queuedEmails = _queuedEmailService.SearchEmails(null, null, null, null, false, int.MaxValue, false, i, 100, null); - - foreach (var email in queuedEmails) - { - _queuedEmailService.DeleteQueuedEmail(email); - ++count; - } - - if (!queuedEmails.HasNextPage) - break; - } + int count = _queuedEmailService.DeleteAllQueuedEmails(); NotifySuccess(T("Admin.Common.RecordsDeleted", count)); From 866108a5e83f4516d58c481adb0f93678e228824 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 26 Jun 2015 21:52:07 +0200 Subject: [PATCH 0029/1074] Added DeleteAll() extension method to IRepository --- .../Data/RepositoryExtensions.cs | 40 +++++++++++++++++++ .../Messages/QueuedEmailService.cs | 21 +--------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs b/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs index 2e6e8ac414..8551dd2882 100644 --- a/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs +++ b/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs @@ -51,6 +51,46 @@ public static void Delete(this IRepository rs, object id) where T : BaseEn } } + /// + /// Truncates the whole table + /// + /// Entity type + /// + /// The total number of affected entities + /// + /// This method turns off auto detection, validation and hooking. + /// + public static int DeleteAll(this IRepository rs) where T : BaseEntity + { + var autoCommit = rs.AutoCommitEnabled; + rs.AutoCommitEnabled = false; + + var count = 0; + + try + { + using (var scope = new DbContextScope(autoDetectChanges: false, validateOnSave: false, hooksEnabled: false)) + { + var records = rs.Table.ToList(); + foreach (var chunk in records.Chunk(500)) + { + rs.DeleteRange(chunk.ToList()); + count += rs.Context.SaveChanges(); + } + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + rs.AutoCommitEnabled = autoCommit; + } + + return count; + } + public static IQueryable Get( this IRepository rs, Expression> predicate = null, diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 2bd191bede..4a504d5f62 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -68,26 +68,7 @@ public virtual void DeleteQueuedEmail(QueuedEmail queuedEmail) public virtual int DeleteAllQueuedEmails() { - var autoCommit = _queuedEmailRepository.AutoCommitEnabled; - _queuedEmailRepository.AutoCommitEnabled = false; - - var count = 0; - - using (var scope = new DbContextScope(autoDetectChanges: false, validateOnSave: false, hooksEnabled: false)) - { - var queuedEmails = _queuedEmailRepository.Table.ToList(); - foreach (var chunk in queuedEmails.Chunk(500)) - { - _queuedEmailRepository.DeleteRange(chunk.ToList()); - _queuedEmailRepository.Context.SaveChanges(); - } - - count = queuedEmails.Count; - } - - _queuedEmailRepository.AutoCommitEnabled = autoCommit; - - return count; + return _queuedEmailRepository.DeleteAll(); } public virtual QueuedEmail GetQueuedEmailById(int queuedEmailId) From db0f0e5ff24bfe38fbe90ae968b94811bc772a92 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 26 Jun 2015 22:55:34 +0200 Subject: [PATCH 0030/1074] E-mail attachments: added entity & map --- .../EmailAttachmentStorageLocation.cs | 22 +++ .../Domain/Messages/QueuedEmail.cs | 14 +- .../Domain/Messages/QueuedEmailAttachment.cs | 66 +++++++++ .../SmartStore.Core/SmartStore.Core.csproj | 2 + .../Messages/QueuedEmailAttachmentMap.cs | 34 +++++ ...2044329_QueuedEmailAttachments.Designer.cs | 29 ++++ .../201506262044329_QueuedEmailAttachments.cs | 40 ++++++ ...01506262044329_QueuedEmailAttachments.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 8 ++ .../Controllers/EmailAccountController.cs | 4 +- 10 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs create mode 100644 src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs create mode 100644 src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.resx diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs new file mode 100644 index 0000000000..dc5f240370 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs @@ -0,0 +1,22 @@ +using System; + +namespace SmartStore.Core.Domain.Messages +{ + public enum EmailAttachmentStorageLocation + { + /// + /// Attachment is embedded as Blob + /// + Blob, + + /// + /// Attachment is a reference to + /// + FileReference, + + /// + /// Attachment is located on disk (physical or virtual path) + /// + Path + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs index 573231b382..f04ae054ea 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace SmartStore.Core.Domain.Messages { @@ -7,7 +8,9 @@ namespace SmartStore.Core.Domain.Messages /// public partial class QueuedEmail : BaseEntity { - /// + private ICollection _attachments; + + /// /// Gets or sets the priority /// public int Priority { get; set; } @@ -91,5 +94,14 @@ public partial class QueuedEmail : BaseEntity /// Gets the email account /// public virtual EmailAccount EmailAccount { get; set; } + + /// + /// Gets or sets the collection of attachments + /// + public virtual ICollection Attachments + { + get { return _attachments ?? (_attachments = new HashSet()); } + protected set { _attachments = value; } + } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs new file mode 100644 index 0000000000..c0f6978143 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SmartStore.Core.Domain.Media; + +namespace SmartStore.Core.Domain.Messages +{ + /// + /// Reperesents an e-mail attachment + /// + public partial class QueuedEmailAttachment : BaseEntity + { + + /// + /// Gets or sets the queued email identifier + /// + public int QueuedEmailId { get; set; } + + /// + /// Gets or sets the queued email entity instance + /// + public virtual QueuedEmail QueuedEmail { get; set; } + + /// + /// Gets or sets the storage location + /// + public EmailAttachmentStorageLocation StorageLocation { get; set; } + + /// + /// A physical or virtual path to the file (only applicable if location is Path) + /// + public string Path { get; set; } + + /// + /// The id of a record (only applicable if location is FileReference) + /// + public int? FileId { get; set; } + + /// + /// Gets the file object + /// + /// + /// This property is not named Download on purpose, because we're going to rename Download to File in a future release. + /// + public virtual Download File { get; set; } + + /// + /// The attachment's binary data (only applicable if location is Blob) + /// + public byte[] Data { get; set; } + + /// + /// The attachment file name (without path) + /// + public string Name { get; set; } + + /// + /// The attachment file's mime type, e.g. + /// + public string MimeType { get; set; } + + } + +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index fa13b5e483..4251026394 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -158,6 +158,8 @@ + + diff --git a/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs b/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs new file mode 100644 index 0000000000..8b654b17d8 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Data.Entity.ModelConfiguration; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SmartStore.Core.Domain.Messages; + +namespace SmartStore.Data.Mapping.Messages +{ + public class QueuedEmailAttachmentMap : EntityTypeConfiguration + { + public QueuedEmailAttachmentMap() + { + this.ToTable("QueuedEmailAttachment"); + this.HasKey(x => x.Id); + + this.Property(x => x.Path).IsOptional().HasMaxLength(1000); + this.Property(x => x.Data).IsMaxLength(); + this.HasOptional(x => x.File) + .WithMany() + .HasForeignKey(x => x.FileId) + .WillCascadeOnDelete(true); + + this.Property(x => x.Name).IsRequired().HasMaxLength(200); + this.Property(x => x.MimeType).IsRequired().HasMaxLength(200); + + this.HasRequired(x => x.QueuedEmail) + .WithMany(qe => qe.Attachments) + .HasForeignKey(x => x.QueuedEmailId) + .WillCascadeOnDelete(true); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.Designer.cs new file mode 100644 index 0000000000..96a93d428d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class QueuedEmailAttachments : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(QueuedEmailAttachments)); + + string IMigrationMetadata.Id + { + get { return "201506262044329_QueuedEmailAttachments"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs new file mode 100644 index 0000000000..18c4da66ae --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs @@ -0,0 +1,40 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class QueuedEmailAttachments : DbMigration + { + public override void Up() + { + CreateTable( + "dbo.QueuedEmailAttachment", + c => new + { + Id = c.Int(nullable: false, identity: true), + QueuedEmailId = c.Int(nullable: false), + StorageLocation = c.Int(nullable: false), + Path = c.String(maxLength: 1000), + FileId = c.Int(), + Data = c.Binary(), + Name = c.String(nullable: false, maxLength: 200), + MimeType = c.String(nullable: false, maxLength: 200), + }) + .PrimaryKey(t => t.Id) + .ForeignKey("dbo.Download", t => t.FileId, cascadeDelete: true) + .ForeignKey("dbo.QueuedEmail", t => t.QueuedEmailId, cascadeDelete: true) + .Index(t => t.QueuedEmailId) + .Index(t => t.FileId); + + } + + public override void Down() + { + DropForeignKey("dbo.QueuedEmailAttachment", "QueuedEmailId", "dbo.QueuedEmail"); + DropForeignKey("dbo.QueuedEmailAttachment", "FileId", "dbo.Download"); + DropIndex("dbo.QueuedEmailAttachment", new[] { "FileId" }); + DropIndex("dbo.QueuedEmailAttachment", new[] { "QueuedEmailId" }); + DropTable("dbo.QueuedEmailAttachment"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.resx b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.resx new file mode 100644 index 0000000000..f2ec5c9c8a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy92XIcObIo+D5m8w8yPd07dq5UUneZ9W2rmmskRUq0o4XNpKRzzgsNjARJNCMjsmLh0mPzZfMwnzS/MABiSeyBLSIys/JFSgYcDsDh7nA4HI7/7//5f3/7X8+r9NUjLEqUZ7+/fvfml9evYJbkS5Td/f66rm7/x99e/6//83//3347Xa6eX/3o4P5C4HDNrPz99X1Vrf/+9m2Z3MMVKN+sUFLkZX5bvUny1VuwzN++/+WX//n23bu3EKN4jXG9evXbZZ1VaAXpH/jPkzxL4LqqQfolX8K0bL/jkgXF+uorWMFyDRL4++vFChTVosoL+OYDqMDrV0cpArgbC5jevn4FsiyvQIU7+ffvJVxURZ7dLdb4A0ivXtYQw92CtIRt5/++Abcdxy/vyTjebip2qJK6rPKVI8J3f2kJ81as7kXe1z3hMOlOMYmrFzJqSr7fX/+jBvTT9wxVr1+JDf79JC0IMEfhE0pmDIayNx9QARP89eUNi+jfXgng/9Zzyfs379/88uaXf3t1UqdVXcDfM1hXBUj/7dVFfZOi5N/hy1X+ALPfszpN2a7jzuMy7gP+dFHka1hUL5fwth3Q+fL1q7d8vbdixb4aU6cZ5nlW/eX961dfcePgJoU9ZzAkoaP6CDNYgAouL0BVwSIjOCAdv9S60Bb5t2sNsyIWqdevvoDnzzC7q+5/f/0rlqEz9AyX3Ye2A5isWABxnaqooaKD5kY/wDIp0LrhodC2B5pC5ToFL5/zBKQRBmrV2LdiCYuhKTRjOi8/wFuAebJDc5znKQTZAKLf3m4kakDOYA2Xp1ho0qOqAsn9CrOLh8B9gWUJ7mD5RonwIHj6thiCDTdrRkV6gieB8DgnUni1eSPMiATq2BQe5r1Bit798ksMOTpDKZSIMiB6dJ1tZQVloHjhOoZ/qvsVpB3fW47WkchfsNlB2pyg5a/gEd1RVlBMwetXlzClheU9WrcMpRT06wb8rMhXl3mq0y8U6nqR10VCxpYPgl6B4g5W9p1mUDn0nas1NATmq+VI2BqqAVnr7A/5U5bmYOmlppcIvOkQHNSyQY+0NPpYo77V5rejEGPTvsP1vUjdlnF9txhUCq2g1XJuVkzbVqdGYytVvJOq8GQMaLg4YyFqJDMr8TgNnT7jMZVmgzZOS+flV/g0vlkYyRg86Bp9WxcFygsKF2L9kRXLuLEZxUYhrQ7uHWPYglf59IO7yicZ2iVcpy9RxmfVziRjOjkZvYnjJBm9jUV980+YVONvdY7z5cvoS8ZJAYmC+pZ9r3rS4Q0TvEIrd+FYkLW7QLAM3LRiNJoODay01L5OkrzOquCdM8yWX0BWgzR9cTbRtNuQjfFfTrEN6TYV9tuQbuNiOyCW5EMjuuaBlQPhYEzbKB4waPfEd8vftmHxHIybATE1eTB+/XUU13Ljgh1y3Fg2bm7rU16aVoiRRniRF1WY1sNb02JgUzRW30FZPuXFcvqWTzMCvCiDd+JkX9+45vGqSmUB1xppO3YBXoju/gKr+9zH7dPWL99wiA5ay8SgDKEWL2UFh3Y5f7W1A10Z9jlJ6yVcntBJhwVZG8+X5eiWb98uWeCKF3OT7+MYwV2bC2xRrHEbDfmnGG07StoBIgHUN/UcbFd+QRla1St6EHi0akyO1sqFCVoBrIUuCvyrjWj42+tXC3I+iblpEDN4Hglzg+0SlpjWSeVLC3vdVuTLOqmO62yJGRvLGbZVC3RTV/AMpRU5P3VWdyegAml+92YI9UEB6tvaEC1UBnqiR0P0A6R1MLbzEssH3rTg3T1cxtvzbeim3CANseQ1W3+zZ3KoJm2jXOoG7aykhmKK7kFW9W21xAqViIbYkZB1cVdhWPAuLom5tnX4LiAWkazCG/nQbcCwVRjDC3mP93p2wVLRjsswC/aKwnFfo9ghoyW8uq9XNxnjDPBF9gNP/E0aPHNUOZT3Hsp/tGivqP7Z7+tlADKTU5NdPdSezQmWOdHb6bNEui3qbQt2A74W6hgGyYMOr98CvGtwjNswrAZg33VTp10NjXDz4mBUGNRjQyLSXKgtcAEK3ObHIq/XuCNx7It2ETjPlugRLf0ObsZZyl2PniZf23H/pmzvaLlC2Um+aiKLR26s41q4wkty+JYTT87Tt+xTvoIXEWzFL7ACWMSJ49vk0YpjM5LGppxm0t4VqozB9XFGdpSm+VPvDoWPCD4FG6hH63WRP8LlJdad2d2iXoXxzde8ioyxQ3eF1XsqDDq4j/GQtvESV/lREmznf0YrVJHO0ZUseIoXD/X4Qgey+hYkxGAo8KpXfcVbns2mYLRmP2IWG72R8/Ijuq1OQBG8YerwxLAtLuEfNSrgt+oeU7xR/sGc0uLcmCombR0p/ueoJpZshRJiyRwtl0Ifgsd0Xm7CxuOEIIfO3PcsbQS8Qxg8RjwrjcB9u5VwevqfWjSnz2tUULP6A3gRcdqhOEoq9EhRxGD7T6BcAGzjwFizymNzvHSDe0NiCY7uCghZMy/gbH2D7Ao+j283npeXMKmLBnuo9mgRnbwkKWw6FarjWIwXsEB5sPT1OOnaTxEHysp5SY5tm/iKYHY8L8/w9HfnwMHW3XKJiOSBtMN4ck8cEPZuZefuX4Hn02e8CwmWhfPytAwmJ+7NCd4O3eXkID/wSBtkeCt0nj1i0cTouiP64JuLyUO0IwPijaUYjx4BwnVRymAN9PIqe+q9YKEs4sg/50/NqMlKg7GFTgreIKDbF7p9P8uLro/HEO++Ag+aQPKQE285yaAQfCpMdoME43lDS7wD6Te9wRYF9em3QRxxJqnB2ARvxMFICQCXLTImHns8YxXLAungcf1yXFfVxrkQIFsE+icq71NUVnGQtsKfQsy8WK9zxzO+OE+wdU7RoST8/IlFEn0F+pYux22g3ZicMLGv0dtYrDEekDoOxB7nosJ79O5MzOMKAovrNFsGYOrcWacZOVOLwl+t2uIww5GZolVsk7aJNx9XCDYyGazw8RoKy6o/OjzJVzcoa0/RIjIh7nMXilAerdcpCreYf0J0dz+eKPL7mOjof6LliNg/jUubfqUJ1Sc9ojBlEi8gIV6MBEyhT5zd9gZIyANEj7B4IZUdvSdsiirHqseghO3qE2Xb3eP7AkFZF7BJv2WIvY5x87FrM24Yc4+W/OBR25GWBi3QE60BD1Qc93ob1AELEicRy/HBISXUiI1zcZ83/hRQuHs69DFGzZLYL5HKWJWu9LqFvso3vvJNsIoeSoogMoC6Bgyx2sAUaHPNA0oxNly5LryGB/IMB9rE6FhGdPkHOA1GbmkCohxH1Dq86IZYP6DOLWYIdBJBdAOQ4Dw7zh4iGvvOAhr6rwLTjUEJ6zmOC0TxGIfQwhh6L0DoOi6Cefa5PwTXd7kBMfSYB9B1WIDy7C/dgd6iJosbG6+r77+6imE85gq68Q3U8hzvFbgzDu6ag5P1KVOsVacsjKc2/QEKhI061T7S2H1DPcMEWdTSzZJNVc+pElE7DdxhtK5D9B4Xn5PWwIM8oMyEbLmWCzkgVzYUz4YNnRVB5e7yENoOC2CuXWZ9OIru9sUqzpAKJV6QIVSzb5+Cr7+X4pGauDVq+1+HKGR9WwMxuSMl3uxmJkakxveS7JUi3TbS31+K7tTqmnLdlTuf/LYuM58MQI2XzKNmG11VnuT1mlxwXgbPjIxJffwW5/SNzgyNj6RSFsqjG0yEeK5xIEPb+Kt8YCsmb7zZCqa9/AZOWpaMwK6Lk8LFMIZHYngMkvPC2iPRomo5X5+Uqm9TXUMxDhWgfihK6KDrQN2+O+A+UIfisBTr2xpYike6HkNuq0RqeciBP91dieO8wnw66SUc8vDI6CtTJ0axrt8cLsxEGVlz/y5WAGDraXM8qSL3pxboXzCsbe7qT3mVN/k7RNzeETktnm988FjAvsMiAugSZHfGmK1oKQQi3mQbIX5hi28Obdsp+F4mHJBIRXPr/UDw6Yt5U+WpjWMfPnpsWYYPIBX7G2svbKOmlb3fnFR1QJsei2WSJS8BhN3l73rg+ZZFW/9guBvUV0OisZ5xsHil5q/j3JyHucWzDn+JdPnR+bGF2CeksqiqIQZPSAW59hNbDmd4Jo6DGE+V5Utnvk9ng3gtWd7SoDmu0gmNowTHjW0Y6muM5DkK/1uUUywG30GKjXIT5cUCBdkv6xRapSqO479YrOHop0PHKE1JdGGXgzjwlmF3+TMOui5FLjXUuezMTp6RDZpew5vcAXEmj2mUzXQ9ZcPdbAx7W2K33PoFHOfp9BkrKvZ5yQn2ops4g/FOarS7UOO5jt/aw0W7BrzqzCI6rDb6tgYWgnFedT7J07z4BJ9pmubJW9+Jh55d91kRjjgFTAep0bcVaacV68DlvDyDgExEZyDM6D/WrlQbDrWItd8A64Pt+x+aTZEMOMIWzud2wFB/o+ziLuRw/XDdwGI76IfR9QNL7j+FjuC51fJeC1/JfLmF+0Mjh/oKI+iPkBs6Nv2PoksiKZGD9tjmOKpJI1sYTjiEAm1XKNAheGcHg3cO8Sy7F8/idcrFL+7yGZeqXDIUlEAxdhvNldXwfUaDJ5qN8IpkeGjbp9EtrYqh79Zl1espbPkh7R3LhU0IN0lC1CZteRhRPsF0fVun/wlLmmQ0CrKvuQ+uEBve9b63xm7X3Ap37GiDpaVFBssSy+pQigOpzrUgz5oRaWuYr7TrqwWdHXRS7aN+Opuj/3XYn+jb6mj0sUZ9q81vjyzOA8FZkfJRDr0xHqkZi1erI71i0jZ0lhcrEB7x02JbgHT8dWPS114iplk+ur1FKYqwUaXZd4N3M5Es6/OyCQg5SrhnFL1j9G2iS+I8yPwZlNX5+mi5xPud8WMDou4bSNc/53co87ycTOp3OZy1KPwv5TYk1ZgMnfK/ZsCY2HCpVI4Ol0FcTZ026Kefe1M3RVhFX3kQfYcFONdei7sOU7dbmOuNTSP3W4SRjC4toOtNATZ2aYDcAqiC2hyEntg8mCutT5+JSQPSo7q6J0ZNk2ToEiaNd1AxAlMN5TRYVZDmxK6W6wRhM6BeXeSl5i5KX6wciFwq9VoB4tXFq3yNEkMfabm+k3yxupcCjGs3qYtJ3UNapOwcXyL1Syh27dIlxLuMjMRYQd0EcyDKLqohpK5qwNy7/ASK5UWOsqr8hMpKd+yvgNP0Xg+nGIMB2HUkXQyi1VojASvUnwCjV4AioHOGJybxpj5rowilJL8WSKK9HjJoa98T1H1njzcaefamRXDY1evbOkNFWU0SF07M10kaGtr1R9oa5Ks1yF4maEcdlD6wI8PcQRKlPqIscT3VO2GeHhnRH0BF891UDb0fvaH/QmtiK4F0INlTJFfQfZ7BwWckI70M3L2ft+X7bf1OppEh5VLYLbQ9zGYBFIqkRVssd16rWSE1dk6AlLvIAWg7ykOFJVfqyBUQrd/iOCzP+rYGFkzb9Dw+ERll6/gI9qBSZLEy11895Z8hIeJ5mQ8o2vcRFNLVfQGhbYN/idAgVrSwQInQWOCjyz9AsIs3XmxItKCO0OgXwz5WvIvW34JT7qVYmOtN5Ua9CYk/hqEVu6vBKs77W3Yh0AyLWysUq6MSQO68EipoW8jTw2MF6hAIU3dYhwxqae+DU+PppfO7DNO6eUk2OCbv9DlJ6yWWde4isenkK845WyuptHkiAvQ04dn9zNlCyTJ6cgr1KhrHDhrZT13xtnuAvcxhOmirQeYNfuh2HuP75qaAjwgMaL04mTm3wazz2rZ7mieS8BuNmKCAtP7AN0JcWovrIPMGmW9JFXxjziK4JM5NgXOSIhOz3l49fzgYTRA/AEJ3lqaNlPAS6+M0v+vj15xFmtQu3zA4tiPKve3MJJHjZPDEQR7PhOwwKlmKofX1BnDDTqpyiZWUQMFs1HQlgIcIgsNaoG/rM8juanAXHLMZ6/aGa3arfBnjAM7rGl7D7MHb1m5la/GdKJ5ZdTXG8yo+0uY5uJEV3zxP2Rwuxm7jFcuRDjiZdUrtRfFaDUVfrnHJtO1qp5u13aRYN1B8H7lC5XLNQwSt1ZtOOK/VNM0U+hcFftPhOSzZ+rbm8bV0M9NS3bjlG6N9XPuPGi7gFEeZZym4O1/hwZLk2IN3NWJcFa3298GGEbxdTWa6ZjIuYUlVm1qZqyCVGtMIKKl3M3TQkZ0KdbBWVeA8aNhhXRchvS2l9YAKGekJzq71oSSSI22SzksiXRdpfYcySYkMXkrM60SlfKKYTpGUgmhS2akQL6VwobkdHiuRBINyO7xtXO9CxfAnKNsBxgt8ueDv/0+ZOsCYHWE444AXA36FT6W/S5fUfsOg2A4e6zy6k+QdmdJ9TChN7pbEcx93GJWMzkzs9QZww9aqcomJlUDBLNt0xZ9fSf2DoaRva8e9x4v7vIghjo7NnlHVNXWr0XZ08zhp/4w+963yqB6c5lFG5rdl6ZdE1TZFKlSurjyE6wUcZn1We1q8rADRr2I0Ffx2Tnma/sgruiVLaOIhZ2uAoCjfiIi2w4YlvTrKyiePYB791qbHqd7XCIS4ZuGZzYweTN7BGGDD9s1M1wLmvUFxMATNfDhyDOlIZlFzXfPbLea/zQq7RQ/65URFaMSwFZEGhhc9pkgpbmy5cyJFQVw1qRPD9YSUJNFCp3jriSANcdAN+rZibRLn0Q9NwrbW0h3/rnq0TVrUx+rp5usjTa9zlRNNuT1XG+fZjY52odK4C6DaWrUD4AqU+t7f8t/oWL2et1yIVPpctVAFXSYgqKPcJCCIDnpd39bQqeavv47iPCsgjHZDPlbqU4yo1WgEjzAFA6o1SrLTLktpw/yBS4dNilLb2bXWMrBYobIcyEEoQumzKZohZU1kBg8zLgXcPtewYVIXGKtEgIN+8tZPo9qL8+jGzaOAo7cckAo1mhBLdo6dzHsJsSktaZC1YUJ8kG4Dr0e6xDhNCrxulpvR3aIJEoR1TbaGyYQtfyO8TLlvmqaOkgSW5TQNXpAL0HjTaqXmY79lbrwYOlJ+ZlHJumV19tK1fTJlD8VK65abhM4HFapvi2aCDn6iOZIejhQZ5bpvuhi+wh4nfcTOXzx3zpEuag5DGnXbDm4SmA90kQVUdZLJhK7vJgMUrs/azgQpNIrjoNH0bVEqbY1GI7NFEIQiapMTmmJRLG8huZ+Ntm8mhHT/B4JPgShIQmyvhAgaPLGmuMPX6F23I4T9WBDcHqRQ6lrNoxVOa8JQB1sgZe/oT1PXGoDwJSBQ+x8Uv74tSqCPRV6vRz5lHumu1pTBjV83z8wEESrK4kA0aJR9yD4uEX+uV503MqzX5tcskKDNmTK1NmcBwrV524kglU5xHPS6QcnsvTbeSxmfKlqmkaVwdaF8KE2lT7zURTu3zpqieWqt+e+gJPRtUQJN9OwKbSv4XWc64G3xU/CvdgY7K/hX2RwfVKLkJZlm62gdiYPtAryQWylRkTVptMc8SdJwzEldFDBLXiZ5fqlr7BJswkY/wAStQPr61UWBf1Et9vrd316/WpAMCr+//pu3LPCBWKHz9ANUU6qVRX1TYZWYnmdJekXQWhHrr87D4hojaeunaOyKNIbnhr6iPdUIuUanGWmrdaYZYdvYpCPDDTmIsntjnHLEqwgiJgJIzyAcm6b6lscmsL7lsand4h8/tSflodGZtJP1cVuhamW0JrDhXWdLuDxajToS9hXgn7CAmO0ipFe/h8lDXldHFeajm7qCU26lpcbL/1hN8Lppa3rEuuZ0dHuLUoRlMtr+YD06Dej9ILKpIS8bFxDrrxPMW7zt5M1SGBMbVT/eRJIuT2KGS7QZL5EBKB/gUjclo47w5PFx/JdkSUOnz2tUUEfClzyr7idu8z8hGJ+erHw1jxx9gDco+NoKg+oooevmpzxdTsAfcsMTMSbT8DHIHibZAAttTqJi2DbPT6Zsrn9faLomz2/ABMZFu5pSA7BPhTe23Nd4Q1C0aVyvCpCVICE/N6bB5E1PIjK6xi9hWafjk/0ErIkjfVqCy41ONNpFfdPb6NMO+aIukntQwikd+BcA+V76Fl9THXte2ubI/hwrnHXdnJZM7jX+AFNY7dXLW4ad8CUkR2/M3WKrY4tPoPwKn1ovztec3LNJuFcJw486+VMa5ZEnFaNrEXBz7KkqlyIllECuMXnGuMGmBVXIIF+i6Zp3oGDnG/pe4l36J1RWuebBRBXgdXuIu+msHko6TjaAur4J8hHd0o3c4CBUgNffS7j8iap7aTDD0NKgLKq4Do7WIjnfDPxNU8JJ/ReKpM6K5V49+9qkiNL1jBRrerYpUveMKXft2SVcQriCS1aJnWrfAmWhBpliEFgazHAN5+fXcd/1SQe7UpnsfInyoXim2KdXayttLEGK2k4A0Cg9ESoofE2tCD1eW27QlEqFeQhY0bfVH4MGengbrRbqJh7nna3NSYztCrupMbDIdh8lWTFDu9oLrU4Zw0Cw6jivubwkXW0t+AaiqbAdxFzfVkevUAnlVtAYyLgXYaIfLI6kUDpq2lu7mxoDhm73UZJLM7SrQhEMrSmMdqsBqW26IIUTrmQOikXfVuc3Y7SC6rkPO+0UI1Bu5FCF87LrLM2WBiJ4ozqEJ3m9nsipfYmJsUbEQTSF165vbZoENwuYkX3sFCNrmppmWF/wZovJnzpaO+flhjuo+3Buf+tIDij3JdnK7SQt4LajUWtS43iudXXkEWlAtauyDj5oSWZ6GHQD5fAWks1mHBMp+HZIFDv/onn8LRTNP2rQjj5o05Gh6qJAyeghvH1Do0fsTjGaSUYydoRx59tobMSxSca3NjbtZglznTa89UP+lKU5WEZ4zuq87JBFM+M/YwHJStjhddwCEW39E6K7e4ety8BdujpbphCbWWD8QIZGwZ/QPHmx+FtrKB2VZZ6QqORlZ6yoTz0iWkk6y2/Iqgr37zocNCqPaxQHkdYGaTOrA93qoVQdawsNXesgwu3Kr/QtiCC7kqA42JX6tqJYg1+ZNzumy67YXcXMN8EeW7mnHdAEdgf7SnFTHPx7CZviYD0o67QC30EGDXwX6ap9Q/AYOI5BCrIEBm7LytFvmU3lQBtJMxgD2VTRLqqwNhOcpDaMwPFPnCIHBNmMJuJxUxfG4/OkRhtR08cQHfSfvq0oNshVAZIHTPGJAr3pJd24uzvKM9A3fPwDTNEjLF48q09u+1gH14lCr4m9cw350weCshDXGx0gd5AD0AYB8lBBqZ5YlDGU0sHpPiyRlE5RIulUh+jT+MsHhSGmHOjkVS0tnvsVzI7ZJfyDvBnp7yDg0BzkwCAHMRKKRROCWNulOIdPlxCUeXaWFw03Te8GafkXUrd3lAOCsA6YL0/ZTW17A3b8vDGLCtzefs2nSFFztFyhbPhq719/ifIgCKfb4uSV26Irdr47aoYmmr20CkKx71SCBW42c2qcneBFKCyeQsR0WNlM8h9hZbsARWvfOJ4QNud5HhXZKY4RYRnNAxknLGSeFEtYJGGBeYiERYzmsYxjdOyCKt4wt2Z3wWupaxae3WNowRQ7DT1s1DvGUkOqtUQLNNxvb4+s6XxXakVxzKuDGe5ylEPfFslijWWtu+Pe6wKfEylQgTS/e2PEe1geR9fnasJ/W/OJQDzXCpK86gyleGAR3mzHfP30LWuHfcEcLfknwfJOwO8l5UZWV4m8VQX5MWSrWs6+WQOfeIzWjM6WBCYsjnQxogrbPRiH6q04TWgPetNV4Y38eNS4YTZjaDA1mTTvus8t6uL5TgStEaYX1VaesV0NHsYAdK8u24YeOEZQftHV3kHh/RlUk4l7NefF04ucdNYcILYhO7UrcBe+LcNIDqLlLVp/jfRI2dBabVyVrzdTWSqWW7ZYt45yMDF48wcoEMg26dpP8tUNykCgRTyM/MDL+rYWD3UEVh64e18h0yFonEa+gKy+BQmZxOICz/Zg1FmcZh190wO3m2hHYmH7iZbxkH2Ke20KlJBSzjUa2RIt+cGjtjrEOSpLdJdhKUKUj86XpjPod3GOhbsoQeLbdzxz6k4uyCVY15twJb2SF+xM28njJawyk4c4xz7U1/mtrr7dUqTNea8zUfVJ1RjmMK32hsXvmschWQK2VXWONev6MU9OLNrWO1YtavkM1tfFykqx72B5HE4jZqv6DJurH+OsSWwsvml4sAdHV+gtmmiO1iv4XOFPq/X46fFJap4/alSEX1Zn5CWrijyNERcy0+mVKEIO6tVVp3orUpHnfMaj9AfZ1nEdodnZajFUETHN82h0CyhrXGs17yANjPV1jgU3JDE8DxEXk8MqYrGKHKUIDOydImjqmVzco6V+CbWU2jSvsc0livbA7fq2NHQLj6PZISEaiI7M07xY/FGDApaXdzejD6rxLS3/iSWBDe6PHjvaXDedoKHzEmPCCzlMIiRRCrAhBUxUNcQwaz+j7IEE+s6Zw87V2toeO8vS7rQz1rxWpCsEi9YV7r389DgOa41Js8WJ/4xxy6ILiiZM5+m6DvUyRL0YMBh6TgaqlPqeda950I1cqyEkydWAxfSdbppQ7OGlQkMPTft0+0ghwog+N+fJl7L576Av9G1NFKsgtPq9MJ3ijNTookxPMwIfbCAtYIJ5Jc4gBo5V89J4pzbSIePn/C7vDzVnc0CKY69W6XG+fJnirdU8q7C8dOdRX2H1lBcPkWfXTed9AfS6TqDqa7EcNKC+rYb8oWzfYJlHm3oYa/aG+z1cQboXuEl91mFav3zDoTlwo74tSqjRl5VIfGqx+Te08j7O2jUm9x+D5OE8o6Eb7KvYAZtYDcaDSESd4NH2xbGu3c+RnlLDesqr0EOw0rZvsELMLaquMcWGdQDUehxRNrNsDOoVXGE7OejEUYXuoEj0bc1jnf1A5CX4TaTtdC37bsWs+RkzIrzLi5cIvCyiOvDxgY8n4+NWuUdgYwHTgYsPXDwZF9OpQElQLFO+WuXZGxHTgY31bcVxH+ERfSzyej09W+KWZ5DCAdfASKFZY7oKjpL0Eia511PH9DwBo3vTIzlI3NgSN6fD1ngw7hz5c75M+zGEXykaPMvueVR7lq2GkLbaGrCgHfb3IkQK8zd9/YMA7rMALtL6bvpWY12q/AyyuxrcjbWSLZJ7uKxTeAXKB58TH1ytfMMiOciSvq15YtSxwZFny8CHp0jd6bseK4SjytffstOiyIMfofsMaL7uovJIn07qnmZLz5qLOklgWfq2yw4+VmyJvb18e4tS5Odt6euWm58HJaNv62i5LDCfBIf2wBRGCC/3XAT1T9E2o1Mbqx17XPdQjJ0qFsomqgQRdv4DQYn5r3uEypnvP6ACJuTNtDccpgPr69saWF9tr5O4ri4vZQVXmA5PdCsydfOXhHSWcc9/2z5HZsvcH/A6lpV+4RaSpPTIDsJyEJZ9EpaTuihglvg8/7sRkg7JQTi8hePXkTyFzcScYBSmxkcSDDi2XHzOCYJwstr4W8/yYoUnnck5P1Z7n9EKYRa7yptQ7FCDmQpYeb9NFzu36DkTcYxUt+E9NZ7Z6DcnrLUy5rV6FRgySnGUbyRUByWtb4ul08ca9S03v2cK9qQzGJzhKF+jZBfDTiX+VQac6qGkTbkBNDC/GHrEtOhfqPcVWB7PQVoN0hojspvwUCxJvcpjYcL8+U+YGJ+NHMdiJJnQpvfKk6RoINg+OS9bF+Pxy1Fd3Ye75hmEl9huXSMmB4cvzpF0KMvGmswRrFq55uHZBBFaMEUeCD2sa7z+RnRses9Ca/u+ARrqOQMZtARQ1zT+9Dn3uXiJa92Rx9oZLAftr2+LIRNpcmuu5gw++DuSDh1JsQhk1sT09DDXEjwb2KMFU0T36GGjPu3INqRSKqpyY2+jq5KGjDHUCYE/qBR9WzO7kgdchO/HadUrIsLhjs9qDdCdjwOjXZ3LNx2OA+t6885YgUCD25SRGiaJPXZtiY3p5XU4DKVCFHA3qRdDAdVBGr2lcSRNfpwkp3jK0jbYBJr817ZdCJX/SBmGIsn7NAG2zSQkCXkgJjxzZdSzoAXMluTeN0jTl5E0zlf4VH6GRGACDzB6xaPGeNA/Bv2jpFjwiQZlbJNS+XWUk+Q4Uhl18R7zKtjJPUwe8jooq3zzUtAbCdVBaAxCM8tdkp18emRxj9ZrAn/RXFiPhfe8vALPp8+QoYYvKoyoSwoR7fmw7XhoJZbVoveXiVrD8PCHGvZaocM2LjXbOtIDH9YVgx71ULcSUQkfXjwYWqpFioVK2zyq/fBMwEga0F5zTa+zxKMBZ2XnpbMuSQoAwtcX4IWwwCdUkshcf6WlQXjQWvq2RJKFKi06E1sasiWOVSlnGh66litv5My2jiRn1hWjylk8ATtIloGJX5IU8q9Xe0oDQXQBC5Qvw2O9KpBSfIH3oOndXyKSMfwSsVyYke5qnmeoQiDdZk3GdtFKi13zNfSqiwMc1Fc8tGuIg3b9n1oti1s2Z33upZbpPRD0L/rEEyWLV7wExUGB30gID+pZ31achC5+aUkUeOidoPkyovXtz9X0VNnRtMqom0ml9pEk63oDvtE3eihJkRpAA029lEpDlxTaO6knj+igSPRtXXRZ1t+FqYAez/t5nLT2rsYiL0ssFmk4l4moDny2rXzmYNWEhJEfwscH1sq7z/ARpsE3de7zouovfU0dkXaGweM1PrCZW/dJcEYOK9LG4g+II6aC+VW1OITATA6LAhZTtDXhTemhe3Lwj7rJFBF2PYI+lfYJlOYc2j6k87sAoAv8Nwb8xwv0X8A2p4BHtu3sFt3VRbNjbfEcVL6+rXmiMvcwWTUTW+GV4fP5DYPhwLHeHLurTw3QZAQ+nEPqlc1/B7YxyD69xxTpSsiQhz9J6yU8zxYINwl6f5t/BNgFKEty/woXVFECDTqEo9PiClXGZERxWpkkFP4LrEB7D85k7sdr7ANkQsUnaG+auYocvX8JM6ySj8qfaNkcsgRha7D8V56NT4emqZ8FWLf2v9R3m/p4q/3EzVvYyI9zssBF0C8FyguqlYPOk8nAroApuZjPXOjX5HrFrMjNlZWqAsk9OY0j7Io308S13kjkeXmWgruyb9H/Moe5pWirOqYJntz0BdOQnRV+Cr7A1Q0sOr2a5jevX1Fr/ffXv0jTxcGeoRRSLwDeEMO+0jtzpebdqBb2vTxNzYSwH4/KMk8QJUyL4x81rOFSoOE16Y4wtNNs+arZquqrbHa1zcyR3bASGnMhpjlaYypjVvr99f8hDdSquf5seNPch/wpS3OS+oVv4Zc3b969Fg2xb1kTlvCKxDiQYMYTUCZgKYsWJuaS/9JOFjlgxxqoxHyDsko29FCWoDVIrYciYLA0FkkP+7bEkg9wTbR8VllPn00nCLy6I317AgmHKPbbW4Y7rZn2mr0bZ8OyXIUBhvVkU74JBZNyfRba2CouVY5kWh5VzpdNF8RLk3NzKiNsLIu5qT2WMNMpW7ZVBTsbJGaruNk8otlUr2JObfrCVJuNvdvzygtEH32+bv/X8rQaXMXIPKQLB2vaULCtBvn8LGsewgR8ap4nmw60VbaGMdtoCFumER9jH4MxhQfc5Ta2nzH5IczAmPw8WTFmF2ExE2N2hxSDulIEVDHj5szEng0lvPaake6hRMxejKTrxAQspKPrLmi1D6hszOCjNZ4U4gZsR4NgqWUkUyUVU3XwLkxlbEPBYJaMG0SaVtJdCNNVGY8sfQv2aj8CTbof7a16YnVakEVVy4UyUdcr2/6pXEIy3PAkeqk1K9JNoOOsSGTTj67+3HbcNeYb9AiLFxpYNGBhccAGG87DeONRq3iN7edoy6epN9NZYUo6W3EVU29uzurNgX5JGmABqYKBw3zsM20zDsvo1uwUtKOYjku182XTBTbhy1ZwqeVGVoQfmUd3eC+rG8MMDLqDu1mS+e8W0E1RMbijVQGrGJOFc+FKJf45dremjkzAVyY678Iut2VqbhgcTwyoJW1Fgxb05bnBJhX8Z2pra/Ti4IimU5CD82nTFbbeVnG25YquqjMRP+/w6m4ax0wMvIOrPE3OiLK7L7C6z5fXlxBjQySQ9oT4BozOx+GqKibma7nwr0V7qn0ULYzojVxU2KjD0/aIGQVed+i1nVZBK+nCAjqRRdmCPSXmF2jjCCYQZeMcWW0lmyqzCXF71XKQGQU4FRv2tzbtGVDEas968cxyTR8mYB4NTXeJbXjVMzTNvLTEZSEet4KRjFoyPjsp+zMhUylpbdM+V3G+A/Hu0uvmkQkdB8igykPx/uqtw6G4jFnBWHZM6zP2Y5Sm2GrpGhjsJg8fnQoCentSyNLlQY32RsfmDvVQf8UKJnr010XcySI1o1rENGSf34AaGsUEGmtovqzWQyaTwyz6qkmJ1VymwdsL2vNNxikdDxlrqfhVVcGFac0NKjh3kzRr2zjXaigTsK/VHNr0g01MNwsPH6f53UVeVsN8K0GqeLUDcuFPGfFO8aS2+xPwoXZOdob32idtr3vGMXGJCKzjwP6dXDcmlNAr+FDH4NvBh7oRTMSKuvmxab6rM7dH/hI+Ivj0Cabr2zrNiM3LFQw55weqG/z0Uk0PZ/1Q63q/fTu6reNqt4FN58i3nGcHn35TcTb2J8+6nVdwNWwISJAqpu6AXJhYRrxThoC2+xNwpXZOdsIQIL3v1o6ecUxcIgLrONDDEFCiV/ChjsG3gw91I5iIFXXzY9N8V2c+QyBP02EtyEEpl/U8dbo1ziPcKc2n7PoUa7FqDnZC45GeH2XlE4kCyKVEYTxTMHA6PmtAXLmNRayyDBUMvB28puj4RNymmAsrEw/Dz8prP/KKuqqSvFheMxxjYg9NHR0PsuCunKhrSsOVanbfDt4cGMpEfDowd7Y829Saj3NhsUIlydDUjqRz+ZOB6s/GzNWU/CvUcOJfc2uGkyECMMIJoh2R1ODRzw9nIsbpM8lqCdKjuronvNhkABMmSEsbq9oqUpkqupDPrgM7dejoNKQJtKTTHNv0Z/bjyLO8qFfU7TrI4DKoipt7KBfWVaB24tMoATn6TkzAWXri7g4b0TTIlnzEw2oZqU3M7MhJAvKZWEndi6l4SU3g3WGma/pv82SacbIZQC0bOXMQi1TBPkzftm7N1PV/KsZTzIdN05ta26DEGq6xUDLNkMdQXw1mHfNtKd8puj6twuPmw5rvtsD8Yvhl2EpiBhzfBGOQ67hPyddbwoKaMUxqw8nzY9M8rTAbKzbv/FpGEquAVazYPtlhz4ZKxPYBxJHsN1MvJmAkE3VtmudrzsxRg/sBHiwiF+2mz0Pd98m4bid3DF2eqe8kpX/3onefV0zHJcZapkxlbAWffG7qBg2px7aPS62GMgHTWs2hTT9mT1WmHEmj+Zz4qRHjqbi3aU3BukqdvaV8yw1iLqbl5s2mE7TCvIs7DdMx86gAp13eXeP+RLy7w4Kank+1wstzsUvMNpTuRIIcgeF2MaGJtveTst0OJi/5iG6rE0ACInCX70EJlz9Rdb/hIB27DNRTsWVXxYUrh5rRqUUV98e7227Zqwl4z3IarDhRiWF2xuSMiJ6FhvhFWcvElL5Wo7lBBXvqpGB+HWo1lAl52jiHNv3o6mwXD39nRcyNkbmqk3Ez3+ruGKL2g5mLqZXzadMZruK8ZuvXvII2e6QNnNZkJSDOJiuDd3dYU9PzqYxVeS62f490CZ+w+FzkGEHZyc+g791UScWGCngXhjQ2t1NeepuRTMCtNvO3Ex581UDsDIHBmtZqT7n/cWnIT2CCkh6RhJX01pyZSDyYLmem67VHAevuLC/qjk8gr+p52P7Fpet3s2fuWGWILzhoE9O5+uLUDahy+Wm4entYUDmECTlROUc27fcI5g0v6DL22kWsCNARgw1EzCFJ74KsZl1PprKddTS25an1FkSuXMKqLjLy6hW0uRmhBlebAwykm+WsbGLHbGbTGCaxlk3ztBN28qbTlnpPVyH6pb2YCtDJMslpsyegaNay4zpbptB4NmOoo7ZSeHA3S0XflP78kBnDaIuFRc8mMUMGp8KmF5taM5rIwkgGlw1tjdGZcDfXj8FhzMGvO7mKSKMYCqvQVRidU3cx1mJoEHOw6Q5GXvC58YY4VAk9mDnRO13iTjKmcQQTcKVxjnaIJRdrmKDb9vb/UVUV6KauoC2LmmsbWFZd0YOFB3qwgyxtN6LpWNxujneB5dUj+bYmf15rOFK7urvjUhoYBjROxoZHd1Q+ZiuxnF9UAoY7hcXizxtWnkUlhi1dSIwM7qfbzeSdbckxdsta1tSiP7/EhY999hXLhm/85a/BM7cUdsvyFbgz5IeTYQ1y4yEhHGa9CYaL42U8a3H+AAUCWdVPy0m+ukEZBbzGEoMeYfFyhVaGvLZueAyEM6DwoKl1h1R3L9mBj+aF9ezodHrBdU5tesbWm1v4TeOz3NBZoNgKjt/h/Z3DsLZDNHZwp2cxqn/UuARzxvcMBUkFi2crRIPrkEI+uIHPuRioOrodHK+aU5uesfW2jfd9VwAPtR+BofdJwW+PVt8jVd4NZdhTZ4tgHgY3uuOkMe4ay8/hfXOdbwch2Bpnmzi4HyCt+xFK3OrImkZkDlJC8UQQFXN/9GIzJLVbKz1WA55Pkqz4w0GqRBRzC5fT1sDW/vfxom2VJT+zub4XNvn1AqzWKfyQP2VpDvSZDdTgkblLQK5yG3b9HJ231H2ZkLvUlLY6DeBqzsZhVwgWeNQJ5F4c0XKYGlzFYT2kC49p0Ds+f0L5bO412jyUCVjUPFU2HWDrbQGDDjkiJMgR2HIX3Qva3k/KhLvrQmDC8Zuflh4xXT3Deqy/9GCxMmvb2yVmtRzLdEv80Cza9ISruEXs7M7I07GwD/PGtC31XZmF9/ZBffY79TOUViS7+/A1NQccVjwpVA9iUUNXfK61baHuHR7hHLIwzAL2OnnW63LHIHk4zxZVnjws6psyKVATUzZ4a26ookoUNHVcJGCw2Z26Smc7mglY3HY+XTZtW8fVQ8bGQL2JeXoXbWfLsczI0DtoxRwlqeJ9Yi0Xq8FVzNtDurCrBr2jg2x+VjWPYwIONc/TznjHjm5vUYq/wOuhJBgSpJInOyAnnpQwT/5YlbYLU3CSjrA2bc+d5Ye+0uZmfOqraB/i812cDU3N9KDt3JbiMPF3wkbE433EEvMFsz64g9dnRb4a5DtDHfXWnwV32+jrG5qe7Sx6M8kmfJD4Nr1g620L813lrqy3qTEq4zHNzM52cl+mZzqZ7DZ92NSacQtRoUc8OZ/zu2vmN5lMwz5CW0e9mehB3LYT+lZURpzQ+S3cVgyOZ5K9xeDcWdmGfNWtYN9BVakCHolhd9PtaBrBxLy5k6bjyT1MHvJaDCuVPuuzQVoiUGaHVNZ1yhVp27qKqaUxbh13uw5vAo53nW8rKRArz5imN6kLTIq7C/BC01efZ4jgHXowwFBLnbSXr+CWt9fUmH3G/Ch2rVVnJuBKqxmw6gdTb2u4sHsbQmIbWx7RIbDhTa9HWSybV3DrkGjMr5RdRzcD+w/Nt02XxLqzScPnPAEp+hdcdn28/gyyu5p4A3QMqK+i4ngJ2oXXDU0puLvv+dZx9fA4JuDj4Xmz6URXZ0aOtdjaDW3pHLdyvlu4rYjun2n3tiO7tlN6cwrXqXANWHQ3XlagqL7d/BMmFSmCz3i+E9oxkGV5RbH8/XsJT9KCsEH5++uqqGWVSVAvYKW4plW+ftUUa++6ScwoIoM1XJ6uAEqxZQ+Se7KMqLEqAAfRd5d9VBg3d6bs+zjQs0FUTf+TJK/Vo2TLB5G1i+4XWN3nyhFyAMPoBqL+lC0MRnu6NmrVii1aA7Jh1kGldpq6skEkJ6CCd3mBoApLW/gyPBqUVHWhxNEW2RLEhImDsCYPedcEFVAntgqwYdRMoi4lTi5Hmt3AjRPBw1jMRwP/BWT1LaDkMgkHCzaIeginE7JuDVIyX7/WDyBp4yWUhOtDTIY6QlhAJwW0bJjo3UsvenXHQwwjxOsfuSHyiC0BZc84AGti04VWLQwCyCDK4zS/u8hLJa6ubBBJZ+mqkGy2GkNIiNENFxXZ613CkppBSoQKuEHkX+FTqVP9XdmwTOZpepSVTxpR7EutEOlQWDMBsR1NHNCECA71BBYrVJbYRmvi5pS9EmCGLZBnvCxnID2qq3tiaDa5UfUNmOAHG6OxMzoO7gvt0Fzla5Ro8dBSG0RAh8GuFx+LvF5re0FLBxFRx6EKR+uFtVx5mTfL1ZpVATisZhUvoquxqx+1t8RuQmhHP53C6Avt0JA3t7VompfPB9DIb+2q6aV8k9dizdNZVptHRi2R6CjGP4c6OFrmMTv1MLm3Bgf7xr8Yo+6f+LKPnXmmTv5sMNR0aceHxmBIMq0cjzGbuFdj9s3YEo9mpdZSiqaDtkNkSN5oaMCYg9OvYYfWbJuwwe2MVJnDyaHz7fn4QGN9lgAVZiZjw6ANnat3k7TArvoXQMVbi6UtHx7SPd5eUmrcqI0vDmDY+FZfqFHa4rpLUQ6bvSu4WqdAzUoqOFvXw4sJsQhjrR0MOAWQYZMAZhDzmlGWRJjhTWt310S5a91cAxpA870woOkLh9k8uYfLOoVXoHxQsjlTPjy07vKDcmib2yRDvAdBifnpJ0R398qFnAOwRfcBYUui1IiJCGOxmyoKmCUav0FTOGxESQH8WvPdSXj5UFm1JPBhyYM828eJqbmWCd+zR0X9+mZ0TWDpoDpZrQG6UxKvK7PgEkoKo67jQaycB59hhTepQ1OshhweuBh4pKSAHCfmila7zusi4AYtddV5v25voonncGzDBredr4k54FV3WXEgP9hZwlBLw9EADzE8hUVelrhiakApwliMXin9NlKPf1U6Q6opGrahwLPRU74pH6a31mGj9tUwB5sDx4PXZ4jYb0wF0xlhAy2ewG4OxfWV+hP3fmT680rpiNeqge4MnmmAObEUz9F5CrlR75o/WTTSjoe1GhhXZYBu1tTikSpoJZymxqQXM1Pc+a4t07GVXFmDJcGYLMi2o6Cuaco8iMufL17354wyRTWQ+uGpK6hoJx2DGoimwaqglA5dBCp1q8YwlVS5PozjEZJ8RKKSkMRDxhqDSt0aZOIiCUY/BhFURRN2WTSQQ0I1Lrt0Lv7ro/U6RXB5lbP9lIlihNePylRNRSwmdsJAKyNWBd30UxCFchv+tKFbD+0yvq5STJr1OMcVub5hdeCHgWTKChYjVNWLQDglWpUhphxnLAXPv3CoV++GlxBValj94KEFRwwjU5GID9SJRZteh262Glr6yLCDw5KqGOhkqfW1mMfWYmLDw/aCBGo/qmGLwZNc0xgNrBfdZDgo4fSDUYGrSCREdhnIo8Q4idnJtcyHmmkZSl9nkAG0VQ0sZk/GwUYUJDVij0TXYRlVgrsNdFhWwwg5jcjyEX3Xl7CsCsz0cMkEFMpUtKilH+xwZRVNpeBEAzktWlAtG5sRh5OVDWy87gMwFZRUAhqGpoJX0kuIvTSRS4lzZAp1ecUMtBFB9CMQIFX0YIJsDaQQEU1EBCEOVk8KHnB4HPzUBpOFR6cgjpnrfPwQ3cUgpqMKT4QMZXAgSMBKb8QmstvkjJBxKaiiJXIIQY5RmmId1weIG6gigFoMh68RgT4CwomI1IaBb64BGqgkwQ6PSqxiotMmaN2CXBJilR7STYAHvVRB5Zv7vQqimSvoB2ispyKfJizeQENzEwpCMuH7wYTs7gwYiScD6UcjwaqIxNxiMBBGRjUBMU7yFT0J2VymUNNDgjOPQwQPljwlUgV9tKT237pcwkcEnz7BdH1bpxnRjlyBYRczVHNwwzGAIJiqls0YtJuuGQ9ydxddjLIpA+lHJ8Gq6MVcvTEQSkY1smySBjt+39wAUtNDgjOPQwQP5iIlUgV9tKT2kc08TY2MwgMYRICFUzoLmttQJiniUIzMGJt7XNfNfSz10FkQc88ZSN3w+1tlA0RgUancIipKepLgR15R+4FmU2fvtqnJoQM3j0dTK1ztGnBr6KaZAh/qCfflroUbewoCmmsYxmmsqOQ2+cKfiY5m/IZlqx1rvN3eIBE1kBZbs0GiOW71JieS6QKlcetnV1E/ZKv6KooOXBE1UNmuyZG3i/29UiN1FVD6ccnAKrqxt10NRFIgm4IiNOpymCQC2MAweGgtUbpQ0CGqCOimIMs1e3FXQxMWZmAEDKiGGmCYDCwSBQ24i8gxmaO9B23kjAbGah6bscThiQaXmhgSRYOUBnud3KQ2GDgbWWfGEkN1MOh0HKImsAdtmgSZwx5dJZx+MCpwFW266/IGuihRjezFbdo06VMBYqj7Ji1qTYOpdKcqt8D1Ji2SPhxMXUE/LGM9UziYmMDAIjZM3YYhNmw0SraZICzJqMg8PDw+PvHwCATkkw0PMrOvCFJ/i5ZeIsiA/GwgtVI47C4TMU1DAkNYiQxk03lDCIkzIaYJF+kyiFxf4B7fgxIuf6LqnskIIpNmqIp+cAM1VWRjsp8YqDaEWMdOsZyLqsQu15vkLHoaqisMD1RZz0Q/B81kbkNBSu0cxaLkd3ZCrcnJ13IcL1d5TMLyDY2u90h+ngHVz4AM6KkNpFbjtcmChjQeg2lMEigSChnNUSO8fkimaipKafIhGYhmbGFkO1bV9qCEDldyG6yn2Dji9Z0rz7hNeiCmJaEAoR8XD6iLvRy+AingGVMw2YRa15s0XXoi8IDDY+DgTSQZNtHUKFWxczoqe2+duzjYQY+CCDi0Bxbgg/bTIq6RnQpc9rQBba6ENCkIVQW1VuBzvBm1jhLpyEp70/lhFtLCWpwVWTCS4+nTxOwkps67ZlNoq/SRHtykQrS11LpJSvln1E965PrNJJdOPD4VTXKpB3YYpEk6A+k3lYxKDRv8E1pYh3EZvBWBFJvGd8HHnA3fERIADWECKvi4sXPTkkid2NKCZAMVBwdrrm+4aqVN2jlM4IE2R75+ZchUeq3LL6oQbw80Bvl0x6ZUCuasrSYF4dEBlUFtxxTR5cScftZVeIzYfLnbTOEJxczYEes51TBVQPIALkmvdso4sEESsNDBmQNYXHod1fQ/FlUMOYNtsy1YoxikgC0mA6XNmZOHJ8G6C9NldjB1aXj9tqkdRJXhlXzMOZnUiDJ1hH/Ay2s6OBRBVGExzTQxXBeUidK4B9HGmiIPCfEXCw9Z8KLzvFzftW40X63reg/eaKiOQW2jYSrCjEj/5l1wTaHDXJjxOJPJiM5hjrqUvu4TZe6BftIGuSTA6LRcFhx1v62Ct7M7Z1LV1wuwWqdw86KknjoC5PCQ+ArBFBLQjZyBtn9Jgrt3oaKPBlI/IHUFFX3Yty4MFNIgnOCKyKZlwxIvA9kMxbCMO5Nl0qWa8fM3P4etH22VQanQ1TRIm+GIwamFqYnpREYfAo5JupmIJjxqO3CK5lLdYfB6LFaklh/zdaG8ofGpTuE0j+wYD+MG6+hJMFRVmelC+2SQKbfDUEMjH9Tp2jcoiqEq7oM1KI2oRJ1GgfQPDA1aPRpI/cDUFZS5s5gnkEzJs9QIJ7B6+reKrg3hGzKQYSgirJIszPNJJrJIuEYO1ZAeIBq+qumq0vSVtFfS7CXOgHxkBcY/s3R9VuQrE+lM4KYVUVtLvfwKj0MZF1s96mlJd5U7EI4Bth7bpk5kojGIRyYZ827WtfSGlkrB68FNSllbS63q2ZfDjMpej1el36RnxKKSz8RsSji7gZlYzItSk4U1Kh/6ula8LaYIc7StawhStEShjB3SvWZmCoq0bU9FdsWjbBGCb/mXyq7PM1QhkBruAZgq6EdurKeOyJXeWTMG5ZrQj3slRfmO3LX8BtwwMbV17QeuQ2FDYturK5YtKqg+OKm+qTLZV/GG82SqofVD1lfSZsgUH/MzENSAfeTUYkMrkuVKNLQCDa48Y6w4v71tEJDQToAyWPRlv70lj8+uQPvht7cYJIHrqgbpl3wJ07Ir6F5p3tRsv7xarEFC1Pn/WLx+9bxKs/L31/dVtf7727clRV2+WaGkyMv8tnqT5Ku3YJm/ff/LL//z7bt3b1cNjrcJt6/7Teht3xKWLTzbQilJer2EZ6goqw+gAjegxBQ/Wa4ksMUKFNW3m3/CpKIxrs+CLvmtp3LXYPcsHHtoJM8cKSP2UVeL/G4DKEmLpNfwDenaG9PR2IaiZ3iQRCHQ8ULN6ZVcHSNYYOEBRSc6bffPl5gceVqvss3fIv/pa5N/+frNF3sMHyDz2CqLiCtwwIfKdQpemky6Aka+yBlnu9IrULYl9hjPyw/wFtRpJRB/81nG9dtbgQNEXnsrMZugAUQOtuRv5YOCYYyuQOnF8VZ4xmF9pnERkVBkj7NVYYRDZYGQCu3xXoDqnkfWfLHHQB4kFYfZfXMQJDz7ggDRL1MqnC9oBZv9OItl83VrBG9z0h4ia7pYAgvx0lcdR6K69j7WSMDDl9hj/F72sQzfi5THKZa591NCGYjvGGWAvCaiQtmV2WNtL+rIrM4VuGmATJK+zVd7TCQPZFZK+o357LKQfiVpxvlFlH7aGjnmXsqNtGyGLZZTCfRFgfAmuRJYevPVgfmKfCUwHv3ihkFePDZf7TFd5TwO8rdLbbkX3Td7LJdwnb6IHek/OuORu8QVOCidE0HXnLjUPk4Svjr94GA+1XT7JphN3UeHfuRLgWebLw50KCCo4PJb9r0ShsSXOIyNqOzG48SNbvPZDZeia8xnB2XOvLIuaguxzKmHS/KiHEjTF6mTTMnWKHn+sfkQLc9i8lDz5urj6PlmUZGn3mOPLWsirsAe3yf6YAuLqPnisHrlhYCh+eJkfhayybT56rKBK8unvBBmafPVYa4ycJPCRSnO1+azm3nd+CuwVltibkQgLWUrWwGyNXLbete7lxlDBJdD5SG5A/VHMtHYRhcvZQUVVpIWyMXmT9J6CZdsmND5shR3ABogj3aaRxD1TTDl7tj5Rzq1jSjAXPZvtIcUF9kVtU5pcboNYC4+kQyt6hV1Yx6tmiS9vHdELnfADp7N2BXl9tibGt07qXpCmeC2Rx0NBuYGaagB7D5KyxnlOHps0wERD1/iwFfdQCRGYgs88NFABi3SvtTFB3JRwAVMIXkmWPSFcEXby+eRGTsGJ0/nJaENi0iYz65ioMEoFbocdjRni+I5R/fVyc5P5CVg89Ud0wUsEjyhNIpBhZMtn/KgYXGPtwva40251MkVi1UrG90kuGSFUoddE1rCq/t6dZNJOzqhyB7nD1SiG/Estv/oICf1TYrKe1HFMZ/nPNGN7/H5vl5qMPIl26bUo6hyfwU+sdomI9Go7q7IZTdW4JHRx3tojJNyXdDAOAvkebZEj2ip8LEpAfZEddZpqkUsFTpYd8sVytqHPgXLjitx5y+4wvpItkIVxU70ffqWfcJ77Atp2RTLHPZ5sAL/Dl+emltF3A6PK3HDqJ0tqdAN7xWqxEWJ+eww82maP/UeC5rxUBi9GsKhhfW6yB/h8hKQZzEXtXASpih2kNW8GkCvhnDv/VVegVRNHyWE1xj0jWiBnI+XrvKjRLCN+BJ7jJ/RClWkQ3QtE3osFTr09KEWOkg+uHhssvoWJFVdwAKvN9VXbPaJhpIOxr6Vj5ibeJzNF5ed7+blEX7bu/nu0J+2jmpJF8tcjlj/qFEBv1X3JFNCd4uUP2tVQTi3sDEG1Pi5cgf5rbHeAuS1TmwGHC2XAjZRlgehnYIk+5QpQpRk/909ykacWfa7g3GepY14MvlQOBNdUe7kMW3E6dutBr8awp0ap89rVNB4wg/gpVRTRoRxb4Xel6IYVLKlh3LYuIJSzLLDbV7lYgdtytUUey+XOvWanAYe3RUQypajXOp29NhXvCLB7NIZpFDsIpf95RRRMJkCF/3VVjp5SVL4GWZ3YrSqGsK3hQtYoFyaRx2MRyvUwKBoJE2sgnChPDlSas5qJaXIFbngPMN80B1ViUj5Mpf90BIRSQZpV/vkntxWEfdGOiiX/l+B59NnvA+SgumZAhd8p6VEW/rJIcgLPJ/gTdldTk4YhVgvvsjJJsP7sfPsEUssrtydKUpGmRrIKQY9eVD7e4UiZ3cbrX/0CFAKblAqoddD+bWkHoQawums1IBdLnXYDeRPzdjb28Xi5KrKnXZJ6PaFeiPO8qLr3zHEe1Npp6QHdDiKAMlDTryo5KaYdBQhFjrut/VpX6SNt32GGH2b1BvcHoKr510N4dpCcxBuakGEcKQbXLZVpUBCRbGT1JF157h+Oa6rSrrJJZU6Y/6JyvsUlZUBvQjiQJlG16QQs/sF3ofJhwJqCIfDAbwbolVRIgbjcyVOodUiKmcc39KlAs3mq7Ov8kSKueMKHNYgkikfpIre8SV+GBcVKMhlUEjyl8tRsEZIvxZPs6VVeyKcA4e17sXTjESJqBhNBeAcIcRhgSr2MQI6xwxZtGcCdNqJsRkvhW2YKRmmHider2GpTBquGMcgsNNY+ifIj9brFIl7BSWAPf6fEN3dC4LefXOgjmKf576z+4mWIpL2kwO9FOP55Dyefo0wqxcDmEdbJsWiBZrzmDzqIT5MoRTx1H/czaN7w1j7Jzck/5lQ5h7WQ1IGyJeY+TIXy7+E7XKmcFTIpR6Yv0BQ1gVsko0rsXMQHi2oAlWlQg+85IcRNwvgGvhFDy9lb59U6BxQ1rwfr3YSaUA82yA0MDfRQ3iPYvOEn3EkLNjWBNn0C3fYrfAu3s49zEZfdZw4G/JvWDRJ12Pl2YNQ5uRh10UeCkXbEtLY1VapH7HMxV/Y2jHyzoYrscfY2isSPva78+loeZLXaxL0v5RuusrlDraDBqsftm4W6NE/Nf51/MpDOEYcNGdszeNdUsQBW7g1Wq91mRO3VIja6zzvHmpPX3Vb1R6JZpOxbL66GJ9xczQd5xXerGuxKopd3JwISK5N+snFXdfMtS72TlV+CJMz42rCVnWnYnKpA2ZEg5AklJvPLr28gwv0L+n+Y/fVMyywvMqbSzhq/EOw7v3/pjoOkQod3c2XILsTlwyuYO4A1LEdX7sTALiNbpb9vnOhpx69/f4DwacvkpUoFW6NwdVqz8C7HA0Sn7scuprjGFttc6oEXEKRy4mJa545rdqBuTr5FlfgEuGy9Tmz2nPDOFzI4fK/WDQ1T0a8FhrTRPJX4zN7zNqNfnj6UgXCAD+aEcs4rNU1rXMu+GFjBnJZp1CXTMQC3OmQXe3P4gocdqYoTYnPt8sOImxMpVIXi7cNcFSjVhS7uLiapBbEVuRzp4iuLj2cT2sX2gsHKgivFvj0PLpWBCiflroJUO6cDGB+s0SVgWl6egAHt+lzVQA5wy7zeXtUMnNiGaiLGUw+SthYfVs9e7huXnyCzzRXiOh35oqcl/UtyZs+r9kZydvMY/NxOg9i2H7TU+fx8/P1nZdneGNfby6USfcVxOL951b2ImYUhmUR+jOtGcv2My7bf8U1C67swMBeDByPcwNZdg5eDTcDYh/LsVTQHX3pYA7HX2Zch0Oq3TukOhzO7MvhzFxRK620tC9uRDHOmrwl/maZrv72G2QKVeyshpvRyxGy7HcHbDQfjoCp/eZy/SBd39bpf8KS3goX7yEIhc54v+Z6tH1ZfJEZ4O7zkvz+dvvfpBAtXmb+u0+oFo9iKl7vmpV2usx3h43Cun/3nuvS5rPLpqNLfSTuNjbf/5yK3VEHH6f5XZfKzZ0vjbVH4smmOVnhcQUO5yN4CBd5KaeWZb7PPkvcStdquoyITOCiaUQ16vrZtK9ZRTeF9nh/grIdDY+S/T77PH6FT6W/tBlrjyttsqHCl8wnv4QoqiTp7PfZ5/0iT9MfOTGjLmFCnjfxkNtBFCPJK273KCufZCuAL9m6LUpgXL3m5WsHY21qK01+ZJIvcboIFOmVnxjvKMV7Kairc5YXK6BIQyyWumNeAPEBZL7EwZEVPf1u7LRSR7e3KEUKjypX4ICPJAESXXTtt+ndR+dlE7/TPTwmUEwodIia0QQR+UULfQbYQlXvq4SiOXdDpCuf8zuUKS/ByaVumLvkUVrkEsDWrFXt7ASeyndz7L5UaWuOs1KdoaKsZNZnPrvNvIxq83XaNQqr4zXIXiSLtvnogkcZS+cXn1dhfsffHlGWSDpaKnToo5TI68Q1cVfDdu/Eda376ozpvRLTexdM/4XWZLsPUvnmq1DkYBXc5xlUZZrmChzkp0uRK8jP5vMUWn4uu57KQPB92UaSfMx6Xc1tPUynx5tlG+GrOPncFLniVGfNEMsczkGe8s+wqvBGssxl8ZNLHTDfFxCacCvKHeaoxpsrlCgxi2Ued/J+APXDz23JTMez0Y9VQw+lZ9JH/FOYYVqJx+WhnIYQbKuOih3wE587z+8yTOomibN4csUXucS1T/N07BgPrs4lbay9GihsLCofWTPXH8sRH29jEMG0uLkp4CMCstzyJbu2RM3E3N1ZYxhfd1g8z3HVVcfh5s8gu6tJWncBC/t92jCa43wpbGqbL66Rh41bVvlcVl/kgLMNZmjrnsieSDWEgy7YPCKlb0QL5DBH4E4gSvPFyZ2x1Vm5/pxRwGNFlO6ce6JTXWE6vMPiocP1VbfV+O96fFKnNA2BcinoCx2OLzP0Rw0XULErF4ocXG8puDtf4f6Q9BTy0BXFDkGXleB+ph/ml8E/tU3W3A1dVAWNuCjzugjdd6gw+si5FZpdsNu63svixJe4Y1RcIxaKXA6Cz4p8dZHWd+LbjnyJ00F8XieSXDGft0YKuiiqMM7vsHjGvKmr7gKHx9iZ0LehBYO3+eSwetWpsMQ0X+ZZC7bdkj/s5EztbJ/F/+fckc11Rb+P+gy8/NXj8QyG1VUeZ10gLaoCYKfeM3VP5P7IK1H2hKI9ts0J4cO5z5PvdtMSCee8JkCx1Zqq2MW+aCarYpQEvHTB/1jDssLWOZEshT3AF895WLntltWOHvWzR7BxrhUQTAFXC9TVt9XPp3+N2fctZk0gu1cYO67Uipuc21YsmzqYvYszp/OtjEBvSsYOP59rnYfFCpUkJKG58xS45gvYfNb/QRTbKoNxrx306dv4fVr/dWs46PS5IpeW0qO6useNooQGJsTgJhNmD85yQzcOl8W97h8jrL6jyvmS0OQWiXaSqtwde6vihxpRgNm39Y1M7FX+AAWnAfvdEdtRksCy1OHkSh0schLXhK1Onb5QlW+NtJ/lRb0KD6Tp0XjIsaHuOEJ7la9RIqLoP84l/PL1btd73ecX6mwhF1txo23nEjdRvqRsEUE2KB5f4dBUHkc6aIsiiv7jbNJBSKB6u5ErcL4xoLws4OhcbLSn6Fdsv9pjIu+/CGjaTy4OsLJSZWZhv7tj082kqtwdO826rcTblBx0lpvOAuHKyldPTaqiPhZ5vVbqqb5kl69lfO3XHlGzdJ/nUFJENJXmE1dwUFiWPHPItzmS2UZVQASzjeLxVYeaytvq79r+i2XbxN17dl5D5yJMYJrpdJcVTb1xxIQ2psoIwBU44pPTSDGfXY4iFe8BebwBFHfn1V55b30IUs5HqdTl+Lk5xtKgVhQ7zgu5dlhLeIUi9/6q0cqlDi7E5u0qNWKp0Blvc8VZ65/UAblz3EldFDBLXuRbBGoIlxaaepdAjCfgS9z7zB9Y6mRGhnLY2YNKpXGYz658Xd9UJGXzeZakuGMq9hYhPFsgF5zNLfQQ7i3QtNP9c4OmsaghA1s0jk0N6dpiqxIMYxMhPFswjEWE8GwB15VlTw3hqZ+wnkfExgTpGYRKklmAx2hbSUwL8BhtK8lsAe4UvEGqSFdLu6+O/KHmOh9O66RNgW5T5No7Oes9+93lmsxtnS3hUvXMqFjmgvUJFMuLHGVV+RMWEM+tGNinAXFY5+5h8pDX1VFVFeimrqB2n2eGDGix/I9VOtBUA+K+eutCPlXlDqFIkfN09pb3WmORr50DLMm+ACtdvPHF6uAEs4jKxDBDugSvFEs51Gvz1Q2TbIJuvjpiUozZb4RfQPkAl2Zq6mDc+nzy+Phe7nHz1Q3T6fMaFTTo5UueVfcyUgnAF/9/QqCgsljux8EfUAGT6gO8QeLtHh2Qiwuqr9bmnf2Upwp3lA4qpCUVB+mhvFo6BtmDvNVSAnjjl4VVCeCH//xEj5qUeWHtsg7qMPflXtjPb4DoHhUL3dcFapMoM1erIRwkrcY2Y4H+RcX0qgBZCRLyU1rYDHDhrclMaoYMb/ESlrWYV3wI1kU7rkmGBQM91RAhLahGpIdyioTorTzDgAxgLpdXiuQelFDrhVUCuOyrkPruBVfg7vFrcwQq/X1dmTtWsuEiCY/rqlmjjV4660ouBz5x8r7vwrEMu426hCuAMulmhQbEvo1PoPwKn9rN+tecRLwminxvBrCtOQ7qNtzfS7x3+oTKKvwhdAVKn5zCdmjGOTzqPZCizDDfHR0UysMJx6Vi1/I+fUS3dP8UkbkUKH2Yyw7NOMzVtS1iYb87aNASLn+i6l7JZFKhG15Fqhjm85+AcePwagB/TnaFvzXHGG5RvBumh3LnftUZnFjmsDtQeGvdvbTnZdcDeh0RSDaTEsB97HhjulbtlVTlLpZPgtaImBqSTSkUeeBU3FgSyxzsYpgRq182fZnvrtgUHeQKHDyEsCylW/L9Rxdu2pCdGn8yNykA9lir9hojQviRZ8osQ90Rw5BIg5rQoU3R9PbkRcTnuv9RA0plHtXmq4PhkaHqokCJ+mRYLvXArDz3lUtdKKnrr29f9f307aPywNnjWLnbAzXLq3LQGhDfNpRk0IA4mAyDx6Shx6OGY1Hv49AP+VOW5mCpyF8mFLksVF1VrdmjAHCJlE1gVsIOhxSsLxc79B3rz58Q3d2LrxAy3x1CIOtsmUKyygjBj8x3Z/16Qm68qjRsU7Bdy/NXmiAreHkmaHyXZ3XdMZfn8KX0q5T96KtfwqOrvH8iVxVJzxbvsaXIemjj+I1kjD5uIyss43Bq3FjvZgiCVmq/uWI5xiXktRcFsr7Ize+k2s2z36ffy+2cBJFTpCYRa4jUdFg8X91SV91uTX5VgOQBD0x1aCmWOWAlYYgqO4UrcDxZhOojULHM6ZwQPcJC/VqwVPgnkJ5wZwWLKUCKpnRZ9G0qzsG77x4OELVsOvuP3R0Ns9kwVV1kl/APmgEz0HhhUHmZLcb6I7FRpEtusRkoriEVz+91CUGZZ2d50cyW6GsXCl3w0mmHdO8uujikQm+8+kgOI6D7vKmTz8ulLpwKbm+/ykmj2e8OXp/lCmXKED++xIXSjPiqrw5qQHYztGe2RT+nf55g5Rtj4eexeS3+Qyi2W3NfgKI1XeSbrmyJq39OhZEvcTF2NjRWHUmrymfbtEc8rxnDN92NCrMwLOCSHlSox81DzLHaHvRdxzeLNUz6yMTN3IelEzah9skt7IZvHLUYU/zUI/m2VgZkD8A63sY5QykWPikoVixzUqFP37KWDLr3BbhiZ6/47jy/YZqsQIPCgNnHuHBCN5KhoeyDHf9PnjRpPzhxDB6Mxn07lEJr17ih1b/0YekIKzvG47+MKyvPPdPzzssPUCBsxPaScJKvblAGwleNYfz+8+iEdKQV5KEWFgvywSEitxIfLm2+OJwwgqy+BQm5nVfgba3yNrAOxjEcTBEH5hSGA7M78fJ4980ey0+0FJG0nxzuTykOwj65B+uAElIiqI6LpUIPvOSHETcL4GCFlyW6y/DuF1GOOBcfYFSVu5/hkRSl0vUlocx9402CJEWsYplL4JnqKaDN1/1xjWANmjyovRdCkeNu7ltdfbulKNrEjvKmTgbZ9tVvlCUv3jq3iw6HtpJ2k6UqdwhvgM8V/iQ/OsZ8d7s48UeNCtV9ie67hzif5FlV5KnKy6uD2f8NQVyZiyBsk0vZUYqApDbpp0k3lJ45mbdLcdOboaNo7+bOaTQVrkE3qh4X+6BRwSqwXeNmXDcvFn/UoIDl5d2NcMAiFjpug46W/6zLSj5elwodNjV086FDLJe6rGUXBVzAFCaKWxVc0RRrjQ4jFQfVwsgVuNz4yB7I8Z7SfpEK9zD46wrhnT7hxzBl2KPx0HyGuttvrsbOkE6egtUdwndlcxxDu/h15jpHaF4wCDo2ID99TgnU9eZ2FWsjAArBXUA/ODB9mZ5m4CYVFwr2uwM2mNQFlPrEfHZw2MmPCn1yflEov8t7l5awIvBFc66En6pVepwvX8Qust9d7KCswozd+d2+wuopLx5Ec0gNs10KoP0UQQ+0YL7qQFt9HK3QNC/i2Hx1xSRrGfb7eAvkXHbQPVxBuqPB6ivQFmJR+dhD5vrjsA9tVPCJNZ+mXJgUeZycczjtCMMdg+ThPKPebjaRZRjraZB6MKE1ppGOS2NF9kY09ePGyO7cVTP2bPgKrrDREuqLVWH0YFU7NNtqi5MXdS+AeFK9+brHnv0TPFF3efESh5tEbB6cNIziwEVbx0VdrFYUJhKQBYSOHVhod1joI8xggZJIR4wiNp+smoMotn0T+e/wpXlslsO0+eqESUJy2FMo+fgoSS9hkoemg+3ReHCuoe62s2xcv8c4Dv3z8nyZSmFozbetYcPvRRQ27NF4sKGh7p+LDRdpLdyfar7MEfuoexnN/CLaXM7k5B4u6xRegfIh0JnMYPJxJhurb6s1ucDSl4kBw/1HB7+k9Mab6/tuypMqn2OqKl9/y06LIi8kO2BT4CINNAFCUUkOIL7EDeNptlTi67479q9OEliW6h4yZY59lGnIfN4aDdC/rBhoTXVofKwpfd1xBF/z8LnXg+exHvNRLT/6xWcu7ygEZV3AJgIr0C3KovLxh5rrb+2KQV+Mwpu7J2K28RqWL7LHeUnuePG42k977M1o5/8Dwk2WwUdKIjZ/hjSgOPDknvPkSV0UMEtCk+O2aHwy4uqrbivzdT2Wn1/hS5xYT3xvxT2nPmGvzzkulB5h5YpcPSVnebECVYXEdB9yqUt07wphY+Mqb0MDheheodDhVLm+SVF5L9o2zOc5I8O2KWOQdtQ5ec0Qb0poqBY/bL5oa1QYZsF6FS9UQ0LnodMscIyj3Ng25fdi5NK5giwogURU/UcHL0S+RomIp/+4x0EfFwV9RaNNRB56tsri8jpaNSMYidcjhSKdFflKx91imQtn6nDyJU6y/U+YVJJINx/drtrKl2xdr9cCxdVa4Hhk0vocjl+a57ZFhFKxF+7+hTQtegZijzUG9czggs95YAw2g8jrHNJQeyTf2aZJ5dVtuXi22ENV0l+PfL+7zJwEczQGpWcSQUyqxjDSijaCVyN8u+t6TjNb0OJqDdBdoPXfYfEKUtRV3VZHRiyLglxr4pE0X+bcGoe6GGbzEVMbOlIcN4/My0M8gGFbWfs4Seizve0BmcgAiuJdFJt4ISANNRL6IKYULCOUze/nI+8yk9sFIE3FXFhcydaI9Vf4VH6GVQWLeI4qNU4PIbdFNJKsK1uXnVcmOEc+V7D3eOfe0y15OxIMe3IPk4e8jpU4SkLnY7oN49jWhW6bE6fRd+TIPqG9e6HGrYdy6fcVeD59hhIZuAIHqoLn7s6R5L7jixzUxpankYtnZGyLYomQTEyNM4aKmTSBmNS65K9SAUypxw6JucKkd7Y3CpO6IO99XIAX0mqst5ZVWP3eW7bENI7cic2L2FTl9thjvVi7c+5ikWxxuS0Cm02m11+SFKrSsnMFjvguYIHypbRC8EUuJ6EVSGltwQHAFbhsc/D0qd8t5krmcKPECq0+z1CFQKoUcLFsj+Wcxqyhf9Fcj2QgoeuKiM9nRbHAMY6sn0a7yeZ330uLjQYWqu8Vi2UeWDUI3XEp7htzBVvD9ZeQ+Nq7/KahaxuLy2tlMyMYh9cvujxA78SNwOa7B7b3Gmzv99pGPynyssS7kTQKR4nYfPbCgyj2l6tmW0kDo378on0mjPLBTX2GjzCVFjXmu4vrMi+qLqBRcFeyJQ5hhnWaKhFyBQ4m4ro9vBSItvk8VxQTeaJTyhrbf3TZPN/CooCFhIsr2K/4+7OCvMBOrsMIcaj9Z5doMpoX9hMoxc0hW7A1Kgp/qFBwgtgGic91fl3NbT35+RPlz9mcuYTuAJnTG58MsKba28onO2ev0vsbgdNMUPhMsLreOFPbxHTKE8x+d3EZJWm9hOfZAuHaQNiIy6VOBx2gLEngKS6o1McdMoCLvdBUFg2G7quDqxFV4u3H9tOUUVlfYAXaSF3BOONL3DBq33eSCt3wKmjGfJ4/1usSZlg9HZU/0fIOVqIhyJc5HAvSGv+VZ8LQ2e+u2H4WYN2aViqkXLErbrzreFLMlFToivc4J8pfFGixzOkYFy/S4sMmm6+OskweepbFmX6dfrk6Kss8QfR1YmnNwkspjY+8PlqvU0Q4nTFYDAuVuZ64PHXQOiMEr5FLefXXNnC9yOtC+TSQ1WrXo1Yte4SYfV8Cu3kFCiLent3siOXYzd/eKuc7hCV6/5sTQ2xq6dhB40azInOHfat5oe9kGCe0aKZmBBrghv/Ey+p9vry+hGVVIGIknZBRDmkIm9rSXpar0wDaKIvhtgLZRGggArNYdDlQfTTUm5ppOtfbNXNFwZR/RYaWE600MJ1/cJi2MtbA6e8RRph4RefCJrrFM9tEH6M0xZ97963FbItVdFPuMtc8zkCaCshiTruAOowxnTuGDfklIvP56rz8Wqfp769vQVpCx9EHM88FLFaoJLm7mqy612wGYyMPDdWUcjwI8Cy4BXuZmwucPQl5BD4b6HDgmsLgmk3fWLOKroZO2ziyhhr9Nq40+8ICl/AJFMuLHGVV2QbEXn8v4fInqu5bZ7ApomSwshxDIlWx4IvBhgJngMcVgU+GO7yNi9QQGeIpnM5Ud7FwpDoxTBwBaSAfidhiahwR9zYy0PD4w82cduPe/n8F7sy2jQpcTlpFCzcwNlaMjDjUdPFySVh3Loq/BGOKvkJ1vlbiEAcog4UI0jtz2y/932X3gUwouINf8iVMy009kpZ/BeiIyjVI6A5+Cc9QUZLQcHADStiAvH6F+/6IsNbrjtxah8sf6UnapIPqAL6ADN3CsrrKH2D2++v3v7x7//rVUYpASeIG0tvXr55XaVb+PaFyC7Isr+jQf399X1Xrv799W9IWyzcrlBR5md9Wb5J89RYs87cY11/evnv3Fi5Xb8XqLVorLL/8zw5LWS5TdsaZg9N2nrt3xr9nSOCN3/4dSpzWzfAlvH2l0yO/vRUr/qbgLdKF318jQlkqjfQ1JRpdCsi97oxAQdqz16+IuiGXQnuV89aIvjktbRrIHkGR3ANsiHwBz80diN9f//qLM07uUM0adVXIIRgSZj4l6xi4GTuuJbnj6EmCtFtQp1WH5AYNIWEPWAYYENZw2eSVqCqQ3Mt3ZnaWE5mxCS2J4v3382wJn39//X/Rmn9/df4f11zlf3tFJ/Hvr3559X87d6PVjoTFWAb24YTmmTkDk7775RdnNj1DzRNLbvRpaukIYyUeWMV3reKx3KAMFC//bQWe/7srpkGV8/4Xd53zBa1g85BKEGJrSfyQP2VpDpZ7InzdcJq0IE1DdYb+qCGiKG8RUYqOSPEOqcNLI05t1aG+ewyaboK9WLDDd0y5OA5btyEKKib0wkdENlOIihey0+eqfaogBja8qYFP4y5veyJXmwAO/2WE5NIdsHXc9SVBamH7OS9PV3n0rl7lY3T0Eq7TF7feOqAdo8cnJ7ExHidJbJR9OrfIZk8TSxhBd/FXFhqE5MpBhciMuRqLROFvAhH85JsgGeyOlZIX8s25mYh87TAbmksmF32ZYHu6J+tEm0vNZLv++qu72dRsaYcNbh63Da99ykuzkPv09yIvqhBJwgZnoTKZwjvWx1RHRtykA16UQdYxsbMblwNWbpQDca0R5K7N0dFEDO2J4HFjYi8QGCb6r794WDGnz/QiAXf+f74sY6+/fTNN9NVQC+89luKuCT6CbISxtGOg7ZG9C91hPYtLm7OjIEOrekVXt6MVXUK6ZRcmaAVS4r3Gv0rqhn73N8xyxNmIZ921+3jwE7XUYO9C+PwoZa8FmsON4zpbYg7G8tKnPsM71ko8UNxZxbAZn7spxdYNMqS4rHL+PM/nzgvDJaRoi7/IiOy1J/x00WU3cGWmvmIQJzX09O6EUD2oK90pWggXdqHuY2nU/oYALBI84TTFgL+BZmNROG+0SToFw0mbr88RszmTYDhg0J/QEl7d16ubjNna+CD6gefzJg2aAOYhwwAndKQDwqgeCD5fghMyV5W8X4qYtBC2El6AAneBJujq8zyFYWw5Hatf9IiWju6TcLVj59sZRe9g6Ng4j5YrlPVvQEVA2DFO+6ZH2FSTq6ffsk94J3gRuLjwd6PjLjLSFekIZGQuScft7FGa5k/99ho+IvgUtIAdrddF/giX5DHr7G5Rr0Lm+2teRcXXIaO5QIXBBvYvFsr2KOAqP0qC1n/pDrw/qsVDHV1EQFbfgqSqC1jgFaH6ii2ejX0Qq5WPmGVi4zwvP6Lb6gQUQVZRhyN8PW3fL/hW3cPigrvx69ez7j2Efmk2q0efU6mjmmycKpSQpfpouRSaDOr+ednHmESInAibmu9Z2ghhhy5oZJjojZR8u5XweW0GWySnz2tU0B3sB/Ciw+gSHkLzGFOE4dz9CZQLgC0HGGNWeUzu23mxfkhgGB4YOXc5uisgZG0tz5OMDaLmdd0o4Sp9mvEwfdIi4XKEh+g7Ft9FnyE8AkYuQ3iIr4/4+PsnK0N02Rme1O7AIMgoWzYXK0DaYTu5J7H6Po4gy64zD+GEUOC0DCKh8HxOwAEIyEiq6uwRixhG1p3eBFl6VZ48RHLrERcLxXf0CBCui1IGZ4DbRtlHr9ULZdHG+zl/asbavpsbNg3Yhke3L3Tfe5YXXf+OId4WhaA9BskDzWhEbowEHkSQLRrBd97QkH/UL2BS6PLVHu3FmJgGX3OAFwMfHThctqiYgKFopihmcwJ8XL8c11W12at7igyB/onK+xSVVTjCVpZTiPkSK2bOheqD7wTb2xQVSsL8wiyC6EvHt3Q5bgPtNuOEicWJ3sZijfGA1HsgVmcZTBv9WyRXaAUjBMWxuE+zZUTMnavpNKtgUQbzYqu9OKxwZAZqNdykbeL9whWCjewG6Xy8eMKyYl7+W5HofbKUjMqsuP/d6WDZJtoKGUXzktpo1Oa3KdHR/0TLEbF/Gpc2/aoUW+f0iOMqnFgHkHFOQ7vHmRgUes+De5TAtpySKkeOHmHxQmbV3fXC1w5xvLC3kX1uTLK1Q/pxDErYLq/BjoIe1xcIyrqA9Ka1OazQu7vjxuT1zZAffFMeHskm/qZJ4qpwi4UeBbThPbAgAVcx3DQcQkKGmPgW93nj+QGbcPGIEWh9bNF+xDsMRgH4XLftaBTuF/9ewjhBVvqQreiGQ9eUvwaxdKuxzzKG2Q6tJRIBU3vGVZ7k9ZpEGi+DZk3GovOI+Ibw0eNjugqGMeoGD1m6Hfzq1opHnZ16fxWPT/gRiRRyRWzFLZGjXI7zCltg0WOaSOqc2ILSsV2cwKZDOBIXHhjnzOYC0QATj+DxrmKIgU8i1BboXzBkBFxwVnmVNzcIRMxePtwWxzf+FMHG1LGL+sM2/CXI7gZ89n4h3JFiACP7pLYwcmsnfBb7FiGuoiC9Z/oDwacvCpvNQgPbR503qmtPjKF2NDETzlilPPqrR4Q3zHW5ZzjUf/EJORwncUx7ELZnLDPvjbHxbI4Rdamzk6fdze5RHr1uZB6u6b5m6MyJpL2sU6i/XO+l/RZrOLoDpn2HoL9LHxQj1YWrxUC2ea3lKucTCgT4mDdIL7QR015TxSBmsy3ERt5RWLMRCMTeGrFBFD59rgrAJlIcw25iD5j2RKUNOnw8ktSe5GlefILP7dO/cZFvX55aV1Nqz3yRM9tSGi+QRfubmkEdOC/P8Jay3lxNiRBROzIHsherDlwYgwtZirr3ga/9p+HGPWTDUQ5movvlGbofTibinkwcThMGe7d7pwkHZ/tuO9vtwwS65+LaN9H3Y1HqRuVhIvc1w4ySNfe+VjyZPy+7zApBgTK7yqZ7xp+xX0gYTljrcxtsOJ+wD1ZdGly/dDotsrO8WIHAxEkdrgXYPLuzXcmDIl0jPrq9RSkKNoXpfdMgO2ns1f28bM4LujTfIdEMhqy+xi6HZa/9DMpKu6bMn7qedO9zfoeySGGhBF93jdkCpcv5C/tAoptpICEI2bio3mt0646Mwb4/1uuu8pn6nV126fuD0Q4NCZNGQ6ZcYz2fDlqtQRbpfQvl+aKNGd1VDJIRjJ6kiX1EWeLhYBCqh/TkhLmxH2gKUHl6FxPZ+yjI/gutL/KSZHrxC8VS2FH3eQbVGcz88jp2mZ7mXv/sdy2NFOyJ9hz09L7z8PRS51vZLq1BxixFFOO62dVT/hkSYp2X+eBdkveufHd1X0Boj/8vrvixiMACJQLuoJSLP0CQybxV+ZK9HZvWQs+/ZPFnkf1tOOWJ9ujuXYap16QCC3J9T/RMS4SnTey5mzWq9oS5x7NyZ1xXb24K+IiASrhC73jNqNCt+fQ4ze+IPbsnLPoZZHc1ybTnzKObmkFMqjw7lrS0nSPG5vVFh5PbxrEaJTt3i+vEkGDBTqQ3CbBjobwCd3Ecf9t5EfwQTxH/5H2KLW6nXvZEz46yFnc0OqlTeqPIfCTsfu5HDw4XcITN6lkK7s5XuOvkDtcgbdzDjy+r/boSOq5N00SALyqSlPkSlnld7I0JPrt909FzkMl9Etx0yJXXA/xMH5IEO19dpPUd0iVTtTxJzutEz/YBR0df4VO5R0/uzc6hES1w+uxSHFQkhUocTFE08HYat3+mfcp22K+HDUaH1vqiTJ6mR1n5tDcxdmRAHlHptFZ0f56fSuwetvmRV2Fvb4x9yQoTbU+4ZvZlPh73NKFqrc6Lc6IfZYmOlqiILqsfa1hW2IolMrINB4zbaYGMf+zJnnHtiS4Y3gv++qu7wRzp7aIoEcAYScv3BIeG7a0s3OAY4C5Gl/LPSAG6+qkLMZxgsUIlOXe9hAnRtPvL/CHr0CjC1CcWCENsPdenz4SqID2qq3tC14QaA3s177NfnYoXCdvN1jlzpyYi2lZzRsb+jfDWVf4A42wjKbqjJIFlGQ8pjf/AExyUhcla6M7yol7t0Vn+Vb5Gibt4tdXCUofMLdxWz3Da2QsXNjcsfTIY79rdSCoflDv2REDogNxZtK224wJC5pG0HJggrondNfsOPXJRfW00cZAz6kfoW/Dk4g3pRWAK/haLZso9sdFEaYGb9d3UQPukfD4Web321EBt3XFDQr2eWYl8QvG1XXWCZDmGQiGypzKqDmplFA/nbqonKpZ7oqN2Qj3sG7vN4VRviLcfTEvHEvECJ8UXNYGKOSfvbuwf+CQFoUkOAjsjpCgIznEQdomb1iT3l2qxJ57DioGrTWIdEVVz7zBygvQ+TVhdFDBLXqJdEu8QXoLN8e1A6vW/eUslf9wVRu0foIqtzPCmvcKykJ5nSYq7akmOv/pp4q4xcmtwisauSGP9owATjZBrdJqRtrphmhG2jU06MtyQg7C6N8apMaz4EVkbQHoG4dg01bc8NoH1LY9N7RZ/nKtllE9GZ8T+Sd1RW6GqY7QmsKVeY2tnOfKbI5fwCRTLixwvcOVPWEDMWoGJI+9h8pDX1VFVFeimrmDsXaPUQPkfq0h5kVojQBPh5xp7Fid3Xm/1r6OMkUbEkW0MeRumgFiPnOD55+0Ur2nHWNgIobCJIF2KZphK4wtMFF4+wKWOdME9PXl8jJOtiSA7fV6jgu6cvuRZdT8C3v+EIM7YWb78gLByqz5Ayoch8Zo9mjat46c8XUaaKxl5REZgkB+D7CHaVkrAG03EWLznJ7FRdjmyIqM9vwGRFqRWQ1OjIGYSVxKYgwXiX80r4AXISpDwD4uPgj4au+kauIRlHSlx7glYkwvT8YkjI47Ya7zv7G2i+F2/qEndEsZ2p14AFCvYXMiAFYWmLUqyVyEJLuvGZTiKr2vsbMTbe6DBbhcu4QqgjAlS94gK/wTIE63t5vZrTtzyCZeRKOJRSbcr/F5i2/4TwtO1N4kXZ3+Ek1Z1b72tFhaQNUEOk4/olhr7e8g63dDcJ29TM2j+vpdw+RNV954sJFQP7gqXgSG6u2VKZt0TBu3MGWaW8VrucW9XgyfkwLAjdfhh0chuvvOy6yq9hwVE68VTaeCt2TrihuESD3aNiCUQy1LrMca7M7KAGbGrY/WwQReve19gWTK3ZgNfEdnMCLXNZntTyC0eZo+SyvTjiRrHMqO5djHvo6T/qEE7Ef66+nuGKvqy3tjHjX1Do58uTjGaSUYy9mlot19q1uuxSca3NjbtRjuyi39U9yF/ytIcLIOTEZ2XHaoohtFnzOJZCTucWpvQavXFWv8nRHf3XmahTQvHdbZM4QdQgTgOwvYtd3IRMw6Pui37X0mCj31a9mdZoL8yaVLCLmB2kXR5/zbjlhuPrHdzv7w8s0cdN0QNCl6lGI5BCsi7AiHmWzl6VE3MTVjcwwDW/+HxpJxYf4QH5chBzmp/HhqeUZNfFSB5QNldxDNAGvM2rlFCD/JgrJPGDzBFj7CweSNyW94E6wRgj7wY/ZC87nc0NSOcT8l+49G9Bw62R1UX2SX8g2Sr25dpD78uFWniZrd/YvidLiEo8+wsLxpeiWOktxwH6f7XYr/vg9Q2BMHpnpGQLDn0xZPb2695rCh303PeYnJe9xcRWEUR41bYtkSbOCyQOQ31OQHFXi2S4dryAhSt4RDkeWr8Qn7HrGzdsOevN5Mcfrw6u/6f+dhjvMsSWDphgdmfOPdH20/HWD13Ts21M79YYxp2YXH9PO6JzptZLNS0/bbmo3Gt9ypGbGHyS65HnKEUkzswK3CTXLslX2h+7ZGzxpsIuicCoB5iLN7bmkzzszDKnrDIzsxCq1SuwN0eU97xTWtX4v0ABcK2Ts/DeBd5gzKwTxrvoXahqVUYZoXMTxj7vNgDsvoWJOQSUIG3VZrrfaGteJvNVk860H6Nhf0nWo6H/NO4cQ+ghJTy/seATs2QH3xTPg8olCW6y7AEIsqUQ6/Ev/NwLXWHJSSXoMdVEq52yN6/2+6R+Df3fvC1Q/pxXoa/WrF3G3+8HiQPMTbkdE/zra6+3VKUdJBjpMjTrKx7spyG8lf3f0+X6y+AOt42DHjN2o09N77z94IF7HNkDMHZ5vEn5pGc4ID5P2pUhAURMsZfVhV5Gu7+1Br+E/DJ+8FpcZXkfRPhoxSB6I8URNw1BkUDh6rp5j7efky0ZojeWlBJK11hTD0+H8daHU3kaV4s/qhBAcvLu5vY/Wx2Dst/4mliD3ijH3o0YVYTNHReYkwLmMIkMPo9wjIThaWHlxy577Sh8JX2M8oeyGmYyijbnmCjKwSLxvWwV4p1tmOkeGmhyeOG/ofUTe0YW++gKISIZ8H2RwBkDvaEnSP4nRVH1oW0/w/GuSjT04zABy0bC5jUBXTsn5UXkX03JJqX7HN+l/dOuFF2ZY54PlWr9DhfvsRKfYV3nZhxO3feV1g95cVD2Ny4iXG7s9wTaW7GGMYqDY5R9ILz4mVvZdzDFaQ2283evPhMxxRbT7nOqw1OLo+N7gkYZ6zjMcsxSB7OM+oJZtPj7QnbxIjtnNfGnT2CcoqrN+yh7xVc4dV5b5yMo6wd5KFG3DUps3Aw4pEjVbpXwQ9zvL9z3EUjHaZ4b6eY0hUl+3YeFGPDgIfQvGcYe0ox4vj8p7JV/Q6rxjNQj5L0Eib53uRV3PJt6RQOUcvTkfNl6hACZM1Q34sDQ03p50jru+hIY0SI+Tw3Y+9PS+7hsk7hFSgf9oTP4kU2LLD4ZcugrDSkZpzOxHCkV/n6W3ZaFHlQqiXypPSiAkUV4bo2wXWaLSNhWtRJAssyVr9YQnkeD9ibD91zUHsihd4vtsZ5OFb1BIPrCBw1t70XCYKyLmCbJmc/pntwSX7nsyTTZznwyJ6IFRQb+yXhQMtjaPcXY0fe2rY89AGrtqzcHz/4gY0mdnS2jyf/WdjnV5+Npv7Bah63D+vYxsF4c87nnCBwIIp9coezvFjhKWMunEdC/xmtEOaHq5zyh8OdD8WpWH2TovJ+pLjF6Y6oZGRR3236kJO3mrAhjiczNCLGWvlg/qlX+3iYywwpalr+2c9Y6YyFeXCu8jVKZktI5XA6RJN9d4la94Qxw6MMzop85c+GfO2wm1m5fzfYumGBvfXNP2EykMPNw+Yg187ieI3IjTMQtPidl+1e+vilebAzErL+6ZgQfFOoAuoHwJ8+5/sScciMiLTi4aMREex46JDlo7zbyJLUwbwfbDnuPn1wb/jeA6mzU94hBGm1BuhuX2ziiIcy6jXXDxkJi59d7CNugB38h9Sw/bNFP/nI+HGS0Of32oMJOQewqQXL574HrUifiyhWzD1VnpOGhInqGeKphEN1wJstSUwvSNOXEYTsK3wqP0PC1Hvo5VAPLqq/Q/nqpZVhSDqXSp27pgiv220wf8OdFeFf3V254QISdQFR7fRjky1i4o6Te5g85PXeZe4YXI98Yoq2MicNfZWFwLdh1TFwnpdX4Pn0GTIj9UGDkXTx/GELz4R5d0YPM/MXzX1KuCINzsMFIaOInlM3WGUcUpLElUCHV3uSuiApuS/ACyHIfr0aKI7OXXpkDBGecdr6wyVx1HvCDicvSQr5pLJeM0DQXMAC5fr3cS2PiCqQUmxBIbw01NXifbjJAsIjxDaeZ6hCIPV8fJCvvfW3dmkIDPoXTbtE294TeVNeqLCYPoke1yd4N5HX2TIo6ZvmnkKcDv3Vp0M09El/0y1Oz/4ieA987LO+p2N18n20TnrfxXNYHVMqH81Gck9k9aJLsvAuZCnqsbyfftdpv2Ms8rLEtnl6mME4M+iw0O1LhAIeyWf4CNMwA3BxnxeV7VvbduFPGDzm493n6/ZUKfaZ0pgxFVZJUDGFFBnbvIiEORUWBSxi4ZslDNemY2cFebWThOOHbJ+a9GyfQDmUryFSGO8CNjHg+6F5RjlC3okEBoyf/M8yl1uYs4TGR+8J/ZuALqvQH6vFMkvSegnPswXCaEG/o/M7W7oAZUkCzXBBFexG7pBFGecVquQbO16YokWAfIEVaAPz4jyBTRCGPRygxhmPdhHDTC4htrKKo/InWt7BoLPMBsN/5VmcMTbofhZg3VoNmr7Z4yLPh3Jz4D/K45yo2EC5LFBeBKarpsMhjxa6U9xa6+NFhUZGhSzAHY5reSVQwndtKeCHVw6uMbcNBlM1zHXM9t9xj7Op6tAF59kMcIC4Tmbb1K7OJdt9tx5sao4xkzSsBW9u8NJyny9PyFD9hJNHZC2iTYNes6po0Y2yEoLAOxaboTgKa19zjBnu3B2dH8ZjbjsUtrPaNuU1q1xbfo6d0Jlku+/Wg03NMWbyAhar/7+9K2uO21bWfyXlx/sQn7z73CpZjh1XeTuWnNR9YtEzlMQKNVQNOXZyfv3lTizdjQYHCznOS2INGujtY7MBAo28ajeX9GXTxBpvS9yqjsd+aAW+i3wMMraMivoQTo5oTTotg97Q3edzfK7XbR/ms729gid6/d4d3vKfzrpBHM+RKPKG2bKnOGxKgwowyr9Ihr6zR49+zr7l2fffsuLp7lQcFr6AHSx9cXa9OHFHr/Bih4zdzxLlj7QaLO5hw/DLorwfD9Reqi8H/VjH9FnrdI3NPpXVgg2Uc08fD2l7HuRH8aWzhUPX4Gid8LbO1LorzOM8fU8vEbwsit/L9tNf1DLFASJ3o+jVofq+5Gu62Nf7a/RyPRD3bht3saH3k7PQ0NYenKuvLbobrs8D/i+rut3SDob6UFqOhGH9qqrKXd55duDwn1N2yvb9SeK6TncPbZxNXufaTO/Xw/6ndjbSFjb7fijKuQLOTVbc/Tz/+P5U1PlTke8a/v9+9q+ff/7lmfrIfDz0+61/ajdutwdXrtNql+51czRq7DExQMklmRAKWcD/0Zh2e2Paz7NpcV0eqvqYNgbXn/r8sMuf0kI1ikLIDBCtrtOQasur7Kn92nWoSc05jFu/wswnHooDTMZ48VzAFBtqiXh0HQWaRCQ6Vm6Q/ekfbRjGPCELN5V3dLHYqVUIYmNLCGOoKuc59ocIaLYwiBbThJ7R4DeupfVX1CbD/1HMje2ib6ffgmBNFlgWRGnygi7QQn6QpejD4ShcNbwKOIHfvDVnQl78UeAEWWg9cJqnWlHgNG3NcBiXurxe9d080rTpRhxq/nHrMQXeU4S5P3I0mTaUXD01Jm+33w3i51mV3JSn446Y6w195bne9GOQ4KJt5IJk8YytSeUA4KI3riE86c1N0WF2mx7bbZpOwsUFw8zK5TFgRmxwjAaz4fW6qVgGpWxa28VEMpv0bI2BbEKYIYzFT8Tj4ytgKr4EXuSGlaDoGv8xlHVr1zvUnRrrjF2CwKA4UvvFxDBRK5s4FnsRIWk8n3/Ljn/ftqdnUd+KRJJTpQarOaBFNHSFC1RVP9iweq8JssXGxJTFIWdj1pWYK0JDeLqgtFzVyCYrXw2uNrNiGRFU4dcs7VatIi9atjXE79Ju5ewYcOFSZCsNJzdsfQFT0mYLi5gDHCVU4Eqc61C/QQcVCWz3AjVr/7uJQNZsxQ6rwt5m3nArAFv4N519eIv8tlMOhn7OmtHytoJGf1KT8aVGHkHytNoUBH7wMV9crInCCwQVEwRAIuOYM8KYc655JZg0fdYBvI74+YdAoQ0KosEPPyAfCnd1M09p5PrWqJoloOjrwpgor4wtuWXzmJLUscBSNCiNp+Mdgsgwf1RqT3YjTb9tHQBgQYeVu54A7fnP8OrAYP+IBoSEJFy83XDjCf/p8kFTaj32kMPD9GOQl4xaUwUSxXOcGRUOgCqyggzCkq4yEQlZhgTZIkBcLK5sfBwBVnhlodCoepkXRZPRw1WVFmHKtInXJu5tFw0sXrLx46NhKC6ZwEqs9OWlVMSURJnaLublNWpk8/KKhqv+JpKb+tjVHqi6hCgZr59BwTURiB6dfwwCLkhyWR6QwAvMYIP5gRmoFoeveKlQFKyNBVa2ga9RWkmG+cfN42hSZRPYGeuvbAM7o7SSDPOPm8fOpMomsNMWjtkGblpJ5Y+13Q+bx0unxmaw0hcZSnShbT3lESW9jJoE489+vudzvegALYMiHG4teTy8qNVhxQqexhVGtbfsT60xDLqo2r+UfDKhHwSqJgmBRnYtZAyfrOLHKwCr6as+BgTK8T8gSK0BEhughrrLodc7rSLoqpa5TA9IQPAFXfBaCrjVgW1DEXCNoAsV8c4GXtxI9+tf7WVwaXF1qh/aEXddo/JKXnXEozSQK/aRhJuPgKR6NoCMhsXX5fH02C3KugYe/n1x4imNJPy6eVzMumwHBN1tmaFR0F/RqcFg+PkycABcQ7pqICTdf98cy9MTigKBRHPe8HOQF1HHUBfBE3Qww3gED4vRLNcaQgggt73HfOIlQtDh+zJsxOnIV5B8YGKf4zqfEAqevVj6NWj+0okVDUTdZQQeNslRuYt0Y3k3yPDL1vfG9WpwGMkGj+z9TUyaw4ImZJrLR030DHcsz/SlSu+z3/JGmuPfCVxXaqVluETJQXlkgospxCWpxeEbvRIXiDXgWbGPET8AxPgxJRa+Ognjvvi6HXFrRtQkpS6Bx61wwbAzK7IlwKy/hkkc2ASsV2IHnNhVSt7kd/V1etwnn07tBWtVtv8jrx8QHZa70XAsaZRCGmz+0V8kYfvpTFBMurAwAboiOkSkXAdWaKlLPcUaSHJQngBJjxUCHKHNOu8ZO64La1/ER2Gl2dCaoBYsR1qMM8mjcdOmD2WdrT/PbqXUJeh/3TaGZkXWn2d/zr43aP9UNgNUY3DaxPokILgkDti++bVLSKtNrGRCOHP6EjSk4+uBS7AwtBQrklviFvbr7kdd85tsFFIr1ufxXolgAJr0WP9rbBS1WzGC5V7qNc/I0RYc5AZvdUbZjnUEIvayxNQh7kfasTRluEI2/3ymf6YYPWK2Up+Oh/YynczDXmNP+bAgspLaSC0XkAOL+mwi+50O8ISPKv+Ux0LDS8zctuwEuU6Pfcry8nTYFxn5eWL4rCJQAl+8xFYrmKgSKSmJ2ujzixZmCz8A0nTj8JxFXA+ENvGWWgPMQr6rFqEr+utKw9b6v8GvAVgBv8gvwlXsD/MD/5unbJffDacPr+r6mH891dkGMEbKD8mFUW4dfbR6W4AiLPrHp/bPhKOXGHrMeOABwVdoJHRlSDkS+lmJWg6hcyMopSxrMgEOsNLgytfWN3B+yNh8NtiiB2xKg9iYH1OH2/TeXMNsLVnELDMki9h6IdmCoJJFhhCx/BgALkPFHdqngDN/BIhxHR4TZQ15dKD9nh7z9FBPsfW6fPyaHzrCBL8yXjwPIxJJ52CkBqtlQbNsELRIcj9HvFADeUUbpShHClHsNeNvM3Pz1QM1/Hv3XIzGnqoz4PmfU9PSeOnLIccxKhGJWJAbLjI84gZaNfREsdeGv+3GRA4kLzb6bTnkjZAzL0lqhIDLQy9DrhaNQZcdHcByNWuNqhK/p8VpAimtoR9chEVupy5HzIHQJ4YX4ckPlHttLfCsDhAb1tHTSU7KsO3EcHPZX3KTPj4V2avy+6EoU/yI8EQgrb9MP64cDbB68ZEgGz8aFm7z7Njot8ukOuzG/VYdEbf+eocJL2+xSXpJFuHXiyi2PuvDYSZKtwJYrX9KGQdEAaeNdvhZyURx3o46bCReP5A0ye12M28PWLpKHKaSO1cEM6cAM6ZA/6CEZro6fExzudd5Ubf1br0fbwgVphTNaCE14ss5NmHUlR/doh6jeJnu/nx7uKnL3Z83p6/V7pj3e0A3cZoCEV6+Axqj2fzZCkwzm8R/dbhbf+a2PtAFfD+fg7nYb+mrXQFcpOl2+cIT5ibR5QOx868XsXYx67OZtYuru7u8aH7JkkB3GUwM5YHmX7d+oHlWhcMsdqGE7uoNr4kTDgWNt37FyYVlPLpOm8h1Gv2+NYB+3wA1vc+S18fyMRxKZOZK3iQ3bR4fikIcjqIz1gKQ2/IfeKwEHrMrIqatdf6tMfm78j4R/t06Ck82FDo5a1TaAmWwE1dMGl+5C2UzP0ATlWJlMbKIq4DaJhaA4qEqZNyyhVP0kHX9kO3+LE/qzjjtZxxbGqUEMr01zCXuoFq0aD73vhns6QeMiIYsXKpdI9a3252Ojcb3n9K/uxqrbw95O66jUqt4uqUyVgrVqY3brp+q6cPiKXhiNfgYKzbTGrnys7cKiaBSpGh+S0EvA4hbUNpUhlb7RsPnu3KXFvl/s/0oY/IuPdyftFmN4P2JQHT3/GMQBGpiy8LorV5QB5vKD9p0nThMRwkj4sv1BMDfvk4197+MnH8zuf7wVe9z9i3Pvv+WFU93p+LQFhdtXTIP3q16Tphqfq/btOu2TLD+RtgNY4Dom9qst1rpcgBfmgEixs72szA3ahRkmYzjESveMXEoNfyCwkoiw50eDVJu9woMyqwdTVLneHtVivL+unzsJorMqCZ0CR3IRNbSnhTx9wsKV6iprdgFhlH7709lVePxaKTQfNj/GGarkz2UHIWpSdEVAmiULRqQPmTfK8t4JHQJHY9E1uKQ0u8XFI9QU1uxCwyj9t/tPmQ8Ho0Umg8D7kZfACVH8WhSdIUAGmWLl3qXRfF7WeeH+2F/JXfqp/QLPuVT+Ut5udZ4QTGKtrwVzxj4an+4OlTfsyMxn5toNLeOP4c5QXMOyFxN+mal1wquWcR1rCAsWr6KumbFX7PYduhytIARHFDDX8YVqPiHkm3xtL1jLPYgCnt45deu8Ev7VDU9suO41l/us9f5sapfpXX6Na30j31tr5usBgrIPPupb0UL9dzsHrLH9N/P9l/LxvPpV73GjxaGVG7ZKdv/+pjmxVVdp7uHPh0H2IJ0MH+Q1CDIXG5G4z03QezmVr6qtIJGtYyseuV3u/IEGlNuhpjJFAZuw3ft91n9UEL2U9ohfgqJiaHxyLAug7ELKJaxl62kHNGYsnCZ4yxJRuYnJq8wgM1N4BMztRo4XKd1dt9tJNE4zE0Qh7nVZKJ8V5+OGWSisQU00djI8wDBRSEg/JEMRMn7tLvEiu2f9s7P/JghgRWkorwmEZpEkGqo67ylZpCpRMGzNoEajYKy90jFNvjQ8X16ON2lna+ISCRTUXKIlGxZDEKYucsUpgdVnY3oz6tKAT62KhGTLcGPZmTkMJ211BhMLdD4U6NJgfaBguPb2AKKPzYahh9vbkXfzCoBxEylMfGsm8emge63JqmGnnmlHeQokxgYzl+3NF5zE8RmbjVwmPe7aRzmJojD3Gri0G74ym7qY7f8UfWX8QDcQDKQM0hpkGJel9c4z00Qt7bVHB2FNTQ9KAqNYCwU2hl8EA742OxQ0x/fR8NN30yFnJ7CpEN2fMyrqpnfjSt8uj4aCaibRmWaOfzVpLWHtLg61Q/tHLS/ugqVgiYHZxZkD4N03VFe5GEX2iC+XXOVsB74jva2fMp3GJ+hkWA0UHA4YUzI8QcKzvhvjuXpCWMyNBKcBgoDp+FQg8Zk+B0af2hiprFf2uOX085yNI+VyahEVqY0SPEmv2vSxuPeIAVMBkkBUzKlIDjT3HhuRF4CQhvqTtbEtKP8UNZQJBXaUCZ9s4HJ5+x7o/CnMj/UFe4wkApiDBIy8i9k2jU3YTkXa4I1EiIek5spTiy/fc6a6cChnQBmYAhW2mEzSiRG9dQrqAEVVRJYTZWKN5fD7rvEZnUYPTW/Qy4f5c706GtEdXuR5KDtyB6LpGPLZSMR16fd3X2YA7tGwltdO48PeWERxp/sRMhF9lsmL19Iw7qVcgGH7XoKQyCeJNZIQa6k4JplILfw2tDDIJ1QOFoTRWiD+ArNxnl8Ca5YDr/D8/aSsSbaUU0QgMefmlE2XAzdNv2zzsxfwYmb0g7aTCYxLUdgRfz01QmMElyswIgt1gFvs8enIgWfI5jMtC44UzIX8gkJdBJqYZ/NeQzbOGONgor+XLZvskPWPGZU6NJJwMRdozKtWM7l/fQ1y7kNXLWcmw1MvhxxJkIbxERoNgWKpvf+VGS3afUnFCikZjBQSBQmu83F8HS7zW2g3eZm09OYpVXz4PyR5fcPUAKttIPPn0zCY/gqb3L8Cg5DOgnBVqAyLpgdj9lhB65tT03wQtnYylnbMMRYgIZY6bCKrGqhKyCwyATUqpRCanzGhUI1wFMutMLPuUDAZ9XXfaLY9RQGlj2R8YXx+JTm95BL5yb4BTG2Gp+MztbUO1GlgJ8LhYixxv4uq+vsaEAuRoitv0O0JiPrFXF0a+s0oNl1MlvmWHKNEbLE4CXUaP0KYIUDoYTXOhBiS3EYcvAE4H2HkospaKwBGvQLlExmVLt9gvb4rhWVAFZZpjGh8FhWVTN4gXPVSUDkaVRGU0OxG43ZnFjd/KtGJlVjC5gmjY2mqVT6F7G1QmoFp1EigYkV8u2F+OzC+94yrv0Tiugk1EeE5Orpqciz/W050OeZ+VPo2BkHnUbBk2EgN0sgf9THtyEgdOZ9Ap+zqgnB3a5ixjaI4dsovttCo6A+sQ5EDEeon0cNX3lpcs7316QlZS+ATftheB+f+R+hpVr2tutxnGVU5mpqMtPZSgGUPsCEAUgJmQBqxg6U6SChvswjtmL7UCYCRvqIs5JasUSRy0o/ZaTbVyPB9lfIVDYeNrmV4UuNobB/3rATPXmdt8+S0IHaj95Tqxv955MS6h7zhjm+f1zqSW6T74bh7Xp/LqtuZ5ZE3hVOGkWmxRWDdqp3+lA70DHTYAZxawbB3xIPLkjETk7VWgli5D3NybS3WbcPQokrpWyk7tRA9mJDR5TA7kqTc/XHDM6sPnySCTrrpcu/GvWnXdOE3zUa9x5XE/yuIzr/sFeTyv+Tm2G/pa45pxvx/lBOXPTvD+Q0BdgTNIve6Nc8t+nxPgOfCE43Rz5fmXnGmZsVdtROPpEDxR6tzadhbFCjdnIfUiOZBTiEU5EmATv4xAlw2kgahDo+tPhlm8jnhNBXrUxHKAOcW+q1IM4jLcXVcrWn9+gcmlDVdVofgRQ5giWq7zCMqqqZcy2N1FuyFcgE0uEwIuUC6dynXdCxs64zeZxsseeVo3EiCxQCeB/HakGoQAcC272YyfyQgOTeHpTAJpGXqZNxnTobFrfp9J3fGVcbPpTXaUwftSNGURbwgcGwI4NeDIinavzOxNsJUBZRby0mEw80JtO4gHlAQg+mgA5p9iYgz17aqz58i6GUVkncq6t8V+r6YUd0l6uomA5XVCZ07qWAqk/fk6ZPbkTwxIkJjysnvHuXI6e3wZ6QAbQ2H4bAgyBO7MSPazDDy7womkA6jUwYQSH1ZwIWhs5QeqzvNg+Na63R+nwElKoM0gBYqQV7M0BHzucLZgBb0B1wtdTj+J0+2FF7uSdxzL4fhXNs3t40Y6UB0hw6kQ8TqNUSup5oJQR7VcdCAaSqOpEPVdVyBl3P+cfzJ1dlUZBqygQ+VBRrHfRzJqiWwTLV+nILST8irJxIcqaQWg+5VMTUDykCsUBFdWeOuCWGSmN4HQnlkNoOvYqGeg3kSNA2IXBUshaFc1PiiRCvo/kFpylMKbhKE4Ibs1jJtCX6HGQTJqOHMQ0jvQ6OplgmomqqkOkor6MPNHHqzHSjWdWLsTfdVDWGtBNA5cMoWnmbrqvwqxt1u63SZn0VMm8KS5u9Z43hDd0LVU7EWjeIviKNQWSpos4sMlgpR++td3Tr2WFI0q09zdmCxvFm9ySKw1JPrEDnUPTAz21X9oaxqgLSuV9SkYo9db3gWk5LFaVik0LhIyz5Uw+qPZXM+yvwjRxwB2IHw9kbOaBKV9IoZOUqR6YZ7M60C3hHub1fV2GOqZoWbgOVxK3iWiWwuZ+jBZRZfuKbtE7k/ku0f1XH+mvJp2Z+9pBW2f6PvH4QOOiKm7o4U0fqq1aY67qi1eOWG0J6bufxcTPAHRwpAvZEn3hW6T5Hpvki+p1tH7mX27gQyzxT5T9DQBRIPAREsWrh3A8sSGivIlBjkEyFSHofiRFRU7EbhFMk0Y1ZjM+FuZNbdMQxzVi+EX8mFAq3SqsFLm/GXTSOtveK1SmTeVxcS5nQkeBgT+39SlbSXDoRGnckGad8KuGW5nxSTVBDwAMp/YQ6oNbp8CRTJUzPWOBmOBulde9v39sm1JKsiXizDfSE4+TGGYF+/444N8Cv1FGefLgY7fD0GwrMOjAQ9WTgxD4ejuimICaMKK37eWNoM5BFhhkbuw0d3RuIVUVZHI1Z2XcBgogixkgFZhBcC4Yh8GO2C88gjFHlgtDE2EhhZ9dopZnbQpgcLbCpVvoE6CVXyF0uOLW3MKEXlhFHEFu9GIPYp4JTG5VCtAHUWIdJiELi3FOW7CGIVXdXBzAZRdhFi9qUUfdiYvNLnNPb2yO6NXPKd9Eusqk0BG4g6NrczhTUdbhbNfECmIbHJsda/k1EppPsvkblSa15eeMqzdgVcE1QtmyT0uMEMQpnXKkILjU4XNh2eSLEDJTBo6HfAgrJTfr4VGRzCTZccYWSSF0WF3nzq/J09Ye0LxZSGaE0LyQt3zmrXWnSdcdvKzlHfeLdpRO5f1v5V1Vb1hzWSs0vbbSLt5f20pVZJ2axMshFm0K5196wFm/TPczavEkiemiN+PwTf/B1PeQSvrGPj5V8w3VF3UDcu4fcmYl4ME1d3D+ecU00XcpjfG0jlD5f29plQ/3XRfQeoQXqj3frJMRXUZ3I/edQ7X6gvid69c/Cre3saEFQ+4gT6GU7N9NWd8fAl+/ESV4fy0fKHhS5D4PA1/8MQYW8zedsU9yWFoYQiLduBuESoUS7UAiKhzg5FdLAC4+GwEbeYoSNg43h2CQUKEA6H3gIozZ8z08C3EIEbKHh9iXMg12c1NvJdBcSPZa+BMS81WjJxiv5fqDk7SGv87QgNlVSHXAll22ohG9Buun3YBluNjrfGOOmUZ2V2S5oX0/qkiPBu1F5V1MtLAMj3vtkrgEDU+MKnlkABrrfqh/CeGXVEnPQgdl7QFYDsZsAPMybtLtSkva9eF0eqvqY5u2FGE0aNuk3Fj26LROsP7Ha4J6X2dwLKidBU070rhpxDmq+d8ahm6SGX6ysrnRlKo9rvGoDCnfzcOEmXecDrF+cN6J/zAK3GfVLHMQ1RecZdiw/BeIQJqTFZxe4iqC4cAUT1//SrU26hc4c0T+igEurujGo26jOM+xY5QtEFExIi8+uIxZBcfV+LfZ7UbuXC3gLuBo7wLsWua+sf0WY7iBzYPa5PBn8QqXoabWsaqHFNYr4Kl6UoBlzkWWjBs71+OnO2UYe/jIncTOlt0+YDpV/8bwfpDV94+fsOLW9eN7f+Df80PzZTF2bmd/7cp8VVffri+efT03vx6z/61VW5ffzEC+aMQ9ZdzfpPOhI8/ZwV47zP0WikWRsnm4Sr9N9WqdXxzpvC9U3zbsm++zusuxWatrL7L5m+7eHj6f66VQ3KmePXwtpdvniOc3/xXNN5hf97vPKhQqNmHmjQvbx8PKUF/tJ7tdpUSkzamyI68b6b7Lm996XzcNZZ/d/TyN9KA/MgQbzvcqessO+eejGq9Wrj4eb9Fu2RLYvVfYuu093f39qS2Z3C0/YIGZHyGZ/8SpP74/pYzWMMfdv/mwwvH/863//HwZWraTfMAgA + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 4d60239cc6..c34ecbb4e8 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -116,6 +116,7 @@ Properties\AssemblyVersionInfo.cs + @@ -281,6 +282,10 @@ 201506211043073_PaymentShippingRestrictions.cs + + + 201506262044329_QueuedEmailAttachments.cs + @@ -544,6 +549,9 @@ 201506211043073_PaymentShippingRestrictions.cs + + 201506262044329_QueuedEmailAttachments.cs + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs index 7426f8e60f..b7ffea3206 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs @@ -188,7 +188,9 @@ public ActionResult SendTestEmail(EmailAccountModel model) string subject = _storeContext.CurrentStore.Name + ". Testing email functionality."; string body = "Email works fine."; - _emailSender.SendEmail(new SmtpContext(emailAccount), new EmailMessage(to, subject, body, from)); + var msg = new EmailMessage(to, subject, body, from); + + _emailSender.SendEmail(new SmtpContext(emailAccount), msg); NotifySuccess(_localizationService.GetResource("Admin.Configuration.EmailAccounts.SendTestEmail.Success"), false); } From 6a1bf36ee35b9820cf4a91dc1b90b56c153c4054 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Mon, 29 Jun 2015 20:01:31 +0200 Subject: [PATCH 0031/1074] Revert "E-mail attachments: added entity & map" This reverts commit db0f0e5ff24bfe38fbe90ae968b94811bc772a92. --- .../EmailAttachmentStorageLocation.cs | 22 --- .../Domain/Messages/QueuedEmail.cs | 14 +- .../Domain/Messages/QueuedEmailAttachment.cs | 66 --------- .../SmartStore.Core/SmartStore.Core.csproj | 2 - .../Messages/QueuedEmailAttachmentMap.cs | 34 ----- ...2044329_QueuedEmailAttachments.Designer.cs | 29 ---- .../201506262044329_QueuedEmailAttachments.cs | 40 ------ ...01506262044329_QueuedEmailAttachments.resx | 126 ------------------ .../SmartStore.Data/SmartStore.Data.csproj | 8 -- .../Controllers/EmailAccountController.cs | 4 +- 10 files changed, 2 insertions(+), 343 deletions(-) delete mode 100644 src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs delete mode 100644 src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs delete mode 100644 src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.Designer.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.resx diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs deleted file mode 100644 index dc5f240370..0000000000 --- a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace SmartStore.Core.Domain.Messages -{ - public enum EmailAttachmentStorageLocation - { - /// - /// Attachment is embedded as Blob - /// - Blob, - - /// - /// Attachment is a reference to - /// - FileReference, - - /// - /// Attachment is located on disk (physical or virtual path) - /// - Path - } -} diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs index f04ae054ea..573231b382 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace SmartStore.Core.Domain.Messages { @@ -8,9 +7,7 @@ namespace SmartStore.Core.Domain.Messages /// public partial class QueuedEmail : BaseEntity { - private ICollection _attachments; - - /// + /// /// Gets or sets the priority /// public int Priority { get; set; } @@ -94,14 +91,5 @@ public partial class QueuedEmail : BaseEntity /// Gets the email account /// public virtual EmailAccount EmailAccount { get; set; } - - /// - /// Gets or sets the collection of attachments - /// - public virtual ICollection Attachments - { - get { return _attachments ?? (_attachments = new HashSet()); } - protected set { _attachments = value; } - } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs deleted file mode 100644 index c0f6978143..0000000000 --- a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SmartStore.Core.Domain.Media; - -namespace SmartStore.Core.Domain.Messages -{ - /// - /// Reperesents an e-mail attachment - /// - public partial class QueuedEmailAttachment : BaseEntity - { - - /// - /// Gets or sets the queued email identifier - /// - public int QueuedEmailId { get; set; } - - /// - /// Gets or sets the queued email entity instance - /// - public virtual QueuedEmail QueuedEmail { get; set; } - - /// - /// Gets or sets the storage location - /// - public EmailAttachmentStorageLocation StorageLocation { get; set; } - - /// - /// A physical or virtual path to the file (only applicable if location is Path) - /// - public string Path { get; set; } - - /// - /// The id of a record (only applicable if location is FileReference) - /// - public int? FileId { get; set; } - - /// - /// Gets the file object - /// - /// - /// This property is not named Download on purpose, because we're going to rename Download to File in a future release. - /// - public virtual Download File { get; set; } - - /// - /// The attachment's binary data (only applicable if location is Blob) - /// - public byte[] Data { get; set; } - - /// - /// The attachment file name (without path) - /// - public string Name { get; set; } - - /// - /// The attachment file's mime type, e.g. - /// - public string MimeType { get; set; } - - } - -} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 4251026394..fa13b5e483 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -158,8 +158,6 @@ - - diff --git a/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs b/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs deleted file mode 100644 index 8b654b17d8..0000000000 --- a/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity.ModelConfiguration; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SmartStore.Core.Domain.Messages; - -namespace SmartStore.Data.Mapping.Messages -{ - public class QueuedEmailAttachmentMap : EntityTypeConfiguration - { - public QueuedEmailAttachmentMap() - { - this.ToTable("QueuedEmailAttachment"); - this.HasKey(x => x.Id); - - this.Property(x => x.Path).IsOptional().HasMaxLength(1000); - this.Property(x => x.Data).IsMaxLength(); - this.HasOptional(x => x.File) - .WithMany() - .HasForeignKey(x => x.FileId) - .WillCascadeOnDelete(true); - - this.Property(x => x.Name).IsRequired().HasMaxLength(200); - this.Property(x => x.MimeType).IsRequired().HasMaxLength(200); - - this.HasRequired(x => x.QueuedEmail) - .WithMany(qe => qe.Attachments) - .HasForeignKey(x => x.QueuedEmailId) - .WillCascadeOnDelete(true); - } - } -} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.Designer.cs deleted file mode 100644 index 96a93d428d..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.Designer.cs +++ /dev/null @@ -1,29 +0,0 @@ -// -namespace SmartStore.Data.Migrations -{ - using System.CodeDom.Compiler; - using System.Data.Entity.Migrations; - using System.Data.Entity.Migrations.Infrastructure; - using System.Resources; - - [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] - public sealed partial class QueuedEmailAttachments : IMigrationMetadata - { - private readonly ResourceManager Resources = new ResourceManager(typeof(QueuedEmailAttachments)); - - string IMigrationMetadata.Id - { - get { return "201506262044329_QueuedEmailAttachments"; } - } - - string IMigrationMetadata.Source - { - get { return null; } - } - - string IMigrationMetadata.Target - { - get { return Resources.GetString("Target"); } - } - } -} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs deleted file mode 100644 index 18c4da66ae..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace SmartStore.Data.Migrations -{ - using System; - using System.Data.Entity.Migrations; - - public partial class QueuedEmailAttachments : DbMigration - { - public override void Up() - { - CreateTable( - "dbo.QueuedEmailAttachment", - c => new - { - Id = c.Int(nullable: false, identity: true), - QueuedEmailId = c.Int(nullable: false), - StorageLocation = c.Int(nullable: false), - Path = c.String(maxLength: 1000), - FileId = c.Int(), - Data = c.Binary(), - Name = c.String(nullable: false, maxLength: 200), - MimeType = c.String(nullable: false, maxLength: 200), - }) - .PrimaryKey(t => t.Id) - .ForeignKey("dbo.Download", t => t.FileId, cascadeDelete: true) - .ForeignKey("dbo.QueuedEmail", t => t.QueuedEmailId, cascadeDelete: true) - .Index(t => t.QueuedEmailId) - .Index(t => t.FileId); - - } - - public override void Down() - { - DropForeignKey("dbo.QueuedEmailAttachment", "QueuedEmailId", "dbo.QueuedEmail"); - DropForeignKey("dbo.QueuedEmailAttachment", "FileId", "dbo.Download"); - DropIndex("dbo.QueuedEmailAttachment", new[] { "FileId" }); - DropIndex("dbo.QueuedEmailAttachment", new[] { "QueuedEmailId" }); - DropTable("dbo.QueuedEmailAttachment"); - } - } -} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.resx b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.resx deleted file mode 100644 index f2ec5c9c8a..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index c34ecbb4e8..4d60239cc6 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -116,7 +116,6 @@ Properties\AssemblyVersionInfo.cs - @@ -282,10 +281,6 @@ 201506211043073_PaymentShippingRestrictions.cs - - - 201506262044329_QueuedEmailAttachments.cs - @@ -549,9 +544,6 @@ 201506211043073_PaymentShippingRestrictions.cs - - 201506262044329_QueuedEmailAttachments.cs - diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs index b7ffea3206..7426f8e60f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs @@ -188,9 +188,7 @@ public ActionResult SendTestEmail(EmailAccountModel model) string subject = _storeContext.CurrentStore.Name + ". Testing email functionality."; string body = "Email works fine."; - var msg = new EmailMessage(to, subject, body, from); - - _emailSender.SendEmail(new SmtpContext(emailAccount), msg); + _emailSender.SendEmail(new SmtpContext(emailAccount), new EmailMessage(to, subject, body, from)); NotifySuccess(_localizationService.GetResource("Admin.Configuration.EmailAccounts.SendTestEmail.Success"), false); } From 91734c63e7068dfdbef454f96d10b4b8994343d8 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 30 Jun 2015 00:42:56 +0200 Subject: [PATCH 0032/1074] E-mail attachments: convert QueuedEmail > EmailMessage --- .../Email/DefaultEmailSender.cs | 9 +- .../Messages/QueuedEmailService.cs | 55 +++++++++++ .../Messages/QueuedEmailPersistenceTests.cs | 95 ++++++++++++++++++- 3 files changed, 147 insertions(+), 12 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs b/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs index d519fb2239..42f9b99eec 100644 --- a/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs +++ b/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs @@ -14,10 +14,6 @@ namespace SmartStore.Core.Email public class DefaultEmailSender : IEmailSender { - public DefaultEmailSender() - { - } - /// /// Builds System.Net.Mail.Message /// @@ -54,10 +50,7 @@ protected virtual MailMessage BuildMailMessage(EmailMessage original) msg.Bcc.AddRange(original.Bcc.Where(x => x.Address.HasValue()).Select(x => x.ToMailAddress())); msg.ReplyToList.AddRange(original.ReplyTo.Where(x => x.Address.HasValue()).Select(x => x.ToMailAddress())); - foreach (var attachment in original.Attachments) - { - msg.Attachments.Add(attachment); - } + msg.Attachments.AddRange(original.Attachments); if (original.Headers != null) msg.Headers.AddRange(original.Headers); diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 4a504d5f62..78fe190196 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Mail; +using System.IO; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Messages; @@ -8,6 +10,8 @@ using SmartStore.Core.Events; using SmartStore.Core.Logging; using SmartStore.Services.Localization; +using SmartStore.Utilities; +using System.Web; namespace SmartStore.Services.Messages { @@ -177,6 +181,8 @@ public virtual bool SendEmail(QueuedEmail queuedEmail) msg.Bcc.AddRange(bcc.Where(x => x.HasValue()).Select(x => new EmailAddress(x))); } + CreateAttachments(queuedEmail, msg); + _emailSender.SendEmail(smtpContext, msg); queuedEmail.SentOnUtc = DateTime.UtcNow; @@ -191,7 +197,56 @@ public virtual bool SendEmail(QueuedEmail queuedEmail) queuedEmail.SentTries = queuedEmail.SentTries + 1; UpdateQueuedEmail(queuedEmail); } + return result; } + + private void CreateAttachments(QueuedEmail qe, EmailMessage msg) + { + if (qe.Attachments == null || qe.Attachments.Count == 0) + return; + + foreach (var qea in qe.Attachments) + { + Attachment attachment = null; + + if (qea.StorageLocation == EmailAttachmentStorageLocation.Blob) + { + var data = qea.Data; + if (data != null && data.Length > 0) + { + attachment = new Attachment(data.ToStream(), qea.Name, qea.MimeType); + } + } + else if (qea.StorageLocation == EmailAttachmentStorageLocation.Path) + { + var path = qea.Path; + if (path.HasValue()) + { + if (path[0] == '~' || path[0] == '/') + { + path = CommonHelper.MapPath(VirtualPathUtility.ToAppRelative(path)); + } + if (File.Exists(path)) + { + attachment = new Attachment(path, qea.MimeType); + } + } + } + else if (qea.StorageLocation == EmailAttachmentStorageLocation.FileReference) + { + var file = qea.File; + if (file != null && file.UseDownloadUrl == false && file.DownloadBinary != null && file.DownloadBinary.Length > 0) + { + attachment = new Attachment(file.DownloadBinary.ToStream(), file.Filename + file.Extension, file.ContentType); + } + } + + if (attachment != null) + { + msg.Attachments.Add(attachment); + } + } + } } } diff --git a/src/Tests/SmartStore.Data.Tests/Messages/QueuedEmailPersistenceTests.cs b/src/Tests/SmartStore.Data.Tests/Messages/QueuedEmailPersistenceTests.cs index 66e5261771..0228d4c3f1 100644 --- a/src/Tests/SmartStore.Data.Tests/Messages/QueuedEmailPersistenceTests.cs +++ b/src/Tests/SmartStore.Data.Tests/Messages/QueuedEmailPersistenceTests.cs @@ -1,7 +1,10 @@ using System; +using System.Collections.Generic; +using System.Linq; using SmartStore.Core.Domain.Messages; using SmartStore.Tests; using NUnit.Framework; +using SmartStore.Core.Domain.Media; namespace SmartStore.Data.Tests.Messages { @@ -11,7 +14,7 @@ public class QueuedEmailPersistenceTests : PersistenceTest [Test] public void Can_save_and_load_queuedEmail() { - var qe = new QueuedEmail() + var qe = new QueuedEmail { Priority = 1, From = "From", @@ -35,11 +38,9 @@ public void Can_save_and_load_queuedEmail() Password = "111", EnableSsl = true, UseDefaultCredentials = true - } - + }, }; - var fromDb = SaveAndLoadEntity(qe); fromDb.ShouldNotBeNull(); fromDb.Priority.ShouldEqual(1); @@ -58,5 +59,91 @@ public void Can_save_and_load_queuedEmail() fromDb.EmailAccount.ShouldNotBeNull(); fromDb.EmailAccount.DisplayName.ShouldEqual("Administrator"); } + + [Test] + public void Can_cascade_delete_attachment() + { + var account = new EmailAccount + { + Email = "admin@yourstore.com", + Host = "127.0.0.1", + Username = "John", + Password = "111" + }; + + var download = new Download + { + ContentType = "text/plain", + DownloadBinary = new byte[10], + DownloadGuid = Guid.NewGuid(), + Extension = "txt", + Filename = "file" + }; + + // add attachment + var attach = new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.FileReference, + Name = "file.txt", + MimeType = "text/plain", + File = download + }; + + var qe = new QueuedEmail + { + Priority = 1, + From = "From", + To = "To", + Subject = "Subject", + CreatedOnUtc = DateTime.UtcNow, + EmailAccount = account + }; + + qe.Attachments.Add(attach); + + var fromDb = SaveAndLoadEntity(qe); + fromDb.ShouldNotBeNull(); + + Assert.AreEqual(fromDb.Attachments.Count, 1); + attach = fromDb.Attachments.FirstOrDefault(); + attach.ShouldNotBeNull(); + + download = attach.File; + download.ShouldNotBeNull(); + + var attachId = attach.Id; + var downloadId = download.Id; + + // delete Attachment.Download + context.Set().Remove(download); + context.SaveChanges(); + base.ReloadContext(); + + attach = context.Set().Find(attachId); + attach.ShouldBeNull(); + + // add new attachment + attach = new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.FileReference, + Name = "file.txt", + MimeType = "text/plain" + }; + + qe = context.Set().FirstOrDefault(); + qe.Attachments.Add(attach); + + fromDb = SaveAndLoadEntity(qe); + fromDb.ShouldNotBeNull(); + + // delete QueuedEmail + context.Set().Remove(fromDb); + context.SaveChanges(); + base.ReloadContext(); + + // Attachment should also be gone now + attach = context.Set().FirstOrDefault(); + attach.ShouldBeNull(); + } } } \ No newline at end of file From e85a366bd13caf211b58bd6802633058c9ff1b08 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 26 Jun 2015 13:42:23 +0200 Subject: [PATCH 0033/1074] Primary store currency and exchange rate currency on store entity --- .../SmartStore.Core/Domain/Stores/Store.cs | 27 ++++ .../Mapping/Stores/StoreMap.cs | 8 ++ .../201506261018157_Merge.Designer.cs | 29 ++++ .../Migrations/201506261018157_Merge.cs | 16 +++ .../Migrations/201506261018157_Merge.resx | 126 ++++++++++++++++++ ...PrimaryStoreCurrencyMultiStore.Designer.cs | 29 ++++ ...61028198_PrimaryStoreCurrencyMultiStore.cs | 68 ++++++++++ ...028198_PrimaryStoreCurrencyMultiStore.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 14 ++ 9 files changed, 443 insertions(+) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.resx create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.resx diff --git a/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs b/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs index 0b5c7e30b2..597198913e 100644 --- a/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs +++ b/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs @@ -1,4 +1,5 @@ using System.Runtime.Serialization; +using SmartStore.Core.Domain.Directory; namespace SmartStore.Core.Domain.Stores { @@ -59,8 +60,34 @@ public partial class Store : BaseEntity /// /// Gets or sets the CDN host name, if static media content should be served through a CDN. /// + [DataMember] public string ContentDeliveryNetwork { get; set; } + /// + /// Gets or sets the primary store currency identifier + /// + [DataMember] + public int? PrimaryStoreCurrencyId { get; set; } + + /// + /// Gets or sets the primary exchange rate currency identifier + /// + [DataMember] + public int? PrimaryExchangeRateCurrencyId { get; set; } + + /// + /// Gets or sets the primary store currency + /// + [DataMember] + public virtual Currency PrimaryStoreCurrency { get; set; } + + /// + /// Gets or sets the primary exchange rate currency + /// + [DataMember] + public virtual Currency PrimaryExchangeRateCurrency { get; set; } + + /// /// Gets the security mode for the store /// diff --git a/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs b/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs index 486167b3a6..4203d1a743 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs @@ -14,6 +14,14 @@ public StoreMap() this.Property(s => s.ContentDeliveryNetwork).HasMaxLength(400); this.Property(s => s.SecureUrl).HasMaxLength(400); this.Property(s => s.Hosts).HasMaxLength(1000); + + this.HasOptional(s => s.PrimaryStoreCurrency) + .WithMany() + .HasForeignKey(s => s.PrimaryStoreCurrencyId).WillCascadeOnDelete(false); + + this.HasOptional(s => s.PrimaryExchangeRateCurrency) + .WithMany() + .HasForeignKey(s => s.PrimaryExchangeRateCurrencyId).WillCascadeOnDelete(false); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.Designer.cs new file mode 100644 index 0000000000..8d36b523ab --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class Merge : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(Merge)); + + string IMigrationMetadata.Id + { + get { return "201506261018157_Merge"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.cs b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.cs new file mode 100644 index 0000000000..d5201b31f3 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.cs @@ -0,0 +1,16 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class Merge : DbMigration + { + public override void Up() + { + } + + public override void Down() + { + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.resx b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.resx new file mode 100644 index 0000000000..01a895415e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.Designer.cs new file mode 100644 index 0000000000..26e9e30860 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class PrimaryStoreCurrencyMultiStore : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(PrimaryStoreCurrencyMultiStore)); + + string IMigrationMetadata.Id + { + get { return "201506261028198_PrimaryStoreCurrencyMultiStore"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.cs new file mode 100644 index 0000000000..02f5cc517f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.cs @@ -0,0 +1,68 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Linq; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Configuration; + using SmartStore.Data.Setup; + using SmartStore.Core.Domain.Stores; + + public partial class PrimaryStoreCurrencyMultiStore : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Store", "PrimaryStoreCurrencyId", c => c.Int()); + AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int()); + CreateIndex("dbo.Store", "PrimaryStoreCurrencyId"); + CreateIndex("dbo.Store", "PrimaryExchangeRateCurrencyId"); + AddForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency", "Id"); + AddForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency", "Id"); + } + + public override void Down() + { + DropForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency"); + DropForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency"); + DropIndex("dbo.Store", new[] { "PrimaryExchangeRateCurrencyId" }); + DropIndex("dbo.Store", new[] { "PrimaryStoreCurrencyId" }); + DropColumn("dbo.Store", "PrimaryExchangeRateCurrencyId"); + DropColumn("dbo.Store", "PrimaryStoreCurrencyId"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var settings = context.Set(); + var primaryStoreCurrency = settings.FirstOrDefault(x => x.Name == "CurrencySettings.PrimaryStoreCurrencyId"); + var primaryExchangeRateCurrency = settings.FirstOrDefault(x => x.Name == "CurrencySettings.PrimaryExchangeRateCurrencyId"); + + var stores = context.Set().ToList(); + + foreach (var store in stores) + { + int id = primaryStoreCurrency.Value.ToInt(); + if (id != 0) + store.PrimaryStoreCurrencyId = id; + + id = primaryExchangeRateCurrency.Value.ToInt(); + if (id != 0) + store.PrimaryExchangeRateCurrencyId = id; + } + + settings.Remove(primaryStoreCurrency); + settings.Remove(primaryExchangeRateCurrency); + + context.SaveChanges(); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.resx b/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.resx new file mode 100644 index 0000000000..b90afc9625 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 4d60239cc6..962e995619 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -281,6 +281,14 @@ 201506211043073_PaymentShippingRestrictions.cs + + + 201506261018157_Merge.cs + + + + 201506261028198_PrimaryStoreCurrencyMultiStore.cs + @@ -544,6 +552,12 @@ 201506211043073_PaymentShippingRestrictions.cs + + 201506261018157_Merge.cs + + + 201506261028198_PrimaryStoreCurrencyMultiStore.cs + From f8279ef623e2dd3d9742c6aa5d5b5e618be6b334 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 27 Jun 2015 11:10:17 +0200 Subject: [PATCH 0034/1074] Refactored and removed CurrencySettings.PrimaryStoreCurrencyId --- .../Domain/Directory/CurrencySettings.cs | 4 +- .../SmartStore.Core/Domain/Stores/Store.cs | 4 +- .../Mapping/Stores/StoreMap.cs | 4 +- ...028198_PrimaryStoreCurrencyMultiStore.resx | 126 ---- ...rimaryStoreCurrencyMultiStore.Designer.cs} | 2 +- ...1756463_PrimaryStoreCurrencyMultiStore.cs} | 9 +- ...756463_PrimaryStoreCurrencyMultiStore.resx | 126 ++++ .../Setup/SeedData/InvariantSeedData.cs | 10 +- .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../Directory/CurrencyService.cs | 15 +- .../Directory/ICurrencyService.cs | 7 +- .../Orders/OrderProcessingService.cs | 4 +- .../FroogleFeedPlugin.cs | 22 +- .../Services/GoogleFeedService.cs | 12 +- .../Controllers/PayPalExpressController.cs | 11 +- .../Providers/PayPalDirectProvider.cs | 26 +- .../Providers/PayPalExpressProvider.cs | 56 +- .../Providers/PayPalProviderBase.cs | 14 +- .../Providers/PayPalStandardProvider.cs | 11 +- .../Controllers/ByTotalController.cs | 46 +- .../Controllers/ShippingByWeightController.cs | 74 +-- .../Plugins/PluginHelper.cs | 26 - .../WebWorkContext.cs | 27 +- .../CheckoutAttributeController.cs | 77 +-- .../Controllers/CommonController.cs | 2 +- .../Controllers/CurrencyController.cs | 86 +-- .../Controllers/DiscountController.cs | 84 ++- .../Controllers/GiftCardController.cs | 75 +-- .../Controllers/OrderController.cs | 2 +- .../Controllers/ProductController.cs | 4 +- .../Controllers/SettingController.cs | 600 +++++++++--------- .../Controllers/CatalogHelper.cs | 8 +- .../Installation/DeDESeedData.cs | 1 - .../Installation/InstallDataSeeder.cs | 2 +- .../Catalog/PriceFormatterTests.cs | 5 +- .../Directory/CurrencyServiceTests.cs | 10 +- 36 files changed, 765 insertions(+), 837 deletions(-) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.resx rename src/Libraries/SmartStore.Data/Migrations/{201506261028198_PrimaryStoreCurrencyMultiStore.Designer.cs => 201506261756463_PrimaryStoreCurrencyMultiStore.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201506261028198_PrimaryStoreCurrencyMultiStore.cs => 201506261756463_PrimaryStoreCurrencyMultiStore.cs} (97%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.resx diff --git a/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs b/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs index d1c807b4a6..77caffa2b6 100644 --- a/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs @@ -1,11 +1,9 @@ - -using SmartStore.Core.Configuration; +using SmartStore.Core.Configuration; namespace SmartStore.Core.Domain.Directory { public class CurrencySettings : ISettings { - public int PrimaryStoreCurrencyId { get; set; } public int PrimaryExchangeRateCurrencyId { get; set; } public string ActiveExchangeRateProviderSystemName { get; set; } public bool AutoUpdateEnabled { get; set; } diff --git a/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs b/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs index 597198913e..0d9fe6be96 100644 --- a/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs +++ b/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs @@ -67,13 +67,13 @@ public partial class Store : BaseEntity /// Gets or sets the primary store currency identifier /// [DataMember] - public int? PrimaryStoreCurrencyId { get; set; } + public int PrimaryStoreCurrencyId { get; set; } /// /// Gets or sets the primary exchange rate currency identifier /// [DataMember] - public int? PrimaryExchangeRateCurrencyId { get; set; } + public int PrimaryExchangeRateCurrencyId { get; set; } /// /// Gets or sets the primary store currency diff --git a/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs b/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs index 4203d1a743..bc204d80e9 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs @@ -15,11 +15,11 @@ public StoreMap() this.Property(s => s.SecureUrl).HasMaxLength(400); this.Property(s => s.Hosts).HasMaxLength(1000); - this.HasOptional(s => s.PrimaryStoreCurrency) + this.HasRequired(s => s.PrimaryStoreCurrency) .WithMany() .HasForeignKey(s => s.PrimaryStoreCurrencyId).WillCascadeOnDelete(false); - this.HasOptional(s => s.PrimaryExchangeRateCurrency) + this.HasRequired(s => s.PrimaryExchangeRateCurrency) .WithMany() .HasForeignKey(s => s.PrimaryExchangeRateCurrencyId).WillCascadeOnDelete(false); } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.resx b/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.resx deleted file mode 100644 index b90afc9625..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.Designer.cs index 26e9e30860..11aadff013 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class PrimaryStoreCurrencyMultiStore : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201506261028198_PrimaryStoreCurrencyMultiStore"; } + get { return "201506261756463_PrimaryStoreCurrencyMultiStore"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs similarity index 97% rename from src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.cs rename to src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index 02f5cc517f..ed33800321 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261028198_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -1,18 +1,17 @@ namespace SmartStore.Data.Migrations { - using System; - using System.Linq; using System.Data.Entity.Migrations; + using System.Linq; using SmartStore.Core.Domain.Configuration; - using SmartStore.Data.Setup; using SmartStore.Core.Domain.Stores; + using SmartStore.Data.Setup; public partial class PrimaryStoreCurrencyMultiStore : DbMigration, ILocaleResourcesProvider, IDataSeeder { public override void Up() { - AddColumn("dbo.Store", "PrimaryStoreCurrencyId", c => c.Int()); - AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int()); + AddColumn("dbo.Store", "PrimaryStoreCurrencyId", c => c.Int(nullable: false)); + AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int(nullable: false)); CreateIndex("dbo.Store", "PrimaryStoreCurrencyId"); CreateIndex("dbo.Store", "PrimaryExchangeRateCurrencyId"); AddForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency", "Id"); diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.resx b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.resx new file mode 100644 index 0000000000..7e45cc22c4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs index d6f664d19d..970ba62e41 100644 --- a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs +++ b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs @@ -73,6 +73,10 @@ public IList Stores() var seName = GetSeName("company-logo"); var imgCompanyLogo = _ctx.Set().Where(x => x.SeoFilename == seName).FirstOrDefault(); + var currency = _ctx.Set().FirstOrDefault(x => x.CurrencyCode == "EUR"); + if (currency == null) + currency = _ctx.Set().First(); + var entities = new List() { new Store() @@ -82,7 +86,9 @@ public IList Stores() Hosts = "yourstore.com,www.yourstore.com", SslEnabled = false, DisplayOrder = 1, - LogoPictureId = imgCompanyLogo.Id + LogoPictureId = imgCompanyLogo.Id, + PrimaryStoreCurrencyId = currency.Id, + PrimaryExchangeRateCurrencyId = currency.Id } }; this.Alter(entities); @@ -4244,8 +4250,6 @@ public IList Settings() }, new CurrencySettings() { - PrimaryStoreCurrencyId = _ctx.Set().First().Id, - PrimaryExchangeRateCurrencyId = _ctx.Set().First().Id, }, new MeasureSettings() { diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 962e995619..1d9b57ac77 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -285,9 +285,9 @@ 201506261018157_Merge.cs - - - 201506261028198_PrimaryStoreCurrencyMultiStore.cs + + + 201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -555,8 +555,8 @@ 201506261018157_Merge.cs - - 201506261028198_PrimaryStoreCurrencyMultiStore.cs + + 201506261756463_PrimaryStoreCurrencyMultiStore.cs diff --git a/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs b/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs index 6b436fd14d..25fcf7762c 100644 --- a/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs +++ b/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs @@ -33,6 +33,7 @@ public partial class CurrencyService : ICurrencyService private readonly IPluginFinder _pluginFinder; private readonly IEventPublisher _eventPublisher; private readonly IProviderManager _providerManager; + private readonly IStoreContext _storeContext; #endregion @@ -53,7 +54,8 @@ public CurrencyService(ICacheManager cacheManager, CurrencySettings currencySettings, IPluginFinder pluginFinder, IEventPublisher eventPublisher, - IProviderManager providerManager) + IProviderManager providerManager, + IStoreContext storeContext) { this._cacheManager = cacheManager; this._currencyRepository = currencyRepository; @@ -62,6 +64,7 @@ public CurrencyService(ICacheManager cacheManager, this._pluginFinder = pluginFinder; this._eventPublisher = eventPublisher; this._providerManager = providerManager; + this._storeContext = storeContext; } #endregion @@ -268,11 +271,13 @@ public virtual decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Cu /// /// Amount /// Source currency code + /// Store to get the primary store currency from /// Converted value - public virtual decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency sourceCurrencyCode) + public virtual decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency sourceCurrencyCode, Store store = null) { decimal result = amount; - var primaryStoreCurrency = GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var primaryStoreCurrency = (store == null ? _storeContext.CurrentStore.PrimaryStoreCurrency : store.PrimaryStoreCurrency); + if (result != decimal.Zero && sourceCurrencyCode.Id != primaryStoreCurrency.Id) { decimal exchangeRate = sourceCurrencyCode.Rate; @@ -289,10 +294,10 @@ public virtual decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency so /// Amount /// Target currency code /// Converted value - public virtual decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency targetCurrencyCode) + public virtual decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency targetCurrencyCode, Store store = null) { decimal result = amount; - var primaryStoreCurrency = GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var primaryStoreCurrency = (store == null ? _storeContext.CurrentStore.PrimaryStoreCurrency : store.PrimaryStoreCurrency); result = ConvertCurrency(amount, primaryStoreCurrency, targetCurrencyCode); return result; } diff --git a/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs b/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs index b1481d03f3..f7285a3ecf 100644 --- a/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs +++ b/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Stores; using SmartStore.Core.Plugins; namespace SmartStore.Services.Directory @@ -96,16 +97,18 @@ public partial interface ICurrencyService /// /// Amount /// Source currency code + /// Store to get the primary store currency from /// Converted value - decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency sourceCurrencyCode); + decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency sourceCurrencyCode, Store store = null); /// /// Converts from primary store currency /// /// Amount /// Target currency code + /// Store to get the primary store currency from /// Converted value - decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency targetCurrencyCode); + decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency targetCurrencyCode, Store store = null); diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index a1b07c3749..e7179516c0 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -521,7 +521,9 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR var currencyTmp = _currencyService.GetCurrencyById(customer.GetAttribute(SystemCustomerAttributeNames.CurrencyId, processPaymentRequest.StoreId)); var customerCurrency = (currencyTmp != null && currencyTmp.Published) ? currencyTmp : _workContext.WorkingCurrency; customerCurrencyCode = customerCurrency.CurrencyCode; - var primaryStoreCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + + var primaryStoreCurrency = _storeContext.CurrentStore.PrimaryStoreCurrency; + customerCurrencyRate = customerCurrency.Rate / primaryStoreCurrency.Rate; } else diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/FroogleFeedPlugin.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/FroogleFeedPlugin.cs index 478cd9cd2d..a4f5d4d476 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/FroogleFeedPlugin.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/FroogleFeedPlugin.cs @@ -3,25 +3,21 @@ using SmartStore.Core.Plugins; using SmartStore.GoogleMerchantCenter.Data.Migrations; using SmartStore.GoogleMerchantCenter.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; +using SmartStore.Services; namespace SmartStore.GoogleMerchantCenter { public class FroogleFeedPlugin : BasePlugin, IConfigurable { private readonly IGoogleFeedService _googleService; - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; + private readonly ICommonServices _services; public FroogleFeedPlugin( IGoogleFeedService googleService, - ISettingService settingService, - ILocalizationService localizationService) + ICommonServices services) { _googleService = googleService; - _settingService = settingService; - _localizationService = localizationService; + _services = services; } /// @@ -43,11 +39,11 @@ public void GetConfigurationRoute(out string actionName, out string controllerNa public override void Install() { var settings = new FroogleSettings(); - settings.CurrencyId = _googleService.Helper.CurrencyID; + settings.CurrencyId = _services.StoreContext.CurrentStore.PrimaryStoreCurrencyId; - _settingService.SaveSetting(settings); + _services.Settings.SaveSetting(settings); - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); + _services.Localization.ImportPluginResourcesFromXml(this.PluginDescriptor); _googleService.Helper.InsertScheduleTask(); @@ -62,9 +58,9 @@ public override void Uninstall() _googleService.Helper.DeleteFeedFiles(); _googleService.Helper.DeleteScheduleTask(); - _settingService.DeleteSetting(); + _services.Settings.DeleteSetting(); - _localizationService.DeleteLocaleStringResources(PluginDescriptor.ResourceRootKey); + _services.Localization.DeleteLocaleStringResources(PluginDescriptor.ResourceRootKey); var migrator = new DbMigrator(new Configuration()); migrator.Update(DbMigrator.InitialDatabase); diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs index c0e67eff5a..de92f5e59b 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs @@ -14,6 +14,7 @@ using SmartStore.Core.Logging; using SmartStore.GoogleMerchantCenter.Domain; using SmartStore.GoogleMerchantCenter.Models; +using SmartStore.Services; using SmartStore.Services.Catalog; using SmartStore.Services.Directory; using SmartStore.Services.Localization; @@ -35,6 +36,8 @@ public partial class GoogleFeedService : IGoogleFeedService private readonly MeasureSettings _measureSettings; private readonly IDbContext _dbContext; private readonly AdminAreaSettings _adminAreaSettings; + private readonly ICurrencyService _currencyService; + private readonly ICommonServices _services; public GoogleFeedService( IRepository gpRepository, @@ -45,6 +48,8 @@ public GoogleFeedService( MeasureSettings measureSettings, IDbContext dbContext, AdminAreaSettings adminAreaSettings, + ICurrencyService currencyService, + ICommonServices services, IComponentContext ctx) { _gpRepository = gpRepository; @@ -55,6 +60,8 @@ public GoogleFeedService( _measureSettings = measureSettings; _dbContext = dbContext; _adminAreaSettings = adminAreaSettings; + _currencyService = currencyService; + _services = services; _helper = new FeedPluginHelper(ctx, "SmartStore.GoogleMerchantCenter", "SmartStore.GoogleMerchantCenter", () => { @@ -690,9 +697,12 @@ private void CreateFeed(FeedFileCreationContext fileCreation, TaskExecutionConte VisibleIndividuallyOnly = true }; - var currency = Helper.GetUsedCurrency(Settings.CurrencyId); + var currency = _currencyService.GetCurrencyById(Settings.CurrencyId); var measureWeightSystemKey = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).SystemKeyword; + if (currency == null || !currency.Published) + currency = _services.WorkContext.WorkingCurrency; + writer.WriteStartDocument(); writer.WriteStartElement("rss"); writer.WriteAttributeString("version", "2.0"); diff --git a/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs b/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs index b3af94a0b9..0318a9e097 100644 --- a/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs +++ b/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs @@ -364,13 +364,14 @@ public ActionResult SubmitButton() if ((_services.WorkContext.CurrentCustomer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed)) return RedirectToRoute("Login"); - var settings = _services.Settings.LoadSetting(_services.StoreContext.CurrentStore.Id); - var cart = _services.WorkContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, _services.StoreContext.CurrentStore.Id); + var store = _services.StoreContext.CurrentStore; + var settings = _services.Settings.LoadSetting(store.Id); + var cart = _services.WorkContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, store.Id); if (cart.Count == 0) return RedirectToRoute("ShoppingCart"); - var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + var currency = store.PrimaryStoreCurrency.CurrencyCode; if (String.IsNullOrEmpty(settings.ApiAccountName)) throw new ApplicationException("PayPal API Account Name is not set"); @@ -393,9 +394,9 @@ public ActionResult SubmitButton() Discount orderSubTotalAppliedDiscount = null; decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; + _orderTotalCalculationService.GetShoppingCartSubTotal(cart, - out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount, - out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); + out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); //order total decimal resultTemp = decimal.Zero; diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalDirectProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalDirectProvider.cs index 1227e36887..ec49fe64e7 100644 --- a/src/Plugins/SmartStore.PayPal/Providers/PayPalDirectProvider.cs +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalDirectProvider.cs @@ -3,16 +3,13 @@ using Autofac; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Plugins; using SmartStore.PayPal.Controllers; using SmartStore.PayPal.PayPalSvc; using SmartStore.PayPal.Services; using SmartStore.PayPal.Settings; -using SmartStore.Services.Configuration; using SmartStore.Services.Customers; -using SmartStore.Services.Directory; using SmartStore.Services.Payments; namespace SmartStore.PayPal @@ -27,22 +24,17 @@ public class PayPalDirectProvider : PayPalProviderBase(processPaymentRequest.StoreId); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); var req = new DoDirectPaymentReq(); req.DoDirectPaymentRequest = new DoDirectPaymentRequestType(); @@ -72,7 +65,7 @@ public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest proces var details = new DoDirectPaymentRequestDetailsType(); req.DoDirectPaymentRequest.DoDirectPaymentRequestDetails = details; - details.IPAddress = CommonServices.WebHelper.GetCurrentIpAddress(); + details.IPAddress = Services.WebHelper.GetCurrentIpAddress(); if (details.IPAddress.IsEmpty()) details.IPAddress = "127.0.0.1"; @@ -110,8 +103,10 @@ public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest proces details.CreditCard.CardOwner.PayerName = new PersonNameType(); details.CreditCard.CardOwner.PayerName.FirstName = customer.BillingAddress.FirstName; details.CreditCard.CardOwner.PayerName.LastName = customer.BillingAddress.LastName; - //order totals - var payPalCurrency = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)); + + //order totals + var payPalCurrency = PayPalHelper.GetPaypalCurrency(store.PrimaryStoreCurrency); + details.PaymentDetails = new PaymentDetailsType(); details.PaymentDetails.OrderTotal = new BasicAmountType(); details.PaymentDetails.OrderTotal.Value = Math.Round(processPaymentRequest.OrderTotal, 2).ToString("N", new CultureInfo("en-us")); @@ -180,8 +175,9 @@ public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentReque { var result = new ProcessPaymentResult(); + var store = Services.StoreService.GetStoreById(processPaymentRequest.StoreId); var customer = _customerService.GetCustomerById(processPaymentRequest.CustomerId); - var settings = CommonServices.Settings.LoadSetting(processPaymentRequest.StoreId); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); var req = new CreateRecurringPaymentsProfileReq(); req.CreateRecurringPaymentsProfileRequest = new CreateRecurringPaymentsProfileRequestType(); @@ -228,7 +224,7 @@ public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentReque details.ScheduleDetails.PaymentPeriod = new BillingPeriodDetailsType(); details.ScheduleDetails.PaymentPeriod.Amount = new BasicAmountType(); details.ScheduleDetails.PaymentPeriod.Amount.Value = Math.Round(processPaymentRequest.OrderTotal, 2).ToString("N", new CultureInfo("en-us")); - details.ScheduleDetails.PaymentPeriod.Amount.currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)); + details.ScheduleDetails.PaymentPeriod.Amount.currencyID = PayPalHelper.GetPaypalCurrency(store.PrimaryStoreCurrency); details.ScheduleDetails.PaymentPeriod.BillingFrequency = processPaymentRequest.RecurringCycleLength; switch (processPaymentRequest.RecurringCyclePeriod) { diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalExpressProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalExpressProvider.cs index d46643b8f7..8322cfe177 100644 --- a/src/Plugins/SmartStore.PayPal/Providers/PayPalExpressProvider.cs +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalExpressProvider.cs @@ -5,7 +5,6 @@ using System.Web; using SmartStore.Core; using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Shipping; @@ -15,10 +14,8 @@ using SmartStore.PayPal.PayPalSvc; using SmartStore.PayPal.Services; using SmartStore.PayPal.Settings; -using SmartStore.Services; using SmartStore.Services.Catalog; using SmartStore.Services.Common; -using SmartStore.Services.Configuration; using SmartStore.Services.Customers; using SmartStore.Services.Directory; using SmartStore.Services.Orders; @@ -33,7 +30,6 @@ namespace SmartStore.PayPal public partial class PayPalExpress : PayPalProviderBase { private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; private readonly IPriceCalculationService _priceCalculationService; private readonly IGenericAttributeService _genericAttributeService; private readonly IStateProvinceService _stateProvinceService; @@ -45,7 +41,6 @@ public partial class PayPalExpress : PayPalProviderBase(processPaymentRequest.StoreId); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); if (doPayment.Ack == AckCodeType.Success) { @@ -122,7 +116,7 @@ public override void PostProcessPayment(PostProcessPaymentRequest postProcessPay public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) { var result = new DoCaptureResponseType(); - var settings = CommonServices.Settings.LoadSetting(capturePaymentRequest.Order.StoreId); + var settings = Services.Settings.LoadSetting(capturePaymentRequest.Order.StoreId); // build the request var req = new DoCaptureReq @@ -188,8 +182,9 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq IList cart) { var result = new SetExpressCheckoutResponseType(); - var currentStore = CommonServices.StoreContext.CurrentStore; - var settings = CommonServices.Settings.LoadSetting(processPaymentRequest.StoreId); + var store = Services.StoreService.GetStoreById(processPaymentRequest.StoreId); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); + var payPalCurrency = PayPalHelper.GetPaypalCurrency(store.PrimaryStoreCurrency); var req = new SetExpressCheckoutReq { @@ -204,8 +199,8 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq { PaymentAction = PayPalHelper.GetPaymentAction(settings), PaymentActionSpecified = true, - CancelURL = CommonServices.WebHelper.GetStoreLocation(currentStore.SslEnabled) + "cart", - ReturnURL = CommonServices.WebHelper.GetStoreLocation(currentStore.SslEnabled) + "Plugins/SmartStore.PayPal/PayPalExpress/GetDetails", + CancelURL = Services.WebHelper.GetStoreLocation(store.SslEnabled) + "cart", + ReturnURL = Services.WebHelper.GetStoreLocation(store.SslEnabled) + "Plugins/SmartStore.PayPal/PayPalExpress/GetDetails", //CallbackURL = _webHelper.GetStoreLocation(currentStore.SslEnabled) + "Plugins/SmartStore.PayPal/PayPalExpress/ShippingOptions?CustomerID=" + _workContext.CurrentCustomer.Id.ToString(), //CallbackTimeout = _payPalExpressPaymentSettings.CallbackTimeout.ToString() ReqConfirmShipping = settings.ConfirmedShipment.ToString(), @@ -218,7 +213,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq foreach (OrganizedShoppingCartItem item in cart) { decimal shoppingCartUnitPriceWithDiscountBase = _priceCalculationService.GetUnitPrice(item, true); - decimal shoppingCartUnitPriceWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartUnitPriceWithDiscountBase, CommonServices.WorkContext.WorkingCurrency); + decimal shoppingCartUnitPriceWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartUnitPriceWithDiscountBase, Services.WorkContext.WorkingCurrency); decimal priceIncludingTier = shoppingCartUnitPriceWithDiscount; cartItems.Add(new PaymentDetailsItemType() @@ -228,7 +223,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq Quantity = item.Item.Quantity.ToString(), Amount = new BasicAmountType() // this is the per item cost { - currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)), + currencyID = payPalCurrency, Value = (priceIncludingTier).ToString("N", new CultureInfo("en-us")) } }); @@ -243,7 +238,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq Quantity = "1", Amount = new BasicAmountType() { - currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)), + currencyID = payPalCurrency, Value = (additionalHandlingFee).ToString("N", new CultureInfo("en-us")) } }); @@ -256,7 +251,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq decimal? shoppingCartShippingBase = OrderTotalCalculationService.GetShoppingCartShippingTotal(cart); if (shoppingCartShippingBase.HasValue && shoppingCartShippingBase > 0) { - shippingTotal = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartShippingBase.Value, CommonServices.WorkContext.WorkingCurrency); + shippingTotal = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartShippingBase.Value, Services.WorkContext.WorkingCurrency); } else { @@ -295,7 +290,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq Quantity = "1", Amount = new BasicAmountType() // this is the total discount { - currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)), + currencyID = payPalCurrency, Value = discount.ToString("N", new CultureInfo("en-us")) } }); @@ -304,7 +299,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq } // get customer - int customerId = Convert.ToInt32(CommonServices.WorkContext.CurrentCustomer.Id.ToString()); + int customerId = Convert.ToInt32(Services.WorkContext.CurrentCustomer.Id.ToString()); var customer = _customerService.GetCustomerById(customerId); if (!cart.IsRecurring()) @@ -332,7 +327,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq Quantity = "1", Amount = new BasicAmountType() { - currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)), + currencyID = payPalCurrency, Value = amountToSubtract.ToString("N", new CultureInfo("en-us")) } }); @@ -350,12 +345,12 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq ItemTotal = new BasicAmountType { Value = Math.Round(itemTotal, 2).ToString("N", new CultureInfo("en-us")), - currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)) + currencyID = payPalCurrency }, ShippingTotal = new BasicAmountType { Value = Math.Round(shippingTotal, 2).ToString("N", new CultureInfo("en-us")), - currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)) + currencyID = payPalCurrency }, //TaxTotal = new BasicAmountType //{ @@ -365,7 +360,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq OrderTotal = new BasicAmountType { Value = Math.Round(itemTotal + shippingTotal, 2).ToString("N", new CultureInfo("en-us")), - currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)) + currencyID = payPalCurrency }, Custom = processPaymentRequest.OrderGuid.ToString(), ButtonSource = SmartStoreVersion.CurrentFullVersion, @@ -394,7 +389,7 @@ public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentReq public GetExpressCheckoutDetailsResponseType GetExpressCheckoutDetails(string token) { var result = new GetExpressCheckoutDetailsResponseType(); - var settings = CommonServices.Settings.LoadSetting(CommonServices.StoreContext.CurrentStore.Id); + var settings = Services.Settings.LoadSetting(Services.StoreContext.CurrentStore.Id); using (var service = new PayPalAPIAASoapBinding()) { @@ -414,14 +409,14 @@ public GetExpressCheckoutDetailsResponseType GetExpressCheckoutDetails(string to public ProcessPaymentRequest SetCheckoutDetails(ProcessPaymentRequest processPaymentRequest, GetExpressCheckoutDetailsResponseDetailsType checkoutDetails) { - int customerId = Convert.ToInt32(CommonServices.WorkContext.CurrentCustomer.Id.ToString()); + int customerId = Convert.ToInt32(Services.WorkContext.CurrentCustomer.Id.ToString()); var customer = _customerService.GetCustomerById(customerId); - var settings = CommonServices.Settings.LoadSetting(CommonServices.StoreContext.CurrentStore.Id); + var settings = Services.Settings.LoadSetting(Services.StoreContext.CurrentStore.Id); - CommonServices.WorkContext.CurrentCustomer = customer; + Services.WorkContext.CurrentCustomer = customer; //var cart = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList(); - var cart = CommonServices.WorkContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, CommonServices.StoreContext.CurrentStore.Id); + var cart = Services.WorkContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, Services.StoreContext.CurrentStore.Id); // get/update billing address string billingFirstName = checkoutDetails.PayerInfo.PayerName.FirstName; @@ -541,7 +536,7 @@ public ProcessPaymentRequest SetCheckoutDetails(ProcessPaymentRequest processPay if (checkoutDetails.UserSelectedOptions.ShippingOptionName.Contains(shippingOption.Name) && checkoutDetails.UserSelectedOptions.ShippingOptionName.Contains(shippingOption.Description)) { - _genericAttributeService.SaveAttribute(CommonServices.WorkContext.CurrentCustomer, SystemCustomerAttributeNames.SelectedShippingOption, shippingOption); + _genericAttributeService.SaveAttribute(Services.WorkContext.CurrentCustomer, SystemCustomerAttributeNames.SelectedShippingOption, shippingOption); isShippingSet = true; break; } @@ -569,7 +564,8 @@ public ProcessPaymentRequest SetCheckoutDetails(ProcessPaymentRequest processPay public DoExpressCheckoutPaymentResponseType DoExpressCheckoutPayment(ProcessPaymentRequest processPaymentRequest) { var result = new DoExpressCheckoutPaymentResponseType(); - var settings = CommonServices.Settings.LoadSetting(processPaymentRequest.StoreId); + var store = Services.StoreService.GetStoreById(processPaymentRequest.StoreId); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); // populate payment details var paymentDetails = new PaymentDetailsType @@ -577,7 +573,7 @@ public DoExpressCheckoutPaymentResponseType DoExpressCheckoutPayment(ProcessPaym OrderTotal = new BasicAmountType { Value = Math.Round(processPaymentRequest.OrderTotal, 2).ToString("N", new CultureInfo("en-us")), - currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)) + currencyID = PayPalHelper.GetPaypalCurrency(store.PrimaryStoreCurrency) }, Custom = processPaymentRequest.OrderGuid.ToString(), ButtonSource = SmartStoreVersion.CurrentFullVersion diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalProviderBase.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalProviderBase.cs index 687d179faf..656429ce43 100644 --- a/src/Plugins/SmartStore.PayPal/Providers/PayPalProviderBase.cs +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalProviderBase.cs @@ -31,7 +31,7 @@ protected PayPalProviderBase() public ILogger Logger { get; set; } - public ICommonServices CommonServices { get; set; } + public ICommonServices Services { get; set; } public IOrderService OrderService { get; set; } @@ -63,7 +63,7 @@ public PluginHelper Helper public bool VerifyIPN(string formString, out Dictionary values) { // settings: multistore context not possible here. we need the custom value to determine what store it is. - var settings = CommonServices.Settings.LoadSetting(); + var settings = Services.Settings.LoadSetting(); var req = (HttpWebRequest)WebRequest.Create(PayPalHelper.GetPaypalUrl(settings)); req.Method = "POST"; @@ -107,7 +107,7 @@ public override decimal GetAdditionalHandlingFee(IList(); + var settings = Services.Settings.LoadSetting(); result = this.CalculateAdditionalFee(OrderTotalCalculationService, cart, settings.AdditionalFee, settings.AdditionalFeePercentage); } @@ -129,7 +129,7 @@ public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymen NewPaymentStatus = capturePaymentRequest.Order.PaymentStatus }; - var settings = CommonServices.Settings.LoadSetting(capturePaymentRequest.Order.StoreId); + var settings = Services.Settings.LoadSetting(capturePaymentRequest.Order.StoreId); string authorizationId = capturePaymentRequest.Order.AuthorizationTransactionId; var req = new DoCaptureReq(); @@ -175,7 +175,7 @@ public override RefundPaymentResult Refund(RefundPaymentRequest request) NewPaymentStatus = request.Order.PaymentStatus }; - var settings = CommonServices.Settings.LoadSetting(request.Order.StoreId); + var settings = Services.Settings.LoadSetting(request.Order.StoreId); string transactionId = request.Order.CaptureTransactionId; var req = new RefundTransactionReq(); @@ -221,7 +221,7 @@ public override VoidPaymentResult Void(VoidPaymentRequest request) }; string transactionId = request.Order.AuthorizationTransactionId; - var settings = CommonServices.Settings.LoadSetting(request.Order.StoreId); + var settings = Services.Settings.LoadSetting(request.Order.StoreId); if (String.IsNullOrEmpty(transactionId)) transactionId = request.Order.CaptureTransactionId; @@ -262,7 +262,7 @@ public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurr { var result = new CancelRecurringPaymentResult(); var order = request.Order; - var settings = CommonServices.Settings.LoadSetting(order.StoreId); + var settings = Services.Settings.LoadSetting(order.StoreId); var req = new ManageRecurringPaymentsProfileStatusReq(); req.ManageRecurringPaymentsProfileStatusRequest = new ManageRecurringPaymentsProfileStatusRequestType(); diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs index c009c24d3c..609a7192e5 100644 --- a/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs @@ -9,7 +9,6 @@ using System.Web; using System.Web.Routing; using SmartStore.Core.Domain.Common; -using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Shipping; @@ -34,22 +33,17 @@ namespace SmartStore.PayPal [DisplayOrder(2)] public partial class PayPalStandardProvider : PaymentPluginBase, IConfigurable { - private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; private readonly IOrderTotalCalculationService _orderTotalCalculationService; private readonly HttpContextBase _httpContext; private readonly ICommonServices _services; private readonly ILogger _logger; - public PayPalStandardProvider(ICurrencyService currencyService, + public PayPalStandardProvider( HttpContextBase httpContext, - CurrencySettings currencySettings, IOrderTotalCalculationService orderTotalCalculationService, ICommonServices services, ILogger logger) { - _currencyService = currencyService; - _currencySettings = currencySettings; _orderTotalCalculationService = orderTotalCalculationService; _httpContext = httpContext; _services = services; @@ -85,6 +79,7 @@ public override void PostProcessPayment(PostProcessPaymentRequest postProcessPay if (postProcessPaymentRequest.Order.PaymentStatus == PaymentStatus.Paid) return; + var store = _services.StoreService.GetStoreById(postProcessPaymentRequest.Order.StoreId); var settings = _services.Settings.LoadSetting(postProcessPaymentRequest.Order.StoreId); var builder = new StringBuilder(); @@ -220,7 +215,7 @@ public override void PostProcessPayment(PostProcessPaymentRequest postProcessPay builder.AppendFormat("&custom={0}", postProcessPaymentRequest.Order.OrderGuid); builder.AppendFormat("&charset={0}", "utf-8"); - builder.Append(string.Format("&no_note=1¤cy_code={0}", HttpUtility.UrlEncode(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode))); + builder.Append(string.Format("&no_note=1¤cy_code={0}", HttpUtility.UrlEncode(store.PrimaryStoreCurrency.CurrencyCode))); builder.AppendFormat("&invoice={0}", HttpUtility.UrlEncode(orderNumber)); builder.AppendFormat("&rm=2", new object[0]); diff --git a/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs b/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs index c751879157..92b915c7d5 100644 --- a/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs +++ b/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs @@ -1,13 +1,11 @@ using System.Web.Mvc; using SmartStore.Core.Domain.Common; -using SmartStore.Core.Domain.Directory; +using SmartStore.Services; +using SmartStore.Services.Directory; +using SmartStore.Services.Shipping; using SmartStore.Shipping.Domain; using SmartStore.Shipping.Models; using SmartStore.Shipping.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Directory; -using SmartStore.Services.Shipping; -using SmartStore.Services.Stores; using SmartStore.Web.Framework.Controllers; using Telerik.Web.Mvc; @@ -17,34 +15,26 @@ namespace SmartStore.Shipping.Controllers public class ByTotalController : PluginControllerBase { private readonly IShippingService _shippingService; - private readonly IStoreService _storeService; - private readonly ISettingService _settingService; private readonly IShippingByTotalService _shippingByTotalService; private readonly ShippingByTotalSettings _shippingByTotalSettings; private readonly ICountryService _countryService; - private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; private readonly AdminAreaSettings _adminAreaSettings; + private readonly ICommonServices _services; - public ByTotalController(IShippingService shippingService, - IStoreService storeService, - ISettingService settingService, + public ByTotalController( + IShippingService shippingService, IShippingByTotalService shippingByTotalService, ShippingByTotalSettings shippingByTotalSettings, ICountryService countryService, - ICurrencyService currencyService, - CurrencySettings currencySettings, - AdminAreaSettings adminAreaSettings) + AdminAreaSettings adminAreaSettings, + ICommonServices services) { this._shippingService = shippingService; - this._storeService = storeService; - this._settingService = settingService; this._shippingByTotalService = shippingByTotalService; this._shippingByTotalSettings = shippingByTotalSettings; this._countryService = countryService; - this._currencyService = currencyService; - this._currencySettings = currencySettings; this._adminAreaSettings = adminAreaSettings; + this._services = services; } public ActionResult Configure() @@ -56,29 +46,31 @@ public ActionResult Configure() } var model = new ByTotalListModel(); + var allStores = _services.StoreService.GetAllStores(); + foreach (var sm in shippingMethods) { - model.AvailableShippingMethods.Add(new SelectListItem() { Text = sm.Name, Value = sm.Id.ToString() }); + model.AvailableShippingMethods.Add(new SelectListItem { Text = sm.Name, Value = sm.Id.ToString() }); } //stores - model.AvailableStores.Add(new SelectListItem() { Text = "*", Value = "0" }); - foreach (var store in _storeService.GetAllStores()) + model.AvailableStores.Add(new SelectListItem { Text = "*", Value = "0" }); + foreach (var store in allStores) { - model.AvailableStores.Add(new SelectListItem() { Text = store.Name, Value = store.Id.ToString() }); + model.AvailableStores.Add(new SelectListItem { Text = store.Name, Value = store.Id.ToString() }); } - //model.AvailableCountries.Add(new SelectListItem() { Text = "*", Value = "0" }); + //model.AvailableCountries.Add(new SelectListItem { Text = "*", Value = "0" }); var countries = _countryService.GetAllCountries(true); foreach (var c in countries) { - model.AvailableCountries.Add(new SelectListItem() { Text = c.Name, Value = c.Id.ToString() }); + model.AvailableCountries.Add(new SelectListItem { Text = c.Name, Value = c.Id.ToString() }); } model.LimitMethodsToCreated = _shippingByTotalSettings.LimitMethodsToCreated; model.SmallQuantityThreshold = _shippingByTotalSettings.SmallQuantityThreshold; model.SmallQuantitySurcharge = _shippingByTotalSettings.SmallQuantitySurcharge; - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; model.GridPageSize = _adminAreaSettings.GridPageSize; return View(model); @@ -166,7 +158,7 @@ public ActionResult SaveGeneralSettings(ByTotalListModel model) _shippingByTotalSettings.SmallQuantityThreshold = model.SmallQuantityThreshold; _shippingByTotalSettings.SmallQuantitySurcharge = model.SmallQuantitySurcharge; - _settingService.SaveSetting(_shippingByTotalSettings); + _services.Settings.SaveSetting(_shippingByTotalSettings); return Json(new { Result = true }); } diff --git a/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs b/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs index 6d7c63bf12..1e6c968f0a 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs @@ -1,16 +1,12 @@ -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Web.Mvc; +using System.Web.Mvc; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Directory; +using SmartStore.Services; +using SmartStore.Services.Directory; +using SmartStore.Services.Shipping; using SmartStore.ShippingByWeight.Domain; using SmartStore.ShippingByWeight.Models; using SmartStore.ShippingByWeight.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Directory; -using SmartStore.Services.Shipping; -using SmartStore.Services.Stores; using SmartStore.Web.Framework.Controllers; using Telerik.Web.Mvc; @@ -21,37 +17,32 @@ namespace SmartStore.ShippingByWeight.Controllers public class ShippingByWeightController : PluginControllerBase { private readonly IShippingService _shippingService; - private readonly IStoreService _storeService; private readonly ICountryService _countryService; private readonly ShippingByWeightSettings _shippingByWeightSettings; private readonly IShippingByWeightService _shippingByWeightService; - private readonly ISettingService _settingService; - - private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; private readonly IMeasureService _measureService; private readonly MeasureSettings _measureSettings; private readonly AdminAreaSettings _adminAreaSettings; - - public ShippingByWeightController(IShippingService shippingService, - IStoreService storeService, ICountryService countryService, ShippingByWeightSettings shippingByWeightSettings, - IShippingByWeightService shippingByWeightService, ISettingService settingService, - ICurrencyService currencyService, CurrencySettings currencySettings, - IMeasureService measureService, MeasureSettings measureSettings, - AdminAreaSettings adminAreaSettings) + private readonly ICommonServices _services; + + public ShippingByWeightController( + IShippingService shippingService, + ICountryService countryService, + ShippingByWeightSettings shippingByWeightSettings, + IShippingByWeightService shippingByWeightService, + IMeasureService measureService, + MeasureSettings measureSettings, + AdminAreaSettings adminAreaSettings, + ICommonServices services) { this._shippingService = shippingService; - this._storeService = storeService; this._countryService = countryService; this._shippingByWeightSettings = shippingByWeightSettings; this._shippingByWeightService = shippingByWeightService; - this._settingService = settingService; - - this._currencyService = currencyService; - this._currencySettings = currencySettings; this._measureService = measureService; this._measureSettings = measureSettings; this._adminAreaSettings = adminAreaSettings; + this._services = services; } public ActionResult Configure() @@ -61,21 +52,30 @@ public ActionResult Configure() return Content("No shipping methods can be loaded"); var model = new ShippingByWeightListModel(); - foreach (var sm in shippingMethods) - model.AvailableShippingMethods.Add(new SelectListItem() { Text = sm.Name, Value = sm.Id.ToString() }); + var countries = _countryService.GetAllCountries(true); + var allStores = _services.StoreService.GetAllStores(); + + foreach (var sm in shippingMethods) + { + model.AvailableShippingMethods.Add(new SelectListItem { Text = sm.Name, Value = sm.Id.ToString() }); + } //stores - model.AvailableStores.Add(new SelectListItem() { Text = "*", Value = "0" }); - foreach (var store in _storeService.GetAllStores()) - model.AvailableStores.Add(new SelectListItem() { Text = store.Name, Value = store.Id.ToString() }); - - model.AvailableCountries.Add(new SelectListItem() { Text = "*", Value = "0" }); - var countries = _countryService.GetAllCountries(true); - foreach (var c in countries) - model.AvailableCountries.Add(new SelectListItem() { Text = c.Name, Value = c.Id.ToString() }); + model.AvailableStores.Add(new SelectListItem { Text = "*", Value = "0" }); + foreach (var store in allStores) + { + model.AvailableStores.Add(new SelectListItem { Text = store.Name, Value = store.Id.ToString() }); + } + + model.AvailableCountries.Add(new SelectListItem { Text = "*", Value = "0" }); + foreach (var c in countries) + { + model.AvailableCountries.Add(new SelectListItem { Text = c.Name, Value = c.Id.ToString() }); + } + model.LimitMethodsToCreated = _shippingByWeightSettings.LimitMethodsToCreated; model.CalculatePerWeightUnit = _shippingByWeightSettings.CalculatePerWeightUnit; - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; model.GridPageSize = _adminAreaSettings.GridPageSize; @@ -160,7 +160,7 @@ public ActionResult SaveGeneralSettings(ShippingByWeightListModel model) //save settings _shippingByWeightSettings.LimitMethodsToCreated = model.LimitMethodsToCreated; _shippingByWeightSettings.CalculatePerWeightUnit = model.CalculatePerWeightUnit; - _settingService.SaveSetting(_shippingByWeightSettings); + _services.Settings.SaveSetting(_shippingByWeightSettings); return Configure(); } diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs index 0f6789e863..b3d71558e0 100644 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs @@ -24,7 +24,6 @@ public partial class PluginHelper private string _pluginResRootKey; private string _providerResRootKey; private Language _language; - private int? _currencyID; private string _currencyCode; private Currency _euroCurrency; private Dictionary _resMap = new Dictionary(); @@ -101,18 +100,6 @@ public bool IsLanguageGerman } } - public int CurrencyID - { - get - { - if (!_currencyID.HasValue) - { - _currencyID = _ctx.Resolve().PrimaryStoreCurrencyId; - } - return _currencyID ?? 1; - } - } - public string CurrencyCode { get @@ -219,19 +206,6 @@ public XmlDocument CreateXmlDocument(Func content) } } - public Currency GetUsedCurrency(int currencyId) - { - var currencyService = _ctx.Resolve(); - var currency = currencyService.GetCurrencyById(currencyId); - - if (currency == null || !currency.Published) - { - currency = currencyService.GetCurrencyById(CurrencyID); - } - - return currency; - } - public decimal ConvertFromStoreCurrency(decimal price, Currency currency) { return _ctx.Resolve().ConvertFromPrimaryStoreCurrency(price, currency); diff --git a/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs b/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs index bb717b809f..1b9a6d7c96 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs @@ -10,7 +10,6 @@ using SmartStore.Core.Fakes; using SmartStore.Services.Authentication; using SmartStore.Services.Common; -using SmartStore.Services.Configuration; using SmartStore.Services.Customers; using SmartStore.Services.Directory; using SmartStore.Services.Localization; @@ -35,11 +34,9 @@ public partial class WebWorkContext : IWorkContext private readonly ICurrencyService _currencyService; private readonly IGenericAttributeService _attrService; private readonly TaxSettings _taxSettings; - private readonly CurrencySettings _currencySettings; private readonly LocalizationSettings _localizationSettings; private readonly ICacheManager _cacheManager; private readonly IStoreService _storeService; - private readonly ISettingService _settingService; private readonly Lazy _taxService; private readonly IUserAgent _userAgent; @@ -58,9 +55,10 @@ public WebWorkContext(Func cacheManager, ILanguageService languageService, ICurrencyService currencyService, IGenericAttributeService attrService, - TaxSettings taxSettings, CurrencySettings currencySettings, - LocalizationSettings localizationSettings, Lazy taxService, - IStoreService storeService, ISettingService settingService, + TaxSettings taxSettings, + LocalizationSettings localizationSettings, + Lazy taxService, + IStoreService storeService, IUserAgent userAgent) { this._cacheManager = cacheManager("static"); @@ -73,10 +71,8 @@ public WebWorkContext(Func cacheManager, this._currencyService = currencyService; this._taxSettings = taxSettings; this._taxService = taxService; - this._currencySettings = currencySettings; this._localizationSettings = localizationSettings; this._storeService = storeService; - this._settingService = settingService; this._userAgent = userAgent; } @@ -353,13 +349,12 @@ public Currency WorkingCurrency if (_cachedCurrency != null) return _cachedCurrency; - bool fixPrimaryStoreCurrency = false; Currency currency = null; // return primary store currency when we're in admin area/mode if (this.IsAdmin) { - currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + currency = _storeContext.CurrentStore.PrimaryStoreCurrency; } if (currency == null) @@ -400,11 +395,7 @@ public Currency WorkingCurrency // get PrimaryStoreCurrency if (currency == null) { - if (storeCurrenciesMap.TryGetValue(_currencySettings.PrimaryStoreCurrencyId, out currency)) - { - currency = VerifyCurrency(currency); - fixPrimaryStoreCurrency = (currency == null); - } + currency = VerifyCurrency(_storeContext.CurrentStore.PrimaryStoreCurrency); } // get the first published currency for current store @@ -431,12 +422,6 @@ public Currency WorkingCurrency } } - if (fixPrimaryStoreCurrency) - { - _currencySettings.PrimaryStoreCurrencyId = currency.Id; - _settingService.UpdateSetting(_currencySettings, x => x.PrimaryStoreCurrencyId, true, _storeContext.CurrentStore.Id); - } - _cachedCurrency = currency; return _cachedCurrency; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CheckoutAttributeController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CheckoutAttributeController.cs index 11009f3784..36002de30e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CheckoutAttributeController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CheckoutAttributeController.cs @@ -2,12 +2,12 @@ using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Orders; -using SmartStore.Core; using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Logging; +using SmartStore.Services; using SmartStore.Services.Directory; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Orders; using SmartStore.Services.Security; using SmartStore.Services.Tax; @@ -24,40 +24,33 @@ public class CheckoutAttributeController : AdminControllerBase private readonly ICheckoutAttributeService _checkoutAttributeService; private readonly ILanguageService _languageService; private readonly ILocalizedEntityService _localizedEntityService; - private readonly ILocalizationService _localizationService; private readonly ITaxCategoryService _taxCategoryService; - private readonly IWorkContext _workContext; - private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; private readonly IMeasureService _measureService; private readonly MeasureSettings _measureSettings; private readonly ICustomerActivityService _customerActivityService; - private readonly IPermissionService _permissionService; + private readonly ICommonServices _services; #endregion #region Constructors public CheckoutAttributeController(ICheckoutAttributeService checkoutAttributeService, - ILanguageService languageService, ILocalizedEntityService localizedEntityService, - ILocalizationService localizationService, ITaxCategoryService taxCategoryService, - IWorkContext workContext, ICurrencyService currencyService, - ICustomerActivityService customerActivityService, CurrencySettings currencySettings, - IMeasureService measureService, MeasureSettings measureSettings, - IPermissionService permissionService) + ILanguageService languageService, + ILocalizedEntityService localizedEntityService, + ITaxCategoryService taxCategoryService, + ICustomerActivityService customerActivityService, + IMeasureService measureService, + MeasureSettings measureSettings, + ICommonServices services) { this._checkoutAttributeService = checkoutAttributeService; this._languageService = languageService; this._localizedEntityService = localizedEntityService; - this._localizationService = localizationService; this._taxCategoryService = taxCategoryService; - this._workContext = workContext; - this._currencyService = currencyService; this._customerActivityService = customerActivityService; - this._currencySettings = currencySettings; this._measureService = measureService; this._measureSettings = measureSettings; - this._permissionService = permissionService; + this._services = services; } #endregion @@ -117,7 +110,7 @@ public ActionResult Index() public ActionResult List() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); return View(); @@ -126,7 +119,7 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(true); @@ -135,7 +128,7 @@ public ActionResult List(GridCommand command) Data = checkoutAttributes.Select(x => { var caModel = x.ToModel(); - caModel.AttributeControlTypeName = x.AttributeControlType.GetLocalizedEnum(_localizationService, _workContext); + caModel.AttributeControlTypeName = x.AttributeControlType.GetLocalizedEnum(_services.Localization, _services.WorkContext); return caModel; }), Total = checkoutAttributes.Count() @@ -149,7 +142,7 @@ public ActionResult List(GridCommand command) //create public ActionResult Create() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var model = new CheckoutAttributeModel(); @@ -164,7 +157,7 @@ public ActionResult Create() [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Create(CheckoutAttributeModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); if (ModelState.IsValid) @@ -174,9 +167,9 @@ public ActionResult Create(CheckoutAttributeModel model, bool continueEditing) UpdateAttributeLocales(checkoutAttribute, model); //activity log - _customerActivityService.InsertActivity("AddNewCheckoutAttribute", _localizationService.GetResource("ActivityLog.AddNewCheckoutAttribute"), checkoutAttribute.Name); + _customerActivityService.InsertActivity("AddNewCheckoutAttribute", _services.Localization.GetResource("ActivityLog.AddNewCheckoutAttribute"), checkoutAttribute.Name); - NotifySuccess(_localizationService.GetResource("Admin.Catalog.Attributes.CheckoutAttributes.Added")); + NotifySuccess(_services.Localization.GetResource("Admin.Catalog.Attributes.CheckoutAttributes.Added")); return continueEditing ? RedirectToAction("Edit", new { id = checkoutAttribute.Id }) : RedirectToAction("List"); } @@ -188,7 +181,7 @@ public ActionResult Create(CheckoutAttributeModel model, bool continueEditing) //edit public ActionResult Edit(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var checkoutAttribute = _checkoutAttributeService.GetCheckoutAttributeById(id); @@ -211,7 +204,7 @@ public ActionResult Edit(int id) [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Edit(CheckoutAttributeModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var checkoutAttribute = _checkoutAttributeService.GetCheckoutAttributeById(model.Id); @@ -227,9 +220,9 @@ public ActionResult Edit(CheckoutAttributeModel model, bool continueEditing) UpdateAttributeLocales(checkoutAttribute, model); //activity log - _customerActivityService.InsertActivity("EditCheckoutAttribute", _localizationService.GetResource("ActivityLog.EditCheckoutAttribute"), checkoutAttribute.Name); + _customerActivityService.InsertActivity("EditCheckoutAttribute", _services.Localization.GetResource("ActivityLog.EditCheckoutAttribute"), checkoutAttribute.Name); - NotifySuccess(_localizationService.GetResource("Admin.Catalog.Attributes.CheckoutAttributes.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Catalog.Attributes.CheckoutAttributes.Updated")); return continueEditing ? RedirectToAction("Edit", checkoutAttribute.Id) : RedirectToAction("List"); } @@ -242,16 +235,16 @@ public ActionResult Edit(CheckoutAttributeModel model, bool continueEditing) [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var checkoutAttribute = _checkoutAttributeService.GetCheckoutAttributeById(id); _checkoutAttributeService.DeleteCheckoutAttribute(checkoutAttribute); //activity log - _customerActivityService.InsertActivity("DeleteCheckoutAttribute", _localizationService.GetResource("ActivityLog.DeleteCheckoutAttribute"), checkoutAttribute.Name); + _customerActivityService.InsertActivity("DeleteCheckoutAttribute", _services.Localization.GetResource("ActivityLog.DeleteCheckoutAttribute"), checkoutAttribute.Name); - NotifySuccess(_localizationService.GetResource("Admin.Catalog.Attributes.CheckoutAttributes.Deleted")); + NotifySuccess(_services.Localization.GetResource("Admin.Catalog.Attributes.CheckoutAttributes.Deleted")); return RedirectToAction("List"); } @@ -263,7 +256,7 @@ public ActionResult DeleteConfirmed(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult ValueList(int checkoutAttributeId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var values = _checkoutAttributeService.GetCheckoutAttributeValues(checkoutAttributeId); @@ -290,12 +283,12 @@ public ActionResult ValueList(int checkoutAttributeId, GridCommand command) //create public ActionResult ValueCreatePopup(int checkoutAttributeId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var model = new CheckoutAttributeValueModel(); model.CheckoutAttributeId = checkoutAttributeId; - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; //locales @@ -306,7 +299,7 @@ public ActionResult ValueCreatePopup(int checkoutAttributeId) [HttpPost] public ActionResult ValueCreatePopup(string btnId, string formId, CheckoutAttributeValueModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var checkoutAttribute = _checkoutAttributeService.GetCheckoutAttributeById(model.CheckoutAttributeId); @@ -314,7 +307,7 @@ public ActionResult ValueCreatePopup(string btnId, string formId, CheckoutAttrib //No checkout attribute found with the specified id return RedirectToAction("List"); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; if (ModelState.IsValid) @@ -337,7 +330,7 @@ public ActionResult ValueCreatePopup(string btnId, string formId, CheckoutAttrib //edit public ActionResult ValueEditPopup(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var cav = _checkoutAttributeService.GetCheckoutAttributeValueById(id); @@ -346,7 +339,7 @@ public ActionResult ValueEditPopup(int id) return RedirectToAction("List"); var model = cav.ToModel(); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; //locales @@ -361,7 +354,7 @@ public ActionResult ValueEditPopup(int id) [HttpPost] public ActionResult ValueEditPopup(string btnId, string formId, CheckoutAttributeValueModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var cav = _checkoutAttributeService.GetCheckoutAttributeValueById(model.Id); @@ -369,7 +362,7 @@ public ActionResult ValueEditPopup(string btnId, string formId, CheckoutAttribut //No checkout attribute value found with the specified id return RedirectToAction("List"); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; if (ModelState.IsValid) @@ -393,7 +386,7 @@ public ActionResult ValueEditPopup(string btnId, string formId, CheckoutAttribut [GridAction(EnableCustomBinding = true)] public ActionResult ValueDelete(int valueId, int checkoutAttributeId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); var cav = _checkoutAttributeService.GetCheckoutAttributeValueById(valueId); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs index d9424d8fe0..ce27f22ebc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs @@ -578,7 +578,7 @@ public ActionResult Warnings() } //primary store currency - var pscCurrency = _currencyService.Value.GetCurrencyById(_currencySettings.Value.PrimaryStoreCurrencyId); + var pscCurrency = _services.StoreContext.CurrentStore.PrimaryStoreCurrency; if (pscCurrency != null) { model.Add(new SystemWarningModel diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs index 6af5cd0a89..4006edb580 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs @@ -4,7 +4,7 @@ using System.Web.Mvc; using SmartStore.Admin.Models.Directory; using SmartStore.Core.Domain.Directory; -using SmartStore.Services.Configuration; +using SmartStore.Services; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; @@ -23,40 +23,34 @@ public class CurrencyController : AdminControllerBase private readonly ICurrencyService _currencyService; private readonly CurrencySettings _currencySettings; - private readonly ISettingService _settingService; private readonly IDateTimeHelper _dateTimeHelper; - private readonly ILocalizationService _localizationService; - private readonly IPermissionService _permissionService; private readonly ILocalizedEntityService _localizedEntityService; private readonly ILanguageService _languageService; - private readonly IStoreService _storeService; private readonly IStoreMappingService _storeMappingService; private readonly PluginMediator _pluginMediator; + private readonly ICommonServices _services; #endregion #region Constructors public CurrencyController(ICurrencyService currencyService, - CurrencySettings currencySettings, ISettingService settingService, - IDateTimeHelper dateTimeHelper, ILocalizationService localizationService, - IPermissionService permissionService, - ILocalizedEntityService localizedEntityService, ILanguageService languageService, - IStoreService storeService, + CurrencySettings currencySettings, + IDateTimeHelper dateTimeHelper, + ILocalizedEntityService localizedEntityService, + ILanguageService languageService, IStoreMappingService storeMappingService, - PluginMediator pluginMediator) + PluginMediator pluginMediator, + ICommonServices services) { this._currencyService = currencyService; this._currencySettings = currencySettings; - this._settingService = settingService; this._dateTimeHelper = dateTimeHelper; - this._localizationService = localizationService; - this._permissionService = permissionService; this._localizedEntityService = localizedEntityService; this._languageService = languageService; - this._storeService = storeService; this._storeMappingService = storeMappingService; this._pluginMediator = pluginMediator; + this._services = services; } #endregion @@ -81,7 +75,7 @@ private void PrepareStoresMappingModel(CurrencyModel model, Currency currency, b if (model == null) throw new ArgumentNullException("model"); - model.AvailableStores = _storeService + model.AvailableStores = _services.StoreService .GetAllStores() .Select(s => s.ToModel()) .ToList(); @@ -109,14 +103,21 @@ public ActionResult Index() public ActionResult List(bool liveRates = false) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); var currenciesModel = _currencyService.GetAllCurrencies(true).Select(x => x.ToModel()).ToList(); - foreach (var currency in currenciesModel) - currency.IsPrimaryExchangeRateCurrency = currency.Id == _currencySettings.PrimaryExchangeRateCurrencyId ? true : false; - foreach (var currency in currenciesModel) - currency.IsPrimaryStoreCurrency = currency.Id == _currencySettings.PrimaryStoreCurrencyId ? true : false; + + foreach (var currency in currenciesModel) + { + currency.IsPrimaryExchangeRateCurrency = (currency.Id == _services.StoreContext.CurrentStore.PrimaryExchangeRateCurrencyId); + } + + foreach (var currency in currenciesModel) + { + currency.IsPrimaryStoreCurrency = (currency.Id == _services.StoreContext.CurrentStore.PrimaryStoreCurrencyId); + } + if (liveRates) { try @@ -153,7 +154,7 @@ public ActionResult List(bool liveRates = false) public ActionResult ApplyRate(string currencyCode, decimal rate) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); Currency currency = _currencyService.GetCurrencyByCode(currencyCode); @@ -169,19 +170,19 @@ public ActionResult ApplyRate(string currencyCode, decimal rate) [HttpPost] public ActionResult Save(FormCollection formValues) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); _currencySettings.ActiveExchangeRateProviderSystemName = formValues["exchangeRateProvider"]; _currencySettings.AutoUpdateEnabled = formValues["autoUpdateEnabled"].Equals("false") ? false : true; - _settingService.SaveSetting(_currencySettings); + _services.Settings.SaveSetting(_currencySettings); return RedirectToAction("List", "Currency"); } [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); var currencies = _currencyService.GetAllCurrencies(true); @@ -198,21 +199,21 @@ public ActionResult List(GridCommand command) public ActionResult MarkAsPrimaryExchangeRateCurrency(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); _currencySettings.PrimaryExchangeRateCurrencyId = id; - _settingService.SaveSetting(_currencySettings); + _services.Settings.SaveSetting(_currencySettings); return RedirectToAction("List"); } public ActionResult MarkAsPrimaryStoreCurrency(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); - _currencySettings.PrimaryStoreCurrencyId = id; - _settingService.SaveSetting(_currencySettings); + //_currencySettings.PrimaryStoreCurrencyId = id; + //_services.Settings.SaveSetting(_currencySettings); return RedirectToAction("List"); } @@ -222,7 +223,7 @@ public ActionResult MarkAsPrimaryStoreCurrency(int id) public ActionResult Create() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); var model = new CurrencyModel(); @@ -239,7 +240,7 @@ public ActionResult Create() [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Create(CurrencyModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); if (ModelState.IsValid) @@ -256,7 +257,7 @@ public ActionResult Create(CurrencyModel model, bool continueEditing) //Stores _storeMappingService.SaveStoreMappings(currency, model.SelectedStoreIds); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Currencies.Added")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Currencies.Added")); return continueEditing ? RedirectToAction("Edit", new { id = currency.Id }) : RedirectToAction("List"); } @@ -270,7 +271,7 @@ public ActionResult Create(CurrencyModel model, bool continueEditing) public ActionResult Edit(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); var currency = _currencyService.GetCurrencyById(id); @@ -304,7 +305,7 @@ public ActionResult Edit(int id) [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Edit(CurrencyModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); var currency = _currencyService.GetCurrencyById(model.Id); @@ -324,7 +325,7 @@ public ActionResult Edit(CurrencyModel model, bool continueEditing) //Stores _storeMappingService.SaveStoreMappings(currency, model.SelectedStoreIds); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Currencies.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Currencies.Updated")); return continueEditing ? RedirectToAction("Edit", new { id = currency.Id }) : RedirectToAction("List"); } @@ -340,7 +341,7 @@ public ActionResult Edit(CurrencyModel model, bool continueEditing) [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageCurrencies)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); var currency = _currencyService.GetCurrencyById(id); @@ -349,15 +350,16 @@ public ActionResult DeleteConfirmed(int id) try { - if (currency.Id == _currencySettings.PrimaryStoreCurrencyId) - throw new SmartException(_localizationService.GetResource("Admin.Configuration.Currencies.CantDeletePrimary")); + // TODO + //if (currency.Id == _currencySettings.PrimaryStoreCurrencyId) + // throw new SmartException(_services.Localization.GetResource("Admin.Configuration.Currencies.CantDeletePrimary")); - if (currency.Id == _currencySettings.PrimaryExchangeRateCurrencyId) - throw new SmartException(_localizationService.GetResource("Admin.Configuration.Currencies.CantDeleteExchange")); + //if (currency.Id == _currencySettings.PrimaryExchangeRateCurrencyId) + // throw new SmartException(_services.Localization.GetResource("Admin.Configuration.Currencies.CantDeleteExchange")); _currencyService.DeleteCurrency(currency); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Currencies.Deleted")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Currencies.Deleted")); return RedirectToAction("List"); } catch (Exception exc) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/DiscountController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/DiscountController.cs index ff5d7b75ca..a12bea379e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/DiscountController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/DiscountController.cs @@ -2,22 +2,16 @@ using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Discounts; -using SmartStore.Core.Plugins; -using SmartStore.Core; -using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Logging; +using SmartStore.Services; using SmartStore.Services.Catalog; -using SmartStore.Services.Directory; using SmartStore.Services.Discounts; using SmartStore.Services.Helpers; -using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Security; using SmartStore.Web.Framework.Controllers; -using Telerik.Web.Mvc; -using SmartStore.Core.ComponentModel; -using System.Collections.Generic; using SmartStore.Web.Framework.Plugins; +using Telerik.Web.Mvc; namespace SmartStore.Admin.Controllers { @@ -27,40 +21,33 @@ public class DiscountController : AdminControllerBase #region Fields private readonly IDiscountService _discountService; - private readonly ILocalizationService _localizationService; - private readonly IWebHelper _webHelper; private readonly IDateTimeHelper _dateTimeHelper; private readonly ICustomerActivityService _customerActivityService; - private readonly ICurrencyService _currencyService; private readonly ICategoryService _categoryService; private readonly IProductService _productService; - private readonly CurrencySettings _currencySettings; - private readonly IPermissionService _permissionService; private readonly PluginMediator _pluginMediator; + private readonly ICommonServices _services; #endregion #region Constructors - public DiscountController(IDiscountService discountService, - ILocalizationService localizationService, ICurrencyService currencyService, - ICategoryService categoryService, IProductService productService, - IWebHelper webHelper, IDateTimeHelper dateTimeHelper, - ICustomerActivityService customerActivityService, CurrencySettings currencySettings, - IPermissionService permissionService, - PluginMediator pluginMediator) + public DiscountController( + IDiscountService discountService, + ICategoryService categoryService, + IProductService productService, + IDateTimeHelper dateTimeHelper, + ICustomerActivityService customerActivityService, + PluginMediator pluginMediator, + ICommonServices services) { this._discountService = discountService; - this._localizationService = localizationService; - this._currencyService = currencyService; this._categoryService = categoryService; this._productService = productService; - this._webHelper = webHelper; this._dateTimeHelper = dateTimeHelper; this._customerActivityService = customerActivityService; - this._currencySettings = currencySettings; - this._permissionService = permissionService; this._pluginMediator = pluginMediator; + this._services = services; } #endregion @@ -76,7 +63,7 @@ public string GetRequirementUrlInternal(IDiscountRequirementRule discountRequire if (discount == null) throw new ArgumentNullException("discount"); - string url = string.Format("{0}{1}", _webHelper.GetStoreLocation(), discountRequirementRule.GetConfigurationUrl(discount.Id, discountRequirementId)); + string url = string.Format("{0}{1}", _services.WebHelper.GetStoreLocation(), discountRequirementRule.GetConfigurationUrl(discount.Id, discountRequirementId)); return url; } @@ -86,9 +73,10 @@ private void PrepareDiscountModel(DiscountModel model, Discount discount) if (model == null) throw new ArgumentNullException("model"); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; - model.AvailableDiscountRequirementRules.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Promotions.Discounts.Requirements.DiscountRequirementType.Select"), Value = "" }); - var discountRules = _discountService.LoadAllDiscountRequirementRules(); + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; + model.AvailableDiscountRequirementRules.Add(new SelectListItem() { Text = _services.Localization.GetResource("Admin.Promotions.Discounts.Requirements.DiscountRequirementType.Select"), Value = "" }); + + var discountRules = _discountService.LoadAllDiscountRequirementRules(); foreach (var discountRule in discountRules) { model.AvailableDiscountRequirementRules.Add(new SelectListItem() @@ -156,7 +144,7 @@ public ActionResult Index() public ActionResult List() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discounts = _discountService.GetAllDiscounts(null, null, true); @@ -171,7 +159,7 @@ public ActionResult List() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult List(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discounts = _discountService.GetAllDiscounts(null, null, true); @@ -189,7 +177,7 @@ public ActionResult List(GridCommand command) //create public ActionResult Create() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var model = new DiscountModel(); @@ -202,7 +190,7 @@ public ActionResult Create() [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Create(DiscountModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); if (ModelState.IsValid) @@ -211,9 +199,9 @@ public ActionResult Create(DiscountModel model, bool continueEditing) _discountService.InsertDiscount(discount); //activity log - _customerActivityService.InsertActivity("AddNewDiscount", _localizationService.GetResource("ActivityLog.AddNewDiscount"), discount.Name); + _customerActivityService.InsertActivity("AddNewDiscount", _services.Localization.GetResource("ActivityLog.AddNewDiscount"), discount.Name); - NotifySuccess(_localizationService.GetResource("Admin.Promotions.Discounts.Added")); + NotifySuccess(_services.Localization.GetResource("Admin.Promotions.Discounts.Added")); return continueEditing ? RedirectToAction("Edit", new { id = discount.Id }) : RedirectToAction("List"); } @@ -225,7 +213,7 @@ public ActionResult Create(DiscountModel model, bool continueEditing) //edit public ActionResult Edit(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discount = _discountService.GetDiscountById(id); @@ -241,7 +229,7 @@ public ActionResult Edit(int id) [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Edit(DiscountModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discount = _discountService.GetDiscountById(model.Id); @@ -280,9 +268,9 @@ public ActionResult Edit(DiscountModel model, bool continueEditing) } //activity log - _customerActivityService.InsertActivity("EditDiscount", _localizationService.GetResource("ActivityLog.EditDiscount"), discount.Name); + _customerActivityService.InsertActivity("EditDiscount", _services.Localization.GetResource("ActivityLog.EditDiscount"), discount.Name); - NotifySuccess(_localizationService.GetResource("Admin.Promotions.Discounts.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Promotions.Discounts.Updated")); return continueEditing ? RedirectToAction("Edit", discount.Id) : RedirectToAction("List"); } @@ -295,7 +283,7 @@ public ActionResult Edit(DiscountModel model, bool continueEditing) [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discount = _discountService.GetDiscountById(id); @@ -317,9 +305,9 @@ public ActionResult DeleteConfirmed(int id) _productService.UpdateHasDiscountsApplied(product); //activity log - _customerActivityService.InsertActivity("DeleteDiscount", _localizationService.GetResource("ActivityLog.DeleteDiscount"), discount.Name); + _customerActivityService.InsertActivity("DeleteDiscount", _services.Localization.GetResource("ActivityLog.DeleteDiscount"), discount.Name); - NotifySuccess(_localizationService.GetResource("Admin.Promotions.Discounts.Deleted")); + NotifySuccess(_services.Localization.GetResource("Admin.Promotions.Discounts.Deleted")); return RedirectToAction("List"); } @@ -330,7 +318,7 @@ public ActionResult DeleteConfirmed(int id) [AcceptVerbs(HttpVerbs.Get)] public ActionResult GetDiscountRequirementConfigurationUrl(string systemName, int discountId, int? discountRequirementId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); if (String.IsNullOrEmpty(systemName)) @@ -350,7 +338,7 @@ public ActionResult GetDiscountRequirementConfigurationUrl(string systemName, in public ActionResult GetDiscountRequirementMetaInfo(int discountRequirementId, int discountId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discount = _discountService.GetDiscountById(discountId); @@ -373,7 +361,7 @@ public ActionResult GetDiscountRequirementMetaInfo(int discountRequirementId, in public ActionResult DeleteDiscountRequirement(int discountRequirementId, int discountId) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discount = _discountService.GetDiscountById(discountId); @@ -396,7 +384,7 @@ public ActionResult DeleteDiscountRequirement(int discountRequirementId, int dis [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult UsageHistoryList(int discountId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discount = _discountService.GetDiscountById(discountId); @@ -427,7 +415,7 @@ public ActionResult UsageHistoryList(int discountId, GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult UsageHistoryDelete(int discountId, int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageDiscounts)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageDiscounts)) return AccessDeniedView(); var discount = _discountService.GetDiscountById(discountId); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/GiftCardController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/GiftCardController.cs index 17f6cc0416..0d2a1ef483 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/GiftCardController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/GiftCardController.cs @@ -2,14 +2,12 @@ using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Orders; -using SmartStore.Core; -using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Logging; +using SmartStore.Services; using SmartStore.Services.Catalog; -using SmartStore.Services.Directory; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Messages; using SmartStore.Services.Orders; using SmartStore.Services.Security; @@ -29,35 +27,31 @@ public class GiftCardController : AdminControllerBase private readonly IWorkflowMessageService _workflowMessageService; private readonly IDateTimeHelper _dateTimeHelper; private readonly LocalizationSettings _localizationSettings; - private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; - private readonly ILocalizationService _localizationService; private readonly ILanguageService _languageService; private readonly ICustomerActivityService _customerActivityService; - private readonly IPermissionService _permissionService; + private readonly ICommonServices _services; #endregion #region Constructors public GiftCardController(IGiftCardService giftCardService, - IPriceFormatter priceFormatter, IWorkflowMessageService workflowMessageService, - IDateTimeHelper dateTimeHelper, LocalizationSettings localizationSettings, - ICurrencyService currencyService, CurrencySettings currencySettings, - ILocalizationService localizationService, ILanguageService languageService, - ICustomerActivityService customerActivityService, IPermissionService permissionService) + IPriceFormatter priceFormatter, + IWorkflowMessageService workflowMessageService, + IDateTimeHelper dateTimeHelper, + LocalizationSettings localizationSettings, + ILanguageService languageService, + ICustomerActivityService customerActivityService, + ICommonServices services) { this._giftCardService = giftCardService; this._priceFormatter = priceFormatter; this._workflowMessageService = workflowMessageService; this._dateTimeHelper = dateTimeHelper; this._localizationSettings = localizationSettings; - this._currencyService = currencyService; - this._currencySettings = currencySettings; - this._localizationService = localizationService; this._languageService = languageService; this._customerActivityService = customerActivityService; - this._permissionService = permissionService; + this._services = services; } #endregion @@ -72,7 +66,7 @@ public ActionResult Index() public ActionResult List() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); var model = new GiftCardListModel(); @@ -80,17 +74,17 @@ public ActionResult List() { Value = "0", Selected = true, - Text = _localizationService.GetResource("Common.All", logIfNotFound: false, defaultValue: "All") + Text = _services.Localization.GetResource("Common.All", logIfNotFound: false, defaultValue: "All") }); model.ActivatedList.Add(new SelectListItem() { Value = "1", - Text = _localizationService.GetResource("Common.Activated", logIfNotFound: false, defaultValue: "Activated") + Text = _services.Localization.GetResource("Common.Activated", logIfNotFound: false, defaultValue: "Activated") }); model.ActivatedList.Add(new SelectListItem() { Value = "2", - Text = _localizationService.GetResource("Common.Deactivated", logIfNotFound: false, defaultValue: "Deactivated") + Text = _services.Localization.GetResource("Common.Deactivated", logIfNotFound: false, defaultValue: "Deactivated") }); return View(model); } @@ -98,7 +92,7 @@ public ActionResult List() [GridAction(EnableCustomBinding = true)] public ActionResult GiftCardList(GridCommand command, GiftCardListModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); bool? isGiftCardActivated = null; @@ -127,11 +121,11 @@ public ActionResult GiftCardList(GridCommand command, GiftCardListModel model) public ActionResult Create() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); var model = new GiftCardModel(); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; return View(model); } @@ -139,7 +133,7 @@ public ActionResult Create() [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] public ActionResult Create(GiftCardModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); if (ModelState.IsValid) @@ -149,20 +143,21 @@ public ActionResult Create(GiftCardModel model, bool continueEditing) _giftCardService.InsertGiftCard(giftCard); //activity log - _customerActivityService.InsertActivity("AddNewGiftCard", _localizationService.GetResource("ActivityLog.AddNewGiftCard"), giftCard.GiftCardCouponCode); + _customerActivityService.InsertActivity("AddNewGiftCard", _services.Localization.GetResource("ActivityLog.AddNewGiftCard"), giftCard.GiftCardCouponCode); - NotifySuccess(_localizationService.GetResource("Admin.GiftCards.Added")); + NotifySuccess(_services.Localization.GetResource("Admin.GiftCards.Added")); return continueEditing ? RedirectToAction("Edit", new { id = giftCard.Id }) : RedirectToAction("List"); } //If we got this far, something failed, redisplay form - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; + return View(model); } public ActionResult Edit(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); var giftCard = _giftCardService.GetGiftCardById(id); @@ -175,7 +170,7 @@ public ActionResult Edit(int id) model.RemainingAmountStr = _priceFormatter.FormatPrice(giftCard.GetGiftCardRemainingAmount(), true, false); model.AmountStr = _priceFormatter.FormatPrice(giftCard.Amount, true, false); model.CreatedOn = _dateTimeHelper.ConvertToUserTime(giftCard.CreatedOnUtc, DateTimeKind.Utc); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; return View(model); } @@ -184,7 +179,7 @@ public ActionResult Edit(int id) [FormValueRequired("save", "save-continue")] public ActionResult Edit(GiftCardModel model, bool continueEditing) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); var giftCard = _giftCardService.GetGiftCardById(model.Id); @@ -193,7 +188,7 @@ public ActionResult Edit(GiftCardModel model, bool continueEditing) model.RemainingAmountStr = _priceFormatter.FormatPrice(giftCard.GetGiftCardRemainingAmount(), true, false); model.AmountStr = _priceFormatter.FormatPrice(giftCard.Amount, true, false); model.CreatedOn = _dateTimeHelper.ConvertToUserTime(giftCard.CreatedOnUtc, DateTimeKind.Utc); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; if (ModelState.IsValid) { @@ -201,9 +196,9 @@ public ActionResult Edit(GiftCardModel model, bool continueEditing) _giftCardService.UpdateGiftCard(giftCard); //activity log - _customerActivityService.InsertActivity("EditGiftCard", _localizationService.GetResource("ActivityLog.EditGiftCard"), giftCard.GiftCardCouponCode); + _customerActivityService.InsertActivity("EditGiftCard", _services.Localization.GetResource("ActivityLog.EditGiftCard"), giftCard.GiftCardCouponCode); - NotifySuccess(_localizationService.GetResource("Admin.GiftCards.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.GiftCards.Updated")); return continueEditing ? RedirectToAction("Edit", giftCard.Id) : RedirectToAction("List"); } @@ -221,7 +216,7 @@ public ActionResult GenerateCouponCode() [FormValueRequired("notifyRecipient")] public ActionResult NotifyRecipient(GiftCardModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); var giftCard = _giftCardService.GetGiftCardById(model.Id); @@ -231,7 +226,7 @@ public ActionResult NotifyRecipient(GiftCardModel model) model.RemainingAmountStr = _priceFormatter.FormatPrice(giftCard.GetGiftCardRemainingAmount(), true, false); model.AmountStr = _priceFormatter.FormatPrice(giftCard.Amount, true, false); model.CreatedOn = _dateTimeHelper.ConvertToUserTime(giftCard.CreatedOnUtc, DateTimeKind.Utc); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; try { @@ -272,7 +267,7 @@ public ActionResult NotifyRecipient(GiftCardModel model) [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); var giftCard = _giftCardService.GetGiftCardById(id); @@ -283,9 +278,9 @@ public ActionResult DeleteConfirmed(int id) _giftCardService.DeleteGiftCard(giftCard); //activity log - _customerActivityService.InsertActivity("DeleteGiftCard", _localizationService.GetResource("ActivityLog.DeleteGiftCard"), giftCard.GiftCardCouponCode); + _customerActivityService.InsertActivity("DeleteGiftCard", _services.Localization.GetResource("ActivityLog.DeleteGiftCard"), giftCard.GiftCardCouponCode); - NotifySuccess(_localizationService.GetResource("Admin.GiftCards.Deleted")); + NotifySuccess(_services.Localization.GetResource("Admin.GiftCards.Deleted")); return RedirectToAction("List"); } @@ -293,7 +288,7 @@ public ActionResult DeleteConfirmed(int id) [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult UsageHistoryList(int giftCardId, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageGiftCards)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageGiftCards)) return AccessDeniedView(); var giftCard = _giftCardService.GetGiftCardById(giftCardId); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs index c4157b9b0a..06d9801b8e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs @@ -187,7 +187,7 @@ protected void PrepareOrderDetailsModel(OrderModel model, Order order) throw new ArgumentNullException("model"); var store = _storeService.GetStoreById(order.StoreId); - var primaryStoreCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var primaryStoreCurrency = store.PrimaryStoreCurrency; model.Id = order.Id; model.OrderStatus = order.OrderStatus.GetLocalizedEnum(_localizationService, _workContext); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index c5fe38faec..feb12bf6c3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -649,7 +649,7 @@ protected void PrepareProductModel(ProductModel model, Product product, bool set model.ProductUrl = Url.RouteUrl("Product", new { SeName = product.GetSeName() }, Request.Url.Scheme); } - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; model.BaseDimensionIn = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId).Name; @@ -3004,7 +3004,7 @@ protected void PreparePrintableProductsModel(PrintableProductsModel model, IList model.MerchantContactData = contactSettings; string dimension = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId).Name; - string currencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + string currencyCode = store.PrimaryStoreCurrency.CurrencyCode; foreach (var product in products) { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs index 48bd56cf5f..e754b7f659 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs @@ -4,7 +4,6 @@ using System.Web.Mvc; using SmartStore.Admin.Models.Common; using SmartStore.Admin.Models.Settings; -using SmartStore.Core; using SmartStore.Core.Domain; using SmartStore.Core.Domain.Blogs; using SmartStore.Core.Domain.Catalog; @@ -22,8 +21,8 @@ using SmartStore.Core.Domain.Tax; using SmartStore.Core.Logging; using SmartStore.Core.Themes; +using SmartStore.Services; using SmartStore.Services.Common; -using SmartStore.Services.Configuration; using SmartStore.Services.Customers; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; @@ -31,7 +30,6 @@ using SmartStore.Services.Media; using SmartStore.Services.Orders; using SmartStore.Services.Security; -using SmartStore.Services.Stores; using SmartStore.Services.Tax; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; @@ -47,30 +45,24 @@ public partial class SettingController : AdminControllerBase { #region Fields - private readonly ISettingService _settingService; - private readonly ICountryService _countryService; - private readonly IStateProvinceService _stateProvinceService; - private readonly IAddressService _addressService; - private readonly ITaxCategoryService _taxCategoryService; - private readonly ICurrencyService _currencyService; - private readonly IPictureService _pictureService; - private readonly ILocalizationService _localizationService; - private readonly IDateTimeHelper _dateTimeHelper; - private readonly IOrderService _orderService; - private readonly IEncryptionService _encryptionService; - private readonly IThemeRegistry _themeRegistry; - private readonly ICustomerService _customerService; - private readonly ICustomerActivityService _customerActivityService; - private readonly IPermissionService _permissionService; - private readonly IWebHelper _webHelper; - private readonly IFulltextService _fulltextService; - private readonly IMaintenanceService _maintenanceService; - private readonly IStoreService _storeService; - private readonly IWorkContext _workContext; + private readonly ICountryService _countryService; + private readonly IStateProvinceService _stateProvinceService; + private readonly IAddressService _addressService; + private readonly ITaxCategoryService _taxCategoryService; + private readonly IPictureService _pictureService; + private readonly IDateTimeHelper _dateTimeHelper; + private readonly IOrderService _orderService; + private readonly IEncryptionService _encryptionService; + private readonly IThemeRegistry _themeRegistry; + private readonly ICustomerService _customerService; + private readonly ICustomerActivityService _customerActivityService; + private readonly IFulltextService _fulltextService; + private readonly IMaintenanceService _maintenanceService; private readonly IGenericAttributeService _genericAttributeService; private readonly ILocalizedEntityService _localizedEntityService; private readonly ILanguageService _languageService; private readonly IDeliveryTimeService _deliveryTimesService; + private readonly ICommonServices _services; private StoreDependingSettingHelper _storeDependingSettings; @@ -78,45 +70,44 @@ public partial class SettingController : AdminControllerBase #region Constructors - public SettingController(ISettingService settingService, - ICountryService countryService, IStateProvinceService stateProvinceService, - IAddressService addressService, ITaxCategoryService taxCategoryService, - ICurrencyService currencyService, IPictureService pictureService, - ILocalizationService localizationService, IDateTimeHelper dateTimeHelper, - IOrderService orderService, IEncryptionService encryptionService, - IThemeRegistry themeRegistry, ICustomerService customerService, - ICustomerActivityService customerActivityService, IPermissionService permissionService, - IWebHelper webHelper, IFulltextService fulltextService, - IMaintenanceService maintenanceService, IStoreService storeService, - IWorkContext workContext, IGenericAttributeService genericAttributeService, + public SettingController( + ICountryService countryService, + IStateProvinceService stateProvinceService, + IAddressService addressService, + ITaxCategoryService taxCategoryService, + IPictureService pictureService, + IDateTimeHelper dateTimeHelper, + IOrderService orderService, + IEncryptionService encryptionService, + IThemeRegistry themeRegistry, + ICustomerService customerService, + ICustomerActivityService customerActivityService, + IFulltextService fulltextService, + IMaintenanceService maintenanceService, + IGenericAttributeService genericAttributeService, ILocalizedEntityService localizedEntityService, ILanguageService languageService, - IDeliveryTimeService deliveryTimesService) + IDeliveryTimeService deliveryTimesService, + ICommonServices services) { - this._settingService = settingService; this._countryService = countryService; this._stateProvinceService = stateProvinceService; this._addressService = addressService; this._taxCategoryService = taxCategoryService; - this._currencyService = currencyService; this._pictureService = pictureService; - this._localizationService = localizationService; this._dateTimeHelper = dateTimeHelper; this._orderService = orderService; this._encryptionService = encryptionService; this._themeRegistry = themeRegistry; this._customerService = customerService; this._customerActivityService = customerActivityService; - this._permissionService = permissionService; - this._webHelper = webHelper; this._fulltextService = fulltextService; this._maintenanceService = maintenanceService; - this._storeService = storeService; - this._workContext = workContext; this._genericAttributeService = genericAttributeService; this._localizedEntityService = localizedEntityService; this._languageService = languageService; this._deliveryTimesService = deliveryTimesService; + this._services = services; } #endregion  @@ -136,13 +127,13 @@ private StoreDependingSettingHelper StoreDependingSettings [ChildActionOnly] public ActionResult StoreScopeConfiguration() { - var allStores = _storeService.GetAllStores(); + var allStores = _services.StoreService.GetAllStores(); if (allStores.Count < 2) return Content(""); var model = new StoreScopeConfigurationModel() { - StoreId = this.GetActiveStoreScopeConfiguration(_storeService, _workContext) + StoreId = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext) }; foreach (var store in allStores) @@ -157,7 +148,7 @@ public ActionResult StoreScopeConfiguration() model.AllStores.Insert(0, new SelectListItem() { - Text = _localizationService.GetResource("Admin.Common.StoresAll"), + Text = _services.Localization.GetResource("Admin.Common.StoresAll"), Selected = (0 == model.StoreId), Value = Url.Action("ChangeStoreScopeConfiguration", "Setting", new { storeid = 0, returnUrl = Request.RawUrl }) }); @@ -167,16 +158,16 @@ public ActionResult StoreScopeConfiguration() public ActionResult ChangeStoreScopeConfiguration(int storeid, string returnUrl = "") { - var store = _storeService.GetStoreById(storeid); + var store = _services.StoreService.GetStoreById(storeid); if (store != null || storeid == 0) { - _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, + _genericAttributeService.SaveAttribute(_services.WorkContext.CurrentCustomer, SystemCustomerAttributeNames.AdminAreaStoreScopeConfiguration, storeid); } //url referrer if (String.IsNullOrEmpty(returnUrl)) - returnUrl = _webHelper.GetUrlReferrer(); + returnUrl = _services.WebHelper.GetUrlReferrer(); //home page if (String.IsNullOrEmpty(returnUrl)) @@ -187,38 +178,38 @@ public ActionResult ChangeStoreScopeConfiguration(int storeid, string returnUrl public ActionResult Blog() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var blogSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var blogSettings = _services.Settings.LoadSetting(storeScope); var model = blogSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(blogSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(blogSettings, model, storeScope, _services.Settings); return View(model); } [HttpPost] public ActionResult Blog(BlogSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var blogSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var blogSettings = _services.Settings.LoadSetting(storeScope); blogSettings = model.ToEntity(blogSettings); - StoreDependingSettings.UpdateSettings(blogSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(blogSettings, form, storeScope, _services.Settings); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("Blog"); } @@ -227,15 +218,15 @@ public ActionResult Blog(BlogSettingsModel model, FormCollection form) public ActionResult Forum() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var forumSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var forumSettings = _services.Settings.LoadSetting(storeScope); var model = forumSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(forumSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(forumSettings, model, storeScope, _services.Settings); model.ForumEditorValues = forumSettings.ForumEditor.ToSelectList(); @@ -244,23 +235,23 @@ public ActionResult Forum() [HttpPost] public ActionResult Forum(ForumSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var forumSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var forumSettings = _services.Settings.LoadSetting(storeScope); forumSettings = model.ToEntity(forumSettings); - StoreDependingSettings.UpdateSettings(forumSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(forumSettings, form, storeScope, _services.Settings); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("Forum"); } @@ -269,38 +260,38 @@ public ActionResult Forum(ForumSettingsModel model, FormCollection form) public ActionResult News() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var newsSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var newsSettings = _services.Settings.LoadSetting(storeScope); var model = newsSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(newsSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(newsSettings, model, storeScope, _services.Settings); return View(model); } [HttpPost] public ActionResult News(NewsSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var newsSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var newsSettings = _services.Settings.LoadSetting(storeScope); newsSettings = model.ToEntity(newsSettings); - StoreDependingSettings.UpdateSettings(newsSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(newsSettings, form, storeScope, _services.Settings); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("News"); } @@ -309,18 +300,18 @@ public ActionResult News(NewsSettingsModel model, FormCollection form) public ActionResult Shipping() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var shippingSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var shippingSettings = _services.Settings.LoadSetting(storeScope); var model = shippingSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(shippingSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(shippingSettings, model, storeScope, _services.Settings); //shipping origin - if (storeScope > 0 && _settingService.SettingExists(shippingSettings, x => x.ShippingOriginAddressId, storeScope)) + if (storeScope > 0 && _services.Settings.SettingExists(shippingSettings, x => x.ShippingOriginAddressId, storeScope)) StoreDependingSettings.AddOverrideKey(shippingSettings, "ShippingOriginAddress"); var originAddress = shippingSettings.ShippingOriginAddressId > 0 @@ -351,7 +342,7 @@ public ActionResult Shipping() else { model.ShippingOriginAddress.AvailableStates.Add( - new SelectListItem() { Text = _localizationService.GetResource("Admin.Address.OtherNonUS"), Value = "0" } + new SelectListItem() { Text = _services.Localization.GetResource("Admin.Address.OtherNonUS"), Value = "0" } ); } @@ -365,22 +356,22 @@ public ActionResult Shipping() [HttpPost] public ActionResult Shipping(ShippingSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var shippingSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var shippingSettings = _services.Settings.LoadSetting(storeScope); shippingSettings = model.ToEntity(shippingSettings); - StoreDependingSettings.UpdateSettings(shippingSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(shippingSettings, form, storeScope, _services.Settings); bool shippingOriginAddressOverride = StoreDependingSettings.IsOverrideChecked(shippingSettings, "ShippingOriginAddress", form); if (shippingOriginAddressOverride || storeScope == 0) { //update address - var addressId = _settingService.SettingExists(shippingSettings, x => x.ShippingOriginAddressId, storeScope) ? shippingSettings.ShippingOriginAddressId : 0; + var addressId = _services.Settings.SettingExists(shippingSettings, x => x.ShippingOriginAddressId, storeScope) ? shippingSettings.ShippingOriginAddressId : 0; var originAddress = _addressService.GetAddressById(addressId) ?? new Core.Domain.Common.Address() { CreatedOnUtc = DateTime.UtcNow }; @@ -393,22 +384,22 @@ public ActionResult Shipping(ShippingSettingsModel model, FormCollection form) _addressService.InsertAddress(originAddress); shippingSettings.ShippingOriginAddressId = originAddress.Id; - _settingService.SaveSetting(shippingSettings, x => x.ShippingOriginAddressId, storeScope, false); + _services.Settings.SaveSetting(shippingSettings, x => x.ShippingOriginAddressId, storeScope, false); } else { _addressService.DeleteAddress(shippingSettings.ShippingOriginAddressId); - _settingService.DeleteSetting(shippingSettings, x => x.ShippingOriginAddressId, storeScope); + _services.Settings.DeleteSetting(shippingSettings, x => x.ShippingOriginAddressId, storeScope); } //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("Shipping"); } @@ -417,15 +408,15 @@ public ActionResult Shipping(ShippingSettingsModel model, FormCollection form) public ActionResult Tax() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var taxSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var taxSettings = _services.Settings.LoadSetting(storeScope); var model = taxSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(taxSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(taxSettings, model, storeScope, _services.Settings); model.TaxBasedOnValues = taxSettings.TaxBasedOn.ToSelectList(); model.TaxDisplayTypeValues = taxSettings.TaxDisplayType.ToSelectList(); @@ -464,7 +455,7 @@ public ActionResult Tax() else model.DefaultTaxAddress = new AddressModel(); - if (storeScope > 0 && _settingService.SettingExists(taxSettings, x => x.DefaultTaxAddressId, storeScope)) + if (storeScope > 0 && _services.Settings.SettingExists(taxSettings, x => x.DefaultTaxAddressId, storeScope)) StoreDependingSettings.AddOverrideKey(taxSettings, "DefaultTaxAddress"); foreach (var c in _countryService.GetAllCountries(true)) @@ -488,7 +479,7 @@ public ActionResult Tax() else { model.DefaultTaxAddress.AvailableStates.Add( - new SelectListItem() { Text = _localizationService.GetResource("Admin.Address.OtherNonUS"), Value = "0" } + new SelectListItem() { Text = _services.Localization.GetResource("Admin.Address.OtherNonUS"), Value = "0" } ); } model.DefaultTaxAddress.CountryEnabled = true; @@ -501,25 +492,25 @@ public ActionResult Tax() [HttpPost] public ActionResult Tax(TaxSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var taxSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var taxSettings = _services.Settings.LoadSetting(storeScope); taxSettings = model.ToEntity(taxSettings); - StoreDependingSettings.UpdateSettings(taxSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(taxSettings, form, storeScope, _services.Settings); bool defaultTaxAddressOverride = StoreDependingSettings.IsOverrideChecked(taxSettings, "DefaultTaxAddress", form); taxSettings.AllowCustomersToSelectTaxDisplayType = false; - _settingService.UpdateSetting(taxSettings, x => x.AllowCustomersToSelectTaxDisplayType, false, storeScope); + _services.Settings.UpdateSetting(taxSettings, x => x.AllowCustomersToSelectTaxDisplayType, false, storeScope); if (defaultTaxAddressOverride || storeScope == 0) { //update address - var addressId = _settingService.SettingExists(taxSettings, x => x.DefaultTaxAddressId, storeScope) ? taxSettings.DefaultTaxAddressId : 0; + var addressId = _services.Settings.SettingExists(taxSettings, x => x.DefaultTaxAddressId, storeScope) ? taxSettings.DefaultTaxAddressId : 0; var originAddress = _addressService.GetAddressById(addressId) ?? new Core.Domain.Common.Address() { CreatedOnUtc = DateTime.UtcNow }; @@ -532,22 +523,22 @@ public ActionResult Tax(TaxSettingsModel model, FormCollection form) _addressService.InsertAddress(originAddress); taxSettings.DefaultTaxAddressId = originAddress.Id; - _settingService.SaveSetting(taxSettings, x => x.DefaultTaxAddressId, storeScope, false); + _services.Settings.SaveSetting(taxSettings, x => x.DefaultTaxAddressId, storeScope, false); } else if (storeScope > 0) { _addressService.DeleteAddress(taxSettings.DefaultTaxAddressId); - _settingService.DeleteSetting(taxSettings, x => x.DefaultTaxAddressId, storeScope); + _services.Settings.DeleteSetting(taxSettings, x => x.DefaultTaxAddressId, storeScope); } //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("Tax"); } @@ -556,23 +547,23 @@ public ActionResult Tax(TaxSettingsModel model, FormCollection form) public ActionResult Catalog() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var catalogSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var catalogSettings = _services.Settings.LoadSetting(storeScope); var model = catalogSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(catalogSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(catalogSettings, model, storeScope, _services.Settings); model.AvailableSubCategoryDisplayTypes = catalogSettings.SubCategoryDisplayType.ToSelectList(); model.AvailableDefaultViewModes.Add( - new SelectListItem { Value = "grid", Text = _localizationService.GetResource("Common.Grid"), Selected = model.DefaultViewMode.IsCaseInsensitiveEqual("grid") } + new SelectListItem { Value = "grid", Text = _services.Localization.GetResource("Common.Grid"), Selected = model.DefaultViewMode.IsCaseInsensitiveEqual("grid") } ); model.AvailableDefaultViewModes.Add( - new SelectListItem { Value = "list", Text = _localizationService.GetResource("Common.List"), Selected = model.DefaultViewMode.IsCaseInsensitiveEqual("list") } + new SelectListItem { Value = "list", Text = _services.Localization.GetResource("Common.List"), Selected = model.DefaultViewMode.IsCaseInsensitiveEqual("list") } ); var deliveryTimes = _deliveryTimesService.GetAllDeliveryTimes(); @@ -591,23 +582,23 @@ public ActionResult Catalog() [HttpPost] public ActionResult Catalog(CatalogSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var catalogSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var catalogSettings = _services.Settings.LoadSetting(storeScope); catalogSettings = model.ToEntity(catalogSettings); - StoreDependingSettings.UpdateSettings(catalogSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(catalogSettings, form, storeScope, _services.Settings); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("Catalog"); } @@ -615,54 +606,56 @@ public ActionResult Catalog(CatalogSettingsModel model, FormCollection form) public ActionResult RewardPoints() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var rewardPointsSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var rewardPointsSettings = _services.Settings.LoadSetting(storeScope); + var store = (storeScope == 0 ? _services.StoreContext.CurrentStore : _services.StoreService.GetStoreById(storeScope)); + var model = rewardPointsSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(rewardPointsSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(rewardPointsSettings, model, storeScope, _services.Settings); - if (storeScope > 0 && (_settingService.SettingExists(rewardPointsSettings, x => x.PointsForPurchases_Amount, storeScope) || - _settingService.SettingExists(rewardPointsSettings, x => x.PointsForPurchases_Points, storeScope))) + if (storeScope > 0 && (_services.Settings.SettingExists(rewardPointsSettings, x => x.PointsForPurchases_Amount, storeScope) || + _services.Settings.SettingExists(rewardPointsSettings, x => x.PointsForPurchases_Points, storeScope))) { StoreDependingSettings.AddOverrideKey(rewardPointsSettings, "PointsForPurchases_OverrideForStore"); } - var currencySettings = _settingService.LoadSetting(storeScope); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = store.PrimaryStoreCurrency.CurrencyCode; return View(model); } + [HttpPost] public ActionResult RewardPoints(RewardPointsSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); if (ModelState.IsValid) { //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var rewardPointsSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var rewardPointsSettings = _services.Settings.LoadSetting(storeScope); rewardPointsSettings = model.ToEntity(rewardPointsSettings); - StoreDependingSettings.UpdateSettings(rewardPointsSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(rewardPointsSettings, form, storeScope, _services.Settings); bool pointsForPurchases = StoreDependingSettings.IsOverrideChecked(rewardPointsSettings, "PointsForPurchases", form); - _settingService.UpdateSetting(rewardPointsSettings, x => x.PointsForPurchases_Amount, pointsForPurchases, storeScope); - _settingService.UpdateSetting(rewardPointsSettings, x => x.PointsForPurchases_Points, pointsForPurchases, storeScope); + _services.Settings.UpdateSetting(rewardPointsSettings, x => x.PointsForPurchases_Amount, pointsForPurchases, storeScope); + _services.Settings.UpdateSetting(rewardPointsSettings, x => x.PointsForPurchases_Points, pointsForPurchases, storeScope); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); } else { @@ -679,18 +672,19 @@ public ActionResult RewardPoints(RewardPointsSettingsModel model, FormCollection public ActionResult Order() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var orderSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var orderSettings = _services.Settings.LoadSetting(storeScope); + var store = (storeScope == 0 ? _services.StoreContext.CurrentStore : _services.StoreService.GetStoreById(storeScope)); + var model = orderSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(orderSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(orderSettings, model, storeScope, _services.Settings); - var currencySettings = _settingService.LoadSetting(storeScope); - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(currencySettings.PrimaryStoreCurrencyId).CurrencyCode; + model.PrimaryStoreCurrencyCode = store.PrimaryStoreCurrency.CurrencyCode; //gift card activation/deactivation model.GiftCards_Activated_OrderStatuses = OrderStatus.Pending.ToSelectList(false).ToList(); @@ -710,20 +704,20 @@ public ActionResult Order() [HttpPost] public ActionResult Order(OrderSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); if (ModelState.IsValid) { //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var orderSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var orderSettings = _services.Settings.LoadSetting(storeScope); orderSettings = model.ToEntity(orderSettings); - StoreDependingSettings.UpdateSettings(orderSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(orderSettings, form, storeScope, _services.Settings); - _settingService.SaveSetting(orderSettings, x => x.ReturnRequestActions, 0, false); - _settingService.SaveSetting(orderSettings, x => x.ReturnRequestReasons, 0, false); + _services.Settings.SaveSetting(orderSettings, x => x.ReturnRequestActions, 0, false); + _services.Settings.SaveSetting(orderSettings, x => x.ReturnRequestReasons, 0, false); foreach (var localized in model.Locales) { @@ -732,17 +726,17 @@ public ActionResult Order(OrderSettingsModel model, FormCollection form) } if (model.GiftCards_Activated_OrderStatusId.HasValue) - _settingService.SaveSetting(orderSettings, x => x.GiftCards_Activated_OrderStatusId, 0, false); + _services.Settings.SaveSetting(orderSettings, x => x.GiftCards_Activated_OrderStatusId, 0, false); else - _settingService.DeleteSetting(orderSettings, x => x.GiftCards_Activated_OrderStatusId); + _services.Settings.DeleteSetting(orderSettings, x => x.GiftCards_Activated_OrderStatusId); if (model.GiftCards_Deactivated_OrderStatusId.HasValue) - _settingService.SaveSetting(orderSettings, x => x.GiftCards_Deactivated_OrderStatusId, 0, false); + _services.Settings.SaveSetting(orderSettings, x => x.GiftCards_Deactivated_OrderStatusId, 0, false); else - _settingService.DeleteSetting(orderSettings, x => x.GiftCards_Deactivated_OrderStatusId); + _services.Settings.DeleteSetting(orderSettings, x => x.GiftCards_Deactivated_OrderStatusId); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //order ident if (model.OrderIdent.HasValue) @@ -758,9 +752,9 @@ public ActionResult Order(OrderSettingsModel model, FormCollection form) } //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); } else { @@ -779,15 +773,15 @@ public ActionResult Order(OrderSettingsModel model, FormCollection form) public ActionResult ShoppingCart() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var shoppingCartSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var shoppingCartSettings = _services.Settings.LoadSetting(storeScope); var model = shoppingCartSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(shoppingCartSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(shoppingCartSettings, model, storeScope, _services.Settings); return View(model); @@ -795,23 +789,23 @@ public ActionResult ShoppingCart() [HttpPost] public ActionResult ShoppingCart(ShoppingCartSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var shoppingCartSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var shoppingCartSettings = _services.Settings.LoadSetting(storeScope); shoppingCartSettings = model.ToEntity(shoppingCartSettings); - StoreDependingSettings.UpdateSettings(shoppingCartSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(shoppingCartSettings, form, storeScope, _services.Settings); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("ShoppingCart"); } @@ -820,32 +814,32 @@ public ActionResult ShoppingCart(ShoppingCartSettingsModel model, FormCollection public ActionResult Media() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var mediaSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var mediaSettings = _services.Settings.LoadSetting(storeScope); var model = mediaSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(mediaSettings, model, storeScope, _settingService); + StoreDependingSettings.GetOverrideKeys(mediaSettings, model, storeScope, _services.Settings); model.PicturesStoredIntoDatabase = _pictureService.StoreInDb; var resKey = "Admin.Configuration.Settings.Media.PictureZoomType."; model.AvailablePictureZoomTypes.Add(new SelectListItem { - Text = _localizationService.GetResource(resKey + "Window"), + Text = _services.Localization.GetResource(resKey + "Window"), Value = "window", Selected = model.PictureZoomType.Equals("window") }); model.AvailablePictureZoomTypes.Add(new SelectListItem { - Text = _localizationService.GetResource(resKey + "Inner"), + Text = _services.Localization.GetResource(resKey + "Inner"), Value = "inner", Selected = model.PictureZoomType.Equals("inner") }); model.AvailablePictureZoomTypes.Add(new SelectListItem { - Text = _localizationService.GetResource(resKey + "Lens"), + Text = _services.Localization.GetResource(resKey + "Lens"), Value = "lens", Selected = model.PictureZoomType.Equals("lens") }); @@ -856,38 +850,38 @@ public ActionResult Media() [FormValueRequired("save")] public ActionResult Media(MediaSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var mediaSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var mediaSettings = _services.Settings.LoadSetting(storeScope); mediaSettings = model.ToEntity(mediaSettings); - StoreDependingSettings.UpdateSettings(mediaSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(mediaSettings, form, storeScope, _services.Settings); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("Media"); } [HttpPost, ActionName("Media")] [FormValueRequired("change-picture-storage")] public ActionResult ChangePictureStorage() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); _pictureService.StoreInDb = !_pictureService.StoreInDb; //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("Media"); } @@ -895,26 +889,26 @@ public ActionResult ChangePictureStorage() public ActionResult CustomerUser() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); StoreDependingSettings.CreateViewDataObject(storeScope); - var customerSettings = _settingService.LoadSetting(storeScope); - var addressSettings = _settingService.LoadSetting(storeScope); - var dateTimeSettings = _settingService.LoadSetting(storeScope); - var externalAuthenticationSettings = _settingService.LoadSetting(storeScope); + var customerSettings = _services.Settings.LoadSetting(storeScope); + var addressSettings = _services.Settings.LoadSetting(storeScope); + var dateTimeSettings = _services.Settings.LoadSetting(storeScope); + var externalAuthenticationSettings = _services.Settings.LoadSetting(storeScope); //merge settings var model = new CustomerUserSettingsModel(); model.CustomerSettings = customerSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(customerSettings, model.CustomerSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(customerSettings, model.CustomerSettings, storeScope, _services.Settings, false); model.AddressSettings = addressSettings.ToModel(); - StoreDependingSettings.GetOverrideKeys(addressSettings, model.AddressSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(addressSettings, model.AddressSettings, storeScope, _services.Settings, false); model.DateTimeSettings.AllowCustomersToSetTimeZone = dateTimeSettings.AllowCustomersToSetTimeZone; model.DateTimeSettings.DefaultStoreTimeZoneId = _dateTimeHelper.DefaultStoreTimeZone.Id; @@ -928,52 +922,52 @@ public ActionResult CustomerUser() }); } - StoreDependingSettings.GetOverrideKeys(dateTimeSettings, model.DateTimeSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(dateTimeSettings, model.DateTimeSettings, storeScope, _services.Settings, false); model.ExternalAuthenticationSettings.AutoRegisterEnabled = externalAuthenticationSettings.AutoRegisterEnabled; - StoreDependingSettings.GetOverrideKeys(externalAuthenticationSettings, model.ExternalAuthenticationSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(externalAuthenticationSettings, model.ExternalAuthenticationSettings, storeScope, _services.Settings, false); return View(model); } [HttpPost] public ActionResult CustomerUser(CustomerUserSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); - var customerSettings = _settingService.LoadSetting(storeScope); + var customerSettings = _services.Settings.LoadSetting(storeScope); customerSettings = model.CustomerSettings.ToEntity(customerSettings); - StoreDependingSettings.UpdateSettings(customerSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(customerSettings, form, storeScope, _services.Settings); - _settingService.SaveSetting(customerSettings, x => x.DefaultPasswordFormat, 0, false); + _services.Settings.SaveSetting(customerSettings, x => x.DefaultPasswordFormat, 0, false); - var addressSettings = _settingService.LoadSetting(storeScope); + var addressSettings = _services.Settings.LoadSetting(storeScope); addressSettings = model.AddressSettings.ToEntity(addressSettings); - StoreDependingSettings.UpdateSettings(addressSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(addressSettings, form, storeScope, _services.Settings); - var dateTimeSettings = _settingService.LoadSetting(storeScope); + var dateTimeSettings = _services.Settings.LoadSetting(storeScope); dateTimeSettings.DefaultStoreTimeZoneId = model.DateTimeSettings.DefaultStoreTimeZoneId; dateTimeSettings.AllowCustomersToSetTimeZone = model.DateTimeSettings.AllowCustomersToSetTimeZone; - StoreDependingSettings.UpdateSettings(dateTimeSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(dateTimeSettings, form, storeScope, _services.Settings); - var externalAuthenticationSettings = _settingService.LoadSetting(storeScope); + var externalAuthenticationSettings = _services.Settings.LoadSetting(storeScope); externalAuthenticationSettings.AutoRegisterEnabled = model.ExternalAuthenticationSettings.AutoRegisterEnabled; - StoreDependingSettings.UpdateSettings(externalAuthenticationSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(externalAuthenticationSettings, form, storeScope, _services.Settings); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("CustomerUser"); } @@ -984,26 +978,26 @@ public ActionResult CustomerUser(CustomerUserSettingsModel model, FormCollection public ActionResult GeneralCommon() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //set page timeout to 5 minutes this.Server.ScriptTimeout = 300; var model = new GeneralCommonSettingsModel(); - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); StoreDependingSettings.CreateViewDataObject(storeScope); //store information - var storeInformationSettings = _settingService.LoadSetting(storeScope); + var storeInformationSettings = _services.Settings.LoadSetting(storeScope); model.StoreInformationSettings.StoreClosed = storeInformationSettings.StoreClosed; model.StoreInformationSettings.StoreClosedAllowForAdmins = storeInformationSettings.StoreClosedAllowForAdmins; - StoreDependingSettings.GetOverrideKeys(storeInformationSettings, model.StoreInformationSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(storeInformationSettings, model.StoreInformationSettings, storeScope, _services.Settings, false); //seo settings - var seoSettings = _settingService.LoadSetting(storeScope); + var seoSettings = _services.Settings.LoadSetting(storeScope); model.SeoSettings.PageTitleSeoAdjustment = seoSettings.PageTitleSeoAdjustment; model.SeoSettings.PageTitleSeparator = seoSettings.PageTitleSeparator; model.SeoSettings.DefaultTitle = seoSettings.DefaultTitle; @@ -1013,10 +1007,10 @@ public ActionResult GeneralCommon() model.SeoSettings.CanonicalUrlsEnabled = seoSettings.CanonicalUrlsEnabled; model.SeoSettings.CanonicalHostNameRule = seoSettings.CanonicalHostNameRule; - StoreDependingSettings.GetOverrideKeys(seoSettings, model.SeoSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(seoSettings, model.SeoSettings, storeScope, _services.Settings, false); //security settings - var securitySettings = _settingService.LoadSetting(storeScope); + var securitySettings = _services.Settings.LoadSetting(storeScope); model.SecuritySettings.EncryptionKey = securitySettings.EncryptionKey; if (securitySettings.AdminAreaAllowedIpAddresses != null) { @@ -1029,7 +1023,7 @@ public ActionResult GeneralCommon() } model.SecuritySettings.HideAdminMenuItemsBasedOnPermissions = securitySettings.HideAdminMenuItemsBasedOnPermissions; - var captchaSettings = _settingService.LoadSetting(storeScope); + var captchaSettings = _services.Settings.LoadSetting(storeScope); model.CaptchaSettings.Enabled = captchaSettings.Enabled; model.CaptchaSettings.ShowOnLoginPage = captchaSettings.ShowOnLoginPage; model.CaptchaSettings.ShowOnRegistrationPage = captchaSettings.ShowOnRegistrationPage; @@ -1043,18 +1037,18 @@ public ActionResult GeneralCommon() model.CaptchaSettings.ReCaptchaPublicKey = captchaSettings.ReCaptchaPublicKey; model.CaptchaSettings.ReCaptchaPrivateKey = captchaSettings.ReCaptchaPrivateKey; - StoreDependingSettings.GetOverrideKeys(captchaSettings, model.CaptchaSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(captchaSettings, model.CaptchaSettings, storeScope, _services.Settings, false); //PDF settings - var pdfSettings = _settingService.LoadSetting(storeScope); + var pdfSettings = _services.Settings.LoadSetting(storeScope); model.PdfSettings.Enabled = pdfSettings.Enabled; model.PdfSettings.LetterPageSizeEnabled = pdfSettings.LetterPageSizeEnabled; model.PdfSettings.LogoPictureId = pdfSettings.LogoPictureId; - StoreDependingSettings.GetOverrideKeys(pdfSettings, model.PdfSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(pdfSettings, model.PdfSettings, storeScope, _services.Settings, false); //localization - var localizationSettings = _settingService.LoadSetting(storeScope); + var localizationSettings = _services.Settings.LoadSetting(storeScope); model.LocalizationSettings.UseImagesForLanguageSelection = localizationSettings.UseImagesForLanguageSelection; model.LocalizationSettings.SeoFriendlyUrlsForLanguagesEnabled = localizationSettings.SeoFriendlyUrlsForLanguagesEnabled; model.LocalizationSettings.LoadAllLocaleRecordsOnStartup = localizationSettings.LoadAllLocaleRecordsOnStartup; @@ -1062,17 +1056,17 @@ public ActionResult GeneralCommon() model.LocalizationSettings.InvalidLanguageRedirectBehaviour = localizationSettings.InvalidLanguageRedirectBehaviour; model.LocalizationSettings.DetectBrowserUserLanguage = localizationSettings.DetectBrowserUserLanguage; - StoreDependingSettings.GetOverrideKeys(localizationSettings, model.LocalizationSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(localizationSettings, model.LocalizationSettings, storeScope, _services.Settings, false); //full-text support - var commonSettings = _settingService.LoadSetting(storeScope); + var commonSettings = _services.Settings.LoadSetting(storeScope); model.FullTextSettings.Supported = _fulltextService.IsFullTextSupported(); model.FullTextSettings.Enabled = commonSettings.UseFullTextSearch; model.FullTextSettings.SearchMode = commonSettings.FullTextMode; model.FullTextSettings.SearchModeValues = commonSettings.FullTextMode.ToSelectList(); //company information - var companySettings = _settingService.LoadSetting(storeScope); + var companySettings = _services.Settings.LoadSetting(storeScope); model.CompanyInformationSettings.CompanyName = companySettings.CompanyName; model.CompanyInformationSettings.Salutation = companySettings.Salutation; model.CompanyInformationSettings.Title = companySettings.Title; @@ -1090,7 +1084,7 @@ public ActionResult GeneralCommon() model.CompanyInformationSettings.CommercialRegister = companySettings.CommercialRegister; model.CompanyInformationSettings.TaxNumber = companySettings.TaxNumber; - StoreDependingSettings.GetOverrideKeys(companySettings, model.CompanyInformationSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(companySettings, model.CompanyInformationSettings, storeScope, _services.Settings, false); foreach (var c in _countryService.GetAllCountries(true)) { @@ -1118,7 +1112,7 @@ public ActionResult GeneralCommon() ResToSelectListItem("Admin.Configuration.Settings.GeneralCommon.CompanyInformationSettings.ManagementDescriptions.ManagingPartner")); //contact data - var contactDataSettings = _settingService.LoadSetting(storeScope); + var contactDataSettings = _services.Settings.LoadSetting(storeScope); model.ContactDataSettings.CompanyTelephoneNumber = contactDataSettings.CompanyTelephoneNumber; model.ContactDataSettings.HotlineTelephoneNumber = contactDataSettings.HotlineTelephoneNumber; model.ContactDataSettings.MobileTelephoneNumber = contactDataSettings.MobileTelephoneNumber; @@ -1128,10 +1122,10 @@ public ActionResult GeneralCommon() model.ContactDataSettings.SupportEmailAddress = contactDataSettings.SupportEmailAddress; model.ContactDataSettings.ContactEmailAddress = contactDataSettings.ContactEmailAddress; - StoreDependingSettings.GetOverrideKeys(contactDataSettings, model.ContactDataSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(contactDataSettings, model.ContactDataSettings, storeScope, _services.Settings, false); //bank connection - var bankConnectionSettings = _settingService.LoadSetting(storeScope); + var bankConnectionSettings = _services.Settings.LoadSetting(storeScope); model.BankConnectionSettings.Bankname = bankConnectionSettings.Bankname; model.BankConnectionSettings.Bankcode = bankConnectionSettings.Bankcode; model.BankConnectionSettings.AccountNumber = bankConnectionSettings.AccountNumber; @@ -1139,10 +1133,10 @@ public ActionResult GeneralCommon() model.BankConnectionSettings.Iban = bankConnectionSettings.Iban; model.BankConnectionSettings.Bic = bankConnectionSettings.Bic; - StoreDependingSettings.GetOverrideKeys(bankConnectionSettings, model.BankConnectionSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(bankConnectionSettings, model.BankConnectionSettings, storeScope, _services.Settings, false); //social - var socialSettings = _settingService.LoadSetting(storeScope); + var socialSettings = _services.Settings.LoadSetting(storeScope); model.SocialSettings.ShowSocialLinksInFooter = socialSettings.ShowSocialLinksInFooter; model.SocialSettings.FacebookLink = socialSettings.FacebookLink; model.SocialSettings.GooglePlusLink = socialSettings.GooglePlusLink; @@ -1150,14 +1144,14 @@ public ActionResult GeneralCommon() model.SocialSettings.PinterestLink = socialSettings.PinterestLink; model.SocialSettings.YoutubeLink = socialSettings.YoutubeLink; - StoreDependingSettings.GetOverrideKeys(socialSettings, model.SocialSettings, storeScope, _settingService, false); + StoreDependingSettings.GetOverrideKeys(socialSettings, model.SocialSettings, storeScope, _services.Settings, false); return View(model); } private SelectListItem ResToSelectListItem(string resourceKey) { - string value = _localizationService.GetResource(resourceKey).EmptyNull(); + string value = _services.Localization.GetResource(resourceKey).EmptyNull(); return new SelectListItem() { Text = value, Value = value }; } @@ -1165,21 +1159,21 @@ private SelectListItem ResToSelectListItem(string resourceKey) [FormValueRequired("save")] public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollection form) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); //store information - var storeInformationSettings = _settingService.LoadSetting(storeScope); + var storeInformationSettings = _services.Settings.LoadSetting(storeScope); storeInformationSettings.StoreClosed = model.StoreInformationSettings.StoreClosed; storeInformationSettings.StoreClosedAllowForAdmins = model.StoreInformationSettings.StoreClosedAllowForAdmins; - StoreDependingSettings.UpdateSettings(storeInformationSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(storeInformationSettings, form, storeScope, _services.Settings); //seo settings - var seoSettings = _settingService.LoadSetting(storeScope); + var seoSettings = _services.Settings.LoadSetting(storeScope); seoSettings.PageTitleSeparator = model.SeoSettings.PageTitleSeparator; seoSettings.PageTitleSeoAdjustment = model.SeoSettings.PageTitleSeoAdjustment; seoSettings.DefaultTitle = model.SeoSettings.DefaultTitle; @@ -1189,10 +1183,10 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti seoSettings.CanonicalUrlsEnabled = model.SeoSettings.CanonicalUrlsEnabled; seoSettings.CanonicalHostNameRule = model.SeoSettings.CanonicalHostNameRule; - StoreDependingSettings.UpdateSettings(seoSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(seoSettings, form, storeScope, _services.Settings); //security settings - var securitySettings = _settingService.LoadSetting(storeScope); + var securitySettings = _services.Settings.LoadSetting(storeScope); if (securitySettings.AdminAreaAllowedIpAddresses == null) securitySettings.AdminAreaAllowedIpAddresses = new List(); securitySettings.AdminAreaAllowedIpAddresses.Clear(); @@ -1205,9 +1199,9 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti } } securitySettings.HideAdminMenuItemsBasedOnPermissions = model.SecuritySettings.HideAdminMenuItemsBasedOnPermissions; - _settingService.SaveSetting(securitySettings); + _services.Settings.SaveSetting(securitySettings); - var captchaSettings = _settingService.LoadSetting(storeScope); + var captchaSettings = _services.Settings.LoadSetting(storeScope); captchaSettings.Enabled = model.CaptchaSettings.Enabled; captchaSettings.ShowOnLoginPage = model.CaptchaSettings.ShowOnLoginPage; captchaSettings.ShowOnRegistrationPage = model.CaptchaSettings.ShowOnRegistrationPage; @@ -1221,51 +1215,51 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti captchaSettings.ReCaptchaPublicKey = model.CaptchaSettings.ReCaptchaPublicKey; captchaSettings.ReCaptchaPrivateKey = model.CaptchaSettings.ReCaptchaPrivateKey; - StoreDependingSettings.UpdateSettings(captchaSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(captchaSettings, form, storeScope, _services.Settings); if (captchaSettings.Enabled && (String.IsNullOrWhiteSpace(captchaSettings.ReCaptchaPublicKey) || String.IsNullOrWhiteSpace(captchaSettings.ReCaptchaPrivateKey))) { - NotifyError(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.CaptchaEnabledNoKeys")); + NotifyError(_services.Localization.GetResource("Admin.Configuration.Settings.GeneralCommon.CaptchaEnabledNoKeys")); } //PDF settings - var pdfSettings = _settingService.LoadSetting(storeScope); + var pdfSettings = _services.Settings.LoadSetting(storeScope); pdfSettings.Enabled = model.PdfSettings.Enabled; pdfSettings.LetterPageSizeEnabled = model.PdfSettings.LetterPageSizeEnabled; pdfSettings.LogoPictureId = model.PdfSettings.LogoPictureId; - StoreDependingSettings.UpdateSettings(pdfSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(pdfSettings, form, storeScope, _services.Settings); //localization settings - var localizationSettings = _settingService.LoadSetting(storeScope); + var localizationSettings = _services.Settings.LoadSetting(storeScope); localizationSettings.LoadAllLocaleRecordsOnStartup = model.LocalizationSettings.LoadAllLocaleRecordsOnStartup; localizationSettings.DefaultLanguageRedirectBehaviour = model.LocalizationSettings.DefaultLanguageRedirectBehaviour; localizationSettings.InvalidLanguageRedirectBehaviour = model.LocalizationSettings.InvalidLanguageRedirectBehaviour; localizationSettings.UseImagesForLanguageSelection = model.LocalizationSettings.UseImagesForLanguageSelection; localizationSettings.DetectBrowserUserLanguage = model.LocalizationSettings.DetectBrowserUserLanguage; - StoreDependingSettings.UpdateSettings(localizationSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(localizationSettings, form, storeScope, _services.Settings); - _settingService.SaveSetting(localizationSettings, x => x.LoadAllLocaleRecordsOnStartup, 0, false); - _settingService.SaveSetting(localizationSettings, x => x.DefaultLanguageRedirectBehaviour, 0, false); - _settingService.SaveSetting(localizationSettings, x => x.InvalidLanguageRedirectBehaviour, 0, false); + _services.Settings.SaveSetting(localizationSettings, x => x.LoadAllLocaleRecordsOnStartup, 0, false); + _services.Settings.SaveSetting(localizationSettings, x => x.DefaultLanguageRedirectBehaviour, 0, false); + _services.Settings.SaveSetting(localizationSettings, x => x.InvalidLanguageRedirectBehaviour, 0, false); if (localizationSettings.SeoFriendlyUrlsForLanguagesEnabled != model.LocalizationSettings.SeoFriendlyUrlsForLanguagesEnabled) { localizationSettings.SeoFriendlyUrlsForLanguagesEnabled = model.LocalizationSettings.SeoFriendlyUrlsForLanguagesEnabled; - _settingService.SaveSetting(localizationSettings, x => x.SeoFriendlyUrlsForLanguagesEnabled, 0, false); + _services.Settings.SaveSetting(localizationSettings, x => x.SeoFriendlyUrlsForLanguagesEnabled, 0, false); System.Web.Routing.RouteTable.Routes.ClearSeoFriendlyUrlsCachedValueForRoutes(); // clear cached values of routes } //full-text - var commonSettings = _settingService.LoadSetting(storeScope); + var commonSettings = _services.Settings.LoadSetting(storeScope); commonSettings.FullTextMode = model.FullTextSettings.SearchMode; - _settingService.SaveSetting(commonSettings); + _services.Settings.SaveSetting(commonSettings); //company information - var companySettings = _settingService.LoadSetting(storeScope); + var companySettings = _services.Settings.LoadSetting(storeScope); companySettings.CompanyName = model.CompanyInformationSettings.CompanyName; companySettings.Salutation = model.CompanyInformationSettings.Salutation; companySettings.Title = model.CompanyInformationSettings.Title; @@ -1287,10 +1281,10 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti companySettings.CommercialRegister = model.CompanyInformationSettings.CommercialRegister; companySettings.TaxNumber = model.CompanyInformationSettings.TaxNumber; - StoreDependingSettings.UpdateSettings(companySettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(companySettings, form, storeScope, _services.Settings); //contact data - var contactDataSettings = _settingService.LoadSetting(storeScope); + var contactDataSettings = _services.Settings.LoadSetting(storeScope); contactDataSettings.CompanyTelephoneNumber = model.ContactDataSettings.CompanyTelephoneNumber; contactDataSettings.HotlineTelephoneNumber = model.ContactDataSettings.HotlineTelephoneNumber; contactDataSettings.MobileTelephoneNumber = model.ContactDataSettings.MobileTelephoneNumber; @@ -1300,10 +1294,10 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti contactDataSettings.SupportEmailAddress = model.ContactDataSettings.SupportEmailAddress; contactDataSettings.ContactEmailAddress = model.ContactDataSettings.ContactEmailAddress; - StoreDependingSettings.UpdateSettings(contactDataSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(contactDataSettings, form, storeScope, _services.Settings); //bank connection - var bankConnectionSettings = _settingService.LoadSetting(storeScope); + var bankConnectionSettings = _services.Settings.LoadSetting(storeScope); bankConnectionSettings.Bankname = model.BankConnectionSettings.Bankname; bankConnectionSettings.Bankcode = model.BankConnectionSettings.Bankcode; bankConnectionSettings.AccountNumber = model.BankConnectionSettings.AccountNumber; @@ -1311,10 +1305,10 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti bankConnectionSettings.Iban = model.BankConnectionSettings.Iban; bankConnectionSettings.Bic = model.BankConnectionSettings.Bic; - StoreDependingSettings.UpdateSettings(bankConnectionSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(bankConnectionSettings, form, storeScope, _services.Settings); //social - var socialSettings = _settingService.LoadSetting(storeScope); + var socialSettings = _services.Settings.LoadSetting(storeScope); socialSettings.ShowSocialLinksInFooter = model.SocialSettings.ShowSocialLinksInFooter; socialSettings.FacebookLink = model.SocialSettings.FacebookLink; socialSettings.GooglePlusLink = model.SocialSettings.GooglePlusLink; @@ -1322,29 +1316,29 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti socialSettings.PinterestLink = model.SocialSettings.PinterestLink; socialSettings.YoutubeLink = model.SocialSettings.YoutubeLink; - StoreDependingSettings.UpdateSettings(socialSettings, form, storeScope, _settingService); + StoreDependingSettings.UpdateSettings(socialSettings, form, storeScope, _services.Settings); //now clear settings cache - _settingService.ClearCache(); + _services.Settings.ClearCache(); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Updated")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Updated")); return RedirectToAction("GeneralCommon"); } [HttpPost, ActionName("GeneralCommon")] [FormValueRequired("changeencryptionkey")] public ActionResult ChangeEnryptionKey(GeneralCommonSettingsModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); //set page timeout to 5 minutes this.Server.ScriptTimeout = 300; - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var securitySettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var securitySettings = _services.Settings.LoadSetting(storeScope); try { @@ -1355,11 +1349,11 @@ public ActionResult ChangeEnryptionKey(GeneralCommonSettingsModel model) var newEncryptionPrivateKey = model.SecuritySettings.EncryptionKey; if (String.IsNullOrEmpty(newEncryptionPrivateKey) || newEncryptionPrivateKey.Length != 16) - throw new SmartException(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.TooShort")); + throw new SmartException(_services.Localization.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.TooShort")); string oldEncryptionPrivateKey = securitySettings.EncryptionKey; if (oldEncryptionPrivateKey == newEncryptionPrivateKey) - throw new SmartException(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.TheSame")); + throw new SmartException(_services.Localization.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.TheSame")); //update encrypted order info var orders = _orderService.LoadAllOrders(); @@ -1431,8 +1425,8 @@ public ActionResult ChangeEnryptionKey(GeneralCommonSettingsModel model) } securitySettings.EncryptionKey = newEncryptionPrivateKey; - _settingService.SaveSetting(securitySettings); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.Changed")); + _services.Settings.SaveSetting(securitySettings); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Settings.GeneralCommon.EncryptionKey.Changed")); } catch (Exception exc) { @@ -1444,34 +1438,34 @@ public ActionResult ChangeEnryptionKey(GeneralCommonSettingsModel model) [FormValueRequired("togglefulltext")] public ActionResult ToggleFullText(GeneralCommonSettingsModel model) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var commonSettings = _settingService.LoadSetting(storeScope); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var commonSettings = _services.Settings.LoadSetting(storeScope); try { if (! _fulltextService.IsFullTextSupported()) - throw new SmartException(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.FullTextSettings.NotSupported")); + throw new SmartException(_services.Localization.GetResource("Admin.Configuration.Settings.GeneralCommon.FullTextSettings.NotSupported")); if (commonSettings.UseFullTextSearch) { _fulltextService.DisableFullText(); commonSettings.UseFullTextSearch = false; - _settingService.SaveSetting(commonSettings, storeScope); + _services.Settings.SaveSetting(commonSettings, storeScope); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.FullTextSettings.Disabled")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Settings.GeneralCommon.FullTextSettings.Disabled")); } else { _fulltextService.EnableFullText(); commonSettings.UseFullTextSearch = true; - _settingService.SaveSetting(commonSettings, storeScope); + _services.Settings.SaveSetting(commonSettings, storeScope); - NotifySuccess(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.FullTextSettings.Enabled")); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Settings.GeneralCommon.FullTextSettings.Enabled")); } } catch (Exception exc) @@ -1487,7 +1481,7 @@ public ActionResult ToggleFullText(GeneralCommonSettingsModel model) //all settings public ActionResult AllSettings() { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); return View(); @@ -1496,13 +1490,13 @@ public ActionResult AllSettings() [HttpPost, GridAction(EnableCustomBinding = true)] public ActionResult AllSettings(GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); - var stores = _storeService.GetAllStores(); - string allStoresString = _localizationService.GetResource("Admin.Common.StoresAll"); + var stores = _services.StoreService.GetAllStores(); + string allStoresString = _services.Localization.GetResource("Admin.Common.StoresAll"); - var settings = _settingService + var settings = _services.Settings .GetAllSettings() .Select(x => { @@ -1544,7 +1538,7 @@ public ActionResult AllSettings(GridCommand command) [GridAction(EnableCustomBinding = true)] public ActionResult SettingUpdate(SettingModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); if (model.Name != null) @@ -1559,9 +1553,9 @@ public ActionResult SettingUpdate(SettingModel model, GridCommand command) return Content(modelStateErrors.FirstOrDefault()); } - var setting = _settingService.GetSettingById(model.Id); + var setting = _services.Settings.GetSettingById(model.Id); if (setting == null) - return Content(_localizationService.GetResource("Admin.Configuration.Settings.NoneWithThatId")); + return Content(_services.Localization.GetResource("Admin.Configuration.Settings.NoneWithThatId")); var storeId = model.Store.ToInt(); //use Store property (not StoreId) because appropriate property is stored in it @@ -1569,20 +1563,20 @@ public ActionResult SettingUpdate(SettingModel model, GridCommand command) setting.StoreId != storeId) { //setting name or store has been changed - _settingService.DeleteSetting(setting); + _services.Settings.DeleteSetting(setting); } - _settingService.SetSetting(model.Name, model.Value, storeId); + _services.Settings.SetSetting(model.Name, model.Value, storeId); //activity log - _customerActivityService.InsertActivity("EditSettings", _localizationService.GetResource("ActivityLog.EditSettings")); + _customerActivityService.InsertActivity("EditSettings", _services.Localization.GetResource("ActivityLog.EditSettings")); return AllSettings(command); } [GridAction(EnableCustomBinding = true)] public ActionResult SettingAdd([Bind(Exclude = "Id")] SettingModel model, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); if (model.Name != null) @@ -1598,26 +1592,26 @@ public ActionResult SettingAdd([Bind(Exclude = "Id")] SettingModel model, GridCo } var storeId = model.Store.ToInt(); //use Store property (not StoreId) because appropriate property is stored in it - _settingService.SetSetting(model.Name, model.Value, storeId); + _services.Settings.SetSetting(model.Name, model.Value, storeId); //activity log - _customerActivityService.InsertActivity("AddNewSetting", _localizationService.GetResource("ActivityLog.AddNewSetting"), model.Name); + _customerActivityService.InsertActivity("AddNewSetting", _services.Localization.GetResource("ActivityLog.AddNewSetting"), model.Name); return AllSettings(command); } [GridAction(EnableCustomBinding = true)] public ActionResult SettingDelete(int id, GridCommand command) { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings)) + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings)) return AccessDeniedView(); - var setting = _settingService.GetSettingById(id); + var setting = _services.Settings.GetSettingById(id); if (setting == null) throw new ArgumentException("No setting found with the specified id"); - _settingService.DeleteSetting(setting); + _services.Settings.DeleteSetting(setting); //activity log - _customerActivityService.InsertActivity("DeleteSetting", _localizationService.GetResource("ActivityLog.DeleteSetting"), setting.Name); + _customerActivityService.InsertActivity("DeleteSetting", _services.Localization.GetResource("ActivityLog.DeleteSetting"), setting.Name); return AllSettings(command); } diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index 6ecce2697c..3049beedef 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -58,7 +58,6 @@ public class CatalogHelper private readonly CatalogSettings _catalogSettings; private readonly CustomerSettings _customerSettings; private readonly CaptchaSettings _captchaSettings; - private readonly CurrencySettings _currencySettings; private readonly TaxSettings _taxSettings; private readonly IMeasureService _measureService; private readonly IQuantityUnitService _quantityUnitService; @@ -91,7 +90,6 @@ public CatalogHelper( MediaSettings mediaSettings, CatalogSettings catalogSettings, CustomerSettings customerSettings, - CurrencySettings currencySettings, CaptchaSettings captchaSettings, IMeasureService measureService, IQuantityUnitService quantityUnitService, @@ -131,7 +129,6 @@ public CatalogHelper( this._catalogSettings = catalogSettings; this._customerSettings = customerSettings; this._captchaSettings = captchaSettings; - this._currencySettings = currencySettings; this._menuPublisher = _menuPublisher; this._httpRequest = httpRequest; this._urlHelper = urlHelper; @@ -1314,9 +1311,8 @@ from a in colorAttr.ProductVariantAttributeValues.Take(50) model.BasePriceInfo = minPriceProduct.GetBasePriceInfo(_localizationService, _priceFormatter); } - var addShippingPrice = _currencyService.ConvertCurrency( - minPriceProduct.AdditionalShippingCharge, - _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId), _services.WorkContext.WorkingCurrency); + var addShippingPrice = _currencyService.ConvertCurrency(minPriceProduct.AdditionalShippingCharge, + _services.StoreContext.CurrentStore.PrimaryStoreCurrency, _services.WorkContext.WorkingCurrency); if (addShippingPrice > 0 && displayPrices) { diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs index 54df8e0005..69fb6c60a5 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs @@ -2114,7 +2114,6 @@ protected override void Alter(IList settings) .Alter(x => { - x.PrimaryStoreCurrencyId = base.DbContext.Set().Where(c => c.CurrencyCode == "EUR").Single().Id; x.PrimaryExchangeRateCurrencyId = base.DbContext.Set().Where(c => c.CurrencyCode == "EUR").Single().Id; }) diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs index 597a33ef39..55ad836c04 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs @@ -549,12 +549,12 @@ public virtual void Seed(SmartObjectContext context) }); Populate("PopulatePictures", _data.Pictures()); + Populate("PopulateCurrencies", PopulateCurrencies); Populate("PopulateStores", PopulateStores); Populate("InstallLanguages", () => PopulateLanguage(_config.Language)); Populate("PopulateMeasureDimensions", _data.MeasureDimensions()); Populate("PopulateMeasureWeights", _data.MeasureWeights()); Populate("PopulateTaxCategories", PopulateTaxCategories); - Populate("PopulateCurrencies", PopulateCurrencies); Populate("PopulateCountriesAndStates", PopulateCountriesAndStates); Populate("PopulateShippingMethods", PopulateShippingMethods); Populate("PopulateDeliveryTimes", _data.DeliveryTimes()); diff --git a/src/Tests/SmartStore.Services.Tests/Catalog/PriceFormatterTests.cs b/src/Tests/SmartStore.Services.Tests/Catalog/PriceFormatterTests.cs index 73ab646fc2..9b1d90095f 100644 --- a/src/Tests/SmartStore.Services.Tests/Catalog/PriceFormatterTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Catalog/PriceFormatterTests.cs @@ -31,6 +31,7 @@ public class PriceFormatterTests : ServiceTest ILocalizationService _localizationService; TaxSettings _taxSettings; IPriceFormatter _priceFormatter; + IStoreContext _storeContext; [SetUp] public new void SetUp() @@ -64,14 +65,16 @@ public class PriceFormatterTests : ServiceTest CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc= DateTime.UtcNow }; + _currencyRepo = MockRepository.GenerateMock>(); _currencyRepo.Expect(x => x.Table).Return(new List() { currency1, currency2 }.AsQueryable()); _storeMappingService = MockRepository.GenerateMock(); + _storeContext = MockRepository.GenerateMock(); var pluginFinder = new PluginFinder(); _currencyService = new CurrencyService(cacheManager, _currencyRepo, _storeMappingService, - _currencySettings, pluginFinder, null, this.ProviderManager); + _currencySettings, pluginFinder, null, this.ProviderManager, _storeContext); _taxSettings = new TaxSettings(); diff --git a/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs index 8d87cc1d6b..3b1c680985 100644 --- a/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs @@ -14,6 +14,7 @@ using NUnit.Framework; using Rhino.Mocks; using SmartStore.Services.Stores; +using SmartStore.Core; namespace SmartStore.Services.Tests.Directory { @@ -25,6 +26,7 @@ public class CurrencyServiceTests : ServiceTest CurrencySettings _currencySettings; IEventPublisher _eventPublisher; ICurrencyService _currencyService; + IStoreContext _storeContext; Currency currencyUSD, currencyRUR, currencyEUR; @@ -70,6 +72,7 @@ public class CurrencyServiceTests : ServiceTest CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow, }; + _currencyRepository = MockRepository.GenerateMock>(); _currencyRepository.Expect(x => x.Table).Return(new List() { currencyUSD, currencyEUR, currencyRUR }.AsQueryable()); _currencyRepository.Expect(x => x.GetById(currencyUSD.Id)).Return(currencyUSD); @@ -77,20 +80,19 @@ public class CurrencyServiceTests : ServiceTest _currencyRepository.Expect(x => x.GetById(currencyRUR.Id)).Return(currencyRUR); _storeMappingService = MockRepository.GenerateMock(); + _storeContext = MockRepository.GenerateMock(); var cacheManager = new NullCache(); _currencySettings = new CurrencySettings(); - _currencySettings.PrimaryStoreCurrencyId = currencyUSD.Id; _currencySettings.PrimaryExchangeRateCurrencyId = currencyEUR.Id; _eventPublisher = MockRepository.GenerateMock(); _eventPublisher.Expect(x => x.Publish(Arg.Is.Anything)); var pluginFinder = new PluginFinder(); - _currencyService = new CurrencyService(cacheManager, - _currencyRepository, _storeMappingService, - _currencySettings, pluginFinder, _eventPublisher, this.ProviderManager); + _currencyService = new CurrencyService(cacheManager, _currencyRepository, _storeMappingService, + _currencySettings, pluginFinder, _eventPublisher, this.ProviderManager, _storeContext); } [Test] From 8e751c8823b8f161dfc4cf975ed0d9ef6fcb01c6 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 27 Jun 2015 11:35:46 +0200 Subject: [PATCH 0035/1074] Refactored and removed CurrencySettings.PrimaryExchangeRateCurrencyId --- .../Domain/Directory/CurrencySettings.cs | 1 - .../Directory/CurrencyService.cs | 13 ++++---- .../Directory/ICurrencyService.cs | 6 ++-- .../Directory/UpdateExchangeRateTask.cs | 16 +++++----- .../Controllers/CommonController.cs | 7 +++-- .../Controllers/CurrencyController.cs | 6 ++-- .../Installation/DeDESeedData.cs | 30 ++++++------------- .../Directory/CurrencyServiceTests.cs | 14 ++++----- 8 files changed, 42 insertions(+), 51 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs b/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs index 77caffa2b6..371d202799 100644 --- a/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs @@ -4,7 +4,6 @@ namespace SmartStore.Core.Domain.Directory { public class CurrencySettings : ISettings { - public int PrimaryExchangeRateCurrencyId { get; set; } public string ActiveExchangeRateProviderSystemName { get; set; } public bool AutoUpdateEnabled { get; set; } public long LastUpdateTime { get; set; } diff --git a/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs b/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs index 25fcf7762c..b71220ab74 100644 --- a/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs +++ b/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs @@ -8,7 +8,6 @@ using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; using SmartStore.Core.Plugins; -using SmartStore.Services.Customers; using SmartStore.Services.Stores; namespace SmartStore.Services.Directory @@ -231,11 +230,13 @@ public virtual decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCo /// /// Amount /// Source currency code + /// Store to get the primary exchange rate currency from /// Converted value - public virtual decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Currency sourceCurrencyCode) + public virtual decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Currency sourceCurrencyCode, Store store = null) { decimal result = amount; - var primaryExchangeRateCurrency = GetCurrencyById(_currencySettings.PrimaryExchangeRateCurrencyId); + var primaryExchangeRateCurrency = (store == null ? _storeContext.CurrentStore.PrimaryExchangeRateCurrency : store.PrimaryExchangeRateCurrency); + if (result != decimal.Zero && sourceCurrencyCode.Id != primaryExchangeRateCurrency.Id) { decimal exchangeRate = sourceCurrencyCode.Rate; @@ -251,11 +252,13 @@ public virtual decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Curr /// /// Amount /// Target currency code + /// Store to get the primary exchange rate currency from /// Converted value - public virtual decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Currency targetCurrencyCode) + public virtual decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Currency targetCurrencyCode, Store store = null) { decimal result = amount; - var primaryExchangeRateCurrency = GetCurrencyById(_currencySettings.PrimaryExchangeRateCurrencyId); + var primaryExchangeRateCurrency = (store == null ? _storeContext.CurrentStore.PrimaryExchangeRateCurrency : store.PrimaryExchangeRateCurrency); + if (result != decimal.Zero && targetCurrencyCode.Id != primaryExchangeRateCurrency.Id) { decimal exchangeRate = targetCurrencyCode.Rate; diff --git a/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs b/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs index f7285a3ecf..6c609d61eb 100644 --- a/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs +++ b/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs @@ -81,16 +81,18 @@ public partial interface ICurrencyService /// /// Amount /// Source currency code + /// Store to get the primary exchange rate currency from /// Converted value - decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Currency sourceCurrencyCode); + decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Currency sourceCurrencyCode, Store store = null); /// /// Converts from primary exchange rate currency /// /// Amount /// Target currency code + /// Store to get the primary exchange rate currency from /// Converted value - decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Currency targetCurrencyCode); + decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Currency targetCurrencyCode, Store store = null); /// /// Converts to primary store currency diff --git a/src/Libraries/SmartStore.Services/Directory/UpdateExchangeRateTask.cs b/src/Libraries/SmartStore.Services/Directory/UpdateExchangeRateTask.cs index a3d52f317c..0882af90c5 100644 --- a/src/Libraries/SmartStore.Services/Directory/UpdateExchangeRateTask.cs +++ b/src/Libraries/SmartStore.Services/Directory/UpdateExchangeRateTask.cs @@ -1,6 +1,5 @@ using System; using SmartStore.Core.Domain.Directory; -using SmartStore.Services.Configuration; using SmartStore.Services.Tasks; namespace SmartStore.Services.Directory @@ -11,15 +10,17 @@ namespace SmartStore.Services.Directory public partial class UpdateExchangeRateTask : ITask { private readonly ICurrencyService _currencyService; - private readonly ISettingService _settingService; private readonly CurrencySettings _currencySettings; + private readonly ICommonServices _services; - public UpdateExchangeRateTask(ICurrencyService currencyService, - ISettingService settingService, CurrencySettings currencySettings) + public UpdateExchangeRateTask( + ICurrencyService currencyService, + CurrencySettings currencySettings, + ICommonServices services) { this._currencyService = currencyService; - this._settingService = settingService; this._currencySettings = currencySettings; + this._services = services; } /// @@ -33,10 +34,11 @@ public void Execute(TaskExecutionContext ctx) long lastUpdateTimeTicks = _currencySettings.LastUpdateTime; DateTime lastUpdateTime = DateTime.FromBinary(lastUpdateTimeTicks); lastUpdateTime = DateTime.SpecifyKind(lastUpdateTime, DateTimeKind.Utc); + if (lastUpdateTime.AddHours(1) < DateTime.UtcNow) { //update rates each one hour - var exchangeRates = _currencyService.GetCurrencyLiveRates(_currencyService.GetCurrencyById(_currencySettings.PrimaryExchangeRateCurrencyId).CurrencyCode); + var exchangeRates = _currencyService.GetCurrencyLiveRates(_services.StoreContext.CurrentStore.PrimaryExchangeRateCurrency.CurrencyCode); foreach (var exchageRate in exchangeRates) { @@ -51,7 +53,7 @@ public void Execute(TaskExecutionContext ctx) //save new update time value _currencySettings.LastUpdateTime = DateTime.UtcNow.ToBinary(); - _settingService.SaveSetting(_currencySettings); + _services.Settings.SaveSetting(_currencySettings); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs index ce27f22ebc..3abb1f2d5b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs @@ -496,9 +496,10 @@ public ActionResult SystemInfo() public ActionResult Warnings() { var model = new List(); + var store = _services.StoreContext.CurrentStore; //store URL - var storeUrl = _services.StoreContext.CurrentStore.Url.EnsureEndsWith("/"); + var storeUrl = store.Url.EnsureEndsWith("/"); if (storeUrl.HasValue() && (storeUrl.IsCaseInsensitiveEqual(_services.WebHelper.GetStoreLocation(false)) || storeUrl.IsCaseInsensitiveEqual(_services.WebHelper.GetStoreLocation(true)))) { model.Add(new SystemWarningModel @@ -550,7 +551,7 @@ public ActionResult Warnings() } //primary exchange rate currency - var perCurrency = _currencyService.Value.GetCurrencyById(_currencySettings.Value.PrimaryExchangeRateCurrencyId); + var perCurrency = store.PrimaryExchangeRateCurrency; if (perCurrency != null) { model.Add(new SystemWarningModel @@ -578,7 +579,7 @@ public ActionResult Warnings() } //primary store currency - var pscCurrency = _services.StoreContext.CurrentStore.PrimaryStoreCurrency; + var pscCurrency = store.PrimaryStoreCurrency; if (pscCurrency != null) { model.Add(new SystemWarningModel diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs index 4006edb580..57094f5593 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs @@ -122,7 +122,7 @@ public ActionResult List(bool liveRates = false) { try { - var primaryExchangeCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryExchangeRateCurrencyId); + var primaryExchangeCurrency = _services.StoreContext.CurrentStore.PrimaryExchangeRateCurrency; if (primaryExchangeCurrency == null) throw new SmartException("Primary exchange rate currency is not set"); @@ -202,8 +202,8 @@ public ActionResult MarkAsPrimaryExchangeRateCurrency(int id) if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); - _currencySettings.PrimaryExchangeRateCurrencyId = id; - _services.Settings.SaveSetting(_currencySettings); + //_currencySettings.PrimaryExchangeRateCurrencyId = id; + //_services.Settings.SaveSetting(_currencySettings); return RedirectToAction("List"); } diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs index 69fb6c60a5..446edc1c2d 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs @@ -1,35 +1,28 @@ using System; -using System.Linq; -using System.Linq.Expressions; using System.Collections.Generic; -using System.IO; -using SmartStore.Core; +using System.Linq; using SmartStore.Core.Configuration; -using SmartStore.Core.Domain; using SmartStore.Core.Domain.Blogs; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Cms; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Discounts; -using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.Forums; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Logging; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.News; +using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Polls; -using SmartStore.Core.Domain.Tax; -using SmartStore.Core.Domain.Topics; using SmartStore.Core.Domain.Seo; -using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; -using SmartStore.Core.Domain.Tasks; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Data; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Stores; -using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Domain.Topics; using SmartStore.Data.Setup; namespace SmartStore.Web.Infrastructure.Installation @@ -2112,11 +2105,6 @@ protected override void Alter(IList settings) x.BaseWeightId = base.DbContext.Set().Where(m => m.SystemKeyword == "kg").Single().Id; }) - .Alter(x => - { - x.PrimaryExchangeRateCurrencyId = base.DbContext.Set().Where(c => c.CurrencyCode == "EUR").Single().Id; - }) - .Alter(x => { x.DefaultTitle = "Mein Shop"; diff --git a/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs index 3b1c680985..7f0055c635 100644 --- a/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs @@ -1,20 +1,17 @@ using System; using System.Collections.Generic; using System.Linq; +using NUnit.Framework; +using Rhino.Mocks; +using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Stores; -using SmartStore.Core.Infrastructure; +using SmartStore.Core.Events; using SmartStore.Core.Plugins; -using SmartStore.Services.Customers; using SmartStore.Services.Directory; -using SmartStore.Core.Events; -using SmartStore.Tests; -using NUnit.Framework; -using Rhino.Mocks; using SmartStore.Services.Stores; -using SmartStore.Core; +using SmartStore.Tests; namespace SmartStore.Services.Tests.Directory { @@ -85,7 +82,6 @@ public class CurrencyServiceTests : ServiceTest var cacheManager = new NullCache(); _currencySettings = new CurrencySettings(); - _currencySettings.PrimaryExchangeRateCurrencyId = currencyEUR.Id; _eventPublisher = MockRepository.GenerateMock(); _eventPublisher.Expect(x => x.Publish(Arg.Is.Anything)); From ecb243724f319ce621b30d5900126b8c5fe64c85 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 27 Jun 2015 12:07:53 +0200 Subject: [PATCH 0036/1074] A currency cannot be deleted or deactivated if it is attached to a store as primary or exchange rate currency. --- ...61756463_PrimaryStoreCurrencyMultiStore.cs | 8 +++ .../Controllers/CurrencyController.cs | 53 ++++++++++++------- .../Models/Directory/CurrencyModel.cs | 10 ++-- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index ed33800321..029472c05c 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -62,6 +62,14 @@ public void Seed(SmartObjectContext context) public void MigrateLocaleResources(LocaleResourcesBuilder builder) { + builder.AddOrUpdate("Admin.Configuration.Currencies.NoDeleteOrDeactivate", + "The currency cannot be deleted or deactivated because it is attached to the store \"{0}\" as primary or exchange rate currency.", + "Die Whrung kann nicht gelscht oder deaktiviert werden, weil sie dem Shop \"{0}\" als Leit- oder Umrechnungswhrung zugeordnet ist."); + + + + builder.Delete("Admin.Configuration.Currencies.CantDeletePrimary"); + builder.Delete("Admin.Configuration.Currencies.CantDeleteExchange"); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs index 57094f5593..dc8f7c3bc0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs @@ -4,6 +4,7 @@ using System.Web.Mvc; using SmartStore.Admin.Models.Directory; using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Stores; using SmartStore.Services; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; @@ -92,6 +93,19 @@ private void PrepareStoresMappingModel(CurrencyModel model, Currency currency, b } } + private bool IsAttachedToStore(Currency currency, IList stores) + { + foreach (var store in stores) + { + if (store.PrimaryStoreCurrencyId == currency.Id || store.PrimaryExchangeRateCurrencyId == currency.Id) + { + NotifyError(T("Admin.Configuration.Currencies.NoDeleteOrDeactivate", store.Name)); + return true; + } + } + return false; + } + #endregion #region Methods @@ -315,18 +329,22 @@ public ActionResult Edit(CurrencyModel model, bool continueEditing) if (ModelState.IsValid) { currency = model.ToEntity(currency); - currency.UpdatedOnUtc = DateTime.UtcNow; + + if (currency.Published || (!currency.Published && !IsAttachedToStore(currency, _services.StoreService.GetAllStores()))) + { + currency.UpdatedOnUtc = DateTime.UtcNow; - _currencyService.UpdateCurrency(currency); + _currencyService.UpdateCurrency(currency); - //locales - UpdateLocales(currency, model); + //locales + UpdateLocales(currency, model); - //Stores - _storeMappingService.SaveStoreMappings(currency, model.SelectedStoreIds); + //Stores + _storeMappingService.SaveStoreMappings(currency, model.SelectedStoreIds); - NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Currencies.Updated")); - return continueEditing ? RedirectToAction("Edit", new { id = currency.Id }) : RedirectToAction("List"); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Currencies.Updated")); + return continueEditing ? RedirectToAction("Edit", new { id = currency.Id }) : RedirectToAction("List"); + } } //If we got this far, something failed, redisplay form @@ -350,23 +368,20 @@ public ActionResult DeleteConfirmed(int id) try { - // TODO - //if (currency.Id == _currencySettings.PrimaryStoreCurrencyId) - // throw new SmartException(_services.Localization.GetResource("Admin.Configuration.Currencies.CantDeletePrimary")); - - //if (currency.Id == _currencySettings.PrimaryExchangeRateCurrencyId) - // throw new SmartException(_services.Localization.GetResource("Admin.Configuration.Currencies.CantDeleteExchange")); - - _currencyService.DeleteCurrency(currency); + if (!IsAttachedToStore(currency, _services.StoreService.GetAllStores())) + { + _currencyService.DeleteCurrency(currency); - NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Currencies.Deleted")); - return RedirectToAction("List"); + NotifySuccess(_services.Localization.GetResource("Admin.Configuration.Currencies.Deleted")); + return RedirectToAction("List"); + } } catch (Exception exc) { NotifyError(exc); - return RedirectToAction("Edit", new { id = currency.Id }); } + + return RedirectToAction("Edit", new { id = currency.Id }); } #endregion diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Directory/CurrencyModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Directory/CurrencyModel.cs index 179fa5bd37..e62df8f0e1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Directory/CurrencyModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Directory/CurrencyModel.cs @@ -17,12 +17,12 @@ public CurrencyModel() { Locales = new List(); - AvailableDomainEndings = new List() + AvailableDomainEndings = new List { - new SelectListItem() { Text = ".com", Value = ".com" }, - new SelectListItem() { Text = ".uk", Value = ".uk" }, - new SelectListItem() { Text = ".de", Value = ".de" }, - new SelectListItem() { Text = ".ch", Value = ".ch" } + new SelectListItem { Text = ".com", Value = ".com" }, + new SelectListItem { Text = ".uk", Value = ".uk" }, + new SelectListItem { Text = ".de", Value = ".de" }, + new SelectListItem { Text = ".ch", Value = ".ch" } }; } [SmartResourceDisplayName("Admin.Configuration.Currencies.Fields.Name")] From 0d0ab6b386cad0c4508c528a33043549bedaf8f2 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 27 Jun 2015 12:43:42 +0200 Subject: [PATCH 0037/1074] Edit primary store and exchange rate currency --- ...61756463_PrimaryStoreCurrencyMultiStore.cs | 10 +++++ .../Controllers/StoreController.cs | 41 ++++++++++++++----- .../Infrastructure/AutoMapperStartupTask.cs | 3 +- .../Models/Stores/StoreModel.cs | 11 ++++- .../Views/Store/_CreateOrUpdate.cshtml | 18 ++++++++ 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index 029472c05c..7e70a09bca 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -66,7 +66,17 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "The currency cannot be deleted or deactivated because it is attached to the store \"{0}\" as primary or exchange rate currency.", "Die Whrung kann nicht gelscht oder deaktiviert werden, weil sie dem Shop \"{0}\" als Leit- oder Umrechnungswhrung zugeordnet ist."); + builder.AddOrUpdate("Admin.Configuration.Stores.Fields.PrimaryStoreCurrencyId", + "Primary store currency", + "Leitwhrung", + "Specifies the the primary store currency.", + "Legt die Leitwhrung des Shops fest."); + builder.AddOrUpdate("Admin.Configuration.Stores.Fields.PrimaryExchangeRateCurrencyId", + "Primary exchange rate currency", + "Haupwhrung fr Whrungsumrechnung", + "Specifies the primary exchange rate currency for this store.", + "Legt die Haupwhrung fr Whrungsumrechnungen fr diesen Shop fest."); builder.Delete("Admin.Configuration.Currencies.CantDeletePrimary"); builder.Delete("Admin.Configuration.Currencies.CantDeleteExchange"); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs index b29282d610..70fbc6b815 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs @@ -1,9 +1,7 @@ using System; using System.Linq; using System.Web.Mvc; -using SmartStore.Admin.Models.Directory; using SmartStore.Admin.Models.Stores; -using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Stores; using SmartStore.Services.Configuration; using SmartStore.Services.Directory; @@ -22,16 +20,30 @@ public partial class StoreController : AdminControllerBase private readonly ISettingService _settingService; private readonly ILocalizationService _localizationService; private readonly IPermissionService _permissionService; + private readonly ICurrencyService _currencyService; public StoreController(IStoreService storeService, ISettingService settingService, ILocalizationService localizationService, - IPermissionService permissionService) + IPermissionService permissionService, + ICurrencyService currencyService) { this._storeService = storeService; this._settingService = settingService; this._localizationService = localizationService; this._permissionService = permissionService; + this._currencyService = currencyService; + } + + private void PrepareStoreModel(StoreModel model, Store store) + { + model.AvailableCurrencies = _currencyService.GetAllCurrencies() + .Select(x => new SelectListItem + { + Text = x.Name, + Value = x.Id.ToString() + }) + .ToList(); } public ActionResult List() @@ -91,6 +103,8 @@ public ActionResult Create() return AccessDeniedView(); var model = new StoreModel(); + PrepareStoreModel(model, null); + return View(model); } @@ -103,6 +117,7 @@ public ActionResult Create(StoreModel model, bool continueEditing) if (ModelState.IsValid) { var store = model.ToEntity(); + //ensure we have "/" at the end store.Url = store.Url.EnsureEndsWith("/"); _storeService.InsertStore(store); @@ -112,6 +127,7 @@ public ActionResult Create(StoreModel model, bool continueEditing) } //If we got this far, something failed, redisplay form + PrepareStoreModel(model, null); return View(model); } @@ -122,10 +138,11 @@ public ActionResult Edit(int id) var store = _storeService.GetStoreById(id); if (store == null) - //No store found with the specified id return RedirectToAction("List"); var model = store.ToModel(); + PrepareStoreModel(model, store); + return View(model); } @@ -138,12 +155,12 @@ public ActionResult Edit(StoreModel model, bool continueEditing) var store = _storeService.GetStoreById(model.Id); if (store == null) - //No store found with the specified id return RedirectToAction("List"); if (ModelState.IsValid) { store = model.ToEntity(store); + //ensure we have "/" at the end store.Url = store.Url.EnsureEndsWith("/"); _storeService.UpdateStore(store); @@ -153,6 +170,7 @@ public ActionResult Edit(StoreModel model, bool continueEditing) } //If we got this far, something failed, redisplay form + PrepareStoreModel(model, store); return View(model); } @@ -164,7 +182,6 @@ public ActionResult Delete(int id) var store = _storeService.GetStoreById(id); if (store == null) - //No store found with the specified id return RedirectToAction("List"); try @@ -176,18 +193,20 @@ public ActionResult Delete(int id) .GetAllSettings() .Where(s => s.StoreId == id) .ToList(); - foreach (var setting in settingsToDelete) - _settingService.DeleteSetting(setting); + + settingsToDelete.ForEach(x => _settingService.DeleteSetting(x)); + //when we had two stores and now have only one store, we also should delete all "per store" settings var allStores = _storeService.GetAllStores(); + if (allStores.Count == 1) { settingsToDelete = _settingService .GetAllSettings() .Where(s => s.StoreId == allStores[0].Id) .ToList(); - foreach (var setting in settingsToDelete) - _settingService.DeleteSetting(setting); + + settingsToDelete.ForEach(x => _settingService.DeleteSetting(x)); } NotifySuccess(_localizationService.GetResource("Admin.Configuration.Stores.Deleted")); @@ -196,8 +215,8 @@ public ActionResult Delete(int id) catch (Exception exc) { NotifyError(exc); - return RedirectToAction("Edit", new { id = store.Id }); } + return RedirectToAction("Edit", new { id = store.Id }); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index 958b035003..271fcbcf2a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -567,7 +567,8 @@ public void Execute() .ForMember(dest => dest.IsRecipientNotified, mo => mo.Ignore()) .ForMember(dest => dest.CreatedOnUtc, mo => mo.Ignore()); //stores - Mapper.CreateMap(); + Mapper.CreateMap() + .ForMember(dest => dest.AvailableCurrencies, mo => mo.Ignore()); Mapper.CreateMap(); //Settings diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs index f64293b561..1fa8c5b051 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Admin.Validators.Stores; @@ -42,5 +43,13 @@ public partial class StoreModel : EntityModelBase [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.ContentDeliveryNetwork")] [AllowHtml] public string ContentDeliveryNetwork { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.PrimaryStoreCurrencyId")] + public int PrimaryStoreCurrencyId { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.PrimaryExchangeRateCurrencyId")] + public int PrimaryExchangeRateCurrencyId { get; set; } + + public List AvailableCurrencies { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml index aac7dff4f0..ae8d7a39ad 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml @@ -94,6 +94,24 @@ @Html.ValidationMessageFor(model => model.HtmlBodyId)
+ @Html.SmartLabelFor(model => model.PrimaryStoreCurrencyId) + + @Html.DropDownListFor(model => model.PrimaryStoreCurrencyId, Model.AvailableCurrencies) + @Html.ValidationMessageFor(model => model.PrimaryStoreCurrencyId) +
+ @Html.SmartLabelFor(model => model.PrimaryExchangeRateCurrencyId) + + @Html.DropDownListFor(model => model.PrimaryExchangeRateCurrencyId, Model.AvailableCurrencies) + @Html.ValidationMessageFor(model => model.PrimaryExchangeRateCurrencyId) +
@Html.SmartLabelFor(model => model.DisplayOrder) From 4b9b2861e5c700c3644a5374770d7de5eaf03740 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 28 Jun 2015 16:36:44 +0200 Subject: [PATCH 0038/1074] More UI changes for multi-store qualified primary store and exchange rate currency --- .../Mapping/Stores/StoreMap.cs | 6 +- ...61756463_PrimaryStoreCurrencyMultiStore.cs | 50 ++++++- .../UI/ScaffoldExtensions.cs | 29 +++- .../Controllers/CurrencyController.cs | 129 ++++++++++-------- .../Controllers/StoreController.cs | 13 +- .../Infrastructure/AutoMapperStartupTask.cs | 6 +- .../Models/Directory/CurrencyModel.cs | 10 +- .../Models/Stores/StoreModel.cs | 33 ++++- .../Administration/Views/Currency/List.cshtml | 79 +++++------ .../Views/Currency/_CreateOrUpdate.cshtml | 36 +++++ .../Administration/Views/Store/List.cshtml | 8 +- .../Views/Store/_CreateOrUpdate.cshtml | 46 +++---- 12 files changed, 302 insertions(+), 143 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs b/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs index bc204d80e9..6e8cdad339 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Stores/StoreMap.cs @@ -17,11 +17,13 @@ public StoreMap() this.HasRequired(s => s.PrimaryStoreCurrency) .WithMany() - .HasForeignKey(s => s.PrimaryStoreCurrencyId).WillCascadeOnDelete(false); + .HasForeignKey(s => s.PrimaryStoreCurrencyId) + .WillCascadeOnDelete(false); this.HasRequired(s => s.PrimaryExchangeRateCurrency) .WithMany() - .HasForeignKey(s => s.PrimaryExchangeRateCurrencyId).WillCascadeOnDelete(false); + .HasForeignKey(s => s.PrimaryExchangeRateCurrencyId) + .WillCascadeOnDelete(false); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index 7e70a09bca..98d7b998ea 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -11,9 +11,15 @@ public partial class PrimaryStoreCurrencyMultiStore : DbMigration, ILocaleResour public override void Up() { AddColumn("dbo.Store", "PrimaryStoreCurrencyId", c => c.Int(nullable: false)); - AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int(nullable: false)); + AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int(nullable: false)); + + // avoid conflicts with foreign key constraint + Sql("Update dbo.Store Set PrimaryStoreCurrencyId = (Select Top(1) [Id] From dbo.Currency)"); + Sql("Update dbo.Store Set PrimaryExchangeRateCurrencyId = (Select Top(1) [Id] From dbo.Currency)"); + CreateIndex("dbo.Store", "PrimaryStoreCurrencyId"); CreateIndex("dbo.Store", "PrimaryExchangeRateCurrencyId"); + AddForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency", "Id"); AddForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency", "Id"); } @@ -22,8 +28,10 @@ public override void Down() { DropForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency"); DropForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency"); + DropIndex("dbo.Store", new[] { "PrimaryExchangeRateCurrencyId" }); DropIndex("dbo.Store", new[] { "PrimaryStoreCurrencyId" }); + DropColumn("dbo.Store", "PrimaryExchangeRateCurrencyId"); DropColumn("dbo.Store", "PrimaryStoreCurrencyId"); } @@ -62,10 +70,14 @@ public void Seed(SmartObjectContext context) public void MigrateLocaleResources(LocaleResourcesBuilder builder) { - builder.AddOrUpdate("Admin.Configuration.Currencies.NoDeleteOrDeactivate", + builder.AddOrUpdate("Admin.Configuration.Currencies.DeleteOrPublishStoreConflict", "The currency cannot be deleted or deactivated because it is attached to the store \"{0}\" as primary or exchange rate currency.", "Die Whrung kann nicht gelscht oder deaktiviert werden, weil sie dem Shop \"{0}\" als Leit- oder Umrechnungswhrung zugeordnet ist."); + //builder.AddOrUpdate("Admin.Configuration.Currencies.StoreLimitationConflict", + // "The store limitations must include store \"{0}\" because the currency is attached to it as primary or exchange rate currency.", + // "Die Shop-Eingrenzungen mssen den Shop \"{0}\" enthalten, da ihm die Whrung als Leit- oder Umrechnungswhrung zugeordnet ist."); + builder.AddOrUpdate("Admin.Configuration.Stores.Fields.PrimaryStoreCurrencyId", "Primary store currency", "Leitwhrung", @@ -73,13 +85,41 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Legt die Leitwhrung des Shops fest."); builder.AddOrUpdate("Admin.Configuration.Stores.Fields.PrimaryExchangeRateCurrencyId", - "Primary exchange rate currency", - "Haupwhrung fr Whrungsumrechnung", + "Exchange rate currency", + "Umrechnungswhrung", "Specifies the primary exchange rate currency for this store.", - "Legt die Haupwhrung fr Whrungsumrechnungen fr diesen Shop fest."); + "Legt die Umrechnungswhrung fr diesen Shop fest."); + + builder.AddOrUpdate("Admin.Configuration.Currencies.Fields.IsPrimaryStoreCurrency", + "Primary currency", + "Leitwhrung"); + + builder.AddOrUpdate("Admin.Configuration.Currencies.Fields.IsPrimaryExchangeRateCurrency", + "Exchange rate currency", + "Umrechnungswhrung"); + + builder.AddOrUpdate("Admin.Configuration.Currencies.Fields.PrimaryStoreCurrencyStores", + "Is primary store currency for", + "Ist Leitwhrung fr", + "A list of shores where the currency is primary store currency.", + "Eine Liste mit Shops, in denen die Whrung Leitwhrung ist."); + + builder.AddOrUpdate("Admin.Configuration.Currencies.Fields.PrimaryExchangeRateCurrencyStores", + "Is exchange rate currency for", + "Ist Umrechnungswhrung fr", + "A list of shores where the currency is primary exchange rate currency.", + "Eine Liste mit Shops, in denen die Whrung Umrechnungswhrung ist."); + + builder.AddOrUpdate("Admin.Configuration.Stores.Fields.SslEnabled", + "SSL", + "SSL", + "Specifies whether the store should be SSL secured.", + "Legt fest, ob der Shop SSL gesichert werden soll."); builder.Delete("Admin.Configuration.Currencies.CantDeletePrimary"); builder.Delete("Admin.Configuration.Currencies.CantDeleteExchange"); + builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryStoreCurrency"); + builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryExchangeRateCurrency"); } } } diff --git a/src/Presentation/SmartStore.Web.Framework/UI/ScaffoldExtensions.cs b/src/Presentation/SmartStore.Web.Framework/UI/ScaffoldExtensions.cs index 71f761010f..6c30d0edcb 100644 --- a/src/Presentation/SmartStore.Web.Framework/UI/ScaffoldExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/UI/ScaffoldExtensions.cs @@ -1,10 +1,11 @@ -using System.Web.Mvc; +using System.Text; +using System.Web.Mvc; using System.Web.WebPages; -using Telerik.Web.Mvc.UI.Fluent; -using SmartStore.Core.Infrastructure; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Infrastructure; using SmartStore.Core.Localization; using SmartStore.Services.Localization; +using Telerik.Web.Mvc.UI.Fluent; namespace SmartStore.Web.Framework.UI { @@ -73,6 +74,28 @@ public static string LabeledOrderNumber(this HtmlHelper helper) return "<# if(HasNewPaymentNotification) {{ #>{0}<# }} #>{1}".FormatInvariant(label, link); } + public static HelperResult LabeledCurrencyName(this HtmlHelper helper, int id, string name, bool isPrimaryStoreCurrency, bool isPrimaryExchangeRateCurrency) + { + var localize = EngineContext.Current.Resolve(); + var sb = new StringBuilder(); + + if (isPrimaryStoreCurrency) + { + sb.AppendFormat("{0}", localize.GetResource("Admin.Configuration.Currencies.Fields.IsPrimaryStoreCurrency")); + } + + if (isPrimaryExchangeRateCurrency) + { + sb.AppendFormat("{0}", localize.GetResource("Admin.Configuration.Currencies.Fields.IsPrimaryExchangeRateCurrency")); + } + + string url = UrlHelper.GenerateContentUrl("~/Admin/Currency/Edit/", helper.ViewContext.RequestContext.HttpContext); + + sb.AppendFormat("{2}", url, id, helper.Encode(name.NaIfEmpty())); + + return new HelperResult(writer => writer.Write(sb.ToString())); + } + public static string RichEditorFlavor(this HtmlHelper helper) { return EngineContext.Current.Resolve().RichEditorFlavor.NullEmpty() ?? "RichEditor"; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs index dc8f7c3bc0..00fb1f65db 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CurrencyController.cs @@ -70,38 +70,66 @@ public void UpdateLocales(Currency currency, CurrencyModel model) } } - [NonAction] - private void PrepareStoresMappingModel(CurrencyModel model, Currency currency, bool excludeProperties) + private void PrepareCurrencyModel(CurrencyModel model, Currency currency, bool excludeProperties) { if (model == null) throw new ArgumentNullException("model"); - model.AvailableStores = _services.StoreService - .GetAllStores() - .Select(s => s.ToModel()) - .ToList(); + var allStores = _services.StoreService.GetAllStores(); + + model.AvailableStores = allStores.Select(s => s.ToModel()).ToList(); + + if (currency != null) + { + model.PrimaryStoreCurrencyStores = allStores + .Where(x => x.PrimaryStoreCurrencyId == currency.Id) + .Select(x => new SelectListItem + { + Text = x.Name, + Value = Url.Action("Edit", "Store", new { id = x.Id }) + }) + .ToList(); + + model.PrimaryExchangeRateCurrencyStores = allStores + .Where(x => x.PrimaryExchangeRateCurrencyId == currency.Id) + .Select(x => new SelectListItem + { + Text = x.Name, + Value = Url.Action("Edit", "Store", new { id = x.Id }) + }) + .ToList(); + } + if (!excludeProperties) { - if (currency != null) - { - model.SelectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(currency); - } - else - { - model.SelectedStoreIds = new int[0]; - } + model.SelectedStoreIds = (currency == null ? new int[0] : _storeMappingService.GetStoresIdsWithAccess(currency)); } } - private bool IsAttachedToStore(Currency currency, IList stores) + private bool IsAttachedToStore(Currency currency, IList stores, bool force) { - foreach (var store in stores) + var attachedStore = stores.FirstOrDefault(x => x.PrimaryStoreCurrencyId == currency.Id || x.PrimaryExchangeRateCurrencyId == currency.Id); + + if (attachedStore != null) { - if (store.PrimaryStoreCurrencyId == currency.Id || store.PrimaryExchangeRateCurrencyId == currency.Id) + if (force || (!force && !currency.Published)) { - NotifyError(T("Admin.Configuration.Currencies.NoDeleteOrDeactivate", store.Name)); + NotifyError(T("Admin.Configuration.Currencies.DeleteOrPublishStoreConflict", attachedStore.Name)); return true; } + + // Must store limitations include the store where the currency is attached as primary or exchange rate currency? + //if (currency.LimitedToStores) + //{ + // if (selectedStoreIds == null) + // selectedStoreIds = _storeMappingService.GetStoreMappingsFor("Currency", currency.Id).Select(x => x.StoreId).ToArray(); + + // if (!selectedStoreIds.Contains(attachedStore.Id)) + // { + // NotifyError(T("Admin.Configuration.Currencies.StoreLimitationConflict", attachedStore.Name)); + // return true; + // } + //} } return false; } @@ -120,17 +148,26 @@ public ActionResult List(bool liveRates = false) if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) return AccessDeniedView(); - var currenciesModel = _currencyService.GetAllCurrencies(true).Select(x => x.ToModel()).ToList(); + var store = _services.StoreContext.CurrentStore; + var models = _currencyService.GetAllCurrencies(true).Select(x => x.ToModel()).ToList(); - foreach (var currency in currenciesModel) + foreach (var model in models) { - currency.IsPrimaryExchangeRateCurrency = (currency.Id == _services.StoreContext.CurrentStore.PrimaryExchangeRateCurrencyId); + model.IsPrimaryStoreCurrency = (store.PrimaryStoreCurrencyId == model.Id); + model.IsPrimaryExchangeRateCurrency = (store.PrimaryExchangeRateCurrencyId == model.Id); } - foreach (var currency in currenciesModel) - { - currency.IsPrimaryStoreCurrency = (currency.Id == _services.StoreContext.CurrentStore.PrimaryStoreCurrencyId); - } + //var allStores = _services.StoreService.GetAllStores(); + //foreach (var model in models) + //{ + // var storeNames = allStores.Where(x => x.PrimaryStoreCurrencyId == model.Id).Select(x => x.Name).ToList(); + + // model.IsPrimaryStoreCurrency = string.Join("
", storeNames); + + // storeNames = allStores.Where(x => x.PrimaryExchangeRateCurrencyId == model.Id).Select(x => x.Name).ToList(); + + // model.IsPrimaryExchangeRateCurrency = string.Join("
", storeNames); + //} if (liveRates) { @@ -147,21 +184,25 @@ public ActionResult List(bool liveRates = false) NotifyError(exc, false); } } + ViewBag.ExchangeRateProviders = new List(); + foreach (var erp in _currencyService.LoadAllExchangeRateProviders()) { - ViewBag.ExchangeRateProviders.Add(new SelectListItem() + ViewBag.ExchangeRateProviders.Add(new SelectListItem { Text = _pluginMediator.GetLocalizedFriendlyName(erp.Metadata), Value = erp.Metadata.SystemName, Selected = erp.Metadata.SystemName.Equals(_currencySettings.ActiveExchangeRateProviderSystemName, StringComparison.InvariantCultureIgnoreCase) }); } + ViewBag.AutoUpdateEnabled = _currencySettings.AutoUpdateEnabled; + var gridModel = new GridModel { - Data = currenciesModel, - Total = currenciesModel.Count() + Data = models, + Total = models.Count() }; return View(gridModel); } @@ -210,26 +251,6 @@ public ActionResult List(GridCommand command) Data = gridModel }; } - - public ActionResult MarkAsPrimaryExchangeRateCurrency(int id) - { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) - return AccessDeniedView(); - - //_currencySettings.PrimaryExchangeRateCurrencyId = id; - //_services.Settings.SaveSetting(_currencySettings); - return RedirectToAction("List"); - } - - public ActionResult MarkAsPrimaryStoreCurrency(int id) - { - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageCurrencies)) - return AccessDeniedView(); - - //_currencySettings.PrimaryStoreCurrencyId = id; - //_services.Settings.SaveSetting(_currencySettings); - return RedirectToAction("List"); - } #endregion @@ -244,7 +265,7 @@ public ActionResult Create() //locales AddLocales(_languageService, model.Locales); //Stores - PrepareStoresMappingModel(model, null, false); + PrepareCurrencyModel(model, null, false); //default values model.Published = true; model.Rate = 1; @@ -278,7 +299,7 @@ public ActionResult Create(CurrencyModel model, bool continueEditing) //If we got this far, something failed, redisplay form //Stores - PrepareStoresMappingModel(model, null, true); + PrepareCurrencyModel(model, null, true); return View(model); } @@ -311,7 +332,7 @@ public ActionResult Edit(int id) } //Stores - PrepareStoresMappingModel(model, currency, false); + PrepareCurrencyModel(model, currency, false); return View(model); } @@ -330,7 +351,7 @@ public ActionResult Edit(CurrencyModel model, bool continueEditing) { currency = model.ToEntity(currency); - if (currency.Published || (!currency.Published && !IsAttachedToStore(currency, _services.StoreService.GetAllStores()))) + if (!IsAttachedToStore(currency, _services.StoreService.GetAllStores(), false)) { currency.UpdatedOnUtc = DateTime.UtcNow; @@ -351,7 +372,7 @@ public ActionResult Edit(CurrencyModel model, bool continueEditing) model.CreatedOn = _dateTimeHelper.ConvertToUserTime(currency.CreatedOnUtc, DateTimeKind.Utc); //Stores - PrepareStoresMappingModel(model, currency, true); + PrepareCurrencyModel(model, currency, true); return View(model); } @@ -368,7 +389,7 @@ public ActionResult DeleteConfirmed(int id) try { - if (!IsAttachedToStore(currency, _services.StoreService.GetAllStores())) + if (!IsAttachedToStore(currency, _services.StoreService.GetAllStores(), true)) { _currencyService.DeleteCurrency(currency); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs index 70fbc6b815..e5196ce3d9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs @@ -37,7 +37,7 @@ public StoreController(IStoreService storeService, private void PrepareStoreModel(StoreModel model, Store store) { - model.AvailableCurrencies = _currencyService.GetAllCurrencies() + model.AvailableCurrencies = _currencyService.GetAllCurrencies(false, store == null ? 0 : store.Id) .Select(x => new SelectListItem { Text = x.Name, @@ -82,7 +82,16 @@ public ActionResult List(GridCommand command) return AccessDeniedView(); var storeModels = _storeService.GetAllStores() - .Select(x => x.ToModel()) + .Select(x => + { + var model = x.ToModel(); + + PrepareStoreModel(model, x); + + model.Hosts = model.Hosts.EmptyNull().Replace(",", "
"); + + return model; + }) .ToList(); var gridModel = new GridModel diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index 271fcbcf2a..beb5350570 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -317,6 +317,8 @@ public void Execute() .ForMember(dest => dest.CreatedOn, mo => mo.Ignore()) .ForMember(dest => dest.IsPrimaryExchangeRateCurrency, mo => mo.Ignore()) .ForMember(dest => dest.IsPrimaryStoreCurrency, mo => mo.Ignore()) + .ForMember(dest => dest.PrimaryStoreCurrencyStores, mo => mo.Ignore()) + .ForMember(dest => dest.PrimaryExchangeRateCurrencyStores, mo => mo.Ignore()) .ForMember(dest => dest.Locales, mo => mo.Ignore()) .ForMember(dest => dest.AvailableStores, mo => mo.Ignore()) .ForMember(dest => dest.SelectedStoreIds, mo => mo.Ignore()) @@ -568,7 +570,9 @@ public void Execute() .ForMember(dest => dest.CreatedOnUtc, mo => mo.Ignore()); //stores Mapper.CreateMap() - .ForMember(dest => dest.AvailableCurrencies, mo => mo.Ignore()); + .ForMember(dest => dest.AvailableCurrencies, mo => mo.Ignore()) + .ForMember(dest => dest.PrimaryStoreCurrency, mo => mo.Ignore()) + .ForMember(dest => dest.PrimaryExchangeRateCurrency, mo => mo.Ignore()); Mapper.CreateMap(); //Settings diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Directory/CurrencyModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Directory/CurrencyModel.cs index e62df8f0e1..395fa757dd 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Directory/CurrencyModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Directory/CurrencyModel.cs @@ -53,11 +53,14 @@ public CurrencyModel() [SmartResourceDisplayName("Admin.Configuration.Currencies.Fields.CreatedOn")] public DateTime CreatedOn { get; set; } - [SmartResourceDisplayName("Admin.Configuration.Currencies.Fields.IsPrimaryExchangeRateCurrency")] + public bool IsPrimaryStoreCurrency { get; set; } public bool IsPrimaryExchangeRateCurrency { get; set; } - [SmartResourceDisplayName("Admin.Configuration.Currencies.Fields.IsPrimaryStoreCurrency")] - public bool IsPrimaryStoreCurrency { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Currencies.Fields.PrimaryStoreCurrencyStores")] + public IList PrimaryStoreCurrencyStores { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Currencies.Fields.PrimaryExchangeRateCurrencyStores")] + public IList PrimaryExchangeRateCurrencyStores { get; set; } [SmartResourceDisplayName("Admin.Configuration.Currencies.Fields.DomainEndings")] public string DomainEndings { get; set; } @@ -68,6 +71,7 @@ public CurrencyModel() //Store mapping [SmartResourceDisplayName("Admin.Common.Store.LimitedTo")] public bool LimitedToStores { get; set; } + [SmartResourceDisplayName("Admin.Common.Store.AvailableFor")] public List AvailableStores { get; set; } public int[] SelectedStoreIds { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs index 1fa8c5b051..bfbaafc87b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Linq; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using FluentValidation.Attributes; @@ -47,9 +48,39 @@ public partial class StoreModel : EntityModelBase [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.PrimaryStoreCurrencyId")] public int PrimaryStoreCurrencyId { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.PrimaryStoreCurrencyId")] + public string PrimaryStoreCurrency + { + get + { + try + { + return AvailableCurrencies.First(x => x.Value == PrimaryStoreCurrencyId.ToString()).Text; + } + catch { } + + return null; + } + } + [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.PrimaryExchangeRateCurrencyId")] public int PrimaryExchangeRateCurrencyId { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.PrimaryExchangeRateCurrencyId")] + public string PrimaryExchangeRateCurrency + { + get + { + try + { + return AvailableCurrencies.First(x => x.Value == PrimaryExchangeRateCurrencyId.ToString()).Text; + } + catch { } + + return null; + } + } + public List AvailableCurrencies { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Currency/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Currency/List.cshtml index f659ace41d..029108bc38 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Currency/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Currency/List.cshtml @@ -3,9 +3,10 @@ @{ List rates = ViewBag.Rates; bool autoUpdateEnabled = ViewBag.AutoUpdateEnabled ?? false; - //page title + ViewBag.Title = T("Admin.Configuration.Currencies").Text; } +
@@ -26,6 +27,7 @@
+ @using (Html.BeginForm("Save", "Currency", FormMethod.Post, new { name = "CurrencySettings" })) { @@ -48,58 +50,41 @@
} +
@(Html.Telerik().Grid() - .Name("currencies-grid") - .BindTo(Model.Data) - .Columns(columns => - { - columns.Bound(x => x.Name) - .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })); - columns.Bound(x => x.CurrencyCode) - .Centered(); - columns.Bound(x => x.Rate) - .RightAlign() - .Format("{0:0.00000000}") - .Width(180); - columns.Bound(x => x.DomainEndings); - columns.Bound(x => x.IsPrimaryExchangeRateCurrency) - .Centered() - .Template( - @ - @if (item.IsPrimaryExchangeRateCurrency) - { - - } - @T("Admin.Telerik.GridLocalization.Select") - - ) - .Width(100); - columns.Bound(x => x.IsPrimaryStoreCurrency) - .Centered() - .Template( - @ - @if (item.IsPrimaryStoreCurrency) - { - - } - @T("Admin.Telerik.GridLocalization.Select") - - ) - .Width(100); - columns.Bound(x => x.Published) - .Template(item => Html.SymbolForBool(item.Published)) - .Centered() - .Width(100); - }) -) + .Name("currencies-grid") + .BindTo(Model.Data) + .Columns(columns => + { + columns.Bound(x => x.Name) + .Template(x => Html.LabeledCurrencyName(x.Id, x.Name, x.IsPrimaryStoreCurrency, x.IsPrimaryExchangeRateCurrency)); + columns.Bound(x => x.CurrencyCode) + .Centered() + .Width(160); + columns.Bound(x => x.Published) + .Template(item => Html.SymbolForBool(item.Published)) + .Centered() + .Width(160); + columns.Bound(x => x.Rate) + .RightAlign() + .Format("{0:0.00000000}") + .Width(160); + columns.Bound(x => x.LimitedToStores) + .Template(item => Html.SymbolForBool(item.LimitedToStores)) + .Centered() + .Width(160); + columns.Bound(x => x.DomainEndings); + }) + )
-

-

+ +

+ @if (rates != null) {

@T("Admin.Configuration.Currencies.LiveRates")

@@ -129,7 +114,7 @@ }) .EnableCustomBinding(true) - ) + )
diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Currency/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Currency/_CreateOrUpdate.cshtml index 270d2f982b..2e86287c4b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Currency/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Currency/_CreateOrUpdate.cshtml @@ -141,6 +141,42 @@
+ @Html.SmartLabelFor(model => model.PrimaryStoreCurrencyStores) + + @if (Model.PrimaryStoreCurrencyStores != null && Model.PrimaryStoreCurrencyStores.Count > 0) + { + foreach (var store in Model.PrimaryStoreCurrencyStores) + { + @store.Text.NaIfEmpty()
+ } + } + else + { + @T("Common.Unspecified") + } +
+ @Html.SmartLabelFor(model => model.PrimaryExchangeRateCurrencyStores) + + @if (Model.PrimaryExchangeRateCurrencyStores != null && Model.PrimaryExchangeRateCurrencyStores.Count > 0) + { + foreach (var store in Model.PrimaryExchangeRateCurrencyStores) + { + @store.Text.NaIfEmpty()
+ } + } + else + { + @T("Common.Unspecified") + } +
} diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Store/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Store/List.cshtml index ff0728c169..0376a98f21 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Store/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Store/List.cshtml @@ -23,13 +23,17 @@ .ClientTemplate("\"><#= Name #>"); columns.Bound(x => x.Url) .ClientTemplate("\" target=\"_blank\"><#= Url #>"); + columns.Bound(x => x.Hosts) + .Encoded(false); + columns.Bound(x => x.PrimaryStoreCurrency); + columns.Bound(x => x.PrimaryExchangeRateCurrency); columns.Bound(x => x.ContentDeliveryNetwork) .ClientTemplate("\" target=\"_blank\"><#= ContentDeliveryNetwork #>"); - columns.Bound(x => x.Hosts); columns.Bound(x => x.SslEnabled) .Template(item => @Html.SymbolForBool(item.SslEnabled)) .ClientTemplate(@Html.SymbolForBool("SslEnabled")) - .Centered(); + .Centered() + .Width(80); columns.Bound(x => x.DisplayOrder) .Centered(); }) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml index ae8d7a39ad..04f6cbc086 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml @@ -51,65 +51,65 @@ - @Html.SmartLabelFor(model => model.ContentDeliveryNetwork) + @Html.SmartLabelFor(model => model.Hosts) - @Html.EditorFor(model => model.ContentDeliveryNetwork) - @Html.ValidationMessageFor(model => model.ContentDeliveryNetwork) + @Html.TextBoxFor(model => model.Hosts, new { @class = "input-large" }) + @Html.ValidationMessageFor(model => model.Hosts) - @Html.SmartLabelFor(model => model.SslEnabled) + @Html.SmartLabelFor(model => model.ContentDeliveryNetwork) - @Html.EditorFor(model => model.SslEnabled) - @Html.ValidationMessageFor(model => model.SslEnabled) + @Html.EditorFor(model => model.ContentDeliveryNetwork) + @Html.ValidationMessageFor(model => model.ContentDeliveryNetwork) - + - @Html.SmartLabelFor(model => model.SecureUrl) + @Html.SmartLabelFor(model => model.PrimaryStoreCurrencyId) - @Html.EditorFor(model => model.SecureUrl) - @Html.ValidationMessageFor(model => model.SecureUrl) + @Html.DropDownListFor(model => model.PrimaryStoreCurrencyId, Model.AvailableCurrencies) + @Html.ValidationMessageFor(model => model.PrimaryStoreCurrencyId) - @Html.SmartLabelFor(model => model.Hosts) + @Html.SmartLabelFor(model => model.PrimaryExchangeRateCurrencyId) - @Html.TextBoxFor(model => model.Hosts, new { @class = "input-large" }) - @Html.ValidationMessageFor(model => model.Hosts) + @Html.DropDownListFor(model => model.PrimaryExchangeRateCurrencyId, Model.AvailableCurrencies) + @Html.ValidationMessageFor(model => model.PrimaryExchangeRateCurrencyId) - @Html.SmartLabelFor(model => model.HtmlBodyId) + @Html.SmartLabelFor(model => model.SslEnabled) - @Html.EditorFor(model => model.HtmlBodyId) - @Html.ValidationMessageFor(model => model.HtmlBodyId) + @Html.EditorFor(model => model.SslEnabled) + @Html.ValidationMessageFor(model => model.SslEnabled) - + - @Html.SmartLabelFor(model => model.PrimaryStoreCurrencyId) + @Html.SmartLabelFor(model => model.SecureUrl) - @Html.DropDownListFor(model => model.PrimaryStoreCurrencyId, Model.AvailableCurrencies) - @Html.ValidationMessageFor(model => model.PrimaryStoreCurrencyId) + @Html.EditorFor(model => model.SecureUrl) + @Html.ValidationMessageFor(model => model.SecureUrl) - @Html.SmartLabelFor(model => model.PrimaryExchangeRateCurrencyId) + @Html.SmartLabelFor(model => model.HtmlBodyId) - @Html.DropDownListFor(model => model.PrimaryExchangeRateCurrencyId, Model.AvailableCurrencies) - @Html.ValidationMessageFor(model => model.PrimaryExchangeRateCurrencyId) + @Html.EditorFor(model => model.HtmlBodyId) + @Html.ValidationMessageFor(model => model.HtmlBodyId) From 09f07682dd1bea6905f484a007fc6244c6ecc043 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 29 Jun 2015 12:00:36 +0200 Subject: [PATCH 0039/1074] Testing multi-store qualified primary store and exchange rate currency --- changelog.md | 1 + .../SmartStore.Core/IStoreContext.cs | 8 +---- .../Directory/CurrencyService.cs | 10 +++--- .../Directory/ICurrencyService.cs | 3 +- .../Services/GoogleFeedService.cs | 4 +-- .../Plugins/FeedPluginHelper.cs | 15 ++++++--- .../Plugins/PluginHelper.cs | 5 --- .../Infrastructure/AutoMapperStartupTask.cs | 8 +++-- .../Stores/StorePersistenceTests.cs | 31 +++++++++++++++++-- .../Directory/CurrencyServiceTests.cs | 10 ++++++ 10 files changed, 65 insertions(+), 30 deletions(-) diff --git a/changelog.md b/changelog.md index 96936ed74e..eddfefc44a 100644 --- a/changelog.md +++ b/changelog.md @@ -9,6 +9,7 @@ * #526 Min\max amount option for which the payment method should be offered during checkout * #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" * #702 Facebook and Twitter external authentication suitable for multi-stores +* #704 Make primary store currency suitable for multi-stores ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Core/IStoreContext.cs b/src/Libraries/SmartStore.Core/IStoreContext.cs index 0986f24bb8..2ab8bfede9 100644 --- a/src/Libraries/SmartStore.Core/IStoreContext.cs +++ b/src/Libraries/SmartStore.Core/IStoreContext.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Domain.Stores; namespace SmartStore.Core { @@ -44,7 +39,6 @@ public interface IStoreContext /// /// IsSingleStoreMode ? 0 : CurrentStore.Id /// - /// codehint: sm-add int CurrentStoreIdIfMultiStoreMode { get; } } } diff --git a/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs b/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs index b71220ab74..5dd60700e7 100644 --- a/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs +++ b/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs @@ -191,7 +191,6 @@ public virtual void UpdateCurrency(Currency currency) } - /// /// Converts currency /// @@ -211,16 +210,17 @@ public virtual decimal ConvertCurrency(decimal amount, decimal exchangeRate) /// Amount /// Source currency code /// Target currency code + /// Store to get the primary currencies from /// Converted value - public virtual decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCode, Currency targetCurrencyCode) + public virtual decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCode, Currency targetCurrencyCode, Store store = null) { decimal result = amount; if (sourceCurrencyCode.Id == targetCurrencyCode.Id) return result; if (result != decimal.Zero && sourceCurrencyCode.Id != targetCurrencyCode.Id) { - result = ConvertToPrimaryExchangeRateCurrency(result, sourceCurrencyCode); - result = ConvertFromPrimaryExchangeRateCurrency(result, targetCurrencyCode); + result = ConvertToPrimaryExchangeRateCurrency(result, sourceCurrencyCode, store); + result = ConvertFromPrimaryExchangeRateCurrency(result, targetCurrencyCode, store); } return result; } @@ -301,7 +301,7 @@ public virtual decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency { decimal result = amount; var primaryStoreCurrency = (store == null ? _storeContext.CurrentStore.PrimaryStoreCurrency : store.PrimaryStoreCurrency); - result = ConvertCurrency(amount, primaryStoreCurrency, targetCurrencyCode); + result = ConvertCurrency(amount, primaryStoreCurrency, targetCurrencyCode, store); return result; } diff --git a/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs b/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs index 6c609d61eb..65f633fed4 100644 --- a/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs +++ b/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs @@ -73,8 +73,9 @@ public partial interface ICurrencyService /// Amount /// Source currency code /// Target currency code + /// Store to get the primary currencies from /// Converted value - decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCode, Currency targetCurrencyCode); + decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCode, Currency targetCurrencyCode, Store store = null); /// /// Converts to primary exchange rate currency diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs index de92f5e59b..9eb7c134dc 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs @@ -394,7 +394,7 @@ private void WriteItem(FeedFileCreationContext fileCreation, XmlWriter writer, P writer.WriteElementString("g", "condition", _googleNamespace, Condition()); writer.WriteElementString("g", "availability", _googleNamespace, Availability(product)); - decimal price = Helper.GetProductPrice(product, currency); + decimal price = Helper.GetProductPrice(product, currency, fileCreation.Store); string specialPriceDate; if (SpecialPrice(product, out specialPriceDate)) @@ -405,7 +405,7 @@ private void WriteItem(FeedFileCreationContext fileCreation, XmlWriter writer, P // get regular price ignoring any special price decimal specialPrice = product.SpecialPrice.Value; product.SpecialPrice = null; - price = Helper.GetProductPrice(product, currency); + price = Helper.GetProductPrice(product, currency, fileCreation.Store); product.SpecialPrice = specialPrice; _dbContext.SetToUnchanged(product); diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs index 235c0bbf40..9acc2ee0b5 100644 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs @@ -17,6 +17,7 @@ using SmartStore.Core.Html; using SmartStore.Core.Logging; using SmartStore.Services.Catalog; +using SmartStore.Services.Directory; using SmartStore.Services.Localization; using SmartStore.Services.Media; using SmartStore.Services.Seo; @@ -110,6 +111,12 @@ private IWorkContext WorkContext get { return _workContext ?? (_workContext = _ctx.Resolve()); } } + private ICurrencyService _currencyService; + private ICurrencyService CurrencyService + { + get { return _currencyService ?? (_currencyService = _ctx.Resolve()); } + } + #endregion private PromotionFeedSettings BaseSettings @@ -266,7 +273,7 @@ public string GetProductDetailUrl(Store store, Product product) return "{0}{1}".FormatWith(store.Url, product.GetSeName(Language.Id, UrlRecordService, LanguageService)); } - public decimal GetProductPrice(Product product, Currency currency) + public decimal GetProductPrice(Product product, Currency currency, Store store) { decimal priceBase = PriceCalculationService.GetPreselectedPrice(product); @@ -276,11 +283,11 @@ public decimal GetProductPrice(Product product, Currency currency) priceBase = TaxService.GetProductPrice(product, priceBase, true, WorkContext.CurrentCustomer, out taxRate); } - decimal price = ConvertFromStoreCurrency(priceBase, currency); + decimal price = CurrencyService.ConvertFromPrimaryStoreCurrency(priceBase, currency, store); return price; } - public decimal? GetOldPrice(Product product, Currency currency) + public decimal? GetOldPrice(Product product, Currency currency, Store store) { if (!decimal.Equals(product.OldPrice, decimal.Zero) && !decimal.Equals(product.OldPrice, product.Price) && !(product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)) @@ -293,7 +300,7 @@ public decimal GetProductPrice(Product product, Currency currency) price = TaxService.GetProductPrice(product, price, true, WorkContext.CurrentCustomer, out taxRate); } - return ConvertFromStoreCurrency(price, currency); + return CurrencyService.ConvertFromPrimaryStoreCurrency(price, currency, store); } return null; } diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs index b3d71558e0..f18077c900 100644 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs @@ -206,11 +206,6 @@ public XmlDocument CreateXmlDocument(Func content) } } - public decimal ConvertFromStoreCurrency(decimal price, Currency currency) - { - return _ctx.Resolve().ConvertFromPrimaryStoreCurrency(price, currency); - } - public List AvailableCurrencies() { var lst = new List(); diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index beb5350570..6380f0632c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -389,12 +389,14 @@ public void Execute() //shipping methods Mapper.CreateMap() .ForMember(dest => dest.Locales, mo => mo.Ignore()) + .ForMember(dest => dest.ExcludedCountryIds, mo => mo.Ignore()) .ForMember(dest => dest.AvailableCustomerRoles, mo => mo.Ignore()) .ForMember(dest => dest.AvailableCountries, mo => mo.Ignore()) .ForMember(dest => dest.AvailableCountryExclusionContextTypes, mo => mo.Ignore()); - Mapper.CreateMap() - .ForMember(dest => dest.RestrictedCountries, mo => mo.Ignore()) - .ForMember(dest => dest.ExcludedCustomerRoleIds, mo => mo.Ignore()); + Mapper.CreateMap() + .ForMember(dest => dest.RestrictedCountries, mo => mo.Ignore()) + .ForMember(dest => dest.ExcludedCustomerRoleIds, mo => mo.Ignore()) + .ForMember(dest => dest.CountryExclusionContextId, mo => mo.Ignore()); //plugins Mapper.CreateMap() .ForMember(dest => dest.ConfigurationUrl, mo => mo.Ignore()) diff --git a/src/Tests/SmartStore.Data.Tests/Stores/StorePersistenceTests.cs b/src/Tests/SmartStore.Data.Tests/Stores/StorePersistenceTests.cs index eebc1ebded..65509fe49a 100644 --- a/src/Tests/SmartStore.Data.Tests/Stores/StorePersistenceTests.cs +++ b/src/Tests/SmartStore.Data.Tests/Stores/StorePersistenceTests.cs @@ -1,24 +1,49 @@ using SmartStore.Core.Domain.Stores; using SmartStore.Tests; using NUnit.Framework; +using SmartStore.Core.Domain.Directory; +using System; namespace SmartStore.Data.Tests.Stores { [TestFixture] public class StorePersistenceTests : PersistenceTest { - [Test] - public void Can_save_and_load_store() + public static Store GetTestStore() { + var currency = new Currency + { + Name = "US Dollar", + CurrencyCode = "USD", + Rate = 1.1M, + DisplayLocale = "en-US", + CustomFormatting = "CustomFormatting 1", + LimitedToStores = true, + Published = true, + DisplayOrder = 2, + CreatedOnUtc = new DateTime(2010, 01, 01), + UpdatedOnUtc = new DateTime(2010, 01, 02), + }; + var store = new Store { Name = "Computer store", Url = "http://www.yourStore.com", Hosts = "yourStore.com,www.yourStore.com", LogoPictureId = 0, - DisplayOrder = 1 + DisplayOrder = 1, + PrimaryStoreCurrency = currency, + PrimaryExchangeRateCurrency = currency }; + return store; + } + + [Test] + public void Can_save_and_load_store() + { + var store = GetTestStore(); + var fromDb = SaveAndLoadEntity(store); fromDb.ShouldNotBeNull(); fromDb.Name.ShouldEqual("Computer store"); diff --git a/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs index 7f0055c635..7f5b6ea83d 100644 --- a/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Directory/CurrencyServiceTests.cs @@ -7,6 +7,7 @@ using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; using SmartStore.Core.Plugins; using SmartStore.Services.Directory; @@ -83,6 +84,15 @@ public class CurrencyServiceTests : ServiceTest _currencySettings = new CurrencySettings(); + _storeContext.Expect(x => x.CurrentStore).Return(new Store + { + Name = "Computer store", + Url = "http://www.yourStore.com", + Hosts = "yourStore.com,www.yourStore.com", + PrimaryStoreCurrency = currencyUSD, + PrimaryExchangeRateCurrency = currencyEUR + }); + _eventPublisher = MockRepository.GenerateMock(); _eventPublisher.Expect(x => x.Publish(Arg.Is.Anything)); From 589c89568b60b9e23272b00cc0cd8705178d4d25 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 29 Jun 2015 17:00:55 +0200 Subject: [PATCH 0040/1074] WorkingCurrency may throw exception Admin warnigs should catch exceptions --- .../WebWorkContext.cs | 12 ++++----- .../Controllers/CommonController.cs | 26 +++++++++++++++---- .../Infrastructure/AutoMapperStartupTask.cs | 5 ++-- .../Models/Stores/StoreModel.cs | 4 +-- .../Administration/Views/Store/List.cshtml | 4 +-- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs b/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs index 1b9a6d7c96..58684d0f8a 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs @@ -380,16 +380,16 @@ public Currency WorkingCurrency } } - // find currency by domain ending - if (currency == null && _httpContext != null && _httpContext.Request != null && _httpContext.Request.Url != null) + // if there's only one currency for current store it dominates the primary currency + if (storeCurrenciesMap.Count == 1) { - currency = storeCurrenciesMap.Values.GetByDomainEnding(_httpContext.Request.Url.Authority); + currency = storeCurrenciesMap[storeCurrenciesMap.Keys.First()]; } - // if there's only one currency for current store it dominates the primary currency - if (storeCurrenciesMap.Count == 1) + // find currency by domain ending + if (currency == null && _httpContext != null && _httpContext.Request != null && _httpContext.Request.Url != null) { - currency = storeCurrenciesMap[0]; + currency = storeCurrenciesMap.Values.GetByDomainEnding(_httpContext.Request.Url.Authority); } // get PrimaryStoreCurrency diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs index 3abb1f2d5b..b2e0ec9a03 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs @@ -655,10 +655,18 @@ public ActionResult Warnings() }); } - // shipping rate coputation methods - if (_shippingService.Value.LoadActiveShippingRateComputationMethods() - .Where(x => x.Value.ShippingRateComputationMethodType == ShippingRateComputationMethodType.Offline) - .Count() > 1) + // shipping rate coputation methods + int activeShippingMethodCount = 0; + + try + { + activeShippingMethodCount = _shippingService.Value.LoadActiveShippingRateComputationMethods() + .Where(x => x.Value.ShippingRateComputationMethodType == ShippingRateComputationMethodType.Offline) + .Count(); + } + catch { } + + if (activeShippingMethodCount > 1) { model.Add(new SystemWarningModel { @@ -668,7 +676,15 @@ public ActionResult Warnings() } //payment methods - if (_paymentService.Value.LoadActivePaymentMethods().Count() > 0) + int activePaymentMethodCount = 0; + + try + { + activePaymentMethodCount = _paymentService.Value.LoadActivePaymentMethods().Count(); + } + catch { } + + if (activePaymentMethodCount > 0) { model.Add(new SystemWarningModel { diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index 6380f0632c..81fcb2d184 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -573,10 +573,11 @@ public void Execute() //stores Mapper.CreateMap() .ForMember(dest => dest.AvailableCurrencies, mo => mo.Ignore()) + .ForMember(dest => dest.PrimaryStoreCurrencyName, mo => mo.Ignore()) + .ForMember(dest => dest.PrimaryExchangeRateCurrencyName, mo => mo.Ignore()); + Mapper.CreateMap() .ForMember(dest => dest.PrimaryStoreCurrency, mo => mo.Ignore()) .ForMember(dest => dest.PrimaryExchangeRateCurrency, mo => mo.Ignore()); - Mapper.CreateMap(); - //Settings Mapper.CreateMap() .ForMember(dest => dest.DefaultTaxAddress, mo => mo.Ignore()) diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs index bfbaafc87b..8da3b70ada 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Stores/StoreModel.cs @@ -49,7 +49,7 @@ public partial class StoreModel : EntityModelBase public int PrimaryStoreCurrencyId { get; set; } [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.PrimaryStoreCurrencyId")] - public string PrimaryStoreCurrency + public string PrimaryStoreCurrencyName { get { @@ -67,7 +67,7 @@ public string PrimaryStoreCurrency public int PrimaryExchangeRateCurrencyId { get; set; } [SmartResourceDisplayName("Admin.Configuration.Stores.Fields.PrimaryExchangeRateCurrencyId")] - public string PrimaryExchangeRateCurrency + public string PrimaryExchangeRateCurrencyName { get { diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Store/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Store/List.cshtml index 0376a98f21..b3832779c4 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Store/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Store/List.cshtml @@ -25,8 +25,8 @@ .ClientTemplate("\" target=\"_blank\"><#= Url #>"); columns.Bound(x => x.Hosts) .Encoded(false); - columns.Bound(x => x.PrimaryStoreCurrency); - columns.Bound(x => x.PrimaryExchangeRateCurrency); + columns.Bound(x => x.PrimaryStoreCurrencyName); + columns.Bound(x => x.PrimaryExchangeRateCurrencyName); columns.Bound(x => x.ContentDeliveryNetwork) .ClientTemplate("\" target=\"_blank\"><#= ContentDeliveryNetwork #>"); columns.Bound(x => x.SslEnabled) From fb9e46395abfc9c20af3aee731cf1eceb541f5f2 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 30 Jun 2015 12:23:02 +0200 Subject: [PATCH 0041/1074] PrimaryStoreCurrencyMultiStore migration may fail for SQL-Server Compact --- ...61756463_PrimaryStoreCurrencyMultiStore.cs | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index 98d7b998ea..95492db892 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -2,7 +2,9 @@ namespace SmartStore.Data.Migrations { using System.Data.Entity.Migrations; using System.Linq; + using SmartStore.Core.Data; using SmartStore.Core.Domain.Configuration; + using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Stores; using SmartStore.Data.Setup; @@ -10,18 +12,27 @@ public partial class PrimaryStoreCurrencyMultiStore : DbMigration, ILocaleResour { public override void Up() { - AddColumn("dbo.Store", "PrimaryStoreCurrencyId", c => c.Int(nullable: false)); - AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int(nullable: false)); + AddColumn("dbo.Store", "PrimaryStoreCurrencyId", c => c.Int(nullable: false, defaultValue: 1)); + AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int(nullable: false, defaultValue: 1)); // avoid conflicts with foreign key constraint - Sql("Update dbo.Store Set PrimaryStoreCurrencyId = (Select Top(1) [Id] From dbo.Currency)"); - Sql("Update dbo.Store Set PrimaryExchangeRateCurrencyId = (Select Top(1) [Id] From dbo.Currency)"); + if (DataSettings.Current.IsSqlServer) + { + // what sql-server compact does not support here: + // - Update Set with a select sub-query + // - Select in variable via declare + // - Alter table to check/nocheck a constraint + // so the the foreign key check constraint fails here (and therefore this migration) if there's no currency with id 1. + + Sql("Update dbo.Store Set PrimaryStoreCurrencyId = (Select Min(Id) From dbo.Currency)"); + Sql("Update dbo.Store Set PrimaryExchangeRateCurrencyId = (Select Min(Id) From dbo.Currency)"); + } CreateIndex("dbo.Store", "PrimaryStoreCurrencyId"); CreateIndex("dbo.Store", "PrimaryExchangeRateCurrencyId"); - AddForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency", "Id"); - AddForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency", "Id"); + AddForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency", "Id"); + AddForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency", "Id"); } public override void Down() @@ -46,24 +57,28 @@ public void Seed(SmartObjectContext context) context.MigrateLocaleResources(MigrateLocaleResources); var settings = context.Set(); - var primaryStoreCurrency = settings.FirstOrDefault(x => x.Name == "CurrencySettings.PrimaryStoreCurrencyId"); - var primaryExchangeRateCurrency = settings.FirstOrDefault(x => x.Name == "CurrencySettings.PrimaryExchangeRateCurrencyId"); + var primaryStoreCurrencySetting = settings.FirstOrDefault(x => x.Name == "CurrencySettings.PrimaryStoreCurrencyId"); + var primaryExchangeRateCurrencySetting = settings.FirstOrDefault(x => x.Name == "CurrencySettings.PrimaryExchangeRateCurrencyId"); + + int primaryStoreCurrencyId = primaryStoreCurrencySetting.Value.ToInt(); + int primaryExchangeRateCurrencyId = primaryExchangeRateCurrencySetting.Value.ToInt(); + + if (primaryStoreCurrencyId == 0) + primaryStoreCurrencyId = context.Set().First().Id; + + if (primaryExchangeRateCurrencyId == 0) + primaryExchangeRateCurrencyId = primaryStoreCurrencyId; var stores = context.Set().ToList(); - foreach (var store in stores) + stores.ForEach(x => { - int id = primaryStoreCurrency.Value.ToInt(); - if (id != 0) - store.PrimaryStoreCurrencyId = id; - - id = primaryExchangeRateCurrency.Value.ToInt(); - if (id != 0) - store.PrimaryExchangeRateCurrencyId = id; - } + x.PrimaryStoreCurrencyId = primaryStoreCurrencyId; + x.PrimaryExchangeRateCurrencyId = primaryExchangeRateCurrencyId; + }); - settings.Remove(primaryStoreCurrency); - settings.Remove(primaryExchangeRateCurrency); + settings.Remove(primaryStoreCurrencySetting); + settings.Remove(primaryExchangeRateCurrencySetting); context.SaveChanges(); } From d757c8ba5dcd3a3d1dd5bc5d7fa04b429003dce9 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 30 Jun 2015 12:36:13 +0200 Subject: [PATCH 0042/1074] Fixed unit testing failure --- .../Forums/PrivateMessagePersistenceTests.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Tests/SmartStore.Data.Tests/Forums/PrivateMessagePersistenceTests.cs b/src/Tests/SmartStore.Data.Tests/Forums/PrivateMessagePersistenceTests.cs index 9ab69bb6e7..26f7b200ab 100644 --- a/src/Tests/SmartStore.Data.Tests/Forums/PrivateMessagePersistenceTests.cs +++ b/src/Tests/SmartStore.Data.Tests/Forums/PrivateMessagePersistenceTests.cs @@ -1,9 +1,9 @@ using System; +using NUnit.Framework; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Forums; +using SmartStore.Data.Tests.Stores; using SmartStore.Tests; -using NUnit.Framework; -using SmartStore.Core.Domain.Stores; namespace SmartStore.Data.Tests.Forums { @@ -13,7 +13,7 @@ public class PrivateMessagePersistenceTests : PersistenceTest [Test] public void Can_save_and_load_privatemessage() { - var store = GetTestStore(); + var store = StorePersistenceTests.GetTestStore(); var storeFromDb = SaveAndLoadEntity(store); storeFromDb.ShouldNotBeNull(); @@ -59,15 +59,5 @@ protected Customer GetTestCustomer() LastActivityDateUtc = new DateTime(2010, 01, 02) }; } - - protected Store GetTestStore() - { - return new Store - { - Name = "Store 1", - Url = "http://www.test.com", - DisplayOrder = 1 - }; - } } } From 79ebde8c484b1886d031a7e8667eca1189511756 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 30 Jun 2015 16:38:59 +0200 Subject: [PATCH 0043/1074] Resolves #725 Prevent LowestProductPrice being 0 --- changelog.md | 1 + .../Catalog/PriceCalculationService.cs | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/changelog.md b/changelog.md index eddfefc44a..5060856f29 100644 --- a/changelog.md +++ b/changelog.md @@ -14,6 +14,7 @@ ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. * #721 Message Queue: implement "Delete all" +* #725 Prevent LowestProductPrice being 0 ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index e61c60cc35..e28b08d053 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -476,6 +476,15 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa } } + if (lowestPrice == decimal.Zero && product.Price == decimal.Zero) + { + var combination = product.ProductVariantAttributeCombinations.OrderBy(x => x.Price).FirstOrDefault(x => x.Price > decimal.Zero); + if (combination != null) + { + lowestPrice = combination.Price ?? decimal.Zero; + } + } + return lowestPrice; } From b8b855e6f9dcc68e61960caf1118e49d13e7c8a3 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 30 Jun 2015 21:04:14 +0200 Subject: [PATCH 0044/1074] E-mail attachments: test cases --- .../Email/DefaultEmailSender.cs | 17 +- .../Messages/QueuedEmailService.cs | 149 ++++++++--------- .../Controllers/EmailAccountController.cs | 1 - .../Messages/Attachment.pdf | Bin 0 -> 5064 bytes .../Messages/QueuedEmailServiceTests.cs | 155 ++++++++++++++++++ .../SmartStore.Services.Tests.csproj | 3 + 6 files changed, 243 insertions(+), 82 deletions(-) create mode 100644 src/Tests/SmartStore.Services.Tests/Messages/Attachment.pdf create mode 100644 src/Tests/SmartStore.Services.Tests/Messages/QueuedEmailServiceTests.cs diff --git a/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs b/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs index 42f9b99eec..b9862e0c52 100644 --- a/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs +++ b/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs @@ -68,11 +68,12 @@ public void SendEmail(SmtpContext context, EmailMessage message) Guard.ArgumentNotNull(() => context); Guard.ArgumentNotNull(() => message); - var msg = this.BuildMailMessage(message); - - using (var client = context.ToSmtpClient()) + using (var msg = this.BuildMailMessage(message)) { - client.Send(msg); + using (var client = context.ToSmtpClient()) + { + client.Send(msg); + } } } @@ -81,12 +82,14 @@ public Task SendEmailAsync(SmtpContext context, EmailMessage message) Guard.ArgumentNotNull(() => context); Guard.ArgumentNotNull(() => message); + var client = context.ToSmtpClient(); var msg = this.BuildMailMessage(message); - using (var client = context.ToSmtpClient()) + return client.SendMailAsync(msg).ContinueWith(t => { - return client.SendMailAsync(msg); - } + client.Dispose(); + msg.Dispose(); + }); } #endregion diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 78fe190196..1c40be1554 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -12,30 +12,28 @@ using SmartStore.Services.Localization; using SmartStore.Utilities; using System.Web; +using SmartStore.Core.Localization; namespace SmartStore.Services.Messages { public partial class QueuedEmailService : IQueuedEmailService { private readonly IRepository _queuedEmailRepository; - private readonly IEventPublisher _eventPublisher; private readonly IEmailSender _emailSender; - private readonly ILogger _logger; - private readonly ILocalizationService _localizationService; - - public QueuedEmailService( - IRepository queuedEmailRepository, - IEventPublisher eventPublisher, - IEmailSender emailSender, - ILogger logger, - ILocalizationService localizationService) + private readonly ICommonServices _services; + + public QueuedEmailService(IRepository queuedEmailRepository, IEmailSender emailSender, ICommonServices services) { - _queuedEmailRepository = queuedEmailRepository; - _eventPublisher = eventPublisher; - _emailSender = emailSender; - _logger = logger; - _localizationService = localizationService; + this._queuedEmailRepository = queuedEmailRepository; + this._emailSender = emailSender; + this._services = services; + + T = NullLocalizer.Instance; + Logger = NullLogger.Instance; } + + public Localizer T { get; set; } + public ILogger Logger { get; set; } public virtual void InsertQueuedEmail(QueuedEmail queuedEmail) { @@ -45,7 +43,7 @@ public virtual void InsertQueuedEmail(QueuedEmail queuedEmail) _queuedEmailRepository.Insert(queuedEmail); //event notification - _eventPublisher.EntityInserted(queuedEmail); + _services.EventPublisher.EntityInserted(queuedEmail); } public virtual void UpdateQueuedEmail(QueuedEmail queuedEmail) @@ -56,7 +54,7 @@ public virtual void UpdateQueuedEmail(QueuedEmail queuedEmail) _queuedEmailRepository.Update(queuedEmail); //event notification - _eventPublisher.EntityUpdated(queuedEmail); + _services.EventPublisher.EntityUpdated(queuedEmail); } public virtual void DeleteQueuedEmail(QueuedEmail queuedEmail) @@ -67,7 +65,7 @@ public virtual void DeleteQueuedEmail(QueuedEmail queuedEmail) _queuedEmailRepository.Delete(queuedEmail); //event notification - _eventPublisher.EntityDeleted(queuedEmail); + _services.EventPublisher.EntityDeleted(queuedEmail); } public virtual int DeleteAllQueuedEmails() @@ -155,33 +153,8 @@ public virtual bool SendEmail(QueuedEmail queuedEmail) try { - var bcc = String.IsNullOrWhiteSpace(queuedEmail.Bcc) ? null : queuedEmail.Bcc.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - var cc = String.IsNullOrWhiteSpace(queuedEmail.CC) ? null : queuedEmail.CC.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - var smtpContext = new SmtpContext(queuedEmail.EmailAccount); - - var msg = new EmailMessage( - new EmailAddress(queuedEmail.To, queuedEmail.ToName), - queuedEmail.Subject, - queuedEmail.Body, - new EmailAddress(queuedEmail.From, queuedEmail.FromName)); - - if (queuedEmail.ReplyTo.HasValue()) - { - msg.ReplyTo.Add(new EmailAddress(queuedEmail.ReplyTo, queuedEmail.ReplyToName)); - } - - if (cc != null) - { - msg.Cc.AddRange(cc.Where(x => x.HasValue()).Select(x => new EmailAddress(x))); - } - - if (bcc != null) - { - msg.Bcc.AddRange(bcc.Where(x => x.HasValue()).Select(x => new EmailAddress(x))); - } - - CreateAttachments(queuedEmail, msg); + var msg = ConvertEmail(queuedEmail); _emailSender.SendEmail(smtpContext, msg); @@ -190,7 +163,7 @@ public virtual bool SendEmail(QueuedEmail queuedEmail) } catch (Exception exc) { - _logger.Error(string.Concat(_localizationService.GetResource("Admin.Common.ErrorSendingEmail"), ": ", exc.Message), exc); + Logger.Error(string.Concat(T("Admin.Common.ErrorSendingEmail"), ": ", exc.Message), exc); } finally { @@ -201,52 +174,80 @@ public virtual bool SendEmail(QueuedEmail queuedEmail) return result; } - private void CreateAttachments(QueuedEmail qe, EmailMessage msg) + private void AddEmailAddresses(string addresses, ICollection target) + { + var arr = addresses.IsEmpty() ? null : addresses.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + if (arr != null && arr.Length > 0) + { + target.AddRange(arr.Where(x => x.Trim().HasValue()).Select(x => new EmailAddress(x))); + } + } + + internal EmailMessage ConvertEmail(QueuedEmail qe) { - if (qe.Attachments == null || qe.Attachments.Count == 0) - return; + // 'internal' for testing purposes + + var msg = new EmailMessage( + new EmailAddress(qe.To, qe.ToName), + qe.Subject, + qe.Body, + new EmailAddress(qe.From, qe.FromName)); - foreach (var qea in qe.Attachments) + if (qe.ReplyTo.HasValue()) { - Attachment attachment = null; + msg.ReplyTo.Add(new EmailAddress(qe.ReplyTo, qe.ReplyToName)); + } - if (qea.StorageLocation == EmailAttachmentStorageLocation.Blob) + AddEmailAddresses(qe.CC, msg.Cc); + AddEmailAddresses(qe.Bcc, msg.Bcc); + + if (qe.Attachments != null && qe.Attachments.Count > 0) + { + foreach (var qea in qe.Attachments) { - var data = qea.Data; - if (data != null && data.Length > 0) + Attachment attachment = null; + + if (qea.StorageLocation == EmailAttachmentStorageLocation.Blob) { - attachment = new Attachment(data.ToStream(), qea.Name, qea.MimeType); + var data = qea.Data; + if (data != null && data.Length > 0) + { + attachment = new Attachment(data.ToStream(), qea.Name, qea.MimeType); + } } - } - else if (qea.StorageLocation == EmailAttachmentStorageLocation.Path) - { - var path = qea.Path; - if (path.HasValue()) + else if (qea.StorageLocation == EmailAttachmentStorageLocation.Path) { - if (path[0] == '~' || path[0] == '/') + var path = qea.Path; + if (path.HasValue()) { - path = CommonHelper.MapPath(VirtualPathUtility.ToAppRelative(path)); + if (path[0] == '~' || path[0] == '/') + { + path = CommonHelper.MapPath(VirtualPathUtility.ToAppRelative(path), false); + } + if (File.Exists(path)) + { + attachment = new Attachment(path, qea.MimeType); + attachment.Name = qea.Name; + } } - if (File.Exists(path)) + } + else if (qea.StorageLocation == EmailAttachmentStorageLocation.FileReference) + { + var file = qea.File; + if (file != null && file.UseDownloadUrl == false && file.DownloadBinary != null && file.DownloadBinary.Length > 0) { - attachment = new Attachment(path, qea.MimeType); + attachment = new Attachment(file.DownloadBinary.ToStream(), file.Filename + file.Extension, file.ContentType); } } - } - else if (qea.StorageLocation == EmailAttachmentStorageLocation.FileReference) - { - var file = qea.File; - if (file != null && file.UseDownloadUrl == false && file.DownloadBinary != null && file.DownloadBinary.Length > 0) + + if (attachment != null) { - attachment = new Attachment(file.DownloadBinary.ToStream(), file.Filename + file.Extension, file.ContentType); + msg.Attachments.Add(attachment); } } - - if (attachment != null) - { - msg.Attachments.Add(attachment); - } } + + return msg; } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs index b7ffea3206..c71aaed290 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs @@ -182,7 +182,6 @@ public ActionResult SendTestEmail(EmailAccountModel model) if (String.IsNullOrWhiteSpace(model.SendTestEmailTo)) throw new SmartException("Enter test email address"); - var to = new EmailAddress(model.SendTestEmailTo); var from = new EmailAddress(emailAccount.Email, emailAccount.DisplayName); string subject = _storeContext.CurrentStore.Name + ". Testing email functionality."; diff --git a/src/Tests/SmartStore.Services.Tests/Messages/Attachment.pdf b/src/Tests/SmartStore.Services.Tests/Messages/Attachment.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e6654ec8bedfb85691ae63c6bbbb280b5ab63ee9 GIT binary patch literal 5064 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 literal 0 HcmV?d00001 diff --git a/src/Tests/SmartStore.Services.Tests/Messages/QueuedEmailServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Messages/QueuedEmailServiceTests.cs new file mode 100644 index 0000000000..7f0ea69976 --- /dev/null +++ b/src/Tests/SmartStore.Services.Tests/Messages/QueuedEmailServiceTests.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Events; +using SmartStore.Core.Email; +using SmartStore.Services.Messages; +using NUnit.Framework; +using Rhino.Mocks; +using SmartStore.Services.Stores; +using System.Web.Mail; +using SmartStore.Utilities; +using SmartStore.Core.Domain.Media; +using System.Threading.Tasks; + +namespace SmartStore.Services.Tests.Messages +{ + [TestFixture] + public class QueuedEmailServiceTests : ServiceTest + { + IRepository _qeRepository; + IEmailSender _emailSender; + ICommonServices _commonServices; + QueuedEmailService _queuedEmailService; + + [SetUp] + public new void SetUp() + { + _qeRepository = MockRepository.GenerateStub>(); + _emailSender = MockRepository.GenerateStub(); + _commonServices = MockRepository.GenerateStub(); + + _queuedEmailService = new QueuedEmailService(_qeRepository, _emailSender, _commonServices); + } + + [Test] + public void Can_convert_email() + { + var qe = new QueuedEmail + { + Bcc = "bcc1@mail.com;bcc2@mail.com", + Body = "Body", + CC = "cc1@mail.com;cc2@mail.com", + CreatedOnUtc = DateTime.UtcNow, + From = "from@mail.com", + FromName = "FromName", + Priority = 10, + ReplyTo = "replyto@mail.com", + ReplyToName = "ReplyToName", + Subject = "Subject", + To = "to@mail.com", + ToName = "ToName" + }; + + // load attachment file resource and save as file + var asm = typeof(QueuedEmailServiceTests).Assembly; + var pdfStream = asm.GetManifestResourceStream("{0}.Messages.Attachment.pdf".FormatInvariant(asm.GetName().Name)); + var pdfBinary = pdfStream.ToByteArray(); + pdfStream.Seek(0, SeekOrigin.Begin); + var path1 = "~/Attachment.pdf"; + var path2 = CommonHelper.MapPath(path1, false); + Assert.IsTrue(pdfStream.ToFile(path2)); + + var attachBlob = new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.Blob, + Data = pdfBinary, + Name = "blob.pdf", + MimeType = "application/pdf" + }; + var attachPath1 = new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.Path, + Path = path1, + Name = "path1.pdf", + MimeType = "application/pdf" + }; + var attachPath2 = new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.Path, + Path = path2, + Name = "path2.pdf", + MimeType = "application/pdf" + }; + var attachFile = new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.FileReference, + Name = "file.pdf", + MimeType = "application/pdf", + File = new Download + { + ContentType = "application/pdf", + DownloadBinary = pdfBinary, + Extension = ".pdf", + Filename = "file" + } + }; + + qe.Attachments.Add(attachBlob); + qe.Attachments.Add(attachFile); + qe.Attachments.Add(attachPath1); + qe.Attachments.Add(attachPath2); + + var msg = _queuedEmailService.ConvertEmail(qe); + + Assert.IsNotNull(msg); + Assert.IsNotNull(msg.To); + Assert.IsNotNull(msg.From); + + Assert.AreEqual(msg.ReplyTo.Count, 1); + Assert.AreEqual(qe.ReplyTo, msg.ReplyTo.First().Address); + Assert.AreEqual(qe.ReplyToName, msg.ReplyTo.First().DisplayName); + + Assert.AreEqual(msg.Cc.Count, 2); + Assert.AreEqual(msg.Cc.First().Address, "cc1@mail.com"); + Assert.AreEqual(msg.Cc.ElementAt(1).Address, "cc2@mail.com"); + + Assert.AreEqual(msg.Bcc.Count, 2); + Assert.AreEqual(msg.Bcc.First().Address, "bcc1@mail.com"); + Assert.AreEqual(msg.Bcc.ElementAt(1).Address, "bcc2@mail.com"); + + Assert.AreEqual(qe.Subject, msg.Subject); + Assert.AreEqual(qe.Body, msg.Body); + + Assert.AreEqual(msg.Attachments.Count, 4); + + var attach1 = msg.Attachments.First(); + var attach2 = msg.Attachments.ElementAt(1); + var attach3 = msg.Attachments.ElementAt(2); + var attach4 = msg.Attachments.ElementAt(3); + + // test file names + Assert.AreEqual(attach1.Name, "blob.pdf"); + Assert.AreEqual(attach2.Name, "file.pdf"); + Assert.AreEqual(attach3.Name, "path1.pdf"); + Assert.AreEqual(attach4.Name, "path2.pdf"); + + // test file streams + Assert.AreEqual(attach1.ContentStream.Length, pdfBinary.Length); + Assert.AreEqual(attach2.ContentStream.Length, pdfBinary.Length); + Assert.Greater(attach3.ContentStream.Length, 0); + Assert.Greater(attach4.ContentStream.Length, 0); + + // cleanup + msg.Attachments.Each(x => x.Dispose()); + msg.Attachments.Clear(); + + // delete attachment file + File.Delete(path2); + } + + } +} \ No newline at end of file diff --git a/src/Tests/SmartStore.Services.Tests/SmartStore.Services.Tests.csproj b/src/Tests/SmartStore.Services.Tests/SmartStore.Services.Tests.csproj index a264eb3938..4ea6b276d1 100644 --- a/src/Tests/SmartStore.Services.Tests/SmartStore.Services.Tests.csproj +++ b/src/Tests/SmartStore.Services.Tests/SmartStore.Services.Tests.csproj @@ -77,6 +77,7 @@ + @@ -104,6 +105,7 @@ + @@ -143,6 +145,7 @@ + From efb74dd791b5264d5878d52bd43789eb1b0f445f Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 1 Jul 2015 00:19:01 +0200 Subject: [PATCH 0045/1074] E-mail attachments: event & co. --- .../Messages/EventPublisherExtensions.cs | 7 +- .../Messages/MessageTokenProvider.cs | 12 ++- .../Messages/QueuingEmailEvent.cs | 42 +++++++++ .../Messages/QueuingEmailEventConsumer.cs | 46 ++++++++++ .../Messages/WorkflowMessageService.cs | 17 +++- .../Orders/OrderProcessingService.cs | 86 +++++++++---------- .../SmartStore.Services.csproj | 2 + .../OrderPlacedEventConsumer.cs | 4 +- 8 files changed, 154 insertions(+), 62 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/Messages/QueuingEmailEvent.cs create mode 100644 src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs diff --git a/src/Libraries/SmartStore.Services/Messages/EventPublisherExtensions.cs b/src/Libraries/SmartStore.Services/Messages/EventPublisherExtensions.cs index ada12006c8..681cb588b6 100644 --- a/src/Libraries/SmartStore.Services/Messages/EventPublisherExtensions.cs +++ b/src/Libraries/SmartStore.Services/Messages/EventPublisherExtensions.cs @@ -1,4 +1,5 @@ -using SmartStore.Core; +using System.Collections.Generic; +using SmartStore.Core; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Events; @@ -26,12 +27,12 @@ public static void PublishNewsletterUnsubscribe(this IEventPublisher eventPublis eventPublisher.Publish(new EmailUnsubscribedEvent(email)); } - public static void EntityTokensAdded(this IEventPublisher eventPublisher, T entity, System.Collections.Generic.IList tokens) where T : BaseEntity + public static void EntityTokensAdded(this IEventPublisher eventPublisher, T entity, IList tokens) where T : BaseEntity { eventPublisher.Publish(new EntityTokensAddedEvent(entity, tokens)); } - public static void MessageTokensAdded(this IEventPublisher eventPublisher, MessageTemplate message, System.Collections.Generic.IList tokens) + public static void MessageTokensAdded(this IEventPublisher eventPublisher, MessageTemplate message, IList tokens) { eventPublisher.Publish(new MessageTokensAddedEvent(message, tokens)); } diff --git a/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs b/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs index ed4c1ea719..23a16fffb2 100644 --- a/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs +++ b/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs @@ -716,16 +716,14 @@ public virtual void AddContactDataTokens(IList tokens) tokens.Add(new Token("Contact.ContactEmailAddress", _contactDataSettings.ContactEmailAddress)); } - //codehint: sm-add end - public virtual void AddOrderTokens(IList tokens, Order order, int languageId) { - tokens.Add(new Token("Order.OrderNumber", order.GetOrderNumber())); + tokens.Add(new Token("Order.ID", order.Id.ToString())); + tokens.Add(new Token("Order.OrderNumber", order.GetOrderNumber())); tokens.Add(new Token("Order.CustomerFullName", string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName))); tokens.Add(new Token("Order.CustomerEmail", order.BillingAddress.Email)); - tokens.Add(new Token("Order.BillingFirstName", order.BillingAddress.FirstName)); tokens.Add(new Token("Order.BillingLastName", order.BillingAddress.LastName)); tokens.Add(new Token("Order.BillingPhoneNumber", order.BillingAddress.PhoneNumber)); @@ -772,7 +770,7 @@ public virtual void AddOrderTokens(IList tokens, Order order, int languag tokens.Add(new Token("Order.CreatedOn", order.CreatedOnUtc.ToString("D"))); } - //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) + // TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) tokens.Add(new Token("Order.OrderURLForCustomer", string.Format("{0}order/details/{1}", _webHelper.GetStoreLocation(false), order.Id), true)); tokens.Add(new Token("Order.Disclaimer", TopicToHtml("Disclaimer", languageId), true)); @@ -861,13 +859,13 @@ public virtual void AddGiftCardTokens(IList tokens, GiftCard giftCard) public virtual void AddCustomerTokens(IList tokens, Customer customer) { - tokens.Add(new Token("Customer.Email", customer.Email)); + tokens.Add(new Token("Customer.ID", customer.Id.ToString())); + tokens.Add(new Token("Customer.Email", customer.Email)); tokens.Add(new Token("Customer.Username", customer.Username)); tokens.Add(new Token("Customer.FullName", customer.GetFullName())); tokens.Add(new Token("Customer.VatNumber", customer.GetAttribute(SystemCustomerAttributeNames.VatNumber))); tokens.Add(new Token("Customer.VatNumberStatus", ((VatNumberStatus)customer.GetAttribute(SystemCustomerAttributeNames.VatNumberStatusId)).ToString())); - //note: we do not use SEO friendly URLS because we can get errors caused by having .(dot) in the URL (from the emauk address) //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) string passwordRecoveryUrl = string.Format("{0}customer/passwordrecoveryconfirm?token={1}&email={2}", _webHelper.GetStoreLocation(), diff --git a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEvent.cs b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEvent.cs new file mode 100644 index 0000000000..d9efdacd84 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEvent.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using SmartStore.Core.Domain.Messages; + +namespace SmartStore.Services.Messages +{ + /// + /// An event message, which gets published just before a new instance + /// of is persisted to the database + /// + public class QueuingEmailEvent + { + public QueuedEmail QueuedEmail + { + get; + set; + } + + public MessageTemplate MessageTemplate + { + get; + set; + } + + public EmailAccount EmailAccount + { + get; + set; + } + + public IList Tokens + { + get; + set; + } + + public int LanguageId + { + get; + set; + } + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs new file mode 100644 index 0000000000..04bb77d509 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Events; + +namespace SmartStore.Services.Messages +{ + public class QueuingEmailEventConsumer : IConsumer + { + private readonly PdfSettings _pdfSettings; + + public QueuingEmailEventConsumer(PdfSettings pdfSettings) + { + this._pdfSettings = pdfSettings; + } + + public void HandleEvent(QueuingEmailEvent eventMessage) + { + var qe = eventMessage.QueuedEmail; + var tpl = eventMessage.MessageTemplate; + + // TODO: (mc) determine and apply PdfSettings + + if (tpl.Name.IsCaseInsensitiveEqual("OrderPlaced.CustomerNotification")) + { + var orderId = eventMessage.Tokens.First(x => x.Key.IsCaseInsensitiveEqual("Order.ID")).Value.ToInt(); + var qea = CreatePdfInvoiceAttachment(orderId); + if (qea != null) + { + qe.Attachments.Add(qea); + } + } + } + + private QueuedEmailAttachment CreatePdfInvoiceAttachment(int orderId) + { + // TODO: (mc) implement + return null; + } + + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs b/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs index b194690096..57efae24d2 100644 --- a/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs +++ b/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs @@ -74,7 +74,7 @@ protected int SendNotification( MessageTemplate messageTemplate, EmailAccount emailAccount, int languageId, - IEnumerable tokens, + IList tokens, string toEmailAddress, string toName, string replyTo = null, @@ -90,7 +90,7 @@ protected int SendNotification( var bodyReplaced = _tokenizer.Replace(body, tokens, true); bodyReplaced = WebHelper.MakeAllUrlsAbsolute(bodyReplaced, _httpRequest); - + var email = new QueuedEmail { Priority = 5, @@ -109,7 +109,18 @@ protected int SendNotification( SendManually = messageTemplate.SendManually }; + // publish event so that integrators can add attachments, alter the email etc. + _eventPublisher.Publish(new QueuingEmailEvent + { + EmailAccount = emailAccount, + LanguageId = languageId, + MessageTemplate = messageTemplate, + QueuedEmail = email, + Tokens = tokens + }); + _queuedEmailService.InsertQueuedEmail(email); + return email.Id; } @@ -434,7 +445,7 @@ public virtual int SendOrderPlacedCustomerNotification(Order order, int language _messageTokenProvider.AddBankConnectionTokens(tokens); _messageTokenProvider.AddContactDataTokens(tokens); - //event notification + // event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index a1b07c3749..1ce5ce0eb6 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -203,7 +203,7 @@ private decimal Round(decimal value) return (_shoppingCartSettings.RoundPricesDuringCalculation ? Math.Round(value, 2) : value); } - private string T(string resKey) + private string TNote(string resKey) { return _localizationService.GetResource("Admin.OrderNotice." + resKey); } @@ -348,26 +348,24 @@ protected void SetOrderStatus(Order order, OrderStatus os, bool notifyCustomer) _orderService.UpdateOrder(order); //order notes, notifications - order.OrderNotes.Add(new OrderNote() + order.OrderNotes.Add(new OrderNote { - Note = string.Format(T("OrderStatusChanged"), os.GetLocalizedEnum(_localizationService)), + Note = string.Format(TNote("OrderStatusChanged"), os.GetLocalizedEnum(_localizationService)), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); _orderService.UpdateOrder(order); - if (prevOrderStatus != OrderStatus.Complete && - os == OrderStatus.Complete - && notifyCustomer) + if (prevOrderStatus != OrderStatus.Complete && os == OrderStatus.Complete && notifyCustomer) { //notification int orderCompletedCustomerNotificationQueuedEmailId = _workflowMessageService.SendOrderCompletedCustomerNotification(order, order.CustomerLanguageId); if (orderCompletedCustomerNotificationQueuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() + order.OrderNotes.Add(new OrderNote { - Note = string.Format(T("CustomerCompletedEmailQueued"), orderCompletedCustomerNotificationQueuedEmailId), + Note = string.Format(TNote("CustomerCompletedEmailQueued"), orderCompletedCustomerNotificationQueuedEmailId), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -375,17 +373,15 @@ protected void SetOrderStatus(Order order, OrderStatus os, bool notifyCustomer) } } - if (prevOrderStatus != OrderStatus.Cancelled && - os == OrderStatus.Cancelled - && notifyCustomer) + if (prevOrderStatus != OrderStatus.Cancelled && os == OrderStatus.Cancelled && notifyCustomer) { //notification int orderCancelledCustomerNotificationQueuedEmailId = _workflowMessageService.SendOrderCancelledCustomerNotification(order, order.CustomerLanguageId); if (orderCancelledCustomerNotificationQueuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() + order.OrderNotes.Add(new OrderNote { - Note = string.Format(T("CustomerCancelledEmailQueued"), orderCancelledCustomerNotificationQueuedEmailId), + Note = string.Format(TNote("CustomerCancelledEmailQueued"), orderCancelledCustomerNotificationQueuedEmailId), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -437,8 +433,7 @@ public void CheckOrderStatus(Order order) if (order.OrderStatus == OrderStatus.Pending) { - if (order.PaymentStatus == PaymentStatus.Authorized || - order.PaymentStatus == PaymentStatus.Paid) + if (order.PaymentStatus == PaymentStatus.Authorized || order.PaymentStatus == PaymentStatus.Paid) { SetOrderStatus(order, OrderStatus.Processing, false); } @@ -446,16 +441,13 @@ public void CheckOrderStatus(Order order) if (order.OrderStatus == OrderStatus.Pending) { - if (order.ShippingStatus == ShippingStatus.PartiallyShipped || - order.ShippingStatus == ShippingStatus.Shipped || - order.ShippingStatus == ShippingStatus.Delivered) + if (order.ShippingStatus == ShippingStatus.PartiallyShipped || order.ShippingStatus == ShippingStatus.Shipped || order.ShippingStatus == ShippingStatus.Delivered) { SetOrderStatus(order, OrderStatus.Processing, false); } } - if (order.OrderStatus != OrderStatus.Cancelled && - order.OrderStatus != OrderStatus.Complete) + if (order.OrderStatus != OrderStatus.Cancelled && order.OrderStatus != OrderStatus.Complete) { if (order.PaymentStatus == PaymentStatus.Paid) { @@ -1348,7 +1340,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR //notes, messages order.OrderNotes.Add(new OrderNote() { - Note = T("OrderPlaced"), + Note = TNote("OrderPlaced"), DisplayToCustomer = false, CreatedOnUtc = utcNow }); @@ -1358,9 +1350,9 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR int orderPlacedStoreOwnerNotificationQueuedEmailId = _workflowMessageService.SendOrderPlacedStoreOwnerNotification(order, _localizationSettings.DefaultAdminLanguageId); if (orderPlacedStoreOwnerNotificationQueuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() + order.OrderNotes.Add(new OrderNote { - Note = string.Format(T("MerchantEmailQueued"), orderPlacedStoreOwnerNotificationQueuedEmailId), + Note = string.Format(TNote("MerchantEmailQueued"), orderPlacedStoreOwnerNotificationQueuedEmailId), DisplayToCustomer = false, CreatedOnUtc = utcNow }); @@ -1370,9 +1362,9 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR int orderPlacedCustomerNotificationQueuedEmailId = _workflowMessageService.SendOrderPlacedCustomerNotification(order, order.CustomerLanguageId); if (orderPlacedCustomerNotificationQueuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() + order.OrderNotes.Add(new OrderNote { - Note = string.Format(T("CustomerEmailQueued"), orderPlacedCustomerNotificationQueuedEmailId), + Note = string.Format(TNote("CustomerEmailQueued"), orderPlacedCustomerNotificationQueuedEmailId), DisplayToCustomer = false, CreatedOnUtc = utcNow }); @@ -1405,7 +1397,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR _localizationService.GetResource("ActivityLog.PublicStore.PlaceOrder"), order.GetOrderNumber()); } - + //raise event if (order.PaymentStatus == PaymentStatus.Paid) { @@ -1463,7 +1455,7 @@ public virtual void DeleteOrder(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = T("OrderDeleted"), + Note = TNote("OrderDeleted"), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -1577,7 +1569,7 @@ public virtual IList CancelRecurringPayment(RecurringPayment recurringPa //add a note initialOrder.OrderNotes.Add(new OrderNote() { - Note = T("RecurringPaymentCancelled"), + Note = TNote("RecurringPaymentCancelled"), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -1610,7 +1602,7 @@ public virtual IList CancelRecurringPayment(RecurringPayment recurringPa //add a note initialOrder.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("RecurringPaymentCancellationError"), error), + Note = string.Format(TNote("RecurringPaymentCancellationError"), error), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -1692,7 +1684,7 @@ public virtual void Ship(Shipment shipment, bool notifyCustomer) //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("ShipmentSent"), shipment.Id), + Note = string.Format(TNote("ShipmentSent"), shipment.Id), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -1706,7 +1698,7 @@ public virtual void Ship(Shipment shipment, bool notifyCustomer) { order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("CustomerShippedEmailQueued"), queuedEmailId), + Note = string.Format(TNote("CustomerShippedEmailQueued"), queuedEmailId), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -1745,7 +1737,7 @@ public virtual void Deliver(Shipment shipment, bool notifyCustomer) //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("ShipmentDelivered"), shipment.Id), + Note = string.Format(TNote("ShipmentDelivered"), shipment.Id), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -1759,7 +1751,7 @@ public virtual void Deliver(Shipment shipment, bool notifyCustomer) { order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("CustomerDeliveredEmailQueued"), queuedEmailId), + Note = string.Format(TNote("CustomerDeliveredEmailQueued"), queuedEmailId), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -1808,7 +1800,7 @@ public virtual void CancelOrder(Order order, bool notifyCustomer) //add a note order.OrderNotes.Add(new OrderNote() { - Note = T("OrderCancelled"), + Note = TNote("OrderCancelled"), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -1926,7 +1918,7 @@ public virtual void MarkAsAuthorized(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = T("OrderMarkedAsAuthorized"), + Note = TNote("OrderMarkedAsAuthorized"), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2032,7 +2024,7 @@ public virtual IList Capture(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = T("OrderCaptured"), + Note = TNote("OrderCaptured"), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2075,7 +2067,7 @@ public virtual IList Capture(Order order) _orderService.UpdateOrder(order); //log it - string logError = string.Format(T("OrderCaptureError"), order.GetOrderNumber(), error); + string logError = string.Format(TNote("OrderCaptureError"), order.GetOrderNumber(), error); _logger.InsertLog(LogLevel.Error, logError, logError); } return result.Errors; @@ -2121,7 +2113,7 @@ public virtual void MarkOrderAsPaid(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = T("OrderMarkedAsPaid"), + Note = TNote("OrderMarkedAsPaid"), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2196,7 +2188,7 @@ public virtual IList Refund(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("OrderRefunded"), _priceFormatter.FormatPrice(request.AmountToRefund, true, false)), + Note = string.Format(TNote("OrderRefunded"), _priceFormatter.FormatPrice(request.AmountToRefund, true, false)), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2227,7 +2219,7 @@ public virtual IList Refund(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("OrderRefundError"), error), + Note = string.Format(TNote("OrderRefundError"), error), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2289,7 +2281,7 @@ public virtual void RefundOffline(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("OrderMarkedAsRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), + Note = string.Format(TNote("OrderMarkedAsRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2370,7 +2362,7 @@ public virtual IList PartiallyRefund(Order order, decimal amountToRefund //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("OrderPartiallyRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), + Note = string.Format(TNote("OrderPartiallyRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2400,7 +2392,7 @@ public virtual IList PartiallyRefund(Order order, decimal amountToRefund //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("OrderPartiallyRefundError"), error), + Note = string.Format(TNote("OrderPartiallyRefundError"), error), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2470,7 +2462,7 @@ public virtual void PartiallyRefundOffline(Order order, decimal amountToRefund) //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("OrderMarkedAsPartiallyRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), + Note = string.Format(TNote("OrderMarkedAsPartiallyRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2535,7 +2527,7 @@ public virtual IList Void(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = T("OrderVoided"), + Note = TNote("OrderVoided"), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2565,7 +2557,7 @@ public virtual IList Void(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = string.Format(T("OrderVoidError"), error), + Note = string.Format(TNote("OrderVoidError"), error), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); @@ -2619,7 +2611,7 @@ public virtual void VoidOffline(Order order) //add a note order.OrderNotes.Add(new OrderNote() { - Note = T("OrderMarkedAsVoided"), + Note = TNote("OrderMarkedAsVoided"), DisplayToCustomer = false, CreatedOnUtc = DateTime.UtcNow }); diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 91cca5e43a..d479dda36e 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -161,6 +161,8 @@ + + diff --git a/src/Plugins/SmartStore.Clickatell/OrderPlacedEventConsumer.cs b/src/Plugins/SmartStore.Clickatell/OrderPlacedEventConsumer.cs index 580460d574..3ba9e1742b 100644 --- a/src/Plugins/SmartStore.Clickatell/OrderPlacedEventConsumer.cs +++ b/src/Plugins/SmartStore.Clickatell/OrderPlacedEventConsumer.cs @@ -14,7 +14,7 @@ public class OrderPlacedEventConsumer : IConsumer private readonly IPluginFinder _pluginFinder; private readonly IOrderService _orderService; private readonly IStoreContext _storeContext; - private readonly ISettingService _settingService; // codehint: sm-add + private readonly ISettingService _settingService; public OrderPlacedEventConsumer(ClickatellSettings clickatellSettings, IPluginFinder pluginFinder, @@ -26,7 +26,7 @@ public OrderPlacedEventConsumer(ClickatellSettings clickatellSettings, this._pluginFinder = pluginFinder; this._orderService = orderService; this._storeContext = storeContext; - this._settingService = settingService; // codehint: sm-add + this._settingService = settingService; } /// From 471885419de3ae23ecf0a69891341aeb3c135cab Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 1 Jul 2015 11:58:43 +0200 Subject: [PATCH 0046/1074] #709 News feed produced invalid RSS feed. Added content:encoded. Added maximum news age setting for feed export. --- changelog.md | 1 + .../Domain/News/NewsSettings.cs | 9 +- .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../Utilities/SmartSyndicationFeed.cs | 35 +++++++ ...61756463_PrimaryStoreCurrencyMultiStore.cs | 6 ++ .../SmartStore.Services/News/INewsService.cs | 14 ++- .../SmartStore.Services/News/NewsService.cs | 96 ++++++++++++++++--- .../SmartStore.Services.csproj | 1 + .../Controllers/RssActionResult.cs | 6 +- .../Models/Settings/NewsSettingsModel.cs | 3 + .../Administration/Views/Setting/News.cshtml | 9 ++ .../Controllers/NewsController.cs | 32 ++----- .../SmartStore.Web/Views/News/List.cshtml | 2 +- 13 files changed, 171 insertions(+), 44 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Utilities/SmartSyndicationFeed.cs diff --git a/changelog.md b/changelog.md index 5060856f29..fe27596550 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. * #721 Message Queue: implement "Delete all" * #725 Prevent LowestProductPrice being 0 +* #709 News feed produced invalid RSS feed. Added content:encoded. Added maximum news age setting for feed export. ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Core/Domain/News/NewsSettings.cs b/src/Libraries/SmartStore.Core/Domain/News/NewsSettings.cs index 479b3c5c9b..ffceb3edab 100644 --- a/src/Libraries/SmartStore.Core/Domain/News/NewsSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/News/NewsSettings.cs @@ -1,5 +1,4 @@ - -using SmartStore.Core.Configuration; +using SmartStore.Core.Configuration; namespace SmartStore.Core.Domain.News { @@ -12,6 +11,7 @@ public NewsSettings() ShowNewsOnMainPage = true; MainPageNewsCount = 3; NewsArchivePageSize = 10; + MaxAgeInDays = 180; } /// @@ -44,6 +44,11 @@ public NewsSettings() /// public int NewsArchivePageSize { get; set; } + /// + /// The maximum age of news (in days) for RSS feed + /// + public int MaxAgeInDays { get; set; } + /// /// Enable the news RSS feed link in customers browser address bar /// diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index fa13b5e483..c1e2d2bae1 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -560,6 +560,7 @@ + diff --git a/src/Libraries/SmartStore.Core/Utilities/SmartSyndicationFeed.cs b/src/Libraries/SmartStore.Core/Utilities/SmartSyndicationFeed.cs new file mode 100644 index 0000000000..ccc8d5e68d --- /dev/null +++ b/src/Libraries/SmartStore.Core/Utilities/SmartSyndicationFeed.cs @@ -0,0 +1,35 @@ +using System; +using System.ServiceModel.Syndication; +using System.Xml; +using System.Xml.Linq; +using SmartStore.Core.Domain.Localization; + +namespace SmartStore.Utilities +{ + public class SmartSyndicationFeed : SyndicationFeed + { + public SmartSyndicationFeed(Uri feedAlternateLink, string title, string description = null) + : base(title, description ?? title, feedAlternateLink, null, DateTime.UtcNow) + { + } + + public static string UrlAtom { get { return "http://www.w3.org/2005/Atom"; } } + public static string UrlPurlContent { get { return "http://purl.org/rss/1.0/modules/content/"; } } + + public void AddNamespaces(bool purlContent) + { + this.AttributeExtensions.Add(new XmlQualifiedName("atom", XNamespace.Xmlns.NamespaceName), UrlAtom); + + if (purlContent) + this.AttributeExtensions.Add(new XmlQualifiedName("content", XNamespace.Xmlns.ToString()), UrlPurlContent); + } + + public void Init(string selfLink, Language language = null) + { + this.ElementExtensions.Add(new XElement(((XNamespace)UrlAtom) + "link", new XAttribute("href", selfLink), new XAttribute("rel", "self"), new XAttribute("type", "application/rss+xml"))); + + if (language != null) + this.Language = language.LanguageCulture.EmptyNull().ToLower(); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index 95492db892..e6954aacb8 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -131,6 +131,12 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies whether the store should be SSL secured.", "Legt fest, ob der Shop SSL gesichert werden soll."); + builder.AddOrUpdate("Admin.Configuration.Settings.News.MaxAgeInDays", + "Maximum age (in days)", + "Maximales Alter (in Tagen)", + "Specifies the maximum news age in days. Older news are not exported in the RSS feed.", + "Legt das maximale News-Alter in Tagen fest. ltere News werden im RSS-Feed nicht exportiert."); + builder.Delete("Admin.Configuration.Currencies.CantDeletePrimary"); builder.Delete("Admin.Configuration.Currencies.CantDeleteExchange"); builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryStoreCurrency"); diff --git a/src/Libraries/SmartStore.Services/News/INewsService.cs b/src/Libraries/SmartStore.Services/News/INewsService.cs index e2308c6260..c07cceb570 100644 --- a/src/Libraries/SmartStore.Services/News/INewsService.cs +++ b/src/Libraries/SmartStore.Services/News/INewsService.cs @@ -1,6 +1,9 @@ +using System; using System.Linq; +using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.News; +using SmartStore.Utilities; namespace SmartStore.Services.News { @@ -37,8 +40,9 @@ public partial interface INewsService /// Page index /// Page size /// A value indicating whether to show hidden records + /// The maximum age of returned news /// News items - IPagedList GetAllNews(int languageId, int storeId, int pageIndex, int pageSize, bool showHidden = false); + IPagedList GetAllNews(int languageId, int storeId, int pageIndex, int pageSize, bool showHidden = false, DateTime? maxAge = null); /// /// Inserts a news item @@ -57,5 +61,13 @@ public partial interface INewsService /// /// News item void UpdateCommentTotals(NewsItem newsItem); + + /// + /// Creates a RSS feed with news items + /// + /// UrlHelper to generate URLs + /// Language identifier + /// SmartSyndicationFeed object + SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int languageId); } } diff --git a/src/Libraries/SmartStore.Services/News/NewsService.cs b/src/Libraries/SmartStore.Services/News/NewsService.cs index c715f78a84..77ad186e06 100644 --- a/src/Libraries/SmartStore.Services/News/NewsService.cs +++ b/src/Libraries/SmartStore.Services/News/NewsService.cs @@ -1,11 +1,16 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.ServiceModel.Syndication; +using System.Web.Mvc; using SmartStore.Core; -using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.News; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; +using SmartStore.Services.Localization; +using SmartStore.Services.Seo; +using SmartStore.Utilities; namespace SmartStore.Services.News { @@ -18,8 +23,10 @@ public partial class NewsService : INewsService private readonly IRepository _newsItemRepository; private readonly IRepository _storeMappingRepository; - private readonly ICacheManager _cacheManager; - private readonly IEventPublisher _eventPublisher; + private readonly ICommonServices _services; + private readonly ILanguageService _languageService; + + private readonly NewsSettings _newsSettings; #endregion @@ -27,13 +34,15 @@ public partial class NewsService : INewsService public NewsService(IRepository newsItemRepository, IRepository storeMappingRepository, - ICacheManager cacheManager, - IEventPublisher eventPublisher) + ICommonServices services, + ILanguageService languageService, + NewsSettings newsSettings) { _newsItemRepository = newsItemRepository; _storeMappingRepository = storeMappingRepository; - _cacheManager = cacheManager; - _eventPublisher = eventPublisher; + _services = services; + _languageService = languageService; + _newsSettings = newsSettings; this.QuerySettings = DbQuerySettings.Default; } @@ -56,7 +65,7 @@ public virtual void DeleteNews(NewsItem newsItem) _newsItemRepository.Delete(newsItem); //event notification - _eventPublisher.EntityDeleted(newsItem); + _services.EventPublisher.EntityDeleted(newsItem); } /// @@ -98,12 +107,22 @@ where newsIds.Contains(x.Id) /// Page index /// Page size /// A value indicating whether to show hidden records + /// The maximum age of returned news /// News items - public virtual IPagedList GetAllNews(int languageId, int storeId, int pageIndex, int pageSize, bool showHidden = false) + public virtual IPagedList GetAllNews(int languageId, int storeId, int pageIndex, int pageSize, bool showHidden = false, DateTime? maxAge = null) { var query = _newsItemRepository.Table; - if (languageId > 0) - query = query.Where(n => languageId == n.LanguageId); + + if (languageId > 0) + { + query = query.Where(n => languageId == n.LanguageId); + } + + if (maxAge.HasValue) + { + query = query.Where(n => n.CreatedOnUtc >= maxAge.Value); + } + if (!showHidden) { var utcNow = DateTime.UtcNow; @@ -111,6 +130,7 @@ public virtual IPagedList GetAllNews(int languageId, int storeId, int query = query.Where(n => !n.StartDateUtc.HasValue || n.StartDateUtc <= utcNow); query = query.Where(n => !n.EndDateUtc.HasValue || n.EndDateUtc >= utcNow); } + query = query.OrderByDescending(n => n.CreatedOnUtc); //Store mapping @@ -128,6 +148,7 @@ from sm in n_sm.DefaultIfEmpty() group n by n.Id into nGroup orderby nGroup.Key select nGroup.FirstOrDefault(); + query = query.OrderByDescending(n => n.CreatedOnUtc); } @@ -147,7 +168,7 @@ public virtual void InsertNews(NewsItem news) _newsItemRepository.Insert(news); //event notification - _eventPublisher.EntityInserted(news); + _services.EventPublisher.EntityInserted(news); } /// @@ -162,7 +183,7 @@ public virtual void UpdateNews(NewsItem news) _newsItemRepository.Update(news); //event notification - _eventPublisher.EntityUpdated(news); + _services.EventPublisher.EntityUpdated(news); } /// @@ -190,6 +211,55 @@ public virtual void UpdateCommentTotals(NewsItem newsItem) UpdateNews(newsItem); } + /// + /// Creates a RSS feed with news items + /// + /// UrlHelper to generate URLs + /// Language identifier + /// SmartSyndicationFeed object + public virtual SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int languageId) + { + if (urlHelper == null) + throw new ArgumentNullException("urlHelper"); + + DateTime? maxAge = null; + var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = urlHelper.Action("rss", null, new { languageId = languageId }, protocol); + var newsLink = urlHelper.RouteUrl("NewsArchive", null, protocol); + + var title = "{0} - News".FormatInvariant(_services.StoreContext.CurrentStore.Name); + + if (_newsSettings.MaxAgeInDays > 0) + maxAge = DateTime.UtcNow.Subtract(new TimeSpan(_newsSettings.MaxAgeInDays, 0, 0, 0)); + + var language = _languageService.GetLanguageById(languageId); + var feed = new SmartSyndicationFeed(new Uri(newsLink), title); + + feed.AddNamespaces(true); + feed.Init(selfLink, language); + + if (!_newsSettings.Enabled) + return feed; + + var items = new List(); + var newsItems = GetAllNews(languageId, _services.StoreContext.CurrentStore.Id, 0, int.MaxValue, false, maxAge); + + foreach (var n in newsItems) + { + var newsUrl = urlHelper.RouteUrl("NewsItem", new { SeName = n.GetSeName(n.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); + + var item = new SyndicationItem(n.Title, n.Short, new Uri(newsUrl), newsUrl, n.CreatedOnUtc); + + item.ElementExtensions.Add("encoded", SmartSyndicationFeed.UrlPurlContent, n.Full); + + items.Add(item); + } + + feed.Items = items; + + return feed; + } + #endregion } } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 91cca5e43a..de2ce339ea 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -113,6 +113,7 @@ ..\..\packages\System.Linq.Dynamic.1.0.0\lib\net40\System.Linq.Dynamic.dll + False diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/RssActionResult.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/RssActionResult.cs index 2015b85b1b..eb6c4dd45a 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/RssActionResult.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/RssActionResult.cs @@ -12,8 +12,10 @@ public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.ContentType = "application/rss+xml"; - var rssFormatter = new Rss20FeedFormatter(Feed); - using (var writer = XmlWriter.Create(context.HttpContext.Response.Output)) + var rssFormatter = new Rss20FeedFormatter(Feed, false); + var settings = new XmlWriterSettings { Indent = true, IndentChars = "\t", CheckCharacters = false }; + + using (var writer = XmlWriter.Create(context.HttpContext.Response.Output, settings)) { rssFormatter.WriteTo(writer); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/NewsSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/NewsSettingsModel.cs index 4bc18260a2..f7a00fd03e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/NewsSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/NewsSettingsModel.cs @@ -22,6 +22,9 @@ public class NewsSettingsModel [SmartResourceDisplayName("Admin.Configuration.Settings.News.NewsArchivePageSize")] public int NewsArchivePageSize { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.News.MaxAgeInDays")] + public int MaxAgeInDays { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.News.ShowHeaderRSSUrl")] public bool ShowHeaderRssUrl { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/News.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/News.cshtml index cf0d619047..cd65a40c30 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/News.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/News.cshtml @@ -73,6 +73,15 @@ @Html.ValidationMessageFor(model => model.NewsArchivePageSize) + + + @Html.SmartLabelFor(model => model.MaxAgeInDays) + + + @Html.SettingEditorFor(model => model.MaxAgeInDays) + @Html.ValidationMessageFor(model => model.MaxAgeInDays) + + @Html.SmartLabelFor(model => model.ShowHeaderRssUrl) diff --git a/src/Presentation/SmartStore.Web/Controllers/NewsController.cs b/src/Presentation/SmartStore.Web/Controllers/NewsController.cs index ccc30b1c10..b3ada79a8b 100644 --- a/src/Presentation/SmartStore.Web/Controllers/NewsController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/NewsController.cs @@ -1,27 +1,24 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.ServiceModel.Syndication; using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Caching; -using SmartStore.Core.Domain; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.News; +using SmartStore.Core.Logging; using SmartStore.Services.Common; using SmartStore.Services.Customers; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.News; using SmartStore.Services.Seo; using SmartStore.Services.Stores; -using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Mvc; using SmartStore.Web.Framework.Security; using SmartStore.Web.Framework.UI.Captcha; using SmartStore.Web.Infrastructure.Cache; @@ -208,28 +205,12 @@ public ActionResult List(NewsPagingFilteringModel command) return View(model); } - [ActionName("rss")] + [ActionName("rss"), Compress] public ActionResult ListRss(int languageId) { - var feed = new SyndicationFeed( - string.Format("{0}: News", _storeContext.CurrentStore.Name), - "News", - new Uri(_webHelper.GetStoreLocation(false)), - "NewsRSS", - DateTime.UtcNow); - - if (!_newsSettings.Enabled) - return new RssActionResult() { Feed = feed }; + var feed = _newsService.CreateRssFeed(Url, languageId); - var items = new List(); - var newsItems = _newsService.GetAllNews(languageId, _storeContext.CurrentStore.Id, 0, int.MaxValue); - foreach (var n in newsItems) - { - string newsUrl = Url.RouteUrl("NewsItem", new { SeName = n.GetSeName(n.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); - items.Add(new SyndicationItem(n.Title, n.Short, new Uri(newsUrl), String.Format("Blog:{0}", n.Id), n.CreatedOnUtc)); - } - feed.Items = items; - return new RssActionResult() { Feed = feed }; + return new RssActionResult { Feed = feed }; } public ActionResult NewsItem(int newsItemId) @@ -319,7 +300,8 @@ public ActionResult RssHeaderLink() return Content(""); string link = string.Format("", - Url.Action("rss", null, new { languageId = _workContext.WorkingLanguage.Id }, _webHelper.IsCurrentConnectionSecured() ? "https" : "http"), _storeContext.CurrentStore.Name); + Url.Action("rss", null, new { languageId = _workContext.WorkingLanguage.Id }, _webHelper.IsCurrentConnectionSecured() ? "https" : "http"), + _storeContext.CurrentStore.Name); return Content(link); } diff --git a/src/Presentation/SmartStore.Web/Views/News/List.cshtml b/src/Presentation/SmartStore.Web/Views/News/List.cshtml index 5a282b3eb4..cd0474dbad 100644 --- a/src/Presentation/SmartStore.Web/Views/News/List.cshtml +++ b/src/Presentation/SmartStore.Web/Views/News/List.cshtml @@ -10,7 +10,7 @@ }
- + @T("News.RSS") From 714ac296ef1118704e1908e7909e4c38bea740d4 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 1 Jul 2015 14:53:50 +0200 Subject: [PATCH 0047/1074] #709 Blog post RSS feed improvements. --- .../Domain/Blogs/BlogSettings.cs | 6 ++ ...61756463_PrimaryStoreCurrencyMultiStore.cs | 6 ++ .../SmartStore.Services/Blogs/BlogService.cs | 86 ++++++++++++++++--- .../SmartStore.Services/Blogs/IBlogService.cs | 13 ++- .../SmartStore.Services/News/NewsService.cs | 8 +- .../Models/Settings/BlogSettingsModel.cs | 3 + .../Administration/Views/Setting/Blog.cshtml | 9 ++ .../Controllers/BlogController.cs | 26 ++---- 8 files changed, 120 insertions(+), 37 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Domain/Blogs/BlogSettings.cs b/src/Libraries/SmartStore.Core/Domain/Blogs/BlogSettings.cs index 8a1b5ca08e..e0c7492934 100644 --- a/src/Libraries/SmartStore.Core/Domain/Blogs/BlogSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Blogs/BlogSettings.cs @@ -11,6 +11,7 @@ public BlogSettings() PostsPageSize = 10; AllowNotRegisteredUsersToLeaveComments = true; NumberOfTags = 15; + MaxAgeInDays = 180; } /// @@ -38,6 +39,11 @@ public BlogSettings() /// public int NumberOfTags { get; set; } + /// + /// The maximum age of blog items (in days) for RSS feed + /// + public int MaxAgeInDays { get; set; } + /// /// Enable the blog RSS feed link in customers browser address bar /// diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index e6954aacb8..1903182830 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -137,6 +137,12 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies the maximum news age in days. Older news are not exported in the RSS feed.", "Legt das maximale News-Alter in Tagen fest. ltere News werden im RSS-Feed nicht exportiert."); + builder.AddOrUpdate("Admin.Configuration.Settings.Blog.MaxAgeInDays", + "Maximum age (in days)", + "Maximales Alter (in Tagen)", + "Specifies the maximum news age in days. Older blog posts are not exported in the RSS feed.", + "Legt das maximale Blog-Alter in Tagen fest. ltere Blog-Eintrge werden im RSS-Feed nicht exportiert."); + builder.Delete("Admin.Configuration.Currencies.CantDeletePrimary"); builder.Delete("Admin.Configuration.Currencies.CantDeleteExchange"); builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryStoreCurrency"); diff --git a/src/Libraries/SmartStore.Services/Blogs/BlogService.cs b/src/Libraries/SmartStore.Services/Blogs/BlogService.cs index 79a9d607e2..8ed8612483 100644 --- a/src/Libraries/SmartStore.Services/Blogs/BlogService.cs +++ b/src/Libraries/SmartStore.Services/Blogs/BlogService.cs @@ -1,12 +1,16 @@ using System; using System.Collections.Generic; using System.Linq; +using System.ServiceModel.Syndication; +using System.Web.Mvc; using SmartStore.Core; -using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Blogs; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; +using SmartStore.Services.Localization; +using SmartStore.Services.Seo; +using SmartStore.Utilities; namespace SmartStore.Services.Blogs { @@ -15,13 +19,14 @@ namespace SmartStore.Services.Blogs ///
public partial class BlogService : IBlogService { - #region Fields private readonly IRepository _blogPostRepository; private readonly IRepository _storeMappingRepository; - private readonly ICacheManager _cacheManager; - private readonly IEventPublisher _eventPublisher; + private readonly ICommonServices _services; + private readonly ILanguageService _languageService; + + private readonly BlogSettings _blogSettings; #endregion @@ -29,13 +34,15 @@ public partial class BlogService : IBlogService public BlogService(IRepository blogPostRepository, IRepository storeMappingRepository, - ICacheManager cacheManager, - IEventPublisher eventPublisher) + ICommonServices services, + ILanguageService languageService, + BlogSettings blogSettings) { _blogPostRepository = blogPostRepository; _storeMappingRepository = storeMappingRepository; - _cacheManager = cacheManager; - _eventPublisher = eventPublisher; + _services = services; + _languageService = languageService; + _blogSettings = blogSettings; this.QuerySettings = DbQuerySettings.Default; } @@ -58,7 +65,7 @@ public virtual void DeleteBlogPost(BlogPost blogPost) _blogPostRepository.Delete(blogPost); //event notification - _eventPublisher.EntityDeleted(blogPost); + _services.EventPublisher.EntityDeleted(blogPost); } /// @@ -84,17 +91,25 @@ public virtual BlogPost GetBlogPostById(int blogPostId) /// Page index /// Page size /// A value indicating whether to show hidden records + /// The maximum age of returned blog posts /// Blog posts public virtual IPagedList GetAllBlogPosts(int storeId, int languageId, - DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false) + DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false, DateTime? maxAge = null) { var query = _blogPostRepository.Table; + if (dateFrom.HasValue) query = query.Where(b => dateFrom.Value <= b.CreatedOnUtc); + if (dateTo.HasValue) query = query.Where(b => dateTo.Value >= b.CreatedOnUtc); + if (languageId > 0) query = query.Where(b => languageId == b.LanguageId); + + if (maxAge.HasValue) + query = query.Where(b => b.CreatedOnUtc >= maxAge.Value); + if (!showHidden) { var utcNow = DateTime.UtcNow; @@ -202,7 +217,7 @@ public virtual void InsertBlogPost(BlogPost blogPost) _blogPostRepository.Insert(blogPost); //event notification - _eventPublisher.EntityInserted(blogPost); + _services.EventPublisher.EntityInserted(blogPost); } /// @@ -217,7 +232,7 @@ public virtual void UpdateBlogPost(BlogPost blogPost) _blogPostRepository.Update(blogPost); //event notification - _eventPublisher.EntityUpdated(blogPost); + _services.EventPublisher.EntityUpdated(blogPost); } /// @@ -245,6 +260,53 @@ public virtual void UpdateCommentTotals(BlogPost blogPost) UpdateBlogPost(blogPost); } + /// + /// Creates a RSS feed with blog posts + /// + /// UrlHelper to generate URLs + /// Language identifier + /// SmartSyndicationFeed object + public virtual SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int languageId) + { + if (urlHelper == null) + throw new ArgumentNullException("urlHelper"); + + DateTime? maxAge = null; + var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = urlHelper.RouteUrl("BlogRSS", new { languageId = languageId }, protocol); + var blogLink = urlHelper.RouteUrl("Blog", null, protocol); + + var title = "{0} - Blog".FormatInvariant(_services.StoreContext.CurrentStore.Name); + + if (_blogSettings.MaxAgeInDays > 0) + maxAge = DateTime.UtcNow.Subtract(new TimeSpan(_blogSettings.MaxAgeInDays, 0, 0, 0)); + + var language = _languageService.GetLanguageById(languageId); + var feed = new SmartSyndicationFeed(new Uri(blogLink), title); + + feed.AddNamespaces(false); + feed.Init(selfLink, language); + + if (!_blogSettings.Enabled) + return feed; + + var items = new List(); + var blogPosts = GetAllBlogPosts(_services.StoreContext.CurrentStore.Id, languageId, null, null, 0, int.MaxValue, false, maxAge); + + foreach (var blogPost in blogPosts) + { + var blogPostUrl = urlHelper.RouteUrl("BlogPost", new { SeName = blogPost.GetSeName(blogPost.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); + + var item = new SyndicationItem(blogPost.Title, blogPost.Body.RemoveInvalidXmlChars(), new Uri(blogPostUrl), blogPostUrl, blogPost.CreatedOnUtc); + + items.Add(item); + } + + feed.Items = items; + + return feed; + } + #endregion } } diff --git a/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs b/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs index eabf47a802..983932b0bf 100644 --- a/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs +++ b/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Blogs; +using SmartStore.Utilities; namespace SmartStore.Services.Blogs { @@ -33,9 +35,10 @@ public partial interface IBlogService /// Page index /// Page size /// A value indicating whether to show hidden records + /// The maximum age of returned blog posts /// Blog posts IPagedList GetAllBlogPosts(int storeId, int languageId, - DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false); + DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false, DateTime? maxAge = null); /// /// Gets all blog posts @@ -76,5 +79,13 @@ IPagedList GetAllBlogPostsByTag(int storeId, int languageId, string ta /// /// Blog post void UpdateCommentTotals(BlogPost blogPost); + + /// + /// Creates a RSS feed with blog posts + /// + /// UrlHelper to generate URLs + /// Language identifier + /// SmartSyndicationFeed object + SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int languageId); } } diff --git a/src/Libraries/SmartStore.Services/News/NewsService.cs b/src/Libraries/SmartStore.Services/News/NewsService.cs index 77ad186e06..c0d576ca29 100644 --- a/src/Libraries/SmartStore.Services/News/NewsService.cs +++ b/src/Libraries/SmartStore.Services/News/NewsService.cs @@ -244,13 +244,13 @@ public virtual SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int langu var items = new List(); var newsItems = GetAllNews(languageId, _services.StoreContext.CurrentStore.Id, 0, int.MaxValue, false, maxAge); - foreach (var n in newsItems) + foreach (var news in newsItems) { - var newsUrl = urlHelper.RouteUrl("NewsItem", new { SeName = n.GetSeName(n.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); + var newsUrl = urlHelper.RouteUrl("NewsItem", new { SeName = news.GetSeName(news.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); - var item = new SyndicationItem(n.Title, n.Short, new Uri(newsUrl), newsUrl, n.CreatedOnUtc); + var item = new SyndicationItem(news.Title, news.Short.RemoveInvalidXmlChars(), new Uri(newsUrl), newsUrl, news.CreatedOnUtc); - item.ElementExtensions.Add("encoded", SmartSyndicationFeed.UrlPurlContent, n.Full); + item.ElementExtensions.Add("encoded", SmartSyndicationFeed.UrlPurlContent, news.Full.RemoveInvalidXmlChars()); items.Add(item); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/BlogSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/BlogSettingsModel.cs index 17b4578b0f..1e16f2230d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/BlogSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/BlogSettingsModel.cs @@ -20,6 +20,9 @@ public class BlogSettingsModel : ModelBase [SmartResourceDisplayName("Admin.Configuration.Settings.Blog.NumberOfTags")] public int NumberOfTags { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.Blog.MaxAgeInDays")] + public int MaxAgeInDays { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.Blog.ShowHeaderRSSUrl")] public bool ShowHeaderRssUrl { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Blog.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Blog.cshtml index dc64352a48..973aa0703f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Blog.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Blog.cshtml @@ -64,6 +64,15 @@ @Html.ValidationMessageFor(model => model.NumberOfTags) + + + @Html.SmartLabelFor(model => model.MaxAgeInDays) + + + @Html.SettingEditorFor(model => model.MaxAgeInDays) + @Html.ValidationMessageFor(model => model.MaxAgeInDays) + + @Html.SmartLabelFor(model => model.ShowHeaderRssUrl) diff --git a/src/Presentation/SmartStore.Web/Controllers/BlogController.cs b/src/Presentation/SmartStore.Web/Controllers/BlogController.cs index a1aa99e822..194543c724 100644 --- a/src/Presentation/SmartStore.Web/Controllers/BlogController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/BlogController.cs @@ -27,6 +27,7 @@ using SmartStore.Web.Framework.UI.Captcha; using SmartStore.Web.Infrastructure.Cache; using SmartStore.Web.Models.Blogs; +using SmartStore.Web.Framework.Mvc; namespace SmartStore.Web.Controllers { @@ -228,28 +229,12 @@ public ActionResult BlogByMonth(BlogPagingFilteringModel command) return View("List", model); } + [Compress] public ActionResult ListRss(int languageId) { - var feed = new SyndicationFeed( - string.Format("{0}: Blog", _storeContext.CurrentStore.Name), - "Blog", - new Uri(_webHelper.GetStoreLocation(false)), - "BlogRSS", - DateTime.UtcNow); + var feed = _blogService.CreateRssFeed(Url, languageId); - if (!_blogSettings.Enabled) - return new RssActionResult() { Feed = feed }; - - var items = new List(); - var blogPosts = _blogService.GetAllBlogPosts(_storeContext.CurrentStore.Id, languageId, - null, null, 0, int.MaxValue); - foreach (var blogPost in blogPosts) - { - string blogPostUrl = Url.RouteUrl("BlogPost", new { SeName = blogPost.GetSeName(blogPost.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); - items.Add(new SyndicationItem(blogPost.Title, blogPost.Body, new Uri(blogPostUrl), String.Format("Blog:{0}", blogPost.Id), blogPost.CreatedOnUtc)); - } - feed.Items = items; - return new RssActionResult() { Feed = feed }; + return new RssActionResult { Feed = feed }; } public ActionResult BlogPost(int blogPostId) @@ -449,11 +434,12 @@ public ActionResult RssHeaderLink() if (!_blogSettings.Enabled || !_blogSettings.ShowHeaderRssUrl) return Content(""); - string link = string.Format("", + string link = string.Format("", Url.RouteUrl("BlogRSS", new { languageId = _workContext.WorkingLanguage.Id }, _webHelper.IsCurrentConnectionSecured() ? "https" : "http"), _storeContext.CurrentStore.Name); return Content(link); } + #endregion } } From ed957839c4d8f92bb39a80f1b1c2a444044340c8 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 1 Jul 2015 21:09:47 +0200 Subject: [PATCH 0048/1074] #709 Recently added products RSS feed improvements. --- .../Utilities/SmartSyndicationFeed.cs | 46 ++++- .../SmartStore.Services/Blogs/BlogService.cs | 2 +- .../Catalog/IProductService.cs | 9 + .../Catalog/ProductService.cs | 160 +++++++++++++----- .../SmartStore.Services/News/NewsService.cs | 6 +- .../Controllers/CatalogController.cs | 34 +--- .../Catalog/RecentlyAddedProducts.cshtml | 10 +- 7 files changed, 187 insertions(+), 80 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Utilities/SmartSyndicationFeed.cs b/src/Libraries/SmartStore.Core/Utilities/SmartSyndicationFeed.cs index ccc8d5e68d..f93e4e6ea3 100644 --- a/src/Libraries/SmartStore.Core/Utilities/SmartSyndicationFeed.cs +++ b/src/Libraries/SmartStore.Core/Utilities/SmartSyndicationFeed.cs @@ -3,6 +3,7 @@ using System.Xml; using System.Xml.Linq; using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Media; namespace SmartStore.Utilities { @@ -21,15 +22,58 @@ public void AddNamespaces(bool purlContent) this.AttributeExtensions.Add(new XmlQualifiedName("atom", XNamespace.Xmlns.NamespaceName), UrlAtom); if (purlContent) + { this.AttributeExtensions.Add(new XmlQualifiedName("content", XNamespace.Xmlns.ToString()), UrlPurlContent); + } } public void Init(string selfLink, Language language = null) { - this.ElementExtensions.Add(new XElement(((XNamespace)UrlAtom) + "link", new XAttribute("href", selfLink), new XAttribute("rel", "self"), new XAttribute("type", "application/rss+xml"))); + this.ElementExtensions.Add( + new XElement(((XNamespace)UrlAtom) + "link", + new XAttribute("href", selfLink), + new XAttribute("rel", "self"), + new XAttribute("type", "application/rss+xml"))); if (language != null) + { this.Language = language.LanguageCulture.EmptyNull().ToLower(); + } + } + + public SyndicationItem CreateItem(string title, string synopsis, string url, DateTimeOffset published, string contentEncoded = null) + { + var item = new SyndicationItem( + title.RemoveInvalidXmlChars().EmptyNull(), + synopsis.RemoveInvalidXmlChars().EmptyNull(), + new Uri(url), + url, + published); + + if (contentEncoded != null) + { + item.ElementExtensions.Add("encoded", SmartSyndicationFeed.UrlPurlContent, contentEncoded.RemoveInvalidXmlChars().EmptyNull()); + } + + return item; + } + + public bool AddEnclosue(SyndicationItem item, Picture picture, string pictureUrl) + { + if (picture != null && pictureUrl.HasValue()) + { + long pictureLength = 10000; // 0 omits the length attribute but that invalidates the feed + + if (picture.PictureBinary != null) + pictureLength = picture.PictureBinary.LongLength; + + var enclosure = SyndicationLink.CreateMediaEnclosureLink(new Uri(pictureUrl), picture.MimeType.EmptyNull(), pictureLength); + + item.Links.Add(enclosure); + + return true; + } + return false; } } } diff --git a/src/Libraries/SmartStore.Services/Blogs/BlogService.cs b/src/Libraries/SmartStore.Services/Blogs/BlogService.cs index 8ed8612483..c616abefbe 100644 --- a/src/Libraries/SmartStore.Services/Blogs/BlogService.cs +++ b/src/Libraries/SmartStore.Services/Blogs/BlogService.cs @@ -297,7 +297,7 @@ public virtual SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int langu { var blogPostUrl = urlHelper.RouteUrl("BlogPost", new { SeName = blogPost.GetSeName(blogPost.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); - var item = new SyndicationItem(blogPost.Title, blogPost.Body.RemoveInvalidXmlChars(), new Uri(blogPostUrl), blogPostUrl, blogPost.CreatedOnUtc); + var item = feed.CreateItem(blogPost.Title, blogPost.Body, blogPostUrl, blogPost.CreatedOnUtc); items.Add(item); } diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductService.cs index aa3199641f..e080a437b5 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductService.cs @@ -2,9 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Orders; +using SmartStore.Utilities; namespace SmartStore.Services.Catalog { @@ -151,6 +153,13 @@ public partial interface IProductService /// Product void UpdateHasDiscountsApplied(Product product); + /// + /// Creates a RSS feed with recently added products + /// + /// UrlHelper to generate URLs + /// SmartSyndicationFeed object + SmartSyndicationFeed CreateRecentlyAddedProductsRssFeed(UrlHelper urlHelper); + #endregion #region Related products diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs index 2f8c1270e3..5618ba86ad 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs @@ -3,19 +3,24 @@ using System.Data; using System.Linq; using System.Linq.Expressions; +using System.ServiceModel.Syndication; +using System.Web.Mvc; using SmartStore.Core; -using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Security; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; using SmartStore.Services.Localization; +using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.Orders; +using SmartStore.Services.Seo; +using SmartStore.Utilities; namespace SmartStore.Services.Catalog { @@ -50,12 +55,12 @@ public partial class ProductService : IProductService private readonly IWorkflowMessageService _workflowMessageService; private readonly IDataProvider _dataProvider; private readonly IDbContext _dbContext; - private readonly ICacheManager _cacheManager; - private readonly IWorkContext _workContext; - private readonly IStoreContext _storeContext; private readonly LocalizationSettings _localizationSettings; private readonly CommonSettings _commonSettings; - private readonly IEventPublisher _eventPublisher; + private readonly ICommonServices _services; + private readonly CatalogSettings _catalogSettings; + private readonly MediaSettings _mediaSettings; + private readonly IPictureService _pictureService; #endregion @@ -85,7 +90,7 @@ public partial class ProductService : IProductService /// Localization settings /// Common settings /// Event published - public ProductService(ICacheManager cacheManager, + public ProductService( IRepository productRepository, IRepository relatedProductRepository, IRepository crossSellProductRepository, @@ -101,13 +106,15 @@ public ProductService(ICacheManager cacheManager, IProductAttributeParser productAttributeParser, ILanguageService languageService, IWorkflowMessageService workflowMessageService, - IDataProvider dataProvider, IDbContext dbContext, - IWorkContext workContext, - IStoreContext storeContext, - LocalizationSettings localizationSettings, CommonSettings commonSettings, - IEventPublisher eventPublisher) + IDataProvider dataProvider, + IDbContext dbContext, + LocalizationSettings localizationSettings, + CommonSettings commonSettings, + ICommonServices services, + CatalogSettings catalogSettings, + MediaSettings mediaSettings, + IPictureService pictureService) { - this._cacheManager = cacheManager; this._productRepository = productRepository; this._relatedProductRepository = relatedProductRepository; this._crossSellProductRepository = crossSellProductRepository; @@ -125,11 +132,12 @@ public ProductService(ICacheManager cacheManager, this._workflowMessageService = workflowMessageService; this._dataProvider = dataProvider; this._dbContext = dbContext; - this._workContext = workContext; - this._storeContext = storeContext; this._localizationSettings = localizationSettings; this._commonSettings = commonSettings; - this._eventPublisher = eventPublisher; + this._services = services; + this._catalogSettings = catalogSettings; + this._mediaSettings = mediaSettings; + this._pictureService = pictureService; this.QuerySettings = DbQuerySettings.Default; } @@ -264,7 +272,7 @@ public virtual Product GetProductById(int productId) return null; string key = string.Format(PRODUCTS_BY_ID_KEY, productId); - return _cacheManager.Get(key, () => + return _services.Cache.Get(key, () => { return _productRepository.GetById(productId); }); @@ -306,10 +314,10 @@ public virtual void InsertProduct(Product product) _productRepository.Insert(product); //clear cache - _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(product); + _services.EventPublisher.EntityInserted(product); } /// @@ -331,12 +339,12 @@ public virtual void UpdateProduct(Product product, bool publishEvent = true) _productRepository.Update(product); // cache - _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); // event notification if (publishEvent && modified) { - _eventPublisher.EntityUpdated(product); + _services.EventPublisher.EntityUpdated(product); } } @@ -355,7 +363,7 @@ public virtual IPagedList SearchProducts(ProductSearchContext ctx) ctx.FilterableSpecificationAttributeOptionIds = new List(); - _eventPublisher.Publish(new ProductsSearchingEvent(ctx)); + _services.EventPublisher.Publish(new ProductsSearchingEvent(ctx)); //search by keyword bool searchLocalizedValue = false; @@ -378,7 +386,7 @@ public virtual IPagedList SearchProducts(ProductSearchContext ctx) ctx.CategoryIds.Remove(0); //Access control list. Allowed customer roles - var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles + var allowedCustomerRolesIds = _services.WorkContext.CurrentCustomer.CustomerRoles .Where(cr => cr.Active).Select(cr => cr.Id).ToList(); if (_commonSettings.UseStoredProceduresIfSupported && _dataProvider.StoredProceduresSupported) @@ -735,7 +743,7 @@ public virtual IQueryable PrepareProductSearchQuery( if (allowedCustomerRolesIds == null) { - allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles.Where(cr => cr.Active).Select(cr => cr.Id).ToList(); + allowedCustomerRolesIds = _services.WorkContext.CurrentCustomer.CustomerRoles.Where(cr => cr.Active).Select(cr => cr.Id).ToList(); } // products @@ -1249,6 +1257,76 @@ public virtual void UpdateHasDiscountsApplied(Product product) UpdateProduct(product); } + /// + /// Creates a RSS feed with recently added products + /// + /// UrlHelper to generate URLs + /// SmartSyndicationFeed object + public virtual SmartSyndicationFeed CreateRecentlyAddedProductsRssFeed(UrlHelper urlHelper) + { + if (urlHelper == null) + throw new ArgumentNullException("urlHelper"); + + var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = urlHelper.RouteUrl("RecentlyAddedProductsRSS", null, protocol); + var recentProductsLink = urlHelper.RouteUrl("RecentlyAddedProducts", null, protocol); + + var title = "{0} - {1}".FormatInvariant(_services.StoreContext.CurrentStore.Name, _services.Localization.GetResource("RSS.RecentlyAddedProducts")); + + var feed = new SmartSyndicationFeed(new Uri(recentProductsLink), title, _services.Localization.GetResource("RSS.InformationAboutProducts")); + + feed.AddNamespaces(true); + feed.Init(selfLink, _services.WorkContext.WorkingLanguage); + + if (!_catalogSettings.RecentlyAddedProductsEnabled) + return feed; + + var items = new List(); + var searchContext = new ProductSearchContext + { + LanguageId = _services.WorkContext.WorkingLanguage.Id, + OrderBy = ProductSortingEnum.CreatedOn, + PageSize = _catalogSettings.RecentlyAddedProductsNumber, + StoreId = _services.StoreContext.CurrentStoreIdIfMultiStoreMode, + VisibleIndividuallyOnly = true + }; + + var products = SearchProducts(searchContext); + var storeUrl = _services.StoreContext.CurrentStore.Url; + + foreach (var product in products) + { + string productUrl = urlHelper.RouteUrl("Product", new { SeName = product.GetSeName() }, "http"); + if (productUrl.HasValue()) + { + var item = feed.CreateItem( + product.GetLocalized(x => x.Name), + product.GetLocalized(x => x.ShortDescription), + productUrl, + product.CreatedOnUtc, + product.FullDescription); + + try + { + // we add only the first picture + var picture = product.ProductPictures.OrderBy(x => x.DisplayOrder).Select(x => x.Picture).FirstOrDefault(); + + if (picture != null) + { + feed.AddEnclosue(item, picture, _pictureService.GetPictureUrl(picture, _mediaSettings.ProductDetailsPictureSize, false, storeUrl)); + } + } + catch { } + + items.Add(item); + } + } + + feed.Items = items; + + return feed; + } + #endregion #region Related products @@ -1265,7 +1343,7 @@ public virtual void DeleteRelatedProduct(RelatedProduct relatedProduct) _relatedProductRepository.Delete(relatedProduct); //event notification - _eventPublisher.EntityDeleted(relatedProduct); + _services.EventPublisher.EntityDeleted(relatedProduct); } /// @@ -1312,7 +1390,7 @@ public virtual void InsertRelatedProduct(RelatedProduct relatedProduct) _relatedProductRepository.Insert(relatedProduct); //event notification - _eventPublisher.EntityInserted(relatedProduct); + _services.EventPublisher.EntityInserted(relatedProduct); } /// @@ -1327,7 +1405,7 @@ public virtual void UpdateRelatedProduct(RelatedProduct relatedProduct) _relatedProductRepository.Update(relatedProduct); //event notification - _eventPublisher.EntityUpdated(relatedProduct); + _services.EventPublisher.EntityUpdated(relatedProduct); } /// @@ -1363,7 +1441,7 @@ public virtual void DeleteCrossSellProduct(CrossSellProduct crossSellProduct) _crossSellProductRepository.Delete(crossSellProduct); //event notification - _eventPublisher.EntityDeleted(crossSellProduct); + _services.EventPublisher.EntityDeleted(crossSellProduct); } /// @@ -1411,7 +1489,7 @@ public virtual void InsertCrossSellProduct(CrossSellProduct crossSellProduct) _crossSellProductRepository.Insert(crossSellProduct); //event notification - _eventPublisher.EntityInserted(crossSellProduct); + _services.EventPublisher.EntityInserted(crossSellProduct); } /// @@ -1426,7 +1504,7 @@ public virtual void UpdateCrossSellProduct(CrossSellProduct crossSellProduct) _crossSellProductRepository.Update(crossSellProduct); //event notification - _eventPublisher.EntityUpdated(crossSellProduct); + _services.EventPublisher.EntityUpdated(crossSellProduct); } /// @@ -1510,10 +1588,10 @@ public virtual void DeleteTierPrice(TierPrice tierPrice) _tierPriceRepository.Delete(tierPrice); - _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(tierPrice); + _services.EventPublisher.EntityDeleted(tierPrice); } /// @@ -1541,10 +1619,10 @@ public virtual void InsertTierPrice(TierPrice tierPrice) _tierPriceRepository.Insert(tierPrice); - _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(tierPrice); + _services.EventPublisher.EntityInserted(tierPrice); } /// @@ -1558,10 +1636,10 @@ public virtual void UpdateTierPrice(TierPrice tierPrice) _tierPriceRepository.Update(tierPrice); - _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(tierPrice); + _services.EventPublisher.EntityUpdated(tierPrice); } #endregion @@ -1582,7 +1660,7 @@ public virtual void DeleteProductPicture(ProductPicture productPicture) _productPictureRepository.Delete(productPicture); //event notification - _eventPublisher.EntityDeleted(productPicture); + _services.EventPublisher.EntityDeleted(productPicture); } private void UnassignDeletedPictureFromVariantCombinations(ProductPicture productPicture) @@ -1656,7 +1734,7 @@ public virtual void InsertProductPicture(ProductPicture productPicture) _productPictureRepository.Insert(productPicture); //event notification - _eventPublisher.EntityInserted(productPicture); + _services.EventPublisher.EntityInserted(productPicture); } /// @@ -1671,7 +1749,7 @@ public virtual void UpdateProductPicture(ProductPicture productPicture) _productPictureRepository.Update(productPicture); //event notification - _eventPublisher.EntityUpdated(productPicture); + _services.EventPublisher.EntityUpdated(productPicture); } #endregion @@ -1699,7 +1777,7 @@ public virtual void InsertBundleItem(ProductBundleItem bundleItem) _productBundleItemRepository.Insert(bundleItem); //event notification - _eventPublisher.EntityInserted(bundleItem); + _services.EventPublisher.EntityInserted(bundleItem); } /// @@ -1714,7 +1792,7 @@ public virtual void UpdateBundleItem(ProductBundleItem bundleItem) _productBundleItemRepository.Update(bundleItem); //event notification - _eventPublisher.EntityUpdated(bundleItem); + _services.EventPublisher.EntityUpdated(bundleItem); } /// @@ -1729,7 +1807,7 @@ public virtual void DeleteBundleItem(ProductBundleItem bundleItem) _productBundleItemRepository.Delete(bundleItem); //event notification - _eventPublisher.EntityDeleted(bundleItem); + _services.EventPublisher.EntityDeleted(bundleItem); } /// diff --git a/src/Libraries/SmartStore.Services/News/NewsService.cs b/src/Libraries/SmartStore.Services/News/NewsService.cs index c0d576ca29..66adadf90e 100644 --- a/src/Libraries/SmartStore.Services/News/NewsService.cs +++ b/src/Libraries/SmartStore.Services/News/NewsService.cs @@ -224,7 +224,7 @@ public virtual SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int langu DateTime? maxAge = null; var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; - var selfLink = urlHelper.Action("rss", null, new { languageId = languageId }, protocol); + var selfLink = urlHelper.Action("rss", "News", new { languageId = languageId }, protocol); var newsLink = urlHelper.RouteUrl("NewsArchive", null, protocol); var title = "{0} - News".FormatInvariant(_services.StoreContext.CurrentStore.Name); @@ -248,9 +248,7 @@ public virtual SmartSyndicationFeed CreateRssFeed(UrlHelper urlHelper, int langu { var newsUrl = urlHelper.RouteUrl("NewsItem", new { SeName = news.GetSeName(news.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); - var item = new SyndicationItem(news.Title, news.Short.RemoveInvalidXmlChars(), new Uri(newsUrl), newsUrl, news.CreatedOnUtc); - - item.ElementExtensions.Add("encoded", SmartSyndicationFeed.UrlPurlContent, news.Full.RemoveInvalidXmlChars()); + var item = feed.CreateItem(news.Title, news.Short, newsUrl, news.CreatedOnUtc, news.Full); items.Add(item); } diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs index 7c210cee70..1e77b41b24 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs @@ -22,6 +22,7 @@ using SmartStore.Services.Seo; using SmartStore.Services.Stores; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Mvc; using SmartStore.Web.Framework.Security; using SmartStore.Web.Framework.UI; using SmartStore.Web.Infrastructure.Cache; @@ -854,39 +855,12 @@ public ActionResult RecentlyAddedProducts(CatalogPagingFilteringModel command) return View(model); } + [Compress] public ActionResult RecentlyAddedProductsRss() { - var feed = new SyndicationFeed( - string.Format("{0}: {1}", _services.StoreContext.CurrentStore.Name, T("RSS.RecentlyAddedProducts")), - T("RSS.InformationAboutProducts"), - new Uri(_services.WebHelper.GetStoreLocation(false)), - "RecentlyAddedProductsRSS", - DateTime.UtcNow); + var feed = _productService.CreateRecentlyAddedProductsRssFeed(Url); - if (!_catalogSettings.RecentlyAddedProductsEnabled) - return new RssActionResult() { Feed = feed }; - - var items = new List(); - - var ctx = new ProductSearchContext(); - ctx.LanguageId = _services.WorkContext.WorkingLanguage.Id; - ctx.OrderBy = ProductSortingEnum.CreatedOn; - ctx.PageSize = _catalogSettings.RecentlyAddedProductsNumber; - ctx.StoreId = _services.StoreContext.CurrentStoreIdIfMultiStoreMode; - ctx.VisibleIndividuallyOnly = true; - - var products = _productService.SearchProducts(ctx); - - foreach (var product in products) - { - string productUrl = Url.RouteUrl("Product", new { SeName = product.GetSeName() }, "http"); - if (!String.IsNullOrEmpty(productUrl)) - { - items.Add(new SyndicationItem(product.GetLocalized(x => x.Name), product.GetLocalized(x => x.ShortDescription), new Uri(productUrl), String.Format("RecentlyAddedProduct:{0}", product.Id), product.CreatedOnUtc)); - } - } - feed.Items = items; - return new RssActionResult() { Feed = feed }; + return new RssActionResult { Feed = feed }; } #endregion diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.cshtml index db5b531560..0fadfa1646 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.cshtml @@ -24,11 +24,15 @@
-
-
+ +
+
@*@if (ShowListOptions()) { From 991d84d8b27c340db5b2d21a187aeca45f2afd46 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 2 Jul 2015 01:03:49 +0200 Subject: [PATCH 0049/1074] E-mail attachments: further development --- .../Extensions/ConversionExtensions.cs | 51 ++++---------- .../Extensions/HttpExtensions.cs | 17 +++++ .../Messages/QueuingEmailEventConsumer.cs | 67 ++++++++++++++++++- .../Services/ProfilerService.cs | 7 +- .../Controllers/OrderController.cs | 1 + 5 files changed, 102 insertions(+), 41 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs index 20ff82f9a2..35781072ef 100644 --- a/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs @@ -498,45 +498,23 @@ public static byte[] ToByteArray(this Stream stream) { Guard.ArgumentNotNull(stream, "stream"); - byte[] buffer; - - if (stream is MemoryStream && stream.CanRead && stream.CanSeek) - { - int len = System.Convert.ToInt32(stream.Length); - buffer = new byte[len]; - stream.Read(buffer, 0, len); - return buffer; - } - - MemoryStream memStream = null; - try - { - buffer = new byte[1024]; - memStream = new MemoryStream(); - int bytesRead = stream.Read(buffer, 0, buffer.Length); - if (bytesRead > 0) - { - memStream.Write(buffer, 0, bytesRead); - bytesRead = stream.Read(buffer, 0, buffer.Length); - } - } - finally - { - if (memStream != null) - memStream.Close(); - } - - if (memStream != null) - { - return memStream.ToArray(); - } - - return null; + if (stream is MemoryStream) + { + return ((MemoryStream)stream).ToArray(); + } + else + { + using (var ms = new MemoryStream()) + { + stream.CopyTo(ms); + return ms.ToArray(); + } + } } public static string AsString(this Stream stream) { - // convert memory stream to string + // convert stream to string string result; stream.Position = 0; @@ -546,7 +524,6 @@ public static string AsString(this Stream stream) } return result; - } #endregion @@ -644,7 +621,7 @@ internal static byte[] ToByteArray(this Image image, ImageFormat format) using (var stream = new MemoryStream()) { image.Save(stream, format); - return stream.ToByteArray(); + return stream.ToArray(); } } diff --git a/src/Libraries/SmartStore.Core/Extensions/HttpExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/HttpExtensions.cs index be4e64b78b..4279070910 100644 --- a/src/Libraries/SmartStore.Core/Extensions/HttpExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/HttpExtensions.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Net; using System.Text; using System.Web; +using System.Web.Security; namespace SmartStore { @@ -31,6 +33,21 @@ public static bool IsSecureConnection(this HttpRequest request) { return (request.IsSecureConnection || (request.ServerVariables[HTTP_CLUSTER_VAR] != null || request.ServerVariables[HTTP_CLUSTER_VAR] == "on")); } + + public static void SetFormsAuthenticationCookie(this HttpWebRequest webRequest, HttpRequestBase httpRequest) + { + Guard.ArgumentNotNull(() => webRequest); + Guard.ArgumentNotNull(() => httpRequest); + + var authCookie = httpRequest.Cookies[FormsAuthentication.FormsCookieName]; + var sendCookie = new Cookie(authCookie.Name, authCookie.Value, authCookie.Path, httpRequest.Url.Host); + + if (webRequest.CookieContainer == null) + { + webRequest.CookieContainer = new CookieContainer(); + } + webRequest.CookieContainer.Add(sendCookie); + } } } diff --git a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs index 04bb77d509..63d2ae0eae 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs @@ -1,23 +1,36 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; +using System.Net.Mime; using System.Text; using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using System.Web.Security; +using SmartStore.Core; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Events; +using SmartStore.Core.Logging; namespace SmartStore.Services.Messages { public class QueuingEmailEventConsumer : IConsumer { private readonly PdfSettings _pdfSettings; + private readonly HttpRequestBase _httpRequest; - public QueuingEmailEventConsumer(PdfSettings pdfSettings) + public QueuingEmailEventConsumer(PdfSettings pdfSettings, HttpRequestBase httpRequest) { this._pdfSettings = pdfSettings; + this._httpRequest = httpRequest; + + Logger = NullLogger.Instance; } + public ILogger Logger { get; set; } + public void HandleEvent(QueuingEmailEvent eventMessage) { var qe = eventMessage.QueuedEmail; @@ -38,7 +51,57 @@ public void HandleEvent(QueuingEmailEvent eventMessage) private QueuedEmailAttachment CreatePdfInvoiceAttachment(int orderId) { - // TODO: (mc) implement + // TODO: (mc) create common util function 'CreateAttachmentFromUrl()' OR 'DownloadFile()' + + var urlHelper = new UrlHelper(_httpRequest.RequestContext); + var path = urlHelper.Action("Print", "Order", new { id = orderId, pdf = true }); + var url = WebHelper.GetAbsoluteUrl(path, _httpRequest); + + var request = (HttpWebRequest)WebRequest.Create(url); + request.UserAgent = "SmartStore.NET"; + request.Timeout = 5000; + + request.SetFormsAuthenticationCookie(_httpRequest); + + HttpWebResponse response = null; + + try + { + response = (HttpWebResponse)request.GetResponse(); + + using (var stream = response.GetResponseStream()) + { + if (response.StatusCode == HttpStatusCode.OK && response.ContentType == "application/pdf") + { + var pdfBinary = stream.ToByteArray(); + + var cd = new ContentDisposition(response.Headers["Content-Disposition"]); + var fileName = cd.FileName; + + return new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.Blob, + Data = pdfBinary, + MimeType = "application/pdf", + Name = fileName + }; + } + } + } + catch (Exception ex) + { + // TODO localize + Logger.Error("Error occured while creating e-mail attachment", ex); + } + finally + { + if (response != null) + { + response.Close(); + response.Dispose(); + } + } + return null; } diff --git a/src/Plugins/SmartStore.DevTools/Services/ProfilerService.cs b/src/Plugins/SmartStore.DevTools/Services/ProfilerService.cs index 462451a123..e490e592f2 100644 --- a/src/Plugins/SmartStore.DevTools/Services/ProfilerService.cs +++ b/src/Plugins/SmartStore.DevTools/Services/ProfilerService.cs @@ -43,9 +43,12 @@ public void StepStop(string key) } IDisposable step; - if (this.steps[key].TryPop(out step)) + if (this.steps.ContainsKey(key)) { - step.Dispose(); + if (this.steps[key].TryPop(out step)) + { + step.Dispose(); + } } } diff --git a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs index b1217ad312..70ba4ddab4 100644 --- a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Web.Mvc; using System.Web.Routing; +using System.Web.SessionState; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; From 48da5ef9d9111efc9aa2a087bba697be5cf2ef85 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Sat, 4 Jul 2015 01:04:54 +0200 Subject: [PATCH 0050/1074] E-mail attachments: further development --- .../Domain/Common/PdfSettings.cs | 10 ++ .../Domain/Messages/QueuedEmailAttachment.cs | 2 +- .../Utilities/FileDownloadManager.cs | 82 ++++++++++++- .../Messages/IQueuedEmailService.cs | 31 +++-- .../Messages/QueuedEmailService.cs | 110 +++++++++++++----- .../Messages/QueuedMessagesSendTask.cs | 9 +- .../Messages/QueuingEmailEventConsumer.cs | 71 +++++------ .../Orders/OrderProcessingService.cs | 4 +- .../DependencyRegistrar.cs | 1 + .../Controllers/QueuedEmailController.cs | 55 ++++++++- .../Controllers/SettingController.cs | 4 + .../Infrastructure/AutoMapperStartupTask.cs | 14 ++- .../Models/Messages/QueuedEmailModel.cs | 20 +++- .../Settings/GeneralCommonSettingsModel.cs | 6 + .../Views/QueuedEmail/List.cshtml | 9 +- .../Views/QueuedEmail/_CreateOrUpdate.cshtml | 17 +++ .../Views/Setting/GeneralCommon.cshtml | 23 ++++ .../Messages/QueuedEmailServiceTests.cs | 4 +- 18 files changed, 366 insertions(+), 106 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Domain/Common/PdfSettings.cs b/src/Libraries/SmartStore.Core/Domain/Common/PdfSettings.cs index 45a7c50906..bddfb93963 100644 --- a/src/Libraries/SmartStore.Core/Domain/Common/PdfSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Common/PdfSettings.cs @@ -30,5 +30,15 @@ public PdfSettings() /// Gets or sets a value indicating whether to render order notes in PDf reports ///
public bool RenderOrderNotes { get; set; } + + /// + /// Gets or sets a value indicating whether to attach the order PDF to 'Order Placed (customer)' email + /// + public bool AttachOrderPdfToOrderPlacedEmail { get; set; } + + /// + /// Gets or sets a value indicating whether to attach the order PDF to 'Order Completed (customer)' email + /// + public bool AttachOrderPdfToOrderCompletedEmail { get; set; } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs index c0f6978143..6f131b0a41 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs @@ -57,7 +57,7 @@ public partial class QueuedEmailAttachment : BaseEntity public string Name { get; set; } /// - /// The attachment file's mime type, e.g. + /// The attachment file's mime type, e.g. application/pdf /// public string MimeType { get; set; } diff --git a/src/Libraries/SmartStore.Core/Utilities/FileDownloadManager.cs b/src/Libraries/SmartStore.Core/Utilities/FileDownloadManager.cs index 6b95e181b6..de2db7a3e9 100644 --- a/src/Libraries/SmartStore.Core/Utilities/FileDownloadManager.cs +++ b/src/Libraries/SmartStore.Core/Utilities/FileDownloadManager.cs @@ -5,8 +5,11 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Net.Mime; using System.Threading; using System.Threading.Tasks; +using System.Web; +using SmartStore.Core; using SmartStore.Core.Logging; namespace SmartStore.Utilities @@ -15,8 +18,57 @@ public class FileDownloadManager { private const int _bufferSize = 16384; + private readonly HttpRequestBase _httpRequest; + + public FileDownloadManager(HttpRequestBase httpRequest) + { + this._httpRequest = httpRequest; + } + /// - /// Start asynchronous download of files + /// Downloads a single file synchronously + /// + /// The URL to download the file from (either a fully qualified URL or an app relative/absolute path) + /// Specifies whether the FormsAuthenticationCookie should be sent + /// Timeout in milliseconds + public FileDownloadResponse DownloadFile(string url, bool sendAuthCookie = false, int? timeout = null) + { + Guard.ArgumentNotEmpty(() => url); + + url = WebHelper.GetAbsoluteUrl(url, _httpRequest); + + var req = (HttpWebRequest)WebRequest.Create(url); + req.UserAgent = "SmartStore.NET"; + + if (timeout.HasValue) + { + req.Timeout = timeout.Value; + } + + if (sendAuthCookie) + { + req.SetFormsAuthenticationCookie(_httpRequest); + } + + using (var resp = (HttpWebResponse)req.GetResponse()) + { + using (var stream = resp.GetResponseStream()) + { + if (resp.StatusCode == HttpStatusCode.OK) + { + var data = stream.ToByteArray(); + var cd = new ContentDisposition(resp.Headers["Content-Disposition"]); + var fileName = cd.FileName; + return new FileDownloadResponse(data, fileName, resp.ContentType); + } + } + } + + return null; + } + + /// + /// Starts asynchronous download of files and saves them to disk /// /// Download context /// Items to be downloaded @@ -96,6 +148,34 @@ private async Task ProcessUrl(FileDownloadManagerContext context, HttpClient cli } + public class FileDownloadResponse + { + public FileDownloadResponse(byte[] data, string fileName, string contentType) + { + Guard.ArgumentNotNull(() => data); + Guard.ArgumentNotEmpty(() => fileName); + Guard.ArgumentNotEmpty(() => contentType); + + this.Data = data; + this.FileName = fileName; + this.ContentType = contentType; + } + + /// + /// The downloaded file's byte array + /// + public byte[] Data { get; private set; } + + /// + /// The file name + /// + public string FileName { get; private set; } + + /// + /// The mime type opf the downloaded file + /// + public string ContentType { get; private set; } + } public class FileDownloadManagerContext { diff --git a/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs index 6b1db9e52c..12baf20719 100644 --- a/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs @@ -48,23 +48,9 @@ public partial interface IQueuedEmailService /// /// Search queued emails /// - /// From Email - /// To Email - /// The start time - /// The end time - /// A value indicating whether to load only not sent emails - /// Maximum send tries - /// A value indicating whether we should sort queued email descending; otherwise, ascending. - /// Page index - /// Page size - /// A value indicating whether to load manually send emails + /// An object containing the query criteria /// Email item collection - IPagedList SearchEmails( - string fromEmail, string toEmail, - DateTime? startTime, DateTime? endTime, - bool loadUnsentItemsOnly, int maxSendTries, - bool loadNewest, int pageIndex, int pageSize, - bool? sendManually = null); + IPagedList SearchEmails(SearchEmailsQuery query); /// /// Sends a queued email @@ -72,5 +58,18 @@ IPagedList SearchEmails( /// Queued email /// Whether the operation succeeded bool SendEmail(QueuedEmail queuedEmail); + + /// + /// Gets a queued email attachment by identifier + /// + /// Queued email attachment identifier + /// Queued email attachment + QueuedEmailAttachment GetQueuedEmailAttachmentById(int id); + + /// + /// Deleted a queued email attachment + /// + /// Queued email attachment + void DeleteQueuedEmailAttachment(QueuedEmailAttachment qea); } } diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 1c40be1554..8a742c99e6 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -19,12 +19,18 @@ namespace SmartStore.Services.Messages public partial class QueuedEmailService : IQueuedEmailService { private readonly IRepository _queuedEmailRepository; + private readonly IRepository _queuedEmailAttachmentRepository; private readonly IEmailSender _emailSender; private readonly ICommonServices _services; - public QueuedEmailService(IRepository queuedEmailRepository, IEmailSender emailSender, ICommonServices services) + public QueuedEmailService( + IRepository queuedEmailRepository, + IRepository queuedEmailAttachmentRepository, + IEmailSender emailSender, + ICommonServices services) { this._queuedEmailRepository = queuedEmailRepository; + this._queuedEmailAttachmentRepository = queuedEmailAttachmentRepository; this._emailSender = emailSender; this._services = services; @@ -80,7 +86,6 @@ public virtual QueuedEmail GetQueuedEmailById(int queuedEmailId) var queuedEmail = _queuedEmailRepository.GetById(queuedEmailId); return queuedEmail; - } public virtual IList GetQueuedEmailsByIds(int[] queuedEmailIds) @@ -106,44 +111,48 @@ where queuedEmailIds.Contains(qe.Id) return sortedQueuedEmails; } - public virtual IPagedList SearchEmails(string fromEmail, - string toEmail, DateTime? startTime, DateTime? endTime, - bool loadUnsentItemsOnly, int maxSendTries, - bool loadNewest, int pageIndex, int pageSize, - bool? sendManually = null) + public virtual IPagedList SearchEmails(SearchEmailsQuery query) { - fromEmail = (fromEmail ?? String.Empty).Trim(); - toEmail = (toEmail ?? String.Empty).Trim(); + Guard.ArgumentNotNull(() => query); - var query = _queuedEmailRepository.Table.Expand(x => x.EmailAccount); + var q = _queuedEmailRepository.Table; - if (!String.IsNullOrEmpty(fromEmail)) - query = query.Where(qe => qe.From.Contains(fromEmail)); + if (query.Expand.HasValue()) + { + var expands = query.Expand.Split(','); + foreach (var expand in expands) + { + q = q.Expand(expand.Trim()); + } + } - if (!String.IsNullOrEmpty(toEmail)) - query = query.Where(qe => qe.To.Contains(toEmail)); + if (query.From.HasValue()) + q = q.Where(qe => qe.From.Contains(query.From.Trim())); - if (startTime.HasValue) - query = query.Where(qe => qe.CreatedOnUtc >= startTime); + if (query.To.HasValue()) + q = q.Where(qe => qe.To.Contains(query.To.Trim())); - if (endTime.HasValue) - query = query.Where(qe => qe.CreatedOnUtc <= endTime); + if (query.StartTime.HasValue) + q = q.Where(qe => qe.CreatedOnUtc >= query.StartTime); - if (loadUnsentItemsOnly) - query = query.Where(qe => !qe.SentOnUtc.HasValue); + if (query.EndTime.HasValue) + q = q.Where(qe => qe.CreatedOnUtc <= query.EndTime); - if (sendManually.HasValue) - query = query.Where(qe => qe.SendManually == sendManually.Value); + if (query.UnsentOnly) + q = q.Where(qe => !qe.SentOnUtc.HasValue); - query = query.Where(qe => qe.SentTries < maxSendTries); + if (query.SendManually.HasValue) + q = q.Where(qe => qe.SendManually == query.SendManually.Value); + + q = q.Where(qe => qe.SentTries < query.MaxSendTries); - query = query.OrderByDescending(qe => qe.Priority); + q = q.OrderByDescending(qe => qe.Priority); - query = loadNewest ? - ((IOrderedQueryable)query).ThenByDescending(qe => qe.CreatedOnUtc) : - ((IOrderedQueryable)query).ThenBy(qe => qe.CreatedOnUtc); + q = query.OrderByLatest ? + ((IOrderedQueryable)q).ThenByDescending(qe => qe.CreatedOnUtc) : + ((IOrderedQueryable)q).ThenBy(qe => qe.CreatedOnUtc); - var queuedEmails = new PagedList(query, pageIndex, pageSize); + var queuedEmails = new PagedList(q, query.PageIndex, query.PageSize); return queuedEmails; } @@ -249,5 +258,48 @@ internal EmailMessage ConvertEmail(QueuedEmail qe) return msg; } - } + + #region Attachments + + public virtual QueuedEmailAttachment GetQueuedEmailAttachmentById(int id) + { + if (id == 0) + return null; + + var qea = _queuedEmailAttachmentRepository.GetById(id); + return qea; + } + + public virtual void DeleteQueuedEmailAttachment(QueuedEmailAttachment qea) + { + if (qea == null) + throw new ArgumentNullException("qea"); + + _queuedEmailAttachmentRepository.Delete(qea); + + _services.EventPublisher.EntityDeleted(qea); + } + + #endregion + } + + public class SearchEmailsQuery + { + public string From { get; set; } + public string To { get; set; } + public DateTime? StartTime { get; set; } + public DateTime? EndTime { get; set; } + public bool UnsentOnly { get; set; } + public int MaxSendTries { get; set; } + public bool OrderByLatest { get; set; } + public int PageIndex { get; set; } + public int PageSize { get; set; } + public bool? SendManually { get; set; } + + /// + /// Navigation properties to eager load (comma separataed) + /// + public string Expand { get; set; } + } + } diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs index 3223633b5f..b3058c31a8 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs @@ -21,7 +21,14 @@ public void Execute(TaskExecutionContext ctx) for (int i = 0; i < 9999999; ++i) { - var queuedEmails = _queuedEmailService.SearchEmails(null, null, null, null, true, maxTries, false, i, pageSize, false); + var q = new SearchEmailsQuery + { + MaxSendTries = maxTries, + PageIndex = i, + PageSize = pageSize, + Expand = "Attachments" + }; + var queuedEmails = _queuedEmailService.SearchEmails(q); foreach (var queuedEmail in queuedEmails) { diff --git a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs index 63d2ae0eae..dd50b40c44 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs @@ -13,6 +13,7 @@ using SmartStore.Core.Domain.Messages; using SmartStore.Core.Events; using SmartStore.Core.Logging; +using SmartStore.Utilities; namespace SmartStore.Services.Messages { @@ -20,11 +21,16 @@ public class QueuingEmailEventConsumer : IConsumer { private readonly PdfSettings _pdfSettings; private readonly HttpRequestBase _httpRequest; + private readonly Lazy _fileDownloadManager; - public QueuingEmailEventConsumer(PdfSettings pdfSettings, HttpRequestBase httpRequest) + public QueuingEmailEventConsumer( + PdfSettings pdfSettings, + HttpRequestBase httpRequest, + Lazy fileDownloadManager) { this._pdfSettings = pdfSettings; this._httpRequest = httpRequest; + this._fileDownloadManager = fileDownloadManager; Logger = NullLogger.Instance; } @@ -36,9 +42,14 @@ public void HandleEvent(QueuingEmailEvent eventMessage) var qe = eventMessage.QueuedEmail; var tpl = eventMessage.MessageTemplate; - // TODO: (mc) determine and apply PdfSettings - - if (tpl.Name.IsCaseInsensitiveEqual("OrderPlaced.CustomerNotification")) + var handledTemplates = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "OrderPlaced.CustomerNotification", _pdfSettings.AttachOrderPdfToOrderPlacedEmail }, + { "OrderCompleted.CustomerNotification", _pdfSettings.AttachOrderPdfToOrderCompletedEmail } + }; + + bool shouldHandle = false; + if (handledTemplates.TryGetValue(tpl.Name, out shouldHandle) && shouldHandle) { var orderId = eventMessage.Tokens.First(x => x.Key.IsCaseInsensitiveEqual("Order.ID")).Value.ToInt(); var qea = CreatePdfInvoiceAttachment(orderId); @@ -51,56 +62,36 @@ public void HandleEvent(QueuingEmailEvent eventMessage) private QueuedEmailAttachment CreatePdfInvoiceAttachment(int orderId) { - // TODO: (mc) create common util function 'CreateAttachmentFromUrl()' OR 'DownloadFile()' - var urlHelper = new UrlHelper(_httpRequest.RequestContext); - var path = urlHelper.Action("Print", "Order", new { id = orderId, pdf = true }); - var url = WebHelper.GetAbsoluteUrl(path, _httpRequest); - - var request = (HttpWebRequest)WebRequest.Create(url); - request.UserAgent = "SmartStore.NET"; - request.Timeout = 5000; - - request.SetFormsAuthenticationCookie(_httpRequest); - - HttpWebResponse response = null; + var path = urlHelper.Action("Print", "Order", new { id = orderId, pdf = true, area = "" }); try { - response = (HttpWebResponse)request.GetResponse(); + var fileResponse = _fileDownloadManager.Value.DownloadFile(path, true, 5000); - using (var stream = response.GetResponseStream()) + if (fileResponse == null) { - if (response.StatusCode == HttpStatusCode.OK && response.ContentType == "application/pdf") - { - var pdfBinary = stream.ToByteArray(); - - var cd = new ContentDisposition(response.Headers["Content-Disposition"]); - var fileName = cd.FileName; + // ... + } - return new QueuedEmailAttachment - { - StorageLocation = EmailAttachmentStorageLocation.Blob, - Data = pdfBinary, - MimeType = "application/pdf", - Name = fileName - }; - } + if (!fileResponse.ContentType.IsCaseInsensitiveEqual("application/pdf")) + { + // ... } + + return new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.Blob, + Data = fileResponse.Data, + MimeType = fileResponse.ContentType, + Name = fileResponse.FileName + }; } catch (Exception ex) { // TODO localize Logger.Error("Error occured while creating e-mail attachment", ex); } - finally - { - if (response != null) - { - response.Close(); - response.Dispose(); - } - } return null; } diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index 1ce5ce0eb6..d955f22aab 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -2111,7 +2111,7 @@ public virtual void MarkOrderAsPaid(Order order) _orderService.UpdateOrder(order); //add a note - order.OrderNotes.Add(new OrderNote() + order.OrderNotes.Add(new OrderNote { Note = TNote("OrderMarkedAsPaid"), DisplayToCustomer = false, @@ -2121,7 +2121,7 @@ public virtual void MarkOrderAsPaid(Order order) CheckOrderStatus(order); - //raise event + // raise event if (order.PaymentStatus == PaymentStatus.Paid) { _eventPublisher.PublishOrderPaid(order); diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 549ad459a9..51d8199e1a 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -575,6 +575,7 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().InstancePerRequest(); builder.RegisterFilterProvider(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs index 2b6f9fce31..d00783f2cf 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Web; using System.Web.Mvc; using SmartStore.Admin.Models.Messages; using SmartStore.Core.Domain.Messages; @@ -8,6 +9,7 @@ using SmartStore.Services.Localization; using SmartStore.Services.Messages; using SmartStore.Services.Security; +using SmartStore.Utilities; using SmartStore.Web.Framework.Controllers; using Telerik.Web.Mvc; @@ -53,13 +55,22 @@ public ActionResult QueuedEmailList(GridCommand command, QueuedEmailListModel mo return AccessDeniedView(); DateTime? startDateValue = (model.SearchStartDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.SearchStartDate.Value, _dateTimeHelper.CurrentTimeZone); - DateTime? endDateValue = (model.SearchEndDate == null) ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(model.SearchEndDate.Value, _dateTimeHelper.CurrentTimeZone).AddDays(1); - var queuedEmails = _queuedEmailService.SearchEmails(model.SearchFromEmail, model.SearchToEmail, - startDateValue, endDateValue, - model.SearchLoadNotSent, model.SearchMaxSentTries, true, - command.Page - 1, command.PageSize, model.SearchSendManually); + var q = new SearchEmailsQuery + { + EndTime = endDateValue, + From = model.SearchFromEmail, + MaxSendTries = model.SearchMaxSentTries, + OrderByLatest = true, + PageIndex = command.Page - 1, + PageSize = command.PageSize, + SendManually = model.SearchSendManually, + StartTime = startDateValue, + To = model.SearchToEmail, + UnsentOnly = model.SearchLoadNotSent + }; + var queuedEmails = _queuedEmailService.SearchEmails(q); var gridModel = new GridModel { @@ -239,5 +250,39 @@ public ActionResult DeleteAll() return RedirectToAction("List"); } + + public ActionResult DownloadAttachment(int id) + { + if (!_permissionService.Authorize(StandardPermissionProvider.ManageMessageQueue)) + return AccessDeniedView(); + + var qea = _queuedEmailService.GetQueuedEmailAttachmentById(id); + if (qea == null) + return HttpNotFound("List"); + + if (qea.StorageLocation == EmailAttachmentStorageLocation.Blob) + { + return File(qea.Data, qea.MimeType, qea.Name); + } + else if (qea.StorageLocation == EmailAttachmentStorageLocation.Path) + { + var path = qea.Path; + if (path[0] == '~' || path[0] == '/') + { + path = CommonHelper.MapPath(VirtualPathUtility.ToAppRelative(path), false); + } + return File(path, qea.MimeType, qea.Name); + } + + // FileReference + if (qea.FileId.HasValue) + { + return RedirectToAction("DownloadFile", "Download", new { downloadId = qea.FileId.Value }); + } + + NotifyError("Could not download e-mail attachment: no data"); + return RedirectToAction("List"); + + } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs index 48bd56cf5f..90b04c7bfc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs @@ -1050,6 +1050,8 @@ public ActionResult GeneralCommon() model.PdfSettings.Enabled = pdfSettings.Enabled; model.PdfSettings.LetterPageSizeEnabled = pdfSettings.LetterPageSizeEnabled; model.PdfSettings.LogoPictureId = pdfSettings.LogoPictureId; + model.PdfSettings.AttachOrderPdfToOrderPlacedEmail = pdfSettings.AttachOrderPdfToOrderPlacedEmail; + model.PdfSettings.AttachOrderPdfToOrderCompletedEmail = pdfSettings.AttachOrderPdfToOrderCompletedEmail; StoreDependingSettings.GetOverrideKeys(pdfSettings, model.PdfSettings, storeScope, _settingService, false); @@ -1233,6 +1235,8 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti pdfSettings.Enabled = model.PdfSettings.Enabled; pdfSettings.LetterPageSizeEnabled = model.PdfSettings.LetterPageSizeEnabled; pdfSettings.LogoPictureId = model.PdfSettings.LogoPictureId; + pdfSettings.AttachOrderPdfToOrderPlacedEmail = model.PdfSettings.AttachOrderPdfToOrderPlacedEmail; + pdfSettings.AttachOrderPdfToOrderCompletedEmail = model.PdfSettings.AttachOrderPdfToOrderCompletedEmail; StoreDependingSettings.UpdateSettings(pdfSettings, form, storeScope, _settingService); diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index 958b035003..ea8671c313 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Linq; using AutoMapper; using SmartStore.Admin.Models.Blogs; using SmartStore.Admin.Models.Catalog; @@ -147,17 +148,20 @@ public void Execute() .ForMember(dest => dest.SelectedStoreIds, mo => mo.Ignore()); Mapper.CreateMap(); //queued email - Mapper.CreateMap() - .ForMember(dest => dest.EmailAccountName, mo => mo.MapFrom(src => src.EmailAccount != null ? src.EmailAccount.FriendlyName : string.Empty)) - .ForMember(dest => dest.CreatedOn, mo => mo.Ignore()) - .ForMember(dest => dest.SentOn, mo => mo.Ignore()); + Mapper.CreateMap() + .ForMember(dest => dest.EmailAccountName, mo => mo.MapFrom(src => src.EmailAccount != null ? src.EmailAccount.FriendlyName : string.Empty)) + .ForMember(dest => dest.CreatedOn, mo => mo.Ignore()) + .ForMember(dest => dest.SentOn, mo => mo.Ignore()) + .ForMember(dest => dest.AttachmentsCount, mo => mo.MapFrom(src => src.Attachments.Count)) + .ForMember(dest => dest.Attachments, mo => mo.MapFrom(src => src.Attachments.Select(x => new QueuedEmailModel.QueuedEmailAttachmentModel { Id = x.Id, Name = x.Name, MimeType = x.MimeType } ))); Mapper.CreateMap() .ForMember(dest=> dest.CreatedOnUtc, dt=> dt.Ignore()) .ForMember(dest => dest.SentOnUtc, mo => mo.Ignore()) .ForMember(dest => dest.EmailAccount, mo => mo.Ignore()) .ForMember(dest => dest.EmailAccountId, mo => mo.Ignore()) .ForMember(dest => dest.ReplyTo, mo => mo.Ignore()) - .ForMember(dest => dest.ReplyToName, mo => mo.Ignore()); + .ForMember(dest => dest.ReplyToName, mo => mo.Ignore()) + .ForMember(dest => dest.Attachments, mo => mo.Ignore()); //campaign Mapper.CreateMap() .ForMember(dest => dest.CreatedOn, mo => mo.Ignore()) diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Messages/QueuedEmailModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Messages/QueuedEmailModel.cs index fd843f7bc6..844e79e388 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Messages/QueuedEmailModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Messages/QueuedEmailModel.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Admin.Validators.Messages; +using SmartStore.Core.Domain.Messages; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Mvc; @@ -11,7 +13,12 @@ namespace SmartStore.Admin.Models.Messages [Validator(typeof(QueuedEmailValidator))] public class QueuedEmailModel : EntityModelBase { - [SmartResourceDisplayName("Admin.System.QueuedEmails.Fields.Id")] + public QueuedEmailModel() + { + this.Attachments = new List(); + } + + [SmartResourceDisplayName("Admin.System.QueuedEmails.Fields.Id")] public override int Id { get; set; } [SmartResourceDisplayName("Admin.System.QueuedEmails.Fields.Priority")] @@ -65,5 +72,16 @@ public class QueuedEmailModel : EntityModelBase [SmartResourceDisplayName("Admin.System.QueuedEmails.Fields.SendManually")] public bool SendManually { get; set; } + + public int AttachmentsCount { get; set; } + + [SmartResourceDisplayName("Admin.System.QueuedEmails.Fields.Attachments")] + public ICollection Attachments { get; set; } + + public class QueuedEmailAttachmentModel : EntityModelBase + { + public string Name { get; set; } + public string MimeType { get; set; } + } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/GeneralCommonSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/GeneralCommonSettingsModel.cs index 5605695ad8..da408da1f3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/GeneralCommonSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/GeneralCommonSettingsModel.cs @@ -153,6 +153,12 @@ public partial class PdfSettingsModel [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.PdfLogo")] [UIHint("Picture")] public int LogoPictureId { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.AttachOrderPdfToOrderPlacedEmail")] + public bool AttachOrderPdfToOrderPlacedEmail { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Settings.GeneralCommon.AttachOrderPdfToOrderCompletedEmail")] + public bool AttachOrderPdfToOrderCompletedEmail { get; set; } } public partial class LocalizationSettingsModel diff --git a/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml index d4497b7a7a..ad1a0f5350 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml @@ -119,15 +119,16 @@ .HtmlAttributes(new { style = "text-align:center" }) .HeaderHtmlAttributes(new { style = "text-align:center" }); columns.Bound(x => x.Id) - .Template(x => Html.ActionLink(x.Id.ToString(), "Edit", new { id = x.Id })) .ClientTemplate("\"><#= Id #>"); + columns.Bound(x => x.AttachmentsCount) + .HeaderTemplate("") + .Width(20); columns.Bound(x => x.Subject); columns.Bound(x => x.Priority) .Centered(); - columns.Bound(x => x.From); - columns.Bound(x => x.FromName); + columns.Bound(x => x.From) + .ClientTemplate("<#= FromName #> (<#= From #>)"); columns.Bound(x => x.SendManually) - .Template(item => @Html.SymbolForBool(item.SendManually)) .ClientTemplate(@Html.SymbolForBool("SendManually")) .Centered(); columns.Bound(x => x.SentTries) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/_CreateOrUpdate.cshtml index f297897a7a..b1720f9b11 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/_CreateOrUpdate.cshtml @@ -79,6 +79,23 @@ @Html.ValidationMessageFor(model => model.Subject) + @if (Model.Attachments.Any()) + { + + + @Html.SmartLabelFor(model => model.Attachments) + + + @foreach (var attach in Model.Attachments) + { + + + @attach.Name + + } + + + } @Html.SmartLabelFor(model => model.Body) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml index 76180000af..a10cd45bd9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml @@ -359,6 +359,29 @@ @Html.ValidationMessageFor(model => model.PdfSettings.LogoPictureId) + + +
+ + + + + @Html.SmartLabelFor(model => model.PdfSettings.AttachOrderPdfToOrderPlacedEmail) + + + @Html.SettingEditorFor(model => model.PdfSettings.AttachOrderPdfToOrderPlacedEmail) + @Html.ValidationMessageFor(model => model.PdfSettings.AttachOrderPdfToOrderPlacedEmail) + + + + + @Html.SmartLabelFor(model => model.PdfSettings.AttachOrderPdfToOrderCompletedEmail) + + + @Html.SettingEditorFor(model => model.PdfSettings.AttachOrderPdfToOrderCompletedEmail) + @Html.ValidationMessageFor(model => model.PdfSettings.AttachOrderPdfToOrderCompletedEmail) + + } @helper TabLocalizationSettings() diff --git a/src/Tests/SmartStore.Services.Tests/Messages/QueuedEmailServiceTests.cs b/src/Tests/SmartStore.Services.Tests/Messages/QueuedEmailServiceTests.cs index 7f0ea69976..39991dda91 100644 --- a/src/Tests/SmartStore.Services.Tests/Messages/QueuedEmailServiceTests.cs +++ b/src/Tests/SmartStore.Services.Tests/Messages/QueuedEmailServiceTests.cs @@ -21,6 +21,7 @@ namespace SmartStore.Services.Tests.Messages public class QueuedEmailServiceTests : ServiceTest { IRepository _qeRepository; + IRepository _qeaRepository; IEmailSender _emailSender; ICommonServices _commonServices; QueuedEmailService _queuedEmailService; @@ -29,10 +30,11 @@ public class QueuedEmailServiceTests : ServiceTest public new void SetUp() { _qeRepository = MockRepository.GenerateStub>(); + _qeaRepository = MockRepository.GenerateStub>(); _emailSender = MockRepository.GenerateStub(); _commonServices = MockRepository.GenerateStub(); - _queuedEmailService = new QueuedEmailService(_qeRepository, _emailSender, _commonServices); + _queuedEmailService = new QueuedEmailService(_qeRepository, _qeaRepository, _emailSender, _commonServices); } [Test] From 8e3e00191a6b72a14f3fac9df6d1c66663c54b4d Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Mon, 6 Jul 2015 18:00:43 +0200 Subject: [PATCH 0051/1074] Minor WebApi fixes --- .../WebApi/WebApiEntityController.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs index 4bec2890bf..039d981db0 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs @@ -91,15 +91,15 @@ protected virtual internal HttpResponseMessage UnmappedGetProperty(TEntity entit return Request.CreateErrorResponse(HttpStatusCode.BadRequest, WebApiGlobal.Error.PropertyNotFound.FormatWith(propertyName)); } - protected virtual IRepository CreateRepository() - { - var repository = EngineContext.Current.Resolve>(); + //protected virtual IRepository CreateRepository() + //{ + // var repository = EngineContext.Current.Resolve>(); - // false means not resolving navigation properties (related entities) - repository.Context.ProxyCreationEnabled = false; + // // false means not resolving navigation properties (related entities) + // repository.Context.ProxyCreationEnabled = false; - return repository; - } + // return repository; + //} /// /// Auto injected by Autofac @@ -163,7 +163,7 @@ protected override TEntity GetEntityByKey(int key) if (!ModelState.IsValid) throw this.ExceptionInvalidModelState(); - return GetEntitySet().FirstOrDefault(x => x.Id == key); + return this.Repository.GetById(key); } protected internal virtual TEntity GetEntityByKeyNotNull(int key) From ddb5bfb8e60b66d03b3e5a539b89414c3a12e38c Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 7 Jul 2015 01:50:38 +0200 Subject: [PATCH 0052/1074] E-mail attachments: finalized queued email attachments. Next step: message template attachments. --- .../Data/RepositoryExtensions.cs | 46 ++++++++++- .../201506262044329_QueuedEmailAttachments.cs | 82 +++++++++++++++++-- .../Setup/SeedData/InvariantSeedData.cs | 8 ++ .../Messages/QueuedEmailService.cs | 4 +- .../Messages/QueuedMessagesClearTask.cs | 28 +++++++ .../Messages/QueuingEmailEventConsumer.cs | 49 ++++++----- .../SmartStore.Services.csproj | 1 + .../Controllers/QueuedEmailController.cs | 2 +- .../Views/QueuedEmail/List.cshtml | 9 +- .../Controllers/OrderController.cs | 3 +- .../Installation/DeDESeedData.cs | 4 + 11 files changed, 189 insertions(+), 47 deletions(-) create mode 100644 src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs diff --git a/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs b/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs index 8551dd2882..0685c1a477 100644 --- a/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs +++ b/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs @@ -52,15 +52,16 @@ public static void Delete(this IRepository rs, object id) where T : BaseEn } /// - /// Truncates the whole table + /// Truncates the table /// /// Entity type - /// + /// The repository + /// An optional filter /// The total number of affected entities /// /// This method turns off auto detection, validation and hooking. /// - public static int DeleteAll(this IRepository rs) where T : BaseEntity + public static int DeleteAll(this IRepository rs, Expression> predicate = null) where T : BaseEntity { var autoCommit = rs.AutoCommitEnabled; rs.AutoCommitEnabled = false; @@ -71,7 +72,13 @@ public static int DeleteAll(this IRepository rs) where T : BaseEntity { using (var scope = new DbContextScope(autoDetectChanges: false, validateOnSave: false, hooksEnabled: false)) { - var records = rs.Table.ToList(); + var query = rs.Table; + if (predicate != null) + { + query = query.Where(predicate); + } + + var records = query.ToList(); foreach (var chunk in records.Chunk(500)) { rs.DeleteRange(chunk.ToList()); @@ -91,6 +98,37 @@ public static int DeleteAll(this IRepository rs) where T : BaseEntity return count; } + private static int DeleteAllInternal(IRepository rs, Expression> predicate) where T : BaseEntity + { + var autoCommit = rs.AutoCommitEnabled; + rs.AutoCommitEnabled = false; + + var count = 0; + + try + { + using (var scope = new DbContextScope(autoDetectChanges: false, validateOnSave: false, hooksEnabled: false)) + { + var records = rs.Table.ToList(); + foreach (var chunk in records.Chunk(500)) + { + rs.DeleteRange(chunk.ToList()); + count += rs.Context.SaveChanges(); + } + } + } + catch (Exception ex) + { + throw ex; + } + finally + { + rs.AutoCommitEnabled = autoCommit; + } + + return count; + } + public static IQueryable Get( this IRepository rs, Expression> predicate = null, diff --git a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs index 18c4da66ae..225aaf9d43 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs @@ -1,9 +1,11 @@ namespace SmartStore.Data.Migrations { - using System; - using System.Data.Entity.Migrations; - - public partial class QueuedEmailAttachments : DbMigration + using System; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Tasks; + using SmartStore.Data.Setup; + + public partial class QueuedEmailAttachments : DbMigration, ILocaleResourcesProvider, IDataSeeder { public override void Up() { @@ -24,8 +26,7 @@ public override void Up() .ForeignKey("dbo.Download", t => t.FileId, cascadeDelete: true) .ForeignKey("dbo.QueuedEmail", t => t.QueuedEmailId, cascadeDelete: true) .Index(t => t.QueuedEmailId) - .Index(t => t.FileId); - + .Index(t => t.FileId); } public override void Down() @@ -36,5 +37,72 @@ public override void Down() DropIndex("dbo.QueuedEmailAttachment", new[] { "QueuedEmailId" }); DropTable("dbo.QueuedEmailAttachment"); } - } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + context.Set().AddOrUpdate(x => x.Type, + new ScheduleTask + { + Name = "Clear email queue", + Seconds = 86400, // 1 day + Type = "SmartStore.Services.Messages.QueuedMessagesClearTask, SmartStore.Services", + Enabled = true, + StopOnError = false, + } + ); + + context.SaveChanges(); + } + + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.AttachOrderPdfToOrderPlacedEmail", + "Attach order PDF to 'Order Placed' email", + "Bei Bestelleingang PDF mitsenden", + "Dynamically creates and attaches the order PDF to the 'Order Placed' customer notification email.", + "Erstellt bei Bestelleingang das Auftrags-PDF-Dokument und hngt es der Kunden-Benachrichtigungs-Email an"); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.AttachOrderPdfToOrderCompletedEmail", + "Attach order PDF to 'Order Completed' email", + "Bei Abschluss einer Bestellung PDF mitsenden", + "Dynamically creates and attaches the order PDF to the 'Order Completed' customer notification email.", + "Erstellt bei Abschluss einer Bestellung das Auftrags-PDF-Dokument und hngt es der Kunden-Benachrichtigungs-Email an"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.Fields.Attachments", + "Attachments", + "Anhnge"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.CouldNotDownloadAttachment", + "Could not download e-mail attachment: no data.", + "E-Mail Anhang konnte nicht herunterladen: Daten nicht verfgbar."); + + builder.AddOrUpdate("Admin.System.QueuedEmails.ErrorCreatingAttachment", + "An error occured while creating e-mail attachment", + "Whrend der Erstellung des E-Mail-Anhangs ist ein Fehler aufgetreten"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.ErrorEmptyAttachmentResult", + "The e-mail attachment data could not be downloaded from path '{0}'", + "Daten fr den E-Mail Anhang konnten nicht heruntergeladen werden. Pfad: {0}"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.ErrorNoPdfAttachment", + "The content type of the e-mail attachment must be 'application/pdf'", + "Der Inhaltstyp des E-Mail Anhangs muss 'application/pdf' sein"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.List.AttachmentsCount", + "Number of attachments", + "Anzahl Anhnge"); + + builder.AddOrUpdate("Order.PdfInvoiceFileName", + "order-{0}.pdf", + "bestellung-{0}.pdf"); + } + } } diff --git a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs index d6f664d19d..ab25464ca0 100644 --- a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs +++ b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs @@ -4812,6 +4812,14 @@ public IList ScheduleTasks() Enabled = true, StopOnError = false, }, + new ScheduleTask + { + Name = "Clear email queue", + Seconds = 86400, // 1 day + Type = "SmartStore.Services.Messages.QueuedMessagesClearTask, SmartStore.Services", + Enabled = true, + StopOnError = false, + }, }; this.Alter(entities); return entities; diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 8a742c99e6..68cf11d375 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Net.Mail; using System.IO; using SmartStore.Core; @@ -76,7 +77,8 @@ public virtual void DeleteQueuedEmail(QueuedEmail queuedEmail) public virtual int DeleteAllQueuedEmails() { - return _queuedEmailRepository.DeleteAll(); + // do not delete e-mails which are about to be sent + return _queuedEmailRepository.DeleteAll(x => x.SentOnUtc.HasValue || x.SentTries >= 3); } public virtual QueuedEmail GetQueuedEmailById(int queuedEmailId) diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs new file mode 100644 index 0000000000..a51b84a925 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs @@ -0,0 +1,28 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Messages; +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.Messages +{ + /// + /// Represents a task for deleting sent emails from the message queue + /// + public partial class QueuedMessagesClearTask : ITask + { + private readonly IRepository _qeRepository; + + public QueuedMessagesClearTask(IRepository qeRepository) + { + this._qeRepository = qeRepository; + } + + public void Execute(TaskExecutionContext ctx) + { + var olderThan = DateTime.UtcNow.AddDays(-14); + _qeRepository.DeleteAll(x => x.SentOnUtc.HasValue && x.CreatedOnUtc < olderThan); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs index dd50b40c44..11eca682cc 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs @@ -12,6 +12,7 @@ using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Events; +using SmartStore.Core.Localization; using SmartStore.Core.Logging; using SmartStore.Utilities; @@ -33,9 +34,11 @@ public QueuingEmailEventConsumer( this._fileDownloadManager = fileDownloadManager; Logger = NullLogger.Instance; + T = NullLocalizer.Instance; } public ILogger Logger { get; set; } + public Localizer T { get; set; } public void HandleEvent(QueuingEmailEvent eventMessage) { @@ -52,11 +55,15 @@ public void HandleEvent(QueuingEmailEvent eventMessage) if (handledTemplates.TryGetValue(tpl.Name, out shouldHandle) && shouldHandle) { var orderId = eventMessage.Tokens.First(x => x.Key.IsCaseInsensitiveEqual("Order.ID")).Value.ToInt(); - var qea = CreatePdfInvoiceAttachment(orderId); - if (qea != null) + try { + var qea = CreatePdfInvoiceAttachment(orderId); qe.Attachments.Add(qea); } + catch (Exception ex) + { + Logger.Error(T("Admin.System.QueuedEmails.ErrorCreatingAttachment"), ex); + } } } @@ -65,35 +72,25 @@ private QueuedEmailAttachment CreatePdfInvoiceAttachment(int orderId) var urlHelper = new UrlHelper(_httpRequest.RequestContext); var path = urlHelper.Action("Print", "Order", new { id = orderId, pdf = true, area = "" }); - try - { - var fileResponse = _fileDownloadManager.Value.DownloadFile(path, true, 5000); - - if (fileResponse == null) - { - // ... - } - - if (!fileResponse.ContentType.IsCaseInsensitiveEqual("application/pdf")) - { - // ... - } + var fileResponse = _fileDownloadManager.Value.DownloadFile(path, true, 5000); - return new QueuedEmailAttachment - { - StorageLocation = EmailAttachmentStorageLocation.Blob, - Data = fileResponse.Data, - MimeType = fileResponse.ContentType, - Name = fileResponse.FileName - }; + if (fileResponse == null) + { + throw new InvalidOperationException(T("Admin.System.QueuedEmails.ErrorEmptyAttachmentResult", path)); } - catch (Exception ex) + + if (!fileResponse.ContentType.IsCaseInsensitiveEqual("application/pdf")) { - // TODO localize - Logger.Error("Error occured while creating e-mail attachment", ex); + throw new InvalidOperationException(T("Admin.System.QueuedEmails.ErrorNoPdfAttachment")); } - return null; + return new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.Blob, + Data = fileResponse.Data, + MimeType = fileResponse.ContentType, + Name = fileResponse.FileName + }; } } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index d479dda36e..8c64d2273a 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -161,6 +161,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs index d00783f2cf..115d2b1beb 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/QueuedEmailController.cs @@ -280,7 +280,7 @@ public ActionResult DownloadAttachment(int id) return RedirectToAction("DownloadFile", "Download", new { downloadId = qea.FileId.Value }); } - NotifyError("Could not download e-mail attachment: no data"); + NotifyError(T("Admin.System.QueuedEmails.CouldNotDownloadAttachment")); return RedirectToAction("List"); } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml index ad1a0f5350..44c2fe7f1e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/QueuedEmail/List.cshtml @@ -67,12 +67,7 @@ @Html.SmartLabelFor(model => model.SearchSendManually) - @Html.DropDownList("SearchSendManually", new List - { - new SelectListItem { Text = T("Common.Unspecified"), Value = "", Selected = !Model.SearchSendManually.HasValue }, - new SelectListItem { Text = T("Admin.Common.Yes"), Value = "true", Selected = Model.SearchSendManually ?? false }, - new SelectListItem { Text = T("Admin.Common.No"), Value = "false", Selected = !Model.SearchSendManually ?? false } - }) + @Html.EditorFor(model => Model.SearchSendManually) @@ -121,7 +116,7 @@ columns.Bound(x => x.Id) .ClientTemplate("\"><#= Id #>"); columns.Bound(x => x.AttachmentsCount) - .HeaderTemplate("") + .HeaderTemplate(@) .Width(20); columns.Bound(x => x.Subject); columns.Bound(x => x.Priority) diff --git a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs index 70ba4ddab4..bf25af3aaa 100644 --- a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs @@ -514,8 +514,9 @@ public ActionResult Print(int id, bool pdf = false) return new HttpUnauthorizedResult(); var model = PrepareOrderDetailsModel(order); + var fileName = T("Order.PdfInvoiceFileName", order.Id); - return PrintCore(new List { model }, pdf, "order-{0}.pdf".FormatWith(order.Id)); + return PrintCore(new List { model }, pdf, fileName); } [AdminAuthorize] diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs index 54df8e0005..cd7ddaf22c 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs @@ -2530,6 +2530,10 @@ protected override void Alter(IList entities) { x.Name = "E-Mail senden"; }) + .Alter("Clear email queue", x => + { + x.Name = "E-Mail Queue bereinigen"; + }) .Alter("Keep alive", x => { x.Name = "Keep alive"; From 81aa3b935d2721257d917565fcac48359b56129e Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 8 Jul 2015 00:31:52 +0200 Subject: [PATCH 0053/1074] E-mail attachments: added attachment support to message templates. Next step: proper UI (upload files) --- .../Domain/Messages/MessageTemplate.cs | 16 +++ ...058_MessageTemplateAttachments.Designer.cs | 29 ++++ ...507072138058_MessageTemplateAttachments.cs | 22 +++ ...7072138058_MessageTemplateAttachments.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 7 + .../Media/DownloadService.cs | 60 +++------ .../Media/IDownloadService.cs | 8 ++ .../Messages/MessageTemplateService.cs | 16 ++- .../Messages/WorkflowMessageService.cs | 108 +++++++++------ .../Controllers/MessageTemplateController.cs | 48 +++---- .../Models/Messages/MessageTemplateModel.cs | 18 +++ .../MessageTemplate/_CreateOrUpdate.cshtml | 59 +++++++- .../Shared/EditorTemplates/Download.cshtml | 1 + 13 files changed, 405 insertions(+), 113 deletions(-) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.resx diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/MessageTemplate.cs b/src/Libraries/SmartStore.Core/Domain/Messages/MessageTemplate.cs index 282fc0407d..75f66564ae 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/MessageTemplate.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/MessageTemplate.cs @@ -1,4 +1,5 @@ using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Stores; namespace SmartStore.Core.Domain.Messages @@ -47,5 +48,20 @@ public partial class MessageTemplate : BaseEntity, ILocalizedEntity, IStoreMappi /// Gets or sets a value indicating whether emails derived from the template are only send manually /// public bool SendManually { get; set; } + + /// + /// Gets or sets the attachment 1 file identifier + /// + public int? Attachment1FileId { get; set; } + + /// + /// Gets or sets the attachment 2 file identifier + /// + public int? Attachment2FileId { get; set; } + + /// + /// Gets or sets the attachment 3 file identifier + /// + public int? Attachment3FileId { get; set; } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.Designer.cs new file mode 100644 index 0000000000..cb29f9e05f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class MessageTemplateAttachments : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(MessageTemplateAttachments)); + + string IMigrationMetadata.Id + { + get { return "201507072138058_MessageTemplateAttachments"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs new file mode 100644 index 0000000000..0a48be7f37 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs @@ -0,0 +1,22 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class MessageTemplateAttachments : DbMigration + { + public override void Up() + { + AddColumn("dbo.MessageTemplate", "Attachment1FileId", c => c.Int()); + AddColumn("dbo.MessageTemplate", "Attachment2FileId", c => c.Int()); + AddColumn("dbo.MessageTemplate", "Attachment3FileId", c => c.Int()); + } + + public override void Down() + { + DropColumn("dbo.MessageTemplate", "Attachment3FileId"); + DropColumn("dbo.MessageTemplate", "Attachment2FileId"); + DropColumn("dbo.MessageTemplate", "Attachment1FileId"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.resx b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.resx new file mode 100644 index 0000000000..3970382b24 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index c34ecbb4e8..0cdc69b343 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -286,6 +286,10 @@ 201506262044329_QueuedEmailAttachments.cs + + + 201507072138058_MessageTemplateAttachments.cs + @@ -552,6 +556,9 @@ 201506262044329_QueuedEmailAttachments.cs + + 201507072138058_MessageTemplateAttachments.cs + diff --git a/src/Libraries/SmartStore.Services/Media/DownloadService.cs b/src/Libraries/SmartStore.Services/Media/DownloadService.cs index 71117a3bcd..25d9bc9b2c 100644 --- a/src/Libraries/SmartStore.Services/Media/DownloadService.cs +++ b/src/Libraries/SmartStore.Services/Media/DownloadService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; @@ -23,13 +24,7 @@ public partial class DownloadService : IDownloadService #region Ctor - /// - /// Ctor - /// - /// Download repository - /// - public DownloadService(IRepository downloadRepository, - IEventPublisher eventPubisher) + public DownloadService(IRepository downloadRepository, IEventPublisher eventPubisher) { _downloadRepository = downloadRepository; _eventPubisher = eventPubisher; @@ -39,11 +34,6 @@ public DownloadService(IRepository downloadRepository, #region Methods - /// - /// Gets a download - /// - /// Download identifier - /// Download public virtual Download GetDownloadById(int downloadId) { if (downloadId == 0) @@ -53,11 +43,25 @@ public virtual Download GetDownloadById(int downloadId) return download; } - /// - /// Gets a download by GUID - /// - /// Download GUID - /// Download + public virtual IList GetDownloadsByIds(int[] downloadIds) + { + if (downloadIds == null || downloadIds.Length == 0) + return new List(); + + var query = from dl in _downloadRepository.Table + where downloadIds.Contains(dl.Id) + select dl; + + var downloads = query.ToList(); + + // sort by passed identifier sequence + var sortQuery = from i in downloadIds + join d in downloads on i equals d.Id + select d; + + return sortQuery.ToList(); + } + public virtual Download GetDownloadByGuid(Guid downloadGuid) { if (downloadGuid == Guid.Empty) @@ -70,10 +74,6 @@ public virtual Download GetDownloadByGuid(Guid downloadGuid) return order; } - /// - /// Deletes a download - /// - /// Download public virtual void DeleteDownload(Download download) { if (download == null) @@ -84,10 +84,6 @@ public virtual void DeleteDownload(Download download) _eventPubisher.EntityDeleted(download); } - /// - /// Inserts a download - /// - /// Download public virtual void InsertDownload(Download download) { if (download == null) @@ -98,10 +94,6 @@ public virtual void InsertDownload(Download download) _eventPubisher.EntityInserted(download); } - /// - /// Updates the download - /// - /// Download public virtual void UpdateDownload(Download download) { if (download == null) @@ -112,11 +104,6 @@ public virtual void UpdateDownload(Download download) _eventPubisher.EntityUpdated(download); } - /// - /// Gets a value indicating whether download is allowed - /// - /// Order item to check - /// True if download is allowed; otherwise, false. public virtual bool IsDownloadAllowed(OrderItem orderItem) { if (orderItem == null) @@ -182,11 +169,6 @@ public virtual bool IsDownloadAllowed(OrderItem orderItem) return false; } - /// - /// Gets a value indicating whether license download is allowed - /// - /// Order item to check - /// True if license download is allowed; otherwise, false. public virtual bool IsLicenseDownloadAllowed(OrderItem orderItem) { if (orderItem == null) diff --git a/src/Libraries/SmartStore.Services/Media/IDownloadService.cs b/src/Libraries/SmartStore.Services/Media/IDownloadService.cs index 73afed9a32..70282f56a4 100644 --- a/src/Libraries/SmartStore.Services/Media/IDownloadService.cs +++ b/src/Libraries/SmartStore.Services/Media/IDownloadService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Orders; @@ -16,6 +17,13 @@ public partial interface IDownloadService /// Download Download GetDownloadById(int downloadId); + /// + /// Gets downloads by identifiers + /// + /// Download identifiers + /// List of download entities + IList GetDownloadsByIds(int[] downloadIds); + /// /// Gets a download by GUID /// diff --git a/src/Libraries/SmartStore.Services/Messages/MessageTemplateService.cs b/src/Libraries/SmartStore.Services/Messages/MessageTemplateService.cs index 92ae48a637..65d8fe735c 100644 --- a/src/Libraries/SmartStore.Services/Messages/MessageTemplateService.cs +++ b/src/Libraries/SmartStore.Services/Messages/MessageTemplateService.cs @@ -45,7 +45,8 @@ public partial class MessageTemplateService: IMessageTemplateService /// Store mapping service /// Message template repository /// Event published - public MessageTemplateService(ICacheManager cacheManager, + public MessageTemplateService( + ICacheManager cacheManager, IRepository storeMappingRepository, ILanguageService languageService, ILocalizedEntityService localizedEntityService, @@ -209,7 +210,7 @@ public virtual MessageTemplate CopyMessageTemplate(MessageTemplate messageTempla if (messageTemplate == null) throw new ArgumentNullException("messageTemplate"); - var mtCopy = new MessageTemplate() + var mtCopy = new MessageTemplate { Name = messageTemplate.Name, BccEmailAddresses = messageTemplate.BccEmailAddresses, @@ -218,25 +219,26 @@ public virtual MessageTemplate CopyMessageTemplate(MessageTemplate messageTempla IsActive = messageTemplate.IsActive, EmailAccountId = messageTemplate.EmailAccountId, LimitedToStores = messageTemplate.LimitedToStores + // INFO: we do not copy attachments }; InsertMessageTemplate(mtCopy); var languages = _languageService.GetAllLanguages(true); - //localization + // localization foreach (var lang in languages) { var bccEmailAddresses = messageTemplate.GetLocalized(x => x.BccEmailAddresses, lang.Id, false, false); - if (!String.IsNullOrEmpty(bccEmailAddresses)) + if (bccEmailAddresses.HasValue()) _localizedEntityService.SaveLocalizedValue(mtCopy, x => x.BccEmailAddresses, bccEmailAddresses, lang.Id); var subject = messageTemplate.GetLocalized(x => x.Subject, lang.Id, false, false); - if (!String.IsNullOrEmpty(subject)) + if (subject.HasValue()) _localizedEntityService.SaveLocalizedValue(mtCopy, x => x.Subject, subject, lang.Id); var body = messageTemplate.GetLocalized(x => x.Body, lang.Id, false, false); - if (!String.IsNullOrEmpty(body)) + if (body.HasValue()) _localizedEntityService.SaveLocalizedValue(mtCopy, x => x.Body, subject, lang.Id); var emailAccountId = messageTemplate.GetLocalized(x => x.EmailAccountId, lang.Id, false, false); @@ -244,7 +246,7 @@ public virtual MessageTemplate CopyMessageTemplate(MessageTemplate messageTempla _localizedEntityService.SaveLocalizedValue(mtCopy, x => x.EmailAccountId, emailAccountId, lang.Id); } - //store mapping + // store mapping var selectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(messageTemplate); foreach (var id in selectedStoreIds) { diff --git a/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs b/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs index 57efae24d2..64adb4aa26 100644 --- a/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs +++ b/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs @@ -16,6 +16,7 @@ using SmartStore.Core.Events; using SmartStore.Services.Customers; using SmartStore.Services.Localization; +using SmartStore.Services.Media; using SmartStore.Services.Stores; namespace SmartStore.Services.Messages @@ -36,21 +37,26 @@ public partial class WorkflowMessageService : IWorkflowMessageService private readonly IEventPublisher _eventPublisher; private readonly IWorkContext _workContext; private readonly HttpRequestBase _httpRequest; + private readonly IDownloadService _downloadServioce; #endregion #region Ctor - public WorkflowMessageService(IMessageTemplateService messageTemplateService, - IQueuedEmailService queuedEmailService, ILanguageService languageService, - ITokenizer tokenizer, IEmailAccountService emailAccountService, + public WorkflowMessageService( + IMessageTemplateService messageTemplateService, + IQueuedEmailService queuedEmailService, + ILanguageService languageService, + ITokenizer tokenizer, + IEmailAccountService emailAccountService, IMessageTokenProvider messageTokenProvider, IStoreService storeService, IStoreContext storeContext, EmailAccountSettings emailAccountSettings, IEventPublisher eventPublisher, IWorkContext workContext, - HttpRequestBase httpRequest) + HttpRequestBase httpRequest, + IDownloadService downloadServioce) { this._messageTemplateService = messageTemplateService; this._queuedEmailService = queuedEmailService; @@ -63,7 +69,8 @@ public WorkflowMessageService(IMessageTemplateService messageTemplateService, this._emailAccountSettings = emailAccountSettings; this._eventPublisher = eventPublisher; this._workContext = workContext; - _httpRequest = httpRequest; + this._httpRequest = httpRequest; + this._downloadServioce = downloadServioce; } #endregion @@ -109,6 +116,33 @@ protected int SendNotification( SendManually = messageTemplate.SendManually }; + // create attachments if any + var fileIds = (new int?[] + { + messageTemplate.GetLocalized(x => x.Attachment1FileId, languageId), + messageTemplate.GetLocalized(x => x.Attachment2FileId, languageId), + messageTemplate.GetLocalized(x => x.Attachment3FileId, languageId) + }) + .Where(x => x.HasValue) + .Select(x => x.Value) + .ToArray(); + + if (fileIds.Any()) + { + var files = _downloadServioce.GetDownloadsByIds(fileIds); + foreach (var file in files) + { + email.Attachments.Add(new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.FileReference, + FileId = file.Id, + Name = (file.Filename.NullEmpty() ?? file.Id.ToString()) + file.Extension.EmptyNull(), + MimeType = file.ContentType.NullEmpty() ?? "application/octet-stream" + }); + } + } + + // publish event so that integrators can add attachments, alter the email etc. _eventPublisher.Publish(new QueuingEmailEvent { @@ -124,12 +158,10 @@ protected int SendNotification( return email.Id; } - protected MessageTemplate GetLocalizedActiveMessageTemplate(string messageTemplateName, int languageId, int storeId) + protected MessageTemplate GetActiveMessageTemplate(string messageTemplateName, int storeId) { - //TODO remove languageId parameter var messageTemplate = _messageTemplateService.GetMessageTemplateByName(messageTemplateName, storeId); - //no template found if (messageTemplate == null) return null; @@ -241,7 +273,7 @@ public virtual int SendCustomerRegisteredNotificationMessage(Customer customer, var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewCustomer.Notification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewCustomer.Notification", store.Id); if (messageTemplate == null) return 0; @@ -280,7 +312,7 @@ public virtual int SendCustomerWelcomeMessage(Customer customer, int languageId) var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.WelcomeMessage", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.WelcomeMessage", store.Id); if (messageTemplate == null) return 0; @@ -314,7 +346,7 @@ public virtual int SendCustomerEmailValidationMessage(Customer customer, int lan var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.EmailValidationMessage", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.EmailValidationMessage", store.Id); if (messageTemplate == null) return 0; @@ -348,7 +380,7 @@ public virtual int SendCustomerPasswordRecoveryMessage(Customer customer, int la var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.PasswordRecovery", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.PasswordRecovery", store.Id); if (messageTemplate == null) return 0; @@ -386,7 +418,7 @@ public virtual int SendOrderPlacedStoreOwnerNotification(Order order, int langua var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("OrderPlaced.StoreOwnerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("OrderPlaced.StoreOwnerNotification", store.Id); if (messageTemplate == null) return 0; @@ -431,7 +463,7 @@ public virtual int SendOrderPlacedCustomerNotification(Order order, int language var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("OrderPlaced.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("OrderPlaced.CustomerNotification", store.Id); if (messageTemplate == null) return 0; @@ -474,7 +506,7 @@ public virtual int SendShipmentSentCustomerNotification(Shipment shipment, int l var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("ShipmentSent.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("ShipmentSent.CustomerNotification", store.Id); if (messageTemplate == null) return 0; @@ -514,7 +546,7 @@ public virtual int SendShipmentDeliveredCustomerNotification(Shipment shipment, var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("ShipmentDelivered.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("ShipmentDelivered.CustomerNotification", store.Id); if (messageTemplate == null) return 0; @@ -550,7 +582,7 @@ public virtual int SendOrderCompletedCustomerNotification(Order order, int langu var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("OrderCompleted.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("OrderCompleted.CustomerNotification", store.Id); if (messageTemplate == null) return 0; @@ -589,7 +621,7 @@ public virtual int SendOrderCancelledCustomerNotification(Order order, int langu var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("OrderCancelled.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("OrderCancelled.CustomerNotification", store.Id); if (messageTemplate == null) return 0; @@ -626,7 +658,7 @@ public virtual int SendNewOrderNoteAddedCustomerNotification(OrderNote orderNote var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.NewOrderNote", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.NewOrderNote", store.Id); if (messageTemplate == null) return 0; @@ -662,7 +694,7 @@ public virtual int SendRecurringPaymentCancelledStoreOwnerNotification(Recurring var store = _storeService.GetStoreById(recurringPayment.InitialOrder.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("RecurringPaymentCancelled.StoreOwnerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("RecurringPaymentCancelled.StoreOwnerNotification", store.Id); if (messageTemplate == null) return 0; @@ -704,7 +736,7 @@ public virtual int SendNewsLetterSubscriptionActivationMessage(NewsLetterSubscri var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewsLetterSubscription.ActivationMessage", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewsLetterSubscription.ActivationMessage", store.Id); if (messageTemplate == null) return 0; @@ -739,7 +771,7 @@ public virtual int SendNewsLetterSubscriptionDeactivationMessage(NewsLetterSubsc var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewsLetterSubscription.DeactivationMessage", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewsLetterSubscription.DeactivationMessage", store.Id); if (messageTemplate == null) return 0; @@ -784,7 +816,7 @@ public virtual int SendProductEmailAFriendMessage(Customer customer, int languag var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Service.EmailAFriend", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Service.EmailAFriend", store.Id); if (messageTemplate == null) return 0; @@ -822,7 +854,7 @@ public virtual int SendProductQuestionMessage(Customer customer, int languageId, var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Product.AskQuestion", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Product.AskQuestion", store.Id); if (messageTemplate == null) return 0; @@ -864,7 +896,7 @@ public virtual int SendWishlistEmailAFriendMessage(Customer customer, int langua var store = _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Wishlist.EmailAFriend", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Wishlist.EmailAFriend", store.Id); if (messageTemplate == null) return 0; @@ -905,7 +937,7 @@ public virtual int SendNewReturnRequestStoreOwnerNotification(ReturnRequest retu var store = _storeService.GetStoreById(orderItem.Order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewReturnRequest.StoreOwnerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewReturnRequest.StoreOwnerNotification", store.Id); if (messageTemplate == null) return 0; @@ -946,7 +978,7 @@ public virtual int SendReturnRequestStatusChangedCustomerNotification(ReturnRequ var store = _storeService.GetStoreById(orderItem.Order.StoreId) ?? _storeContext.CurrentStore; languageId = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("ReturnRequestStatusChanged.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("ReturnRequestStatusChanged.CustomerNotification", store.Id); if (messageTemplate == null) return 0; @@ -991,7 +1023,7 @@ public int SendNewForumTopicMessage(Customer customer, var store = _storeContext.CurrentStore; - var messageTemplate = GetLocalizedActiveMessageTemplate("Forums.NewForumTopic", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Forums.NewForumTopic", store.Id); if (messageTemplate == null) { return 0; @@ -1035,7 +1067,7 @@ public int SendNewForumPostMessage(Customer customer, var store = _storeContext.CurrentStore; - var messageTemplate = GetLocalizedActiveMessageTemplate("Forums.NewForumPost", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Forums.NewForumPost", store.Id); if (messageTemplate == null) { return 0; @@ -1074,7 +1106,7 @@ public int SendPrivateMessageNotification(Customer customer, PrivateMessage priv var store = _storeService.GetStoreById(privateMessage.StoreId) ?? _storeContext.CurrentStore; - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.NewPM", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.NewPM", store.Id); if (messageTemplate == null) { return 0; @@ -1133,7 +1165,7 @@ public virtual int SendGenericMessage(string messageTemplateName, Action x.BccEmailAddresses, - localized.BccEmailAddresses, - localized.LanguageId); - - _localizedEntityService.SaveLocalizedValue(mt, - x => x.Subject, - localized.Subject, - localized.LanguageId); - - _localizedEntityService.SaveLocalizedValue(mt, - x => x.Body, - localized.Body, - localized.LanguageId); - - _localizedEntityService.SaveLocalizedValue(mt, - x => x.EmailAccountId, - localized.EmailAccountId, - localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(mt, x => x.BccEmailAddresses, localized.BccEmailAddresses, localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Subject, localized.Subject, localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(mt,x => x.Body, localized.Body, localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(mt, x => x.EmailAccountId, localized.EmailAccountId, localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment1FileId, localized.Attachment1FileId, localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment2FileId, localized.Attachment2FileId, localized.LanguageId); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment3FileId, localized.Attachment3FileId, localized.LanguageId); } } - [NonAction] private void PrepareStoresMappingModel(MessageTemplateModel model, MessageTemplate messageTemplate, bool excludeProperties) { @@ -156,7 +143,9 @@ public ActionResult List() //stores model.AvailableStores.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" }); foreach (var s in _storeService.GetAllStores()) + { model.AvailableStores.Add(new SelectListItem() { Text = s.Name, Value = s.Id.ToString() }); + } return View(model); } @@ -192,19 +181,24 @@ public ActionResult Edit(int id) FillTokensTree(model.TokensTree, _messageTokenProvider.GetListOfAllowedTokens()); - //available email accounts - foreach (var ea in _emailAccountService.GetAllEmailAccounts()) - model.AvailableEmailAccounts.Add(ea.ToModel()); + // available email accounts + foreach (var ea in _emailAccountService.GetAllEmailAccounts()) + { + model.AvailableEmailAccounts.Add(ea.ToModel()); + } - //Store + // Store PrepareStoresMappingModel(model, messageTemplate, false); - //locales + // locales AddLocales(_languageService, model.Locales, (locale, languageId) => { locale.BccEmailAddresses = messageTemplate.GetLocalized(x => x.BccEmailAddresses, languageId, false, false); locale.Subject = messageTemplate.GetLocalized(x => x.Subject, languageId, false, false); locale.Body = messageTemplate.GetLocalized(x => x.Body, languageId, false, false); + locale.Attachment1FileId = messageTemplate.GetLocalized(x => x.Attachment1FileId, languageId, false, false); + locale.Attachment2FileId = messageTemplate.GetLocalized(x => x.Attachment2FileId, languageId, false, false); + locale.Attachment3FileId = messageTemplate.GetLocalized(x => x.Attachment3FileId, languageId, false, false); var emailAccountId = messageTemplate.GetLocalized(x => x.EmailAccountId, languageId, false, false); locale.EmailAccountId = emailAccountId > 0 ? emailAccountId : _emailAccountSettings.DefaultEmailAccountId; @@ -229,10 +223,10 @@ public ActionResult Edit(MessageTemplateModel model, bool continueEditing) messageTemplate = model.ToEntity(messageTemplate); _messageTemplateService.UpdateMessageTemplate(messageTemplate); - //Stores + // Stores _storeMappingService.SaveStoreMappings(messageTemplate, model.SelectedStoreIds); - //locales + // locales UpdateLocales(messageTemplate, model); NotifySuccess(_localizationService.GetResource("Admin.ContentManagement.MessageTemplates.Updated")); diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Messages/MessageTemplateModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Messages/MessageTemplateModel.cs index a0de763db5..5764db0656 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Messages/MessageTemplateModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Messages/MessageTemplateModel.cs @@ -52,6 +52,15 @@ public MessageTemplateModel() [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.SendManually")] public bool SendManually { get; set; } + [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.Attachment1FileId")] + public int? Attachment1FileId { get; set; } + + [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.Attachment2FileId")] + public int? Attachment2FileId { get; set; } + + [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.Attachment3FileId")] + public int? Attachment3FileId { get; set; } + //Store mapping [SmartResourceDisplayName("Admin.Common.Store.LimitedTo")] public bool LimitedToStores { get; set; } @@ -81,5 +90,14 @@ public class MessageTemplateLocalizedModel : ILocalizedModelLocal [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.EmailAccount")] public int EmailAccountId { get; set; } + + [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.Attachment1FileId")] + public int? Attachment1FileId { get; set; } + + [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.Attachment2FileId")] + public int? Attachment2FileId { get; set; } + + [SmartResourceDisplayName("Admin.ContentManagement.MessageTemplates.Fields.Attachment3FileId")] + public int? Attachment3FileId { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/_CreateOrUpdate.cshtml index 82c2317d34..7021397e30 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/_CreateOrUpdate.cshtml @@ -13,7 +13,7 @@ x.Add().Text(T("Admin.Common.Info").Text).Content(TabInfo()).Selected(true); x.Add().Text(T("Admin.Common.Stores").Text).Content(TabStores()); - //generate an event + // generate an event EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "template-edit", this.Html, this.Model)); }) @@ -126,6 +126,33 @@ @Html.ValidationMessageFor(model => model.Locales[item].Subject) + + + @Html.SmartLabelFor(model => model.Locales[item].Attachment1FileId) + + + @Html.EditorFor(model => Model.Locales[item].Attachment1FileId) + @Html.ValidationMessageFor(model => model.Locales[item].Attachment1FileId) + + + + + @Html.SmartLabelFor(model => model.Locales[item].Attachment2FileId) + + + @Html.EditorFor(model => Model.Locales[item].Attachment2FileId) + @Html.ValidationMessageFor(model => model.Locales[item].Attachment2FileId) + + + + + @Html.SmartLabelFor(model => model.Locales[item].Attachment3FileId) + + + @Html.EditorFor(model => Model.Locales[item].Attachment3FileId) + @Html.ValidationMessageFor(model => model.Locales[item].Attachment3FileId) + + @Html.SmartLabelFor(model => model.Locales[item].Body) @@ -170,6 +197,33 @@ @Html.ValidationMessageFor(model => model.Subject) + + + @Html.SmartLabelFor(model => model.Attachment1FileId) + + + @Html.EditorFor(model => Model.Attachment1FileId) + @Html.ValidationMessageFor(model => model.Attachment1FileId) + + + + + @Html.SmartLabelFor(model => model.Attachment2FileId) + + + @Html.EditorFor(model => Model.Attachment2FileId) + @Html.ValidationMessageFor(model => model.Attachment2FileId) + + + + + @Html.SmartLabelFor(model => model.Attachment3FileId) + + + @Html.EditorFor(model => Model.Attachment3FileId) + @Html.ValidationMessageFor(model => model.Attachment3FileId) + + @Html.SmartLabelFor(model => model.Body) @@ -246,7 +300,8 @@ else {
@T("Admin.Configuration.Stores.NoStoresDefined")
- } + } + } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download.cshtml index d530182896..a3b33585b9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download.cshtml @@ -55,6 +55,7 @@ } +
@(download != null ? download.Filename : "")
From f6301f03a2cb1b0a176cabf32c8a1c26d3fdeb7c Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 13 Jul 2015 11:29:00 +0200 Subject: [PATCH 0054/1074] Payment pre-processing should not output unlocalized messages --- .../Migrations/201506181858349_AclRecordCustomerRole.cs | 4 ++++ .../SmartStore.Services/Orders/OrderProcessingService.cs | 9 +++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs index 2641ef6b47..9723bf49da 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs @@ -30,6 +30,10 @@ public void Seed(SmartObjectContext context) public void MigrateLocaleResources(LocaleResourcesBuilder builder) { + builder.AddOrUpdate("Common.Error.PreProcessPayment", + "Unfortunately the selected payment method caused an error. Please correct your entries, try it again or select another payment method.", + "Die gewhlte Zahlungsart verursachte leider einen Fehler. Bitte korrigieren Sie Ihre Eingaben, versuchen Sie es erneut oder whlen Sie eine andere Zahlungsart."); + builder.AddOrUpdate("Admin.Configuration.Category.Acl.AssignToSubCategoriesAndProducts", "Transfer this ACL configuration to children", "Diese Konfiguration fr Kindelemente bernehmen"); diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index a1b07c3749..0c2a0176b3 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -808,12 +808,9 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR if (!preProcessPaymentResult.Success) { - foreach (var paymentError in preProcessPaymentResult.Errors) - { - result.AddError(string.Format("Payment error: {0}", paymentError)); - } - - throw new SmartException("Error while pre-processing the payment"); + result.Errors.AddRange(preProcessPaymentResult.Errors); + result.Errors.Add(T("Common.Error.PreProcessPayment")); + return result; } Address billingAddress = null; From cb13b148b753d1e92b80a9748f40eb140548475f Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 13 Jul 2015 11:33:50 +0200 Subject: [PATCH 0055/1074] Updated changelog --- changelog.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 2d8240fc1c..daf03d0e7f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,10 +1,11 @@ -# Release Notes +# Release Notes ## SmartStore.NET 2.2.2 ### New Features * #210 Implement multi-store support for import/export * Added zip code to shipping by weight computation method +* Skrill payment plugin ### Improvements * (Soft) deletion of SEO slug supporting entities now also deletes the corresponding url records From 9a89768c69df96a87d5a9f619b5ea94e47074e7c Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Mon, 13 Jul 2015 14:21:15 +0200 Subject: [PATCH 0056/1074] Weight adjustments of attributes weren't applied in shopping cart overview --- changelog.md | 1 + .../SmartStore.Web/Controllers/ShoppingCartController.cs | 7 +++++++ .../SmartStore.Web/Views/Checkout/ShippingAddress.cshtml | 4 ++-- .../SmartStore.Web/Views/Product/_Attributes.Mobile.cshtml | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index daf03d0e7f..eedc045a1d 100644 --- a/changelog.md +++ b/changelog.md @@ -23,6 +23,7 @@ * #691 Product quantity not added to cart on mobile theme * #186 Mobile: variant images do not refresh * #671 Bundle products: display base price according to applied discount +* Weight adjustment of attributes weren't applied in shopping cart overview ## SmartStore.NET 2.2.1 diff --git a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs index 9229462276..ea2abd62de 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs @@ -271,6 +271,13 @@ private ShoppingCartModel.ShoppingCartItemModel PrepareShoppingCartItemModel(Org else { model.AttributeInfo = _productAttributeFormatter.FormatAttributes(product, item.AttributesXml); + + var selectedAttributeValues = _productAttributeParser.ParseProductVariantAttributeValues(item.AttributesXml).ToList(); + if (selectedAttributeValues != null) + { + foreach (var attributeValue in selectedAttributeValues) + model.Weight = decimal.Add(model.Weight, attributeValue.WeightAdjustment); + } } if (product.DisplayDeliveryTimeAccordingToStock(_catalogSettings)) diff --git a/src/Presentation/SmartStore.Web/Views/Checkout/ShippingAddress.cshtml b/src/Presentation/SmartStore.Web/Views/Checkout/ShippingAddress.cshtml index 1d7d4e6552..e003882015 100644 --- a/src/Presentation/SmartStore.Web/Views/Checkout/ShippingAddress.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Checkout/ShippingAddress.cshtml @@ -45,8 +45,8 @@ @item.PhoneNumber
} - @if (item.FaxEnabled) - { + @if (item.FaxEnabled && !String.IsNullOrEmpty(item.FaxNumber)) +{
@T("Address.Fields.FaxNumber"): @item.FaxNumber diff --git a/src/Presentation/SmartStore.Web/Views/Product/_Attributes.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Product/_Attributes.Mobile.cshtml index 1f759cc15d..c7b07caebf 100644 --- a/src/Presentation/SmartStore.Web/Views/Product/_Attributes.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Product/_Attributes.Mobile.cshtml @@ -51,7 +51,7 @@ } @foreach (var pvaValue in attribute.Values) { - + } } From e3d8592be3a8424ca5896e729ffd3c57faa2c765 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Mon, 13 Jul 2015 15:52:23 +0200 Subject: [PATCH 0057/1074] Added link to imprint and disclaimer to footer in mobile theme --- changelog.md | 5 +++-- .../Views/Common/InfoBlock.Mobile.cshtml | 12 +++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index eedc045a1d..fafe3b82cf 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,4 @@ -# Release Notes +# Release Notes ## SmartStore.NET 2.2.2 @@ -11,7 +11,8 @@ * (Soft) deletion of SEO slug supporting entities now also deletes the corresponding url records * License checker now supports IDN mapping for domain names * #716 Supporting of paged google-product data query for SQL-Server Compact Edition -* #648 Add hint for * at mandatory form fields at address creation +* #648 Add hint for * at mandatory form fields at address creation +* Added link to imprint and disclaimer to footer in mobile theme ### Bugfixes * #694 Product variant attribute in product page should not be preselected implicitly diff --git a/src/Presentation/SmartStore.Web/Views/Common/InfoBlock.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Common/InfoBlock.Mobile.cshtml index 118f1f892d..3eb5680b4e 100644 --- a/src/Presentation/SmartStore.Web/Views/Common/InfoBlock.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Common/InfoBlock.Mobile.cshtml @@ -19,7 +19,7 @@ @@ -30,13 +30,19 @@
  • @T("ConditionsOfUse")
  • + @if (Model.AllowPrivateMessages) { - + } -@Html.Widget("mobile_infoblock_after") \ No newline at end of file +@Html.Widget("mobile_infoblock_after") From aea09827418dcf5cd59dd6222e0f04bf7d9b2f2d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 13 Jul 2015 20:42:35 +0200 Subject: [PATCH 0058/1074] Changed some string resources --- .../201506181858349_AclRecordCustomerRole.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs index 7b37421da7..9126926fe2 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs @@ -99,6 +99,26 @@ before you can assign them to all subcategories and products.
    builder.AddOrUpdate("Admin.Configuration.Payment.CannotActivatePaymentMethod") .Value("de", "Das Plugin erlaubt keine Aktivierung dieser Zahlungsart."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.SupportCapture", + "Supports capture", + "Buchung mglich"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.SupportPartiallyRefund", + "Supports partial refund", + "Teilerstattung mglich"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.SupportRefund", + "Supports refund", + "Erstattung mglich"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.SupportVoid", + "Supports void", + "Stornierung mglich"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.RecurringPaymentType", + "Recurring payments", + "Wiederkehrende Zahlungen"); } } } From af28c9bc56b68f800c0f64c2f485c312bdb3c812 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 14 Jul 2015 00:46:19 +0200 Subject: [PATCH 0059/1074] Solution did not compile: Included missing files and code. Re-created QueuedEmailAttachments migration. --- .../EmailAttachmentStorageLocation.cs | 21 +++ .../Domain/Messages/QueuedEmail.cs | 12 ++ .../Domain/Messages/QueuedEmailAttachment.cs | 7 +- .../SmartStore.Core/Plugins/ILicensable.cs | 11 -- .../SmartStore.Core/SmartStore.Core.csproj | 2 + .../Messages/QueuedEmailAttachmentMap.cs | 29 ++++ ...2241575_QueuedEmailAttachments.Designer.cs | 29 ++++ ...201507132241575_QueuedEmailAttachments.cs} | 9 +- ...01507132241575_QueuedEmailAttachments.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 8 ++ .../Controllers/EmailAccountController.cs | 4 +- 11 files changed, 235 insertions(+), 23 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs delete mode 100644 src/Libraries/SmartStore.Core/Plugins/ILicensable.cs create mode 100644 src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.Designer.cs rename src/Libraries/SmartStore.Data/Migrations/{201506262044329_QueuedEmailAttachments.cs => 201507132241575_QueuedEmailAttachments.cs} (98%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.resx diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs new file mode 100644 index 0000000000..34d369c1cf --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs @@ -0,0 +1,21 @@ + +namespace SmartStore.Core.Domain.Messages +{ + public enum EmailAttachmentStorageLocation + { + /// + /// Attachment is embedded as Blob + /// + Blob, + + /// + /// Attachment is a reference to + /// + FileReference, + + /// + /// Attachment is located on disk (physical or virtual path) + /// + Path + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs index 573231b382..d3f7e63b93 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace SmartStore.Core.Domain.Messages { @@ -7,6 +8,8 @@ namespace SmartStore.Core.Domain.Messages ///
    public partial class QueuedEmail : BaseEntity { + private ICollection _attachments; + /// /// Gets or sets the priority /// @@ -91,5 +94,14 @@ public partial class QueuedEmail : BaseEntity /// Gets the email account ///
    public virtual EmailAccount EmailAccount { get; set; } + + /// + /// Gets or sets the collection of attachments + /// + public virtual ICollection Attachments + { + get { return _attachments ?? (_attachments = new HashSet()); } + protected set { _attachments = value; } + } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs index 6f131b0a41..cd6d436139 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Media; namespace SmartStore.Core.Domain.Messages { diff --git a/src/Libraries/SmartStore.Core/Plugins/ILicensable.cs b/src/Libraries/SmartStore.Core/Plugins/ILicensable.cs deleted file mode 100644 index b2c4b60eb8..0000000000 --- a/src/Libraries/SmartStore.Core/Plugins/ILicensable.cs +++ /dev/null @@ -1,11 +0,0 @@ - -namespace SmartStore.Core.Plugins -{ - /// - /// Marks a plugin as a licensed piece of code where the user has to enter a license key that has to be activated. - /// Note that a license key is only valid for the IP address that activated the key. - /// - public interface ILicensable - { - } -} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index c1e2d2bae1..f4d3363c1d 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -158,6 +158,8 @@ + + diff --git a/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs b/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs new file mode 100644 index 0000000000..1ed9e206e3 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Mapping/Messages/QueuedEmailAttachmentMap.cs @@ -0,0 +1,29 @@ +using System.Data.Entity.ModelConfiguration; +using SmartStore.Core.Domain.Messages; + +namespace SmartStore.Data.Mapping.Messages +{ + public class QueuedEmailAttachmentMap : EntityTypeConfiguration + { + public QueuedEmailAttachmentMap() + { + this.ToTable("QueuedEmailAttachment"); + this.HasKey(x => x.Id); + + this.Property(x => x.Path).IsOptional().HasMaxLength(1000); + this.Property(x => x.Data).IsMaxLength(); + this.HasOptional(x => x.File) + .WithMany() + .HasForeignKey(x => x.FileId) + .WillCascadeOnDelete(true); + + this.Property(x => x.Name).IsRequired().HasMaxLength(200); + this.Property(x => x.MimeType).IsRequired().HasMaxLength(200); + + this.HasRequired(x => x.QueuedEmail) + .WithMany(qe => qe.Attachments) + .HasForeignKey(x => x.QueuedEmailId) + .WillCascadeOnDelete(true); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.Designer.cs new file mode 100644 index 0000000000..c4e3a3c11d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class QueuedEmailAttachments : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(QueuedEmailAttachments)); + + string IMigrationMetadata.Id + { + get { return "201507132241575_QueuedEmailAttachments"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.cs similarity index 98% rename from src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs rename to src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.cs index 225aaf9d43..cf40d1a76d 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506262044329_QueuedEmailAttachments.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.cs @@ -1,6 +1,5 @@ namespace SmartStore.Data.Migrations { - using System; using System.Data.Entity.Migrations; using SmartStore.Core.Domain.Tasks; using SmartStore.Data.Setup; @@ -26,7 +25,8 @@ public override void Up() .ForeignKey("dbo.Download", t => t.FileId, cascadeDelete: true) .ForeignKey("dbo.QueuedEmail", t => t.QueuedEmailId, cascadeDelete: true) .Index(t => t.QueuedEmailId) - .Index(t => t.FileId); + .Index(t => t.FileId); + } public override void Down() @@ -46,7 +46,7 @@ public bool RollbackOnFailure public void Seed(SmartObjectContext context) { context.MigrateLocaleResources(MigrateLocaleResources); - + context.Set().AddOrUpdate(x => x.Type, new ScheduleTask { @@ -61,7 +61,6 @@ public void Seed(SmartObjectContext context) context.SaveChanges(); } - public void MigrateLocaleResources(LocaleResourcesBuilder builder) { builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.AttachOrderPdfToOrderPlacedEmail", @@ -104,5 +103,5 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "order-{0}.pdf", "bestellung-{0}.pdf"); } - } + } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.resx b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.resx new file mode 100644 index 0000000000..4bcdc56bda --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 1d9b57ac77..4eefab19db 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -116,6 +116,7 @@ Properties\AssemblyVersionInfo.cs + @@ -289,6 +290,10 @@ 201506261756463_PrimaryStoreCurrencyMultiStore.cs + + + 201507132241575_QueuedEmailAttachments.cs + @@ -558,6 +563,9 @@ 201506261756463_PrimaryStoreCurrencyMultiStore.cs + + 201507132241575_QueuedEmailAttachments.cs + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs index 4e53971a04..ce28526e6d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/EmailAccountController.cs @@ -187,7 +187,9 @@ public ActionResult SendTestEmail(EmailAccountModel model) string subject = _storeContext.CurrentStore.Name + ". Testing email functionality."; string body = "Email works fine."; - _emailSender.SendEmail(new SmtpContext(emailAccount), new EmailMessage(to, subject, body, from)); + var msg = new EmailMessage(to, subject, body, from); + + _emailSender.SendEmail(new SmtpContext(emailAccount), msg); NotifySuccess(_localizationService.GetResource("Admin.Configuration.EmailAccounts.SendTestEmail.Success"), false); } From 043545159c6256929f6026897fec347015d47045 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 14 Jul 2015 12:04:53 +0200 Subject: [PATCH 0060/1074] Web-API: Added OData endpoint for payment method --- .../OData/PaymentMethodsController.cs | 35 ++++++++++++++++++ src/Plugins/SmartStore.WebApi/Description.txt | 2 +- .../SmartStore.WebApi.csproj | 1 + .../WebApiConfigurationProvider.cs | 3 ++ src/Plugins/SmartStore.WebApi/changelog.md | 36 ++++++++++--------- 5 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 src/Plugins/SmartStore.WebApi/Controllers/OData/PaymentMethodsController.cs diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/PaymentMethodsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/PaymentMethodsController.cs new file mode 100644 index 0000000000..ccc87cfad6 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/PaymentMethodsController.cs @@ -0,0 +1,35 @@ +using System.Web.Http; +using SmartStore.Core.Domain.Payments; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManagePaymentMethods")] + public class PaymentMethodsController : WebApiEntityController + { + protected override void Insert(PaymentMethod entity) + { + Service.InsertPaymentMethod(entity); + } + protected override void Update(PaymentMethod entity) + { + Service.UpdatePaymentMethod(entity); + } + protected override void Delete(PaymentMethod entity) + { + Service.DeletePaymentMethod(entity); + } + + [WebApiQueryable] + public SingleResult GetShippingMethod(int key) + { + return GetSingleResult(key); + } + + // navigation properties + + } +} diff --git a/src/Plugins/SmartStore.WebApi/Description.txt b/src/Plugins/SmartStore.WebApi/Description.txt index 53b6ca55d7..75af20211c 100644 --- a/src/Plugins/SmartStore.WebApi/Description.txt +++ b/src/Plugins/SmartStore.WebApi/Description.txt @@ -1,6 +1,6 @@ FriendlyName: SmartStore.NET Web Api SystemName: SmartStore.WebApi -Version: 2.2.0.2 +Version: 2.2.0.3 Group: Api MinAppVersion: 2.2.0 Author: SmartStore AG diff --git a/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj b/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj index 114a7f15ce..250694e7d7 100644 --- a/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj +++ b/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj @@ -204,6 +204,7 @@ + diff --git a/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs b/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs index 0c87fc0992..59d82d0e80 100644 --- a/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs +++ b/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs @@ -8,6 +8,7 @@ using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Seo; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Stores; @@ -72,6 +73,7 @@ public void Configure(WebApiConfigurationBroadcaster configData) m.EntitySet(WebApiOdataEntitySet.OrderNotes); m.EntitySet(WebApiOdataEntitySet.Orders); m.EntitySet(WebApiOdataEntitySet.OrderItems); + m.EntitySet(WebApiOdataEntitySet.PaymentMethods); m.EntitySet(WebApiOdataEntitySet.Pictures); m.EntitySet(WebApiOdataEntitySet.ProductAttributes); m.EntitySet(WebApiOdataEntitySet.ProductBundleItems); @@ -123,6 +125,7 @@ public static class WebApiOdataEntitySet public static string OrderNotes { get { return "OrderNotes"; } } public static string Orders { get { return "Orders"; } } public static string OrderItems { get { return "OrderItems"; } } + public static string PaymentMethods { get { return "PaymentMethods"; } } public static string Pictures { get { return "Pictures"; } } public static string ProductAttributes { get { return "ProductAttributes"; } } public static string ProductBundleItems { get { return "ProductBundleItems"; } } diff --git a/src/Plugins/SmartStore.WebApi/changelog.md b/src/Plugins/SmartStore.WebApi/changelog.md index 0ca6ad8919..f778ac4a79 100644 --- a/src/Plugins/SmartStore.WebApi/changelog.md +++ b/src/Plugins/SmartStore.WebApi/changelog.md @@ -1,32 +1,36 @@ -#Release Notes# +#Release Notes -##Web Api 2.2.0.2## -###Improvements### +##Web Api 2.2.0.3 +###New Features +* Added OData endpoint for payment method + +##Web Api 2.2.0.2 +###Improvements * WebApiAuthenticate attribute can be applied on methods too * Product image upload requires manage catalog permission -##Web Api 2.2.0.1## -###New Features### +##Web Api 2.2.0.1 +###New Features * #652 Support for file upload and multipart mime -##Web Api 1.32## -###New Features### +##Web Api 1.32 +###New Features * #618 Add endpoint for quantity units -##Web Api 1.31## -###Bugfixes### +##Web Api 1.31 +###Bugfixes * WebApiController requires more permission checks -##Web Api 1.23## -###New Features### +##Web Api 1.23 +###New Features * #431 Add support for localized properties -##Web Api 1.22## -###New Features### +##Web Api 1.22 +###New Features * #393 Implement OData actions for simpler working with product attributes -> added ProductsController.ManageAttributes and ProductsController.CreateAttributeCombinations. -##Web Api 1.21## -###Improvements### +##Web Api 1.21 +###Improvements * #384 Inserting sluged recources like products require an URL record -###Bugfixes### +###Bugfixes * PUT implementation was incomplete \ No newline at end of file From 0c37994babd7abe8bcf5b77d378dce841052d07d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 14 Jul 2015 12:23:45 +0200 Subject: [PATCH 0061/1074] Moved BuildQueryString extension method into core --- .../Extensions/EnumerableExtensions.cs | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs index cd3fe2ffd1..e588f20f6a 100644 --- a/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs @@ -1,10 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Collections; -using System.Linq; -using System.Linq.Expressions; using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Web; using SmartStore.Collections; namespace SmartStore @@ -186,6 +187,42 @@ public static void AddRange(this NameValueCollection initial, NameValueCollectio } } + /// + /// Builds an URL query string + /// + /// Namer value collection + /// Encoding type. Can be null. + /// Whether to encode keys and values + /// The query string without leading a question mark + public static string BuildQueryString(this NameValueCollection nvc, Encoding encoding, bool encode = true) + { + var sb = new StringBuilder(); + + foreach (string str in nvc) + { + if (sb.Length > 0) + sb.Append('&'); + + if (!encode) + sb.Append(str); + else if (encoding == null) + sb.Append(HttpUtility.UrlEncode(str)); + else + sb.Append(HttpUtility.UrlEncode(str, encoding)); + + sb.Append('='); + + if (!encode) + sb.Append(nvc[str]); + else if (encoding == null) + sb.Append(HttpUtility.UrlEncode(nvc[str])); + else + sb.Append(HttpUtility.UrlEncode(nvc[str], encoding)); + } + + return sb.ToString(); + } + #endregion #region AsSerializable From a900bd47412d34a54921976090d73d50054f0eb1 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 14 Jul 2015 13:38:00 +0200 Subject: [PATCH 0062/1074] Minor change --- src/Plugins/SmartStore.Shipping/Views/ByTotal/Configure.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/SmartStore.Shipping/Views/ByTotal/Configure.cshtml b/src/Plugins/SmartStore.Shipping/Views/ByTotal/Configure.cshtml index 779738d741..ae05d59b64 100644 --- a/src/Plugins/SmartStore.Shipping/Views/ByTotal/Configure.cshtml +++ b/src/Plugins/SmartStore.Shipping/Views/ByTotal/Configure.cshtml @@ -146,7 +146,7 @@ data: $(this.form).serialize(), dataType: 'json', success: function (data) { - alert('Saved'); + EventBroker.publish('message', { title: '@T("Admin.Common.DataEditSuccess")', type: 'success' }); }, error: function (xhr, ajaxOptions, thrownError) { alert('Failed to add record.'); From afc7e61c4ef4d60a5b496a14d639f8cfa5693752 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 14 Jul 2015 16:10:55 +0200 Subject: [PATCH 0063/1074] Resolves #727 Web-API: Option to deactivate TimestampOlderThanLastRequest validation --- .../SmartStore.WebApi/Localization/resources.de-de.xml | 6 ++++++ .../SmartStore.WebApi/Localization/resources.en-us.xml | 6 ++++++ .../SmartStore.WebApi/Models/WebApiConfigModel.cs | 5 +++++ .../SmartStore.WebApi/Views/WebApi/Configure.cshtml | 9 +++++++++ src/Plugins/SmartStore.WebApi/changelog.md | 5 ++++- .../WebApi/Caching/WebApiCachingControllingData.cs | 2 ++ .../WebApi/OData/WebApiQueryableAttribute.cs | 2 +- .../WebApi/Security/WebApiAuthenticateAttribute.cs | 8 ++++---- .../SmartStore.Web.Framework/WebApi/WebApiSettings.cs | 1 + 9 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/Plugins/SmartStore.WebApi/Localization/resources.de-de.xml b/src/Plugins/SmartStore.WebApi/Localization/resources.de-de.xml index 0159961db4..a7215f44e6 100644 --- a/src/Plugins/SmartStore.WebApi/Localization/resources.de-de.xml +++ b/src/Plugins/SmartStore.WebApi/Localization/resources.de-de.xml @@ -35,6 +35,12 @@ Jeder unauthorisierte Zugriff wird in der Ereignisliste gespeichert. + + Keine Zeitstempelprüfung + + + Legt fest, ob geprüft werden soll, ob der Zeitstempel der letzten Anfrage kleiner gleich der der aktuellen ist. Verhindert das Auftreten von HmacResult.TimestampOlderThanLastRequest. + Öffentlicher Schlüssel diff --git a/src/Plugins/SmartStore.WebApi/Localization/resources.en-us.xml b/src/Plugins/SmartStore.WebApi/Localization/resources.en-us.xml index 4b7f67b5bf..253bdb5938 100644 --- a/src/Plugins/SmartStore.WebApi/Localization/resources.en-us.xml +++ b/src/Plugins/SmartStore.WebApi/Localization/resources.en-us.xml @@ -35,6 +35,12 @@ Each unauthorized access will be saved in the log list. + + No timestamp validation + + + Specifies whether to validate that the timestamp of the previous request is less or equal than the one of the current. Prevents the occurrence of HmacResult.TimestampOlderThanLastRequest. + Public key diff --git a/src/Plugins/SmartStore.WebApi/Models/WebApiConfigModel.cs b/src/Plugins/SmartStore.WebApi/Models/WebApiConfigModel.cs index 0688b8f792..7dfb61fc69 100644 --- a/src/Plugins/SmartStore.WebApi/Models/WebApiConfigModel.cs +++ b/src/Plugins/SmartStore.WebApi/Models/WebApiConfigModel.cs @@ -15,6 +15,9 @@ public class WebApiConfigModel : ModelBase [SmartResourceDisplayName("Plugins.Api.WebApi.ValidMinutePeriod")] public int ValidMinutePeriod { get; set; } + [SmartResourceDisplayName("Plugins.Api.WebApi.NoRequestTimestampValidation")] + public bool NoRequestTimestampValidation { get; set; } + [SmartResourceDisplayName("Plugins.Api.WebApi.LogUnauthorized")] public bool LogUnauthorized { get; set; } @@ -25,11 +28,13 @@ public void Copy(WebApiSettings settings, bool fromSettings) if (fromSettings) { ValidMinutePeriod = settings.ValidMinutePeriod; + NoRequestTimestampValidation = settings.NoRequestTimestampValidation; LogUnauthorized = settings.LogUnauthorized; } else { settings.ValidMinutePeriod = ValidMinutePeriod; + settings.NoRequestTimestampValidation = NoRequestTimestampValidation; settings.LogUnauthorized = LogUnauthorized; } } diff --git a/src/Plugins/SmartStore.WebApi/Views/WebApi/Configure.cshtml b/src/Plugins/SmartStore.WebApi/Views/WebApi/Configure.cshtml index 222894529b..9e21e21993 100644 --- a/src/Plugins/SmartStore.WebApi/Views/WebApi/Configure.cshtml +++ b/src/Plugins/SmartStore.WebApi/Views/WebApi/Configure.cshtml @@ -98,6 +98,15 @@ @Html.ValidationMessageFor(model => model.ValidMinutePeriod) + + + @Html.SmartLabelFor(model => model.NoRequestTimestampValidation) + + + @Html.EditorFor(model => model.NoRequestTimestampValidation) + @Html.ValidationMessageFor(model => model.NoRequestTimestampValidation) + + @Html.SmartLabelFor(model => model.LogUnauthorized) diff --git a/src/Plugins/SmartStore.WebApi/changelog.md b/src/Plugins/SmartStore.WebApi/changelog.md index f778ac4a79..7d45bbd682 100644 --- a/src/Plugins/SmartStore.WebApi/changelog.md +++ b/src/Plugins/SmartStore.WebApi/changelog.md @@ -3,6 +3,9 @@ ##Web Api 2.2.0.3 ###New Features * Added OData endpoint for payment method +* #727 Option to deactivate TimestampOlderThanLastRequest validation +###Improvements +* Using header timestamp as last user request date rather than API server date ##Web Api 2.2.0.2 ###Improvements @@ -27,7 +30,7 @@ ##Web Api 1.22 ###New Features -* #393 Implement OData actions for simpler working with product attributes -> added ProductsController.ManageAttributes and ProductsController.CreateAttributeCombinations. +* #393 Implement OData actions for simpler working with product attributes -> added ProductsController.ManageAttributes and ProductsController.CreateAttributeCombinations ##Web Api 1.21 ###Improvements diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/Caching/WebApiCachingControllingData.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/Caching/WebApiCachingControllingData.cs index 0514ba29e0..d68ad50cef 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/Caching/WebApiCachingControllingData.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/Caching/WebApiCachingControllingData.cs @@ -38,6 +38,7 @@ public static WebApiControllingCacheData Data() data = new WebApiControllingCacheData { ValidMinutePeriod = settings.ValidMinutePeriod, + NoRequestTimestampValidation = settings.NoRequestTimestampValidation, LogUnauthorized = settings.LogUnauthorized, ApiUnavailable = (plugin == null || !plugin.Installed), PluginVersion = (plugin == null ? "1.0" : plugin.Version.ToString()) @@ -55,6 +56,7 @@ public partial class WebApiControllingCacheData { public bool ApiUnavailable { get; set; } public int ValidMinutePeriod { get; set; } + public bool NoRequestTimestampValidation { get; set; } public bool LogUnauthorized { get; set; } public string PluginVersion { get; set; } diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/OData/WebApiQueryableAttribute.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/OData/WebApiQueryableAttribute.cs index 91f968700d..f3487d624a 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/OData/WebApiQueryableAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/OData/WebApiQueryableAttribute.cs @@ -21,7 +21,7 @@ protected virtual bool MissingClientPaging(HttpActionExecutedContext actionExecu bool singleResult = (responseContent != null && responseContent.Value is SingleResult); if (singleResult) - return false; + return false; // 'true' would result in a 500 'internal server error' var query = actionExecutedContext.Request.RequestUri.Query; diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/Security/WebApiAuthenticateAttribute.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/Security/WebApiAuthenticateAttribute.cs index 5878b455f7..06f25a322e 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/Security/WebApiAuthenticateAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/Security/WebApiAuthenticateAttribute.cs @@ -74,7 +74,7 @@ protected virtual void LogUnauthorized(HttpActionContext actionContext, HmacResu string strResult = result.ToString(); string description = localization.GetResource("Admin.WebApi.AuthResult." + strResult, 0, false, strResult); - var logContext = new LogContext() + var logContext = new LogContext { ShortMessage = localization.GetResource("Admin.WebApi.UnauthorizedRequest").FormatWith(strResult), FullMessage = "{0}\r\n{1}".FormatWith(description, actionContext.Request.Headers.ToString()), @@ -146,10 +146,10 @@ protected virtual HmacResult IsAuthenticated(HttpActionContext actionContext, Da if (!apiUser.Enabled) return HmacResult.UserDisabled; - if (apiUser.LastRequest.HasValue && headDateTime <= apiUser.LastRequest.Value) + if (!cacheControllingData.NoRequestTimestampValidation && apiUser.LastRequest.HasValue && headDateTime <= apiUser.LastRequest.Value) return HmacResult.TimestampOlderThanLastRequest; - var context = new WebApiRequestContext() + var context = new WebApiRequestContext { HttpMethod = request.HttpMethod, HttpAcceptType = request.Headers["Accept"], @@ -183,7 +183,7 @@ protected virtual HmacResult IsAuthenticated(HttpActionContext actionContext, Da //var headers = HttpContext.Current.Response.Headers; //headers.Add(ApiHeaderName.LastRequest, apiUser.LastRequest.HasValue ? apiUser.LastRequest.Value.ToString("o") : ""); - apiUser.LastRequest = now; + apiUser.LastRequest = headDateTime; return HmacResult.Success; } diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiSettings.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiSettings.cs index 5436f564c7..1f2207d94f 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiSettings.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiSettings.cs @@ -6,5 +6,6 @@ public class WebApiSettings : ISettings { public int ValidMinutePeriod { get; set; } public bool LogUnauthorized { get; set; } + public bool NoRequestTimestampValidation { get; set; } } } From 02527a354c42422c0db43a67e51aa1538ded7363 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 14 Jul 2015 18:06:05 +0200 Subject: [PATCH 0064/1074] Shipping by weight calculates wrong surcharge if attribute combination prices are set --- changelog.md | 3 ++- .../SmartStore.Services/Catalog/PriceCalculationService.cs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index fafe3b82cf..f6523321a6 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,4 @@ -# Release Notes +# Release Notes ## SmartStore.NET 2.2.2 @@ -25,6 +25,7 @@ * #186 Mobile: variant images do not refresh * #671 Bundle products: display base price according to applied discount * Weight adjustment of attributes weren't applied in shopping cart overview +* Shipping by weight calculates wrong surcharge if attribute combination prices are set ## SmartStore.NET 2.2.1 diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index 4a7ea62463..4028e6026b 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -750,6 +750,8 @@ public virtual decimal GetUnitPrice(OrganizedShoppingCartItem shoppingCartItem, } else { + product.MergeWithCombination(shoppingCartItem.Item.AttributesXml, _productAttributeParser); + decimal attributesTotalPrice = decimal.Zero; var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml); From 0e81d9e8e581e70975c95da34aa74415918c1705 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 14 Jul 2015 18:49:49 +0200 Subject: [PATCH 0065/1074] Closes #646 Format the company information in message templates --- .../SmartStore.Services/Messages/MessageTokenProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs b/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs index c91c6cf510..f4a5c24050 100644 --- a/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs +++ b/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs @@ -554,7 +554,7 @@ protected virtual string GetSupplierIdentification() sb.AppendLine(""); sb.AppendLine(""); - sb.AppendLine(" diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/Index.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/Index.cshtml index 8ee7574be3..94fe748755 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/Index.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/Index.cshtml @@ -78,7 +78,7 @@ @Html.SmartLabelFor(model => model.BackgroundPictureId) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/_CreateOrUpdate.cshtml index e164727ae2..a518e17ef7 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ContentSlider/_CreateOrUpdate.cshtml @@ -109,7 +109,7 @@ @Html.SmartLabelFor(model => model.PictureId) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/_CreateOrUpdate.cshtml index 68163284cf..25db45dfe1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Manufacturer/_CreateOrUpdate.cshtml @@ -79,7 +79,7 @@ @Html.SmartLabelFor(model => model.PictureId) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/_CreateOrUpdate.cshtml index 7021397e30..a90e6cf18e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/MessageTemplate/_CreateOrUpdate.cshtml @@ -131,7 +131,7 @@ @Html.SmartLabelFor(model => model.Locales[item].Attachment1FileId) @@ -140,7 +140,7 @@ @Html.SmartLabelFor(model => model.Locales[item].Attachment2FileId) @@ -149,7 +149,7 @@ @Html.SmartLabelFor(model => model.Locales[item].Attachment3FileId) @@ -202,7 +202,7 @@ @Html.SmartLabelFor(model => model.Attachment1FileId) @@ -211,7 +211,7 @@ @Html.SmartLabelFor(model => model.Attachment2FileId) @@ -220,7 +220,7 @@ @Html.SmartLabelFor(model => model.Attachment3FileId) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/_CreateOrUpdate.Pictures.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/_CreateOrUpdate.Pictures.cshtml index 346b925d83..7c08977c2b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/_CreateOrUpdate.Pictures.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/_CreateOrUpdate.Pictures.cshtml @@ -78,7 +78,7 @@ @Html.SmartLabelFor(model => model.AddPictureModel.PictureId) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml index a10cd45bd9..84ac29f33b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/GeneralCommon.cshtml @@ -355,7 +355,7 @@ @Html.SmartLabelFor(model => model.PdfSettings.LogoPictureId) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download.cshtml index a3b33585b9..3e767879ca 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download.cshtml @@ -1,4 +1,4 @@ -@model int +@model int? @using SmartStore.Core; @using SmartStore.Web.Framework.UI; @using SmartStore.Utilities; @@ -8,7 +8,7 @@ var randomNumber = CommonHelper.GenerateRandomInteger(); var clientId = "download" + randomNumber; var downloadService = EngineContext.Current.Resolve(); - var download = downloadService.GetDownloadById(Model); + var download = downloadService.GetDownloadById(Model.GetValueOrDefault()); Html.AddScriptParts("~/bundles/fileupload"); Html.AddCssFileParts("~/css/fileupload"); @@ -174,7 +174,7 @@
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download2.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download2.cshtml new file mode 100644 index 0000000000..4e031002d0 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download2.cshtml @@ -0,0 +1,134 @@ +@model int? +@using SmartStore.Core; +@using SmartStore.Web.Framework.UI; +@using SmartStore.Utilities; + +@functions { + private bool MinimalMode + { + get + { + if (ViewData.ContainsKey("minimalMode")) + { + var x = ViewData["minimalMode"].Convert(); + return x; + } + return false; + } + } +} + +@{ + var randomNumber = CommonHelper.GenerateRandomInteger(); + var clientId = "download-editor-" + randomNumber; + var downloadService = EngineContext.Current.Resolve(); + var download = downloadService.GetDownloadById(Model.GetValueOrDefault()); + var initiallyShowUrlPanel = false; + var hasFile = false; + var downloadUrl = ""; + if (download != null) { + downloadUrl = Url.Action("DownloadFile", "Download", new { downloadId = download.Id }); + initiallyShowUrlPanel = !MinimalMode && download.UseDownloadUrl; + hasFile = !download.UseDownloadUrl; + } + + Html.AddScriptParts("~/bundles/fileupload"); + Html.AddCssFileParts("~/css/fileupload"); + Html.AddScriptParts(true, "~/Administration/Scripts/smartstore.download.js"); +} + + +
    + + @Html.HiddenFor(x => x, new { @class = "hidden" }) + + + @if (!MinimalMode) + { +
    +
    + + + + + +
    +
    + } + + +
    + + +
    + + + @if (hasFile) + { + + @download.Filename.Truncate(50, "...")@download.Extension + + } + + + + @if (hasFile) + { + + } + else + { + @T("Common.Fileuploader.Upload") + } + + + + + + +
    + +
    +
    +
    + +
     
    +
    +
    + + + @if (!MinimalMode) + { +
    +
    + @Html.TextBox("DownloadUrl", download != null ? download.DownloadUrl : "", new { style = "width: 330px" }) + +
    +
    + } + +
    +
    + + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Picture.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Picture.cshtml index d60f7b8d8a..e1641c7b18 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Picture.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Picture.cshtml @@ -2,6 +2,22 @@ @using SmartStore.Core; @using SmartStore.Web.Framework.UI; @using SmartStore.Utilities; + +@functions { + private bool TransientUpload + { + get + { + if (ViewData.ContainsKey("transientUpload")) + { + var x = ViewData["transientUpload"].Convert(); + return x; + } + return false; + } + } +} + @{ //other variables @@ -15,7 +31,7 @@ Html.AddCssFileParts("~/css/fileupload"); } -
    +
    @Html.HiddenFor(x => x, new { @class = "hidden"} ) @@ -59,7 +75,7 @@ elRemove = el.find('.remove'); $('#@clientId').fileupload({ - url: '@(Url.Content("~/Admin/Picture/AsyncUpload"))', + url: el.data('upload-url'), dataType: 'json', //acceptFileTypes: /^image\/(gif|jpeg|jpg|png)$/, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml index aac7dff4f0..11d1ce2f41 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Store/_CreateOrUpdate.cshtml @@ -27,7 +27,7 @@ @Html.SmartLabelFor(model => model.LogoPictureId)
    diff --git a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs index c070f2dd37..1dbdf48609 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs @@ -1349,7 +1349,7 @@ public ActionResult DownloadableProducts() null, null, null, true); foreach (var item in items) { - var itemModel = new CustomerDownloadableProductsModel.DownloadableProductsModel() + var itemModel = new CustomerDownloadableProductsModel.DownloadableProductsModel { OrderItemGuid = item.OrderItemGuid, OrderId = item.OrderId, @@ -1532,11 +1532,11 @@ public ActionResult UploadAvatar(CustomerAvatarModel model, HttpPostedFileBase u if (uploadedFile.ContentLength > avatarMaxSize) throw new SmartException(string.Format(_localizationService.GetResource("Account.Avatar.MaximumUploadedFileSize"), Prettifier.BytesToString(avatarMaxSize))); - byte[] customerPictureBinary = uploadedFile.GetPictureBits(); + byte[] customerPictureBinary = uploadedFile.InputStream.ToByteArray(); if (customerAvatar != null) customerAvatar = _pictureService.UpdatePicture(customerAvatar.Id, customerPictureBinary, uploadedFile.ContentType, null, true); else - customerAvatar = _pictureService.InsertPicture(customerPictureBinary, uploadedFile.ContentType, null, true); + customerAvatar = _pictureService.InsertPicture(customerPictureBinary, uploadedFile.ContentType, null, true, false); } int customerAvatarId = 0; diff --git a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs index 4a328185b2..604a4b8441 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs @@ -1084,11 +1084,11 @@ protected void ParseAndSaveCheckoutAttributes(List ca break; case AttributeControlType.FileUpload: { - var httpPostedFile = this.Request.Files[controlId]; - if ((httpPostedFile != null) && (!String.IsNullOrEmpty(httpPostedFile.FileName))) + var postedFile = this.Request.Files[controlId].ToPostedFileResult(); + if (postedFile != null && postedFile.FileName.HasValue()) { int fileMaxSize = _catalogSettings.FileUploadMaximumSizeBytes; - if (httpPostedFile.ContentLength > fileMaxSize) + if (postedFile.Size > fileMaxSize) { //TODO display warning //warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.MaximumUploadedFileSize"), (int)(fileMaxSize / 1024))); @@ -1096,21 +1096,20 @@ protected void ParseAndSaveCheckoutAttributes(List ca else { //save an uploaded file - var download = new Download() + var download = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = false, DownloadUrl = "", - DownloadBinary = httpPostedFile.GetDownloadBits(), - ContentType = httpPostedFile.ContentType, - Filename = System.IO.Path.GetFileNameWithoutExtension(httpPostedFile.FileName), - Extension = System.IO.Path.GetExtension(httpPostedFile.FileName), + DownloadBinary = postedFile.Buffer, + ContentType = postedFile.ContentType, + Filename = postedFile.FileTitle, + Extension = postedFile.FileExtension, IsNew = true }; _downloadService.InsertDownload(download); //save attribute - selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, - attribute, download.DownloadGuid.ToString()); + selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, attribute, download.DownloadGuid.ToString()); } } } @@ -1369,86 +1368,62 @@ public ActionResult UploadFileProductAttribute(int productId, int productAttribu { success = false, downloadGuid = Guid.Empty, - }, "text/plain"); + }); } - //ensure that this attribute belong to this product and has "file upload" type + + // ensure that this attribute belong to this product and has "file upload" type var pva = _productAttributeService .GetProductVariantAttributesByProductId(productId) .Where(pa => pa.ProductAttributeId == productAttributeId) .FirstOrDefault(); + if (pva == null || pva.AttributeControlType != AttributeControlType.FileUpload) { return Json(new { success = false, downloadGuid = Guid.Empty, - }, "text/plain"); - } - - //we process it distinct ways based on a browser - //find more info here http://stackoverflow.com/questions/4884920/mvc3-valums-ajax-file-upload - Stream stream = null; - var fileName = ""; - var contentType = ""; - if (String.IsNullOrEmpty(Request["qqfile"])) - { - // IE - HttpPostedFileBase httpPostedFile = Request.Files[0]; - if (httpPostedFile == null) - throw new ArgumentException("No file uploaded"); - stream = httpPostedFile.InputStream; - fileName = Path.GetFileName(httpPostedFile.FileName); - contentType = httpPostedFile.ContentType; - } - else - { - //Webkit, Mozilla - stream = Request.InputStream; - fileName = Request["qqfile"]; + }); } - var fileBinary = new byte[stream.Length]; - stream.Read(fileBinary, 0, fileBinary.Length); - - var fileExtension = Path.GetExtension(fileName); - if (!String.IsNullOrEmpty(fileExtension)) - fileExtension = fileExtension.ToLowerInvariant(); + var postedFile = Request.ToPostedFileResult(); + if (postedFile == null) + { + throw new ArgumentException("No file uploaded"); + } int fileMaxSize = _catalogSettings.FileUploadMaximumSizeBytes; - if (fileBinary.Length > fileMaxSize) + if (postedFile.Size > fileMaxSize) { - //when returning JSON the mime-type must be set to text/plain - //otherwise some browsers will pop-up a "Save As" dialog. return Json(new { success = false, message = string.Format(_localizationService.GetResource("ShoppingCart.MaximumUploadedFileSize"), (int)(fileMaxSize / 1024)), downloadGuid = Guid.Empty, - }, "text/plain"); + }); } - var download = new Download() + var download = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = false, DownloadUrl = "", - DownloadBinary = fileBinary, - ContentType = contentType, - //we store filename without extension for downloads - Filename = Path.GetFileNameWithoutExtension(fileName), - Extension = fileExtension, - IsNew = true + DownloadBinary = postedFile.Buffer, + ContentType = postedFile.ContentType, + // we store filename without extension for downloads + Filename = postedFile.FileTitle, + Extension = postedFile.FileExtension, + IsNew = true, + IsTransient = true }; _downloadService.InsertDownload(download); - //when returning JSON the mime-type must be set to text/plain - //otherwise some browsers will pop-up a "Save As" dialog. return Json(new { success = true, message = _localizationService.GetResource("ShoppingCart.FileUploaded"), downloadGuid = download.DownloadGuid, - }, "text/plain"); + }); } diff --git a/src/Presentation/SmartStore.Web/Extensions/ProductDetailsExtensions.cs b/src/Presentation/SmartStore.Web/Extensions/ProductDetailsExtensions.cs index 7b82ca9ec0..173ab96308 100644 --- a/src/Presentation/SmartStore.Web/Extensions/ProductDetailsExtensions.cs +++ b/src/Presentation/SmartStore.Web/Extensions/ProductDetailsExtensions.cs @@ -11,6 +11,7 @@ namespace SmartStore.Web { public static class ProductDetailsExtensions { + public static string UpdateProductDetailsUrl(this ProductDetailsModel model, string itemType = null) { var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext); @@ -24,10 +25,12 @@ public static string UpdateProductDetailsUrl(this ProductDetailsModel model, str return url; } + public static bool RenderBundleTitle(this ProductDetailsModel model) { return model.BundleTitleText.HasValue() && model.BundledItems.Where(x => x.BundleItem.Visible).Count() > 0; } + public static Picture GetAssignedPicture(this ProductDetailsModel model, IPictureService pictureService, IList pictures, int productId = 0) { if (model != null && model.CombinationSelected != null) @@ -51,6 +54,7 @@ public static Picture GetAssignedPicture(this ProductDetailsModel model, IPictur } return null; } + public static string GetAttributeValueInfo(this ProductDetailsModel.ProductVariantAttributeValueModel model) { string result = ""; @@ -77,6 +81,7 @@ public static bool ShouldBeRendered(this ProductDetailsModel.ProductVariantAttri return true; } } + public static bool ShouldBeRendered(this IEnumerable variantAttributes) { if (variantAttributes != null) diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs index cd7ddaf22c..e03c3d4e35 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs @@ -2525,32 +2525,36 @@ protected override void Alter(IList entities) { base.Alter(entities); - entities.WithKey(x => x.Name) - .Alter("Send emails", x => + entities.WithKey(x => x.Type) + .Alter("SmartStore.Services.Messages.QueuedMessagesSendTask, SmartStore.Services", x => { x.Name = "E-Mail senden"; }) - .Alter("Clear email queue", x => + .Alter("SmartStore.Services.Messages.QueuedMessagesClearTask, SmartStore.Services", x => { x.Name = "E-Mail Queue bereinigen"; }) - .Alter("Keep alive", x => + .Alter("SmartStore.Services.Media.TransientMediaClearTask, SmartStore.Services", x => + { + x.Name = "Temporäre Uploads bereinigen"; + }) + .Alter("SmartStore.Services.Common.KeepAliveTask, SmartStore.Services", x => { x.Name = "Keep alive"; }) - .Alter("Delete guests", x => + .Alter("SmartStore.Services.Customers.DeleteGuestsTask, SmartStore.Services", x => { x.Name = "Gastbenutzer löschen"; }) - .Alter("Clear cache", x => + .Alter("SmartStore.Services.Caching.ClearCacheTask, SmartStore.Services", x => { x.Name = "Cache bereinigen"; }) - .Alter("Send emails", x => + .Alter("SmartStore.Services.Messages.QueuedMessagesSendTask, SmartStore.Services", x => { x.Name = "E-Mail senden"; }) - .Alter("Update currency exchange rates", x => + .Alter("SmartStore.Services.Directory.UpdateExchangeRateTask, SmartStore.Services", x => { x.Name = "Wechselkurse aktualisieren"; }); diff --git a/src/Presentation/SmartStore.Web/Views/Product/_Attributes.cshtml b/src/Presentation/SmartStore.Web/Views/Product/_Attributes.cshtml index 0f43e97628..bbe0a418d2 100644 --- a/src/Presentation/SmartStore.Web/Views/Product/_Attributes.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Product/_Attributes.cshtml @@ -117,20 +117,20 @@ case AttributeControlType.Datepicker: { @Html.DatePickerDropDowns(controlId + "_day", controlId + "_month", controlId + "_year", attribute.BeginYear, attribute.EndYear, attribute.SelectedDay, attribute.SelectedMonth, attribute.SelectedYear, true, attribute.IsDisabled) - } - break; - case AttributeControlType.FileUpload: + } + break; + case AttributeControlType.FileUpload: { Html.AddScriptParts("~/bundles/fileupload"); Html.AddCssFileParts("~/css/fileupload"); - var random = CommonHelper.GenerateRandomInteger(); - var clientId = "upload" + CommonHelper.GenerateRandomInteger(); + var random = CommonHelper.GenerateRandomInteger(); + var clientId = "upload" + CommonHelper.GenerateRandomInteger(); + + //ex. ['jpg', 'jpeg', 'png', 'gif'] or [] + var allowedFileExtensions = string.Join("|", attribute.AllowedFileExtensions.Select(x => x.Trim()).ToList()); - //ex. ['jpg', 'jpeg', 'png', 'gif'] or [] - var allowedFileExtensions = string.Join("|", attribute.AllowedFileExtensions.Select(x => x.Trim()).ToList()); -
    diff --git a/src/Tests/SmartStore.Data.Tests/Catalog/ProductPersistenceTests.cs b/src/Tests/SmartStore.Data.Tests/Catalog/ProductPersistenceTests.cs index c19d9250ea..003fca1619 100644 --- a/src/Tests/SmartStore.Data.Tests/Catalog/ProductPersistenceTests.cs +++ b/src/Tests/SmartStore.Data.Tests/Catalog/ProductPersistenceTests.cs @@ -303,7 +303,7 @@ public void Can_save_and_load_product_with_productPictures() new ProductPicture { DisplayOrder = 1, - Picture = new Picture() + Picture = new Picture { PictureBinary = new byte[] { 1, 2, 3 }, MimeType = "image/pjpeg", From 7b4408c8340ffc53e54cae1252e4030d8ca135a2 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Wed, 15 Jul 2015 10:43:32 +0200 Subject: [PATCH 0067/1074] Closes #619 Display base price according to applied tier price --- changelog.md | 3 ++- .../SmartStore.Web/Controllers/CatalogHelper.cs | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index f6523321a6..118f77786d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,4 @@ -# Release Notes +# Release Notes ## SmartStore.NET 2.2.2 @@ -24,6 +24,7 @@ * #691 Product quantity not added to cart on mobile theme * #186 Mobile: variant images do not refresh * #671 Bundle products: display base price according to applied discount +* #619 Display base price according to applied tier price * Weight adjustment of attributes weren't applied in shopping cart overview * Shipping by weight calculates wrong surcharge if attribute combination prices are set diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index dceb88c312..bd9c4354af 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -842,9 +842,12 @@ public ProductDetailsModel PrepareProductDetailModel( model.ProductPrice.NoteWithoutDiscount = T(isBundle && product.BundlePerItemPricing ? "Products.Bundle.PriceWithoutDiscount.Note" : "Products.Price"); } - if (isBundle && product.BundlePerItemPricing && !string.IsNullOrWhiteSpace(model.ProductPrice.PriceWithDiscount)) + if ((isBundle && product.BundlePerItemPricing && !string.IsNullOrWhiteSpace(model.ProductPrice.PriceWithDiscount)) || product.HasTierPrices) { - model.ProductPrice.NoteWithDiscount = T("Products.Bundle.PriceWithDiscount.Note"); + if (!product.HasTierPrices) + { + model.ProductPrice.NoteWithDiscount = T("Products.Bundle.PriceWithDiscount.Note"); + } model.BasePriceInfo = product.GetBasePriceInfo(_localizationService, _priceFormatter, (product.Price - finalPriceWithDiscount) * (-1)); } } From 0a42324234a9d6daff8e967d1dbf0a96ad5fcfb3 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Wed, 15 Jul 2015 10:58:52 +0200 Subject: [PATCH 0068/1074] Closes #726 PAngV: basket displays wrong base price when attribute price adjustment has been set --- changelog.md | 1 + .../SmartStore.Web/Controllers/ShoppingCartController.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/changelog.md b/changelog.md index 118f77786d..9e22a2ad42 100644 --- a/changelog.md +++ b/changelog.md @@ -25,6 +25,7 @@ * #186 Mobile: variant images do not refresh * #671 Bundle products: display base price according to applied discount * #619 Display base price according to applied tier price +* #726 PAngV: basket displays wrong base price when attribute price adjustment has been set * Weight adjustment of attributes weren't applied in shopping cart overview * Shipping by weight calculates wrong surcharge if attribute combination prices are set diff --git a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs index ea2abd62de..cab4328a7b 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs @@ -367,6 +367,8 @@ private ShoppingCartModel.ShoppingCartItemModel PrepareShoppingCartItemModel(Org decimal shoppingCartItemDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemDiscountBase, _workContext.WorkingCurrency); model.Discount = _priceFormatter.FormatPrice(shoppingCartItemDiscount); } + + model.BasePrice = product.GetBasePriceInfo(_localizationService, _priceFormatter, (product.Price - shoppingCartItemSubTotalWithDiscount) * (-1)); } //picture From 29ce959915abeaed1a260356c462111195912bad Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Wed, 15 Jul 2015 11:50:46 +0200 Subject: [PATCH 0069/1074] Closes #521 Display bonus points in order export --- changelog.md | 1 + .../SmartStore.Services/ExportImport/ExportManager.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 9e22a2ad42..6bec688b1e 100644 --- a/changelog.md +++ b/changelog.md @@ -13,6 +13,7 @@ * #716 Supporting of paged google-product data query for SQL-Server Compact Edition * #648 Add hint for * at mandatory form fields at address creation * Added link to imprint and disclaimer to footer in mobile theme +* #521 Display bonus points in order export ### Bugfixes * #694 Product variant attribute in product page should not be preselected implicitly diff --git a/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs b/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs index 21cb3055a1..9a78698af3 100644 --- a/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs +++ b/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs @@ -1342,7 +1342,9 @@ public virtual string ExportOrdersToXml(IList orders) xmlWriter.WriteElementString("Deleted", null, order.Deleted.ToString()); xmlWriter.WriteElementString("CreatedOnUtc", null, order.CreatedOnUtc.ToString()); xmlWriter.WriteElementString("UpdatedOnUtc", null, order.UpdatedOnUtc.ToString()); - xmlWriter.WriteElementString("RewardPointsRemaining", null, order.RewardPointsRemaining.HasValue ? order.RewardPointsRemaining.Value.ToString() : ""); + xmlWriter.WriteElementString("RewardPointsUsed", null, order.RedeemedRewardPointsEntry.Points != 0 ? (order.RedeemedRewardPointsEntry.Points * (-1)).ToString() : ""); + var remainingRewardPoints = order.Customer.GetRewardPointsBalance(); + xmlWriter.WriteElementString("RewardPointsRemaining", null, remainingRewardPoints > 0 ? remainingRewardPoints.ToString() : ""); xmlWriter.WriteElementString("HasNewPaymentNotification", null, order.HasNewPaymentNotification.ToString()); //products @@ -1458,6 +1460,7 @@ public virtual void ExportOrdersToXlsx(Stream stream, IList orders) "VatNumber", "CreatedOnUtc", "UpdatedOnUtc", + "RewardPointsUsed", "RewardPointsRemaining", "HasNewPaymentNotification", //billing address @@ -1589,7 +1592,11 @@ public virtual void ExportOrdersToXlsx(Stream stream, IList orders) worksheet.Cells[row, col].Value = order.UpdatedOnUtc.ToOADate(); col++; - worksheet.Cells[row, col].Value = (order.RewardPointsRemaining.HasValue ? order.RewardPointsRemaining.Value.ToString() : ""); + worksheet.Cells[row, col].Value = (order.RedeemedRewardPointsEntry.Points != 0 ? (order.RedeemedRewardPointsEntry.Points * (-1)).ToString() : ""); + col++; + + var remainingRewardPoints = order.Customer.GetRewardPointsBalance(); + worksheet.Cells[row, col].Value = (remainingRewardPoints > 0 ? remainingRewardPoints.ToString() : ""); col++; worksheet.Cells[row, col].Value = order.HasNewPaymentNotification; From aa42f9ebba604d7aa6e4daee0301bbc4d1322ce3 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 15 Jul 2015 20:43:13 +0200 Subject: [PATCH 0070/1074] Minor fixes --- .../Migrations/201403112331027_Initial.cs | 14 +++++++------- .../201504131412183_NewCategoryProperties.cs | 2 +- ...61756463_PrimaryStoreCurrencyMultiStore.cs | 19 ++++++++++--------- .../Setup/IDbMigrationExtensions.cs | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201403112331027_Initial.cs b/src/Libraries/SmartStore.Data/Migrations/201403112331027_Initial.cs index 75a8e6b211..de838e8eca 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201403112331027_Initial.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201403112331027_Initial.cs @@ -1774,13 +1774,13 @@ public override void Up() #endregion #region Custom - - this.SqlFile("Indexes.sql"); + + this.SqlFileOrResource("Indexes.sql"); if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) { // do not execute in unit tests - this.SqlFile("Indexes.SqlServer.sql"); - this.SqlFile("StoredProcedures.sql"); + this.SqlFileOrResource("Indexes.SqlServer.sql"); + this.SqlFileOrResource("StoredProcedures.sql"); } #endregion @@ -1790,12 +1790,12 @@ public override void Down() { #region Custom - this.SqlFile("Indexes.Inverse.sql"); + this.SqlFileOrResource("Indexes.Inverse.sql"); if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) { // do not execute in unit tests - this.SqlFile("Indexes.SqlServer.Inverse.sql"); - this.SqlFile("StoredProcedures.Inverse.sql"); + this.SqlFileOrResource("Indexes.SqlServer.Inverse.sql"); + this.SqlFileOrResource("StoredProcedures.Inverse.sql"); } #endregion diff --git a/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.cs b/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.cs index 71f6b4076c..0ae7100ae6 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.cs @@ -18,7 +18,7 @@ public override void Up() if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) { - this.SqlFile("LatestProductLoadAllPaged.sql"); + this.SqlFileOrResource("LatestProductLoadAllPaged.sql"); } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index 1903182830..b7862fafd5 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -2,6 +2,7 @@ namespace SmartStore.Data.Migrations { using System.Data.Entity.Migrations; using System.Linq; + using System.Web.Hosting; using SmartStore.Core.Data; using SmartStore.Core.Domain.Configuration; using SmartStore.Core.Domain.Directory; @@ -16,7 +17,7 @@ public override void Up() AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int(nullable: false, defaultValue: 1)); // avoid conflicts with foreign key constraint - if (DataSettings.Current.IsSqlServer) + if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) { // what sql-server compact does not support here: // - Update Set with a select sub-query @@ -28,8 +29,8 @@ public override void Up() Sql("Update dbo.Store Set PrimaryExchangeRateCurrencyId = (Select Min(Id) From dbo.Currency)"); } - CreateIndex("dbo.Store", "PrimaryStoreCurrencyId"); - CreateIndex("dbo.Store", "PrimaryExchangeRateCurrencyId"); + CreateIndex("dbo.Store", "PrimaryStoreCurrencyId"); + CreateIndex("dbo.Store", "PrimaryExchangeRateCurrencyId"); AddForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency", "Id"); AddForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency", "Id"); @@ -37,14 +38,14 @@ public override void Up() public override void Down() { - DropForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency"); - DropForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency"); + DropForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency"); + DropForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency"); - DropIndex("dbo.Store", new[] { "PrimaryExchangeRateCurrencyId" }); - DropIndex("dbo.Store", new[] { "PrimaryStoreCurrencyId" }); + DropIndex("dbo.Store", new[] { "PrimaryExchangeRateCurrencyId" }); + DropIndex("dbo.Store", new[] { "PrimaryStoreCurrencyId" }); - DropColumn("dbo.Store", "PrimaryExchangeRateCurrencyId"); - DropColumn("dbo.Store", "PrimaryStoreCurrencyId"); + DropColumn("dbo.Store", "PrimaryExchangeRateCurrencyId"); + DropColumn("dbo.Store", "PrimaryStoreCurrencyId"); } public bool RollbackOnFailure diff --git a/src/Libraries/SmartStore.Data/Setup/IDbMigrationExtensions.cs b/src/Libraries/SmartStore.Data/Setup/IDbMigrationExtensions.cs index 70bebdd73d..44f470e318 100644 --- a/src/Libraries/SmartStore.Data/Setup/IDbMigrationExtensions.cs +++ b/src/Libraries/SmartStore.Data/Setup/IDbMigrationExtensions.cs @@ -16,7 +16,7 @@ namespace SmartStore.Data.Setup public static class IDbMigrationExtensions { - public static void SqlFile(this IDbMigration migration, string fileName, Assembly assembly = null, string location = null) + public static void SqlFileOrResource(this IDbMigration migration, string fileName, Assembly assembly = null, string location = null) { Guard.ArgumentNotEmpty(() => fileName); From cf4aa9387debc951c7e5dbd9513e7b0a980c32fb Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 15 Jul 2015 21:00:54 +0200 Subject: [PATCH 0071/1074] Updated EntityFramework to version 6.1.3 --- src/Libraries/SmartStore.Core/SmartStore.Core.csproj | 4 ++-- src/Libraries/SmartStore.Core/packages.config | 2 +- src/Libraries/SmartStore.Data/SmartStore.Data.csproj | 6 +++--- src/Libraries/SmartStore.Data/packages.config | 4 ++-- .../SmartStore.Services/SmartStore.Services.csproj | 7 ++++--- src/Libraries/SmartStore.Services/packages.config | 2 +- .../SmartStore.DevTools/SmartStore.DevTools.csproj | 12 ++++++------ src/Plugins/SmartStore.DevTools/packages.config | 2 +- .../SmartStore.GoogleMerchantCenter.csproj | 4 ++-- .../SmartStore.GoogleMerchantCenter/packages.config | 2 +- .../SmartStore.Shipping/SmartStore.Shipping.csproj | 4 ++-- src/Plugins/SmartStore.Shipping/packages.config | 2 +- .../SmartStore.ShippingByWeight.csproj | 6 ++---- .../SmartStore.ShippingByWeight/packages.config | 2 +- src/Plugins/SmartStore.Tax/SmartStore.Tax.csproj | 12 ++++++------ src/Plugins/SmartStore.Tax/packages.config | 2 +- .../SmartStore.Web.Framework.csproj | 4 ++-- .../SmartStore.Web.Framework/packages.config | 2 +- .../Administration/Controllers/ProductController.cs | 12 ++---------- .../SmartStore.Web/SmartStore.Web.csproj | 6 +++--- src/Presentation/SmartStore.Web/packages.config | 4 ++-- .../SmartStore.Data.Tests.csproj | 12 +++++++----- src/Tests/SmartStore.Data.Tests/packages.config | 4 ++-- 23 files changed, 55 insertions(+), 62 deletions(-) diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index f4d3363c1d..0ada459f9e 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -71,11 +71,11 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll False diff --git a/src/Libraries/SmartStore.Core/packages.config b/src/Libraries/SmartStore.Core/packages.config index 333eb7af85..923c1183a2 100644 --- a/src/Libraries/SmartStore.Core/packages.config +++ b/src/Libraries/SmartStore.Core/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 4eefab19db..5ccd723030 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -67,15 +67,15 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll False - ..\..\packages\EntityFramework.SqlServerCompact.6.1.0\lib\net45\EntityFramework.SqlServerCompact.dll + ..\..\packages\EntityFramework.SqlServerCompact.6.1.3\lib\net45\EntityFramework.SqlServerCompact.dll True diff --git a/src/Libraries/SmartStore.Data/packages.config b/src/Libraries/SmartStore.Data/packages.config index 14cad35b89..8ae4db4807 100644 --- a/src/Libraries/SmartStore.Data/packages.config +++ b/src/Libraries/SmartStore.Data/packages.config @@ -1,8 +1,8 @@  - - + + diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index a14d1bc8d7..5f6e45b404 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -67,10 +67,11 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll False diff --git a/src/Libraries/SmartStore.Services/packages.config b/src/Libraries/SmartStore.Services/packages.config index 1d9b39f80e..dfad9d51e6 100644 --- a/src/Libraries/SmartStore.Services/packages.config +++ b/src/Libraries/SmartStore.Services/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj index 7b08208219..5ad4a77279 100644 --- a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj +++ b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj @@ -80,13 +80,13 @@ ..\..\packages\Autofac.Mvc5.3.3.1\lib\net45\Autofac.Integration.Mvc.dll - - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll - False + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll - False + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll diff --git a/src/Plugins/SmartStore.DevTools/packages.config b/src/Plugins/SmartStore.DevTools/packages.config index 5fb210cfc1..8a4fe05ffb 100644 --- a/src/Plugins/SmartStore.DevTools/packages.config +++ b/src/Plugins/SmartStore.DevTools/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj index 8ad761ecef..a5e760e9b6 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj @@ -89,11 +89,11 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll ..\..\packages\FluentValidation.5.0.0.1\lib\Net40\FluentValidation.dll diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/packages.config b/src/Plugins/SmartStore.GoogleMerchantCenter/packages.config index 098fe232fa..769e9cee02 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/packages.config +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/Plugins/SmartStore.Shipping/SmartStore.Shipping.csproj b/src/Plugins/SmartStore.Shipping/SmartStore.Shipping.csproj index 59f1bdcdf0..3de6559bd2 100644 --- a/src/Plugins/SmartStore.Shipping/SmartStore.Shipping.csproj +++ b/src/Plugins/SmartStore.Shipping/SmartStore.Shipping.csproj @@ -89,11 +89,11 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll diff --git a/src/Plugins/SmartStore.Shipping/packages.config b/src/Plugins/SmartStore.Shipping/packages.config index 7605330a41..bbc22c8227 100644 --- a/src/Plugins/SmartStore.Shipping/packages.config +++ b/src/Plugins/SmartStore.Shipping/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/Plugins/SmartStore.ShippingByWeight/SmartStore.ShippingByWeight.csproj b/src/Plugins/SmartStore.ShippingByWeight/SmartStore.ShippingByWeight.csproj index 561149e08f..d3518bfcf0 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/SmartStore.ShippingByWeight.csproj +++ b/src/Plugins/SmartStore.ShippingByWeight/SmartStore.ShippingByWeight.csproj @@ -90,13 +90,11 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll - False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll - False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll diff --git a/src/Plugins/SmartStore.ShippingByWeight/packages.config b/src/Plugins/SmartStore.ShippingByWeight/packages.config index 7605330a41..bbc22c8227 100644 --- a/src/Plugins/SmartStore.ShippingByWeight/packages.config +++ b/src/Plugins/SmartStore.ShippingByWeight/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/Plugins/SmartStore.Tax/SmartStore.Tax.csproj b/src/Plugins/SmartStore.Tax/SmartStore.Tax.csproj index 4c9be02213..08e8670fa0 100644 --- a/src/Plugins/SmartStore.Tax/SmartStore.Tax.csproj +++ b/src/Plugins/SmartStore.Tax/SmartStore.Tax.csproj @@ -85,13 +85,13 @@ ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll False - - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll - False + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll - False + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll diff --git a/src/Plugins/SmartStore.Tax/packages.config b/src/Plugins/SmartStore.Tax/packages.config index fa6b3ec07d..bce2006cf4 100644 --- a/src/Plugins/SmartStore.Tax/packages.config +++ b/src/Plugins/SmartStore.Tax/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj index cd2f03fa0d..e839d52621 100644 --- a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj +++ b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj @@ -95,11 +95,11 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll False diff --git a/src/Presentation/SmartStore.Web.Framework/packages.config b/src/Presentation/SmartStore.Web.Framework/packages.config index 67afa8b56a..2f40cf1830 100644 --- a/src/Presentation/SmartStore.Web.Framework/packages.config +++ b/src/Presentation/SmartStore.Web.Framework/packages.config @@ -8,7 +8,7 @@ - + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index feb12bf6c3..4a8f624b92 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -686,16 +686,8 @@ protected void PrepareProductModel(ProductModel model, Product product, bool set if (product != null) { - var result = new StringBuilder(); - var tags = product.ProductTags.ToList(); - for (int i = 0; i < product.ProductTags.Count; i++) - { - var pt = tags[i]; - result.Append(pt.Name); - if (i != product.ProductTags.Count - 1) - result.Append(", "); - } - model.ProductTags = result.ToString(); + //var tags = product.ProductTags; + model.ProductTags = string.Join(", ", product.ProductTags.Select(x => x.Name)); } //tax categories diff --git a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj index e4db2c4359..1d93356ba2 100644 --- a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj +++ b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj @@ -96,15 +96,15 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll False - ..\..\packages\EntityFramework.SqlServerCompact.6.1.0\lib\net45\EntityFramework.SqlServerCompact.dll + ..\..\packages\EntityFramework.SqlServerCompact.6.1.3\lib\net45\EntityFramework.SqlServerCompact.dll False diff --git a/src/Presentation/SmartStore.Web/packages.config b/src/Presentation/SmartStore.Web/packages.config index 2c48e0cba2..777a775b2c 100644 --- a/src/Presentation/SmartStore.Web/packages.config +++ b/src/Presentation/SmartStore.Web/packages.config @@ -7,8 +7,8 @@ - - + + diff --git a/src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj b/src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj index 894a358733..528660817e 100644 --- a/src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj +++ b/src/Tests/SmartStore.Data.Tests/SmartStore.Data.Tests.csproj @@ -62,15 +62,17 @@ MinimumRecommendedRules.ruleset - - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll False - ..\..\packages\EntityFramework.SqlServerCompact.6.1.0\lib\net45\EntityFramework.SqlServerCompact.dll + ..\..\packages\EntityFramework.SqlServerCompact.6.1.3\lib\net45\EntityFramework.SqlServerCompact.dll False diff --git a/src/Tests/SmartStore.Data.Tests/packages.config b/src/Tests/SmartStore.Data.Tests/packages.config index 694797e037..a4f9326a28 100644 --- a/src/Tests/SmartStore.Data.Tests/packages.config +++ b/src/Tests/SmartStore.Data.Tests/packages.config @@ -1,7 +1,7 @@  - - + + \ No newline at end of file From 0961e3dbf2ccc1899901d8a1b1b6129e4784b707 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 16 Jul 2015 00:11:44 +0200 Subject: [PATCH 0072/1074] Implemented Entity Framework 2nd level cache for some unfrequently changed entities --- .../Caching/DefaultCacheManager.cs | 18 ++- .../SmartStore.Data/Caching/EfCacheImpl.cs | 118 ++++++++++++++++++ .../Caching/EfCachingPolicy.cs | 84 +++++++++++++ .../Setup/SeedData/InvariantSeedData.cs | 2 +- .../SmartStore.Data/SmartDbConfiguration.cs | 24 ++++ .../SmartStore.Data/SmartStore.Data.csproj | 6 + src/Libraries/SmartStore.Data/packages.config | 1 + .../Messages/QueuedEmailService.cs | 2 +- 8 files changed, 243 insertions(+), 12 deletions(-) create mode 100644 src/Libraries/SmartStore.Data/Caching/EfCacheImpl.cs create mode 100644 src/Libraries/SmartStore.Data/Caching/EfCachingPolicy.cs diff --git a/src/Libraries/SmartStore.Core/Caching/DefaultCacheManager.cs b/src/Libraries/SmartStore.Core/Caching/DefaultCacheManager.cs index bdf35da722..9ecc1425fa 100644 --- a/src/Libraries/SmartStore.Core/Caching/DefaultCacheManager.cs +++ b/src/Libraries/SmartStore.Core/Caching/DefaultCacheManager.cs @@ -34,21 +34,19 @@ public T Get(string key, Func acquirer, int? cacheTime = null) { return (T)_cache.Get(key); } - else + + using (EnterReadLock()) { - using (EnterReadLock()) + if (!_cache.Contains(key)) { - if (!_cache.Contains(key)) - { - var value = acquirer(); - this.Set(key, value, cacheTime); + var value = acquirer(); + this.Set(key, value, cacheTime); - return value; - } + return value; } - - return (T)_cache.Get(key); } + + return (T)_cache.Get(key); } public void Set(string key, object value, int? cacheTime = null) diff --git a/src/Libraries/SmartStore.Data/Caching/EfCacheImpl.cs b/src/Libraries/SmartStore.Data/Caching/EfCacheImpl.cs new file mode 100644 index 0000000000..e4b6debc8d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Caching/EfCacheImpl.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using SmartStore.Collections; +using SmartStore.Core.Caching; +using SmartStore.Utilities.Threading; + +namespace SmartStore.Data.Caching +{ + + internal class EfCacheImpl : EFCache.ICache + { + private const string KEYPREFIX = "EfCache__"; + private readonly Multimap _entitySetToKey = new Multimap(() => new HashSet()); + + private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); + private readonly ICache _cache; + + public EfCacheImpl(ICache innerCache) + { + this._cache = innerCache; + } + + public bool GetItem(string key, out object value) + { + value = null; + key = HashKey(key); + + if (_cache.Contains(key)) + { + value = _cache.Get(key); + return true; + } + + return false; + } + + public void PutItem(string key, object value, IEnumerable dependentEntitySets, TimeSpan slidingExpiration, DateTimeOffset absoluteExpiration) + { + key = HashKey(key); + + using (EnterWriteLock()) + { + var now = DateTimeOffset.Now; + var expiresInMinutes = Math.Max(1, Math.Min(int.MaxValue, (absoluteExpiration - now).TotalMinutes)); + _cache.Set(key, value, (int)expiresInMinutes); + + foreach (var s in dependentEntitySets) + { + _entitySetToKey[s].Add(key); + } + } + } + + public void InvalidateItem(string key) + { + key = HashKey(key); + + using (EnterWriteLock()) + { + _cache.Remove(key); + + foreach (var p in _entitySetToKey) + p.Value.Remove(key); + } + } + + public void InvalidateSets(IEnumerable entitySets) + { + var keysToRemove = new HashSet(); + + using (EnterWriteLock()) + { + foreach (var entitySet in entitySets) + { + if (_entitySetToKey.ContainsKey(entitySet)) + { + keysToRemove.AddRange(_entitySetToKey[entitySet]); + + } + } + + foreach (var k in keysToRemove) + _cache.Remove(k); + + foreach (var s in entitySets) + _entitySetToKey.RemoveAll(s); + } + } + + private static string HashKey(string key) + { + // Looking up large Keys can be expensive (comparing Large Strings), so if keys are large, hash them, otherwise if keys are short just use as-is + if (key.Length <= 128) + return KEYPREFIX + key; + + using (var sha = new SHA1CryptoServiceProvider()) + { + key = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(key))); + return KEYPREFIX + key; + } + } + + private IDisposable EnterReadLock() + { + return _rwLock.GetUpgradeableReadLock(); + } + + public IDisposable EnterWriteLock() + { + return _rwLock.GetWriteLock(); + } + + } +} diff --git a/src/Libraries/SmartStore.Data/Caching/EfCachingPolicy.cs b/src/Libraries/SmartStore.Data/Caching/EfCachingPolicy.cs new file mode 100644 index 0000000000..38f748f6d4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Caching/EfCachingPolicy.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data.Entity.Core.Metadata.Edm; +using System.Diagnostics; +using System.Linq; +using System.Text; +using EFCache; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Logging; +using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Security; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Domain.Themes; +using SmartStore.Core.Domain.Topics; + +namespace SmartStore.Data.Caching +{ + + /* TODO: (mc) + * ======================== + * 1. Let developers register custom caching policies for single entities (from plugins) + * 2. Caching policies should contain expiration info and cacheable rows count + * 3. Backend: Let users decide which entities to cache + * 4. Backend: Let users purge the cache + */ + + internal class EfCachingPolicy : CachingPolicy + { + private static readonly HashSet _cacheableSets = new HashSet + { + typeof(AclRecord).Name, + typeof(ActivityLogType).Name, + typeof(CategoryTemplate).Name, + typeof(CheckoutAttribute).Name, + typeof(CheckoutAttributeValue).Name, + typeof(Country).Name, + typeof(Currency).Name, + typeof(CustomerRole).Name, + typeof(DeliveryTime).Name, + typeof(Discount).Name, + typeof(DiscountRequirement).Name, + typeof(EmailAccount).Name, + typeof(Language).Name, + typeof(ManufacturerTemplate).Name, + typeof(MeasureDimension).Name, + typeof(MeasureWeight).Name, + typeof(MessageTemplate).Name, + typeof(PermissionRecord).Name, + typeof(ProductTemplate).Name, + typeof(QuantityUnit).Name, + typeof(StateProvince).Name, + typeof(Store).Name, + typeof(StoreMapping).Name, + typeof(TaxCategory).Name, + typeof(ThemeVariable).Name, + typeof(Topic).Name + }; + + protected override bool CanBeCached(ReadOnlyCollection affectedEntitySets, string sql, IEnumerable> parameters) + { + var entitySets = affectedEntitySets.Select(x => x.Name); + var result = entitySets.Any(x => _cacheableSets.Contains(x)); + return result; + } + + protected override void GetExpirationTimeout(ReadOnlyCollection affectedEntitySets, out TimeSpan slidingExpiration, out DateTimeOffset absoluteExpiration) + { + base.GetExpirationTimeout(affectedEntitySets, out slidingExpiration, out absoluteExpiration); + absoluteExpiration = DateTimeOffset.Now.AddHours(24); + } + + protected override void GetCacheableRows(ReadOnlyCollection affectedEntitySets, out int minCacheableRows, out int maxCacheableRows) + { + base.GetCacheableRows(affectedEntitySets, out minCacheableRows, out maxCacheableRows); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs index 3742c8b59e..8a1eb6ba78 100644 --- a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs +++ b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs @@ -4803,7 +4803,7 @@ public IList ScheduleTasks() new ScheduleTask { Name = "Clear cache", - Seconds = 600, + Seconds = 14400, // 4 hrs Type = "SmartStore.Services.Caching.ClearCacheTask, SmartStore.Services", Enabled = false, StopOnError = false, diff --git a/src/Libraries/SmartStore.Data/SmartDbConfiguration.cs b/src/Libraries/SmartStore.Data/SmartDbConfiguration.cs index 476f612085..f67db1a271 100644 --- a/src/Libraries/SmartStore.Data/SmartDbConfiguration.cs +++ b/src/Libraries/SmartStore.Data/SmartDbConfiguration.cs @@ -1,11 +1,15 @@ using System; using System.Collections.Generic; using System.Data.Entity; +using System.Data.Entity.Core.Common; using System.Data.Entity.Infrastructure; using System.Data.Entity.Infrastructure.DependencyResolution; using System.Linq; +using EFCache; using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; using SmartStore.Data.Setup; +using SmartStore.Data.Caching; namespace SmartStore.Data { @@ -24,6 +28,26 @@ public SmartDbConfiguration() if (provider != null) { base.SetDefaultConnectionFactory(provider.GetConnectionFactory()); + + // prepare EntityFramework 2nd level cache + ICache cache = null; + try + { + var innerCache = EngineContext.Current.Resolve>(); + cache = new EfCacheImpl(innerCache(typeof(SmartStore.Core.Caching.StaticCache))); + } + catch + { + cache = new InMemoryCache(); + } + + var transactionHandler = new CacheTransactionHandler(cache); + AddInterceptor(transactionHandler); + + Loaded += + (sender, args) => args.ReplaceService( + (s, _) => new CachingProviderServices(s, transactionHandler, + new EfCachingPolicy())); } } } diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 5ccd723030..a0525d3e01 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -65,6 +65,9 @@ ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll + + ..\..\packages\EntityFramework.Cache.1.0.0\lib\net45\EFCache.dll + False ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll @@ -115,6 +118,8 @@ Properties\AssemblyVersionInfo.cs + + @@ -584,6 +589,7 @@ + diff --git a/src/Libraries/SmartStore.Data/packages.config b/src/Libraries/SmartStore.Data/packages.config index 8ae4db4807..1101cadf32 100644 --- a/src/Libraries/SmartStore.Data/packages.config +++ b/src/Libraries/SmartStore.Data/packages.config @@ -2,6 +2,7 @@ + diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 68cf11d375..b03c247f39 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -95,7 +95,7 @@ public virtual IList GetQueuedEmailsByIds(int[] queuedEmailIds) if (queuedEmailIds == null || queuedEmailIds.Length == 0) return new List(); - var query = from qe in _queuedEmailRepository.Table.Expand(x => x.EmailAccount) + var query = from qe in _queuedEmailRepository.Table where queuedEmailIds.Contains(qe.Id) select qe; From ddd534318d05aedaa55b7bee64dfc8764ee2c49b Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 16 Jul 2015 12:44:03 +0200 Subject: [PATCH 0073/1074] Resolves #731 Web-Api: allow deletion of product category and manufacturer assignments --- changelog.md | 2 + .../Controllers/OData/ProductsController.cs | 81 ++++++++++++---- src/Plugins/SmartStore.WebApi/changelog.md | 1 + .../WebApi/WebApiCore.cs | 73 ++++++++------- .../WebApi/WebApiEntityController.cs | 92 ++++++++++++------- .../WebApi/WebApiExtension.cs | 18 ++++ 6 files changed, 183 insertions(+), 84 deletions(-) diff --git a/changelog.md b/changelog.md index fe27596550..69001129fd 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,8 @@ * #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" * #702 Facebook and Twitter external authentication suitable for multi-stores * #704 Make primary store currency suitable for multi-stores +* #727 Web-API: Option to deactivate TimestampOlderThanLastRequest validation +* #731 Web-API: Allow deletion and inserting of product category and manufacturer assignments ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs index e0a6d49da2..4e0e4044be 100644 --- a/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; +using System.Net.Http; using System.Web.Http; using System.Web.Http.OData; using SmartStore.Core; @@ -24,17 +26,23 @@ public class ProductsController : WebApiEntityController _priceCalculationService; private readonly Lazy _urlRecordService; private readonly Lazy _productAttributeService; + private readonly Lazy _categoryService; + private readonly Lazy _manufacturerService; public ProductsController( Lazy workContext, Lazy priceCalculationService, Lazy urlRecordService, - Lazy productAttributeService) + Lazy productAttributeService, + Lazy categoryService, + Lazy manufacturerService) { _workContext = workContext; _priceCalculationService = priceCalculationService; _urlRecordService = urlRecordService; _productAttributeService = productAttributeService; + _categoryService = categoryService; + _manufacturerService = manufacturerService; } protected override IQueryable GetEntitySet() @@ -79,6 +87,60 @@ public SingleResult GetProduct(int key) // navigation properties + public HttpResponseMessage NavigationProductCategories(int key, int relatedKey) + { + var productCategories = _categoryService.Value.GetProductCategoriesByProductId(key, true); + var productCategory = productCategories.FirstOrDefault(x => x.CategoryId == relatedKey); + + if (Request.Method == HttpMethod.Post) + { + if (productCategory == null) + { + productCategory = new ProductCategory { ProductId = key, CategoryId = relatedKey }; + + _categoryService.Value.InsertProductCategory(productCategory); + + return Request.CreateResponse(HttpStatusCode.Created, productCategory); + } + } + else if (Request.Method == HttpMethod.Delete) + { + if (productCategory != null) + _categoryService.Value.DeleteProductCategory(productCategory); + + return Request.CreateResponse(HttpStatusCode.NoContent); + } + + return Request.CreateResponseForEntity(productCategory, relatedKey); + } + + public HttpResponseMessage NavigationProductManufacturers(int key, int relatedKey) + { + var productManufacturers = _manufacturerService.Value.GetProductManufacturersByProductId(key, true); + var productManufacturer = productManufacturers.FirstOrDefault(x => x.ManufacturerId == relatedKey); + + if (Request.Method == HttpMethod.Post) + { + if (productManufacturer == null) + { + productManufacturer = new ProductManufacturer { ProductId = key, ManufacturerId = relatedKey }; + + _manufacturerService.Value.InsertProductManufacturer(productManufacturer); + + return Request.CreateResponse(HttpStatusCode.Created, productManufacturer); + } + } + else if (Request.Method == HttpMethod.Delete) + { + if (productManufacturer != null) + _manufacturerService.Value.DeleteProductManufacturer(productManufacturer); + + return Request.CreateResponse(HttpStatusCode.NoContent); + } + + return Request.CreateResponseForEntity(productManufacturer, relatedKey); + } + public DeliveryTime GetDeliveryTime(int key) { return GetExpandedProperty(key, x => x.DeliveryTime); @@ -345,22 +407,5 @@ public IQueryable ManageAttributes(int key, ODataAction return entity.ProductVariantAttributes.AsQueryable(); } - - - //[HttpGet, WebApiQueryable] - //public IQueryable GetRelatedProducts(int key) - //{ - // if (!ModelState.IsValid) - // throw this.ExceptionInvalidModelState(); - - // var repository = EngineContext.Current.Resolve>(); - - // var query = - // from x in repository.Table - // where x.ProductId1 == key - // select x; - - // return query; - //} } } diff --git a/src/Plugins/SmartStore.WebApi/changelog.md b/src/Plugins/SmartStore.WebApi/changelog.md index 7d45bbd682..6c5bd87808 100644 --- a/src/Plugins/SmartStore.WebApi/changelog.md +++ b/src/Plugins/SmartStore.WebApi/changelog.md @@ -4,6 +4,7 @@ ###New Features * Added OData endpoint for payment method * #727 Option to deactivate TimestampOlderThanLastRequest validation +* #731 Allow deletion and inserting of product category and manufacturer assignments ###Improvements * Using header timestamp as last user request date rather than API server date diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiCore.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiCore.cs index 3c2517732b..9f97de2d1b 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiCore.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiCore.cs @@ -1,40 +1,8 @@ using System.Text; +using Microsoft.Data.OData; namespace SmartStore.Web.Framework.WebApi { - public class WebApiRequestContext - { - public string PublicKey { get; set; } - public string SecretKey { get; set; } - - public string Url { get; set; } - public string HttpMethod { get; set; } - public string HttpAcceptType { get; set; } - - public bool IsValid - { - get - { - return - !string.IsNullOrWhiteSpace(PublicKey) && !string.IsNullOrWhiteSpace(SecretKey) && - !string.IsNullOrWhiteSpace(Url) && - !string.IsNullOrWhiteSpace(HttpMethod) && !string.IsNullOrWhiteSpace(HttpAcceptType); - } - } - public override string ToString() - { - var sb = new StringBuilder(); - - sb.AppendLine(string.Format("PublicKey: ", PublicKey)); - sb.AppendLine(string.Format("Url: ", Url)); - sb.AppendLine(string.Format("HttpMethod: ", HttpMethod)); - sb.AppendLine(string.Format("HttpAcceptType: ", HttpAcceptType)); - - return sb.ToString(); - } - } - - public static class WebApiGlobal { public static int MaxApiVersion { get { return 1; } } @@ -45,6 +13,8 @@ public static class WebApiGlobal public static string MostRecentOdataPath { get { return "odata/v1"; } } public static string PluginSystemName { get { return "SmartStore.WebApi"; } } + public static ODataVersion ODataVersion { get { return ODataVersion.V3; } } + /// see http://tools.ietf.org/html/rfc6648 public static class Header { @@ -72,7 +42,9 @@ public static class Error { public static string PropertyNotFound { get { return "Entity does not own property '{0}'."; } } public static string PropertyNotExpanded { get { return "Property path '{0}' cannot be expanded."; } } - public static string NoKeyFromPath { get { return "Cannot retrieve entity key from OData path."; } } + public static string NoKeyFromPath { get { return "Cannot retrieve valid entity key from OData path."; } } + public static string NoRelatedKeyFromPath { get { return "Cannot retrieve valid related entity key from OData path."; } } + public static string NoNavigationFromPath { get { return "Cannot retrieve the navigation property from OData path."; } } public static string EntityNotFound { get { return "Entity with key '{0}' could not be found."; } } public static string NoDataToInsert { get { return "No data to be inserted."; } } } @@ -82,4 +54,37 @@ public static class QueryOption public static string Fulfill { get { return "SmNetFulfill"; } } } } + + + public class WebApiRequestContext + { + public string PublicKey { get; set; } + public string SecretKey { get; set; } + + public string Url { get; set; } + public string HttpMethod { get; set; } + public string HttpAcceptType { get; set; } + + public bool IsValid + { + get + { + return + !string.IsNullOrWhiteSpace(PublicKey) && !string.IsNullOrWhiteSpace(SecretKey) && + !string.IsNullOrWhiteSpace(Url) && + !string.IsNullOrWhiteSpace(HttpMethod) && !string.IsNullOrWhiteSpace(HttpAcceptType); + } + } + public override string ToString() + { + var sb = new StringBuilder(); + + sb.AppendLine(string.Format("PublicKey: ", PublicKey)); + sb.AppendLine(string.Format("Url: ", Url)); + sb.AppendLine(string.Format("HttpMethod: ", HttpMethod)); + sb.AppendLine(string.Format("HttpAcceptType: ", HttpAcceptType)); + + return sb.ToString(); + } + } } diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs index 039d981db0..370b667b19 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiEntityController.cs @@ -1,19 +1,19 @@ -using SmartStore.Core; -using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Directory; -using SmartStore.Services.Localization; -using System; +using System; +using System.Data.Entity.Core.Metadata.Edm; +using System.Data.Entity.Infrastructure; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.Http; +using System.Reflection; using System.Web.Http; using System.Web.Http.OData; using System.Web.Http.OData.Routing; -using System.Reflection; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Core.Metadata.Edm; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; +using SmartStore.Services.Directory; +using SmartStore.Services.Localization; namespace SmartStore.Web.Framework.WebApi { @@ -24,7 +24,7 @@ public abstract class WebApiEntityController : EntitySetContr protected internal HttpResponseException ExceptionEntityNotFound(TKey key) { var response = Request.CreateErrorResponse(HttpStatusCode.NotFound, - WebApiGlobal.Error.EntityNotFound.FormatWith(key)); + WebApiGlobal.Error.EntityNotFound.FormatInvariant(key)); return new HttpResponseException(response); } @@ -33,22 +33,32 @@ protected internal HttpResponseException ExceptionNotExpanded(Express { // NotFound cause of nullable properties var response = Request.CreateErrorResponse(HttpStatusCode.NotFound, - WebApiGlobal.Error.PropertyNotExpanded.FormatWith(path.ToString())); + WebApiGlobal.Error.PropertyNotExpanded.FormatInvariant(path.ToString())); return new HttpResponseException(response); } public override HttpResponseMessage HandleUnmappedRequest(ODataPath odataPath) { - if (Request.Method == HttpMethod.Get || Request.Method == HttpMethod.Post) + if (odataPath.PathTemplate.IsCaseInsensitiveEqual("~/entityset/key/property") || + odataPath.PathTemplate.IsCaseInsensitiveEqual("~/entityset/key/cast/property") || + odataPath.PathTemplate.IsCaseInsensitiveEqual("~/entityset/key/unresolved")) { - if (odataPath.PathTemplate.IsCaseInsensitiveEqual("~/entityset/key/property") || - odataPath.PathTemplate.IsCaseInsensitiveEqual("~/entityset/key/cast/property") || - odataPath.PathTemplate.IsCaseInsensitiveEqual("~/entityset/key/unresolved")) + if (Request.Method == HttpMethod.Get || Request.Method == HttpMethod.Post) { return UnmappedGetProperty(odataPath); } } + else if (odataPath.PathTemplate.IsCaseInsensitiveEqual("~/entityset/key/navigation/key")) + { + if (Request.Method == HttpMethod.Get || Request.Method == HttpMethod.Post || Request.Method == HttpMethod.Delete) + { + // we ignore standard odata path cause they differ: + // ~/entityset/key/$links/navigation (odata 3 "link"), ~/entityset/key/navigation/$ref (odata 4 "reference") + + return UnmappedGetNavigation(odataPath); + } + } return base.HandleUnmappedRequest(odataPath); } @@ -63,7 +73,7 @@ protected virtual internal HttpResponseMessage UnmappedGetProperty(ODataPath oda var entity = GetEntityByKey(key); if (entity == null) - return Request.CreateErrorResponse(HttpStatusCode.NotFound, WebApiGlobal.Error.EntityNotFound.FormatWith(key)); + return Request.CreateErrorResponse(HttpStatusCode.NotFound, WebApiGlobal.Error.EntityNotFound.FormatInvariant(key)); PropertyInfo pi = null; string propertyName = null; @@ -88,7 +98,40 @@ protected virtual internal HttpResponseMessage UnmappedGetProperty(ODataPath oda protected virtual internal HttpResponseMessage UnmappedGetProperty(TEntity entity, string propertyName) { - return Request.CreateErrorResponse(HttpStatusCode.BadRequest, WebApiGlobal.Error.PropertyNotFound.FormatWith(propertyName)); + return Request.CreateErrorResponse(HttpStatusCode.BadRequest, WebApiGlobal.Error.PropertyNotFound.FormatInvariant(propertyName)); + } + + protected virtual internal HttpResponseMessage UnmappedGetNavigation(ODataPath odataPath) + { + int key, relatedKey; + + if (!odataPath.GetNormalizedKey(1, out key)) + return Request.CreateErrorResponse(HttpStatusCode.BadRequest, WebApiGlobal.Error.NoKeyFromPath); + + var navigationProperty = odataPath.GetNavigation(2); + + if (navigationProperty.IsEmpty()) + return Request.CreateErrorResponse(HttpStatusCode.BadRequest, WebApiGlobal.Error.NoNavigationFromPath); + + if (!odataPath.GetNormalizedKey(3, out relatedKey)) + return Request.CreateErrorResponse(HttpStatusCode.BadRequest, WebApiGlobal.Error.NoRelatedKeyFromPath); + + var methodName = string.Concat("Navigation", navigationProperty); + var methodInfo = this.GetType().GetMethods().FirstOrDefault(x => x.Name == methodName); + + if (methodInfo != null) + { + HttpResponseMessage response = null; + + this.ProcessEntity(() => + { + response = (HttpResponseMessage)methodInfo.Invoke(this, new object[] { key, relatedKey }); + return null; + }); + + return response; + } + return base.HandleUnmappedRequest(odataPath); } //protected virtual IRepository CreateRepository() @@ -378,20 +421,5 @@ protected internal virtual TEntity FulfillPropertiesOn(TEntity entity) } return entity; } - - //protected internal IQueryable GenericAttributes(int key, string keyGroup) - //{ - // if (!ModelState.IsValid) - // throw this.ExceptionInvalidModelState(); - - // var repository = EngineContext.Current.Resolve>(); - - // var query = - // from x in repository.Table - // where x.EntityId == key && x.KeyGroup == keyGroup && x.Key != WebApiUserCacheData.Key - // select x; - - // return query; - //} } } diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiExtension.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiExtension.cs index 28f430b974..9051894b20 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiExtension.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiExtension.cs @@ -25,6 +25,13 @@ public static HttpResponseMessage CreateResponse(this HttpRequestMessage request { return _createResponse.MakeGenericMethod(type).Invoke(null, new[] { request, status, value }) as HttpResponseMessage; } + public static HttpResponseMessage CreateResponseForEntity(this HttpRequestMessage request, object entity, int key) + { + if (entity == null) + return request.CreateResponse(HttpStatusCode.NotFound, WebApiGlobal.Error.EntityNotFound.FormatInvariant(key)); + + return request.CreateResponse(HttpStatusCode.OK, entity.GetType(), entity); + } public static HttpResponseException ExceptionInvalidModelState(this ApiController apiController) { @@ -98,6 +105,17 @@ public static bool GetNormalizedKey(this ODataPath odataPath, int segmentIndex, return false; } + public static string GetNavigation(this ODataPath odataPath, int segmentIndex) + { + if (odataPath.Segments.Count > segmentIndex) + { + string navigationProperty = (odataPath.Segments[segmentIndex] as NavigationPathSegment).NavigationPropertyName; + + return navigationProperty; + } + return null; + } + public static void DeleteLocalFiles(this MultipartFormDataStreamProvider provider) { try From e45963b8c02b2afc235b938e51e507b883dfa0e1 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 16 Jul 2015 13:19:08 +0200 Subject: [PATCH 0074/1074] Removed odd extension method --- .../Catalog/ManufacturerExtensions.cs | 29 ------------------- .../SmartStore.Services.csproj | 1 - .../Controllers/ManufacturerController.cs | 18 ++++++------ 3 files changed, 9 insertions(+), 39 deletions(-) delete mode 100644 src/Libraries/SmartStore.Services/Catalog/ManufacturerExtensions.cs diff --git a/src/Libraries/SmartStore.Services/Catalog/ManufacturerExtensions.cs b/src/Libraries/SmartStore.Services/Catalog/ManufacturerExtensions.cs deleted file mode 100644 index 9d29a61c29..0000000000 --- a/src/Libraries/SmartStore.Services/Catalog/ManufacturerExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using SmartStore.Core.Domain.Catalog; - -namespace SmartStore.Services.Catalog -{ - /// - /// Extensions - /// - public static class ManufacturerExtensions - { - /// - /// Returns a ProductManufacturer that has the specified values - /// - /// Source - /// Product identifier - /// Manufacturer identifier - /// A ProductManufacturer that has the specified values; otherwise null - public static ProductManufacturer FindProductManufacturer(this IList source, - int productId, int manufacturerId) - { - foreach (var productManufacturer in source) - if (productManufacturer.ProductId == productId && productManufacturer.ManufacturerId == manufacturerId) - return productManufacturer; - - return null; - } - - } -} diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 5f6e45b404..226ed5fa15 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -210,7 +210,6 @@ - diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs index 178d046379..9160edaad3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs @@ -641,16 +641,16 @@ public ActionResult ProductAddPopup(string btnId, string formId, ManufacturerMod if (product != null) { var existingProductmanufacturers = _manufacturerService.GetProductManufacturersByManufacturerId(model.ManufacturerId, 0, int.MaxValue, true); - if (existingProductmanufacturers.FindProductManufacturer(id, model.ManufacturerId) == null) + + if (!existingProductmanufacturers.Any(x => x.ProductId == id && x.ManufacturerId == model.ManufacturerId)) { - _manufacturerService.InsertProductManufacturer( - new ProductManufacturer() - { - ManufacturerId = model.ManufacturerId, - ProductId = id, - IsFeaturedProduct = false, - DisplayOrder = 1 - }); + _manufacturerService.InsertProductManufacturer(new ProductManufacturer + { + ManufacturerId = model.ManufacturerId, + ProductId = id, + IsFeaturedProduct = false, + DisplayOrder = 1 + }); } } } From d617a32d81a23d37a5dcce13dea63077b2100e6d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 16 Jul 2015 14:14:09 +0200 Subject: [PATCH 0075/1074] Price tab threw an exception. Looks like it's not a good idea to use ICommonServices.Cache in a service class. --- ...61756463_PrimaryStoreCurrencyMultiStore.cs | 6 +++ .../Catalog/ProductService.cs | 16 ++++--- .../Controllers/ProductController.cs | 45 ++++++++++++------- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index b7862fafd5..e61acfd677 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -144,6 +144,12 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies the maximum news age in days. Older blog posts are not exported in the RSS feed.", "Legt das maximale Blog-Alter in Tagen fest. ltere Blog-Eintrge werden im RSS-Feed nicht exportiert."); + + builder.AddOrUpdate("Admin.Common.Deleted", + "Deleted", + "Gelscht"); + + builder.Delete("Admin.Configuration.Currencies.CantDeletePrimary"); builder.Delete("Admin.Configuration.Currencies.CantDeleteExchange"); builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryStoreCurrency"); diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs index 5618ba86ad..8dc0d5f73c 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs @@ -6,6 +6,7 @@ using System.ServiceModel.Syndication; using System.Web.Mvc; using SmartStore.Core; +using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; @@ -55,6 +56,7 @@ public partial class ProductService : IProductService private readonly IWorkflowMessageService _workflowMessageService; private readonly IDataProvider _dataProvider; private readonly IDbContext _dbContext; + private readonly ICacheManager _cacheManager; private readonly LocalizationSettings _localizationSettings; private readonly CommonSettings _commonSettings; private readonly ICommonServices _services; @@ -108,6 +110,7 @@ public ProductService( IWorkflowMessageService workflowMessageService, IDataProvider dataProvider, IDbContext dbContext, + ICacheManager cacheManager, LocalizationSettings localizationSettings, CommonSettings commonSettings, ICommonServices services, @@ -132,6 +135,7 @@ public ProductService( this._workflowMessageService = workflowMessageService; this._dataProvider = dataProvider; this._dbContext = dbContext; + this._cacheManager = cacheManager; this._localizationSettings = localizationSettings; this._commonSettings = commonSettings; this._services = services; @@ -272,7 +276,7 @@ public virtual Product GetProductById(int productId) return null; string key = string.Format(PRODUCTS_BY_ID_KEY, productId); - return _services.Cache.Get(key, () => + return _cacheManager.Get(key, () => { return _productRepository.GetById(productId); }); @@ -314,7 +318,7 @@ public virtual void InsertProduct(Product product) _productRepository.Insert(product); //clear cache - _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification _services.EventPublisher.EntityInserted(product); @@ -339,7 +343,7 @@ public virtual void UpdateProduct(Product product, bool publishEvent = true) _productRepository.Update(product); // cache - _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); // event notification if (publishEvent && modified) @@ -1588,7 +1592,7 @@ public virtual void DeleteTierPrice(TierPrice tierPrice) _tierPriceRepository.Delete(tierPrice); - _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification _services.EventPublisher.EntityDeleted(tierPrice); @@ -1619,7 +1623,7 @@ public virtual void InsertTierPrice(TierPrice tierPrice) _tierPriceRepository.Insert(tierPrice); - _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification _services.EventPublisher.EntityInserted(tierPrice); @@ -1636,7 +1640,7 @@ public virtual void UpdateTierPrice(TierPrice tierPrice) _tierPriceRepository.Update(tierPrice); - _services.Cache.RemoveByPattern(PRODUCTS_PATTERN_KEY); + _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification _services.EventPublisher.EntityUpdated(tierPrice); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 4a8f624b92..efd7a9f60c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -3394,34 +3394,49 @@ public ActionResult TierPriceList(GridCommand command, int productId) if (product == null) throw new ArgumentException("No product variant found with the specified id"); + var allStores = _services.StoreService.GetAllStores(); + var allCustomerRoles = _customerService.GetAllCustomerRoles(true); + string allRolesString = T("Admin.Catalog.Products.TierPrices.Fields.CustomerRole.AllRoles"); + string allStoresString = T("Admin.Common.StoresAll"); + string deletedString = "[{0}]".FormatInvariant(T("Admin.Common.Deleted")); + var tierPricesModel = product.TierPrices .OrderBy(x => x.StoreId) .ThenBy(x => x.Quantity) .ThenBy(x => x.CustomerRoleId) .Select(x => { - var storeName = ""; - if (x.StoreId > 0) - { - var store = _storeService.GetStoreById(x.StoreId); - storeName = store != null ? store.Name : "[Deleted]"; - } - else - { - storeName = _localizationService.GetResource("Admin.Common.StoresAll"); - } - return new ProductModel.TierPriceModel() + var tierPriceModel = new ProductModel.TierPriceModel { Id = x.Id, StoreId = x.StoreId, - Store = storeName, - CustomerRole = x.CustomerRoleId.HasValue ? _customerService.GetCustomerRoleById(x.CustomerRoleId.Value).Name : - _localizationService.GetResource("Admin.Catalog.Products.TierPrices.Fields.CustomerRole.AllRoles"), ProductId = x.ProductId, - CustomerRoleId = x.CustomerRoleId.HasValue ? x.CustomerRoleId.Value : 0, + CustomerRoleId = x.CustomerRoleId ?? 0, Quantity = x.Quantity, Price1 = x.Price }; + + if (x.CustomerRoleId.HasValue) + { + var role = allCustomerRoles.FirstOrDefault(r => r.Id == x.CustomerRoleId.Value); + tierPriceModel.CustomerRole = (role == null ? allRolesString : role.Name); + } + else + { + tierPriceModel.CustomerRole = allRolesString; + } + + if (x.StoreId > 0) + { + var store = allStores.FirstOrDefault(s => s.Id == x.StoreId); + tierPriceModel.Store = (store == null ? deletedString : store.Name); + } + else + { + tierPriceModel.Store = allStoresString; + } + + return tierPriceModel; }) .ToList(); From 83c8a71b42d98b156b8476ab84c92c6c618249ee Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 16 Jul 2015 18:00:02 +0200 Subject: [PATCH 0076/1074] The ProductOverviewModel does not require a Product.FullDescription --- src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs | 1 - src/Presentation/SmartStore.Web/Controllers/HomeController.cs | 1 - .../SmartStore.Web/Models/Catalog/ProductOverviewModel.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index 3049beedef..4ee0f016c0 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -1015,7 +1015,6 @@ public IEnumerable PrepareProductOverviewModels( Id = product.Id, Name = product.GetLocalized(x => x.Name).EmptyNull(), ShortDescription = product.GetLocalized(x => x.ShortDescription), - FullDescription = product.GetLocalized(x => x.FullDescription), SeName = product.GetSeName() }; diff --git a/src/Presentation/SmartStore.Web/Controllers/HomeController.cs b/src/Presentation/SmartStore.Web/Controllers/HomeController.cs index 8c1f8fc125..6b65cfaf2d 100644 --- a/src/Presentation/SmartStore.Web/Controllers/HomeController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/HomeController.cs @@ -248,7 +248,6 @@ public ActionResult Sitemap() Id = product.Id, Name = product.GetLocalized(x => x.Name).EmptyNull(), ShortDescription = product.GetLocalized(x => x.ShortDescription), - FullDescription = product.GetLocalized(x => x.FullDescription), SeName = product.GetSeName(), }).ToList(); } diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductOverviewModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductOverviewModel.cs index eb39ca78ee..5561ae3617 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductOverviewModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductOverviewModel.cs @@ -22,7 +22,6 @@ public ProductOverviewModel() public string Name { get; set; } public string ShortDescription { get; set; } - public string FullDescription { get; set; } public string SeName { get; set; } public int ThumbDimension { get; set; } From a94b15221d0684c296fecdc42578179c23aab44e Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 16 Jul 2015 18:36:59 +0200 Subject: [PATCH 0077/1074] GetLowestPrice: Not necessary to fetch the lowest (non-zero) combination price from database. Product.LowestAttributeCombinationPrice sufficient. --- .../SmartStore.Services/Catalog/PriceCalculationService.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index e28b08d053..b254da8051 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -478,11 +478,7 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa if (lowestPrice == decimal.Zero && product.Price == decimal.Zero) { - var combination = product.ProductVariantAttributeCombinations.OrderBy(x => x.Price).FirstOrDefault(x => x.Price > decimal.Zero); - if (combination != null) - { - lowestPrice = combination.Price ?? decimal.Zero; - } + lowestPrice = product.LowestAttributeCombinationPrice ?? decimal.Zero; } return lowestPrice; From 6965a6a36b0d14b1185efa56dc79942a8a106936 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 16 Jul 2015 21:01:56 +0200 Subject: [PATCH 0078/1074] UI: optimized image gallery (white background & nicer animations) + enhanced modal dialog fade animations --- .../Content/bootstrap/custom/custom.less | 69 ++++++---------- .../css/blueimp-gallery-custom.css | 80 +++++++++++++++++-- .../Scripts/public.product-detail.js | 2 +- .../Scripts/smartstore.smartgallery.js | 22 +++-- 4 files changed, 116 insertions(+), 57 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Content/bootstrap/custom/custom.less b/src/Presentation/SmartStore.Web/Content/bootstrap/custom/custom.less index 4100e82a92..6ca430239d 100644 --- a/src/Presentation/SmartStore.Web/Content/bootstrap/custom/custom.less +++ b/src/Presentation/SmartStore.Web/Content/bootstrap/custom/custom.less @@ -417,51 +417,6 @@ th label { } -/*.ui-menu { - padding: 5px 0; - margin: 2px 0 0; // override default ul - background-color: @dropdownBackground; - border: 1px solid #ccc; // Fallback for IE7-8 - border: 1px solid @dropdownBorder; - *border-right-width: 2px; - *border-bottom-width: 2px; - border-top: none; - .border-radius(6px); - .box-shadow(0 5px 10px rgba(0,0,0,.2)); - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; -} - -.ui-autocomplete { - border-color: @inputBorder; // goes nice with textboxes - .box-shadow(0 5px 10px rgba(0,0,0,.12)); - border-top: none !important; -} -.ui-autocomplete.ui-corner-all { - .border-radius(0 0 @inputBorderRadius @inputBorderRadius); -} - -.ui-autocomplete-loading { - background-image: url('images/throbber-progress-black-16.gif'); - background-repeat: no-repeat; - background-position: 98% center; -} - -.ui-autocomplete .ui-menu-item a { - .border-radius(0); - padding: 3px 16px; - font-family: @baseFontFamily; - font-weight: normal; - color: @dropdownLinkColor; - .small(); - - &:hover, - &.ui-state-hover { - color: @dropdownLinkColorHover !important; - background: @dropdownLinkBackgroundHover !important; - } -}*/ // MVC UI adaptation // ------------------------- @@ -513,4 +468,28 @@ th label { .note-editable { background-color: #fff; +} + + +// NICER MODAL FADE +// ------------------------------ + +.modal.fade { + top: 50%; + .transition(~'opacity 0.12s linear, transform 0.12s ease-out'); + .transform(~'translate(0, -40px) scale(0.9, 0.9)'); +} + +.modal.fade.in { + .transform(none); +} + +.modal-backdrop, +.modal-backdrop.fade.in { + .opacity(60); +} + +.modal-header .close { + font-size: 30px; + text-shadow: none; } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css index 20597a70b8..94214b65b8 100644 --- a/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css @@ -1,8 +1,62 @@  +.smartgallery-overlay, +.blueimp-gallery { + -webkit-transition: opacity 0.2s linear, transform 0.2s ease-out; + transition: opacity 0.2s linear, transform 0.2s ease-out; +} + +.smartgallery-overlay { + position: fixed; + z-index: 999998; + background: #000; + left: 0; + top: 0; + width: 100%; + height: 100%; + opacity: 0; +} +.smartgallery-overlay.in { + opacity: 0.3; +} + + +.blueimp-gallery { + left: 40px; + right: 40px; + top: 40px; + bottom: 40px; + background: #fff; + border: 1px solid rgba(0,0,0, 0.25); + border-radius: 4px; + border-top-right-radius: 0; + xtransition-delay: 0.2s; + -webkit-box-shadow: 0px 4px 20px rgba(0,0,0, 0.35); + box-shadow: 0px 4px 20px rgba(0,0,0, 0.35); + -webkit-transform: translate(0, -75px) scale(0.9, 0.9); + -moz-transform: translate(0, -75px) scale(0.9, 0.9); + -ms-transform: translate(0, -75px) scale(0.9, 0.9); + transform: translate(0, -75px) scale(0.9, 0.9); +} + +.blueimp-gallery-display { + -webkit-transform: none; + -moz-transform: none; + -ms-transform: none; + transform: none; +} + + +.blueimp-gallery > .prev, +.blueimp-gallery > .next, +.blueimp-gallery > .close { + -webkit-transition: all 0.1s ease-in-out; + transition: all 0.1s ease-in-out; +} + .blueimp-gallery > .prev, .blueimp-gallery > .next { border: none; - border-radius: none; + border-radius: 0; text-shadow: none; font-family: initial; background: transparent; @@ -12,25 +66,36 @@ color: #bbb; opacity: 1; } +.blueimp-gallery > .prev { left: 0; } +.blueimp-gallery > .next { right: 0; } + .blueimp-gallery > .prev:hover, .blueimp-gallery > .next:hover { - color: #08c; + color: #888; + background-color: #f5f5f5; +} +.blueimp-gallery > .prev:active, +.blueimp-gallery > .next:active { + background-color: #eaeaea; } .blueimp-gallery > .close { text-shadow: none; opacity: 1 !important; - color: #aaa; padding: 8px 12px; - padding-top: 4px; + padding-top: 2px; border-bottom-left-radius: 6px; - background-color: #fff; + background-color: #c5c5c5; + color: #fff; margin: 0; top: 0; right: 0; } .blueimp-gallery > .close:hover { - color: #333; + background-color: #ee5f5b; +} +.blueimp-gallery > .close:active { + background-color: #ea3d38; } .blueimp-gallery > .indicator { @@ -39,6 +104,7 @@ right: 0; bottom: 0; background-color: #fff; + background-color: rgba(255,255,255, 0.5); opacity: 0.95; padding: 10px 0; -webkit-transition: all 0.4s ease-in-out; @@ -82,3 +148,5 @@ height: 25px; } } + + diff --git a/src/Presentation/SmartStore.Web/Scripts/public.product-detail.js b/src/Presentation/SmartStore.Web/Scripts/public.product-detail.js index c86e55904f..bcc3df45d8 100644 --- a/src/Presentation/SmartStore.Web/Scripts/public.product-detail.js +++ b/src/Presentation/SmartStore.Web/Scripts/public.product-detail.js @@ -169,7 +169,7 @@ zoomType: opts.zoomType }, box: { - enabled: true + enabled: true } }); } diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.smartgallery.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.smartgallery.js index 0552e31a90..fe3305017b 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.smartgallery.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.smartgallery.js @@ -410,6 +410,7 @@ initBox: function() { var self = this; + var gov; var getWidget = function (id) { var widget = $('#' + id); @@ -462,10 +463,18 @@ widget = getWidget(id == 'default' ? 'image-gallery-default' : id), container = (widget.length && widget) || $(Gallery.prototype.options.container), callbacks = { - onopen: function () { - container.data('gallery', this).trigger('open'); + onopen: function () { + if (!gov || (gov = $('.smartgallery-overlay')).length == 0) { + gov = $('').insertBefore(widget[0]); + gov.on('click', function (e) { + widget.data('gallery').close(); + }); + } + + gov.show().addClass("in"); + container.data('gallery', this).trigger('open'); }, - onopened: function () { + onopened: function () { container.trigger('opened'); }, onslide: function () { @@ -478,9 +487,11 @@ container.trigger('slidecomplete', arguments); }, onclose: function () { - container.trigger('close'); + gov.removeClass("in"); + container.trigger('close'); }, onclosed: function () { + gov.css('display', 'none'); container.trigger('closed').removeData('gallery'); } }, @@ -494,7 +505,7 @@ event: e }, callbacks, - self.options + self.options.box || {} ), // Select all links with the same data-gallery attribute: links = $('[data-gallery="' + id + '"]').not($(this)); @@ -862,6 +873,7 @@ // full size image box options box: { enabled: true, + closeOnSlideClick: false /* {...} blueimp image gallery options are passed through */ }, callbacks: { From fb832f981df764c74c1931ebb79c198d39ed2b2c Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 16 Jul 2015 22:40:13 +0200 Subject: [PATCH 0079/1074] GetLowestPrice: Load the id of products with price adjustments for all products of a page in one go --- .../Catalog/IProductAttributeService.cs | 10 ++++-- .../Catalog/PriceCalculationService.cs | 12 ------- .../Catalog/ProductAttributeService.cs | 33 ++++++++++++++----- .../Controllers/CatalogHelper.cs | 11 +++++++ 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs index c23e5de26e..c150159c83 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Media; namespace SmartStore.Services.Catalog { @@ -66,7 +65,6 @@ public partial interface IProductAttributeService /// Product variant attribute mapping ProductVariantAttribute GetProductVariantAttributeById(int productVariantAttributeId); - // codehint: sm-add /// /// Gets multiple product variant attribute mappings by their keys /// @@ -110,7 +108,6 @@ public partial interface IProductAttributeService /// Product variant attribute value ProductVariantAttributeValue GetProductVariantAttributeValueById(int productVariantAttributeValueId); - // codehint: sm-add /// /// Gets multiple product variant attribute value /// @@ -130,6 +127,13 @@ public partial interface IProductAttributeService /// The product variant attribute value void UpdateProductVariantAttributeValue(ProductVariantAttributeValue productVariantAttributeValue); + /// + /// Gets a list of product identifiers which have price adjustments + /// + /// Array of product identifiers + /// List of product identifiers + IList GetProductIdsWithPriceAdjustments(int[] productIds); + #endregion #region Product variant attribute combinations (ProductVariantAttributeCombination) diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index b254da8051..b5fc552c0f 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -464,18 +464,6 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa displayFromMessage = true; } - if (!displayFromMessage) - { - foreach (var attribute in product.ProductVariantAttributes) - { - if (attribute.ProductVariantAttributeValues.Any(x => x.PriceAdjustment != decimal.Zero)) - { - displayFromMessage = true; - break; - } - } - } - if (lowestPrice == decimal.Zero && product.Price == decimal.Zero) { lowestPrice = product.LowestAttributeCombinationPrice ?? decimal.Zero; diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs index cda03df832..66a1dc876d 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs @@ -6,11 +6,6 @@ using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Events; using SmartStore.Services.Media; -using SmartStore.Core.Infrastructure; -using SmartStore.Data; -using System.Text; -using System.Linq.Expressions; -using SmartStore.Core.Domain.Media; namespace SmartStore.Services.Catalog { @@ -234,7 +229,6 @@ public virtual ProductVariantAttribute GetProductVariantAttributeById(int produc }); } - // codehint: sm-add public virtual IEnumerable GetProductVariantAttributesByIds(params int[] ids) { if (ids == null || ids.Length == 0) @@ -245,7 +239,6 @@ public virtual IEnumerable GetProductVariantAttributesB return _productVariantAttributeRepository.GetMany(ids); } - // codehint: sm-add public virtual IEnumerable GetProductVariantAttributeValuesByIds(params int[] productVariantAttributeValueIds) { if (productVariantAttributeValueIds == null || productVariantAttributeValueIds.Length == 0) @@ -391,6 +384,30 @@ public virtual void UpdateProductVariantAttributeValue(ProductVariantAttributeVa _eventPublisher.EntityUpdated(productVariantAttributeValue); } + /// + /// Gets a list of product identifiers which have price adjustments + /// + /// Array of product identifiers + /// List of product identifiers + public virtual IList GetProductIdsWithPriceAdjustments(int[] productIds) + { + var queryMappings = + from m in _productVariantAttributeRepository.TableUntracked + where productIds.Contains(m.ProductId) + select new { m.Id, m.ProductId }; + + var query = + from v in _productVariantAttributeValueRepository.TableUntracked + join m in queryMappings on v.ProductVariantAttributeId equals m.Id + where v.PriceAdjustment != 0 + group v by m.ProductId into grp + select grp.Key; + + var result = query.ToList(); + + return result; + } + #endregion #region Product variant attribute combinations (ProductVariantAttributeCombination) @@ -488,7 +505,6 @@ public virtual void InsertProductVariantAttributeCombination(ProductVariantAttri if (combination == null) throw new ArgumentNullException("combination"); - // codehint: sm-add //if (combination.IsDefaultCombination) //{ // EnsureSingleDefaultVariant(combination); @@ -509,7 +525,6 @@ public virtual void UpdateProductVariantAttributeCombination(ProductVariantAttri if (combination == null) throw new ArgumentNullException("combination"); - // codehint: sm-add //if (combination.IsDefaultCombination) //{ // EnsureSingleDefaultVariant(combination); diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index 4ee0f016c0..3401491470 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -1004,6 +1004,9 @@ public IEnumerable PrepareProductOverviewModels( { "Common.AdditionalShippingSurcharge", T("Common.AdditionalShippingSurcharge") } }; + int[] productIds = products.Select(x => x.Id).ToArray(); + IList productIdsWithPriceAdjustments = null; + var models = new List(); foreach (var product in products) @@ -1134,6 +1137,14 @@ public IEnumerable PrepareProductOverviewModels( bool displayFromMessage = false; decimal minPossiblePrice = _priceCalculationService.GetLowestPrice(product, out displayFromMessage); + if (!displayFromMessage) + { + if (productIdsWithPriceAdjustments == null) + productIdsWithPriceAdjustments = _productAttributeService.GetProductIdsWithPriceAdjustments(productIds); + + displayFromMessage = productIdsWithPriceAdjustments.Contains(product.Id); + } + decimal taxRate = decimal.Zero; decimal oldPriceBase = _taxService.GetProductPrice(product, product.OldPrice, out taxRate); decimal finalPriceBase = _taxService.GetProductPrice(product, minPossiblePrice, out taxRate); From 69e63f59979f0ff8b84f3499700d34d98b5fcc0c Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 17 Jul 2015 02:24:54 +0200 Subject: [PATCH 0080/1074] Minor CSS fix --- .../Content/image-gallery/css/blueimp-gallery-custom.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css index 94214b65b8..bc6725bd86 100644 --- a/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css @@ -29,7 +29,6 @@ border: 1px solid rgba(0,0,0, 0.25); border-radius: 4px; border-top-right-radius: 0; - xtransition-delay: 0.2s; -webkit-box-shadow: 0px 4px 20px rgba(0,0,0, 0.35); box-shadow: 0px 4px 20px rgba(0,0,0, 0.35); -webkit-transform: translate(0, -75px) scale(0.9, 0.9); From a163a5801df24ba56fbede5e52a1662eb1f08b3e Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Fri, 17 Jul 2015 17:50:11 +0200 Subject: [PATCH 0081/1074] DevTools: option to display widget zones --- .../Controllers/DevToolsController.cs | 15 ++ .../Settings/ProfilerSettings.cs | 3 + .../SmartStore.DevTools.csproj | 4 + .../Views/DevTools/Configure.cshtml | 9 + .../Views/DevTools/WidgetZone.cshtml | 3 + .../Widgets/ShowZonesWidget.cs | 220 ++++++++++++++++++ .../GoogleAnalyticPlugin.cs | 29 ++- 7 files changed, 268 insertions(+), 15 deletions(-) create mode 100644 src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml create mode 100644 src/Plugins/SmartStore.DevTools/Widgets/ShowZonesWidget.cs diff --git a/src/Plugins/SmartStore.DevTools/Controllers/DevToolsController.cs b/src/Plugins/SmartStore.DevTools/Controllers/DevToolsController.cs index 42d23e84a8..89a261690f 100644 --- a/src/Plugins/SmartStore.DevTools/Controllers/DevToolsController.cs +++ b/src/Plugins/SmartStore.DevTools/Controllers/DevToolsController.cs @@ -71,5 +71,20 @@ public ActionResult MiniProfiler() return View(); } + public ActionResult WidgetZone(string widgetZone) + { + var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); + var settings = _settingService.LoadSetting(storeScope); + + if (settings.DisplayWidgetZones) + { + ViewData["widgetZone"] = widgetZone; + + return View(); + } + + return new EmptyResult(); + } + } } \ No newline at end of file diff --git a/src/Plugins/SmartStore.DevTools/Settings/ProfilerSettings.cs b/src/Plugins/SmartStore.DevTools/Settings/ProfilerSettings.cs index be2df2e227..88da20c658 100644 --- a/src/Plugins/SmartStore.DevTools/Settings/ProfilerSettings.cs +++ b/src/Plugins/SmartStore.DevTools/Settings/ProfilerSettings.cs @@ -9,5 +9,8 @@ namespace SmartStore.DevTools public class ProfilerSettings : ISettings { public bool EnableMiniProfilerInPublicStore { get; set; } + + public bool DisplayWidgetZones { get; set; } + } } \ No newline at end of file diff --git a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj index e1c88f8d2c..2db1f156da 100644 --- a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj +++ b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj @@ -155,6 +155,7 @@ + @@ -198,6 +199,9 @@ Designer PreserveNewest + + PreserveNewest + diff --git a/src/Plugins/SmartStore.DevTools/Views/DevTools/Configure.cshtml b/src/Plugins/SmartStore.DevTools/Views/DevTools/Configure.cshtml index ebeb4a5ae8..7f1bdc6101 100644 --- a/src/Plugins/SmartStore.DevTools/Views/DevTools/Configure.cshtml +++ b/src/Plugins/SmartStore.DevTools/Views/DevTools/Configure.cshtml @@ -14,6 +14,15 @@ @Html.SettingEditorFor(model => model.EnableMiniProfilerInPublicStore) @Html.ValidationMessageFor(model => model.EnableMiniProfilerInPublicStore) + +
    + + + +
    "); + sb.AppendLine(""); sb.AppendLine(String.Format("{0}
    ", _companyInfoSettings.CompanyName )); @@ -597,7 +597,7 @@ protected virtual string GetSupplierIdentification() sb.AppendLine("
    "); - sb.AppendLine(""); + sb.AppendLine(""); if (!String.IsNullOrEmpty(_storeContext.CurrentStore.Url)) { @@ -618,7 +618,7 @@ protected virtual string GetSupplierIdentification() sb.AppendLine(""); - sb.AppendLine(""); + sb.AppendLine(""); if (!String.IsNullOrEmpty(_bankConnectionSettings.Bankname)) { From f07f5ed7405c2f0eaf1ecfd8d83963a153f7d8dd Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 14 Jul 2015 22:23:12 +0200 Subject: [PATCH 0066/1074] Lots of new stuff and enhancements: * Transient media records (pictures & downloads). Prevents database to be flooded with orphaned records. * Added ToPostedFileResult() extension method for much easier handling of uploaded files (much less code now) * Added new scheduled task 'Clear Transient Uploads' * Added SmartStore.Services.Media.MediaHelper utility class (helps to update media records transient states) * E-mail attachments: MessageTemplates can now reference up to 3 attachments. * Began enhancing the uploader UI for 'Download' * (Perf) several enhancements on database level * Added ShrinkDatabase() extension method to IDbContext --- changelog.md | 4 +- src/Libraries/SmartStore.Core/BaseEntity.cs | 8 +- .../SmartStore.Core/Domain/Catalog/Product.cs | 2 +- .../SmartStore.Core/Domain/Media/Download.cs | 18 +- .../SmartStore.Core/Domain/Media/Picture.cs | 18 +- .../Extensions/ConversionExtensions.cs | 62 +----- .../Extensions/MiscExtensions.cs | 12 +- src/Libraries/SmartStore.Core/ITransient.cs | 9 + .../SmartStore.Core/SmartStore.Core.csproj | 2 +- .../Utilities/FileSystemHelper.cs | 2 +- .../Extensions/IDbContextExtensions.cs | 20 ++ .../Mapping/Customers/CustomerMap.cs | 7 +- ...507072138058_MessageTemplateAttachments.cs | 22 ++- ...507092146153_DownloadGuidIndex.Designer.cs | 29 +++ .../201507092146153_DownloadGuidIndex.cs | 18 ++ .../201507092146153_DownloadGuidIndex.resx | 126 ++++++++++++ ...201507102159496_TransientMedia.Designer.cs | 29 +++ .../201507102159496_TransientMedia.cs | 51 +++++ .../201507102159496_TransientMedia.resx | 126 ++++++++++++ ...507141647299_CustomerTablePerf.Designer.cs | 29 +++ .../201507141647299_CustomerTablePerf.cs | 35 ++++ .../201507141647299_CustomerTablePerf.resx | 126 ++++++++++++ .../Setup/SeedData/InvariantSeedData.cs | 8 + .../SmartStore.Data/SmartStore.Data.csproj | 21 ++ .../Catalog/CopyProductService.cs | 10 +- .../Configuration/SettingService.cs | 2 +- .../Customers/CustomerService.cs | 159 +-------------- .../ExportImport/ImportManager.cs | 4 +- .../NameValueCollectionExtensions.cs | 29 ++- .../Logging/DefaultLogger.cs | 15 +- .../Media/DownloadService.cs | 4 + .../SmartStore.Services/Media/Extensions.cs | 39 ---- .../Media/IDownloadService.cs | 2 + .../Media/IPictureService.cs | 21 +- .../Media/MediaExtensions.cs | 187 ++++++++++++++++++ .../Media/PictureService.cs | 150 ++------------ .../Media/TransientMediaClearTask.cs | 70 +++++++ .../Messages/QueuedMessagesClearTask.cs | 3 + .../Orders/OrderProcessingService.cs | 4 +- .../SmartStore.Services.csproj | 3 +- .../Controllers/Api/UploadsController.cs | 2 +- .../Controllers/SmartController.cs | 2 +- .../Extensions/HtmlExtensions.cs | 8 +- ...ContextExtensions.cs => HttpExtensions.cs} | 80 +++++--- .../Extensions/PostedFileResult.cs | 179 +++++++++++++++++ .../SmartStore.Web.Framework.csproj | 3 +- .../Controllers/CategoryController.cs | 20 +- .../Controllers/ContentSliderController.cs | 3 + .../Controllers/DownloadController.cs | 83 ++++---- .../Controllers/LanguageController.cs | 7 +- .../Controllers/ManufacturerController.cs | 13 +- .../Controllers/MediaController.cs | 29 +-- .../Controllers/MessageTemplateController.cs | 26 ++- .../Controllers/OrderController.cs | 12 +- .../Controllers/PackagingController.cs | 8 +- .../Controllers/PictureController.cs | 71 +------ .../Controllers/ProductController.cs | 14 +- .../Controllers/SettingController.cs | 3 +- .../Controllers/StoreController.cs | 5 + .../Controllers/ThemeController.cs | 6 +- .../Scripts/smartstore.download.js | 95 +++++++++ .../Administration/SmartStore.Admin.csproj | 4 + .../Views/Category/_CreateOrUpdate.cshtml | 2 +- .../Views/ContentSlider/Index.cshtml | 2 +- .../ContentSlider/_CreateOrUpdate.cshtml | 2 +- .../Views/Manufacturer/_CreateOrUpdate.cshtml | 2 +- .../MessageTemplate/_CreateOrUpdate.cshtml | 12 +- .../Product/_CreateOrUpdate.Pictures.cshtml | 2 +- .../Views/Setting/GeneralCommon.cshtml | 2 +- .../Shared/EditorTemplates/Download.cshtml | 6 +- .../Shared/EditorTemplates/Download2.cshtml | 134 +++++++++++++ .../Shared/EditorTemplates/Picture.cshtml | 20 +- .../Views/Store/_CreateOrUpdate.cshtml | 2 +- .../Controllers/CustomerController.cs | 6 +- .../Controllers/ShoppingCartController.cs | 85 +++----- .../Extensions/ProductDetailsExtensions.cs | 5 + .../Installation/DeDESeedData.cs | 20 +- .../Views/Product/_Attributes.cshtml | 16 +- .../Catalog/ProductPersistenceTests.cs | 2 +- 79 files changed, 1734 insertions(+), 745 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/ITransient.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.resx create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.resx create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.resx delete mode 100644 src/Libraries/SmartStore.Services/Media/Extensions.cs create mode 100644 src/Libraries/SmartStore.Services/Media/MediaExtensions.cs create mode 100644 src/Libraries/SmartStore.Services/Media/TransientMediaClearTask.cs rename src/Presentation/SmartStore.Web.Framework/Extensions/{HttpContextExtensions.cs => HttpExtensions.cs} (75%) create mode 100644 src/Presentation/SmartStore.Web.Framework/Extensions/PostedFileResult.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Scripts/smartstore.download.js create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/Download2.cshtml diff --git a/changelog.md b/changelog.md index 96936ed74e..ac3fd65818 100644 --- a/changelog.md +++ b/changelog.md @@ -9,10 +9,12 @@ * #526 Min\max amount option for which the payment method should be offered during checkout * #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" * #702 Facebook and Twitter external authentication suitable for multi-stores +* New scheduled task: clear e-mail queue +* New scheduled task: clear uploadeded transient media files ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. -* #721 Message Queue: implement "Delete all" +* #721 Message Queue: implemented "Delete all" ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Core/BaseEntity.cs b/src/Libraries/SmartStore.Core/BaseEntity.cs index 9ff517f329..f555ef1e8d 100644 --- a/src/Libraries/SmartStore.Core/BaseEntity.cs +++ b/src/Libraries/SmartStore.Core/BaseEntity.cs @@ -36,9 +36,9 @@ public Type GetUnproxiedType() /// Transient objects are not associated with an item already in storage. For instance, /// a Product entity is transient if its Id is 0. /// - public virtual bool IsTransient + public virtual bool IsTransientRecord() { - get { return Id == 0; } + return Id == 0; } public override bool Equals(object obj) @@ -66,7 +66,7 @@ protected virtual bool Equals(BaseEntity other) public override int GetHashCode() { - if (this.IsTransient) + if (this.IsTransientRecord()) { return base.GetHashCode(); } @@ -95,7 +95,7 @@ public override int GetHashCode() private bool HasSameNonDefaultIds(BaseEntity other) { - return !this.IsTransient && !other.IsTransient && this.Id == other.Id; + return !this.IsTransientRecord() && !other.IsTransientRecord() && this.Id == other.Id; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs index 61f332eb11..a238d094f7 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs @@ -246,7 +246,7 @@ public string Gtin public bool AutomaticallyAddRequiredProducts { get; set; } /// - /// Gets or sets a value indicating whether the product is download + /// Gets or sets a value indicating whether the product is a download /// [DataMember] public bool IsDownload { get; set; } diff --git a/src/Libraries/SmartStore.Core/Domain/Media/Download.cs b/src/Libraries/SmartStore.Core/Domain/Media/Download.cs index 933790f578..88fb804395 100644 --- a/src/Libraries/SmartStore.Core/Domain/Media/Download.cs +++ b/src/Libraries/SmartStore.Core/Domain/Media/Download.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.Serialization; namespace SmartStore.Core.Domain.Media @@ -7,12 +8,13 @@ namespace SmartStore.Core.Domain.Media /// Represents a download /// [DataContract] - public partial class Download : BaseEntity + public partial class Download : BaseEntity, ITransient { /// /// Gets or sets a GUID /// [DataMember] + [Index] public Guid DownloadGuid { get; set; } /// @@ -55,5 +57,19 @@ public partial class Download : BaseEntity /// [DataMember] public bool IsNew { get; set; } + + /// + /// Gets or sets a value indicating whether the entity transient/preliminary + /// + [DataMember] + [Index("IX_UpdatedOn_IsTransient", 1)] + public bool IsTransient { get; set; } + + /// + /// Gets or sets the date and time of instance update + /// + [DataMember] + [Index("IX_UpdatedOn_IsTransient", 0)] + public DateTime UpdatedOnUtc { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs b/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs index 45d8e80069..c47fc53836 100644 --- a/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs +++ b/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Catalog; using System.Runtime.Serialization; +using System; +using System.ComponentModel.DataAnnotations.Schema; namespace SmartStore.Core.Domain.Media { @@ -8,7 +10,7 @@ namespace SmartStore.Core.Domain.Media /// Represents a picture /// [DataContract] - public partial class Picture : BaseEntity + public partial class Picture : BaseEntity, ITransient { private ICollection _productPictures; /// @@ -34,6 +36,20 @@ public partial class Picture : BaseEntity [DataMember] public bool IsNew { get; set; } + /// + /// Gets or sets a value indicating whether the entity transient/preliminary + /// + [DataMember] + [Index("IX_UpdatedOn_IsTransient", 1)] + public bool IsTransient { get; set; } + + /// + /// Gets or sets the date and time of instance update + /// + [DataMember] + [Index("IX_UpdatedOn_IsTransient", 0)] + public DateTime UpdatedOnUtc { get; set; } + /// /// Gets or sets the product pictures /// diff --git a/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs index 35781072ef..d7d8629f56 100644 --- a/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs @@ -3,9 +3,7 @@ using System.Linq; using System.Text; using System.IO; -using System.Drawing; using System.ComponentModel; -using System.Drawing.Imaging; using System.Globalization; using System.Collections; using System.Reflection; @@ -512,13 +510,20 @@ public static byte[] ToByteArray(this Stream stream) } } - public static string AsString(this Stream stream) + public static string AsString(this Stream stream) + { + return stream.AsString(Encoding.UTF8); + } + + public static string AsString(this Stream stream, Encoding encoding) { - // convert stream to string + Guard.ArgumentNotNull(() => encoding); + + // convert stream to string string result; stream.Position = 0; - using (StreamReader sr = new StreamReader(stream)) + using (StreamReader sr = new StreamReader(stream, encoding)) { result = sr.ReadToEnd(); } @@ -546,14 +551,6 @@ public static object ToObject(this byte[] bytes) } } - public static Image ToImage(this byte[] bytes) - { - using (var stream = new MemoryStream(bytes)) - { - return Image.FromStream(stream); - } - } - public static Stream ToStream(this byte[] bytes) { return new MemoryStream(bytes); @@ -600,45 +597,6 @@ public static string Hash(this byte[] value, bool toBase64 = false) #endregion - #region Image/Bitmap - - public static byte[] ToByteArray(this Image image) - { - Guard.ArgumentNotNull(() => image); - - byte[] bytes; - - ImageConverter converter = new ImageConverter(); - bytes = (byte[])converter.ConvertTo(image, typeof(byte[])); - return bytes; - } - - internal static byte[] ToByteArray(this Image image, ImageFormat format) - { - Guard.ArgumentNotNull(() => image); - Guard.ArgumentNotNull(() => format); - - using (var stream = new MemoryStream()) - { - image.Save(stream, format); - return stream.ToArray(); - } - } - - internal static Image ConvertTo(this Image image, ImageFormat format) - { - Guard.ArgumentNotNull(() => image); - Guard.ArgumentNotNull(() => format); - - using (var stream = new MemoryStream()) - { - image.Save(stream, format); - return Image.FromStream(stream); - } - } - - #endregion - #region Enumerable: Collections/List/Dictionary... public static T ToObject(this IDictionary values) where T : class diff --git a/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs index da7f1483e3..3e871038fe 100644 --- a/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs @@ -21,15 +21,17 @@ public static void Dump(this Exception exc) catch { } } - public static string ToAllMessages(this Exception exc) + public static string ToAllMessages(this Exception exception) { var sb = new StringBuilder(); - while (exc != null) + while (exception != null) { - if (!sb.ToString().EmptyNull().Contains(exc.Message)) - sb.Grow(exc.Message, " "); - exc = exc.InnerException; + if (!sb.ToString().EmptyNull().Contains(exception.Message)) + { + sb.Grow(exception.Message, " * "); + } + exception = exception.InnerException; } return sb.ToString(); } diff --git a/src/Libraries/SmartStore.Core/ITransient.cs b/src/Libraries/SmartStore.Core/ITransient.cs new file mode 100644 index 0000000000..761dcee833 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ITransient.cs @@ -0,0 +1,9 @@ +using System; + +namespace SmartStore +{ + public interface ITransient + { + bool IsTransient { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 4251026394..630ff48dba 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -101,7 +101,6 @@ - ..\..\packages\System.Linq.Dynamic.1.0.0\lib\net40\System.Linq.Dynamic.dll @@ -171,6 +170,7 @@ + diff --git a/src/Libraries/SmartStore.Core/Utilities/FileSystemHelper.cs b/src/Libraries/SmartStore.Core/Utilities/FileSystemHelper.cs index bac48f33cd..18f56f51fb 100644 --- a/src/Libraries/SmartStore.Core/Utilities/FileSystemHelper.cs +++ b/src/Libraries/SmartStore.Core/Utilities/FileSystemHelper.cs @@ -72,7 +72,7 @@ public static bool Delete(string path) { if (Directory.Exists(path)) { - throw new MemberAccessException("Deleting folders cause of security reasons not possible: {0}".FormatWith(path)); + throw new MemberAccessException("Deleting folders due to security reasons not possible: {0}".FormatWith(path)); } File.Delete(path); // no exception, if file doesn't exists diff --git a/src/Libraries/SmartStore.Data/Extensions/IDbContextExtensions.cs b/src/Libraries/SmartStore.Data/Extensions/IDbContextExtensions.cs index a24674703a..102709b1fb 100644 --- a/src/Libraries/SmartStore.Data/Extensions/IDbContextExtensions.cs +++ b/src/Libraries/SmartStore.Data/Extensions/IDbContextExtensions.cs @@ -80,5 +80,25 @@ public static T LoadOriginalCopy(this IDbContext context, T currentCopy) wher { return InnerGetCopy(context, currentCopy, e => e.OriginalValues); } + + /// + /// Executes the DBCC SHRINKDATABASE(0) command against the SQL Server (Express) database + /// + /// The context + /// true, when the operation completed successfully. + public static bool ShrinkDatabase(this IDbContext context) + { + if (DataSettings.Current.IsSqlServer) + { + try + { + context.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); + return true; + } + catch { } + } + + return false; + } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Mapping/Customers/CustomerMap.cs b/src/Libraries/SmartStore.Data/Mapping/Customers/CustomerMap.cs index a130708ccb..6004f3a520 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Customers/CustomerMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Customers/CustomerMap.cs @@ -10,9 +10,12 @@ public CustomerMap() { this.ToTable("Customer"); this.HasKey(c => c.Id); - this.Property(u => u.Username).HasMaxLength(1000); - this.Property(u => u.Email).HasMaxLength(1000); + this.Property(u => u.Username).HasMaxLength(500); + this.Property(u => u.Email).HasMaxLength(500); this.Property(u => u.SystemName).HasMaxLength(500); + this.Property(u => u.Password).HasMaxLength(500); + this.Property(u => u.PasswordSalt).HasMaxLength(500); + this.Property(u => u.LastIpAddress).HasMaxLength(100); this.Ignore(u => u.PasswordFormat); diff --git a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs index 0a48be7f37..448a071417 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs @@ -2,8 +2,9 @@ namespace SmartStore.Data.Migrations { using System; using System.Data.Entity.Migrations; - - public partial class MessageTemplateAttachments : DbMigration + using SmartStore.Data.Setup; + + public partial class MessageTemplateAttachments : DbMigration, ILocaleResourcesProvider, IDataSeeder { public override void Up() { @@ -18,5 +19,22 @@ public override void Down() DropColumn("dbo.MessageTemplate", "Attachment2FileId"); DropColumn("dbo.MessageTemplate", "Attachment1FileId"); } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Replace", + "Replace", + "Ersetzen"); + } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.Designer.cs new file mode 100644 index 0000000000..0693d8660f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class DownloadGuidIndex : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(DownloadGuidIndex)); + + string IMigrationMetadata.Id + { + get { return "201507092146153_DownloadGuidIndex"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs new file mode 100644 index 0000000000..ff65fd3814 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs @@ -0,0 +1,18 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class DownloadGuidIndex : DbMigration + { + public override void Up() + { + CreateIndex("dbo.Download", "DownloadGuid"); + } + + public override void Down() + { + DropIndex("dbo.Download", new[] { "DownloadGuid" }); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.resx b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.resx new file mode 100644 index 0000000000..457d21844b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.Designer.cs new file mode 100644 index 0000000000..d738e053cf --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class TransientMedia : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(TransientMedia)); + + string IMigrationMetadata.Id + { + get { return "201507102159496_TransientMedia"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs new file mode 100644 index 0000000000..509169153e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs @@ -0,0 +1,51 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Tasks; + using SmartStore.Data.Setup; + + public partial class TransientMedia : DbMigration, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Download", "IsTransient", c => c.Boolean(nullable: false)); + AddColumn("dbo.Download", "UpdatedOnUtc", c => c.DateTime(nullable: false)); + AddColumn("dbo.Picture", "IsTransient", c => c.Boolean(nullable: false)); + AddColumn("dbo.Picture", "UpdatedOnUtc", c => c.DateTime(nullable: false)); + CreateIndex("dbo.Download", new[] { "UpdatedOnUtc", "IsTransient" }, name: "IX_UpdatedOn_IsTransient"); + CreateIndex("dbo.Picture", new[] { "UpdatedOnUtc", "IsTransient" }, name: "IX_UpdatedOn_IsTransient"); + } + + public override void Down() + { + DropIndex("dbo.Picture", "IX_UpdatedOn_IsTransient"); + DropIndex("dbo.Download", "IX_UpdatedOn_IsTransient"); + DropColumn("dbo.Picture", "UpdatedOnUtc"); + DropColumn("dbo.Picture", "IsTransient"); + DropColumn("dbo.Download", "UpdatedOnUtc"); + DropColumn("dbo.Download", "IsTransient"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.Set().AddOrUpdate(x => x.Type, + new ScheduleTask + { + Name = "Clear transient uploads", + Seconds = 43200, // 12 hours + Type = "SmartStore.Services.Media.TransientMediaClearTask, SmartStore.Services", + Enabled = true, + StopOnError = false, + } + ); + + context.SaveChanges(); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.resx b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.resx new file mode 100644 index 0000000000..11d76add9f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy923IcObIg+L5m+w8yPc2snZFKqi6zPm1VO0ZSZCnt6MImKemcfqGBkSAZzciIrLjw0mv7ZfuwnzS/MADikrjfIyIzK1+kZMDhABzuDofD4fhf/9///+v/fF5lrx5hWaVF/tvrd29+ev0K5kmxTPO731439e3/+Ovr//l//5//x6+ny9Xzq+893M8YDtXMq99e39f1+m9v31bJPVyB6s0qTcqiKm7rN0mxeguWxdv3P/3072/fvXsLEYrXCNerV79eNHmdriD5A/15UuQJXNcNyD4XS5hV3XdUckmwvvoCVrBagwT+9vpyBcr6si5K+OYDqMHrV0dZClA3LmF2+/oVyPOiBjXq5N++VfCyLov87nKNPoDs6mUNEdwtyCrYdf5vG3Dbcfz0Ho/j7aZijyppqrpYOSJ893NHmLd8dS/yvh4Ih0h3ikhcv+BRE/L99vrvDSCfvuVp/foV3+DfTrISAzMUPiFkRmBp/uZDWsIEfX15QyP6t1cc+L8NXPL+zfs3P7356d9enTRZ3ZTwtxw2dQmyf3t13txkafIf8OWqeID5b3mTZXTXUedRGfMBfTovizUs65cLeNsNaLF8/eotW+8tX3GoRtVph7nI65/fv371BTUObjI4cAZFEjKq32EOS1DD5Tmoa1jmGAck4xda59rC//atIVZEIvX61Wfw/Anmd/X9b69/QTJ0lj7DZf+h6wAiKxJAVKcuGyjpoL7RD7BKynTd8lBo24am0mqdgZdPRQKyCAO1auxruYSlaQr1mBbVB3gLEE/2aI6LIoMgNyD69e1GogxyBhu4PEVCkx3VNUjuV4hdPATuM6wqcAerN1KEB8FTt0URzNysHhXuCZoEzOOMSKHV5g03IwKoY1NomPcaKXr3008x5OgszaBAFIPokXW2k5U0B+UL0zH0U96vIO343nK0jkT+jMwO3OYELX8Bj+kdYQXJFLx+dQEzUljdp+uOoaSCft2Cn5XF6qLIVPqFQF1fFk2Z4LEVRtArUN7B2r7TFCqHvjO1TEOgvlqOhK4hG5C1zv5QPOVZAZZeanqZgjc9goNa1uiRjka/N+nQavvbUYiRad/j+lZmbsu4ulsUKolWUGo5Nyuma6tXo7GVKtpJ1WgyDBouzliwGsn1SjxOQ6fPaEyV3qCN09Ki+gKfQvlpUV2VAPWXWH1hqL6tl1jSvubf6qTHhVZjeJWuTAuQj7kayUg96EB1W+dlWpQELsQqxSupdsM1iu2EWzXuaWPYqFfF9IO7KiYZ2gVcZy9RxmfVziRjOjkZvYnjJBm9jcvm5p8wqcffgh0Xy5fRl7KTEvouHRLSYJuiTGEVuJlGaBQdMlgAxO5PkqLJ6+AdPcyXn0HegCx7cV6fldujzaakmmJ71G927LdH/YbKdkA0yU0jumaBpQNhYHTbOxYwaFfHdsvftqHxHIwbg5jqPCu//DKKy7t1DZscSpaN69v6WFS6FWKkEZ4XZR2m9dCWuTRs1sbqO6iqp6JcTt/yaY6BL6tgDwH2N7RHBmhVJbKAao10enAOXrDu/gzr+8LHHdXVr94wiA5aS8egFKEuX6oamnY5f7G1A10Z9jnJmiVcnpBJhyVeGxfLanTLd2gXL3Dli77J93GM4L7NS2RRrFEbLfmnGG03StIBLAHEZ/YcbFd+TvN01azIAeXRqjU5OisXJukKIC10XqJfXaTFX1+/usTnpoibjJjB80iYW2wXsEK0TmpfWtjrtrJYNkl93ORLxNhIzpCtWqY3TQ3P0qzG57rO6u4E1CAr7t6YUB8UoLqtDdFCZWAgejRE30HWBGNbVEg+0KYF7e7hMt6eb0M36QbJxJLXdP3NnsmhmrCNcqkbtLMSGoopugdZVbfVEStUIlpiR0LWx4OFYUG7uCTm2tbjO4dIRPIabeRDtwFmqzCGF/Ie7fXsgriiHeMhFhwUheO+RrJDTpfw6r5Z3eSUM8AX2Xc08TdZ8MwR5VDdeyj/0aLQovpnA84JDU5NevWQezYnWOZ4b6fPEum2qHct2A34mqujGSQLal6/OXjXoB23YVgNwL7ruk67Ghrh5sXBqNCox5ZEuLlQW+AclKjN38uiWaOOxLEvukVgkS/Tx3Tpd3AzzlLuevQ0+dqO+jdle0fLVZqfFKsVFfsyWmM918IVWpLDt5xocp6+5h+LFTyPYCt+hjVAIo4d3zqPVhybETc25TTj9q7SWhv0H2dkR1lWPA3uUPiYwqdgA/VovS6LR7i8QLozv7tsVmF886WoI2Ps0V0h9Z5xgw7uYzykXbzEVXGUBNv5n9JVWuPOkZUseIovH5rxhQ7kzS1IsMFQolWv/oK2PJtNwWjN/o5YbPRGFtXv6W19AsrgDVOPJ4ZtcQH/aNISfq3vEcVb5R/MKR3Ojami09aR4n+OGmzJ1mmCLZmj5ZLrQ/CYFtUmnD1OaHTozH3Ls1bAe4TBY0Sz0grc11sBp6f/qUNz+rxOS2JWfwAvPE47FEdJnT4SFDHY/iOoLgGycWCsWWWxOV4GQr3BsQRHdyWEtJkXcLa+QXYFn8e3GxfVBUyassUeqj06RCcvSQbbToXqOBrjOSzTIlj6Bpxk7SeIA2VlUeFj2za+IpgdF9UZmv7+HDjYulsuUyx5IOsxntxjB4S9W9k93B88nz6jXUiwLCyq0yqYnKg3J2g7dFfgg/zAI22Qo63QIn9EoonQ9Uf0gWZjXSQP0Y4MsDeWYDx6BCmqm2YU1kAvr7Sn3gtWmkcc+afiqR01XmkQttBJQRuE9PaFbN/PirLv4zFEu6/AgyaQPBTYW44zOwSfCuPdIMa4aGmJdiDDpjfYoiA+/S6II84ktRjb4I04GAkB4LJDRsVjj2esIlnAHTxuXo6but44FwJkC0P/SKv7LK3qOEg74c8gYl6k15njGV+cJ8g6J+jSJPz8iUYSfQX6mi3HbaDbmJxQsa/R27hcIzwgcxyIPc7LGu3R+zMxjysINK7TfBmAqXdnneb4TC0Kf3Vqi8EMR2aKTrFN2ibafFylsJXJYIWP1lBY1cPR4Umxuknz7hQtIhOiPvehCNXRep2l4RbzD5je3Y8niuw+Jjr6H+lyROwfx6XNsNKE6pMBUZgyiReQEC9GAmbQJ85uewMkxAGmj7B8wZUdvSd06izHqseggt3qE2XbPeD7DEHVlLBNC6aJvY5x87FvM24Y84AW/2BR25GWBC2QEy2DByqOe70L6oAljpOI5fhgkGJqxMZ5eV+0/hRQuns61DFG7ZI4LJHSWJW+9LqDvio2vvJNsIoaSogg0oC6BgzR2kAXaHPNAgoxNky5KryGBfIMB9rE6FhGdPkHOBkjtxQBUY4j6hxeZEOsHlDvFtMEOvEgqgEIcJ4dpw8RtX2nATX9l4GpxiCF9RzHeUrwaIfQwWh6z0GoOs6DefZ5OARXd7kF0fSYBVB1mIPy7C/Zgd6mbXY5Ol5X3X95Fc149BVU4zPU8hzvFbjTDu6agRP1KVWsVKc0jKc2/Q7KFBl1sn2ktvuaepoJsqilmiWbqp5TxaN2GrjDaF2H6D0uNleuhgdZQJEJ6XIlFzJArmzInw1rOsuDit1lIZQd5sBcu0z7cCTdHYplnCEUCrwgQshm3z414HAvxSNlcmfUDr8OUcjqtgwxuSMlBO1nJkakxrcK75Ui3TZS31+K7tTqm3LdlTuf/HYuM58MQK2XzKNmF11VnRTNGl9wXgbPjIhJfvwW5/SNzAyJjyRSFsqjG0yYeK5xIKZt/FVh2IqJG2+6gm4vv4ETliUtsOviJHExjOGRMI9BcF5YeyQ6VB3nq5NSDW3Ka0jGIQNUD0UKHXQdqN93B9wH6lEclmJ1W4aleKTrMfi2SqSWTQ786e5KHBc14tNJL+HgB1FGX5l6MYp1/eZwYSbKyNr7d7ECADtPm+NJFb4/dZn+C4a1zVz9qa6KNn8Hj9s7IqfD85UNHgvYd1hEAF2A/E4bsxUthUDEm2wjxC9s8c2hbTsF38uEAwKpSG697yl8+qzfVHlq49iHjx5bFvMBpGR/Y+2FbdW0tPebk6oeaNNjvkyw5AWAsLv8fQ8839jo6h8Md436akk01vMSFq/n/GWcm/OwsHhu4udIlx/35hGI2Ce3ogqRQxhPbjl946dOGJzhGUIO6mWq7GOqbcV0tpHXUuotDYpjNJXQOEpw3JgLU19jJPWR+AWjnK5R+A5SrJWbKC8pSMh+0WTQKoVyHL/K5RqOfmp1nGYZjnrscyMH3n7sL6XGQden7iUbCCZrtJPHZoNm0PA6N0WcyaMapTNwT9lwPxtmL1Dsljt/heM8nT4jRUU/xznBHnkT/zDeCZJyd6w9b/Jbe5go3IBXsGlEh9VG3ZZhIRjnFeyTIivKj/CZpI+evPWdeBjbdZ8V4eiVw3SQGnVbkXZasQ6CFtUZBHgiegNhRr+2cqXacKjFHYANsPoSwPBDsSkSAUfYwvncWjD1N8ou7ly8RhCuG2hsB/0wun6gyf2n0BEst1ret2Er6S/dMH8o5FBdYQT9EXJzyKb/UXRJJCVy0B7bHN81acQNxQmHEKXtClE6BBXtYFDRIc5m9+JsvE652MVdPOOSlQuGghQoxm6jvUobvs9o8USzEV7hzBNd+yTqplMx5D29vH49hS1v0t6xXNiYcJMkam3TqYcR5SPM1rdN9l+wIslPoyD7UvjgCrHhXe+hK+x2xW11x462WDpa5LCqkKyaUi8Ida45eVaMSFlDf9VeXS3o7KCXah/109scw6/D/kTdVk+j35t0aLX97ZFd2hA0FilPpunt80jNWLymHel1la6hs6JcgfCInw7bJcjGXzcmfYUmYvrno9vbNEsjbFRJVuDg3Uwky3pRtQEhRwnzvKP33QGb6JI4D0V/AlW9WB8tl2i/M35sQNR9A+76p+IuzT0vTeP6fW5pJQr/y8ItSRUmQ6/8rykwKmZdKBWj1kUQV1OnC/oZ5l7XTR5W0lcWRN1hDs611/yuQ9ftDuZ6Y9OI/eZhBKNLCeh6g4GOXTKQmwOVUJuBUBObBXOl9ekzNmlAdtTU99ioaZMfXcCk9Q5KRqCrIZ0GqwrCnNjVcp0gZAY0q/OiUtyRGYqlAxFLhV5LQLy6eFWs00TTR1Ku7iRbLO8lB+PaTeJikveQFEk7x5YI/eKKXbt0AdEuI8cxVlA1wQyItItyCKGrCjD3Lj+BcnlepHldfUyrWnXsL4FT9F4NJxmDBth1JH0MotVaIwBL1B8Ho1aAPKBz5ikqIag6myQPJSW/EkigvRoyaGs/ENR9Z482GkX+pkNw2NWr2zpLy6qeJC4cm6+TNGTa9UfaGhSrNchfJmhHHpRu2JEh7sAJXB/TPHE91TuhnkQZ0R9ARPPdVA29H72hf6RrbCuBzJCEKpIr6L7IofF5y0gvFvfv+m35flu9k2llSLoU9gvtALNZALkiYdHmy53XalpItZ3jIMUuMgDKjrJQYUmfenIFROt3OA7Ls7otw4JpmzbIJyKj6hwfwR5UgixWRv2rp+ITxERcVIVB0b6PoJCu7ksIbRv8OUKDSNHCMk24xgIfg/4Ogl288WJDogV1hEa/aPax/F204RacdC9Fw1xvKrfqjUtIYoaW7K6MVZz3t/RCoBgWs1ZIVkcpgNh5KVTQtpClh8cK1CPgpu6wDmnU0t4Hp8bTS4u7HNG6feE2OCbv9DnJmiWSdeYise7kK845WyeppHksAuQ04dn9zNlCyVJ6cgr1yhvHDhrZT12xtnuAvcxgOmgrI/MGP8A7j/F9c1PCxxQYtF6cjKHbYNZ5bds9zRNB+LVGTFBA2nDgGyEurcN1kHmNzHekCr4xZxFcEuemwAKn7kSst1fPMhqjCeIHQKjO0pSREl5ifZwVd0P8mrNI49rVGwrHdkS5d52ZJHIcDx47yOOZkD1GKUtRtL7eAG7YSVYusJIUKJiN2q4E8BBGcFgL1G19AvldA+6CYzZj3d5wzW5VLGMcwHldw2uZPXjb2q9sHb4TyfOvrsZ4UcdH2j5TN7Lim+eJncPF2G28YjnSASe1Tsm9KF6rIe/L1S6Ztl3tdbOymwTrBortI1MoXa5ZiKC1etMJ57WapJlK/0WA3/R4Dku2uq15fC39zHRU1275xmgf1f6jgZdwiqPMswzcLVZosDhpt/GuRoyrovX+PiQxgrerzUzXTsYFrIhqkytzGaRUY2oBBfWuhw46spOhDtaqEpwHDWvWdRHS2xJaG1TISE+D9q2bkkiOtElaVFi6zrPmLs0FJWK8lFg0iUz5RDGdIikF3qSyUyFeSuFccTs8ViIJCuV2eNuY3oWK4Q9QdQOMF/hyzt7/nzJ1gDY7gjnjgBcDfoFPlb9LF9d+Q6HYDh7rPbqT5B2Z0n2MKY3vlsRzH/cYpYxOTez1BnDD1rJygYmlQMEs23bFn19x/YOhpG5rx73Hl/dFGUMcHZs9I6pr6laj7ejmcdL+GX3uW+VRPTjNo4zMb8syLImybYpQKF1dWQjXCzjU+iz3tHhZAbxfRWsq+O2ciiz7XtRkS5aQxEPO1gBGUb3hEW2HDYt7dZRXTx7BPOqtzYBTvq/hCHFNw1ObGTWYuIPRwIbtm6muBcx7i+JgCOr5cOQY0pHMova65tdbxH+bFXaLHvQrsIpQiGEnIi0MK3pUkVTc6HLnRIqcuCpSJ4brCSFJooVO8dYTQRrioBvUbcXaJM6jH9qEbZ2lO/5d9WibtPvi6Wv+ERkS58RaDNwv4c3X7yS9zlWBNeX2XG2cZzc62oVK7S6AaGvZDoApkOp7f8t/o2PVet5yIZLpc9lCFXSZAKOOcpMAIzrodXVbplPNX34ZxXlWQhjthnys1KcIUafRMB5uCgyqNUqy0z5Lacv8gUuHTYpS29m11jKwXKVVZchByEOpsynqIUVNpAcPMy453D7XsGHSlAirQICDfvLWT6Pai/Poxs2jgKO3HJAKNZoQC3aOncx7CbEuLWmQtaFDfJBuDa9HusQ4TQq8fpbb0d2mEyQI65vsDJMJW/6KeZlw3zRNHSUJrKppGjzHF6DRptVKzcd+y1x7MXSk/My8knXL6uyla4dkyh6KldStNgmdDypU3RbJBB38RHMkPRwpMsp133RuvsIeJ33Ezl88d86RzmsOTRp12w5uEpgbukgDyjpJZUJXd5MCCtdnXWeCFBrBcdBo6rYIlbZGo+HZwghCEXXJCXWxKJa3kNzPRrs3E0K6/z2FT4EocEJsr4QICjyxprjH1+pdtyOE/VgQ3B6kkOpaxaMVTmuCqYMdkLR35Keuay1A+BIQqP0Pil/dFiHQ72XRrEc+ZR7prtaUwY1fNs/MBBEqyuKANWiUfcg+LhF/rledNzKs1ubXNBCnzakyuTanAcK1edeJIJVOcBz0ukbJ7L023ksZnypappWlcHUhfShNpk+81EU3t86aon1qrf3voCTUbRECTfTsCmkr+F1nMuBt8VOwr3YGOyvYV9kcH1Qi5MWZZptoHYmD7Ry84FspUZG1abTHPElScMxJU5YwT14meX6pb+wCbMJGP8AkXYHs9avzEv0iWuz1u7++fnWJMyj89vqv3rLABmKFztN3UE+pVi6bmxqpxGyRJ9kVRmtFrL84D4tpDKetn6KxK9wYmhvyivZUI2QanWakndaZZoRdY5OODDXkIMrujTHKEa0iKTYRQHYG4dg0Vbc8NoHVLY9N7Q7/+Kk9CQ+NzqS9rI/bClErozWBDO8mX8Ll0WrUkdCvAP+AJURsFyG9+j1MHoqmPqoRH900NZxyKy00Xv3naoLXTTvTI9Y1p6Pb2zRLkUxG2x+sR6cBuR+ENzX4ZeMSIv11gniLtZ28WQphoqPqx5tI3OVJzHCBNuMlMgDVA1yqpmTUEZ48Po7/kixu6PR5nZbEkfC5yOv7idv8LwjGpyctX+0jRx/gTRp8bYVCdZSQdfNjkS0n4A+x4YkYk2r4GOQPk2yAuTYnUTF0m4uTKZsb3hearsnFDZjAuOhWU2IADqnwxpb7Bm0Iyi6N61UJ8gok+OfGNJi86UlERtX4BayabHyyn4A1dqRPS3Cx0YlGe9ncDDb6tEM+b8rkHlRwSgf+OUh9L33zr6mOPS9dc3h/jhTOumlPSyb3Gn+AGaz36uUtzU74AuKjN+pusdWxxUdQfYFPnRfnS4Hv2STMq4ThR53sKY30yJOI0TUPuDn2lJULkRJSINeYPG3cYNuCLGSQLVF0zTtQsPcNfavQLv1jWtWF4sFEGeB1d4i76awaSjhO1oC6vgnye3pLNnLGQcgAr79VcPkjre+FwZihhUFZVHEdHKmFc75p+JukhBP6zxUJneXLvXr2pU0RpeoZLlb0bFMk7xlV7tqzC7iEcAWXtBI7Vb4FSkMZmcIILAzGXMP5+XXUd3XSwb5UJDtbIn0onir26dXaShsLkLy24wAUSo+HCgpfkytCj9eWWzSVVGEeAlbUbQ3HoIEe3larhbqJx3lna3MSY7vCbmoYFtn+oyAremhXe6HTKWMYCFYdZzWXl6TLrQXfQDQZtoOYq9vq6RUqocwKGgMZ8yJM9IPFkRRKT017a3dTw2Do9h8FudRDuyoUztCawmi3GpDcpgtSOOFK5qBY1G31fjNKK8ie+7DTTjEC5UYOVVhUfWdJtjQQwRvVIzwpmvVETu0LRIx1ih1EU3jthtamSXBzCXO8j51iZG1T0wzrM9psUflTR2tnUW24g7gP5/a3juSAcl+SrdxOwgJuOxq5JtWO51pVRxyRAlS5Kqvgg5ZkqodBN1AObyHZbMYRkYJvh0Sx88/bx99C0fy9Ad3ogzYdeVqfl2kyegjv0NDoEbtTjGaSkYwdYdz7NlobcWySsa2NTbtZwlynDW/9UDzlWQGWEZ6zWlQ9smhm/CckIHkFe7yOWyCsrX/A9O7eYetiuEvX5MsMIjMLjB/I0Cr4E5InLxZ/Kw2lo6oqEhyVvOyNFfmpR0QrSWX5mayqcP+uw0Gj9LhGchBpbZC2s2ro1gAl61hXqOlaDxFuV34hb0EE2ZUYxcGuVLcVxRr8Qr3ZMV12xf4qZrEJ9tjKPa1BE9gd7EvFTXLw7yVskoP1oKzTEnwHGdTwXaSr9i3BY+A4BhnIExi4LatGv2U2lQNtJM2gDWSTRbvIwtp0cILa0ALHP3GKHBBkM5qIx019GI/PkxpdRM0QQ3TQf+q2otggVyVIHhDFJwr0Jpd04+7uCM9A3/DxDzBLH2H54ll9ctvHOriOF3pF7J1ryJ86EJSGuN7oALGDDIAyCJCFCkr1RKOMoZQOTnezRBI6RYmkkx2iT+MvNwpDTDlQyatcWjz3K4gd8wv4B34z0t9BwKA5yIFGDmIkFIsmBLG2S3EOny4gqIr8rChbbpreDdLxLyRu7ygHBGEd0F+espva7gbs+HljLmtwe/ulmCJFzdFylebmq71/+SnKgyCMbouTV26Lrtj57qgpmij20jIIyb5TCha42SyIcXaCFqGweAoe02Fl08l/hJXtHJSdfeN4Qtie53lUpKc4RoRlNA9knLCQeVIsIZGEJeIhHBYxmscyjtGxC6p4w9yK3QWrpa5peHqPoQST7DTUsFHvGAsNydYSJZC5394eWd35rtCK5JhXBWPucpRD3w7J5RrJWn/HfdAFPidSoAZZcfdGi/ewPI6uz+WE/7pmE4F4rhU4edVZmqGBRXizHfH109e8G/Y5dbTknwTLOwG/l5RrWV0m8lYVxMeQrWo5+2Y1fOIxWj06WxLosDjSRYsqbPegHaq34tShPehNV4U38uNR44bZjKHB5GRSvOs+t6jz5zsRtEaYXpRbedp2FXgoA9C9umgbeuAYQflFV3sHhfdnUE067lWcF08vcsJZc4DYhuzUrsBd+LYMITmIlrdo/SXSI2WmtVq7Kl9vprKSLLd0sWodZWBi8OZ3UKYg36RrPylWN2kOAi1iM/IDL6vbunxoIrCy4e59neoOQeM08hnkzS1I8CSW52i2jVFncZp19E0bbjeRjsTC9iNdxkP2Me61KVBBQjnXaGRLtPgHi9rqEOeoqtK7HElRSvhosdSdQb+LcyzcRwli377jmVN/coEvwbrehKvIlbxgZ9pOHi8hlZk8xDn2Ib7Or0399ZYgbc97nYmqTqpGMYdutdcsftcsDsESsK2qcqxZ1495cmLRttqxalHLZ7C+LlZain0Hy+JwGjFd1WfYTP0YZ018Y/FNw4M9OLpC79BEc7RewecafVqtx0+Pj1Pz/NGkZfhldUpe8rosshhxITOdXvEi5KBeXXWqtyLlec5nPFJ/kG0d1xHqna0WQ+URkzyPWreAtMa1UvMaaaCtr3IsuCGJ4XmIuJgcVhGLVeQoS4Fh7xRBU8/k4h4t9UuopdSleY1tLhG0B25Xt6WgW3gczQ4JkSE6ssiK8vKPBpSwuri7GX1QrW9p+U8kCXRwf/TY0fa66QQNLSqECS3kMImQRCnAhuQwEdUQw6z9lOYPONB3zhx2rtbW9thZlnannbHmtSJdpbDsXOHey8+A47DW6DRbnPjPGLcs+qBozHSerutQL0PUiwHG0HM8UKnUD6x7zYJu5FoOIUiuAiym73TThGQPLxRqeqjbp9tHCmFG9Lk5j79U7X8HfaFua6JYBa7Vb6XuFGekRi+r7DTH8MEG0iVMEK/EGYThWLWotHdqIx0yfiruiuFQczYHJD/2epUdF8uXKd5aLfIayUt/HvUF1k9F+RB5dt103mdArusEqr4Oy0EDqttqyR/K9i2WebSph7Fmb7jfwxUke4GbzGcdJvWrNwyaAzeq2yKEGn1ZicSnFpt/TSvv46xdY3L/MUgeFjkJ3aBfxQ7YxCowHkQi6gSPti+Ode1+jvSUCtaTXoU2wQrbPmOFmFtUVWOSDasB1HocUTazdAzqFVwhOznoxFGG7qBI1G3NY519T/FL8JtI2+la9t2KWfMzYkR4V5QvEXiZR3Xg4wMfT8bHnXKPwMYcpgMXH7h4Mi4mU5EmQbFMxWpV5G94TAc2VrcVx32ERvR7WTTr6dkStTyDFBpcAyOFZo3pKjhKsguYFF5PHZPzBITuzYDkIHFjS9ycDlvtwbhz5M9imQ1jCL9SZDzLHnhUeZYthxC22gqwoB32tzJECos3Q/2DAO6zAF5mzd30rca6VPkJ5HcNuBtrJbtM7uGyyeAVqB58TnxQteoNjeQgS+q25olRRwZHkS8DH57CdafveqwQjrpYf81Py7IIfoTuEyD5usvaI306rnuaLz1rXjZJAqvKt1168LFiS+zt5dvbNEv9vC1D3Wrz86Bk1G0dLZcl4pPg0B6YwQjh5Z6LoPop2nZ0cmO1Z4/rAYqyU/lC0UQVIMLOfyCoEP/1j1A58/2HtIQJfjPtDYPpwPrqtgzrq+11EtfV5aWq4QrR4YlsRaZu/gKTzjLu+a/b58jsmPsDWsfyyi/cQpCUAdlBWA7Csk/CctKUJcwTn+d/N0LSIzkIh7dw/DKSp7CdmBOEQtf4SIIBx5aLTwVGEE5WG3/rWVGu0KRTOefHau9TukoRi10VbSh2qMFMBKy636aLnVv0nAk/RqLb0J4azWz0mxPWWhnxWrMKDBklOKo3AqqDkla3RdPp9yYdWm5/zxTsSWYwOMNRsU6TXQw7FfhXGnCqhhI25RrQwPxi6SOixfBCva/AsngO0qqR1hiR3ZiHYknqVRELE+LPf8JE+2zkOBYjzoQ2vVceJ0UDwfbJoupcjMcvR019H+6apxBeILt1nVI5OHxxjqRDaTZWZI6g1co1C08niFCCSfJAqGFd4/U3omPTexpa2fcNkKnnFGTQEkBc0+jTp8Ln4iWqdYcfa6ewHLS/ui2KTLjJrbmaY3zwdyQdOpJi4cisiOkZYK4FeDqwRwkmie5Rw0Z92pFuSKZUZOXa3kZXJS0ZY6gTDH9QKeq2ZnYlG1yE78dp1SsiwuGOz2oN0jsfB0a3OldvehwH1vXmnbECgYzblJEaxok9dm2JjenldTgMJUIUcDdpEEMO1UEavaVxJE1+nCSnaMqyLtgE6vzXtl0Ilf9IGYYiyfs0AbbtJCQJfiAmPHNl1LOgS5gv8b1vkGUvobiO6hok93iz8+4sdU7Rt6n9Pqj2z8ba1rryC3yqPkEs6oFHL4PKlGM8aE51W3KKBZ/FEJHUqcNfRjkDj6NPopodY15iO7mHyUPRBOXDb984eiOgOgiNRmj05sZI91F28tGUy/t0vcbw5+1V+1h4F9UVeD59hhQ1fFEhRH06i2gPn23HEzGx7C21p4/XGponS+Sw1xIdtnEG2tYRniaxrhj0HIm8lYhK+PBWg2mp5ikWKm3zqPbDAwcjaUB7zTW9zuIPNZyVnZfOusDJCzBfn4MXzAIf0wrHFPsrLQXCg9ZSt8WTLFRpkZnY0mAzfqxSOVPw0LVYeSNntnUEObOuGFXO4gnYQbI0TPySZJB9d9tTGjCic1imxTI8Sq0GGcEXeIOb3FrGIhnDLxHL+RrplukiT+sUZNusyeguWmmxa7aGWnUxgEZ9xUK7Bmco1/+p1TK/ZXPW515qmdxgSf9FHqciZPGK9CA4CPAbAeFBPavbipOKxi+higQPuc00Xy63of25mp4qr5tSGfUzKdU+gmRdb8A3+kYNJShSDWigqZcRaejTWXunI2URHRSJuq3zPj/8uzAVMOB5P4+T1t7VWBZVhcQiC+cyHtWBz7aVzxysmpAA+EPgu2GtvPsEH2EWfMfovijr4bra1LF0Zwg8XuOGzdx6SN8zckCU8haBQRwRFfTvwcUhBGJyWJawnKKtCe94m274wT+aNsdF2MUO8sjbR1Dps3/7kM7v6oLqyoL2qkK8KwqXsMuG4JEnPL9N75qy3bF2eA4qX93WPPGke5hmm4qt8MpN+vyGwnDgWG+O3dVHEkgaBR/OwfWq9r8D22hkn9zAinSZxeThT7JmCRf5ZYqaBIO/zT8C7BxUFb45hgrqKIEGPcLRaXGV1to0SnFamSSI/zOsQXeDT2fux2vsA6RCxSdob5q5inzv4ALmSCUfVT/SZXvIEoStxfKPIh+fDm1TP0qw7ux/oe829dFW+4mZt7CRHxd4gYugX8q0KIlWDjpPxgO7Arq0aD5zoV6TmxW1IreXbYbrIJhd0WYau9ZbiVxUZxm4q4YW/S9z6FuKtqojmqDJzV4QDelZYafgM1zdwLLXq1lx8/oVsdZ/e/2TMF0MLL4tQ7wAaEMMh0rv9JXaF686WMntmnZC6I9HVVUkKSFMh+PvDWzgkqPhNe4ON7TTfPmq3aqqq2x2te3M4d2wFBpxIaJ5ukZURqz02+v/SxioVXPD2fCmuQ/FU54VOGkN28JPb968e80bYl/zNizhFY5xwMGMJ6BKwFIULUTMJfulmyx8wI40UIX4Js1r0dBL8yRdg8x6KBwGS2MR93Boiy/5ANdYy+e19fTZdKK/3iV2ZGiPI6GJYr++pbjTmmmv6Vt9NizLVDAwrCebsk1ImJTpM9fGVnGpdCTT8qh0vmy6wF/3nJtTKWGjWcxN7dGEmU7Z0q1K2FkjMVvFzfoRzaZ6JXNq0xeq2mzs3Z1Xnqfkuerr7n8lT8vBZYzMQrpwsKINCdsqkM/PsvohTMCn+nmy6UBXZWsYs4uGsGUa/hn5MRiTe3pebGP7GZMdwgyMyc6TFWP2ERYzMWZ/SGHUlTygjBk3Zyb2bCjgtdeMZA/FY/ZiJFUnJmAhFV13Qat9SKvWDD5ao0nBbsBuNCmslIykqyRjqh7eham0bUgYzJJxg0jTSboLYfoq45FlaMFe7UegSf+ju1WPrU4LsshquVAm6npl2z+ZS0iEM0+il1qzIt0EOs6KRDb96OvPbcddI75JH2H5QgKLDBYWA6yx4TyMNxa1jNfofo62fOp6M50VJqWzFVdR9ebmrMEcGJYkAwsIFTQc5mOfKZtxWEa3ZqegHMV0XKqcL5su0AlftoJLLTeyPPzIPLrDe1nVGGZg0B3czeKchbeAbIpK445WBixjTBrOhSul+OfY3eo6MgFf6ei8C7vcjqmZYTA8YVBLyooaLejLc8YmJfyna2tr9KJxRNMpSON82nSFrrdVnG25osvqTMTPO7y668YxEwPv4CpPkjOm+d1nWN8Xy+sLiLClOJD2BPsGtM5Hc1UZE7O1XPjXoj3ZPooURvRGXtbIqEPT9ogYBV736JWdlkFL6UIDOpFF2oI9JeYXaO0IJhBl7RxZbSXbKrMJcXfV0siMHJyMDYdbm/YMyGO1Z714ZrmiDxMwj4Kmu8Q2rOoxTTMrLXFZiMUtYSStlozPTtL+TMhUUlrbtM9UnO9AvL/0unkeQ8UBIqj0UHy4eutwKC5iljCWHdP6jP04zTJktfQNGLvJwkenAofenhSidHlQo7vRsblDbeovX0FHj+G6iDtZhGZki5iC7PMbUKZRTKCxTPNltR5SmRxm0VdtSqz2Mg3aXpCebzJOqXhIW0vGr7IKLkyrb1DCuZukWdvGuVZDmYB9rebQph90YrpZePg4K+7Oi6o2860AKePVHsiFP0XEO8WTyu5PwIfKOdkZ3use470eGEfHJTywigOHF37dmFBAL+FDFYNvBx+qRjARK6rmx6b5vs7cHvkL+JjCp48wW982WY5tXqbA5Jw3VNf46YWaHs56U+tqv303uq3jareBTefIt5xnB59+W3E29sfPui1quDIbAgKkjKl7IBcmFhHvlCGg7P4EXKmck50wBHDv+7VjYBwdl/DAKg70MASk6CV8qGLw7eBD1QgmYkXV/Ng039eZzxAossysBRko6bJeZE63xlmEO6X5pF2fYi2WzcFOaDzc86O8esJRAIWQKIxlCgpOxWctiCu30YhllqGEgbeD1yQdn4jbJHNhZeIh+Fl57XtRE1dVUpTLa4pjdOyhqKPiQRrclRNVTSm4Us7u28GbhqFMxKeGubPl2bbWfJwLy1Va4QxN3Uh6lz8eqPpsTF9Nyr9cDSf+1bemORnCACOcINoRSQ4e/fxwJmKcPuOsliA7aup7zIttBjBugpS0saotI5Wuogv57DqwU4eOTkOaQEs6zbFNf2Y/jjwrymZF3K5GBhdBZdw8QLmwrgS1E59GCchRd2ICzlITd3fYiKRBtuQjFlbJSF1iZkdO4pDPxEryXkzFS3IC7w4zXZN/2yfTtJNNASrZyJmDaKQS9qH6tnVrpqr/UzGeZD5smt7U2gYl1nKNhZJphzyG+moxq5hvS/lO0vVpFR4zH9Z8twXmF8UvZiuJGnB8E4xCruI+KV9vCQsqxjCpDSfOj03zpMJsrNi+82sZSSwDlrFi92SHPRtKEdsHEEey33S9mICRdNS1aZ6tOTNHGfcDLFhELtpNn4e875Nx3U7uGPo8U99wSv/+Re8hr5iKS7S1dJnK6Ao++dzkDWpSj20fl1oNZQKmtZpDm37MnqpMOpJW8znxUyvGU3Fv25qEdaU6e0v5lhnEXEzLzJtNJ0iFeRd3Eqaj51EOTrm8u8b98Xh3hwUVPZ9qhRfnYpeYzZTuRIAcgeF2MaGJsveTst0OJi/5Pb2tTwAOiEBdvgcVXP5I6/sNB6nYxVBPxpZ9FReuNDWjUosy7o93t92yVxPwnuU0WHGiFMPsjMkYEQMLmfhFWkvHlL5Wo75BCXuqpGB+HWo1lAl5WjuHNv3o62wXD3+jRcyNkZmqk3Ez2+ruGKL2g5mLqaXzadMZpuK8ZuuXooY2e6QNnNJkxSDOJiuFd3dYU9HzqYxVcS62f490AZ+Q+JwXCEHVy4/R966rJGNDCbwLQ2qb2ykvvc1IJuBWm/nbCQ++bCB2hoCxprXak+5/XBryE5igpEc4YSW5NacnEgumypnpeu2Rw7o7y4u84xPIq3wetn9x6fvd7pl7VjHxBQOtYzpXX5y8AVkuPwVXbw8LSocwISdK58im/QHBvOEFfcZeu4gVDjpisAGPOSTpXZDVrOrJVLazisa2PLXegsiVC1g3ZY5fvYI2NyPk4HJzgIJ0s5ylTeyYzawbwyTWsm6edsJO3nTaUu+pKkS/tBdTATpZJgVp9gSU7Vp23OTLDGrPZjR15FYKC+5mqaibUp8fUmMYbbGw6NkkZohxKmx6sak1o4nMjcS4bChrjM6Eu7l+GIcxB7/u5CoijMIUVqGqMDqn7mKshWkQc7DpDkZesLnxTBwqhTZmTvROl7iTjKkdwQRcqZ2jHWLJyzVM0tvu9v9RXZfpTVNDWxbV19awrLyiBwsberCDLG03oulY3G6Od4Hl5SP5usZ/Xis4Urm6u+OSGhgaNE7Ghkd3ZD5mK7GcX1QChjuFxeLPG1aeRSmGLV1ItAzup9v15J1tydF2y1rW5KI/v8SFj332FcuGb/zlr8UztxT2y/IVuNPkhxNhNXLjISEMZrUJhorjZTzrcH4HZQryepiWk2J1k+YE8BpJTPoIy5erdKXJa+uGR0M4DQoPmlp3SHb3kh74aF5Yz45Opxdc59SmZ3S9uYVfNz7LDZ0Fiq3g+B3e3zkMaztEYwd3ehaj+nuDShBnfMvTIKmg8WyFaDAdksgHM/A5FwNZR7eD42VzatMzut628b7vCuCh9iMw9D4p+O3R6nukyvuhmD11tgjmYXCtO04Y466x/BzeN9f5dhCCrXG28YP7DrJmGKHArY6sqUXmICUETwRR0fdHLTYmqd1a6bEa8HySZMUfDlLFo5hbuJy2Brb2v48Xbass+ZnN9b2wya8vwWqdwQ/FU54VQJ3ZQA4embs45DK3Yd/P0XlL3pcJuUtOaavTAKbmbBx2lcISjTqBzIsjSg6Tg8s4bIB04TEFesfnTwifzb1G64cyAYvqp8qmA3S9LWBQkyNCgByBLXfRvaDs/aRMuLsuBCocv/1p6RFT1dOsx+pLDxYrs7K9XWJWy7FMt8SbZtGmJ0zFLWJnd0aejoV9mDembanuyiy8tw/qc9ipn6VZjbO7m6+pOeCw4kmuehCLarric61tC3WveYRzyIKZBex18qzX5Y5B8rDIL+siebhsbqqkTNuYMuOtOVNFmSgo6rhIgLHZnbpKZzuaCVjcdj5dNm1bx9UmY8NQb2Ke3kXb2XIsMzL0DloxR0kmeZ9YycVycBnzDpAu7KpA7+ggm59V9eOYgEP187Qz3rGj29s0Q1/gtSkJhgAp5ckeyIknBcyTP1al7MIUnKQirE3bc2f5Ia+0uRmf6irKh/h8F2dNUzM9aDu3pWgm/k7YiGi8j0hiPiPWB3fw+qwsVka+09SRb/1pcLeNvrqh6dnOojeTbMKNxLfpBV1vW5jvqnBlvU2NURmPamZ2thP7Mj3TiWS36cOm1oxbiDp9RJPzqbi7pn7jydTsI5R15JuJAcRtO6FuRWbEcZ3fwm2FcTyT7C2Mc2dlG7JVt4J9japSBjwSw+6m21E3gol5cydNx5N7mDwUDR9WKnxWZ4O0RCDNDimt65Qr0rZ1GVMLY9w67nYd3gQc7zrfVlLAV54xTW/SlIgUd+fghaSvXuQpxmt6MEBTS560l63glrdX15h9xvwodq1VZybgSqsZsOoHVW9ruLB/G0JgG1seUSGw4U2vR1ksm5dwq0k05lfKrqObgf1N823TJb7ubNLwqUhAlv4LLvs+Xn8C+V2DvQEqBlRXkXG8AO3C65qmJNw99HzruNo8jgn42DxvNp3o68zIsRZbO9OWznEr57uF24ro/pl2bzuyazslN6dQnRrVgGV/42UFyvrrzT9hUuMi+IzmOyEdA3le1ATL375V8CQrMRtUv72uy0ZUmRj1Jawl17Sq16/aYuVdN4EZeWSwgcvTFUgzZNmD5B4vI3KsEkAj+v6yjwzj5s6UfR8NPTOiavufJEUjHyVdbkTWLbqfYX1fSEfIAJjRGaL+pC0Yoz1dG7VqxRatBpmZddJKOU19mRHJCajhXVGmUIalK3wxjyZN6qaU4uiKbAmiw8RAWJMHv2uSllAlthIwM2oqUZcUJ5MjzW7g2olgYSzmo4X/DPLmFhBy6YSDBjOiNuF0QtavQVLmG9Z6A5IuXkJKuCHExNQRzAIqKSBlZqL3L72o1R0LYUaI1j98Q+QRWQLSnjEA1sQmC61cGDgQI8rjrLg7Lyoprr7MiKS3dGVINlsNExJsdMPLGu/1LmBFzCApQgmcEfkX+FSpVH9fZpbJIsuO8upJIYpDqRUiFQprJsC2o44D2hBBU09guUqrCtlobdyctFccjNkCeUbLcg6yo6a+x4ZmmxtV3YAO3tgYiZ1RcfBQaIfmqliniRIPKbVBBFQY7Hrxe1k0a2UvSKkREXEcynB0XljLlZd6s1yuWSWAZjUreRFdjl3+qL0ldh1CO/qpFMZQaIcGv7mtRNO+fG5AI761K6eX9E1eizVPZVltHhm1RKKiGPscqnG01GN28mEybw0a+8a+GCPvH/+yj515Jk/+rDHUVGnHTWPQJJmWjkebTdyrMftmbIlHslIrKUXSQdsh0iRv1DSgzcHp17BDa7ZN2OB2RirN4eTQ+e583NDYkCVAhpnK2GC0oQv5bpIU2FX/DIh4K7F05eYh3aPtJaHGjdz4YgDMxrf8Qo3UFlddinLY7F3B1ToDclaSwdm6Hl50iHkYa+2gwcmBmE0CmEPEa1pZ4mHMm9b+rol017q5BmRA863UoBkKzWye3MNlk8ErUD1I2ZwqNw+tv/wgHdrmNomJ9yCoED/9gOndvXQhZwBs0X1IkSVRKcSEh7HYTZUlzBOF36AtNBtRQgC/0nx3El42VFYuCWxYspFnhzgxOddS4Xv2qIhfX4+uDSw1qpPVGqR3UuL1ZRZcQkih1XUsiJXz4BOs0SbVNMVySPPA+cAjKQXEODFXtMp1XhUBZ7TUZef9qr2JIp7DsQ0b3Ha+JuqAV95lyYG8sbOYoZaaowEWwjyFZVFVqGKmQcnDWIxeKv02Uo9+1SpDqi0y21DgWesp35Sb6a102Mh9NdTBpuF48PosxfYbVUF3RthC8yewm0NxdaXhxH0Ymfq8UjjitWqgP4OnGqBOLPlzdJZCbtS7Zk8WtbRjYa0GxlQx0M2aWixSCa2409SY9KJmijnftWU6upIra9AkGJMF6XYk1NVNmQdx2fPF6+GcUaSoAlI9PHkFGe2EY1AN0RRYJZRSoYtApX7VMFNJlutDOx4uyUckKnFJPESsMajUr0E6LhJg1GPgQWU0oZdFDTkEVOOyS+/ivz5ar7MULq8Kup8iUbTw6lHpqsmIRcVOaGilxSqhm3oKolBuw582dBugXcbXV4pJswHnuCI3NCwP/NCQTFrBYoSyehEIJ0UrM8Sk44yl4NkXDtXqXfMSokwNyx88tOAIMzIZidhAnVi0GXToZquhpI8IaxyWUEVDJ0utr8Q8thbjGzbbCwKo/ajMFoMnuaYxGmgvus5wkMKpByMDl5GIi+zSkEeKcRKzk2mZDTVTMpS6jpEBlFU1LGZPRmMjEpJqsUeiq1lGpeBuAzXLahghpxFZNqLv+gJWdYmYHi6pgEKRiha11IM1V5bRVAhO1JDTogXZsrEZcThZ6cDG6yEAU0JJKaBmaDJ4Kb242EsduaQ4R6ZQn1dMQxseRD0CDlJGDyrIVkMKHtFERODiYNWkYAHN42CnNpgsLDoJcfRc5+OH6C8GUR2VeCJEKI0DQQCWeiM2kd06Z4SIS0IVJZFDCHKcZhnScUOAuIYqHKjFcNgaEejDIZyISF0Y+OYaoIZKAqx5VHwVHZ02QesW5BIQy/SQagI86CULKt/c75UQTV9BPUBtPRn5FGHxGhrqm5AQkgrfDyZkf2dASzwRSD0aAVZGJOoWg4YwIqoJiHFSrMhJyOYyhZweApx+HDx4sORJkUrooyS1/9blAj6m8OkjzNa3TZZj7cgUaHYxpprGDYcBQTBVLZvRaDdVMx7k7i+6aGVTBFKPToCV0Yu6eqMhlIhqZNnEDfb8vrkBJKeHAKcfBw8ezEVSpBL6KEntI5tFlmkZhQXQiAANJ3UWtLehdFLEoBiZMTb3uK7b+1jyodMg+p5TkKrhD7fKDESgUcncIjJKepLge1ET+4FkU6fvtsnJoQLXj0dRK1ztanAr6KaYAh/qcfflrrkbexIC6mtoxqmtKOU28cKfjo56/JplqxtrvN2ekYgKSIutmZFojlu9yYmku0Cp3frZVVQP2aq+jKKGK6IaKts1OfJ2cbhXqqWuBEo9LhFYRjf6tquGSBJkU1CERF2aScKBGYbBQiuJ0oeCmqjCoZuCLNf0xV0FTWgYwwgoUAU1gJkMNBIJDZiLyDGZo7sHreWMFsZqHtuxxOGJFpecGAJFg5QGfZ1cpzYoOBtZp8YSQ3VQ6FQcIiewB23aBJlmj64UTj0YGbiMNv11eQ1dpKhG9uK2ber0KQdh6r5Oi1rTYCrdKcstcL1Ji6QOB5NXUA9LW08XDsYnMLCIDZO3oYkNG42SXSYISzJKMg+bx8cmHh6BgGyyYSMz+4og8bco6cWDGORnA6mUQrO7jMc0DQk0YSUikE3nNSEkzoSYJlykzyByfY56fA8quPyR1vdURhCRNKYq6sEZasrIRmU/0VDNhFjFTrGci7LELteb5CxqGsormAcqraejn4Nm0rchIaVyjmJR8hs9odbkZGs5jpepPCZh2YZG13s4P49B9VMgBj21gVRqvC5ZkEnjUZjGJIEkoZDWHNXCq4ekqyajlCIfkoZo2hZGtmNlbRsl1FzJbbCeYuOI13euPOM2yYGYkoQchHpcLKAq9tJ8BZLDM6Zg0gm1rjdputREYAHNY2DgdSQxm2hylLLYORWVvbfOfRys0aPAA5r2wBx80H6axzWyU4HJnmbQ5lJInYKQVZBrBTbHm1brSJGOrLQ3nTezkBLW4qzIgpEcT58mZic+dd41nUJbpo/U4DoVoqwl101Cyj+tflIjV28mmXTi8amok0s1sMMgddIZSL+pZFRoWOOfUMI6jEvjrQik2DS+CzbmzHxHiAPUhAnI4OPGzk1LInliSwuSGSoaB6uvr7lqpUzaaSawoc2Rr19pMpVeq/KLSsTbA41GPt2xSZWCPmurTkF4dEBmUNsxRXQ50aefdRUeLTZf7tZTeEIx03bEek4VTBWQPIBJ0qucMgbMSAIaOjhzAI1LraPa/seiiiZnsG22BWsURgrYYtJQWp852TwJ1l2YLrODrkvm9dumdhBVzCv5mHMyqRGl6wj7gJfXdDAogqhCY5ppYpguSBOlMQ+ijTVFHhLiLxYesuBF53m5vm9da75a1/UevNZQHYPaWsOUhxmR/u274IpCh7nQ43Emkxadwxz1KX3dJ0rfA/WkGbkkwOi0XBYcdb+tgrezO2dS1deXYLXO4OZFSTV1OEjzkNgKwRTi0I2cgXZ4SYK5dyGjjwJSPSB5BRl96LcuNBRSIJzgisimZc0SLwLZDEWzjDuTZdKlmvLztz/N1o+yilEqVDU10qY5YnBqYWpiOpHRh4Bjkm4monGP2hpO0VyqOwxejcWK1OJjvi6U1zQ+1Smc4pEd7WGcsY6aBKaq0kwXyieDdLkdTA2NfFCnal+jKExV3AerURpRiTqNAhkeGDJaPQpI9cDkFaS5s6gnkHTJs+QIJ7B6hreKrjXhGyKQZig8rJQs1PNJOrIIuEYO1RAeIDJf1XRVaepKyitp9hKnQT6yAmOfWbo+K4uVjnQ6cN2KqKwlX365x6G0i60a9bSkuyocCEcBW49tUycy0SjEI5OMejfrWnhDS6bg1eA6paysJVf19MthWmWvxivTb8IzYlHJp2M2KZzdwHQs5kWpycIapQ99XUveFpOEOdrW1QQpWqKQxg6pXjPTBUXaticju+RRtgjBt+xLZdeLPK1TkGnuAegqqEeurSePyBXeWdMG5erQj3slRfqO3LX4BpyZmMq69gNXobAhse3VFcsWJVQ3Tqpvqkz6VTxznkw5tHrI6krKDJn8Y34agmqwj5xazLQiWa5EphXIuPKMseL8+rZFgEM7QZrDcij79S1+fHYFug+/vkUgCVzXDcg+F0uYVX1B/0rzpmb35dXlGiRYnf+Py9evnldZXv32+r6u1397+7YiqKs3qzQpi6q4rd8kxeotWBZv3//007+/fffu7arF8TZh9nW/cr0dWkKyhWabK8VJr5fwLC2r+gOowQ2oEMVPlisB7HIFyvrrzT9hUpMY12dOl/w6ULlvsH8Wjj40EmcOl2H7qK+Ff3cBlLhF3Gv4Bnftje5obEPRMzRIrBDIeKHi9EqsjhBcIuEBZS86XfcXS0SOImtW+eZvnv/UtfG/bP32iz2GD5B6bJVGxBQ44EurdQZe2ky6HEa2yBlnt9JLUHYl9hgX1Qd4C5qs5oi/+Szi+vUtxwE8r70VmI3TADwHW/K39EHBMEaXoPTieCs847A+1TiPiCuyx9mpMMyhokAIhfZ4z0F9zyJrv9hjwA+S8sPsvzkIEpp9ToDIlykVzud0Bdv9OI1l83VrBG9z0h4ia6pYAgvxUlcdR6L69n5vUg4PW2KP8Vs1xDJ8KzMWJ1/m3k8BZSC+4zQH+DURGcq+zB5rd1FHZHWmwE0D5IL0bb7aY8J5IPNK0G/UZ5eF9AtOM84uouSTC46rEqCWydaTxUQVOHDdeokfCv+af6sTjueYkq3RNMxbvpEW9rDlfCqVc16maBtfc0K3+eogHmWx4kSDfHHDIC5vm6/2mK4KFgf+26W22Iv+mz2WC7jOXviODB+d8YhdYgoc1OIJpw1PXGofJ5xEkw8OBl5DNpicYdd/dOhHseR4tv3iQIcSKpQUW+IwNryotD4xZnSbz264JF2jPjssN9Q78Ly24MucerjEb96BLHsROkmVbI2Sp4capuVpTB5qXl99HD3fLiri1Ht4AURNxBTY4/tInpShEbVfHFavouQwtF+cDORSNOo2X122mFX1VJTcLG2+OsxVDm4yeFnx87X57LYBaD0qSKstETemIKuEwcpAtkZuO/9//3ZkiOAyqDwk11B/JBONbvTypaqhxEpSArnsSpKsWcIlHci0WFb8HkUB5NFO+0yjugmq3B07+4yoshEJmMsOk/SQ4ML7ts5tzk+3BszFa5Onq2ZFHK1HqzaNMOu/EcsdsINnPXZJuT32tkb/kquaUDq47VFHxtDhIA1lwO6jtJxRjqPHNh3g8bAlDnzVD0RgJLrAAx8JtVAiHUpdPCznJbyEGcQPGfM+FqZoe/k8MmPH4OTpvCSkYR4J9dlVDBQYhUKX45j29JM/iem/Otn5ibgEbL66YzqHZYImlMRZyHDS5VMehVzeo+2C8gBWLHVyFiPVSsdfcU5jrtRh15Qu4dV9s7rJhR0dV2SP83tapTf8afHw0UFOmpssre55FUd9nvPMOb7HZ+cc3cMtjgiq3F+BT6y28UgUqrsvctmNlWhk5HkhEoUlXRcUMM4CuciX6WO6lPjYpAB7ojqbLFMiFgodrLvlKs27p0g5y44pcecvuEL6SLRCJcVO9H36mn9Ee+xzYdnkyxz2ebAG/wFfntp7T8wOjylxw6icLaHQDe9VWvOLEvXZYeazrHgaPBYkJyM3ejmEQwvrdVk8wuUFwA93XjbcSZik2EFWi9qAXg7h3vurogaZnD5SCK8xqBtRAjkfL10VRwlnG7El9hg/pau0xh0iaxnXY6HQoacPDddB/MHFY5M3tyCpmxKWaL2pvyCzjzeUVDD2rfyOuInF2X5x2flu3kZht72b7w796erIlnS+zOWI9Y8mLeHX+h7ncujvubJnrTII5xY2xoAcP1PuIL8N0lsAvyeKzICj5ZLDxsuyEdopjHNI6sLFcQ7f3eOA+JmlvzsY53nWiieVsYUx0SXlTh7TVpy+3irwyyHcqXH6vE5LEvH4AbxUcsrwMO6tkBtdBINMttRQDhtXUPF5gJjNq1jsoE2ZmnzvxVKnXuPTwKO7EkLRchRL3Y4eh4pXONxeOIPkil3kcrg+wwsmVeCiv7pKJy9JBj/B/I6Pp5VD+LZwDsu0EOZRBePRCjEwCBpBE8sgXCiPj5Tas1pBKTJFLjjPEB/0R1U8UrbMZT+0TLEkg6yvfXKP79PweyMVlFN8IXg+fUb7IDG+cFPggu+0EmhLPjkEeYHnE7QpuyvwCSMX68UWOdlkaD+2yB+RxKLK/ZmiYJTJgZyi5JMHub+XK3J2t5H6R48gzcBNmgno1VB+LckHIYdwOivVYBdLHXYDxVM79u7+Mz+5snKnXVJ6+0K8EWdF2ffvGKK9qbBTUgM6HEWA5KHAXlR8l004iuALHffb6sQ0wsbbPoeNuk3iDe4OweXzLodwbaE9CNe1wEM40g0uu6pCIKGk2Enq8Lpz3LwcN3Ut3DUTSp0x/0ir+yytag16HsSBMq2uySBi93O0DxMPBeQQDocDaDdEqqYJf12AKXEKreZROeP4mi0laDZfnX2VJ0LMHVPgsAbhXP4gk/SOLfHDeFmDEl9XhTjDuhgFq4X0a/E0X1q1x8M5cFjnXjzNcZSIjNFkAM4RQgwWKGMfLaBzzJBFezpAp50YnZOT24bp0nWqcaL1GlbStOaScRiBncYyPJJ+tF5nKb9XkALY4/8B07t7TtD7bw7Ukezz3Hd2P9Ilj6T75EAvyXg+Oo9nWCP06kUD5tGWTrEogeY8Jo96iA8zKEQ8DR938+heM9bhURDBf8aVuYf14KQG4jVrtszF8q9gt5xJHBViqQfmzxBUTQnbdOhS7AyERwuyQFWh0AMv/qHFTQO4Bn6Rw0vR2ycUOgeUtS/cy51EChDPNjAN9E0MEN6j2DwyqB0JDbY1QTbDwh12b72Pt3MPs1FXHSfOBv8bFk3S91h69sCVOXnYVZGHXNG2hDT2tWXqhy9z8Rd2doy4s2FK7DF29oqAj/7ufDpanRTNGgf9L4WbrmK5g+2gwOqHrZ8FcvRPjH8Vv7IQjhEH7Rlb+7yYEHFAF26N1utc5tgtFaL2es+7h9pTV91WtYej2UQsm68uxmfcLFLHRY0260qskmIXN2cKBNcm+eTirmvnWhV7Jys/hMnpcbVhq6pTMbHUAXNKgpAElJvPLr28g5fpv4T7j/1Xz7DA6qpoL+HI8Ztg3fv/VXYcIhQ6upsvQH7HLxlMwdwBqGM7vnYnAHAb3Sz7fedCTT1y+/17Cp8+C1aiULg1BlenPQPvcrRIfO5yqGqOY2x1zclShHFFLicmrpnwlGoHFvL0YEyBS4TLIauXWO532SmOnDC4/K8+TS01ES+uxjTi/BeamX16nSsiPAWsBGGAp0+LZRzW6ptWuT/8sFEDuWgyqEp3YgHuFAYg97gxBQ575zTLsFe6z1/CbZ2FUhebvAvBlKOWFLs44dq0G9iaZbO78M44NZxPa+fKKxEyCK8W2ARCqlY4KJ+W+gmQ7u00YH6zRJSBbnoGAAfH7nNdAjFLMfV5e1QydaYaqIspTD5KWFt9W32PqG5RfoTPJJsJ7xlnipyX9S3JPT+v2RnJH85i83GLGzFsv+mp8kn6eSMX1RkE2GbtVxbhRgVfvP/cSl8VjcKwNEJ/ptVj2X7GpfsvuQjClB0Y2IuB43FuIMvOwavhZkDsg0OaCqrDORXM4YBOj+twjLZ7x2iH46N9OT6aK66mk5bu1ZIoxlmbWcXfLFPV336DTKKKndVwO3oxhpf+7oCNZOzhMHXfXC5IZOvbJvsvWJF76/xNCa7QGe+XQo12KIsvMgbuXlT499fb/yYEkbEy8999gslYFFPxet+ssNOlvjtsFNZHyyVaWLhlh/rssunokzPxu43N9z+nYnfUwcdZcdcnm3PnS23tkXiybU5UeEyBw/kIGsJ5UYnJb6nvs88Ss9J1mi7HIhO4aGpRjbp+tu0rVtFNoT3eH6DqRsOipL/PPo9f4FPlL23a2uNKm2iosCXzyS8miiyNO/199nk/L7Lse4HNqAuY4AdYPOTWiGIkeUXtHuXVk2gFsCVbt0UJjPxXvB7uYKxNbaWJD3WyJU5XlSK9QxTjpad4bxn1dc6KcgUkiZL5UnfMl4B/RJotcXBkRU8QHDvx1dHtbZqlEo8qU+CAD6cp4l103bfp3UeLqo3f6Z9G4yjGFTpEzSiCiPyihT4BZKHK91Vc0Zy7IdyVT8Vdmkuv6Ymlbpj79FZK5ALA1qxV3ewEnsr3c+y+VClrjrNSnaVlVYusT312m3kR1ebrtGsUUsdrkL8IFm370QWPNJbOLz6vRvyOvj2meSLoaKHQoY9CqrET19RiLdu949e1/qszpvdSTO9dMP0jXePtPsjEu7lckYNVcF/kUJYLmylwkJ8+iS8nP5vPU2j5uex6IgPBN3pbSfIx61U1t/UwnRxvVl2Er+Tkc1PkilOe14MvczgHeSo+wbpGG8mqEMVPLHXAfF9CqMMtKXeYowZtrtJEipkv87g1+B3In6buSmY6no1+rBp6KD2TPmIf6wzTSiwuD+VkQrCtOip2wE987lzc5YjUbZpp/uSKLXKJa5/mcdsxnoSdS9poezVQ2GhUPrKmrz+WIz7exiCCaXFzU8LHFIhyy5bs2hI1E3P3Z41hfN1j8TzHlVcdh5s/gfyuwYnnOSz092nDaI6LJbepbb+4Rh62blnpg15DkQPOLpihq3sieiLlEA66YPPMlboRJZDDHIE7jijtFyd3xlbnDftzRgGPFVG6c+6JXnWF6fAei4cOV1fdVuO/7/FJk5E0BNKlYCh0OL7M0z8aeAklu3KuyMH1loG7xQr1ByfQEIcuKXYIuqw59zP5ML8M/qltsvZu6GVdkoiLqmjK0H2HDKOPnFuh2QW7re+9KE5siTtGyTVirsjlIPisLFbnWXPHvz7JljgdxBdNIsgV9XlrpKCPogrj/B6LZ8ybvOoucHiMnQl5vZozeNtPDqtXk3FLTPtlnrVg2y35w05O1872Wfx/zh3ZXFf0h6jPwMtfAx7PYFhV5XHWBdyiLAB26j1T/4jv96LmZY8r2mPbHBM+nPs8+W43LZFwzmsDFDutKYtdHIpmsipGSRFMFvzfG1jVyDrHkiWxB9jiOQ8rt92y2tGjfvoINs61Aowp4GqBvPq2+vnU70X7vhatCGT3CmNHlTpxE7Pv8mVTB7P3ceZkvqUR6G3J2OHnc63zsFylFQ5JaO88Ba75HDaf9d+IYltlMO61gyF9G7tPG75uDQedPtf40lJ21NT3qNE0IYEJMbhJh9mDs9zQjcNlca/7xwir76myWGKa3Ka8nSQrd8feqXhTIxIw+7a+4om9Kh4g5zSgvztiO0oSWFUqnEypg0WO45qQ1anSF7LyrZH2s6JsVuGBNAMaDznW1B1HaK+KdZrwKIaPcwm/eL3b9V734lyeLeR8K2607VziJsKXhC0iyAbB4yscisrjSAdpkUcxfJxNOjAJZK9LMgXONwaklwUcnYut9uT9it1Xe0z4hRoOTffJxQFW1bLMLPR3d2yqmZSVu2MnWbeleNuSg85y01kgXFn56qlJVdTvZdGspXpqKNnlaxlfhrWH1yz95zmUFBZNqfnEFBwUliXPHPJtjmS2ERUQwWwjeHzVoaLytvq7tv9i2TZx956d15C5CBOYdjrdZUVRbxwxIY3JMgIwBY74xDRS1GeXo0jJe0AebwDF3Xl1V947H4KQ81EodTl+bo+xFKglxY7zgq8dNgJersi9v3K0YqmDC7F9u0qOWCh0xttecVb6J1VA7hx30pQlzJMX8RaBHMKlhbbeBeDjCdgS9z6zB5YqmRGhHHb2oJZpHOqzK183NzVO2bzIkwx1TMbePIRnC/iCs76FAcK9BZJ2enhuUDcWOWRgi9qxySFdW+xUgmZsPIRnC5qx8BCeLaC6ouzJITz1E9LzKbYxQXYGoZRkFuAx2pYS0wI8RttSMluAOwVv4CrC1dL+qyN/yLnOh9N6aZOg2xS59k7Mek9/d7kmc9vkS7iUPTPKl7lgfQLl8rxI87r6AUuI5pYP7FOAOKxz9zB5KJr6qK7L9KapoXKfp4cMaLH6z1VmaKoFcV+9VSGfsnKHUKTIeToHy3utsMjXzgGWeF+AlC7a+CJ1cIJYRGZi6CFdglfKpRjqtfnqhkk0QTdfHTFJxuw3ws+geoBLPTVVMG59Pnl8fC/2uP3qhun0eZ2WJOjlc5HX9yJSAcAX/39BIKEyX+7HwR/SEib1B3iT8rd7VEAuLqihWpd39mORSdxRKqiQlmQcpIbyaukY5A/iVksK4I1fFFYpgB/+xYkaNS7zwtpnHVRhHsq9sC9uAO8e5Qvd1wVik0gzV8shHCStQTZjmf6LiOlVCfIKJPinsLBp4MJbE5lUDxne4gWsGj6vuAnWRTuucYYFDT3lECEtyEakhnKKhBisPM2ANGAul1fK5B5UUOmFlQK47KtS+d0LpsDd49flCJT6+/oyd6x4w4UTHjd1u0ZrvXTWlVwOfOLkfd+FYxl6G3UBVyDNhZsVChD7Nj6C6gt86jbrXwoc8ZpI8r1pwLbmOKjfcH+r0N7pY1rV4Q+hS1D65BS2QzPO4dHggeRlhvru6KCQHk44LhW7lvfp9/SW7J8iMpcEpQ9z2aEZh7n6tnks9HcHDVrB5Y+0vpcymVDohleSKob6/Cdg3Di8GsCfk13h78wxilsk74apody5X3YGx5c57A4k3lp3L+2i6ntAriMCwWaSAriPHW1M17K9kqzcxfJJ0nWKTQ3BpuSKPHBKbizxZQ52Mcyx1S+avtR3V2ySDjIFDh5CWFXCLfnhows3bchOjD+RmyQAe6xVB40RIfzIM2WWpu6IYUi4QUXo0KZoenvyPOJz3X9vAKEyi2rz1cHwyNP6vEwT+cmwWOqBWXruK5a6UFLVX9++qvvp20fpgbPHsXK/B2qXV+mgFSC+bUjJoABxMBmMx6Shx6OaY1Hv49APxVOeFWApyV/GFbksVH1VpdkjAXCJlE1gXsEehxCsLxY79B3pzx8wvbvnXyGkvjuEQDb5MoN4leGCH6nvzvr1BN94lWnYtmC7lucvJEFW8PKM0fguz/K6Yy7P4UvpFyH70Re/hEdXxfBEriySni7eY0uR9tDG8RuJGH3cRlZYxuHUuLHe7RA4rdR9c8VyjErway8SZEORm99Jtpunv0+/l9s5CcKnSG0i1hCp6bF4vrolr7rdmvyqBMkDGpjs0JIvc8CKwxBldgpT4HiyCOVHoHyZ0zlh+ghL+WvBQuGfQHrCnRU0pgApmtJlMbQpOQfvv3s4QOSy6ew/dnc0zGbD1E2ZX8A/SAbMQOOFQuVltmjrj8RGkS65xWaguIZUPL/XBQRVkZ8VZTtbvK+dK3TBS6Ydkr077+IQCr3xqiM5tIDu8yZPPi+WunAquL39IiaNpr87eH2WqzSXhvixJS6UpsRXfnVQAbKboT2zLfoF+fMEKd8YCz+LzWvxN6HYbs19DsrOdBFvutIlrv45GUa2xMXY2dBYdiQtK59t0x7xvGYM33Q/KsTCsIRLclAhHzcLMcdqe9B3Pd9crmEyRCZu5j4snbAOtU9uYTd846jFmOInH8nXtTQg2wDreBvnLM2Q8AlBsXyZkwp9+pp3ZFC9L8AUO3vFd+f5Dd1kBRoUGsw+xoUTupEMDWkf7Ph/8qRJ+8GJY/BgNO7boRRau8YNnf4lD0tHWNkRHv9lXFp57pmed16+gzJFRuwgCSfF6ibNQfiqYcbvP49OSEdaQR4abrHAHxwicmv+4dL2i8MJI8ibW5Dg23kl2tZKbwOrYBzDwSRxYE5hODC/4y+P99/ssfxIlzyS7pPD/SnJQdhH92AdUEFCBNlxsVDogRf/0OKmARys8KpK73K0+00JRyz4Bxhl5e5neDhFqXB9iStz33jjIEkeK1/mEngmewpo83V/XCNIgyYPcu8FV+S4m/va1F9vCYousaO4qRNBtn31G2XJi7fO7aLDoauk3GTJyh3CG+BzjT6Jj45R390uTvzRpKXsvkT/3UOcT4q8LotM5uVVwez/hiCuzEUQtsml7ChLgaA2yadJN5SeOZm3S3GTm6GjaO/2zmk0Fa5AN6oe5/ugUMEysF3jZlS3KC//aEAJq4u7G+6AhS903AYdLf/ZVLV4vC4UOmxqyOZDhVgsdVnLzkt4CTOYSG5VMEVTrDUqjEQcZAsjU+By4yN/wMd7UvtFKNzD4K+rFO30MT+GKcMBjYfm09TdfnM1doZ0/BSs6hC+L5vjGNrFrzPXOUL7gkHQsQH+6XNKIK83t6tYGQFQcu4C8sGB6avsNAc3Gb9Q0N8dsMGkKaHQJ+qzg8NOfFToo/OLQsVdMbi0uBWBLZpzJfxYr7LjYvnCd5H+7mIH5TVi7N7v9gXWT0X5wJtDcpjtUgDdpwh6oAPzVQfK6uNohbZ5HsfmqysmUcvQ38dbIOeyg+7hCpIdDVJfgbYQjcrHHtLXH4d9SKOcT6z9NOXCJMnj5JzDaUcY7hgkD4uceLvpRJZhrKdA6sGE1phGOi6NFdkb0dSPGyO7c1fN6LPhK7hCRkuoL1aG0YNV7dBsqy2OX9Q9B/xJ9ebrHnv2T9BE3RXlSxxu4rF5cJIZxYGLto6L+litKEzEIQsIHTuw0O6w0O8wh2WaRDpi5LH5ZNU0otj2TeR/wJf2sVkG0+arEyYByWFPIeXjoyS7gEkRmg52QOPBuZq6286ycf0e4zj0F9VimQlhaO23rWHDb2UUNhzQeLChpu6fiw0vs4a7P9V+mSP2UfUymv5FtLmcyck9XDYZvALVQ6AzmcLk40zWVt9Wa/ISSV/OBwwPHx38ksIbb67vu0lPqnyOqepi/TU/LcuiFOyATYGLNJAECGUtOIDYEjeMp/lSiq//7ti/JklgVcl7SJU59lGkIfV5azTA8LJioDXVo/GxptR1xxF8xcPnXg+ex3rMR7b8qBefubyjEFRNCdsIrEC3KI3Kxx+qr7+1KwZ5MQpt7p6w2cZqWLbIHucFvuPF4uo+7bE3o5v/Dylqsgo+UuKx+TOkBsWBJ/ecJ0+asoR5Epoct0PjkxFXXXVbma/vsfj8ClvixHr8eyvuOfUxe30qUKHwCCtT5OopOSvKFajrlE/3IZa6RPeuUmRsXBVdaCAX3csVOpwqNzdZWt3ztg31ec7IsG3KGKQcdYFfM0SbEhKqxQ6bLdoaFYZYsFnFC9UQ0HnoNAsc4yg3uk3xvRixdK4gC0IgHtXw0cELUazThMczfNzjoI/zkryi0SUiDz1bpXF5Ha3qEYzE65FCkc7KYqXibr7MhTNVONkSJ9n+J0xqQaTbj25XbcVLtq7Xa4Hkai1wPDLpfA7HL+1z2zxCodgL9/BCmhI9BbHHGoN4ZlDBpyIwBptC5HUOqak9ku9s06T06rZYPFvsoSzpr0e+311mTow5GoOSM4kgJpVjGGlFG8GrEb7ddT2nmS1ocbUG6V2g9d9j8QpSVFXdVkdGLIsCX2tikbRf5twah7oYZvMRExs6Uhw3i8zLQ2zAsK2sfZwk5Nne7oCMZwBJ8S6KTbwQkJYaCXkQUwiW4crm9/Phd5nx7QKQZXwuLKbEwUasa5DcYxl4d5aKgWGSYh/c7/W434fg/lmP+2c17plU3Rf4VH2CdQ3LeM47OU4PxWeLaCT9J21ddOjp4BxlXyLy48UCTGcG7EiA8Mk9TB6KJlYyLQGdjzlrxrGti/82J5Mjb+vhvVN3H0WOWw3l0u8r8Hz6DAUyMAUOVAXP/T0swaXJFjktX1udWi+e4bUtiiVCgjU5zhgqZtKkakLrgg9PBjClHjskKwuT3tnebUyaEr+Bcg5ecKux3p+WYfV7g9oS0zhyxzfPY5OV22OP9YrvzrnQebLF5bYIbDaZXn9JMihLVc8UOOI7h2VaLIUVgi1yOR2uQUZqc04RpsBlm4OmT/6WM1Myh2spVrj5Ik/rFGRSAefL9ljOSRxf+i+S/xIPJHRd4fH5rCgWOMaR9dNot/v87sApsZFgS/lda77MA6sCoTsuyR1spmBruP4C4vOHPudr6NpG4/Ja2fQIxuH18z430jt+I7D57oHtvQLb+7220U/KoqrQbiSLwlE8Np+9sBHF/nLVbCtpYCSUXwTUhJFPqKlP8BFmwqJGfXdxXRZl3Qd5cu5KusQh9LLJMilCpsDBRFx3B7oc0Taf54rsws+WCpl0h48um+dbWJawFHAxBft1J+GsxK/S4ytCXGzu8Nklwo7kyv0IKn5zSBdsjYpCH+o0OGlui8QnxYGq5rae/PyJcgptzlxCd4DU6Y1PVlxd7W3lk52zV8mdlsBpxih8Jlheb5ypbeNcxQmmv7u4jJKsWcJFfpmi2oDbiIulTgcdoKpwMC4qqOXHHSKAi73QVuYNhv6rg6sxrfkbod2nKSPVPsMadNHLnHHGlrhhVL55JRS64ZXQjPo8f/zbBcyRejqqfqTLO1jzhiBb5nAsSGr8o8i5odPfXbH9KMG6M61kSJliV9xo1/EkmSmh0BXvcYGVPy/QfJnTMS5apPnHXjZfHWUZP34tijP5Ov1ydVRVRZKSF5uFNQstpSRm9Ppovc5SzOmUwaJZqPT1+OWph1YZIWiNXIqrv7KB68uiKaXPJVmtdgNq2bKHiTn0JbCbV6DE4u3ZzZ5Yjt389a10vkNYYvC/OTHEppaKHRRuNCsy99i3mheGToZxQodmakYgAW7oT7Ss3hfL6wtY1WWKjaQTPEqThrCpLexlmTotoI2yMLcVyCZcAxGYxaLLgeqjpd7UTNO73q6paxu6nDQitJh8poXp/YNm2opYA6d/QBhh4iWdC5voDs9sE32cZhn6PLhvLWabr6Kacpe5ZnEG0pRDFnPaOdRhjOncMWTIL1M8n68W1Zcmy357fQuyCjqOPph5zmG5Siucz6zNNHxNZ3XW8pCpppD3goOnwS3YS99c4OwJyCPwmaHDgWsKhWs2fWPNKqoaKm3jyBpy9Nu40uwLC1zAJ1Auz4s0r6suIPb6WwWXP9L6vnMG6yJKjJXFGBKhigVfGBsKnAEWVwQ+MXd4GxcpExniKZzeVHexcIQ6MUwcDmkgH/HYYmocHvc2MpB5/OFmTrdx7/6/And620YGLibyIoUbGBsrRkQcarp4uSSsOxfFX4IwRV+hel8rdoiDNIclDzI4c7svw99V/wFPKLiDn4slzKpNPfxUwQqQEVVrkJAd/BKepWWFQ8PBDahgC/L6Fer7Y4q0Xn/k1jlc/shOsjZFVg/wGeTpLazqq+IB5r+9fv/Tu/evXx1lKahw3EB2+/rV8yrLq78lRG5Bnhc1Gfpvr+/rev23t28r0mL1ZpUmZVEVt/WbpFi9BcviLcL189t3797C5eotX71Da4Xlp3/vsVTVMqNnnDo47ea5f3v9W55yvPHrf0CB0/oZvoC3r1R65Ne3fMVfJbyFu/Db6xRTlkgjeWGKRJcCfK87x1CQ9Oz1K6xu8KXQQeW81aJvT0vbBvJHUCb3ABkin8Fzewfit9e//OSMkzlUs0Zdl2IIhoCZTVM7Bm7KjutI7jh6nDTuFjRZ3SO5SU1I6AMWAwPCBi7bXBtD1oY94URqbFxLvHj/bZEv4fNvr/8fUvNvrxb/ec1U/rdXZBL/9uqnV/+vczc67YhZjGZgH05on97TMOm7n35yZtM+RYcbfdpaKsJYiQdS8X2raCw3aQ7Kl/+2As//3RWTUeW8/8ld53xOV7B9XCYIsbUkfiie8qwAyz0Rvn44bVqQtqEmT/9oYEpQ3qZYKaoZzV3O0Papb5SEo9rqSnXfKTT97HvxZ4/vmLB4HJ7v4hdkHOqFD8tzLpEjL2Snz3X3tkMMbGjHA59C5nNRXZUA9YdYkhQaCzU3RA9fU0gGrffOh02ZeOS2N/hLnWLiB3fJvEL52AZ7opQ20S/+azBOzmwwFN0XG4zUwnB2XtuviuhdvSrG6OgFXGcvbr11QDtGj09OYmM8TpLYKIf8gJFtxjYQM4JuZ+978NrQ1dLGC+ImisNPvjESY3esFkEugaGbfc3WDtuAMNkJo28h6Z7uyTrRJaLTGf6//OJuVrb+APNuhcVtw2sfi0ov5D79PS/KOkSSkEFeykzK8I4NAemREbf5pS+roN0D3oe0/hqk3AgHolojyF2X4KQNt9oTwWPGRN++0Ez0X37ysGJOn8ktDCZ4YrGsYq+/QzNt6JqphfceS3HfBBt+N8JYujGQ9vDejuxAn/mlzdnLkqerZkVWt6MVWUL6ZRcm6Qpk2PWPflXEh//ur4jlsKcWzbpr99HgJ2qpxd7HP/pRyl4LtCdDx02+RByM5GXIG4d29DV/GruzimEzPndTiq4bZEgxKfn8eZ5NPBiGi8tvF3+R4dlrT/jpvE8N4cpMQ8UgTmrp6d0JrnpQV/ojyBAu7O8JjKVRh+sVsEzQhJP8DP4Gmo1F4bzRxrkoNMeUvj5ZxOZUduaAQX9Ml/Dqvlnd5NTWxgfRdzSfN1nQBFAvYwY46SOdrkb1QOidu1FV8n4pYtxC2Ep4DkrUBZLdbEiSFYax43SkftPHdOnoPglXO3a+nVH0DoKOjfNouUrz4VGxCAh7xukeiQmbanxv92v+Ee0EzwMXF/ZiedxFRrhfHoGM1A3zuJ09yrLiadhew8cUPgUtYEfrdVk8wiV+HT2/u2xWIfP9paij4uuRkUSq3GAD+xcLZXcUcFUcJUHrv5BAwB/V5UMTXURA3tyCpG5KWKIVof6CLJ6NfRCrld8Ry8TGuah+T2/rE1AGWUU9jvD1tHv84Wt9D8tz5rq0X8/6xySGpVmvHn1OpY4avHGq0wQv1UfLJddkUPcX1RCgEyGyJGxqvuVZK4Q9uqCRIaK3UvL1VsDntRnskJw+r9OS7GA/gBcVRpfwGZIEmiAM5+6PoLoEyHKAMWaVxeS+nefrh0TVoYHhc5ejuxLCFR/w4nGAMyBqn2uOEs4z5GgP0ycdEibBeoi+o/GdD+nVI2Bk0quH+Pqwj394AzVEl52hSe0PDIKMsmV7KwVkPbaTe3zRwccRZBvKtXlFKIQCp1UQCbm3hwIOQECO83znj0jEELL+9CbI0quL5CGSWw+7WAi+o0eQorppRuEMcNtI++i1eqV5tPF+Kp7asXYPMYdNA7Lh09sXsu89K8q+f8cQbYtC0B6D5IGkg8LXbQIPIvAWDeNbtDRkX0QMmBSyfHVHezEmpsXXHuDFwEcGDpcdKipgKJopitgcAx83L8dNXW/26p4ig6F/pNV9llZ1OMJOljOI+BIpZsaF6oPvBNnbBFWahPmFaQTRl46v2XLcBrptxgkVixO9jcs1wgMy74FYnWVQbQwPuVylKxghKI7GfZovI2LuXU2neQ3LKpgXO+3FYIUjM1Cn4SZtE+0XrlLYym6QzkeLJ6xq6tnEFb7dgJeSUZkV9b8/Hay6LGUho2ifoRuN2uw2JTr6H+lyROwfx6XNsCrF1jkD4rgKJ9YBZJzT0P5lKwpFzMtV23JKKh15+gjLFzyr7q4XtnaI44W+yu1z3ZSuHdKPY1DBbnkNdhQMuD5DUDUlJNfU9WGF3t0dNyZvaAb/YJvy8Ei28TdtBlyJWyz0KKAL74ElDriK4aZhEGIyxMR3eV+0nh+wCRePGIE2xBbtR7yDMQrA565yT6Nwv/i3CsYJslKHbEU3HPqm/DWIpVuNftMyzHboLJEImLozruqkaNY40ngZNGsiFpVHxDeEjxwfk1UwjFE3ePDS7eBXt1Y88tTe+6t4fMKPcKSQK2Irbokc5XJc1MgCix7ThPMOxRaUnu3iBDYdwpGY8MA4ZzbnKQkw8Qge7yuGGPg4Qu0y/RcMGQETnFVdFe0NAh6zlw+3w/GVPUWwMXXsov6QDX8B8juDz94vhDtSDGBkn9QWRm7thM9i3yLEZRQk90y/p/Dps8Rms9DA9lHnreraE2OoG03MhDxW+aL+4hHhDQtVbh4G9c8+IYeHxDpzJNbpDgr3TKTmvVE3nk024lrj7ATrdvt7lKSxH5mH636oGTpzPGkvmgyqkw94rQ6Xazi6g6p75GLINRAUQ9aH88VAtnkK6KpgEy4E+OA3SM+VEeVeU0UhprNRxEbeU1ixUQrE3hn5QRQ+fa5LQGfpHMOupA/g9kSlGR1iHhmQT4qsKD/C5+5d6bjIty8JsqsptWe+2pltKYWXzKL9Tc2gDiyqM7TlbjZXdyJEHI/MgfTFswMXxuBCmqLufWBr/2m4cQ/ZcJSDq+jnFhTdDyc3cU9uDqctxt7t3mnL4TBitw8j7MMo+rcI24T1e7Io9aPyMJGHmmFGyZp5vC2ezC+qPvNEUCDRrrLpnvGn/vkN9+BAc0Jfn9ty5nzLPlhVaYL90g11yM6KcgUCE0v1uC7B5k2n7UquFOma9dHtbZqlwaYwuY8bZCeNvbovqva8oE+DHhLtocl6rO1yWHbfT6CqlWvK/Kn9cfc+FXdpHilsFuPrr3lboHQ5f6Ff33QzDQQEIRsX2WOgbt0RMdj3x3rd7TluP5Zd8rhltENDzKTRkEnXWM+np1ZrkEd6/0N6vmhjRvcVg2QEocdpdB/TPPFwMHDVQ3pyQmU0CDQFiDy9i4nsfRRk/0jX50WFM+H4hapJ7Kj7IofyDG9+eS/7TFhzr3/2u5ZWCvZEexo9ve88PL3E+VZ1S2uQMUsQxbiOd/VUfIKYWIuqMN61ee/Kd1f3JYT2+H92xY9EBJZpwuEOSkn5HQSZzFuVT9rbsWkt9OxLH38W2d+GU55oLzrf5Yh6baq0INf3RM/YRHj6xZ67aaNqT5h7PCt3xnX15qaEjymQCVfoHbgZFbo1nx5nxR22Z/eERT+B/K7BmQideXRTM4hJpWfHgpa2c8TYvE7pcHLbOlajZC/vcJ1oElDYifQmQXgslFfgLo7jbzsvyh/iKeKfvE+xxe3Vy57o2VHW4p5GJ01GbhTpj4Tdz/3IweElHGGzepaBu8UKdR3fcTPSxj38+KLeryuz49o0bQT4ZY2TVl/AqmjKvTHBZ7dvenoamdwnAVCPXHo9wM/0wUnCi9V51tylqmSzlifJRZOo2T7g6OgLfKr26EnC2Tk0ogVOnqWKgwqnmImDKYoG3k7j9s+0T9kO+/WwwejRWl+UKbLsKK+e9ibGDg/IIyqd1Iruz/NTif3DP9+LOuxtkrEvWSGi7QnXzL7Mx+OeNlSt03lxTvSjLNHREjmRZfX3BlY1smKxjGzDAeN2WiDjH3vSZ1x7ogvMe8FffnE3mCO97RQlAhgh6fge41CwvZWFGxwD3MfoEv4ZKUBXPXUhhhMsV2mFz10vYII17f4yf8g6NIowDYkFwhBbz/XpM6YqyI6a+h7TNSHGwF7N++xXp+JFwvaztaDu1ERE22nOyNi/Yt66Kh5gnG0kQXeUJLCq4iEl8R9ogoOyMFkL3VlRNqs9Osu/KtZp4i5eXbWw1CFzC7fVM6V29sK5zQ1LnwzPu3Y3ksgH4Y49ERAyIHcW7artuIDgecQtByaIa2N39b5Dj1xUX1pNHOSMwvlwgxDgize4F4FPFHRYFFPuiY0kSgvcrO+mBton5fN7WTRrTw3U1R03JNTrGZrIJxRfulUnSJZjKBQsezKj6qBWRvFw7qZ6ImK5JzpqJ9TDvrHbHE71lnj7wbRkLBEvcBJ8UROo6HPy7sb+gU1SEJrkILAzXIqC4BwHYZe4SU18f6nhe+I5rBi4uiTWEVG19w4jJ0gf0oQ1ZQnz5CXaJfEe4QXYHN8aUq//1Vsq2eOuMGp/B3VsZYY27TWShWyRJxnqqiU5/uKnifvG8K3BKRq7wo0NjwJMNEKm0WlG2umGaUbYNTbpyFBDDsLq3hijxpDiT/HaALIzCMemqbrlsQmsbnlsanf441wtI3wyOiMOTw6P2gpRHaM1gSz1Blk7y5HfHLmAT6Bcnhdogat+wBIi1gpMHHkPk4eiqY/qukxvmhrG3jUKDVT/uYqUF6kzAhQRfq6xZ3Fy5w1W/zrKGElEHN7G4LdhSoj0yAmaf9ZO8Zp2hIWOEAqbCNylaIapML7AROHVA1yqSBfc05PHxzjZmjCy0+d1WpKd0+cir+9HwPtfEMQZO82XH1Kk3OoPkPBhSLzmgKZL6/ixyJaR5kpEHpERKOTHIH+ItpXi8EYTMRrv4iQ2yj5HVmS0ixsQaUHqNDQxCmImccWBOUgg/tW+ko4fNAQJ+/D6KOijsZuqgQtYNZES556ANb4wHZ84IuKIvUb7zsEmit/18wbXrWBsd+o5SGMFm3MZsKLQtEOJ9yo4wWXTugxH8XWNnY14ew806O3CBVyBNKeC1D2iwj8C/IRtt7n9UmC3fMJkJIp4VNLvCr9VyLb/mKLp2pvEi7M/wkmqurfeVQsLyJogh8nv6S0x9veQdfqhuU/epmbQ/H2r4PJHWt97shBXPbgrTAaG6O6WKZl1Txi0N2eoWUZruce9XQWekAPDntThh0Uju/kWVd9Vcg8L8NaLp9JAW7N1xA3DBRrsGj/aHs1SGzDGuzNyCXNsV8fqYYsuXvc+w6qibs0GviKymRFim832ppBbPMweJZUZxhM1jmVGc+183kdJ/96AbiL8dfW3PK3Jy3pjHzcODY1+ujjFaCYZydinof1+qV2vxyYZ29rYtBvtyC7+Ud2H4inPCrAMTka0qHpUUQyjT4jF8wr2OJU2odXqi7T+D5je3XuZhTYtHDf5MoMfQA3iOAi7t9zxRcw4POq27H/BCT72admfZYH+QqVJCbuA2UfSFcPbjFtuPNLezf3y8sweddwSNSh4lWA4BhnA7wqEmG/V6FE1MTdhcQ8DaP+Hx5NyfP0RHpTDBzmr/XloeEZNflWC5CHN7yKeAZKYt3GNEnKQB2OdNH6AWfoIS5s3IrflTbBeAPbIizEMyet+R1szwvmU6Dce3XvgYHvUTZlfwD9wtrp9mfbw61KRJm52+yeG3+kCgqrIz4qy5ZU4RnrHcZDsfy32+z5IbUMQnO4ZccmSQ188ub39UsSKctc9580n53V/EYFWFDFuhW1LtInDAlmQUJ8TUO7VIhmuLc9B2RkOQZ6n1i/kd8xK1w17/nozyeHHq7Pr/5mPPca7LIGkE5aI/bFzf7T9dIzVc+fUXDfzl2tEwz4sbpjHPdF5M4uFnLZf12w0rvVeRYstTH7x9YizNEPkDswK3CbX7sgXml975KzxOoLuiQDIhxiL97Ym0/wsjLInLLIzs9AplStwt8eUd3zT2pV430GZIltn4GG0i7xJc7BPGu+hcaGpVRhmneqfMPZ5sQfkzS1I8CWgEm2rFNf7QlvxNputnnQg/RoL+490OR7yj+PGPYAKEsr7HwM6NYN/sE35PKBQVeldjiQwJUxpeiX+nYdrqT8swbkEPa6SMLVD9v79dg/Hv7n3g60d0o9FFf5qxd5t/NF6kDzE2JCTPc3Xpv56S1CSQY6RIk+xsu7JchrKX/3/A12uPwPieNsw4DVtNw7c+M7fCxawzxExBGebR5+oR3KCA+b/aNIyLIiQMv7yuiyycPen0vCfgE/eG6fFVZL3TYSPshREf6Qg4q4xKBo4VE239/H2Y6IVQ/TWglJaqQpj6vH5ONbqaKLIivLyjwaUsLq4u4ndz3bnsPwnmib6gDf6oUcbZjVBQ4sKYbqEGUwCo98jLDNRWNq85Ih9Jw2Fr7Sf0vwBn4bJjLLtCTa6SmHZuh72SrHOdowULy00ftzQ/5C6rR1j6x0UhRDxLNj+CADPwZ6wcwS/s+TIuhT2/8E4L6vsNMfwQcvGJUyaEjr2z8qLSL8bEs1L9qm4KwYn3Ci7Mkc8H+tVdlwsX2KlvkK7TsS4vTvvC6yfivIhbG7cxLjbWe6JNLdjDGOVFscoesF58bK3Mu7hChKb7WZvXnwmY4qtp1zn1QYnk8dG9QSMM9bxmOUYJA+LnHiC6fR4e8I2MWI757VxZ4+gnOLqDX3oewVXaHXeGyfjKGsHfqgRdU3ILByMeORIlf5V8MMc7+8c99FIhyne2ykmdE2TfTsPirFhQENo3zOMPaUIcXz+k9mqfodV4xmoR0l2AZNib/Iqbvm2dAqHqOXpyGKZOYQAWTPUt/LAUFP6ObLmLjrSGBFiPs/N2PvTknu4bDJ4BaqHPeGzeJENl0j88mVQVhpcM05nYjjS62L9NT8tyyIo1RJ+UvqyBmUd4bo2xnWaLyNhumySBFZVrH7RhPI8HrA3H/rnoPZECr1fbI3zcKzsCQbXEThqbnsvEgRVU8IuTc5+TLdxSX7nsySTZznQyJ6wFRQb+wXmQMtjaPcXY0fe2nY89AGptrzaHz/4gY0mdnR2jyf/WdjnF5+NpvrBaha3D+vYxsF4c86nAiNwIIp9coezolyhKaMunEdC/yldpYgfrgrCHw53PiSnYs1Nllb3I8UtTndEJSKL+m7ThwK/1YQMcTSZoREx1soH8U+z2sfDXGpIUdPyz37GSmYszINzVazTZLaEVA6nQyTZd5+odU8YMzzK4KwsVv5syNYOu5lV+HeDrhsW2Nvc/BMmhhxuHjYHvnYWx2uEb5yBoMVvUXV76eOX9sHOSMiGp2NC8E2hCogfAH36VOxLxCE1ItyKh4+GR7DjoUOWj/JuI0sSB/N+sOW4+3Tj3vC9B1Jnp7xDCNJqDdK7fbGJIx7KyNdcP2Q4LH52sY+4AXbwHxLD9s8W/eQj48dJQp7f6w4mxBzAuhYsn/s2WpE+F1GsmHuqPCctCRPZM8RTCYfsgDdf4phekGUvIXiO6hok99iGeHeWCvEobsTe4HofEdfPjrisFckX+FR9glhw99CTIx9cVJ+O9GVPK+MXdy4TOndNEF53W332Fj+tpn5xd1eHK4Goi6TMmxGbbBGTk5zcw+ShaPYuO4lxzfWJm9rKvDvk5RkMf96GjsfAuaiuwPPpM6RG6oMGIenvLIQtrhPmFho9lM5fNPcpqYwwOA83i4giet7gYJVxSLsSVwIdXiZKmhKnHT8HL5gg+/UyIj86d+kRMUR4qmrrD9D4Ue8JO5y8JBlkE+d6zQBGcw7LtFC/AWx5DFaDjGALClMm4bwWb+BNFvQeIX5zkad1CjLPBxbZ2lt/M5mE+aT/IqmlSNt7Im/SSyMW0yfQ4/oE7SaKJl8GJbZT3MWI06G/+HSIhHepb/PF6dnPnPfAxz4bejpWJ99H66T3fUOH1TEj8tFuJPdEVs/7RBLvQpaiAcv76Xed9jvGsqgqZJtnhxmMM4MOC92+RGGgkXyCjzALMwAv74uytn1P3C7EC4HHfKB8se5OzmKfm40ZN2KV6BVRSJKVzotIiFNhWcIyFr5ZQo1tOnZW4pdJ8ZWDkO1Tm4LuI6hMOSkinXJdwjbOfT80zyjH5DuRpIHyk/9Z5nIL87KQGPA9oX8btGYV3mS1WOZJ1izhIr9MEVow7Oj8zpbOQVXhYDpUUAe7kXtkUcZ5ldbirSQvTNGiXD7DGnTBh3Ge+cYIwx5HkOOMR7uIoTQXEFlZ5VH1I13ewaCzzBbDP4r/3d6VNcdtK+u/kvLjfYhP3n1ulSzHjqu86FhyXPeJRc9QEivUcIrk2PH59Zc7sXQ3GhyAIMd5SaxBA719aCwEGgc3OnbNfSniYz9rQGTjt9U8kSr5YL6WL/MmxJ7ZL4s0L85Myd2q0zzMaG9xdtSvB5X29Nc5A/DQRqSPBCD9wAugN48cEjO7BYZQ9bytY1F+yzXOVNVCBGtvnrEBYuvMntVWfSmKbyfBVNOHJ9tjLfXiph5aHvP9daPqvM4pN8Tuoh3DWV4FONpZVmvgzHskkyqWnXWs6cPDw3bHsA8zw7dDE1yv9qxmeVXiNW9j51xPiuLbSTDV9OHJm6R4SsvmcEmXGk7MYzfHrWp77E4r8J3lY5CxZVTUm3ByDW3UaR70+uo++/G5XrftzGd7ewU9ev3e7Uf5m7NeScfnSBR5zWxeL152SoMKMMg/S4auskePfkq+pcn3P5LseH/KDjMHYAdbX5xTL07c0Sk82yFD9bNE+RKXvcU9HBh+meUPw6XhS/Vlrx8rFQFrn6622U1ezjhAOdX00Umb+yA/iy+dbRy6BkfjhLdVouaWYV7n6Wp6ieB5lv2ZN5/+gqZiXiBy14peHcrvc76mi3W9D6OX64Gw7/e4iw2dn5yFhia/4pRhbtb7d9084P+Ssj0t7aCpD7llSxjWr8oy36WtZ3sO/zklp2Tf3ZYeb+9Gze1dBfm/H/a/NKuRJnnb90OWT1l+bpPs/tfpx/enrEqPWbqr+f/72b9+/fW3Z2qX+Xjozlv/0hzcbi6uXMflLt7r5qjV2GNigJJLMiEUsoD/ozFtz8Y0n2fj7Do/lFUR1wbXe3162KXHOFONohAyA0Sj69ikWvIqOTZfuw4VqTmH8XArW2c+8lAcYDLGi+cCpthQi8Tr+SjQJCLRsXKB7E//aMMw5glZuKm8o4vFTs20EBpbQhhDVTnPsT9FQLOFQbCYJtQMBr9hL617hjfq/49ibigXfTv+tgjWZIFlQZQiL+gCLeQHWYo+HI7Cc8qrgBP4zVtzJuTFnwVOkIXWA6dpqRUETuPRDIdxqZ3Xq76bWhoP3YhNTT9uPabAZ4ow9weOJuOBkqtjbfLm+F0vfpqU0W1+KnbEWq+vK6/1xh8XCS7aQS5IFs/YGlVeAFz0wTWEJ324KTjM7uKiOabpJFxcMMysXB4CZsQBx2Aw64fXTcUyaMqmlV1MJLOZnq0xkI0IM4Sx8BPx8PhacCo+B17kgZVF0TX8o0/r1ux3qCc11hm7BIFBcaTyi4lholY2cSz0JkJUez79lhQ/7prbs6hvRSLJqVKB1RrQIhq6wgWqqh9sWI1rgmyhMTHO4pC7MeuamCtCQ3i6oGm5qpHNrHw1uNrMjmVAUC2/Z2m3axV407LJk34ftztnxYIblyJbqTm5YOsbmJI2W9jE7OEooQJX4lyH+g06qEhguReoWfvfTQSyZitWWBX2NjPCrQBsy4909uEt8GinXAz9lNStpU0Gje6mJuNLjdyC5Gm1aBH4wdd8cbFGCi8QVEywABIZ15wRxpx7zSvBpOmzDuB1xM8/BQptUBAMfvgF+aVwV9XrlFqub7WqSQSKvi6MifLK2JJLNo8pSR0LLAWD0nA73iGIDOtHJfdk29L429YBACZ0WLnrCdCe34dXBwb7LrogJCThwp2GG274jw8smqbWQw05PIw/LjLIqDlVIFE8x5lB4QVQRWaQQVjSWSYCIcswQbYIEBeLKxsfB4AVnlloaVS9TLOsntHDWZVmYcp0iNcm7m0XDSxesvHDo6FPLhnBSqx08FIyYkqijGUXM3gNGtkMXsFw1b1EclsVbe6Bsp0QRcPzMyi4RgLRo9OPi4ALklyWByTwAjPYYH5gBqrF4Ss+KhQEa0OClW3ga5BWkmH6cfM4GlXZBHaG/CvbwM4grSTD9OPmsTOqsgnsNIljtoGbRlL5Y237w+bx0qqxGax0SYYiXWhbT3lESSejJsHws5/v+VwvOkBLrwiHW0MeDi9qdlgxg6dxh1GtLftTK1wGXVTuX0o+mdAPAlWTLIFGdi5kDJ+s5McrAKvpqz4GBMrxPyFIrQESGqCGvMtL73daRdBVbXOZOsiC4Ft0w2su4FYHtg1FwDWCbqmIdzbwwka63/9uHoOLs6tT9di0uGsLlSF51RGP0kDO2EcSbj4CkurZADIYFl/nxemp3ZR1DTz8++LIU2pJ+HXzuJh02Q4I2tcyl0ZB90SnBoP+58vAAfAM6aqBELX/fVPkpyOKAoFEc17/8yIDUctQF8ETdDDDeAQPi9Ek1xpCCCC3vcd84iVA0OH7ctmI05KvYPKBiX2O63xCaPHZi6VfF52/tGIFA1H7GIGHQ3LU3EV6sbxtpP9l62fjOjU4jGSDB/b+JhbNy4JmyWkuHzXBZ7hDeqbPZfyQ/JHW0hQ/Ijiv1ErTcImSg/LIBBeTiEtSi8M3eCYuEGtAX7GPET8BxPgxJRS+WgnDDnztibg1I2qUUpfA41G4xbAzKbIlwKw/h0kY2CyYr8QOOKGzlLxJ76vruNhHN6fmgbUy2X9Jq0dEh/luNFxLGqSQGpt+9BdJ2H46ExSjLixMgK4IDhFprgMrNNelnmINJDkozwKTHisEOEKb9bxnqLgurH0Wu8JKZ0Nrgtpic6TZOJM8Gnba9CGvkvXPsxspdQm6X7eNoUmR9c+zPyXfa7Tf5HUD5RCcNrE/CQguiQOWb37vEtJqEzuZEM6cDoKG6fh64LJYGJqLFcktYRP7te+jrnkkG4TUkvV5fFdiMQCNeqx/GBtEbXeMYLnnes0zcrQNB7nAW55RtmMdgYi9LTFWCPuRdkhNuVwim38+0z9TjB5wtlKdikPzmE7i4ayxp/mwILIytZFKLmAOLOqzidnveIFn+ajyT3osNLyEnNvmrSDXcdFNWV6eDvssIT9P9J9VBErgi5dYagUTVSJlSqIW+vyihdnCD4A03Tg8JxHXA6FNjFJrgNmSY9UsdAUfrjRsrf8b/BqAteAX+Vm4Cv1hvud/e0x26X1/+/Cqqor066lKNoAxUn5ILoxy6+ij1dsCFGHRPx6bPyOOXmLoMeOBBwRfoZHQlSHlQOhnJ2o+hM6NoJSyrMUE2MBKgytfW9/A+Slj89lgCx6wKQ1CY36YOtzFD+YcZmuZRUwyQ7KIpRcyWxBUspghBEw/BoDLkHGH9ingzJ8BYlyHh0RZTR4caH/GRRofqjG2XudPX9NDSxjhT8aL92FEIukejFRgtS1olg2CFknu54oXaiCvaKMU5Ughir1m/G1mbb56oC4/7p6L0dBLdQY8/3OqS2ovfT6kOEYlIhELcsFFhkfcQKuGnij22vC33ZjIgeTFRr8th7wBcuYtSY0QcPnS25CrReOi244OYLmavUZViT/j7DSClNbQDy6WRW6rLkfMntAnhmfhyQ+UO20t8Kw2EBrWwaeTnCnDtieGm5v9Rbfx0zFLXuXfD1ke41eERwJp/2X8ceVogNULjwTZ+MGwcJcmRa3fLpHysBvPW7VE3PzrLSa8jGKj9JIswq8XkWx90ofDTJRuBbBa/5IyDIgWXDba4WclC8XpOGp/kHj9QNIktzvNvD1g6SpxmEruXBHMnALMOAX6ByU009XhY1zLvU6zqsl36/16w1JhStGMFlIjvpxrE0Zd+dEt6DWKl/Hur7eH2yrf/XV7+lruirQ7A7qJ2xSI8PIb0BjN5u9WYJrZTPxXh7v1z9zWB7oFx+dzMBd6lL7aZcBDmm63LzxhbhRdvhA7/XoRexeTPpvZu7i6v0+z+pckWugtg5Gh3ND069YvNE+qcJiFTpTQPr3hdeKEQ0HjrT9xcmEzHl2nTcx1av2+1YB+XwM1fkii10X+tBxKZObKvEku2jw+FIU4HEVnrAUgd/k/8FgJPCZXBJy2Vum32uTv8odI+HfjKHyyodDJs0albKEZ7MgVk8bX3IWymR+giUqxZjGyiKuA2iY2gMKhasm4ZQun4CHr+jHZ/ZWf1JNx2s84tjRKCWR66TKPuINq0aL5PPtmsKcfMCIasnCpVg2Y3253KmqNH27iH22O1beHtGnXUapVfLqlMlYS1amF286fqunD4il4YjX4GDI20xq58rO3DImgUqRoflNBzwOIW1DaZIZW6wbD57t8F2fpf5P9IGP0Lj48nLRVjeD9kUB09/TjIgjUxJaF0Uu9oA42lR+06TpxmA4SBsSX6wWAv3Od6tz/Mub8m5nr91/1PiXf0uT7H0l2vD9lhya5aOOSqfF213PEVP171Uy77vIIq2+EXd8GiL6xzPqolS4H8KUZIGKcbD8Lc4NGi2yTcTxixTskDqWC31BYSWS404NByu1ZgV6ZtaNJqhzurEqWP1znT+1CkRnVhCpLBzKRtXQmRfz9gsIVamordgvDqPn3TV5WeDwaKDQfdj8uc9TJHkqOwtSo6AoBNMgWDEgfku+lZTwSqiwdj0TWYpPS7xcUj1BTW7FbGEbNv5tzyHg8Gig0Hy54Gn0GlBzFo1HRFQJokC3c1DvPsj/zKj089OcruUs/pd7iSz6VvzQv1wovKEbRlrfiGQJfzQ9Xh/J7UhDruZFGc+vw8zI3aM4BmatF36T0WsE1ibiOHYRZ21dB96z4exbbDl2ONjAWB1T/l3EHKvylZFs8be8aiz2Ilr288nub+KXpVXWNpBj2+vN98jotyupVXMVf41L/2NfUuk0qIIHMs1+6UjRRz+3uMXmK//1s/zWvPR9/1XP8aGFI5Zackv3vT3GaXVVVvHvspuMAW5AO5g+SGgSZ0s1ovKciiN1UyleVVtColpFVp/xul59AY8rFEDOZwsCt/679Pqkec8h+SjnETyExMTReGdZlMFYBxTLWspWUIxpTFi5znCXJyNxj0hID2FQE9pix1MDhOq6Sh/YgicZhKoI4TKUmE6W76lQkkImGEtBEQyHPAwQXhYDwR9QTRe/j9hErtn+aNz/TIkECK0hFeU0iNIkg5VDXeUvFIFOJgmdtAjUaBWXvgYpt8L7i+/hwuo9bXxGRSKai5BAp2bIYhDBzlylMHVVdjej9VaUAu61KxGRL8KMZGTmMdy01BmMJ1P5YaFKg6VBwfBtKQPGHQkPzw8ut6MisEkDMVBoTz6ruNjV0v9WTaqjPK+UgR5nEwHD6uqXxmoogNlOpgcN03k3jMBVBHKZSE4fmwFdyWxXt9kfZPcYDcAPJQM4gpUGKaV9e4zwVQdyaUnN0FPbQ9KAoFIKxUChn8EE44G2zQ013fR8NN10xFXI6CpMOSfGUlmW9vht2+HR9NBJQN43KtHL4u57WHuLs6lQ9NmvQ7ukqVAqaHFxZkDUM0rVXeZHOLpRBfNviMmJ1+Jb2Lj+mO4xPX0gw6ik4nDAmZPs9Baf9N0V+OmJM+kKCU09h4NRfatCY9L9D7fdFzGns5+b65XiyHJ3HymTURFamNEjxJr2vp43F3iAFTAZJAVMypSA409x4bkQGAaEMdSdrYdpSfsgrKJIKZSiTrtjA5FPyvVb4Jk8PVYk7DKSCGIOEjPkXsuyairA5F2uBNRAiHpOLKU4sv31K6uXAoVkAJmAIVsphM0okRvXUJ6gBFVUSWE2VireWw967xFZ1GD21vkMeH+Wu9OhnRHV7keSg7cgas6Rjy2UjEden7dt9mAPbQsJbbTmPD/lgEcafrETIRdabJy9fSMO+lfIAh+1+CkMgniTWSEGepOCapSe38FpfwyCdkDhaE0Uog/gKxcZ1fA7uWPa/w+v2nLEn2lKNEIDbH4tRNlwM3dX1k9bMX8GFm1IO2kwmMW1HYEn89N0JjBLcrMCILfYB75KnYxaD/QgmM+0LTpTMjXxCAp2E2thncx7CNs5Yo6CiP5ftm+SQ1N2MCl06CThx16hMO5ZTej99z3IqA3ctp2IDk88FzkQog5gIxaZAUdfen7LkLi7/ggKFVAwGConCZLcpGZ5ut6kMtNtUbOqNSVzWHedLkj48QhNopRzsfzIJj+GrtJ7jl3AY0kkItgKVccOsKJLDDtzbHovgjbKhlLO3YYixAA2x02EVWdVEV0BgkQmoXSmF1NjHhUQ1QC8XSuF+LhDwWXV5nyh2HYWBZUdkHDCejnH6ALl0KoIHiKHU2DNaW1NjokoB9wuFiLHH/i6pqqQwIBcjxPbfIVqTkfWMOLq1dRrQ7DqZLXNsco0RssTgTajR/BXADgdCCe91IMSW4jDk4AnA+w4lJ1PQWAM06BcomcyodtOD9vipFZUAVlmmMaGwyMuybjzDueokIPI0KqOpodiNxmxOrK7/VSGLqqEEnCYNhaalVPw3cbRCKgWXUSKBiRXy7YX47ML73jLs/ROK6CTUR4To6njM0mR/l/f0aWL+FDpUxkGnUfBk6MnNEsgf9fFjCAid+ZzAp6SsQ3B7qphxDKL/NoqfttAoqE+sPRHDEernUcNXXpqc8/01akjZG2DjeRjex2f+R2gpl73tfhxnG5W5mxpNdLZSAKkPMGEAUkImgJpxAmW8SKhv84il2DmUkYAxfcRZSaXYRJHLSr9lpNtXI8HOV8hUNh42uZXhS42hcH7ecBI9ep02fUmoQJ1H76jVg/7TTQn1jHnNHD8/LtUkj8m3zfBOvT+XVbczSySfCieNItPiikEn1Vt9qBPomGkwg7g1g+BviQcXJGIlp2qtBDHymeZoPNus2wehxJVSDlK3aiBnsaErSmB1pci5+sMMzqw+fJMJuuuly78a9cdT04TfNRr3Hlcn+G1FdP1hryY1/49u+/OWuuacasT4ody46MYP5DYFWBM0i17o1zx3cfGQgD2CU82Rz1dmnmHlZoUdtZJP5ECxRyvzaRgb1KiV3IfUQGYBLuGUpEnACj5xAtw2khqhrg/NHmwj+Z4QOtTKdIQywL2lTgviPtJcXM1XexxHp9CEqq7T+gikyBUsUX2HYVRVzTzX0ki9TbYWMoF0OYyYcoF07qdd0LWztjJ5nWy255WrcSILFAJ4HcdqQahAGwLLvZjJ3ElAcm8dZWGTyNvU0bBPnfSb2/T0nV8ZVxu+lNdqTF+1I1pRNvCBxrArg14MiE/V+JWJ0QlQFlFvLSYTLzRGY7uAeUBCD6aALml2JiDvXtqr3n+LoZRWSdyrq3xXauthV3Tnq6iYDldUJnTupQVVH78njZ/ciOCJExMeV254dy5Hbm+DNSEDaGU+DIEHQZzYiR/XYIaXaZbVgXRsmTCCQurPBCwMnaH0kN9tahrXWqP12QWUrAxSA1iqBXszQFfOpwdmAFvQFXC11Ov4rT7YVXu5JnHNvmuFc23e3jRDpgHSHDqRDxOo2RLammgmBHtVh0QBpKo6kQ9V1XQGbc3px/MXV3mWkWrKBD5UFHMddGsmKJfBPNW6dAtR1yKsnEhyppBaDTlVxFgPSQIxQ0X1ZI54JIaaxvAqEsohuR06FQ35GsiWoGNCYKtkLgrnpsQnQryK5gFOU5hScJUmBA9msSbTluhzMJswGX0Z0zCm14ujKZSJqJwq5HSUV9EHmjh5ZtrWrPLF2JtuzBpD2gmg8mEULb1NW1X41Y267VFps74KmTeFpcPek8bwge6ZKkdirhtEX5HGILKUUWcSGcyUo9fWK7r1bN8k6daO5mxBw3iz7Ylis1SPFegcir5wv23T3jB2VUA691sqUrKnthacy2muolRsUih8hCV/6kG5p6LpfAV+kAOuQJxgOPsgB5TpSmqFzFzlyDS93Zl2Ad8ot/frKswxZtPCbaCSuFVcywQ21XO0gTLJT3yT1oncf4n2r+qQfy26qddnj3GZ7L+k1aPAQVfcVMWZOlJdNcNcWxXNHjffEFK/ndrHzQBXcKQIWBPt8azUfY5M81n0O9s+ci23cSGUecbMf4aAKJB4CIhi1sKpHpiQ0F5FIMcgORUi6X1MjIicim0jnCSJbsxi7BfmSm7REcY0Q/pGvE8oFG6VVhNc3g6naBwd7xWzU0ZTu7iWMqEjwcGa2vhKZtKcuxAaTiQZl3wq4ZbWfFJOUEPAAyn9hDog12nfk6kUpmdscDOcjdK697fvYxNqStZIfNkG6uE4uXFFoL+/I64N8Cd1lJ4PJ6Pte78hwawDA1E9Ayf20TmCm4JYMKK07teNS5uBTDLMONhtqOjeQKwsymJrzMy+MxBEJDFGMjCD4JrRDIEfs114BmG0KieEJtpGEju7RivN3BbCZGsLm2qlPUBPuUKecsGpvYUJPbGM2IJY6sUYxDkVnNqoFKINoMY6TEIkEufesmQ3Qey6u7qAyUjCLlrUJo26FxObB3FObW9ddGvmlN+inWVTqQncQNCzua0pqOdwt2riGTBdHpsca/k3ETmdZNc1Kk9qzZs3rtKMbQLXCGXLNindziJG4bQrJcGlGocT286fCDED5eLR0G8Cheg2fjpmyZSCDVdcoSSmLrOTvPlVeXz6QzoXC6mMUJo3kuafnNWeNGmr46+VnKM+MXbpRO5HK/+qatua/V6pedBGq3gbtOfuzDoxi5VBLtoUyrv2hr14m+rL7M2bJKKb1ojPv/EHP9dDbuEb6/jYyTc8V9Q2xH17yJ2ZiI5pquK+e4Y10fgoj3HYRih9DtvaY0Pd10X0HaEZ6g9v60TEV1GdyP3nUO19oK4m+vTPzKPt7GhBUPuIE+hjO7fjUXfHwJffxIleF/kTZQ+K3IdB4Od/+qBCvuZztinucgtDCMRbN4PwiFCkPSgExUOcnApp4INHfWAjXzHC2sHacGwSChQgnQ88LKM2/M5PBLxCBByh4dYlzIM9nNTZyfQWEt2WvgXEfNVozsEr+X2g6O0hrdI4Iw5VUhVwJecdqIRfQbrtzmAZXjY63xjDoVGdldkuaF1P6pItwadReU9TzUwDI777ZM4BA1PjCp6ZAAZ636prwvhk1Rxz0IHZe0BWA7GbANyvm7S3UqJmXLzOD2VVxGnzIEY9DRv1G5Ie3eURVp/YbXDPy2zuGZmToCUn+laNuAY1vzvj0E1SwW9WVleqMpXHNV61AYW3ebhwk57zAfYvzmvRP2aB14y6LQ7imaLzDDuknwJxCBPS4rMTXAVQXHiCiet/6dUm3UJntugfUcCjVW0b1GtU5xl2yPIFIgompMVn5xELoLj6vhZ7XNTe5QJGAVdtLzDWIu+VdUOE6Q0yB2af0pPBAypFT6tllQstrFHEoXjWBM04F5nX6sJzPf5052wj93+ZJ3ETpbdPmA6Vf/G8a6Qxfe3npBjLXjzvXvzrf6j/rJeu9crvfb5PsrL99cXzT6e69lPS/fUqKdOHqYkXdZuHpH2bdGp0oHl7uM+H9Z8i0UAyFI8viVfxPq7iq6JKm0T1dfGunn22b1m2OzXNY3Zfk/3bw8dTdTxVtcrJ09dMWl2+eE7zf/Fck/lFd/q8dKFCLWZaq5B8PLw8pdl+lPt1nJXKihpr4rq2/puk/r3zZd05q+Thx9jSh/zAbKg336vkmBz2dacbnlYvPx5u42/JHNk+l8m75CHe/bhpUma3G09YI2ZHyGZ/8SqNH4r4qezbmOrXf9YY3j/9/b//D7DeiAJiOAgA + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.Designer.cs new file mode 100644 index 0000000000..c12151b6d9 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class CustomerTablePerf : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(CustomerTablePerf)); + + string IMigrationMetadata.Id + { + get { return "201507141647299_CustomerTablePerf"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.cs b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.cs new file mode 100644 index 0000000000..982225727d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.cs @@ -0,0 +1,35 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class CustomerTablePerf : DbMigration + { + public override void Up() + { + // without dropping the indexes we cannot adjust column lengths + DropIndex("dbo.Customer", "IX_Customer_Email"); + DropIndex("dbo.Customer", "IX_Customer_Username"); + + AlterColumn("dbo.Customer", "Username", c => c.String(maxLength: 500)); + AlterColumn("dbo.Customer", "Email", c => c.String(maxLength: 500)); + AlterColumn("dbo.Customer", "Password", c => c.String(maxLength: 500)); + AlterColumn("dbo.Customer", "PasswordSalt", c => c.String(maxLength: 500)); + AlterColumn("dbo.Customer", "LastIpAddress", c => c.String(maxLength: 100)); + + // recreate previously dropped indexes + CreateIndex("dbo.Customer", "Email", name: "IX_Customer_Email"); + CreateIndex("dbo.Customer", "Username", name: "IX_Customer_Username"); + } + + public override void Down() + { + //// INFO: (mc) Unnecessary + //AlterColumn("dbo.Customer", "LastIpAddress", c => c.String()); + //AlterColumn("dbo.Customer", "PasswordSalt", c => c.String()); + //AlterColumn("dbo.Customer", "Password", c => c.String()); + //AlterColumn("dbo.Customer", "Email", c => c.String(maxLength: 1000)); + //AlterColumn("dbo.Customer", "Username", c => c.String(maxLength: 1000)); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.resx b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.resx new file mode 100644 index 0000000000..5e18dcfce7 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs index ab25464ca0..0e6186a316 100644 --- a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs +++ b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs @@ -4813,6 +4813,14 @@ public IList ScheduleTasks() StopOnError = false, }, new ScheduleTask + { + Name = "Clear transient uploads", + Seconds = 43200, // 12 hours + Type = "SmartStore.Services.Media.TransientMediaClearTask, SmartStore.Services", + Enabled = true, + StopOnError = false, + }, + new ScheduleTask { Name = "Clear email queue", Seconds = 86400, // 1 day diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 0cdc69b343..075c5ac68c 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -290,6 +290,18 @@ 201507072138058_MessageTemplateAttachments.cs + + + 201507092146153_DownloadGuidIndex.cs + + + + 201507102159496_TransientMedia.cs + + + + 201507141647299_CustomerTablePerf.cs + @@ -559,6 +571,15 @@ 201507072138058_MessageTemplateAttachments.cs + + 201507092146153_DownloadGuidIndex.cs + + + 201507102159496_TransientMedia.cs + + + 201507141647299_CustomerTablePerf.cs + diff --git a/src/Libraries/SmartStore.Services/Catalog/CopyProductService.cs b/src/Libraries/SmartStore.Services/Catalog/CopyProductService.cs index 9f84b9a8de..13f10f4e47 100644 --- a/src/Libraries/SmartStore.Services/Catalog/CopyProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/CopyProductService.cs @@ -91,7 +91,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli var download = _downloadService.GetDownloadById(product.DownloadId); if (download != null) { - var downloadCopy = new Download() + var downloadCopy = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = download.UseDownloadUrl, @@ -111,7 +111,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli var sampleDownload = _downloadService.GetDownloadById(product.SampleDownloadId.GetValueOrDefault()); if (sampleDownload != null) { - var sampleDownloadCopy = new Download() + var sampleDownloadCopy = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = sampleDownload.UseDownloadUrl, @@ -275,8 +275,10 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli _pictureService.LoadPictureBinary(picture), picture.MimeType, _pictureService.GetPictureSeName(newName), - true); - _productService.InsertProductPicture(new ProductPicture() + true, + false, + false); + _productService.InsertProductPicture(new ProductPicture { ProductId = productCopy.Id, PictureId = pictureCopy.Id, diff --git a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs index c0c153badb..f48835151b 100644 --- a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs +++ b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs @@ -384,7 +384,7 @@ public virtual void SetSetting(string key, T value, int storeId = 0, bool cle else { //insert - var setting = new Setting() + var setting = new Setting { Name = key, Value = valueStr, diff --git a/src/Libraries/SmartStore.Services/Customers/CustomerService.cs b/src/Libraries/SmartStore.Services/Customers/CustomerService.cs index 7641b6bd45..25b20c2721 100644 --- a/src/Libraries/SmartStore.Services/Customers/CustomerService.cs +++ b/src/Libraries/SmartStore.Services/Customers/CustomerService.cs @@ -17,6 +17,7 @@ using SmartStore.Core.Domain.Polls; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Events; +using SmartStore.Core.Infrastructure; using SmartStore.Core.Localization; using SmartStore.Services.Common; using SmartStore.Services.Localization; @@ -33,6 +34,7 @@ public partial class CustomerService : ICustomerService private const string CUSTOMERROLES_ALL_KEY = "SmartStore.customerrole.all-{0}"; private const string CUSTOMERROLES_BY_SYSTEMNAME_KEY = "SmartStore.customerrole.systemname-{0}"; private const string CUSTOMERROLES_PATTERN_KEY = "SmartStore.customerrole."; + #endregion #region Fields @@ -49,15 +51,6 @@ public partial class CustomerService : ICustomerService #region Ctor - /// - /// Ctor - /// - /// Cache manager - /// Customer repository - /// Customer role repository - /// Generic attribute repository - /// Generic attribute service - /// Event published public CustomerService(ICacheManager cacheManager, IRepository customerRepository, IRepository customerRoleRepository, @@ -89,26 +82,6 @@ public CustomerService(ICacheManager cacheManager, #region Customers - /// - /// Gets all customers - /// - /// Customer registration from; null to load all customers - /// Customer registration to; null to load all customers - /// A list of customer role identifiers to filter by (at least one match); pass null or empty list in order to load all customers; - /// Email; null to load all customers - /// Username; null to load all customers - /// First name; null to load all customers - /// Last name; null to load all customers - /// Day of birth; 0 to load all customers - /// Month of birth; 0 to load all customers - /// Company; null to load all customers - /// Phone; null to load all customers - /// Phone; null to load all customers - /// Value indicating whther to load customers only with shopping cart - /// Value indicating what shopping cart type to filter; userd when 'loadOnlyWithShoppingCart' param is 'true' - /// Page index - /// Page size - /// Customer collection public virtual IPagedList GetAllCustomers(DateTime? registrationFrom, DateTime? registrationTo, int[] customerRoleIds, string email, string username, string firstName, string lastName, int dayOfBirth, int monthOfBirth, @@ -241,13 +214,6 @@ public virtual IPagedList GetAllCustomers(DateTime? registrationFrom, return customers; } - /// - /// Gets all customers by affiliate identifier - /// - /// Affiliate identifier - /// Page index - /// Page size - /// Customers public virtual IPagedList GetAllCustomers(int affiliateId, int pageIndex, int pageSize) { var query = _customerRepository.Table; @@ -259,11 +225,6 @@ public virtual IPagedList GetAllCustomers(int affiliateId, int pageInd return customers; } - /// - /// Gets all customers by customer format (including deleted ones) - /// - /// Password format - /// Customers public virtual IList GetAllCustomersByPasswordFormat(PasswordFormat passwordFormat) { int passwordFormatId = (int)passwordFormat; @@ -275,14 +236,6 @@ public virtual IList GetAllCustomersByPasswordFormat(PasswordFormat pa return customers; } - /// - /// Gets online customers - /// - /// Customer last activity date (from) - /// A list of customer role identifiers to filter by (at least one match); pass null or empty list in order to load all customers; - /// Page index - /// Page size - /// Customer collection public virtual IPagedList GetOnlineCustomers(DateTime lastActivityFromUtc, int[] customerRoleIds, int pageIndex, int pageSize) { @@ -297,10 +250,6 @@ public virtual IPagedList GetOnlineCustomers(DateTime lastActivityFrom return customers; } - /// - /// Delete a customer - /// - /// Customer public virtual void DeleteCustomer(Customer customer) { if (customer == null) @@ -313,11 +262,6 @@ public virtual void DeleteCustomer(Customer customer) UpdateCustomer(customer); } - /// - /// Gets a customer - /// - /// Customer identifier - /// A customer public virtual Customer GetCustomerById(int customerId) { if (customerId == 0) @@ -327,11 +271,6 @@ public virtual Customer GetCustomerById(int customerId) return customer; } - /// - /// Get customers by identifiers - /// - /// Customer identifiers - /// Customers public virtual IList GetCustomersByIds(int[] customerIds) { if (customerIds == null || customerIds.Length == 0) @@ -352,11 +291,6 @@ where customerIds.Contains(c.Id) return sortedCustomers; } - /// - /// Gets a customer by GUID - /// - /// Customer GUID - /// A customer public virtual Customer GetCustomerByGuid(Guid customerGuid) { if (customerGuid == Guid.Empty) @@ -370,11 +304,6 @@ orderby c.Id return customer; } - /// - /// Get customer by email - /// - /// Email - /// Customer public virtual Customer GetCustomerByEmail(string email) { if (string.IsNullOrWhiteSpace(email)) @@ -388,29 +317,19 @@ orderby c.Id return customer; } - /// - /// Get customer by system name - /// - /// System name - /// Customer public virtual Customer GetCustomerBySystemName(string systemName) { if (string.IsNullOrWhiteSpace(systemName)) return null; - var query = from c in _customerRepository.Table - orderby c.Id - where c.SystemName == systemName - select c; - var customer = query.FirstOrDefault(); - return customer; + var query = from c in _customerRepository.Table + orderby c.Id + where c.SystemName == systemName + select c; + var customer = query.FirstOrDefault(); + return customer; } - /// - /// Get customer by username - /// - /// Username - /// Customer public virtual Customer GetCustomerByUsername(string username) { if (string.IsNullOrWhiteSpace(username)) @@ -425,10 +344,6 @@ orderby c.Id return customer; } - /// - /// Insert a guest customer - /// - /// Customer public virtual Customer InsertGuestCustomer() { var customer = new Customer @@ -450,10 +365,6 @@ public virtual Customer InsertGuestCustomer() return customer; } - /// - /// Insert a customer - /// - /// Customer public virtual void InsertCustomer(Customer customer) { if (customer == null) @@ -465,10 +376,6 @@ public virtual void InsertCustomer(Customer customer) _eventPublisher.EntityInserted(customer); } - /// - /// Updates the customer - /// - /// Customer public virtual void UpdateCustomer(Customer customer) { if (customer == null) @@ -480,16 +387,6 @@ public virtual void UpdateCustomer(Customer customer) _eventPublisher.EntityUpdated(customer); } - /// - /// Reset data required for checkout - /// - /// Customer - /// Store identifier - /// A value indicating whether to clear coupon code - /// A value indicating whether to clear selected checkout attributes - /// A value indicating whether to clear "Use reward points" flag - /// A value indicating whether to clear selected shipping method - /// A value indicating whether to clear selected payment method public virtual void ResetCheckoutData(Customer customer, int storeId, bool clearCouponCodes = false, bool clearCheckoutAttributes = false, bool clearRewardPoints = true, bool clearShippingMethod = true, @@ -533,13 +430,6 @@ public virtual void ResetCheckoutData(Customer customer, int storeId, UpdateCustomer(customer); } - /// - /// Delete guest customer records - /// - /// Customer registration from; null to load all customers - /// Customer registration to; null to load all customers - /// A value indicating whether to delete customers only without shopping cart - /// Number of deleted customers public virtual int DeleteGuestCustomers(DateTime? registrationFrom, DateTime? registrationTo, bool onlyWithoutShoppingCart, int maxItemsToDelete = 5000) { var ctx = _customerRepository.Context; @@ -674,10 +564,6 @@ from inner in c_inner.DefaultIfEmpty() #region Customer roles - /// - /// Delete a customer role - /// - /// Customer role public virtual void DeleteCustomerRole(CustomerRole customerRole) { if (customerRole == null) @@ -694,11 +580,6 @@ public virtual void DeleteCustomerRole(CustomerRole customerRole) _eventPublisher.EntityDeleted(customerRole); } - /// - /// Gets a customer role - /// - /// Customer role identifier - /// Customer role public virtual CustomerRole GetCustomerRoleById(int customerRoleId) { if (customerRoleId == 0) @@ -707,11 +588,6 @@ public virtual CustomerRole GetCustomerRoleById(int customerRoleId) return _customerRoleRepository.GetById(customerRoleId); } - /// - /// Gets a customer role - /// - /// Customer role system name - /// Customer role public virtual CustomerRole GetCustomerRoleBySystemName(string systemName) { if (String.IsNullOrWhiteSpace(systemName)) @@ -729,11 +605,6 @@ orderby cr.Id }); } - /// - /// Gets all customer roles - /// - /// A value indicating whether to show hidden records - /// Customer role collection public virtual IList GetAllCustomerRoles(bool showHidden = false) { string key = string.Format(CUSTOMERROLES_ALL_KEY, showHidden); @@ -748,10 +619,6 @@ orderby cr.Name }); } - /// - /// Inserts a customer role - /// - /// Customer role public virtual void InsertCustomerRole(CustomerRole customerRole) { if (customerRole == null) @@ -765,10 +632,6 @@ public virtual void InsertCustomerRole(CustomerRole customerRole) _eventPublisher.EntityInserted(customerRole); } - /// - /// Updates the customer role - /// - /// Customer role public virtual void UpdateCustomerRole(CustomerRole customerRole) { if (customerRole == null) @@ -786,12 +649,6 @@ public virtual void UpdateCustomerRole(CustomerRole customerRole) #region Reward points - /// - /// Add or remove reward points for a product review - /// - /// The customer - /// The product - /// Whether to add or remove points public virtual void RewardPointsForProductReview(Customer customer, Product product, bool add) { if (_rewardPointsSettings.Enabled && _rewardPointsSettings.PointsForProductReview > 0) diff --git a/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs b/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs index 2dd762b398..0fbc43bd1c 100644 --- a/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs +++ b/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs @@ -718,10 +718,10 @@ private void ProcessProductPictures(ICollection> batch, Impor if (pictureBinary != null && pictureBinary.Length > 0) { // no equal picture found in sequence - var newPicture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, true); + var newPicture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, false, false); if (newPicture != null) { - var mapping = new ProductPicture() + var mapping = new ProductPicture { ProductId = row.Entity.Id, PictureId = newPicture.Id, diff --git a/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs b/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs index 99ee1e5744..96f04e9f7f 100644 --- a/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs +++ b/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs @@ -57,9 +57,16 @@ public static void ConvertAttributeQueryData(this NameValueCollection collection /// Takes selected elements from collection and creates a attribute XML string from it. /// how the name of the controls are formatted. frontend includes productId, backend does not. - public static string CreateSelectedAttributesXml(this NameValueCollection collection, int productId, IList variantAttributes, - IProductAttributeParser productAttributeParser, ILocalizationService localizationService, IDownloadService downloadService, CatalogSettings catalogSettings, - HttpRequestBase request, List warnings, bool formatWithProductId = true, int bundleItemId = 0) + public static string CreateSelectedAttributesXml(this NameValueCollection collection, + int productId, + IList variantAttributes, + IProductAttributeParser productAttributeParser, + ILocalizationService localizationService, + IDownloadService downloadService, + CatalogSettings catalogSettings, + HttpRequestBase request, List warnings, + bool formatWithProductId = true, + int bundleItemId = 0) { if (collection == null) return ""; @@ -142,16 +149,18 @@ public static string CreateSelectedAttributesXml(this NameValueCollection collec var download = downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { + download.IsTransient = false; + downloadService.UpdateDownload(download); selectedAttributes = productAttributeParser.AddProductAttribute(selectedAttributes, attribute, download.DownloadGuid.ToString()); } } else { - var httpPostedFile = request.Files[controlId]; - if (httpPostedFile != null && httpPostedFile.FileName.HasValue()) + var postedFile = request.Files[controlId]; + if (postedFile != null && postedFile.FileName.HasValue()) { int fileMaxSize = catalogSettings.FileUploadMaximumSizeBytes; - if (httpPostedFile.ContentLength > fileMaxSize) + if (postedFile.ContentLength > fileMaxSize) { warnings.Add(string.Format(localizationService.GetResource("ShoppingCart.MaximumUploadedFileSize"), (int)(fileMaxSize / 1024))); } @@ -163,10 +172,10 @@ public static string CreateSelectedAttributesXml(this NameValueCollection collec DownloadGuid = Guid.NewGuid(), UseDownloadUrl = false, DownloadUrl = "", - DownloadBinary = httpPostedFile.GetDownloadBits(), - ContentType = httpPostedFile.ContentType, - Filename = System.IO.Path.GetFileNameWithoutExtension(httpPostedFile.FileName), - Extension = System.IO.Path.GetExtension(httpPostedFile.FileName), + DownloadBinary = postedFile.InputStream.ToByteArray(), + ContentType = postedFile.ContentType, + Filename = System.IO.Path.GetFileNameWithoutExtension(postedFile.FileName), + Extension = System.IO.Path.GetExtension(postedFile.FileName), IsNew = true }; downloadService.InsertDownload(download); diff --git a/src/Libraries/SmartStore.Services/Logging/DefaultLogger.cs b/src/Libraries/SmartStore.Services/Logging/DefaultLogger.cs index d952288f74..8ca87875a8 100644 --- a/src/Libraries/SmartStore.Services/Logging/DefaultLogger.cs +++ b/src/Libraries/SmartStore.Services/Logging/DefaultLogger.cs @@ -7,6 +7,7 @@ using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Logging; using SmartStore.Core.Logging; +using SmartStore.Data; namespace SmartStore.Services.Logging { @@ -93,14 +94,7 @@ public virtual void ClearLog() } } - if (DataSettings.Current.IsSqlServer) - { - try - { - _dbContext.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); - } - catch { } - } + _dbContext.ShrinkDatabase(); } public virtual void ClearLog(DateTime toUtc, LogLevel logLevel) @@ -115,10 +109,7 @@ public virtual void ClearLog(DateTime toUtc, LogLevel logLevel) break; } - if (DataSettings.Current.IsSqlServer) - { - _dbContext.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); - } + _dbContext.ShrinkDatabase(); } catch { } } diff --git a/src/Libraries/SmartStore.Services/Media/DownloadService.cs b/src/Libraries/SmartStore.Services/Media/DownloadService.cs index 25d9bc9b2c..b7f03930e8 100644 --- a/src/Libraries/SmartStore.Services/Media/DownloadService.cs +++ b/src/Libraries/SmartStore.Services/Media/DownloadService.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Media; @@ -89,6 +91,7 @@ public virtual void InsertDownload(Download download) if (download == null) throw new ArgumentNullException("download"); + download.UpdatedOnUtc = DateTime.UtcNow; _downloadRepository.Insert(download); _eventPubisher.EntityInserted(download); @@ -99,6 +102,7 @@ public virtual void UpdateDownload(Download download) if (download == null) throw new ArgumentNullException("download"); + download.UpdatedOnUtc = DateTime.UtcNow; _downloadRepository.Update(download); _eventPubisher.EntityUpdated(download); diff --git a/src/Libraries/SmartStore.Services/Media/Extensions.cs b/src/Libraries/SmartStore.Services/Media/Extensions.cs deleted file mode 100644 index fcc6269049..0000000000 --- a/src/Libraries/SmartStore.Services/Media/Extensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.IO; -using System.Web; - -namespace SmartStore.Services.Media -{ - /// - /// Extensions - /// - public static class Extensions - { - /// - /// Gets the download binary array - /// - /// Posted file - /// Download binary array - public static byte[] GetDownloadBits(this HttpPostedFileBase postedFile) - { - Stream fs = postedFile.InputStream; - int size = postedFile.ContentLength; - byte[] binary = new byte[size]; - fs.Read(binary, 0, size); - return binary; - } - - /// - /// Gets the picture binary array - /// - /// Posted file - /// Picture binary array - public static byte[] GetPictureBits(this HttpPostedFileBase postedFile) - { - Stream fs = postedFile.InputStream; - int size = postedFile.ContentLength; - byte[] img = new byte[size]; - fs.Read(img, 0, size); - return img; - } - } -} diff --git a/src/Libraries/SmartStore.Services/Media/IDownloadService.cs b/src/Libraries/SmartStore.Services/Media/IDownloadService.cs index 70282f56a4..80faf7f50a 100644 --- a/src/Libraries/SmartStore.Services/Media/IDownloadService.cs +++ b/src/Libraries/SmartStore.Services/Media/IDownloadService.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; +using SmartStore.Core; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Orders; diff --git a/src/Libraries/SmartStore.Services/Media/IPictureService.cs b/src/Libraries/SmartStore.Services/Media/IPictureService.cs index f86c307925..216e7ee061 100644 --- a/src/Libraries/SmartStore.Services/Media/IPictureService.cs +++ b/src/Libraries/SmartStore.Services/Media/IPictureService.cs @@ -137,16 +137,17 @@ string GetPictureUrl(Picture picture, /// Pictures IList GetPicturesByProductId(int productId, int recordsToReturn = 0); - /// - /// Inserts a picture - /// - /// The picture binary - /// The picture MIME type - /// The SEO filename - /// A value indicating whether the picture is new - /// A value indicating whether to validated provided picture binary - /// Picture - Picture InsertPicture(byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool validateBinary = true); + /// + /// Inserts a picture + /// + /// The picture binary + /// The picture MIME type + /// The SEO filename + /// A value indicating whether the picture is new + /// A value indicating whether the picture is initially in transient state + /// A value indicating whether to validated provided picture binary + /// Picture + Picture InsertPicture(byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool isTransient = true, bool validateBinary = true); /// /// Updates the picture diff --git a/src/Libraries/SmartStore.Services/Media/MediaExtensions.cs b/src/Libraries/SmartStore.Services/Media/MediaExtensions.cs new file mode 100644 index 0000000000..e3beb9ece1 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Media/MediaExtensions.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Infrastructure; + +namespace SmartStore.Services.Media +{ + + public static class MediaHelper + { + + public static void UpdateDownloadTransientStateFor(TEntity entity, Expression> downloadIdProp, bool save = false) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => downloadIdProp); + + var propName = downloadIdProp.ExtractMemberInfo().Name; + int currentDownloadId = downloadIdProp.Compile().Invoke(entity); + var rs = EngineContext.Current.Resolve>(); + + UpdateTransientStateForEntityInternal(entity, propName, currentDownloadId, rs, null, save); + } + + public static void UpdateDownloadTransientStateFor(TEntity entity, Expression> downloadIdProp, bool save = false) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => downloadIdProp); + + var propName = downloadIdProp.ExtractMemberInfo().Name; + int currentDownloadId = downloadIdProp.Compile().Invoke(entity).GetValueOrDefault(); + var rs = EngineContext.Current.Resolve>(); + + UpdateTransientStateForEntityInternal(entity, propName, currentDownloadId, rs, null, save); + } + + public static void UpdatePictureTransientStateFor(TEntity entity, Expression> pictureIdProp, bool save = false) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => pictureIdProp); + + var propName = pictureIdProp.ExtractMemberInfo().Name; + int currentPictureId = pictureIdProp.Compile().Invoke(entity); + var rs = EngineContext.Current.Resolve>(); + + UpdateTransientStateForEntityInternal(entity, propName, currentPictureId, rs, GetPictureDeleteAction(), save); + } + + public static void UpdatePictureTransientStateFor(TEntity entity, Expression> pictureIdProp, bool save = false) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => pictureIdProp); + + var propName = pictureIdProp.ExtractMemberInfo().Name; + int currentPictureId = pictureIdProp.Compile().Invoke(entity).GetValueOrDefault(); + var rs = EngineContext.Current.Resolve>(); + + UpdateTransientStateForEntityInternal(entity, propName, currentPictureId, rs, GetPictureDeleteAction(), save); + } + + public static void UpdateDownloadTransientState(int? prevDownloadId, int? currentDownloadId, bool save = false) + { + var rs = EngineContext.Current.Resolve>(); + UpdateTransientStateCore(prevDownloadId.GetValueOrDefault(), currentDownloadId.GetValueOrDefault(), rs, null, save); + } + + public static void UpdateDownloadTransientState(int prevDownloadId, int currentDownloadId, bool save = false) + { + var rs = EngineContext.Current.Resolve>(); + UpdateTransientStateCore(prevDownloadId, currentDownloadId, rs, null, save); + } + + public static void UpdatePictureTransientState(int? prevPictureId, int? currentPictureId, bool save = false) + { + var rs = EngineContext.Current.Resolve>(); + UpdateTransientStateCore(prevPictureId.GetValueOrDefault(), currentPictureId.GetValueOrDefault(), rs, GetPictureDeleteAction(), save); + } + + public static void UpdatePictureTransientState(int prevPictureId, int currentPictureId, bool save = false) + { + var rs = EngineContext.Current.Resolve>(); + UpdateTransientStateCore(prevPictureId, currentPictureId, rs, GetPictureDeleteAction(), save); + } + + private static Action GetPictureDeleteAction() + { + Action deleteAction = pic => + { + var svc = EngineContext.Current.Resolve(); + svc.DeletePicture((Picture)pic); + }; + + return deleteAction; + } + + internal static void UpdateTransientStateForEntityInternal( + TEntity entity, + string propName, + int currentMediaId, + IRepository rs, + Action deleteAction, + bool save) where TEntity : BaseEntity where TMedia : BaseEntity + { + bool editMode = !entity.IsTransientRecord(); + var modifiedProperties = editMode ? rs.Context.GetModifiedProperties(entity) : new Dictionary(); + + object obj = null; + int prevMediaId = 0; + if (modifiedProperties.TryGetValue(propName, out obj)) + { + prevMediaId = ((int?)obj).GetValueOrDefault(); + } + + UpdateTransientStateCore(prevMediaId, currentMediaId, rs, deleteAction, save); + } + + internal static void UpdateTransientStateCore( + int prevMediaId, + int currentMediaId, + IRepository rs, + Action deleteAction, + bool save) + where TMedia : BaseEntity + { + var autoCommit = rs.AutoCommitEnabled; + rs.AutoCommitEnabled = false; + + try + { + TMedia media = null; + bool shouldSave = false; + + bool isModified = prevMediaId != currentMediaId; + + if (currentMediaId > 0 && isModified) + { + // new entity with a media or media replaced + media = rs.GetById(currentMediaId); + if (media != null) + { + var transient = media as ITransient; + if (transient != null) + { + transient.IsTransient = false; + shouldSave = true; + } + } + } + + if (prevMediaId > 0) + { + // ID changed, so delete old record + media = rs.GetById(prevMediaId); + if (media != null) + { + if (deleteAction == null) + { + rs.Delete(media); + } + else + { + deleteAction(media); + } + shouldSave = true; + } + } + + if (save && shouldSave) + { + rs.Context.SaveChanges(); + } + } + finally + { + rs.AutoCommitEnabled = autoCommit; + } + } + + + } + +} diff --git a/src/Libraries/SmartStore.Services/Media/PictureService.cs b/src/Libraries/SmartStore.Services/Media/PictureService.cs index bc11e71a36..dc767d2808 100644 --- a/src/Libraries/SmartStore.Services/Media/PictureService.cs +++ b/src/Libraries/SmartStore.Services/Media/PictureService.cs @@ -15,6 +15,7 @@ using SmartStore.Core.Logging; using SmartStore.Services.Configuration; using SmartStore.Utilities; +using SmartStore.Data; namespace SmartStore.Services.Media { @@ -51,16 +52,7 @@ public partial class PictureService : IPictureService #region Ctor - /// - /// Ctor - /// - /// Picture repository - /// Product picture repository - /// Setting service - /// Web helper - /// Logger - /// Event publisher - /// Media settings + public PictureService( IRepository pictureRepository, IRepository productPictureRepository, @@ -147,12 +139,6 @@ private string GetDefaultImageFileName(PictureType defaultPictureType = PictureT return defaultImageFileName; } - /// - /// Validates input picture dimensions and prevents that the image size exceeds global max size - /// - /// Picture binary - /// MIME type - /// Picture binary or throws an exception public virtual byte[] ValidatePicture(byte[] pictureBinary) { Size originalSize = this.GetPictureSize(pictureBinary); @@ -169,25 +155,11 @@ public virtual byte[] ValidatePicture(byte[] pictureBinary) } } - /// - /// Finds an equal picture by comparing the binary buffer - /// - /// The picture to find a duplicate for - /// The sequence of product pictures to seek within for duplicates - /// Id of equal picture if any - /// The picture binary for path when no picture equals in the sequence, null otherwise. public byte[] FindEqualPicture(string path, IEnumerable productPictures, out int equalPictureId) { return FindEqualPicture(File.ReadAllBytes(path), productPictures, out equalPictureId); } - /// - /// Finds an equal picture by comparing the binary buffer - /// - /// Binary picture data - /// The sequence of product pictures to seek within for duplicates - /// Id of equal picture if any - /// The picture binary for path when no picture equals in the sequence, null otherwise. public byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable productPictures, out int equalPictureId) { equalPictureId = 0; @@ -220,23 +192,11 @@ public byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable produc #region Methods - /// - /// Get picture SEO friendly name - /// - /// Name - /// Result public virtual string GetPictureSeName(string name) { return SeoHelper.GetSeName(name, true, false); } - /// - /// Get a picture local path - /// - /// Picture instance - /// The target picture size (longest side) - /// A value indicating whether the default picture is shown - /// public virtual string GetThumbLocalPath(Picture picture, int targetSize = 0, bool showDefaultPicture = true) { // 'GetPictureUrl' takes care of creating the thumb when not created already @@ -271,13 +231,6 @@ public virtual string GetThumbLocalPath(Picture picture, int targetSize = 0, boo } - /// - /// Gets the default picture URL - /// - /// The target picture size (longest side) - /// Default picture type - /// Store location URL; null to use determine the current store location automatically - /// Picture URL public virtual string GetDefaultPictureUrl(int targetSize = 0, PictureType defaultPictureType = PictureType.Entity, string storeLocation = null) { string defaultImageFileName = GetDefaultImageFileName(defaultPictureType); @@ -387,22 +340,11 @@ private byte[] LoadPictureFromFile(int pictureId, string mimeType, out string fi return File.ReadAllBytes(filePath); } - /// - /// Gets the loaded picture binary depending on picture storage settings - /// - /// Picture - /// Picture binary public virtual byte[] LoadPictureBinary(Picture picture) { return LoadPictureBinary(picture, this.StoreInDb); } - /// - /// Gets the loaded picture binary depending on picture storage settings - /// - /// Picture - /// Load from database; otherwise, from file system - /// Picture binary public virtual byte[] LoadPictureBinary(Picture picture, bool fromDb) { if (picture == null) @@ -462,15 +404,6 @@ internal Size GetPictureSize(byte[] pictureBinary) return size; } - /// - /// Get a picture URL - /// - /// Picture identifier - /// The target picture size (longest side) - /// A value indicating whether the default picture is shown - /// Store location URL; null to use determine the current store location automatically - /// Default picture type - /// Picture URL public virtual string GetPictureUrl( int pictureId, int targetSize = 0, @@ -482,15 +415,6 @@ public virtual string GetPictureUrl( return GetPictureUrl(picture, targetSize, showDefaultPicture, storeLocation, defaultPictureType); } - /// - /// Get a picture URL - /// - /// Picture instance - /// The target picture size (longest side) - /// A value indicating whether the default picture is shown - /// Store location URL; null to use determine the current store location automatically - /// Default picture type - /// Picture URL public virtual string GetPictureUrl( Picture picture, int targetSize = 0, @@ -580,37 +504,27 @@ public virtual Picture GetPictureById(int pictureId) return picture; } - /// - /// Deletes a picture - /// - /// Picture public virtual void DeletePicture(Picture picture) { if (picture == null) throw new ArgumentNullException("picture"); - //delete thumbs + // delete thumbs _imageCache.DeleteCachedImages(picture); - //delete from file system + // delete from file system if (!this.StoreInDb) { DeletePictureOnFileSystem(picture); } - //delete from database + // delete from database _pictureRepository.Delete(picture); - //event notification + // event notification _eventPublisher.EntityDeleted(picture); } - /// - /// Gets a collection of pictures - /// - /// Current page - /// Items on each page - /// Paged list of pictures public virtual IPagedList GetPictures(int pageIndex, int pageSize) { var query = from p in _pictureRepository.Table @@ -620,12 +534,6 @@ orderby p.Id descending return pics; } - /// - /// Gets pictures by product identifier - /// - /// Product identifier - /// Number of records to return. 0 if you want to get all items - /// Pictures public virtual IList GetPicturesByProductId(int productId, int recordsToReturn = 0) { if (productId == 0) @@ -644,16 +552,7 @@ orderby pp.DisplayOrder return pics; } - /// - /// Inserts a picture - /// - /// The picture binary - /// The picture MIME type - /// The SEO filename - /// A value indicating whether the picture is new - /// A value indicating whether to validated provided picture binary - /// Picture - public virtual Picture InsertPicture(byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool validateBinary = true) + public virtual Picture InsertPicture(byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool isTransient = true, bool validateBinary = true) { mimeType = mimeType.EmptyNull(); mimeType = mimeType.Truncate(20); @@ -670,6 +569,8 @@ public virtual Picture InsertPicture(byte[] pictureBinary, string mimeType, stri picture.MimeType = mimeType; picture.SeoFilename = seoFilename; picture.IsNew = isNew; + picture.IsTransient = isTransient; + picture.UpdatedOnUtc = DateTime.UtcNow; _pictureRepository.Insert(picture); @@ -684,16 +585,6 @@ public virtual Picture InsertPicture(byte[] pictureBinary, string mimeType, stri return picture; } - /// - /// Updates the picture - /// - /// The picture identifier - /// The picture binary - /// The picture MIME type - /// The SEO filename - /// A value indicating whether the picture is new - /// A value indicating whether to validated provided picture binary - /// Picture public virtual Picture UpdatePicture(int pictureId, byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool validateBinary = true) { mimeType = mimeType.EmptyNull().Truncate(20); @@ -718,6 +609,7 @@ public virtual Picture UpdatePicture(int pictureId, byte[] pictureBinary, string picture.MimeType = mimeType; picture.SeoFilename = seoFilename; picture.IsNew = isNew; + picture.UpdatedOnUtc = DateTime.UtcNow; _pictureRepository.Update(picture); @@ -732,22 +624,15 @@ public virtual Picture UpdatePicture(int pictureId, byte[] pictureBinary, string return picture; } - /// - /// Updates a SEO filename of a picture - /// - /// The picture identifier - /// The SEO filename - /// Picture public virtual Picture SetSeoFilename(int pictureId, string seoFilename) { var picture = GetPictureById(pictureId); if (picture == null) throw new ArgumentException("No picture found with the specified id"); - //update if it has been changed + // update if it has been changed if (seoFilename != picture.SeoFilename) { - //update picture picture = UpdatePicture(picture.Id, LoadPictureBinary(picture), picture.MimeType, seoFilename, true, false); } return picture; @@ -757,10 +642,6 @@ public virtual Picture SetSeoFilename(int pictureId, string seoFilename) #region Properties - - /// - /// Gets or sets a value indicating whether the images should be stored in data base. - /// public virtual bool StoreInDb { get @@ -854,6 +735,7 @@ protected int MovePictures(bool toDb) } // explicitly attach modified entity to context, because we disabled AutoCommit + picture.UpdatedOnUtc = DateTime.UtcNow; _pictureRepository.Update(picture); i++; @@ -898,13 +780,9 @@ protected int MovePictures(bool toDb) } // shrink database (only when DB > FS and success) - if (!toDb && !failed && DataSettings.Current.IsSqlServer) + if (!toDb && !failed) { - try - { - ctx.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); - } - catch { } + ctx.ShrinkDatabase(); } } diff --git a/src/Libraries/SmartStore.Services/Media/TransientMediaClearTask.cs b/src/Libraries/SmartStore.Services/Media/TransientMediaClearTask.cs new file mode 100644 index 0000000000..4392ca231a --- /dev/null +++ b/src/Libraries/SmartStore.Services/Media/TransientMediaClearTask.cs @@ -0,0 +1,70 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Media; +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.Media +{ + /// + /// Represents a task for deleting transient media from the database + /// (pictures and downloads which have been uploaded but never assigned to an entity) + /// + public partial class TransientMediaClearTask : ITask + { + private readonly IPictureService _pictureService; + private readonly IRepository _pictureRepository; + private readonly IRepository _downloadRepository; + + public TransientMediaClearTask( + IPictureService pictureService, + IRepository pictureRepository, + IRepository downloadRepository) + { + this._pictureService = pictureService; + this._pictureRepository = pictureRepository; + this._downloadRepository = downloadRepository; + } + + 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; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs index a51b84a925..b31f3b4ce3 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs @@ -3,6 +3,7 @@ using System.Linq.Expressions; using SmartStore.Core.Data; using SmartStore.Core.Domain.Messages; +using SmartStore.Data; using SmartStore.Services.Tasks; namespace SmartStore.Services.Messages @@ -23,6 +24,8 @@ public void Execute(TaskExecutionContext ctx) { var olderThan = DateTime.UtcNow.AddDays(-14); _qeRepository.DeleteAll(x => x.SentOnUtc.HasValue && x.CreatedOnUtc < olderThan); + + _qeRepository.Context.ShrinkDatabase(); } } } diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index d955f22aab..61470258eb 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -1096,7 +1096,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR var itemWeight = _shippingService.GetShoppingCartItemWeight(sc); //save order item - var orderItem = new OrderItem() + var orderItem = new OrderItem { OrderItemGuid = Guid.NewGuid(), Order = order, @@ -1149,7 +1149,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR for (int i = 0; i < sc.Item.Quantity; i++) { - var gc = new GiftCard() + var gc = new GiftCard { GiftCardType = sc.Item.Product.GiftCardType, PurchasedWithOrderItem = orderItem, diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 8c64d2273a..c63c12ccc2 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -161,6 +161,8 @@ + + @@ -316,7 +318,6 @@ - diff --git a/src/Plugins/SmartStore.WebApi/Controllers/Api/UploadsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/Api/UploadsController.cs index 232860f3c8..8cc5b1ecaf 100644 --- a/src/Plugins/SmartStore.WebApi/Controllers/Api/UploadsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/Api/UploadsController.cs @@ -120,7 +120,7 @@ public async Task> PostProductImages() { var seoName = _pictureService.Value.GetPictureSeName(Path.GetFileNameWithoutExtension(image.FileName)); - var newPicture = _pictureService.Value.InsertPicture(pictureBinary, image.MediaType, seoName, true, false); + var newPicture = _pictureService.Value.InsertPicture(pictureBinary, image.MediaType, seoName, true, false, false); if (newPicture != null) { diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs index 5e69151979..2e5378e75c 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs @@ -77,7 +77,7 @@ protected virtual void NotifyError(Exception exception, bool durable = true, boo LogException(exception); } - _notifier.Value.Error(exception.Message, durable); + _notifier.Value.Error(exception.ToAllMessages(), durable); } protected virtual ActionResult RedirectToReferrer() diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs index 0b7020875a..02f7f9cf9e 100644 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs @@ -564,11 +564,13 @@ public static MvcHtmlString SettingOverrideCheckbox(this HtmlHel return MvcHtmlString.Empty; } - public static MvcHtmlString SettingEditorFor(this HtmlHelper helper, - Expression> expression, string parentSelector = null) + public static MvcHtmlString SettingEditorFor(this HtmlHelper helper, + Expression> expression, + string parentSelector = null, + object additionalViewData = null) { var checkbox = helper.SettingOverrideCheckbox(expression, parentSelector); - var editor = helper.EditorFor(expression); + var editor = helper.EditorFor(expression, additionalViewData); return MvcHtmlString.Create(checkbox.ToString() + editor.ToString()); } diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/HttpContextExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/HttpExtensions.cs similarity index 75% rename from src/Presentation/SmartStore.Web.Framework/Extensions/HttpContextExtensions.cs rename to src/Presentation/SmartStore.Web.Framework/Extensions/HttpExtensions.cs index 9862599a4c..f01379faec 100644 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/HttpContextExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/HttpExtensions.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.IO; using System.Web; using System.Web.Mvc; @@ -8,7 +10,7 @@ namespace SmartStore { - public static class HttpContextExtensions + public static class HttpExtensions { public static bool IsAdminArea(this HttpRequest request) @@ -70,31 +72,63 @@ public static bool IsPublicArea(this HttpRequestBase request) } } - public static Stream ToFileStream(this HttpRequestBase request, out string fileName, out string contentType, string paramName = "qqfile") { - fileName = contentType = ""; - Stream stream = null; + public static PostedFileResult ToPostedFileResult(this HttpRequestBase httpRequest) + { + if (httpRequest != null && httpRequest.Files.Count > 0) + { + return httpRequest.Files[0].ToPostedFileResult(); + } - if (request[paramName].HasValue()) - { - stream = request.InputStream; - fileName = request[paramName]; - } - else - { - if (request.Files.Count > 0) - { - stream = request.Files[0].InputStream; - contentType = request.Files[0].ContentType; - fileName = Path.GetFileName(request.Files[0].FileName); - } - } + return null; + } - if (contentType.IsEmpty()) - { - contentType = SmartStore.Core.IO.MimeTypes.MapNameToMimeType(fileName); - } + public static PostedFileResult ToPostedFileResult(this HttpPostedFile httpFile) + { + if (httpFile != null && httpFile.ContentLength > 0) + { + return new PostedFileResult(new HttpPostedFileWrapper(httpFile)); + } - return stream; + return null; + } + + public static PostedFileResult ToPostedFileResult(this HttpPostedFileBase httpFile) + { + if (httpFile != null && httpFile.ContentLength > 0) + { + return new PostedFileResult(httpFile); + } + + return null; + } + + public static IEnumerable ToPostedFileResults(this HttpFileCollection httpFileCollection) + { + if (httpFileCollection != null && httpFileCollection.Count > 0) + { + return new HttpFileCollectionWrapper(httpFileCollection).ToPostedFileResults(); + } + + return Enumerable.Empty(); + } + + public static IEnumerable ToPostedFileResults(this HttpFileCollectionBase httpFileCollection) + { + if (httpFileCollection == null) + yield break; + + var batchId = Guid.NewGuid(); + + for (var i = 0; i < httpFileCollection.Count; i++) + { + var httpFile = httpFileCollection[i]; + var result = httpFile.ToPostedFileResult(); + if (result != null) + { + result.BatchId = batchId; + yield return result; + } + } } public static RouteData GetRouteData(this HttpContextBase httpContext) diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/PostedFileResult.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/PostedFileResult.cs new file mode 100644 index 0000000000..9ba2b0ed2d --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/PostedFileResult.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; +using SmartStore.Core.IO; + +namespace SmartStore +{ + public class PostedFileResult + { + private static readonly Regex s_ImageTypes = new Regex(@"(.*?)\.(gif|jpg|jpeg|jpe|jfif|pjpeg|pjp|png|tiff|tif|bmp|ico|svg)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private readonly HttpPostedFileBase _httpFile; + + private string _contentType; + private string _fileName; + private string _fileTitle; + private string _fileExt; + private bool? _isImage; + + public PostedFileResult(HttpPostedFileBase httpFile) + { + Guard.ArgumentNotNull(() => httpFile); + + this._httpFile = httpFile; + + this.TimeStamp = DateTime.UtcNow; + this.BatchId = Guid.NewGuid(); + } + + public HttpPostedFileBase File + { + get { return _httpFile; } + } + + public DateTime TimeStamp + { + get; + private set; + } + + public Guid BatchId + { + get; + internal set; + } + + public string FileName + { + get + { + if (_fileName == null) + { + _fileName = Path.GetFileName(_httpFile.FileName); + } + return _fileName; + } + } + + public string FileTitle + { + get + { + if (_fileTitle == null) + { + _fileTitle = Path.GetFileNameWithoutExtension(this.FileName); + } + return _fileTitle; + } + } + + public string FileExtension + { + get + { + if (_fileExt == null) + { + _fileExt = Path.GetExtension(this.FileName).EmptyNull(); + } + return _fileExt; + } + } + + public string ContentType + { + get + { + if (_contentType == null) + { + var contentType = _httpFile.ContentType; + + if (contentType == null && this.FileExtension.HasValue()) + { + contentType = MimeTypes.MapNameToMimeType(this.FileExtension); + + // ContentType is not always available. + // That's why we manually update it here + if (contentType.IsEmpty()) + { + switch (this.FileExtension.ToLowerInvariant()) + { + case ".bmp": + contentType = "image/bmp"; + break; + case ".gif": + contentType = "image/gif"; + break; + case ".jpeg": + case ".jpg": + case ".jpe": + case ".jfif": + case ".pjpeg": + case ".pjp": + contentType = "image/jpeg"; + break; + case ".png": + contentType = "image/png"; + break; + case ".tiff": + case ".tif": + contentType = "image/tiff"; + break; + case ".svg": + contentType = "image/svg+xml"; + break; + case ".ico": + contentType = "image/x-icon"; + break; + default: + break; + } + } + } + + _contentType = contentType.EmptyNull(); + } + return _contentType; + } + } + + public bool IsImage + { + get + { + if (!_isImage.HasValue) + { + _isImage = s_ImageTypes.IsMatch(FileExtension); + } + return _isImage.Value; + } + } + + public int Size + { + get { return _httpFile.ContentLength; } + } + + public Stream Stream + { + get { return _httpFile.InputStream; } + } + + public byte[] Buffer + { + get + { + return _httpFile.InputStream.ToByteArray(); + } + } + + public bool FileNameMatches(string pattern) + { + return Regex.IsMatch(_httpFile.FileName, pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline); + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj index cd2f03fa0d..26765a39af 100644 --- a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj +++ b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj @@ -239,10 +239,11 @@ - + + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs index ceda143ff6..94dddf36f5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs @@ -519,6 +519,9 @@ public ActionResult Create(CategoryModel model, bool continueEditing, FormCollec var category = model.ToEntity(); category.CreatedOnUtc = DateTime.UtcNow; category.UpdatedOnUtc = DateTime.UtcNow; + + MediaHelper.UpdatePictureTransientStateFor(category, c => c.PictureId); + _categoryService.InsertCategory(category); //search engine name @@ -634,15 +637,20 @@ public ActionResult Edit(CategoryModel model, bool continueEditing, FormCollecti if (ModelState.IsValid) { - int prevPictureId = category.PictureId.GetValueOrDefault(); category = model.ToEntity(category); + + MediaHelper.UpdatePictureTransientStateFor(category, c => c.PictureId); + category.UpdatedOnUtc = DateTime.UtcNow; _categoryService.UpdateCategory(category); + //search engine name model.SeName = category.ValidateSeName(model.SeName, category.Name, true); _urlRecordService.SaveSlug(category, model.SeName, 0); + //locales UpdateLocales(category, model); + //discounts var allDiscounts = _discountService.GetAllDiscounts(DiscountType.AssignedToCategories, null, true); foreach (var discount in allDiscounts) @@ -665,14 +673,6 @@ public ActionResult Edit(CategoryModel model, bool continueEditing, FormCollecti //update "HasDiscountsApplied" property _categoryService.UpdateHasDiscountsApplied(category); - //delete an old picture (if deleted or updated) - if (prevPictureId > 0 && prevPictureId != category.PictureId) - { - var prevPicture = _pictureService.GetPictureById(prevPictureId); - if (prevPicture != null) - _pictureService.DeletePicture(prevPicture); - } - //update picture seo file name UpdatePictureSeoNames(category); @@ -718,7 +718,7 @@ public ActionResult Delete(int id, string deleteType) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - + var category = _categoryService.GetCategoryById(id); if (category == null) return RedirectToAction("List"); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ContentSliderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ContentSliderController.cs index 2469fe3fb6..85215e2d65 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ContentSliderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ContentSliderController.cs @@ -134,6 +134,8 @@ public ActionResult Index(ContentSliderSettingsModel model) _contentSliderSettings.AutoPlay = model.AutoPlay; _contentSliderSettings.AutoPlayDelay = model.AutoPlayDelay; + MediaHelper.UpdatePictureTransientState(0, model.BackgroundPictureId, true); + _settingService.SaveSetting(_contentSliderSettings); var viewModel = PrepareContentSliderSettingsModel(model); @@ -174,6 +176,7 @@ public ActionResult CreateSlide(ContentSliderSlideModel model) model.PictureUrl = _pictureService.GetPictureUrl(model.PictureId); model.LanguageName = _languageService.GetLanguageByCulture(model.LanguageCulture).Name; _contentSliderSettings.Slides.Add(model.ToEntity()); + MediaHelper.UpdatePictureTransientState(0, model.PictureId, true); _settingService.SaveSetting(_contentSliderSettings); NotifySuccess(_localizationService.GetResource("Admin.Configuration.ContentSlider.Slide.Added")); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/DownloadController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/DownloadController.cs index b152f65b46..fd60c0768c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/DownloadController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/DownloadController.cs @@ -45,14 +45,14 @@ public ActionResult DownloadFile(int downloadId) [ValidateInput(false)] public ActionResult SaveDownloadUrl(string downloadUrl) { - //insert - var download = new Download() - { - DownloadGuid = Guid.NewGuid(), - UseDownloadUrl = true, - DownloadUrl = downloadUrl, - IsNew = true - }; + var download = new Download + { + DownloadGuid = Guid.NewGuid(), + UseDownloadUrl = true, + DownloadUrl = downloadUrl, + IsNew = true, + IsTransient = true + }; _downloadService.InsertDownload(download); return Json(new { downloadId = download.Id }, JsonRequestBehavior.AllowGet); @@ -61,59 +61,48 @@ public ActionResult SaveDownloadUrl(string downloadUrl) [HttpPost] public ActionResult AsyncUpload() { - //we process it distinct ways based on a browser - //find more info here http://stackoverflow.com/questions/4884920/mvc3-valums-ajax-file-upload - Stream stream = null; - var fileName = ""; - var contentType = ""; - if (String.IsNullOrEmpty(Request["qqfile"])) - { - // IE - HttpPostedFileBase httpPostedFile = Request.Files[0]; - if (httpPostedFile == null) - throw new ArgumentException("No file uploaded"); - stream = httpPostedFile.InputStream; - fileName = Path.GetFileName(httpPostedFile.FileName); - contentType = httpPostedFile.ContentType; - } - else - { - //Webkit, Mozilla - stream = Request.InputStream; - fileName = Request["qqfile"]; - } - - var fileBinary = new byte[stream.Length]; - stream.Read(fileBinary, 0, fileBinary.Length); - - var fileExtension = Path.GetExtension(fileName); - if (!String.IsNullOrEmpty(fileExtension)) - fileExtension = fileExtension.ToLowerInvariant(); + var postedFile = Request.ToPostedFileResult(); + if (postedFile == null) + { + throw new ArgumentException("No file uploaded"); + } - var download = new Download() + var download = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = false, DownloadUrl = "", - DownloadBinary = fileBinary, - ContentType = contentType, + DownloadBinary = postedFile.Buffer, + ContentType = postedFile.ContentType, //we store filename without extension for downloads - Filename = Path.GetFileNameWithoutExtension(fileName), - Extension = fileExtension, - IsNew = true + Filename = postedFile.FileTitle, + Extension = postedFile.FileExtension, + IsNew = true, + IsTransient = true }; _downloadService.InsertDownload(download); - //when returning JSON the mime-type must be set to text/plain - //otherwise some browsers will pop-up a "Save As" dialog. return Json(new { success = true, downloadId = download.Id, - fileName = download.Filename + download.Extension, + fileName = download.Filename.Truncate(50, "...") + download.Extension, downloadUrl = Url.Action("DownloadFile", new { downloadId = download.Id }) - }, - "text/plain"); + }); } + + [HttpPost] + public ActionResult DeleteDownload(int downloadId) + { + var download = _downloadService.GetDownloadById(downloadId); + if (download == null) + { + NotifyError("No download record found with the specified id"); + return Json(new { success = false }); + } + + _downloadService.DeleteDownload(download); + return Json(new { success = true }); + } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs index 0ab3fdcb3d..d13971d7c3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/LanguageController.cs @@ -486,12 +486,7 @@ public ActionResult ImportXml(int id, FormCollection form, ImportModeFlags mode, var file = Request.Files["importxmlfile"]; if (file != null && file.ContentLength > 0) { - using (var sr = new StreamReader(file.InputStream, Encoding.UTF8)) - { - string content = sr.ReadToEnd(); - _localizationService.ImportResourcesFromXml(language, content, mode: mode, updateTouchedResources: updateTouched); - } - + _localizationService.ImportResourcesFromXml(language, file.InputStream.AsString(), mode: mode, updateTouchedResources: updateTouched); } else { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs index 178d046379..677af26b67 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ManufacturerController.cs @@ -311,6 +311,8 @@ public ActionResult Create(ManufacturerModel model, bool continueEditing) var manufacturer = model.ToEntity(); manufacturer.CreatedOnUtc = DateTime.UtcNow; manufacturer.UpdatedOnUtc = DateTime.UtcNow; + + MediaHelper.UpdatePictureTransientStateFor(manufacturer, m => m.PictureId); _manufacturerService.InsertManufacturer(manufacturer); @@ -381,10 +383,9 @@ public ActionResult Edit(ManufacturerModel model, bool continueEditing) if (ModelState.IsValid) { - int prevPictureId = manufacturer.PictureId.GetValueOrDefault(); manufacturer = model.ToEntity(manufacturer); + MediaHelper.UpdatePictureTransientStateFor(manufacturer, m => m.PictureId); manufacturer.UpdatedOnUtc = DateTime.UtcNow; - _manufacturerService.UpdateManufacturer(manufacturer); //search engine name @@ -394,14 +395,6 @@ public ActionResult Edit(ManufacturerModel model, bool continueEditing) //locales UpdateLocales(manufacturer, model); - //delete an old picture (if deleted or updated) - if (prevPictureId > 0 && prevPictureId != manufacturer.PictureId.GetValueOrDefault()) - { - var prevPicture = _pictureService.GetPictureById(prevPictureId); - if (prevPicture != null) - _pictureService.DeletePicture(prevPicture); - } - //update picture seo file name UpdatePictureSeoNames(manufacturer); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/MediaController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/MediaController.cs index ceac9c3ccc..aa64078b5f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/MediaController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/MediaController.cs @@ -12,7 +12,6 @@ namespace SmartStore.Admin.Controllers public partial class MediaController : AdminControllerBase { - private static readonly Regex s_allowedImageTypes = new Regex(@"(.*?)\.(gif|jpg|jpeg|png|bmp|ico|svg)", RegexOptions.Compiled | RegexOptions.IgnoreCase); private readonly IPermissionService _permissionService; private readonly IWebHelper _webHelper; @@ -51,46 +50,34 @@ public ActionResult UploadImageAjax() private UploadFileResult UploadImageInternal() { - if (Request.Files.Count == 0) + var postedFile = Request.ToPostedFileResult(); + if (postedFile == null) { return new UploadFileResult { Message = "No file uploaded" }; } - var uploadFile = Request.Files[0]; - if (uploadFile == null) - { - return new UploadFileResult { Message = "No file name provided" }; - } - - var fileName = Path.GetFileName(uploadFile.FileName); - if (fileName.IsEmpty()) + if (postedFile.FileName.IsEmpty()) { return new UploadFileResult { Message = "No file name provided" }; } var directory = "~/Media/Uploaded/"; - var filePath = Path.Combine(_webHelper.MapPath(directory), fileName); + var filePath = Path.Combine(_webHelper.MapPath(directory), postedFile.FileName); - if (!IsAllowedImageType(fileName)) + if (!!postedFile.IsImage) { - return new UploadFileResult { Message = "Files with extension '{0}' cannot be uploaded".FormatInvariant(Path.GetExtension(filePath)) }; + return new UploadFileResult { Message = "Files with extension '{0}' cannot be uploaded".FormatInvariant(postedFile.FileExtension) }; } - uploadFile.SaveAs(filePath); + postedFile.File.SaveAs(filePath); return new UploadFileResult { Success = true, - Url = this.Url.Content(string.Format("{0}{1}", directory, fileName)) + Url = this.Url.Content(string.Format("{0}{1}", directory, postedFile.FileName)) }; } - [NonAction] - protected virtual bool IsAllowedImageType(string path) - { - return s_allowedImageTypes.IsMatch(path); - } - public class UploadFileResult { public bool Success { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs index c330b410b5..78f290f01f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/MessageTemplateController.cs @@ -5,6 +5,7 @@ using SmartStore.Collections; using SmartStore.Core.Domain.Messages; using SmartStore.Services.Localization; +using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.Security; using SmartStore.Services.Stores; @@ -91,13 +92,19 @@ public void UpdateLocales(MessageTemplate mt, MessageTemplateModel model) { foreach (var localized in model.Locales) { - _localizedEntityService.SaveLocalizedValue(mt, x => x.BccEmailAddresses, localized.BccEmailAddresses, localized.LanguageId); - _localizedEntityService.SaveLocalizedValue(mt, x => x.Subject, localized.Subject, localized.LanguageId); - _localizedEntityService.SaveLocalizedValue(mt,x => x.Body, localized.Body, localized.LanguageId); - _localizedEntityService.SaveLocalizedValue(mt, x => x.EmailAccountId, localized.EmailAccountId, localized.LanguageId); - _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment1FileId, localized.Attachment1FileId, localized.LanguageId); - _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment2FileId, localized.Attachment2FileId, localized.LanguageId); - _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment3FileId, localized.Attachment3FileId, localized.LanguageId); + int lid = localized.LanguageId; + + MediaHelper.UpdateDownloadTransientState(mt.GetLocalized(x => x.Attachment1FileId, lid, false, false), localized.Attachment1FileId, true); + MediaHelper.UpdateDownloadTransientState(mt.GetLocalized(x => x.Attachment2FileId, lid, false, false), localized.Attachment2FileId, true); + MediaHelper.UpdateDownloadTransientState(mt.GetLocalized(x => x.Attachment3FileId, lid, false, false), localized.Attachment3FileId, true); + + _localizedEntityService.SaveLocalizedValue(mt, x => x.BccEmailAddresses, localized.BccEmailAddresses, lid); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Subject, localized.Subject, lid); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Body, localized.Body, lid); + _localizedEntityService.SaveLocalizedValue(mt, x => x.EmailAccountId, localized.EmailAccountId, lid); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment1FileId, localized.Attachment1FileId, lid); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment2FileId, localized.Attachment2FileId, lid); + _localizedEntityService.SaveLocalizedValue(mt, x => x.Attachment3FileId, localized.Attachment3FileId, lid); } } @@ -221,6 +228,11 @@ public ActionResult Edit(MessageTemplateModel model, bool continueEditing) if (ModelState.IsValid) { messageTemplate = model.ToEntity(messageTemplate); + + MediaHelper.UpdateDownloadTransientStateFor(messageTemplate, x => x.Attachment1FileId); + MediaHelper.UpdateDownloadTransientStateFor(messageTemplate, x => x.Attachment2FileId); + MediaHelper.UpdateDownloadTransientStateFor(messageTemplate, x => x.Attachment3FileId); + _messageTemplateService.UpdateMessageTemplate(messageTemplate); // Stores diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs index c4157b9b0a..2f50f21a74 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs @@ -470,7 +470,7 @@ protected void PrepareOrderDetailsModel(OrderModel model, Order order) hasDownloadableItems = true; orderItem.Product.MergeWithCombination(orderItem.AttributesXml); - var orderItemModel = new OrderModel.OrderItemModel() + var orderItemModel = new OrderModel.OrderItemModel { Id = orderItem.Id, ProductId = orderItem.ProductId, @@ -496,7 +496,7 @@ protected void PrepareOrderDetailsModel(OrderModel model, Order order) foreach (var bundleItem in bundleData) { - var bundleItemModel = new OrderModel.BundleItemModel() + var bundleItemModel = new OrderModel.BundleItemModel { ProductId = bundleItem.ProductId, Sku = bundleItem.Sku, @@ -1642,7 +1642,7 @@ public ActionResult UploadLicenseFilePopup(int id, int orderItemId) if (!orderItem.Product.IsDownload) throw new ArgumentException("Product is not downloadable"); - var model = new OrderModel.UploadLicenseModel() + var model = new OrderModel.UploadLicenseModel { LicenseDownloadId = orderItem.LicenseDownloadId.HasValue ? orderItem.LicenseDownloadId.Value : 0, OrderId = order.Id, @@ -1673,6 +1673,9 @@ public ActionResult UploadLicenseFilePopup(string btnId, string formId, OrderMod orderItem.LicenseDownloadId = model.LicenseDownloadId; else orderItem.LicenseDownloadId = null; + + MediaHelper.UpdateDownloadTransientStateFor(orderItem, x => x.LicenseDownloadId); + _orderService.UpdateOrder(order); //success @@ -1701,6 +1704,7 @@ public ActionResult DeleteLicenseFilePopup(string btnId, string formId, OrderMod //attach license orderItem.LicenseDownloadId = null; + MediaHelper.UpdateDownloadTransientStateFor(orderItem, x => x.LicenseDownloadId); _orderService.UpdateOrder(order); //success @@ -1877,7 +1881,7 @@ public ActionResult AddProductToOrderDetails(int orderId, int productId, bool ad string attributeDescription = _productAttributeFormatter.FormatAttributes(product, attributes, order.Customer); //save item - var orderItem = new OrderItem() + var orderItem = new OrderItem { OrderItemGuid = Guid.NewGuid(), Order = order, diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PackagingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PackagingController.cs index ac947d3c8c..4f67cb74c4 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PackagingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PackagingController.cs @@ -52,8 +52,8 @@ public ActionResult UploadPackage(FormCollection form, string returnUrl = "") try { - var file = Request.Files["packagefile"]; - if (file != null && file.ContentLength > 0) + var file = Request.Files["packagefile"].ToPostedFileResult(); + if (file != null) { var requiredPermission = (isTheme = PackagingUtils.IsTheme(file.FileName)) ? StandardPermissionProvider.ManageThemes @@ -64,7 +64,7 @@ public ActionResult UploadPackage(FormCollection form, string returnUrl = "") return AccessDeniedView(); } - if (!Path.GetExtension(file.FileName).IsCaseInsensitiveEqual(".nupkg")) + if (!file.FileExtension.IsCaseInsensitiveEqual(".nupkg")) { NotifyError(T("Admin.Packaging.NotAPackage")); return Redirect(returnUrl); @@ -79,7 +79,7 @@ public ActionResult UploadPackage(FormCollection form, string returnUrl = "") _themeRegistry.Value.StopMonitoring(); } - var packageInfo = _packageManager.Install(file.InputStream, location, appPath); + var packageInfo = _packageManager.Install(file.Stream, location, appPath); if (isTheme) { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PictureController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PictureController.cs index 6eac36619a..ae3a699877 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PictureController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PictureController.cs @@ -22,82 +22,21 @@ public PictureController(IPictureService pictureService, } [HttpPost] - public ActionResult AsyncUpload() + public ActionResult AsyncUpload(bool isTransient = false) { if (!_permissionService.Authorize(StandardPermissionProvider.UploadPictures)) - return Json(new { success = false, error = "You do not have required permissions" }, "text/plain"); + return Json(new { success = false, error = "You do not have the required permissions" }); - //we process it distinct ways based on a browser - //find more info here http://stackoverflow.com/questions/4884920/mvc3-valums-ajax-file-upload - Stream stream = null; - var fileName = ""; - var contentType = ""; - if (String.IsNullOrEmpty(Request["qqfile"])) - { - // IE - HttpPostedFileBase httpPostedFile = Request.Files[0]; - if (httpPostedFile == null) - throw new ArgumentException("No file uploaded"); - stream = httpPostedFile.InputStream; - fileName = Path.GetFileName(httpPostedFile.FileName); - contentType = httpPostedFile.ContentType; - } - else - { - //Webkit, Mozilla - stream = Request.InputStream; - fileName = Request["qqfile"]; - } + var postedFile = Request.ToPostedFileResult(); - var fileBinary = new byte[stream.Length]; - stream.Read(fileBinary, 0, fileBinary.Length); + var picture = _pictureService.InsertPicture(postedFile.Buffer, postedFile.ContentType, null, true, isTransient); - var fileExtension = Path.GetExtension(fileName); - if (!String.IsNullOrEmpty(fileExtension)) - fileExtension = fileExtension.ToLowerInvariant(); - //contentType is not always available - //that's why we manually update it here - //http://www.sfsu.edu/training/mimetype.htm - if (String.IsNullOrEmpty(contentType)) - { - switch (fileExtension) - { - case ".bmp": - contentType = "image/bmp"; - break; - case ".gif": - contentType = "image/gif"; - break; - case ".jpeg": - case ".jpg": - case ".jpe": - case ".jfif": - case ".pjpeg": - case ".pjp": - contentType = "image/jpeg"; - break; - case ".png": - contentType = "image/png"; - break; - case ".tiff": - case ".tif": - contentType = "image/tiff"; - break; - default: - break; - } - } - - var picture = _pictureService.InsertPicture(fileBinary, contentType, null, true); - //when returning JSON the mime-type must be set to text/plain - //otherwise some browsers will pop-up a "Save As" dialog. return Json( new { success = true, pictureId = picture.Id, imageUrl = _pictureService.GetPictureUrl(picture, 100) - }, - "text/plain"); + }); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index c5fe38faec..938076253c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -228,7 +228,7 @@ protected void UpdateProductGeneralInfo(Product product, ProductModel model) p.IsGiftCard = m.IsGiftCard; p.GiftCardTypeId = m.GiftCardTypeId; - + p.IsDownload = m.IsDownload; p.DownloadId = m.DownloadId; p.UnlimitedDownloads = m.UnlimitedDownloads; @@ -553,6 +553,10 @@ private void UpdateDataOfExistingProduct(Product product, ProductModel model, bo var nameChanged = modifiedProperties.ContainsKey("Name"); var seoTabLoaded = m.LoadedTabs.Contains("SEO", StringComparer.OrdinalIgnoreCase); + // Handle Download transiency + MediaHelper.UpdateDownloadTransientStateFor(p, x => x.DownloadId); + MediaHelper.UpdateDownloadTransientStateFor(p, x => x.SampleDownloadId); + // SEO m.SeName = p.ValidateSeName(m.SeName, p.Name, true); _urlRecordService.SaveSlug(p, m.SeName, 0); @@ -2457,12 +2461,16 @@ public ActionResult ProductPictureAdd(int pictureId, int displayOrder, int produ if (product == null) throw new ArgumentException("No product found with the specified id"); - _productService.InsertProductPicture(new ProductPicture() + var productPicture = new ProductPicture { PictureId = pictureId, ProductId = productId, DisplayOrder = displayOrder, - }); + }; + + MediaHelper.UpdatePictureTransientStateFor(productPicture, pp => pp.PictureId); + + _productService.InsertProductPicture(productPicture); _pictureService.SetSeoFilename(pictureId, _pictureService.GetPictureSeName(product.Name)); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs index 90b04c7bfc..66f598883b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs @@ -1230,10 +1230,11 @@ public ActionResult GeneralCommon(GeneralCommonSettingsModel model, FormCollecti NotifyError(_localizationService.GetResource("Admin.Configuration.Settings.GeneralCommon.CaptchaEnabledNoKeys")); } - //PDF settings + // PDF settings var pdfSettings = _settingService.LoadSetting(storeScope); pdfSettings.Enabled = model.PdfSettings.Enabled; pdfSettings.LetterPageSizeEnabled = model.PdfSettings.LetterPageSizeEnabled; + MediaHelper.UpdatePictureTransientState(pdfSettings.LogoPictureId, model.PdfSettings.LogoPictureId, true); pdfSettings.LogoPictureId = model.PdfSettings.LogoPictureId; pdfSettings.AttachOrderPdfToOrderPlacedEmail = model.PdfSettings.AttachOrderPdfToOrderPlacedEmail; pdfSettings.AttachOrderPdfToOrderCompletedEmail = model.PdfSettings.AttachOrderPdfToOrderCompletedEmail; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs index b29282d610..dcd050ea05 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/StoreController.cs @@ -8,6 +8,7 @@ using SmartStore.Services.Configuration; using SmartStore.Services.Directory; using SmartStore.Services.Localization; +using SmartStore.Services.Media; using SmartStore.Services.Security; using SmartStore.Services.Stores; using SmartStore.Web.Framework.Controllers; @@ -103,6 +104,7 @@ public ActionResult Create(StoreModel model, bool continueEditing) if (ModelState.IsValid) { var store = model.ToEntity(); + MediaHelper.UpdatePictureTransientStateFor(store, s => s.LogoPictureId); //ensure we have "/" at the end store.Url = store.Url.EnsureEndsWith("/"); _storeService.InsertStore(store); @@ -144,6 +146,9 @@ public ActionResult Edit(StoreModel model, bool continueEditing) if (ModelState.IsValid) { store = model.ToEntity(store); + + MediaHelper.UpdatePictureTransientStateFor(store, s => s.LogoPictureId); + //ensure we have "/" at the end store.Url = store.Url.EnsureEndsWith("/"); _storeService.UpdateStore(store); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs index 55c6cee336..e8e46d95aa 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs @@ -393,11 +393,7 @@ public ActionResult ImportVariables(string theme, int storeId, FormCollection fo if (file != null && file.ContentLength > 0) { int importedCount = 0; - using (var sr = new StreamReader(file.InputStream, Encoding.UTF8)) - { - string content = sr.ReadToEnd(); - importedCount = _themeVarService.ImportVariables(theme, storeId, content); - } + importedCount = _themeVarService.ImportVariables(theme, storeId, file.InputStream.AsString()); // activity log try diff --git a/src/Presentation/SmartStore.Web/Administration/Scripts/smartstore.download.js b/src/Presentation/SmartStore.Web/Administration/Scripts/smartstore.download.js new file mode 100644 index 0000000000..493fbed959 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Scripts/smartstore.download.js @@ -0,0 +1,95 @@ +; + +// Unobtrusive handler for 'Download' editor template +(function ($, window, document, undefined) { + + var pluginName = 'downloadEditor'; + + function DownloadEditor(element, options) { + var self = this; + + // to access the DOM elem from outside of this constructor + this.element = element; + var el = this.el = $(element); + + // 'this.options' ensures we can reference the merged instance options from outside + var opts = this.options = $.extend({}, options); + + this.togglePanel = function (useUrl) { + if (useUrl && el.hasClass("minimal")) + return; + + if (useUrl == el.data("use-url")) + return; + + if (useUrl) { + el.find('.panel-upload').hide(); + el.find('.panel-url').show(); + el.find('.toggle-file').parent().removeClass("disabled"); + el.find('.toggle-url').parent().addClass("disabled"); + } + else { + el.find('.panel-url').hide(); + el.find('.panel-upload').show(); + el.find('.toggle-file').parent().addClass("disabled"); + el.find('.toggle-url').parent().removeClass("disabled"); + } + + el.data("use-url", useUrl); + }; + + this.init = function () { + var elHidden = el.find('.hidden'), + elRemove = el.find('.remove'); + + // handle panel switcher buttons + el.find('.toggle-file').on('click', function (e) { e.preventDefault(); self.togglePanel(false); }); + el.find('.toggle-url').on('click', function (e) { e.preventDefault(); self.togglePanel(true); }); + + // init file uploader + el.find('.fileupload').fileupload({ + url: el.data('upload-url'), + dataType: 'json', + + done: function (e, data) { + var result = data.result; + if (result.success) { + // >>>>>> $('#@(clientId + "downloadurl")').html('@T("Admin.Download.DownloadUploadedFile"): ' + result.fileName + ''); + elHidden.val(result.downloadId); + elRemove.show(); + } + }, + + error: function (jqXHR, textStatus, errorThrown) { + if (errorThrown === 'abort') { + //alert('File Upload has been canceled'); + } + } + }); + + // Download removal + elRemove.click(function (e) { + // >>>>>> $('#@(clientId + "downloadurl")').html(" "); + elHidden.val(0); + $(this).hide(); + e.preventDefault(); + }); + }; + + this.initialized = false; + this.init(); + this.initialized = true; + } + + $[pluginName] = { defaults: { } }; + + $.fn[pluginName] = function (options) { + return this.each(function () { + if (!$.data(this, pluginName)) { + options = $.extend({}, $[pluginName].defaults, options); + $.data(this, pluginName, new DownloadEditor(this, options)); + } + }); + } + +})(jQuery, window, document); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 60c5ff77f0..209e12c89f 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -466,6 +466,9 @@ + + Always + Always @@ -494,6 +497,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Category/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Category/_CreateOrUpdate.cshtml index dc94281687..6ac00a03c9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Category/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Category/_CreateOrUpdate.cshtml @@ -133,7 +133,7 @@ @Html.SmartLabelFor(model => model.PictureId) - @Html.EditorFor(model => model.PictureId) + @Html.EditorFor(model => model.PictureId, new { transientUpload = true }) @Html.ValidationMessageFor(model => model.PictureId)
    - @Html.EditorFor(model => model.BackgroundPictureId, "Picture") + @Html.EditorFor(model => model.BackgroundPictureId, "Picture", new { transientUpload = true }) @Html.ValidationMessageFor(model => model.BackgroundPictureId)
    - @Html.EditorFor(model => model.PictureId, "Picture") + @Html.EditorFor(model => model.PictureId, "Picture", new { transientUpload = true }) @Html.ValidationMessageFor(model => model.PictureId)
    - @Html.EditorFor(model => model.PictureId) + @Html.EditorFor(model => model.PictureId, new { transientUpload = true }) @Html.ValidationMessageFor(model => model.PictureId)
    - @Html.EditorFor(model => Model.Locales[item].Attachment1FileId) + @Html.EditorFor(model => Model.Locales[item].Attachment1FileId, "Download") @Html.ValidationMessageFor(model => model.Locales[item].Attachment1FileId)
    - @Html.EditorFor(model => Model.Locales[item].Attachment2FileId) + @Html.EditorFor(model => Model.Locales[item].Attachment2FileId, "Download") @Html.ValidationMessageFor(model => model.Locales[item].Attachment2FileId)
    - @Html.EditorFor(model => Model.Locales[item].Attachment3FileId) + @Html.EditorFor(model => Model.Locales[item].Attachment3FileId, "Download") @Html.ValidationMessageFor(model => model.Locales[item].Attachment3FileId)
    - @Html.EditorFor(model => Model.Attachment1FileId) + @Html.EditorFor(model => Model.Attachment1FileId, "Download2") @Html.ValidationMessageFor(model => model.Attachment1FileId)
    - @Html.EditorFor(model => Model.Attachment2FileId) + @Html.EditorFor(model => Model.Attachment2FileId, "Download2") @Html.ValidationMessageFor(model => model.Attachment2FileId)
    - @Html.EditorFor(model => Model.Attachment3FileId) + @Html.EditorFor(model => Model.Attachment3FileId, "Download2", new { minimalMode = false }) @Html.ValidationMessageFor(model => model.Attachment3FileId)
    - @Html.EditorFor(model => model.AddPictureModel.PictureId) + @Html.EditorFor(model => model.AddPictureModel.PictureId, new { transientUpload = true }) @Html.ValidationMessageFor(model => model.AddPictureModel.PictureId)
    - @Html.SettingEditorFor(model => model.PdfSettings.LogoPictureId, "#pdf-logo-picture") + @Html.SettingEditorFor(model => model.PdfSettings.LogoPictureId, "#pdf-logo-picture", new { transientUpload = true }) @Html.ValidationMessageFor(model => model.PdfSettings.LogoPictureId)
    - @Html.EditorFor(model => model.LogoPictureId, "#store-logo-picture") + @Html.EditorFor(model => model.LogoPictureId, "#store-logo-picture", new { transientUpload = true }) @Html.ValidationMessageFor(model => model.LogoPictureId)
    + @Html.SmartLabelFor(model => model.DisplayWidgetZones) + + @Html.SettingEditorFor(model => model.DisplayWidgetZones) + @Html.ValidationMessageFor(model => model.DisplayWidgetZones) +
    diff --git a/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml b/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml new file mode 100644 index 0000000000..2dcf0c42a0 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml @@ -0,0 +1,3 @@ + + Widget Zone + diff --git a/src/Plugins/SmartStore.DevTools/Widgets/ShowZonesWidget.cs b/src/Plugins/SmartStore.DevTools/Widgets/ShowZonesWidget.cs new file mode 100644 index 0000000000..f9834ae0d6 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Widgets/ShowZonesWidget.cs @@ -0,0 +1,220 @@ +using System.Collections.Generic; +using System.Web; +using System.Web.Routing; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Plugins; +using SmartStore.Services; +using SmartStore.Services.Cms; +using SmartStore.Services.Common; + +namespace SmartStore.DevTools.Widgets +{ + [SystemName("Widgets.ShowZones")] + [FriendlyName("Show Zones")] + public class ShowZonesWidget : IWidget + { + private readonly ICommonServices _services; + private readonly HttpContextBase _httpContext; + + public ShowZonesWidget(ICommonServices services, + HttpContextBase httpContext, + IGenericAttributeService genericAttributeService) + { + _services = services; + _httpContext = httpContext; + } + + public IList GetWidgetZones() + { + return new List() + { + //Blogs + "blogpost_page_before_body", "mobile_blogpost_page_before_body", + "blogpost_page_before_comments", "mobile_blogpost_page_before_comments", + "blogpost_page_inside_comment", "mobile_blogpost_page_inside_comment", + "blogpost_page_after_comments", "mobile_blogpost_page_after_comments", + "bloglist_page_before_posts", "mobile_bloglist_page_before_posts", + "bloglist_page_inside_post", "mobile_bloglist_page_inside_post", + "bloglist_page_after_posts", "mobile_bloglist_page_after_posts", + + //Categories + "categorydetails_after_breadcrumb", + "categorydetails_top", "mobile_categorydetails_top", + "categorydetails_before_subcategories", "mobile_categorydetails_before_subcategories", + "categorydetails_before_featured_products", "mobile_categorydetails_before_featured_products", + "categorydetails_after_featured_products", + "categorydetails_before_product_list", "mobile_categorydetails_before_product_list", + "categorydetails_bottom", "mobile_categorydetails_bottom", + "categorydetails_before_filters", + + //Products + "productbox_add_info", + "productsbytag_before_product_list", + "productreviews_page_inside_review", + "productdetails_overview_top", + "productdetails_overview_bottom", + "productsbytag_top", "mobile_productsbytag_top", + "productsbytag_bottom", "mobile_productsbytag_bottom", + "productdetails_add_info", "mobile_productdetails_add_info", + "productdetails_top", "mobile_productdetails_top", + "productdetails_before_pictures", "mobile_productdetails_before_pictures", + "productdetails_after_pictures", "mobile_productdetails_after_pictures", + "productdetails_bottom", "mobile_productdetails_bottom", + + //Navigation + "productbreadcrumb_before", + "productbreadcrumb_after", + "header_menu_before", + "header_menu_after", + "megamenu_before_first_item", + "megamenu_after_last_item", + "account_dropdown_before", + "account_dropdown_after", + "header_links_before", "mobile_header_links_before", + "header_links_after", "mobile_header_links_after", + "infoblock_before", "mobile_infoblock_before", + "infoblock_after", "mobile_infoblock_after", + "account_navigation_before", "mobile_account_navigation_before", + "account_navigation_after", "mobile_account_navigation_after", + + //Checkout + "checkout_progress_before", + "checkout_progress_after", + "checkout_billing_address_top", "mobile_checkout_billing_address_top", + "checkout_billing_address_middle", "mobile_checkout_billing_address_middle", + "checkout_billing_address_bottom", "mobile_checkout_billing_address_bottom", + "checkout_completed_top", "mobile_checkout_completed_top", + "checkout_completed_bottom", "mobile_checkout_completed_bottom", + "checkout_confirm_top", "mobile_checkout_confirm_top", + "checkout_confirm_before_summary", "mobile_checkout_confirm_before_summary", + "checkout_confirm_bottom", "mobile_checkout_confirm_bottom", + "checkout_payment_method_top", "mobile_checkout_payment_method_top", + "checkout_payment_method_bottom", "mobile_checkout_payment_method_bottom", + "checkout_shipping_address_top", "mobile_checkout_shipping_address_top", + "checkout_shipping_address_middle", "mobile_checkout_shipping_address_middle", + "checkout_shipping_address_bottom", "mobile_checkout_shipping_address_bottom", + "checkout_shipping_method_top", "mobile_checkout_shipping_method_top", + "checkout_shipping_method_bottom", "mobile_checkout_shipping_method_bottom", + + //PDF + "invoice_footer_before", + "invoice_footer_after", + "invoice_header_before", + "invoice_header_right", + "invoice_header_after", + "invoice_top", + "invoice_orderinfo_top", + "invoice_orderinfotable_after", + "invoice_orderinfo_bottom", + "invoice_lines_before", + "invoice_checkoutattributes_before", + "invoice_ordertotals_before", + "invoice_ordernotes_before", + "invoice_bottom", + "pdfcatalog_cover_top", + "pdfcatalog_cover_logo_after", + "pdfcatalog_cover_storename_after", + "pdfcatalog_productdetail_top", + "pdfcatalog_productdetail_fulldescription_before", + "pdfcatalog_productdetail_picture_before", + "pdfcatalog_productdetail_specificationattributes_before", + "pdfcatalog_productdetail_bundleditems_before", + "pdfcatalog_productdetail_associatedproducts_before", + + //Manufacturer + "manufacturerdetails_top", "mobile_manufacturerdetails_top", + "manufacturerdetails_before_featured_products", "mobile_manufacturerdetails_before_featured_products", + "manufacturerdetails_after_featured_products", + "manufacturerdetails_before_filters", + "manufacturerdetails_before_product_list", "mobile_manufacturerdetails_before_product_list", + "manufacturerdetails_bottom", "mobile_manufacturerdetails_bottom", + + //Misc + "compareproducts_row", "mobile_compareproducts_row", + "productsearch_page_advanced", + "productsearch_page_basic", + "productsearch_page_advanced", + "searchbox", "mobile_searchbox", + "footer", "mobile_footer", + "contactus_top", "mobile_contactus_top", + "contactus_bottom", "mobile_contactus_bottom", + "productreviews_page_top", "mobile_productreviews_page_top", + "productreviews_page_inside_review", "mobile_productreviews_page_inside_review", + "productreviews_page_bottom", "mobile_productreviews_page_bottom", + "profile_page_info_userdetails", "mobile_profile_page_info_userdetails", + "profile_page_info_userstats", "mobile_profile_page_info_userstats", + "notifications", "mobile_notifications", + "shipmentdetails_top", + "shipmentdetails_orderinfo_top", + "shipmentdetails_orderinfotable_after", + "shipmentdetails_orderinfo_bottom", + "shipmentdetails_lines_before", + + //Global + "home_page_top", "mobile_home_page_top", + "home_page_bottom", "mobile_home_page_bottom", + "main_column_before", + "main_column_after", + "left_side_column_before", + "left_side_column_after_category_navigation", + "left_side_column_after_manufacturer_navigation", + "left_side_column_after_tags", + "left_side_column_after_info", + "left_side_column_after_poll", + "left_side_column_after", + "right_side_column_before", + "right_side_column_after_recentlyviewed", + "right_side_column_after_poll", + "right_side_column_after", + "body_start_html_tag_after", "mobile_body_start_html_tag_after", + "content_before", "mobile_content_before", + "content_after", "mobile_content_after", + "body_end_html_tag_before", "mobile_body_end_html_tag_after", + "head_html_tag", "mobile_head_html_tag", + "admin_navbar_before", + "admin_navbar_after", + "admin_breadcrumb", + "admin_content_before", + "admin_content_after", + "admin_menu_before", + + //News + "newslist_page_before_items", "mobile_newslist_page_before_items", + "newslist_page_inside_item", "mobile_newslist_page_inside_item", + "newslist_page_after_items", "mobile_newslist_page_after_items", + "newsitem_page_before_body", "mobile_newsitem_page_before_body", + "newsitem_page_before_comments", "mobile_newsitem_page_before_comments", + "newsitem_page_inside_comment", "mobile_newsitem_page_inside_comment", + "newsitem_page_after_comments", "mobile_newsitem_page_after_comments", + + //Orders + "orderdetails_page_top", "mobile_orderdetails_page_top", + "orderdetails_page_overview", "mobile_orderdetails_page_overview", + "orderdetails_page_beforeproducts", "mobile_orderdetails_page_beforeproducts", + "orderdetails_page_afterproducts", "mobile_orderdetails_page_afterproducts", + "orderdetails_page_aftertotal", "mobile_orderdetails_page_aftertotal", + "orderdetails_page_bottom", "mobile_orderdetails_page_bottom", + + //Shopping Cart + "mini_shopping_cart_bottom", + "order_summary_content_before", "mobile_order_summary_content_before", + "order_summary_content_totals_left", "mobile_order_summary_content_totals_left", + "order_summary_content_deals", "mobile_order_summary_content_deals", + "order_summary_content_totals_bottom", "mobile_order_summary_content_totals_bottom", + "order_summary_content_after", "mobile_order_summary_content_after" + }; + } + + public void GetDisplayWidgetRoute(string widgetZone, object model, int storeId, out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + controllerName = "DevTools"; + actionName = "WidgetZone"; + routeValues = new RouteValueDictionary() + { + { "Namespaces", "SmartStore.DevTools.Controllers" }, + { "area", "SmartStore.DevTools" }, + { "widgetZone", widgetZone } + }; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs b/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs index fe48664ee6..0c798730ff 100644 --- a/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs +++ b/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs @@ -46,7 +46,7 @@ public void GetConfigurationRoute(out string actionName, out string controllerNa { actionName = "Configure"; controllerName = "WidgetsGoogleAnalytics"; - routeValues = new RouteValueDictionary() { /*{ "Namespaces", "SmartStore.GoogleAnalytics.Controllers" },*/ { "area", "SmartStore.GoogleAnalytics" } }; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.GoogleAnalytics" } }; } /// @@ -62,7 +62,6 @@ public void GetDisplayWidgetRoute(string widgetZone, object model, int storeId, controllerName = "WidgetsGoogleAnalytics"; routeValues = new RouteValueDictionary() { - //{"Namespaces", "SmartStore.GoogleAnalytics.Controllers"}, {"area", "SmartStore.GoogleAnalytics"}, {"widgetZone", widgetZone} }; @@ -78,20 +77,20 @@ public override void Install() GoogleId = "UA-0000000-0", //TrackingScript = " ", TrackingScript = @" -", + ", EcommerceScript = @"_gaq.push(['_addTrans', '{ORDERID}', '{SITE}', '{TOTAL}', '{TAX}', '{SHIP}', '{CITY}', '{STATEPROVINCE}', '{COUNTRY}']); -{DETAILS} -_gaq.push(['_trackTrans']); ", + {DETAILS} + _gaq.push(['_trackTrans']); ", EcommerceDetailScript = @"_gaq.push(['_addItem', '{ORDERID}', '{PRODUCTSKU}', '{PRODUCTNAME}', '{CATEGORYNAME}', '{UNITPRICE}', '{QUANTITY}' ]); ", }; From cd55dd589c405a7ae51216e3cd1013231c70cf4b Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 18 Jul 2015 11:46:57 +0200 Subject: [PATCH 0082/1074] Resolves #523 Redirecting to payment provider performed by core instead of plugin --- changelog.md | 3 ++ src/Libraries/SmartStore.Core/IWebHelper.cs | 11 ------ src/Libraries/SmartStore.Core/WebHelper.cs | 23 ------------ .../Payments/PostProcessPaymentRequest.cs | 5 +++ src/Plugins/SmartStore.PayPal/Description.txt | 2 +- .../Providers/PayPalStandardProvider.cs | 6 +--- src/Plugins/SmartStore.PayPal/changelog.md | 12 ++++--- .../Controllers/CheckoutController.cs | 36 +++++++------------ .../Controllers/OrderController.cs | 33 ++++++++--------- 9 files changed, 44 insertions(+), 87 deletions(-) diff --git a/changelog.md b/changelog.md index 69001129fd..2b5005170b 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,9 @@ * #725 Prevent LowestProductPrice being 0 * #709 News feed produced invalid RSS feed. Added content:encoded. Added maximum news age setting for feed export. +### Bugfixes +* #523 Redirecting to payment provider performed by core instead of plugin + ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Core/IWebHelper.cs b/src/Libraries/SmartStore.Core/IWebHelper.cs index d1fda9b4e8..03b4f128c8 100644 --- a/src/Libraries/SmartStore.Core/IWebHelper.cs +++ b/src/Libraries/SmartStore.Core/IWebHelper.cs @@ -118,16 +118,5 @@ public partial interface IWebHelper /// Redirect URL; empty string if you want to redirect to the current page URL /// Usually true after a new plugin was installed (nukes the MVC cache) void RestartAppDomain(bool makeRedirect = false, string redirectUrl = "", bool aggressive = false); - - /// - /// Gets a value that indicates whether the client is being redirected to a new location - /// - bool IsRequestBeingRedirected { get; } - - /// - /// Gets or sets a value that indicates whether the client is being redirected to a new location using POST - /// - bool IsPostBeingDone { get; set; } - } } diff --git a/src/Libraries/SmartStore.Core/WebHelper.cs b/src/Libraries/SmartStore.Core/WebHelper.cs index 71c23110e5..f7bee23a4c 100644 --- a/src/Libraries/SmartStore.Core/WebHelper.cs +++ b/src/Libraries/SmartStore.Core/WebHelper.cs @@ -474,29 +474,6 @@ internal static bool OptimizedCompilationsEnabled } } - public virtual bool IsRequestBeingRedirected - { - get - { - var response = _httpContext.Response; - return response.IsRequestBeingRedirected; - } - } - - public virtual bool IsPostBeingDone - { - get - { - if (_httpContext.Items["sm.IsPOSTBeingDone"] == null) - return false; - return Convert.ToBoolean(_httpContext.Items["sm.IsPOSTBeingDone"]); - } - set - { - _httpContext.Items["sm.IsPOSTBeingDone"] = value; - } - } - /// /// Finds the trust level of the running application (http://blogs.msdn.com/dmitryr/archive/2007/01/23/finding-out-the-current-trust-level-in-asp-net.aspx) /// diff --git a/src/Libraries/SmartStore.Services/Payments/PostProcessPaymentRequest.cs b/src/Libraries/SmartStore.Services/Payments/PostProcessPaymentRequest.cs index 1ca115635f..f14a6cc6aa 100644 --- a/src/Libraries/SmartStore.Services/Payments/PostProcessPaymentRequest.cs +++ b/src/Libraries/SmartStore.Services/Payments/PostProcessPaymentRequest.cs @@ -16,5 +16,10 @@ public partial class PostProcessPaymentRequest /// Whether the customer clicked the button to re-post the payment process /// public bool IsRePostProcessPayment { get; set; } + + /// + /// URL to a payment provider to fulfill the payment. The .NET core will redirect to it. + /// + public string RedirectUrl { get; set; } } } diff --git a/src/Plugins/SmartStore.PayPal/Description.txt b/src/Plugins/SmartStore.PayPal/Description.txt index 84e4594446..c921d9b989 100644 --- a/src/Plugins/SmartStore.PayPal/Description.txt +++ b/src/Plugins/SmartStore.PayPal/Description.txt @@ -2,7 +2,7 @@ Description: Provides the PayPal payment methods PayPal Express, PayPal Standard and PayPal Direct. SystemName: SmartStore.PayPal Group: Payment -Version: 2.2.0.1 +Version: 2.2.0.2 MinAppVersion: 2.2.0 DisplayOrder: 1 FileName: SmartStore.PayPal.dll diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs index 609a7192e5..f6e333e66c 100644 --- a/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs @@ -18,7 +18,6 @@ using SmartStore.PayPal.Services; using SmartStore.PayPal.Settings; using SmartStore.Services; -using SmartStore.Services.Directory; using SmartStore.Services.Localization; using SmartStore.Services.Orders; using SmartStore.Services.Payments; @@ -34,18 +33,15 @@ namespace SmartStore.PayPal public partial class PayPalStandardProvider : PaymentPluginBase, IConfigurable { private readonly IOrderTotalCalculationService _orderTotalCalculationService; - private readonly HttpContextBase _httpContext; private readonly ICommonServices _services; private readonly ILogger _logger; public PayPalStandardProvider( - HttpContextBase httpContext, IOrderTotalCalculationService orderTotalCalculationService, ICommonServices services, ILogger logger) { _orderTotalCalculationService = orderTotalCalculationService; - _httpContext = httpContext; _services = services; _logger = logger; } @@ -280,7 +276,7 @@ public override void PostProcessPayment(PostProcessPaymentRequest postProcessPay builder.AppendFormat("&zip={0}", HttpUtility.UrlEncode(address.ZipPostalCode)); builder.AppendFormat("&email={0}", HttpUtility.UrlEncode(address.Email)); - _httpContext.Response.Redirect(builder.ToString()); + postProcessPaymentRequest.RedirectUrl = builder.ToString(); } /// diff --git a/src/Plugins/SmartStore.PayPal/changelog.md b/src/Plugins/SmartStore.PayPal/changelog.md index cf618f7d59..62451fa42c 100644 --- a/src/Plugins/SmartStore.PayPal/changelog.md +++ b/src/Plugins/SmartStore.PayPal/changelog.md @@ -1,13 +1,17 @@ #Release Notes# +##PayPal 2.2.0.2 +###Improvements +* Redirecting to payment provider performed by core instead of plugin + ##Paypal 2.2.0.1 ### New Features * Supports order list label for new incoming IPNs -##Paypal 1.22## -###Bugfixes### +##Paypal 1.22 +###Bugfixes * PayPal Standard provider now using shipping rather than billing address if shipping is required -##Paypal 1.21## -###Improvements### +##Paypal 1.21 +###Improvements * Multistore configuration \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs index 16f05a20d0..2112acc435 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs @@ -793,7 +793,6 @@ public ActionResult ConfirmOrder(FormCollection form) if ((_workContext.CurrentCustomer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed)) return new HttpUnauthorizedResult(); - //model var model = new CheckoutConfirmModel(); try @@ -827,12 +826,13 @@ public ActionResult ConfirmOrder(FormCollection form) if (placeOrderResult.Success) { + var postProcessPaymentRequest = new PostProcessPaymentRequest + { + Order = placeOrderResult.PlacedOrder + }; + if (isPaymentPaymentWorkflowRequired) { - var postProcessPaymentRequest = new PostProcessPaymentRequest() - { - Order = placeOrderResult.PlacedOrder - }; _paymentService.PostProcessPayment(postProcessPaymentRequest); } @@ -840,22 +840,16 @@ public ActionResult ConfirmOrder(FormCollection form) _httpContext.Session["OrderPaymentInfo"] = null; _httpContext.RemoveCheckoutState(); - if (_webHelper.IsRequestBeingRedirected || _webHelper.IsPostBeingDone) - { - //redirection or POST has been done in PostProcessPayment - return Content("Redirected"); - } - else - { - //if no redirection has been done (to a third-party payment page) - //theoretically it's not possible - return RedirectToAction("Completed"); - } + if (postProcessPaymentRequest.RedirectUrl.HasValue()) + { + return Redirect(postProcessPaymentRequest.RedirectUrl); + } + + return RedirectToAction("Completed"); } else { - foreach (var error in placeOrderResult.Errors) - model.Warnings.Add(error); + model.Warnings.AddRange(placeOrderResult.Errors); } } catch (Exception exc) @@ -864,12 +858,6 @@ public ActionResult ConfirmOrder(FormCollection form) model.Warnings.Add(exc.Message); } - //If we got this far, something failed, redisplay form - - //if (model.Warnings.Count > 0) - // TempData["ConfirmOrderWarnings"] = model.Warnings; - - //return RedirectToRoute("CheckoutConfirm"); return View(model); } diff --git a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs index bf25af3aaa..05788c95f7 100644 --- a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs @@ -611,27 +611,22 @@ public ActionResult RePostPayment(int id) if (IsUnauthorizedOrder(order)) return new HttpUnauthorizedResult(); - if (!_paymentService.CanRePostProcessPayment(order)) - return RedirectToAction("Details", "Order", new { id = order.Id }); + if (_paymentService.CanRePostProcessPayment(order)) + { + var postProcessPaymentRequest = new PostProcessPaymentRequest + { + Order = order, + IsRePostProcessPayment = true + }; - var postProcessPaymentRequest = new PostProcessPaymentRequest() - { - Order = order, - IsRePostProcessPayment = true - }; - _paymentService.PostProcessPayment(postProcessPaymentRequest); + _paymentService.PostProcessPayment(postProcessPaymentRequest); - if (_services.WebHelper.IsRequestBeingRedirected || _services.WebHelper.IsPostBeingDone) - { - //redirection or POST has been done in PostProcessPayment - return Content("Redirected"); - } - else - { - //if no redirection has been done (to a third-party payment page) - //theoretically it's not possible - return RedirectToAction("Details", "Order", new { id = order.Id }); - } + if (postProcessPaymentRequest.RedirectUrl.HasValue()) + { + return Redirect(postProcessPaymentRequest.RedirectUrl); + } + } + return RedirectToAction("Details", "Order", new { id = order.Id }); } [RequireHttpsByConfigAttribute(SslRequirement.Yes)] From bd2645ed6c4d3aa74ea98c36925a586f65205619 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 18 Jul 2015 12:13:04 +0200 Subject: [PATCH 0083/1074] Resolves #735 Include SKUs of attribute combinations when filtering the backend product list --- changelog.md | 1 + .../Catalog/IProductAttributeService.cs | 9 ++++++++- .../Catalog/ProductAttributeService.cs | 17 ++++++++++++++++- .../Catalog/ProductService.cs | 3 +-- .../Controllers/ProductController.cs | 14 +++++++++++--- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 2b5005170b..c36e803c30 100644 --- a/changelog.md +++ b/changelog.md @@ -18,6 +18,7 @@ * #721 Message Queue: implement "Delete all" * #725 Prevent LowestProductPrice being 0 * #709 News feed produced invalid RSS feed. Added content:encoded. Added maximum news age setting for feed export. +* #735 Include SKUs of attribute combinations when filtering the backend product list ### Bugfixes * #523 Redirecting to payment provider performed by core instead of plugin diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs index c150159c83..0d9f8a46ab 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs @@ -159,12 +159,19 @@ public partial interface IProductAttributeService decimal? GetLowestCombinationPrice(int productId); /// - /// Gets a product variant attribute combination + /// Gets a product variant attribute combination by identifier /// /// Product variant attribute combination identifier /// Product variant attribute combination ProductVariantAttributeCombination GetProductVariantAttributeCombinationById(int productVariantAttributeCombinationId); + /// + /// /// Gets a product variant attribute combination by SKU + /// + /// SKU + /// Product variant attribute combination + ProductVariantAttributeCombination GetProductVariantAttributeCombinationBySku(string sku); + /// /// Inserts a product variant attribute combination /// diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs index 66a1dc876d..97ce41336e 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs @@ -483,7 +483,7 @@ orderby pvac.Price ascending } /// - /// Gets a product variant attribute combination + /// Gets a product variant attribute combination by identifier /// /// Product variant attribute combination identifier /// Product variant attribute combination @@ -496,6 +496,21 @@ public virtual ProductVariantAttributeCombination GetProductVariantAttributeComb return combination; } + + /// + /// /// Gets a product variant attribute combination by SKU + /// + /// SKU + /// Product variant attribute combination + public virtual ProductVariantAttributeCombination GetProductVariantAttributeCombinationBySku(string sku) + { + if (sku.IsEmpty()) + return null; + + var combination = _productVariantAttributeCombinationRepository.Table.FirstOrDefault(x => x.Sku == sku); + return combination; + } + /// /// Inserts a product variant attribute combination /// diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs index 8dc0d5f73c..5401657dd8 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs @@ -1028,8 +1028,7 @@ public virtual Product GetProductBySku(string sku) var query = from p in _productRepository.Table orderby p.DisplayOrder, p.Id - where !p.Deleted && - p.Sku == sku + where !p.Deleted && p.Sku == sku select p; var product = query.FirstOrDefault(); return product; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index efd7a9f60c..612c11b7ac 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -948,9 +948,17 @@ public ActionResult ProductList(GridCommand command, ProductListModel model) public ActionResult GoToSku(ProductListModel model) { string sku = model.GoDirectlyToSku; - var product = _productService.GetProductBySku(sku); - if (product != null) - return RedirectToAction("Edit", "Product", new { id = product.Id }); + + if (sku.HasValue()) + { + var product = _productService.GetProductBySku(sku); + if (product != null) + return RedirectToAction("Edit", "Product", new { id = product.Id }); + + var combination = _productAttributeService.GetProductVariantAttributeCombinationBySku(sku); + if (combination != null && combination.Product != null && !combination.Product.Deleted) + return RedirectToAction("Edit", "Product", new { id = combination.Product.Id }); + } //not found return List(model); From 5f28e47bb1f359be846f17c794a37c9d8b8c9ff5 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 18 Jul 2015 19:16:18 +0200 Subject: [PATCH 0084/1074] #709 Forum active discussions RSS feed improvements --- .../Forums/ForumService.cs | 121 ++++++++++++------ .../Forums/IForumService.cs | 9 ++ .../Controllers/BoardsController.cs | 38 +----- 3 files changed, 93 insertions(+), 75 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Forums/ForumService.cs b/src/Libraries/SmartStore.Services/Forums/ForumService.cs index 4f5ca20ce4..c5fdea7347 100644 --- a/src/Libraries/SmartStore.Services/Forums/ForumService.cs +++ b/src/Libraries/SmartStore.Services/Forums/ForumService.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.ServiceModel.Syndication; +using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; @@ -11,6 +13,8 @@ using SmartStore.Services.Common; using SmartStore.Services.Customers; using SmartStore.Services.Messages; +using SmartStore.Services.Seo; +using SmartStore.Utilities; namespace SmartStore.Services.Forums { @@ -41,11 +45,9 @@ public partial class ForumService : IForumService private readonly ICacheManager _cacheManager; private readonly IGenericAttributeService _genericAttributeService; private readonly ICustomerService _customerService; - private readonly IWorkContext _workContext; private readonly IWorkflowMessageService _workflowMessageService; - private readonly IEventPublisher _eventPublisher; - private readonly IStoreContext _storeContext; private readonly IRepository _storeMappingRepository; + private readonly ICommonServices _services; #endregion @@ -62,11 +64,9 @@ public ForumService(ICacheManager cacheManager, IRepository customerRepository, IGenericAttributeService genericAttributeService, ICustomerService customerService, - IWorkContext workContext, IWorkflowMessageService workflowMessageService, - IEventPublisher eventPublisher, - IStoreContext storeContext, - IRepository storeMappingRepository) + IRepository storeMappingRepository, + ICommonServices services) { _cacheManager = cacheManager; _forumGroupRepository = forumGroupRepository; @@ -79,11 +79,9 @@ public ForumService(ICacheManager cacheManager, _customerRepository = customerRepository; _genericAttributeService = genericAttributeService; _customerService = customerService; - _workContext = workContext; _workflowMessageService = workflowMessageService; - _eventPublisher = eventPublisher; - _storeContext = storeContext; _storeMappingRepository = storeMappingRepository; + _services = services; } public DbQuerySettings QuerySettings { get; set; } @@ -263,7 +261,7 @@ public virtual void DeleteForumGroup(ForumGroup forumGroup) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(forumGroup); + _services.EventPublisher.EntityDeleted(forumGroup); } /// @@ -292,7 +290,7 @@ public virtual IList GetAllForumGroups(bool showHidden = false) if (!showHidden && !QuerySettings.IgnoreMultiStore) { - var currentStoreId = _storeContext.CurrentStore.Id; + var currentStoreId = _services.StoreContext.CurrentStore.Id; query = from fg in query @@ -332,7 +330,7 @@ public virtual void InsertForumGroup(ForumGroup forumGroup) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(forumGroup); + _services.EventPublisher.EntityInserted(forumGroup); } /// @@ -353,7 +351,7 @@ public virtual void UpdateForumGroup(ForumGroup forumGroup) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(forumGroup); + _services.EventPublisher.EntityUpdated(forumGroup); } /// @@ -378,7 +376,7 @@ where queryTopicIds.Contains(fs.TopicId) { _forumSubscriptionRepository.Delete(fs); //event notification - _eventPublisher.EntityDeleted(fs); + _services.EventPublisher.EntityDeleted(fs); } //delete forum subscriptions (forum) @@ -389,7 +387,7 @@ where queryTopicIds.Contains(fs.TopicId) { _forumSubscriptionRepository.Delete(fs2); //event notification - _eventPublisher.EntityDeleted(fs2); + _services.EventPublisher.EntityDeleted(fs2); } //delete forum @@ -399,7 +397,7 @@ where queryTopicIds.Contains(fs.TopicId) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(forum); + _services.EventPublisher.EntityDeleted(forum); } /// @@ -451,7 +449,7 @@ public virtual void InsertForum(Forum forum) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(forum); + _services.EventPublisher.EntityInserted(forum); } /// @@ -471,7 +469,7 @@ public virtual void UpdateForum(Forum forum) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(forum); + _services.EventPublisher.EntityUpdated(forum); } /// @@ -500,7 +498,7 @@ public virtual void DeleteTopic(ForumTopic forumTopic) { _forumSubscriptionRepository.Delete(fs); //event notification - _eventPublisher.EntityDeleted(fs); + _services.EventPublisher.EntityDeleted(fs); } //update stats @@ -511,7 +509,7 @@ public virtual void DeleteTopic(ForumTopic forumTopic) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(forumTopic); + _services.EventPublisher.EntityDeleted(forumTopic); } /// @@ -613,7 +611,7 @@ from ft in _forumTopicRepository.Table if (!QuerySettings.IgnoreMultiStore) { - var currentStoreId = _storeContext.CurrentStore.Id; + var currentStoreId = _services.StoreContext.CurrentStore.Id; query = from ft in query @@ -659,14 +657,14 @@ public virtual void InsertTopic(ForumTopic forumTopic, bool sendNotifications) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(forumTopic); + _services.EventPublisher.EntityInserted(forumTopic); //send notifications if (sendNotifications) { var forum = forumTopic.Forum; var subscriptions = GetAllSubscriptions(0, forum.Id, 0, 0, int.MaxValue); - var languageId = _workContext.WorkingLanguage.Id; + var languageId = _services.WorkContext.WorkingLanguage.Id; foreach (var subscription in subscriptions) { @@ -700,7 +698,7 @@ public virtual void UpdateTopic(ForumTopic forumTopic) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(forumTopic); + _services.EventPublisher.EntityUpdated(forumTopic); } /// @@ -715,7 +713,7 @@ public virtual ForumTopic MoveTopic(int forumTopicId, int newForumId) if (forumTopic == null) return forumTopic; - if (this.IsCustomerAllowedToMoveTopic(_workContext.CurrentCustomer, forumTopic)) + if (this.IsCustomerAllowedToMoveTopic(_services.WorkContext.CurrentCustomer, forumTopic)) { int previousForumId = forumTopic.ForumId; var newForum = GetForumById(newForumId); @@ -783,7 +781,7 @@ public virtual void DeletePost(ForumPost forumPost) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(forumPost); + _services.EventPublisher.EntityDeleted(forumPost); } @@ -887,7 +885,7 @@ public virtual void InsertPost(ForumPost forumPost, bool sendNotifications) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(forumPost); + _services.EventPublisher.EntityInserted(forumPost); //notifications if (sendNotifications) @@ -895,7 +893,7 @@ public virtual void InsertPost(ForumPost forumPost, bool sendNotifications) var forum = forumTopic.Forum; var subscriptions = GetAllSubscriptions(0, 0, forumTopic.Id, 0, int.MaxValue); - var languageId = _workContext.WorkingLanguage.Id; + var languageId = _services.WorkContext.WorkingLanguage.Id; int friendlyTopicPageIndex = CalculateTopicPageIndex(forumPost.TopicId, _forumSettings.PostsPageSize > 0 ? _forumSettings.PostsPageSize : 10, forumPost.Id) + 1; @@ -932,7 +930,7 @@ public virtual void UpdatePost(ForumPost forumPost) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(forumPost); + _services.EventPublisher.EntityUpdated(forumPost); } /// @@ -949,7 +947,7 @@ public virtual void DeletePrivateMessage(PrivateMessage privateMessage) _forumPrivateMessageRepository.Delete(privateMessage); //event notification - _eventPublisher.EntityDeleted(privateMessage); + _services.EventPublisher.EntityDeleted(privateMessage); } /// @@ -1028,7 +1026,7 @@ public virtual void InsertPrivateMessage(PrivateMessage privateMessage) _forumPrivateMessageRepository.Insert(privateMessage); //event notification - _eventPublisher.EntityInserted(privateMessage); + _services.EventPublisher.EntityInserted(privateMessage); var customerTo = _customerService.GetCustomerById(privateMessage.ToCustomerId); if (customerTo == null) @@ -1042,7 +1040,7 @@ public virtual void InsertPrivateMessage(PrivateMessage privateMessage) //Email notification if (_forumSettings.NotifyAboutPrivateMessages) { - _workflowMessageService.SendPrivateMessageNotification(customerTo, privateMessage, _workContext.WorkingLanguage.Id); + _workflowMessageService.SendPrivateMessageNotification(customerTo, privateMessage, _services.WorkContext.WorkingLanguage.Id); } } @@ -1059,13 +1057,13 @@ public virtual void UpdatePrivateMessage(PrivateMessage privateMessage) { _forumPrivateMessageRepository.Delete(privateMessage); //event notification - _eventPublisher.EntityDeleted(privateMessage); + _services.EventPublisher.EntityDeleted(privateMessage); } else { _forumPrivateMessageRepository.Update(privateMessage); //event notification - _eventPublisher.EntityUpdated(privateMessage); + _services.EventPublisher.EntityUpdated(privateMessage); } } @@ -1083,7 +1081,7 @@ public virtual void DeleteSubscription(ForumSubscription forumSubscription) _forumSubscriptionRepository.Delete(forumSubscription); //event notification - _eventPublisher.EntityDeleted(forumSubscription); + _services.EventPublisher.EntityDeleted(forumSubscription); } /// @@ -1151,7 +1149,7 @@ public virtual void InsertSubscription(ForumSubscription forumSubscription) _forumSubscriptionRepository.Insert(forumSubscription); //event notification - _eventPublisher.EntityInserted(forumSubscription); + _services.EventPublisher.EntityInserted(forumSubscription); } /// @@ -1168,7 +1166,7 @@ public virtual void UpdateSubscription(ForumSubscription forumSubscription) _forumSubscriptionRepository.Update(forumSubscription); //event notification - _eventPublisher.EntityUpdated(forumSubscription); + _services.EventPublisher.EntityUpdated(forumSubscription); } /// @@ -1477,7 +1475,52 @@ public virtual int CalculateTopicPageIndex(int forumTopicId, int pageSize, int p return pageIndex; } - + + /// + /// Creates a RSS feed with active discussions + /// + /// UrlHelper to generate URLs + /// SmartSyndicationFeed object + public virtual SmartSyndicationFeed CreateActiveDiscussionsRssFeed(UrlHelper urlHelper, int forumId) + { + if (urlHelper == null) + throw new ArgumentNullException("urlHelper"); + + var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = urlHelper.Action("ActiveDiscussionsRSS", "Boards", null, protocol); + var discussionLink = urlHelper.Action("ActiveDiscussions", "Boards", null, protocol); + + var title = "{0} - {1}".FormatInvariant(_services.StoreContext.CurrentStore.Name, _services.Localization.GetResource("Forum.ActiveDiscussionsFeedTitle")); + + var feed = new SmartSyndicationFeed(new Uri(discussionLink), title, _services.Localization.GetResource("Forum.ActiveDiscussionsFeedDescription")); + + feed.AddNamespaces(false); + feed.Init(selfLink, _services.WorkContext.WorkingLanguage); + + if (!_forumSettings.ActiveDiscussionsFeedEnabled) + return feed; + + var items = new List(); + var topics = GetActiveTopics(forumId, _forumSettings.ActiveDiscussionsFeedCount); + + var viewsText = _services.Localization.GetResource("Forum.Views"); + var repliesText = _services.Localization.GetResource("Forum.Replies"); + + foreach (var topic in topics) + { + string topicUrl = urlHelper.RouteUrl("TopicSlug", new { id = topic.Id, slug = topic.GetSeName() }, "http"); + var synopsis = "{0}: {1}, {2}: {3}".FormatInvariant(repliesText, topic.NumReplies, viewsText, topic.Views); + + var item = feed.CreateItem(topic.Subject, synopsis, topicUrl, topic.LastPostTime ?? topic.UpdatedOnUtc); + + items.Add(item); + } + + feed.Items = items; + + return feed; + } + #endregion } } diff --git a/src/Libraries/SmartStore.Services/Forums/IForumService.cs b/src/Libraries/SmartStore.Services/Forums/IForumService.cs index 46e0f2f428..0d74f8dab0 100644 --- a/src/Libraries/SmartStore.Services/Forums/IForumService.cs +++ b/src/Libraries/SmartStore.Services/Forums/IForumService.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; +using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Forums; +using SmartStore.Utilities; namespace SmartStore.Services.Forums { @@ -344,5 +346,12 @@ IPagedList GetAllSubscriptions(int customerId, int forumId, /// Post identifier /// Page index int CalculateTopicPageIndex(int forumTopicId, int pageSize, int postId); + + /// + /// Creates a RSS feed with active discussions + /// + /// UrlHelper to generate URLs + /// SmartSyndicationFeed object + SmartSyndicationFeed CreateActiveDiscussionsRssFeed(UrlHelper urlHelper, int forumId); } } diff --git a/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs b/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs index d9dcc8baaa..7d52cd5133 100644 --- a/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs @@ -266,45 +266,11 @@ public ActionResult ActiveDiscussions(int forumId = 0) public ActionResult ActiveDiscussionsRss(int forumId = 0) { if (!_forumSettings.ForumsEnabled) - { - return HttpNotFound(); - } - - if (!_forumSettings.ActiveDiscussionsFeedEnabled) - { return HttpNotFound(); - } - - int topicLimit = _forumSettings.ActiveDiscussionsFeedCount; - var topics = _forumService.GetActiveTopics(forumId, topicLimit); - string url = Url.Action("ActiveDiscussionsRSS", null, (object)null, "http"); - var feedTitle = _localizationService.GetResource("Forum.ActiveDiscussionsFeedTitle"); - var feedDescription = _localizationService.GetResource("Forum.ActiveDiscussionsFeedDescription"); - - var feed = new SyndicationFeed( - string.Format(feedTitle, _storeContext.CurrentStore.Name), - feedDescription, - new Uri(url), - "ActiveDiscussionsRSS", - DateTime.UtcNow); - - var items = new List(); - - var viewsText = _localizationService.GetResource("Forum.Views"); - var repliesText = _localizationService.GetResource("Forum.Replies"); - - foreach (var topic in topics) - { - string topicUrl = Url.RouteUrl("TopicSlug", new { id = topic.Id, slug = topic.GetSeName() }, "http"); - string content = String.Format("{2}: {0}, {3}: {1}", topic.NumReplies.ToString(), topic.Views.ToString(), repliesText, viewsText); - - items.Add(new SyndicationItem(topic.Subject, content, new Uri(topicUrl), - String.Format("Topic:{0}", topic.Id), (topic.LastPostTime ?? topic.UpdatedOnUtc))); - } - feed.Items = items; + var feed = _forumService.CreateActiveDiscussionsRssFeed(Url, forumId); - return new RssActionResult() { Feed = feed }; + return new RssActionResult { Feed = feed }; } public ActionResult ForumGroup(int id) From b68157ddc09e3a980ced82b6dfd24074338c1784 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 19 Jul 2015 11:57:35 +0200 Subject: [PATCH 0085/1074] #709 Forum topics RSS feed improvements --- ...61756463_PrimaryStoreCurrencyMultiStore.cs | 1 + .../Forums/ForumService.cs | 56 ++++++++++++++++++- .../Forums/IForumService.cs | 7 +++ .../Controllers/BoardsController.cs | 55 ++---------------- 4 files changed, 68 insertions(+), 51 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs index e61acfd677..f243d50dc2 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -154,6 +154,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.Delete("Admin.Configuration.Currencies.CantDeleteExchange"); builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryStoreCurrency"); builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryExchangeRateCurrency"); + builder.Delete("Forum.ForumFeedTitle"); } } } diff --git a/src/Libraries/SmartStore.Services/Forums/ForumService.cs b/src/Libraries/SmartStore.Services/Forums/ForumService.cs index c5fdea7347..c9f9e63dbd 100644 --- a/src/Libraries/SmartStore.Services/Forums/ForumService.cs +++ b/src/Libraries/SmartStore.Services/Forums/ForumService.cs @@ -12,6 +12,7 @@ using SmartStore.Core.Events; using SmartStore.Services.Common; using SmartStore.Services.Customers; +using SmartStore.Services.Localization; using SmartStore.Services.Messages; using SmartStore.Services.Seo; using SmartStore.Utilities; @@ -1486,6 +1487,7 @@ public virtual SmartSyndicationFeed CreateActiveDiscussionsRssFeed(UrlHelper url if (urlHelper == null) throw new ArgumentNullException("urlHelper"); + var language = _services.WorkContext.WorkingLanguage; var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; var selfLink = urlHelper.Action("ActiveDiscussionsRSS", "Boards", null, protocol); var discussionLink = urlHelper.Action("ActiveDiscussions", "Boards", null, protocol); @@ -1495,7 +1497,7 @@ public virtual SmartSyndicationFeed CreateActiveDiscussionsRssFeed(UrlHelper url var feed = new SmartSyndicationFeed(new Uri(discussionLink), title, _services.Localization.GetResource("Forum.ActiveDiscussionsFeedDescription")); feed.AddNamespaces(false); - feed.Init(selfLink, _services.WorkContext.WorkingLanguage); + feed.Init(selfLink, language); if (!_forumSettings.ActiveDiscussionsFeedEnabled) return feed; @@ -1521,6 +1523,58 @@ public virtual SmartSyndicationFeed CreateActiveDiscussionsRssFeed(UrlHelper url return feed; } + /// + /// Creates a RSS feed with forum topics + /// + /// UrlHelper to generate URLs + /// SmartSyndicationFeed object + public virtual SmartSyndicationFeed CreateForumRssFeed(UrlHelper urlHelper, int forumId) + { + if (urlHelper == null) + throw new ArgumentNullException("urlHelper"); + + var language = _services.WorkContext.WorkingLanguage; + var protocol = _services.WebHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = urlHelper.Action("ForumRSS", "Boards", null, protocol); + var forumLink = urlHelper.Action("Forum", "Boards", new { id = forumId }, protocol); + + var feed = new SmartSyndicationFeed(new Uri(forumLink), _services.StoreContext.CurrentStore.Name, _services.Localization.GetResource("Forum.ForumFeedDescription")); + + feed.AddNamespaces(false); + feed.Init(selfLink, language); + + if (!_forumSettings.ForumFeedsEnabled) + return feed; + + var forum = GetForumById(forumId); + + if (forum == null) + return feed; + + feed.Title = new TextSyndicationContent("{0} - {1}".FormatInvariant(_services.StoreContext.CurrentStore.Name, forum.GetLocalized(x => x.Name, language.Id))); + + var items = new List(); + var topics = GetAllTopics(forumId, 0, string.Empty, ForumSearchType.All, 0, 0, _forumSettings.ForumFeedCount); + + var viewsText = _services.Localization.GetResource("Forum.Views"); + var repliesText = _services.Localization.GetResource("Forum.Replies"); + + foreach (var topic in topics) + { + string topicUrl = urlHelper.RouteUrl("TopicSlug", new { id = topic.Id, slug = topic.GetSeName() }, "http"); + var synopsis = "{0}: {1}, {2}: {3}".FormatInvariant(repliesText, topic.NumReplies, viewsText, topic.Views); + + var item = feed.CreateItem(topic.Subject, synopsis, topicUrl, topic.LastPostTime ?? topic.UpdatedOnUtc); + + items.Add(item); + } + + feed.Items = items; + + return feed; + } + + #endregion } } diff --git a/src/Libraries/SmartStore.Services/Forums/IForumService.cs b/src/Libraries/SmartStore.Services/Forums/IForumService.cs index 0d74f8dab0..efcd21fa32 100644 --- a/src/Libraries/SmartStore.Services/Forums/IForumService.cs +++ b/src/Libraries/SmartStore.Services/Forums/IForumService.cs @@ -353,5 +353,12 @@ IPagedList GetAllSubscriptions(int customerId, int forumId, /// UrlHelper to generate URLs /// SmartSyndicationFeed object SmartSyndicationFeed CreateActiveDiscussionsRssFeed(UrlHelper urlHelper, int forumId); + + /// + /// Creates a RSS feed with forum topics + /// + /// UrlHelper to generate URLs + /// SmartSyndicationFeed object + SmartSyndicationFeed CreateForumRssFeed(UrlHelper urlHelper, int forumId); } } diff --git a/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs b/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs index 7d52cd5133..6e2dd867cf 100644 --- a/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/BoardsController.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.ServiceModel.Syndication; using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Customers; @@ -18,6 +17,7 @@ using SmartStore.Services.Seo; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Mvc; using SmartStore.Web.Framework.Security; using SmartStore.Web.Models.Boards; @@ -34,7 +34,6 @@ public partial class BoardsController : PublicControllerBase private readonly ICountryService _countryService; private readonly IWebHelper _webHelper; private readonly IWorkContext _workContext; - private readonly IStoreContext _storeContext; private readonly ForumSettings _forumSettings; private readonly CustomerSettings _customerSettings; private readonly MediaSettings _mediaSettings; @@ -50,7 +49,6 @@ public BoardsController(IForumService forumService, ICountryService countryService, IWebHelper webHelper, IWorkContext workContext, - IStoreContext storeContext, ForumSettings forumSettings, CustomerSettings customerSettings, MediaSettings mediaSettings, @@ -62,7 +60,6 @@ public BoardsController(IForumService forumService, this._countryService = countryService; this._webHelper = webHelper; this._workContext = workContext; - this._storeContext = storeContext; this._forumSettings = forumSettings; this._customerSettings = customerSettings; this._mediaSettings = mediaSettings; @@ -263,6 +260,7 @@ public ActionResult ActiveDiscussions(int forumId = 0) return View(model); } + [Compress] public ActionResult ActiveDiscussionsRss(int forumId = 0) { if (!_forumSettings.ForumsEnabled) @@ -345,58 +343,15 @@ public ActionResult Forum(int id, int page = 1) return RedirectToRoute("Boards"); } + [Compress] public ActionResult ForumRss(int id) { if (!_forumSettings.ForumsEnabled) - { - return HttpNotFound(); - } - - if (!_forumSettings.ForumFeedsEnabled) - { return HttpNotFound(); - } - - int topicLimit = _forumSettings.ForumFeedCount; - var forum = _forumService.GetForumById(id); - - if (forum != null) - { - //Order by newest topic posts & limit the number of topics to return - var topics = _forumService.GetAllTopics(forum.Id, 0, string.Empty, ForumSearchType.All, 0, 0, topicLimit); - - string url = Url.Action("ForumRSS", null, new { id = forum.Id }, "http"); - var feedTitle = _localizationService.GetResource("Forum.ForumFeedTitle"); - var feedDescription = _localizationService.GetResource("Forum.ForumFeedDescription"); - - var feed = new SyndicationFeed( - string.Format(feedTitle, _storeContext.CurrentStore.Name, forum.GetLocalized(x => x.Name)), - feedDescription, - new Uri(url), - string.Format("ForumRSS:{0}", forum.Id), - DateTime.UtcNow); - - var items = new List(); - - var viewsText = _localizationService.GetResource("Forum.Views"); - var repliesText = _localizationService.GetResource("Forum.Replies"); - - foreach (var topic in topics) - { - string topicUrl = Url.RouteUrl("TopicSlug", new { id = topic.Id, slug = topic.GetSeName() }, "http"); - string content = string.Format("{2}: {0}, {3}: {1}", topic.NumReplies.ToString(), topic.Views.ToString(), repliesText, viewsText); - - items.Add(new SyndicationItem(topic.Subject, content, new Uri(topicUrl), String.Format("Topic:{0}", topic.Id), - (topic.LastPostTime ?? topic.UpdatedOnUtc))); - } - - feed.Items = items; - - return new RssActionResult() { Feed = feed }; - } + var feed = _forumService.CreateForumRssFeed(Url, id); - return new RssActionResult() { Feed = new SyndicationFeed() }; + return new RssActionResult { Feed = feed }; } [HttpPost] From 1e663bc8a44d8dfeaac767ec66ab88b9ffc42d7c Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 20 Jul 2015 10:23:43 +0200 Subject: [PATCH 0086/1074] Minor changes --- .../Controllers/ProductController.cs | 35 +++--- .../Models/Catalog/BulkEditListModel.cs | 8 ++ .../Views/Product/BulkEdit.cshtml | 110 ++++++++++-------- .../Administration/Views/Product/List.cshtml | 30 ++--- 4 files changed, 108 insertions(+), 75 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 612c11b7ac..13c457c0d2 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -867,7 +867,6 @@ public ActionResult List(ProductListModel model) model.GridPageSize = _adminAreaSettings.GridPageSize; model.StoreCount = allStores.Count; - //categories var allCategories = _categoryService.GetAllCategories(showHidden: true); var mappedCategories = allCategories.ToDictionary(x => x.Id); foreach (var c in allCategories) @@ -875,22 +874,17 @@ public ActionResult List(ProductListModel model) model.AvailableCategories.Add(new SelectListItem { Text = c.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = c.Id.ToString() }); } - //manufacturers foreach (var m in _manufacturerService.GetAllManufacturers(true)) { model.AvailableManufacturers.Add(new SelectListItem { Text = m.Name, Value = m.Id.ToString() }); } - //stores - model.AvailableStores.Add(new SelectListItem { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" }); foreach (var s in allStores) { model.AvailableStores.Add(new SelectListItem { Text = s.Name, Value = s.Id.ToString() }); } - //product types model.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); - model.AvailableProductTypes.Insert(0, new SelectListItem { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" }); return View(model); } @@ -3277,25 +3271,30 @@ public ActionResult BulkEdit() if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); + var allStores = _services.StoreService.GetAllStores(); + var model = new BulkEditListModel(); + model.GridPageSize = _adminAreaSettings.GridPageSize; + model.StoreCount = allStores.Count; - //categories var allCategories = _categoryService.GetAllCategories(showHidden: true); var mappedCategories = allCategories.ToDictionary(x => x.Id); foreach (var c in allCategories) { - model.AvailableCategories.Add(new SelectListItem() { Text = c.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = c.Id.ToString() }); + model.AvailableCategories.Add(new SelectListItem { Text = c.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = c.Id.ToString() }); } - //manufacturers foreach (var m in _manufacturerService.GetAllManufacturers(true)) { - model.AvailableManufacturers.Add(new SelectListItem() { Text = m.Name, Value = m.Id.ToString() }); + model.AvailableManufacturers.Add(new SelectListItem { Text = m.Name, Value = m.Id.ToString() }); + } + + foreach (var s in allStores) + { + model.AvailableStores.Add(new SelectListItem { Text = s.Name, Value = s.Id.ToString() }); } - //product types model.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); - model.AvailableProductTypes.Insert(0, new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" }); return View(model); } @@ -3306,9 +3305,9 @@ public ActionResult BulkEditSelect(GridCommand command, BulkEditListModel model) if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - var searchContext = new ProductSearchContext() + var searchContext = new ProductSearchContext { - CategoryIds = new List() { model.SearchCategoryId }, + StoreId = model.SearchStoreId, ManufacturerId = model.SearchManufacturerId, Keywords = model.SearchProductName, SearchSku = !_catalogSettings.SuppressSkuSearch, @@ -3318,6 +3317,9 @@ public ActionResult BulkEditSelect(GridCommand command, BulkEditListModel model) ProductType = model.SearchProductTypeId > 0 ? (ProductType?)model.SearchProductTypeId : null }; + if (model.SearchCategoryId > 0) + searchContext.CategoryIds.Add(model.SearchCategoryId); + var products = _productService.SearchProducts(searchContext); var gridModel = new GridModel(); @@ -3339,7 +3341,9 @@ public ActionResult BulkEditSelect(GridCommand command, BulkEditListModel model) return productModel; }); + gridModel.Total = products.TotalCount; + return new JsonResult { Data = gridModel @@ -3369,15 +3373,16 @@ public ActionResult BulkEditSave(GridCommand command, product.OldPrice = pModel.OldPrice; product.StockQuantity = pModel.StockQuantity; product.Published = pModel.Published; + _productService.UpdateProduct(product); } } } + if (deletedProducts != null) { foreach (var pModel in deletedProducts) { - //delete var product = _productService.GetProductById(pModel.Id); if (product != null) { diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Catalog/BulkEditListModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Catalog/BulkEditListModel.cs index 711cc2d322..1850853370 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Catalog/BulkEditListModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Catalog/BulkEditListModel.cs @@ -11,6 +11,7 @@ public BulkEditListModel() { AvailableCategories = new List(); AvailableManufacturers = new List(); + AvailableStores = new List(); AvailableProductTypes = new List(); } @@ -24,11 +25,18 @@ public BulkEditListModel() [SmartResourceDisplayName("Admin.Catalog.BulkEdit.List.SearchManufacturer")] public int SearchManufacturerId { get; set; } + [SmartResourceDisplayName("Admin.Common.Store.SearchFor")] + public int SearchStoreId { get; set; } + [SmartResourceDisplayName("Admin.Catalog.Products.List.SearchProductType")] public int SearchProductTypeId { get; set; } public IList AvailableProductTypes { get; set; } + + public int GridPageSize { get; set; } + public int StoreCount { get; set; } public IList AvailableCategories { get; set; } public IList AvailableManufacturers { get; set; } + public IList AvailableStores { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/BulkEdit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/BulkEdit.cshtml index 868d78e99f..6eb786b6ba 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/BulkEdit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/BulkEdit.cshtml @@ -1,7 +1,7 @@ @model BulkEditListModel @using Telerik.Web.Mvc.UI @{ - var gridPageSize = EngineContext.Current.Resolve().GridPageSize; + var allString = T("Admin.Common.All").Text; //page title ViewBag.Title = T("Admin.Catalog.BulkEdit").Text; @@ -20,51 +20,63 @@
    @T("Admin.Catalog.BulkEdit.Info")
    - - - - - - - - - - - - - - - - - - - + +
    - @Html.SmartLabelFor(model => model.SearchProductName) - - @Html.EditorFor(model => Model.SearchProductName) -
    - @Html.SmartLabelFor(model => model.SearchCategoryId) - - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, T("Admin.Common.All").Text) -
    - @Html.SmartLabelFor(model => model.SearchManufacturerId) - - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, T("Admin.Common.All").Text) -
    - @Html.SmartLabelFor(model => model.SearchProductTypeId) - - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes) -
    + + + + + + + + + @if (Model.StoreCount > 1) + { + + + + + } + + + + + + + + + - - -
    + @Html.SmartLabelFor(model => model.SearchProductName) + + @Html.EditorFor(model => Model.SearchProductName) +
    + @Html.SmartLabelFor(model => model.SearchProductTypeId) + + @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, allString) +
    + @Html.SmartLabelFor(model => model.SearchStoreId) + + @Html.DropDownList("SearchStoreId", Model.AvailableStores, allString) +
    + @Html.SmartLabelFor(model => model.SearchCategoryId) + + @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, allString) +
    + @Html.SmartLabelFor(model => model.SearchManufacturerId) + + @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, allString) +
      - -
    -

    -

    +
    + +
    + +

    + @@ -56,7 +56,7 @@ @Html.SmartLabelFor(model => model.Description) From 6f727e3b90c9637648f846b6240caf758030e5af Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 22 Jul 2015 03:04:58 +0200 Subject: [PATCH 0098/1074] WebScheduler 2 --- .../Domain/Tasks/ScheduleTask.cs | 9 +- .../201507210153338_WebScheduler.resx | 126 ---------------- ... 201507211743009_WebScheduler.Designer.cs} | 2 +- ...ler.cs => 201507211743009_WebScheduler.cs} | 4 + .../201507211743009_WebScheduler.resx | 126 ++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../ServiceCacheConsumer.cs | 6 +- .../SmartStore.Services.csproj | 5 + .../Tasks/ChangeTaskSweeperBaseUrlConsumer.cs | 44 ++++++ .../Tasks/IScheduleTaskService.cs | 15 +- .../Tasks/ITaskExecutor.cs | 10 ++ .../SmartStore.Services/Tasks/ITaskSweeper.cs | 45 ++++++ .../Tasks/InitializeSchedulerFilter.cs | 16 +-- .../SmartStore.Services/Tasks/Job.cs | 4 +- .../Tasks/ScheduleTaskService.cs | 44 ++---- .../Tasks/TaskExecutionContext.cs | 3 + .../SmartStore.Services/Tasks/TaskExecutor.cs | 98 +++++++++++++ .../SmartStore.Services/Tasks/TaskManager.cs | 94 ------------ .../SmartStore.Services/Tasks/TaskSweeper.cs | 135 ++++++++++++++++++ .../DependencyRegistrar.cs | 3 +- .../Controllers/ScheduleTaskController.cs | 2 +- .../Controllers/TaskSchedulerController.cs | 114 ++++----------- 22 files changed, 549 insertions(+), 366 deletions(-) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.resx rename src/Libraries/SmartStore.Data/Migrations/{201507210153338_WebScheduler.Designer.cs => 201507211743009_WebScheduler.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201507210153338_WebScheduler.cs => 201507211743009_WebScheduler.cs} (67%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.resx create mode 100644 src/Libraries/SmartStore.Services/Tasks/ChangeTaskSweeperBaseUrlConsumer.cs create mode 100644 src/Libraries/SmartStore.Services/Tasks/ITaskExecutor.cs create mode 100644 src/Libraries/SmartStore.Services/Tasks/ITaskSweeper.cs create mode 100644 src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs create mode 100644 src/Libraries/SmartStore.Services/Tasks/TaskSweeper.cs diff --git a/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs b/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs index 1bcfa83e4c..8338a2e671 100644 --- a/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs +++ b/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs @@ -13,6 +13,11 @@ public class ScheduleTask : BaseEntity /// public string Name { get; set; } + /// + /// Gets or sets the task alias (an optional key for advanced customization) + /// + public string Alias { get; set; } + /// /// Gets or sets the run period (in seconds) /// @@ -45,8 +50,10 @@ public class ScheduleTask : BaseEntity public string LastError { get; set; } + public bool IsHidden { get; set; } + /// - /// Gets the value indicating whether a task is running + /// Gets a value indicating whether a task is running /// public bool IsRunning { diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.resx b/src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.resx deleted file mode 100644 index 54d5c87a9d..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.Designer.cs index d6760e5a26..765d3e0a62 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class WebScheduler : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201507210153338_WebScheduler"; } + get { return "201507211743009_WebScheduler"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.cs b/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.cs similarity index 67% rename from src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.cs rename to src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.cs index 441edbc747..d8ba5eb70b 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507210153338_WebScheduler.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.cs @@ -7,14 +7,18 @@ public partial class WebScheduler : DbMigration { public override void Up() { + AddColumn("dbo.ScheduleTask", "Alias", c => c.String(maxLength: 4000)); AddColumn("dbo.ScheduleTask", "NextRunUtc", c => c.DateTime()); + AddColumn("dbo.ScheduleTask", "IsHidden", c => c.Boolean(nullable: false)); CreateIndex("dbo.ScheduleTask", new[] { "NextRunUtc", "Enabled" }, name: "IX_NextRun_Enabled"); } public override void Down() { DropIndex("dbo.ScheduleTask", "IX_NextRun_Enabled"); + DropColumn("dbo.ScheduleTask", "IsHidden"); DropColumn("dbo.ScheduleTask", "NextRunUtc"); + DropColumn("dbo.ScheduleTask", "Alias"); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.resx b/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.resx new file mode 100644 index 0000000000..af5dcde47c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 85284e4a90..f828c8a076 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -303,9 +303,9 @@ 201507200832223_SortFilterHomepageProducts.cs - - - 201507210153338_WebScheduler.cs + + + 201507211743009_WebScheduler.cs @@ -582,8 +582,8 @@ 201507200832223_SortFilterHomepageProducts.cs - - 201507210153338_WebScheduler.cs + + 201507211743009_WebScheduler.cs diff --git a/src/Libraries/SmartStore.Services/ServiceCacheConsumer.cs b/src/Libraries/SmartStore.Services/ServiceCacheConsumer.cs index 702c0e504e..e3fd3f18b8 100644 --- a/src/Libraries/SmartStore.Services/ServiceCacheConsumer.cs +++ b/src/Libraries/SmartStore.Services/ServiceCacheConsumer.cs @@ -6,6 +6,8 @@ using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; +using SmartStore.Services.Tasks; +using SmartStore.Services.Stores; namespace SmartStore.Services { @@ -20,7 +22,7 @@ public class ServiceCacheConsumer : private readonly ICacheManager _cacheManager; - public ServiceCacheConsumer(Func cache) + public ServiceCacheConsumer(Func cache) { this._cacheManager = cache("static"); } @@ -49,5 +51,5 @@ public void HandleEvent(EntityDeleted eventMessage) { _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); } - } + } } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 36b2cef32b..ebf6732394 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -440,13 +440,18 @@ + + + + + diff --git a/src/Libraries/SmartStore.Services/Tasks/ChangeTaskSweeperBaseUrlConsumer.cs b/src/Libraries/SmartStore.Services/Tasks/ChangeTaskSweeperBaseUrlConsumer.cs new file mode 100644 index 0000000000..c02821c5f7 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Tasks/ChangeTaskSweeperBaseUrlConsumer.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Events; +using SmartStore.Services.Stores; + +namespace SmartStore.Services.Tasks +{ + public class ChangeTaskSweeperBaseUrlConsumer : + IConsumer>, + IConsumer>, + IConsumer> + { + private readonly ITaskSweeper _taskSweeper; + private readonly IStoreService _storeService; + private readonly HttpContextBase _httpContext; + + public ChangeTaskSweeperBaseUrlConsumer(ITaskSweeper taskSweeper, IStoreService storeService, HttpContextBase httpContext) + { + this._taskSweeper = taskSweeper; + this._storeService = storeService; + this._httpContext = httpContext; + } + + public void HandleEvent(EntityInserted eventMessage) + { + _taskSweeper.SetBaseUrl(_storeService, _httpContext); + } + + public void HandleEvent(EntityUpdated eventMessage) + { + _taskSweeper.SetBaseUrl(_storeService, _httpContext); + } + + public void HandleEvent(EntityDeleted eventMessage) + { + _taskSweeper.SetBaseUrl(_storeService, _httpContext); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Tasks/IScheduleTaskService.cs b/src/Libraries/SmartStore.Services/Tasks/IScheduleTaskService.cs index fcd853d341..0d53aa9010 100644 --- a/src/Libraries/SmartStore.Services/Tasks/IScheduleTaskService.cs +++ b/src/Libraries/SmartStore.Services/Tasks/IScheduleTaskService.cs @@ -35,6 +35,12 @@ public partial interface IScheduleTaskService /// Tasks IList GetAllTasks(bool showHidden = false); + /// + /// Gets all pending tasks + /// + /// Tasks + IList GetPendingTasks(); + /// /// Inserts a task /// @@ -47,10 +53,11 @@ public partial interface IScheduleTaskService /// Task void UpdateTask(ScheduleTask task); - /// - /// Ensures that a task is not marked as running - /// - /// Task identifier + /// + /// Ensures that a task is not marked as running (normalize last start and end date). + /// + /// Task identifier + /// Problem can be reproduced by inserting a news object without a language identifier. void EnsureTaskIsNotRunning(int taskId); } } diff --git a/src/Libraries/SmartStore.Services/Tasks/ITaskExecutor.cs b/src/Libraries/SmartStore.Services/Tasks/ITaskExecutor.cs new file mode 100644 index 0000000000..b14c0e7c22 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Tasks/ITaskExecutor.cs @@ -0,0 +1,10 @@ +using System; +using SmartStore.Core.Domain.Tasks; + +namespace SmartStore.Services.Tasks +{ + public interface ITaskExecutor + { + void Execute(ScheduleTask task, bool throwOnError = false); + } +} diff --git a/src/Libraries/SmartStore.Services/Tasks/ITaskSweeper.cs b/src/Libraries/SmartStore.Services/Tasks/ITaskSweeper.cs new file mode 100644 index 0000000000..87b90bfdbf --- /dev/null +++ b/src/Libraries/SmartStore.Services/Tasks/ITaskSweeper.cs @@ -0,0 +1,45 @@ +using System; +using System.Web; +using System.Linq; +using SmartStore.Core; +using SmartStore.Services.Stores; + +namespace SmartStore.Services.Tasks +{ + public interface ITaskSweeper + { + TimeSpan Interval { get; set; } + string BaseUrl { get; set; } + bool IsRunning { get; } + + void Start(); + void Stop(); + void ExecuteSingleTask(int scheduleTaskId); + bool VerifyAuthToken(string authToken); + } + + public static class ITaskSweeperExtensions + { + internal static void SetBaseUrl(this ITaskSweeper sweeper, IStoreService storeService, HttpContextBase httpContext) + { + var path = VirtualPathUtility.ToAbsolute("~/TaskScheduler"); + string url = ""; + + if (!httpContext.Request.IsLocal) + { + var defaultStore = storeService.GetAllStores().FirstOrDefault(x => storeService.IsStoreDataValid(x)); + if (defaultStore != null) + { + url = defaultStore.Url; + } + } + + if (url.IsEmpty()) + { + url = WebHelper.GetAbsoluteUrl(path, httpContext.Request); + } + + sweeper.BaseUrl = url; + } + } +} diff --git a/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs b/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs index a7aa3228ed..fa4b435ab8 100644 --- a/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs +++ b/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs @@ -34,20 +34,12 @@ public void OnAuthorization(AuthorizationContext filterContext) taskService.UpdateTask(task); } - var urlHelper = new UrlHelper(filterContext.RequestContext); - var path = urlHelper.Action("Sweep", "TaskScheduler"); + var taskSweeper = EngineContext.Current.Resolve(); - var request = filterContext.HttpContext.Request; + taskSweeper.SetBaseUrl(EngineContext.Current.Resolve(), filterContext.HttpContext); - var taskManager = EngineContext.Current.Resolve(); - var url = WebHelper.GetAbsoluteUrl(path, request); - - if (!request.IsLocal) - { - // TODO: get default store url - } - - taskManager.Start(url, 15 /* seconds */); + taskSweeper.Interval = TimeSpan.FromSeconds(10); + taskSweeper.Start(); var eventPublisher = EngineContext.Current.Resolve(); eventPublisher.Publish(new AppInitScheduledTasksEvent { ScheduledTasks = tasks }); diff --git a/src/Libraries/SmartStore.Services/Tasks/Job.cs b/src/Libraries/SmartStore.Services/Tasks/Job.cs index c38203e95c..ce7c13043b 100644 --- a/src/Libraries/SmartStore.Services/Tasks/Job.cs +++ b/src/Libraries/SmartStore.Services/Tasks/Job.cs @@ -35,7 +35,7 @@ public Job(ScheduleTask task) this.StopOnError = task.StopOnError; this.Name = task.Name; this.LastError = task.LastError; - this.IsRunning = task.IsRunning; //task.LastStartUtc.GetValueOrDefault() > task.LastEndUtc.GetValueOrDefault(); + this.IsRunning = task.IsRunning; } private ITask CreateTask(ILifetimeScope scope) @@ -101,7 +101,7 @@ public void Execute( scheduleTaskService.UpdateTask(scheduleTask); } - //execute task + // execute task var ctx = new TaskExecutionContext { LifetimeScope = scope, diff --git a/src/Libraries/SmartStore.Services/Tasks/ScheduleTaskService.cs b/src/Libraries/SmartStore.Services/Tasks/ScheduleTaskService.cs index 25f8fe6f98..480da73574 100644 --- a/src/Libraries/SmartStore.Services/Tasks/ScheduleTaskService.cs +++ b/src/Libraries/SmartStore.Services/Tasks/ScheduleTaskService.cs @@ -28,10 +28,6 @@ public ScheduleTaskService(IRepository taskRepository) #region Methods - /// - /// Deletes a task - /// - /// Task public virtual void DeleteTask(ScheduleTask task) { if (task == null) @@ -40,11 +36,6 @@ public virtual void DeleteTask(ScheduleTask task) _taskRepository.Delete(task); } - /// - /// Gets a task - /// - /// Task identifier - /// Task public virtual ScheduleTask GetTaskById(int taskId) { if (taskId == 0) @@ -53,11 +44,6 @@ public virtual ScheduleTask GetTaskById(int taskId) return _taskRepository.GetById(taskId); } - /// - /// Gets a task by its type - /// - /// Task type - /// Task public virtual ScheduleTask GetTaskByType(string type) { try @@ -80,11 +66,6 @@ public virtual ScheduleTask GetTaskByType(string type) return null; } - /// - /// Gets all tasks - /// - /// A value indicating whether to show hidden records - /// Tasks public virtual IList GetAllTasks(bool showHidden = false) { var query = _taskRepository.Table; @@ -98,10 +79,18 @@ public virtual IList GetAllTasks(bool showHidden = false) return tasks; } - /// - /// Inserts a task - /// - /// Task + public virtual IList GetPendingTasks() + { + var now = DateTime.UtcNow; + + var query = from t in _taskRepository.Table + where t.Enabled && t.NextRunUtc.HasValue && t.NextRunUtc <= now + orderby t.Seconds + select t; + + return query.ToList(); + } + public virtual void InsertTask(ScheduleTask task) { if (task == null) @@ -110,10 +99,6 @@ public virtual void InsertTask(ScheduleTask task) _taskRepository.Insert(task); } - /// - /// Updates the task - /// - /// Task public virtual void UpdateTask(ScheduleTask task) { if (task == null) @@ -122,11 +107,6 @@ public virtual void UpdateTask(ScheduleTask task) _taskRepository.Update(task); } - /// - /// Ensures that a task is not marked as running (normalize last start and end date). - /// - /// Task identifier - /// Problem can be reproduced by inserting a news object without a language identifier. public virtual void EnsureTaskIsNotRunning(int taskId) { try diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs index 074a7e619a..7b2074f2f2 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; using Autofac; +using SmartStore.Core.Domain.Tasks; namespace SmartStore.Services.Tasks { @@ -22,5 +23,7 @@ public class TaskExecutionContext /// You can use ThrowIfCancellationRequested() for a hard or IsCancellationRequested for a soft break. /// public CancellationToken CancellationToken { get; internal set; } + + public ScheduleTask ScheduleTask { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs new file mode 100644 index 0000000000..57c7f675b8 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs @@ -0,0 +1,98 @@ +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.Services.Tasks +{ + + public class TaskExecutor : ITaskExecutor + { + private readonly IScheduleTaskService _scheduledTaskService; + private readonly Func _taskResolver; + + public TaskExecutor(IScheduleTaskService scheduledTaskService, Func taskResolver) + { + this._scheduledTaskService = scheduledTaskService; + this._taskResolver = taskResolver; + + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + public void Execute(ScheduleTask task, bool throwOnError = false) + { + if (task.IsRunning) + return; // TODO: Really? + + bool faulted = false; + string lastError = null; + ITask instance = null; + + try + { + instance = CreateTaskInstance(task); + + task.LastStartUtc = DateTime.UtcNow; + task.LastEndUtc = null; + task.NextRunUtc = null; + _scheduledTaskService.UpdateTask(task); + + var ctx = new TaskExecutionContext + { + ScheduleTask = task + // TODO: Remove obsolete properties + }; + + instance.Execute(ctx); + } + catch (Exception ex) + { + faulted = true; + Logger.Error(string.Format("Error while running scheduled task '{0}'. {1}", task.Name, ex.Message), ex); + lastError = ex.Message.Truncate(995, "..."); + if (throwOnError) + { + throw; + } + } + finally + { + var now = DateTime.UtcNow; + task.LastError = lastError; + task.LastEndUtc = now; + + if (faulted) + { + if (task.StopOnError || instance == null) + { + task.Enabled = false; + } + } + else + { + task.LastSuccessUtc = now; + } + + if (task.Enabled) + { + task.NextRunUtc = task.LastStartUtc.Value.AddSeconds(task.Seconds); + } + + _scheduledTaskService.UpdateTask(task); + } + } + + private ITask CreateTaskInstance(ScheduleTask task) + { + var type = Type.GetType(task.Type); + return _taskResolver(type); + } + } + +} diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskManager.cs b/src/Libraries/SmartStore.Services/Tasks/TaskManager.cs index 4b1b3a9c5d..d570445604 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskManager.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskManager.cs @@ -4,104 +4,10 @@ using SmartStore.Core.Events; using SmartStore.Core.Infrastructure; using SmartStore.Core.Plugins; -using System.Threading; -using System.Net; -using System; namespace SmartStore.Services.Tasks { - - public class DefaultTaskManager : DisposableObject - { - private bool _isInitialized; - private bool _isSuspended; - private string _url; - private Timer _timer; - private bool _disposed; - - public void Start(string url, int interval) - { - Guard.ArgumentNotEmpty(() => url); - Guard.ArgumentNotZero(interval, "interval"); - - this._url = url; - this._timer = new Timer(new TimerCallback(this.CallEndpoint), null, interval * 1000, interval * 1000); - } - - public void ChangeUrl(string url) - { - Guard.ArgumentNotEmpty(() => url); - - this._url = url; - } - - public void ChangeInterval(int interval) - { - this._timer.Change(interval * 1000, interval * 1000); - } - - public void Suspend() - { - _isSuspended = true; - } - - public void Resume() - { - _isSuspended = false; - } - - public bool IsInitialized - { - get { return _isInitialized; } - } - public bool IsRunning - { - get { return _isInitialized && !_isSuspended; } - } - - public bool VerifyAuthToken(string authToken) - { - // TODO: Verify! - return true; - } - - private void CallEndpoint(object state) - { - var req = (HttpWebRequest)WebRequest.Create(_url); - req.UserAgent = "SmartStore.NET"; - req.Headers.Add("X-AUTH-TOKEN", Guid.NewGuid().ToString()); - req.Method = "POST"; - req.ContentType = "text/plain"; - req.ContentLength = 0; - - req.GetResponseAsync().ContinueWith(t => t.Result.Dispose()); - - //using (var resp = (HttpWebResponse)req.GetResponse()) - //{ - // //using (var stream = resp.GetResponseStream()) - // //{ - // //} - //} - } - - protected override void OnDispose(bool disposing) - { - if (disposing) - { - if ((this._timer != null) && !this._disposed) - { - lock (this) - { - this._timer.Dispose(); - this._timer = null; - this._disposed = true; - } - } - } - } - } - /// /// Represents task manager /// diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskSweeper.cs b/src/Libraries/SmartStore.Services/Tasks/TaskSweeper.cs new file mode 100644 index 0000000000..372bd34e92 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Tasks/TaskSweeper.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Timers; + +namespace SmartStore.Services.Tasks +{ + + public class TaskSweeper : DisposableObject, ITaskSweeper + { + private string _baseUrl; + private Timer _timer; + private readonly ConcurrentDictionary _authTokens = new ConcurrentDictionary(); + + public TaskSweeper() + { + _timer = new Timer(TimeSpan.FromMinutes(1).TotalMilliseconds); + _timer.Elapsed += Elapsed; + } + + public TimeSpan Interval + { + get { return TimeSpan.FromMilliseconds(_timer.Interval); } + set { _timer.Interval = value.TotalMilliseconds; } + } + + public string BaseUrl + { + get { return _baseUrl; } + set + { + CheckUrl(value); + _baseUrl = value.TrimEnd('/', '\\'); + } + } + + public void Start() + { + lock (_timer) + { + CheckUrl(_baseUrl); + _timer.Start(); + } + } + + public void Stop() + { + lock (_timer) + { + _timer.Stop(); + } + } + + public bool IsRunning + { + get { return _timer.Enabled; } + } + + public bool VerifyAuthToken(string authToken) + { + if (authToken.IsEmpty()) + return false; + + bool val = false; + return _authTokens.TryRemove(authToken, out val); + } + + public void ExecuteSingleTask(int scheduleTaskId) + { + CallEndpoint(_baseUrl + "/Execute/{0}".FormatInvariant(scheduleTaskId)); + } + + private void Elapsed(object sender, ElapsedEventArgs e) + { + if (!System.Threading.Monitor.TryEnter(_timer)) + return; + + try + { + if (_timer.Enabled) + { + CallEndpoint(_baseUrl + "/Sweep"); + } + } + finally + { + System.Threading.Monitor.Exit(_timer); + } + } + + private void CallEndpoint(string url) + { + var req = (HttpWebRequest)WebRequest.Create(url); + req.UserAgent = "SmartStore.NET"; + req.Method = "POST"; + req.ContentType = "text/plain"; + req.ContentLength = 0; + + string authToken = Guid.NewGuid().ToString(); + _authTokens.TryAdd(authToken, true); + req.Headers.Add("X-AUTH-TOKEN", authToken); + + req.GetResponseAsync().ContinueWith(t => + { + if (t.IsFaulted) + { + // TODO: Now what?! Disable timer? + } + t.Result.Dispose(); + }); + } + + private void CheckUrl(string url) + { + if (!url.IsWebUrl()) + { + throw Error.InvalidOperation("A valid base url is required for the background task scheduler."); + } + } + + protected override void OnDispose(bool disposing) + { + if (disposing) + { + _timer.Dispose(); + } + } + + } + +} diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 68d016338e..c61afef079 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -939,7 +939,8 @@ protected override void Load(ContainerBuilder builder) if (!DataSettings.DatabaseIsInstalled()) return; - builder.RegisterInstance(new DefaultTaskManager()).SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().InstancePerRequest(); var taskTypes = _typeFinder.FindClassesOfType(ignoreInactivePlugins: true).ToList(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs index d5d6110dee..c2ab804116 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs @@ -72,7 +72,7 @@ protected ScheduleTaskModel PrepareScheduleTaskModel(ScheduleTask task) LastEndUtc = task.LastEndUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(task.LastEndUtc.Value, DateTimeKind.Utc).ToString("G") : "", LastSuccessUtc = task.LastSuccessUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(task.LastSuccessUtc.Value, DateTimeKind.Utc).ToString("G") : "", LastError = task.LastError.EmptyNull(), - IsRunning = task.IsRunning, //task.LastStartUtc.GetValueOrDefault() > task.LastEndUtc.GetValueOrDefault(), + IsRunning = task.IsRunning, Duration = "" }; diff --git a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs index 91d8493ad3..8c664c376a 100644 --- a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs @@ -1,124 +1,68 @@ -using SmartStore.Core.Data; -using SmartStore.Core.Domain.Tasks; -using SmartStore.Core.Localization; -using SmartStore.Core.Logging; -using SmartStore.Services; -using SmartStore.Services.Tasks; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Services.Tasks; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Services.Security; +using SmartStore.Services; namespace SmartStore.Web.Controllers { public class TaskSchedulerController : Controller { - private readonly DefaultTaskManager _taskManager; - private readonly IRepository _tasksRepository; - private readonly Func _taskResolver; + private readonly ITaskSweeper _taskSweeper; + private readonly IScheduleTaskService _scheduledTaskService; + private readonly ITaskExecutor _taskExecutor; private readonly ICommonServices _services; public TaskSchedulerController( - DefaultTaskManager taskManager, - IRepository tasksRepository, - Func taskResolver, + ITaskSweeper taskSweeper, + IScheduleTaskService scheduledTaskService, + ITaskExecutor taskExecutor, ICommonServices services) { - this._taskManager = taskManager; - this._tasksRepository = tasksRepository; - this._taskResolver = taskResolver; + this._taskSweeper = taskSweeper; + this._scheduledTaskService = scheduledTaskService; + this._taskExecutor = taskExecutor; this._services = services; - - T = NullLocalizer.Instance; - Logger = NullLogger.Instance; } - public Localizer T { get; set; } - - public ILogger Logger { get; set; } - [HttpPost] public ActionResult Sweep() { - var authToken = Request.Headers["X-AUTH-TOKEN"]; - if (authToken.IsEmpty()) - return new HttpUnauthorizedResult(); - - if (!_taskManager.VerifyAuthToken(authToken)) + if (!_taskSweeper.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) return new HttpUnauthorizedResult(); - var pendingTasks = GetPendingTasks(); + var pendingTasks = _scheduledTaskService.GetPendingTasks(); foreach (var task in pendingTasks) { - var instance = CreateTaskInstance(task); - ExecuteTask(instance, task); + _taskExecutor.Execute(task); } return Content("{0} tasks executed".FormatInvariant(pendingTasks.Count)); } - private ICollection GetPendingTasks() - { - var now = DateTime.UtcNow; - - var query = from t in _tasksRepository.Table - where t.Enabled && t.NextRunUtc.HasValue && t.NextRunUtc <= now - orderby t.Seconds - select t; - - return query.ToList(); - } - - private ITask CreateTaskInstance(ScheduleTask task) - { - var type = Type.GetType(task.Type); - return _taskResolver(type); - } - - private void ExecuteTask(ITask instance, ScheduleTask task) + [HttpPost] + public ActionResult Execute(int id /* taskId */) { - bool faulted = false; - string lastError = null; + if (!_taskSweeper.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) + return new HttpUnauthorizedResult(); - try - { - task.NextRunUtc = null; - task.LastStartUtc = DateTime.UtcNow; - _tasksRepository.Update(task); + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageScheduleTasks)) + return new HttpUnauthorizedResult(); - // EXECUTE - } - catch (Exception ex) - { - Logger.Error(string.Format("Error while running the '{0}' schedule task. {1}", task.Name, ex.Message), ex); - faulted = true; - lastError = ex.Message.Truncate(995, "..."); - } - finally - { - var now = DateTime.UtcNow; - task.LastError = lastError; - task.LastEndUtc = now; - - if (faulted) - { - task.Enabled = task.StopOnError; - } - else - { - task.LastSuccessUtc = now; - } + var task = _scheduledTaskService.GetTaskById(id); + if (task == null) + return HttpNotFound(); - if (task.Enabled) - { - task.NextRunUtc = task.LastStartUtc.Value.AddSeconds(task.Seconds); - } + _taskExecutor.Execute(task); - _tasksRepository.Update(task); - } + return Content("Task '{0}' executed".FormatCurrent(task.Name)); } } From 20b93a25e13a6eb6f5ecc6b2e71b58497bae0b97 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 22 Jul 2015 04:38:32 +0200 Subject: [PATCH 0099/1074] WebScheduler 3 --- .../Common/KeepAliveTask.cs | 38 +--- .../SmartStore.Services.csproj | 3 - .../SmartStore.Services/Tasks/ITaskSweeper.cs | 3 +- .../Tasks/InitializeSchedulerFilter.cs | 2 - .../SmartStore.Services/Tasks/Job.cs | 205 ------------------ .../Tasks/TaskExecutionContext.cs | 20 +- .../SmartStore.Services/Tasks/TaskManager.cs | 120 ---------- .../SmartStore.Services/Tasks/TaskSweeper.cs | 12 + .../SmartStore.Services/Tasks/TaskThread.cs | 177 --------------- .../StaticFileGenerationTask.cs | 16 +- .../Plugins/FeedPluginHelper.cs | 49 +---- .../Controllers/ScheduleTaskController.cs | 51 +---- .../Models/Tasks/ScheduleTaskModel.cs | 3 + .../Views/ScheduleTask/List.cshtml | 4 +- .../Controllers/KeepAliveController.cs | 12 - .../Controllers/TaskSchedulerController.cs | 3 - .../SmartStore.Web/Global.asax.cs | 4 - .../SmartStore.Web/SmartStore.Web.csproj | 1 - 18 files changed, 55 insertions(+), 668 deletions(-) delete mode 100644 src/Libraries/SmartStore.Services/Tasks/Job.cs delete mode 100644 src/Libraries/SmartStore.Services/Tasks/TaskManager.cs delete mode 100644 src/Libraries/SmartStore.Services/Tasks/TaskThread.cs delete mode 100644 src/Presentation/SmartStore.Web/Controllers/KeepAliveController.cs diff --git a/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs b/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs index 74a382ccae..a7ae21aa9a 100644 --- a/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs +++ b/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs @@ -1,5 +1,6 @@ using System; using System.Net; +using System.Threading.Tasks; using SmartStore.Core; using SmartStore.Services.Tasks; @@ -10,45 +11,10 @@ namespace SmartStore.Services.Common /// public partial class KeepAliveTask : ITask { - private readonly IStoreContext _storeContext; - - public KeepAliveTask(IStoreContext storeContext) - { - this._storeContext = storeContext; - } public void Execute(TaskExecutionContext ctx) { - var storeUrl = _storeContext.CurrentStore.Url.TrimEnd('\\').EnsureEndsWith("/"); - string url = storeUrl + "keepalive/index"; - - try - { - using (var wc = new WebClient()) - { - // FAKE a user-agent - wc.Headers.Add("user-agent", @"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"); - if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) - { - url = "http://" + url; - } - wc.DownloadString(url); - } - } - catch (WebException ex) - { - if (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null) - { - var resp = (HttpWebResponse)ex.Response; - if (resp.StatusCode == HttpStatusCode.NotFound) // HTTP 404 - { - // the page was not found (as it can be expected with some webservers) - return; - } - } - // throw any other exception - this should not occur - throw; - } + // do absolutely nothing } } } diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index ebf6732394..d7056f00dc 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -447,12 +447,9 @@ - - - diff --git a/src/Libraries/SmartStore.Services/Tasks/ITaskSweeper.cs b/src/Libraries/SmartStore.Services/Tasks/ITaskSweeper.cs index 87b90bfdbf..57b0ea4b09 100644 --- a/src/Libraries/SmartStore.Services/Tasks/ITaskSweeper.cs +++ b/src/Libraries/SmartStore.Services/Tasks/ITaskSweeper.cs @@ -3,10 +3,11 @@ using System.Linq; using SmartStore.Core; using SmartStore.Services.Stores; +using System.Web.Hosting; namespace SmartStore.Services.Tasks { - public interface ITaskSweeper + public interface ITaskSweeper : IRegisteredObject { TimeSpan Interval { get; set; } string BaseUrl { get; set; } diff --git a/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs b/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs index fa4b435ab8..0c38de3322 100644 --- a/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs +++ b/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs @@ -37,8 +37,6 @@ public void OnAuthorization(AuthorizationContext filterContext) var taskSweeper = EngineContext.Current.Resolve(); taskSweeper.SetBaseUrl(EngineContext.Current.Resolve(), filterContext.HttpContext); - - taskSweeper.Interval = TimeSpan.FromSeconds(10); taskSweeper.Start(); var eventPublisher = EngineContext.Current.Resolve(); diff --git a/src/Libraries/SmartStore.Services/Tasks/Job.cs b/src/Libraries/SmartStore.Services/Tasks/Job.cs deleted file mode 100644 index ce7c13043b..0000000000 --- a/src/Libraries/SmartStore.Services/Tasks/Job.cs +++ /dev/null @@ -1,205 +0,0 @@ -using System; -using System.Threading; -using Autofac; -using SmartStore.Core.Domain.Tasks; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Logging; - -namespace SmartStore.Services.Tasks -{ - /// - /// Task - /// - /// - /// Formerly Task. Had to rename to Job in order to prevent naming conflicts with System.Threading.Tasks.Task - /// - public partial class Job - { - - /// - /// Ctor for Task - /// - private Job() - { - this.Enabled = true; - } - - /// - /// Ctor for Task - /// - /// Task - public Job(ScheduleTask task) - { - this.Type = task.Type; - this.Enabled = task.Enabled; - this.StopOnError = task.StopOnError; - this.Name = task.Name; - this.LastError = task.LastError; - this.IsRunning = task.IsRunning; - } - - private ITask CreateTask(ILifetimeScope scope) - { - ITask task = null; - if (this.Enabled) - { - var type2 = System.Type.GetType(this.Type); - if (type2 != null) - { - object instance; - if (!EngineContext.Current.ContainerManager.TryResolve(type2, scope, out instance)) - { - // not resolved - instance = EngineContext.Current.ContainerManager.ResolveUnregistered(type2, scope); - } - task = instance as ITask; - } - } - return task; - } - - /// - /// Executes the task - /// - /// - /// The caller is responsible for disposing the lifetime scope - /// - public void Execute(ILifetimeScope scope = null, bool throwOnError = false) - { - Execute(CancellationToken.None, scope, throwOnError); - } - - /// - /// Executes the task - /// - /// - /// The caller is responsible for disposing the lifetime scope - /// - public void Execute( - CancellationToken cancellationToken, - ILifetimeScope scope = null, - bool throwOnError = false) - { - this.IsRunning = true; - var faulted = false; - scope = scope ?? EngineContext.Current.ContainerManager.Scope(); - - try - { - var task = this.CreateTask(scope); - if (task != null) - { - this.LastStartUtc = DateTime.UtcNow; - - var scheduleTaskService = scope.Resolve(); - var scheduleTask = scheduleTaskService.GetTaskByType(this.Type); - - if (scheduleTask != null) - { - //update appropriate datetime properties - scheduleTask.LastStartUtc = this.LastStartUtc; - scheduleTaskService.UpdateTask(scheduleTask); - } - - // execute task - var ctx = new TaskExecutionContext - { - LifetimeScope = scope, - CancellationToken = cancellationToken - }; - - task.Execute(ctx); - - ctx.CancellationToken.ThrowIfCancellationRequested(); - this.LastEndUtc = this.LastSuccessUtc = DateTime.UtcNow; - this.LastError = null; - } - else - { - faulted = true; - this.LastError = "Could not create task instance"; - } - } - catch (Exception ex) - { - faulted = true; - this.Enabled = !this.StopOnError; - this.LastEndUtc = DateTime.UtcNow; - this.LastError = ex.Message.Truncate(995, "..."); - - //log error - var logger = scope.Resolve(); - logger.Error(string.Format("Error while running the '{0}' schedule task. {1}", this.Name, ex.Message), ex); - if (throwOnError) - { - throw; - } - } - finally - { - var scheduleTaskService = scope.Resolve(); - var scheduleTask = scheduleTaskService.GetTaskByType(this.Type); - - if (scheduleTask != null) - { - // update appropriate properties - scheduleTask.LastError = this.LastError; - scheduleTask.LastEndUtc = this.LastEndUtc; - if (!faulted) - { - scheduleTask.LastSuccessUtc = this.LastSuccessUtc; - } - - scheduleTaskService.UpdateTask(scheduleTask); - } - - this.IsRunning = false; - } - } - - /// - /// A value indicating whether a task is running - /// - public bool IsRunning { get; private set; } - - /// - /// Datetime of the last start - /// - public DateTime? LastStartUtc { get; private set; } - - /// - /// Datetime of the last end - /// - public DateTime? LastEndUtc { get; private set; } - - /// - /// Datetime of the last success - /// - public DateTime? LastSuccessUtc { get; private set; } - - /// - /// Message of the last error - /// - public string LastError { get; private set; } - - /// - /// A value indicating type of the task - /// - public string Type { get; private set; } - - /// - /// A value indicating whether to stop task on error - /// - public bool StopOnError { get; private set; } - - /// - /// Get the task name - /// - public string Name { get; private set; } - - /// - /// A value indicating whether the task is enabled - /// - public bool Enabled { get; set; } - } -} diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs index 7b2074f2f2..6012a4dbb7 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs @@ -12,17 +12,17 @@ namespace SmartStore.Services.Tasks /// public class TaskExecutionContext { - /// - /// The shared instance created - /// before the execution of the task's background thread. - /// - public object LifetimeScope { get; internal set; } + /// + /// The shared instance created + /// before the execution of the task's background thread. + /// + public object LifetimeScope { get; internal set; } - /// - /// A cancellation token for the running task. - /// You can use ThrowIfCancellationRequested() for a hard or IsCancellationRequested for a soft break. - /// - public CancellationToken CancellationToken { get; internal set; } + /// + /// A cancellation token for the running task. + /// You can use ThrowIfCancellationRequested() for a hard or IsCancellationRequested for a soft break. + /// + public CancellationToken CancellationToken { get; internal set; } public ScheduleTask ScheduleTask { get; set; } } diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskManager.cs b/src/Libraries/SmartStore.Services/Tasks/TaskManager.cs deleted file mode 100644 index d570445604..0000000000 --- a/src/Libraries/SmartStore.Services/Tasks/TaskManager.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using SmartStore.Core.Events; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Plugins; - -namespace SmartStore.Services.Tasks -{ - - /// - /// Represents task manager - /// - public partial class TaskManager - { - private static readonly TaskManager _taskManager = new TaskManager(); - private readonly List _taskThreads = new List(); - - private TaskManager() - { - } - - /// - /// Initializes the task manager with the property values specified in the configuration file. - /// - public void Initialize() - { - this._taskThreads.Clear(); - - var taskService = EngineContext.Current.Resolve(); - var scheduleTasks = taskService.GetAllTasks(); - - var eventPublisher = EngineContext.Current.Resolve(); - eventPublisher.Publish(new AppInitScheduledTasksEvent { - ScheduledTasks = scheduleTasks - }); - - // group by threads with the same seconds - foreach (var scheduleTaskGrouped in scheduleTasks.GroupBy(x => x.Seconds)) - { - // create a thread - var taskThread = new TaskThread(); - taskThread.Seconds = scheduleTaskGrouped.Key; - - foreach (var scheduleTask in scheduleTaskGrouped) - { - var taskType = System.Type.GetType(scheduleTask.Type); - if (taskType != null) - { - var isActiveModule = PluginManager.IsActivePluginAssembly(taskType.Assembly); - if (isActiveModule) - { - var job = new Job(scheduleTask); - taskThread.AddJob(job); - } - } - } - - if (taskThread.HasJobs) - { - this._taskThreads.Add(taskThread); - } - } - - - //one thread, one task - //foreach (var scheduleTask in scheduleTasks) - //{ - // var taskThread = new TaskThread(scheduleTask); - // this._taskThreads.Add(taskThread); - // var task = new Task(scheduleTask); - // taskThread.AddTask(task); - //} - } - - /// - /// Starts the task manager - /// - public void Start() - { - foreach (var taskThread in this._taskThreads) - { - taskThread.InitTimer(); - } - } - - /// - /// Stops the task manager - /// - public void Stop() - { - foreach (var taskThread in this._taskThreads) - { - taskThread.Dispose(); - } - } - - /// - /// Gets the task mamanger instance - /// - public static TaskManager Instance - { - get - { - return _taskManager; - } - } - - /// - /// Gets a list of task threads of this task manager - /// - public IList TaskThreads - { - get - { - return new ReadOnlyCollection(this._taskThreads); - } - } - } -} diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskSweeper.cs b/src/Libraries/SmartStore.Services/Tasks/TaskSweeper.cs index 372bd34e92..babbbedfef 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskSweeper.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskSweeper.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using System.Timers; +using System.Web.Hosting; namespace SmartStore.Services.Tasks { @@ -14,12 +15,15 @@ public class TaskSweeper : DisposableObject, ITaskSweeper { private string _baseUrl; private Timer _timer; + private bool _shuttingDown; private readonly ConcurrentDictionary _authTokens = new ConcurrentDictionary(); public TaskSweeper() { _timer = new Timer(TimeSpan.FromMinutes(1).TotalMilliseconds); _timer.Elapsed += Elapsed; + + HostingEnvironment.RegisterObject(this); } public TimeSpan Interval @@ -94,6 +98,9 @@ private void Elapsed(object sender, ElapsedEventArgs e) private void CallEndpoint(string url) { + if (_shuttingDown) + return; + var req = (HttpWebRequest)WebRequest.Create(url); req.UserAgent = "SmartStore.NET"; req.Method = "POST"; @@ -130,6 +137,11 @@ protected override void OnDispose(bool disposing) } } + void IRegisteredObject.Stop(bool immediate) + { + _shuttingDown = true; + HostingEnvironment.UnregisterObject(this); + } } } diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskThread.cs b/src/Libraries/SmartStore.Services/Tasks/TaskThread.cs deleted file mode 100644 index b165daaeec..0000000000 --- a/src/Libraries/SmartStore.Services/Tasks/TaskThread.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using SmartStore.Core.Async; -using SmartStore.Core.Domain.Tasks; - -namespace SmartStore.Services.Tasks -{ - /// - /// Represents task thread - /// - public partial class TaskThread : IDisposable - { - private Timer _timer; - private bool _disposed; - private DateTime _startedUtc; - private bool _isRunning; - private readonly Dictionary _jobs; - private int _seconds; - - internal TaskThread() - { - this._jobs = new Dictionary(); - this._seconds = 10 * 60; - } - - internal TaskThread(ScheduleTask scheduleTask) - { - this._jobs = new Dictionary(); - this._seconds = scheduleTask.Seconds; - this._isRunning = false; - } - - private void Run() - { - if (_seconds <=0) - return; - - this._startedUtc = DateTime.UtcNow; - this._isRunning = true; - - var jobs = _jobs.Values - .Select(job => AsyncRunner.Run((c, ct) => job.Execute(ct, c))) - .ToArray(); - - try - { - Task.WaitAll(jobs); - } - catch { } - - this._isRunning = false; - } - - private void TimerHandler(object state) - { - this._timer.Change(-1, -1); - this.Run(); - this._timer.Change(this.Interval, this.Interval); - } - - /// - /// Disposes the instance - /// - public void Dispose() - { - if ((this._timer != null) && !this._disposed) - { - lock (this) - { - this._timer.Dispose(); - this._timer = null; - this._disposed = true; - } - } - } - - /// - /// Inits a timer - /// - public void InitTimer() - { - if (this._timer == null) - { - this._timer = new Timer(new TimerCallback(this.TimerHandler), null, this.Interval, this.Interval); - } - } - - /// - /// Adds a job to the thread - /// - /// The task to be added - public void AddJob(Job job) - { - if (!this._jobs.ContainsKey(job.Name)) - { - this._jobs.Add(job.Name, job); - } - } - - - /// - /// Gets or sets the interval in seconds at which to run the jobs - /// - public int Seconds - { - get - { - return this._seconds; - } - internal set - { - this._seconds = value; - } - } - - /// - /// Get a datetime when thread has been started - /// - public DateTime Started - { - get - { - return this._startedUtc; - } - } - - /// - /// Get a value indicating whether thread is running - /// - public bool IsRunning - { - get - { - return this._isRunning; - } - } - - /// - /// Get a list of jobs - /// - public IList Jobs - { - get - { - var list = new List(); - foreach (var jobs in this._jobs.Values) - { - list.Add(jobs); - } - return new ReadOnlyCollection(list); - } - } - - public bool HasJobs - { - get { return _jobs.Count > 0; } - } - - /// - /// Gets the interval at which to run the jobs - /// - public int Interval - { - get - { - if (_seconds > (Int32.MaxValue / 1000)) - return Int32.MaxValue; - - return this._seconds * 1000; - } - } - } -} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/StaticFileGenerationTask.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/StaticFileGenerationTask.cs index 2cc1cfca3b..5b0c3e456a 100644 --- a/src/Plugins/SmartStore.GoogleMerchantCenter/StaticFileGenerationTask.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/StaticFileGenerationTask.cs @@ -5,13 +5,17 @@ namespace SmartStore.GoogleMerchantCenter { public class StaticFileGenerationTask : ITask - { - public void Execute(TaskExecutionContext context) + { + private readonly IGoogleFeedService _feedService; + + public StaticFileGenerationTask(IGoogleFeedService feedService) + { + this._feedService = feedService; + } + + public void Execute(TaskExecutionContext context) { - var scope = context.LifetimeScope as ILifetimeScope; - var googleService = scope.Resolve(); - - googleService.CreateFeed(context); + _feedService.CreateFeed(context); } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs index 9acc2ee0b5..50fbda7636 100644 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs @@ -609,53 +609,12 @@ public bool RunScheduleTask() return true; } - string scheduleTaskType = ScheduleTaskType; + var taskSweeper = _ctx.Resolve(); + taskSweeper.ExecuteSingleTask(ScheduleTask.Id); - var task = AsyncRunner.Run((container, ct) => - { - int taskId = 0; - try - { - var svc = container.Resolve(); - - var scheduleTask = svc.GetTaskByType(scheduleTaskType); + Notifier.Information(GetResource("Admin.System.ScheduleTasks.RunNow.Progress")); - if (scheduleTask == null) - throw new Exception("Schedule task cannot be loaded"); - - taskId = scheduleTask.Id; - - var job = new Job(scheduleTask); - job.Enabled = true; - job.Execute(ct, container, false); - } - catch (Exception) - { - _scheduleTaskService.EnsureTaskIsNotRunning(taskId); - } - }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); - - task.Wait(100); - - if (task.IsCompleted) - { - if (!task.IsFaulted) - { - Notifier.Success(GetResource("Admin.System.ScheduleTasks.RunNow.Completed")); - } - else - { - var exc = task.Exception.Flatten().InnerException; - Notifier.Error(exc.Message); - Logger.Error(exc.Message, exc); - } - } - else - { - Notifier.Information(GetResource("Admin.System.ScheduleTasks.RunNow.Progress")); - return true; - } - return false; + return true; } public string GetProgressInfo(bool checkIfRunnning = false) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs index c2ab804116..e935d249f6 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs @@ -30,6 +30,7 @@ public partial class ScheduleTaskController : AdminControllerBase #region Fields private readonly IScheduleTaskService _scheduleTaskService; + private readonly ITaskSweeper _taskSweeper; private readonly IPermissionService _permissionService; private readonly IDateTimeHelper _dateTimeHelper; @@ -37,9 +38,14 @@ public partial class ScheduleTaskController : AdminControllerBase #region Constructors - public ScheduleTaskController(IScheduleTaskService scheduleTaskService, IPermissionService permissionService, IDateTimeHelper dateTimeHelper) + public ScheduleTaskController( + IScheduleTaskService scheduleTaskService, + ITaskSweeper taskSweeper, + IPermissionService permissionService, + IDateTimeHelper dateTimeHelper) { this._scheduleTaskService = scheduleTaskService; + this._taskSweeper = taskSweeper; this._permissionService = permissionService; this._dateTimeHelper = dateTimeHelper; } @@ -61,7 +67,7 @@ private bool IsTaskInstalled(ScheduleTask task) [NonAction] protected ScheduleTaskModel PrepareScheduleTaskModel(ScheduleTask task) { - var model = new ScheduleTaskModel() + var model = new ScheduleTaskModel { Id = task.Id, Name = task.Name, @@ -71,6 +77,7 @@ protected ScheduleTaskModel PrepareScheduleTaskModel(ScheduleTask task) LastStartUtc = task.LastStartUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(task.LastStartUtc.Value, DateTimeKind.Utc).ToString("G") : "", LastEndUtc = task.LastEndUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(task.LastEndUtc.Value, DateTimeKind.Utc).ToString("G") : "", LastSuccessUtc = task.LastSuccessUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(task.LastSuccessUtc.Value, DateTimeKind.Utc).ToString("G") : "", + NextRunUtc = task.NextRunUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(task.NextRunUtc.Value, DateTimeKind.Utc).ToString("G") : "", LastError = task.LastError.EmptyNull(), IsRunning = task.IsRunning, Duration = "" @@ -163,45 +170,9 @@ public ActionResult RunJob(int id, string returnUrl = "") returnUrl = returnUrl.NullEmpty() ?? Request.UrlReferrer.ToString(); - var t = AsyncRunner.Run((c, ct) => - { - var svc = c.Resolve(); - - try - { - var scheduleTask = svc.GetTaskById(id); - if (scheduleTask == null) - throw new Exception("Schedule task cannot be loaded"); - - var job = new Job(scheduleTask); - job.Enabled = true; - job.Execute(ct, c, false); - } - catch - { - svc.EnsureTaskIsNotRunning(id); - } - }); - - // wait only 100 ms. - t.Wait(100); - - if (t.IsCompleted) - { - if (!t.IsFaulted) - { - NotifySuccess(T("Admin.System.ScheduleTasks.RunNow.Completed")); - } - else - { - NotifyError(t.Exception.Flatten().InnerException); - } - } - else - { - NotifyInfo(T("Admin.System.ScheduleTasks.RunNow.Progress")); - } + _taskSweeper.ExecuteSingleTask(id); + NotifyInfo(T("Admin.System.ScheduleTasks.RunNow.Progress")); return Redirect(returnUrl); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs index bf8c17662b..fd312654d3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs @@ -31,6 +31,9 @@ public partial class ScheduleTaskModel : EntityModelBase [SmartResourceDisplayName("Admin.System.ScheduleTasks.LastSuccess")] public string LastSuccessUtc { get; set; } + [SmartResourceDisplayName("Admin.System.ScheduleTasks.NextRun")] + public string NextRunUtc { get; set; } + [SmartResourceDisplayName("Common.Error")] public string LastError { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml index c2c9ea2581..e0ec668528 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml @@ -40,11 +40,9 @@ .ClientTemplate(@Html.SymbolForBool("StopOnError")) .Centered() .Width(100); - //columns.Bound(x => x.LastStartUtc).ReadOnly(); - //columns.Bound(x => x.LastEndUtc).ReadOnly(); - //columns.Bound(x => x.LastSuccessUtc).ReadOnly(); columns.Bound(x => x.Id) .ClientTemplate("<# if (LastStartUtc.length) {#>
    " + @T("Admin.System.ScheduleTasks.LastStart") + ": <#= LastStartUtc #>
    <# } #>" + + //"<# if (NextRunUtc) {#>
    " + @T("Admin.System.ScheduleTasks.NextRun") + ": <#= NextRunUtc #>
    <# } #>" + "<# if (!LastEndUtc && !IsRunning) {#>
    " + @T("Admin.System.ScheduleTasks.LastStart") + ": " + @T("Common.Never") + "
    <# } #>" + "<# if (Duration.length) {#>
    " + @T("Common.Duration") + ": <#= Duration #>
    <# } #>" + "<# if (LastError.length) {#>
    " + @T("Common.Error") + ": <#= LastError #>
    <# } #>" + diff --git a/src/Presentation/SmartStore.Web/Controllers/KeepAliveController.cs b/src/Presentation/SmartStore.Web/Controllers/KeepAliveController.cs deleted file mode 100644 index 3093193eb9..0000000000 --- a/src/Presentation/SmartStore.Web/Controllers/KeepAliveController.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Web.Mvc; - -namespace SmartStore.Web.Controllers -{ - public partial class KeepAliveController : Controller - { - public ActionResult Index() - { - return Content("I am alive!"); - } - } -} diff --git a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs index 8c664c376a..bcaaadd658 100644 --- a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs @@ -52,9 +52,6 @@ public ActionResult Execute(int id /* taskId */) { if (!_taskSweeper.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) return new HttpUnauthorizedResult(); - - if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageScheduleTasks)) - return new HttpUnauthorizedResult(); var task = _scheduledTaskService.GetTaskById(id); if (task == null) diff --git a/src/Presentation/SmartStore.Web/Global.asax.cs b/src/Presentation/SmartStore.Web/Global.asax.cs index 0db44b9ae3..1ab1679bc0 100644 --- a/src/Presentation/SmartStore.Web/Global.asax.cs +++ b/src/Presentation/SmartStore.Web/Global.asax.cs @@ -115,10 +115,6 @@ protected void Application_Start() HostingEnvironment.RegisterVirtualPathProvider(new PluginDebugViewVirtualPathProvider()); } - // start scheduled tasks - TaskManager.Instance.Initialize(); - TaskManager.Instance.Start(); - // Install filter GlobalFilters.Filters.Add(new InitializeSchedulerFilter()); } diff --git a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj index 6bf75736ec..30f870100e 100644 --- a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj +++ b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj @@ -253,7 +253,6 @@ - From 368daab9c76a5fb303814f9b18186767890a3f3a Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 22 Jul 2015 11:59:16 +0200 Subject: [PATCH 0100/1074] There was no payment redirect if only one payment method is available in checkout --- changelog.md | 3 ++- .../Controllers/CheckoutController.cs | 15 +++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index 242e7ca78c..6e8c2f90ad 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,4 @@ -# Release Notes +# Release Notes ## SmartStore.NET 2.2.2 @@ -36,6 +36,7 @@ * Weight adjustment of attributes weren't applied in shopping cart overview * Shipping by weight calculates wrong surcharge if attribute combination prices are set * Don't let database hooks call other hooks. +* There was no payment redirect if only one payment method is available in checkout ## SmartStore.NET 2.2.1 diff --git a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs index 8b1e37d65e..1702e3b5c3 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs @@ -797,13 +797,11 @@ public ActionResult ConfirmOrder(FormCollection form) var model = new CheckoutConfirmModel(); try { - bool isPaymentPaymentWorkflowRequired = IsPaymentWorkflowRequired(cart); - var processPaymentRequest = _httpContext.Session["OrderPaymentInfo"] as ProcessPaymentRequest; if (processPaymentRequest == null) { //Check whether payment workflow is required - if (isPaymentPaymentWorkflowRequired) + if (IsPaymentWorkflowRequired(cart)) return RedirectToAction("PaymentMethod"); processPaymentRequest = new ProcessPaymentRequest(); @@ -826,14 +824,11 @@ public ActionResult ConfirmOrder(FormCollection form) if (placeOrderResult.Success) { - if (isPaymentPaymentWorkflowRequired) + var postProcessPaymentRequest = new PostProcessPaymentRequest { - var postProcessPaymentRequest = new PostProcessPaymentRequest() - { - Order = placeOrderResult.PlacedOrder - }; - _paymentService.PostProcessPayment(postProcessPaymentRequest); - } + Order = placeOrderResult.PlacedOrder + }; + _paymentService.PostProcessPayment(postProcessPaymentRequest); _httpContext.Session["PaymentData"] = null; _httpContext.Session["OrderPaymentInfo"] = null; From 13e536d4918aa15913bafc92a2e15b2ed42766fc Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 22 Jul 2015 12:03:39 +0200 Subject: [PATCH 0101/1074] There was no payment redirect if only one payment method is available in checkout --- .../SmartStore.Web/Controllers/CheckoutController.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs index eb18e5bdae..0a960e58d8 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs @@ -806,13 +806,11 @@ public ActionResult ConfirmOrder(FormCollection form) var model = new CheckoutConfirmModel(); try { - bool isPaymentPaymentWorkflowRequired = IsPaymentWorkflowRequired(cart); - var processPaymentRequest = _httpContext.Session["OrderPaymentInfo"] as ProcessPaymentRequest; if (processPaymentRequest == null) { //Check whether payment workflow is required - if (isPaymentPaymentWorkflowRequired) + if (IsPaymentWorkflowRequired(cart)) return RedirectToAction("PaymentMethod"); processPaymentRequest = new ProcessPaymentRequest(); @@ -840,10 +838,7 @@ public ActionResult ConfirmOrder(FormCollection form) Order = placeOrderResult.PlacedOrder }; - if (isPaymentPaymentWorkflowRequired) - { - _paymentService.PostProcessPayment(postProcessPaymentRequest); - } + _paymentService.PostProcessPayment(postProcessPaymentRequest); _httpContext.Session["PaymentData"] = null; _httpContext.Session["OrderPaymentInfo"] = null; From fb22049ed517bcf0b2c1809b56a5f8d3b8c68993 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Wed, 22 Jul 2015 16:10:59 +0200 Subject: [PATCH 0102/1074] Placed initialization of DataSegmenter in try catch block and added errors to result log --- .../ExportImport/ImportManager.cs | 258 +++++++++--------- 1 file changed, 132 insertions(+), 126 deletions(-) diff --git a/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs b/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs index 2dd762b398..b48dcf007a 100644 --- a/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs +++ b/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs @@ -152,134 +152,140 @@ public virtual ImportResult ImportProductsFromExcel( using (var scope = new DbContextScope(ctx: _rsProduct.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) { - using (var segmenter = new DataSegmenter(stream)) - { - result.TotalRecords = segmenter.TotalRows; - - while (segmenter.ReadNextBatch() && !cancellationToken.IsCancellationRequested) - { - var batch = segmenter.CurrentBatch; - - // Perf: detach all entities - _rsProduct.Context.DetachAll(); - - // 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"); - } - } + try { + using (var segmenter = new DataSegmenter(stream)) + { + result.TotalRecords = segmenter.TotalRows; + + while (segmenter.ReadNextBatch() && !cancellationToken.IsCancellationRequested) + { + var batch = segmenter.CurrentBatch; + + // Perf: detach all entities + _rsProduct.Context.DetachAll(); + + // 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"); - } - } - - } - } + // =========================================================================== + // 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; From 5e96c4ddfe055da8f79d62e0495ce69e64167dcb Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 22 Jul 2015 16:46:12 +0200 Subject: [PATCH 0103/1074] Minor migration fix --- .../201507202149123_Merge2.Designer.cs | 29 ++++ .../Migrations/201507202149123_Merge2.cs | 16 +++ .../Migrations/201507202149123_Merge2.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 7 + 4 files changed, 178 insertions(+) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.resx diff --git a/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.Designer.cs new file mode 100644 index 0000000000..7bb45d2585 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class Merge2 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(Merge2)); + + string IMigrationMetadata.Id + { + get { return "201507202149123_Merge2"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.cs b/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.cs new file mode 100644 index 0000000000..a26a4dfe70 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.cs @@ -0,0 +1,16 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class Merge2 : DbMigration + { + public override void Up() + { + } + + public override void Down() + { + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.resx b/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.resx new file mode 100644 index 0000000000..19402f07d2 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index ee035dc982..7a713af0ec 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -319,6 +319,10 @@ 201507200832223_SortFilterHomepageProducts.cs + + + 201507202149123_Merge2.cs + @@ -606,6 +610,9 @@ 201507200832223_SortFilterHomepageProducts.cs + + 201507202149123_Merge2.cs + From 269aa5ffda784d0cb78b1629975c3f8919351177 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 22 Jul 2015 20:07:18 +0200 Subject: [PATCH 0104/1074] Minor widget improvements --- .../Extensions/HtmlExtensions.cs | 3 +- .../SmartStore.Web.Framework.csproj | 1 + .../UI/WidgetZoneModel.cs | 13 + .../Controllers/WidgetController.cs | 23 -- .../Models/Cms/RenderWidgetModel.cs | 12 - .../Administration/SmartStore.Admin.csproj | 4 - .../Administration/Views/Home/Index.cshtml | 4 +- .../Shared/EditorTemplates/WidgetZone.cshtml | 290 +++++++++--------- .../Views/Topic/_CreateOrUpdate.cshtml | 2 +- .../Views/Widget/WidgetsByZone.cshtml | 4 - .../Controllers/WidgetController.cs | 4 +- .../Infrastructure/DefaultWidgetSelector.cs | 1 - .../Views/Widget/WidgetsByZone.cshtml | 4 +- 13 files changed, 172 insertions(+), 193 deletions(-) create mode 100644 src/Presentation/SmartStore.Web.Framework/UI/WidgetZoneModel.cs delete mode 100644 src/Presentation/SmartStore.Web/Administration/Models/Cms/RenderWidgetModel.cs delete mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Widget/WidgetsByZone.cshtml diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs index 0b7020875a..433d1804c5 100644 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs @@ -406,7 +406,8 @@ public static MvcHtmlString Widget(this HtmlHelper helper, string widgetZone, ob var widgets = widgetSelector.GetWidgets(widgetZone, model).ToArray(); if (widgets.Any()) { - var result = helper.Action("WidgetsByZone", "Widget", new { widgets = widgets, model = model, area = "" }); + var zoneModel = new WidgetZoneModel { Widgets = widgets, WidgetZone = widgetZone, Model = model }; + var result = helper.Action("WidgetsByZone", "Widget", new { zoneModel = zoneModel, model = model, area = "" }); return result; } } diff --git a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj index cd2f03fa0d..796666721b 100644 --- a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj +++ b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj @@ -332,6 +332,7 @@ + diff --git a/src/Presentation/SmartStore.Web.Framework/UI/WidgetZoneModel.cs b/src/Presentation/SmartStore.Web.Framework/UI/WidgetZoneModel.cs new file mode 100644 index 0000000000..f043fded2f --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/UI/WidgetZoneModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using SmartStore.Web.Framework.Mvc; + +namespace SmartStore.Web.Framework.UI +{ + public class WidgetZoneModel : ModelBase + { + public IEnumerable Widgets { get; set; } + public string WidgetZone { get; set; } + public object Model { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/WidgetController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/WidgetController.cs index f6dd962c6c..e3c54ac30c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/WidgetController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/WidgetController.cs @@ -100,29 +100,6 @@ public ActionResult ActivateProvider(string systemName, bool activate) return RedirectToAction("Providers"); } - - [ChildActionOnly] - public ActionResult WidgetsByZone(string widgetZone) - { - var model = new List(); - - var widgets = _widgetService.LoadActiveWidgetsByWidgetZone(widgetZone); - foreach (var widget in widgets) - { - var widgetModel = new RenderWidgetModel(); - - string actionName; - string controllerName; - RouteValueDictionary routeValues; - widget.Value.GetDisplayWidgetRoute(widgetZone, null, 0, out actionName, out controllerName, out routeValues); - widgetModel.ActionName = actionName; - widgetModel.ControllerName = controllerName; - widgetModel.RouteValues = routeValues; - - model.Add(widgetModel); - } - return PartialView(model); - } #endregion } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Cms/RenderWidgetModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Cms/RenderWidgetModel.cs deleted file mode 100644 index 5591035fc2..0000000000 --- a/src/Presentation/SmartStore.Web/Administration/Models/Cms/RenderWidgetModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Admin.Models.Cms -{ - public class RenderWidgetModel : ModelBase - { - public string ActionName { get; set; } - public string ControllerName { get; set; } - public RouteValueDictionary RouteValues { get; set; } - } -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index fd2aa999ac..c3fc4b644c 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -235,7 +235,6 @@ - @@ -1089,9 +1088,6 @@ - - - diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Home/Index.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Home/Index.cshtml index cc01d61e3e..8842c7648b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Home/Index.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Home/Index.cshtml @@ -11,7 +11,7 @@
    - @Html.Action("WidgetsByZone", "Widget", new { widgetZone = "admin_dashboard_top" }) + @Html.Widget("admin_dashboard_top")
    @@ -39,6 +39,6 @@
    - @Html.Action("WidgetsByZone", "Widget", new { widgetZone = "admin_dashboard_bottom" }) + @Html.Widget("admin_dashboard_bottom")
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/WidgetZone.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/WidgetZone.cshtml index 819aa95a63..5368dd5aa0 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/WidgetZone.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/WidgetZone.cshtml @@ -11,7 +11,7 @@ } } - + @@ -72,3 +73,14 @@
    @@ -121,8 +133,9 @@ }) .ClientEvents(events => events.OnDataBinding("Grid_onDataBinding").OnError("Grid_onError").OnSubmitChanges("Grid_onSubmitChanges")) .Editable(editing => editing.Mode(GridEditMode.InCell)) - .Pageable(settings => settings.PageSize(gridPageSize).Position(GridPagerPosition.Both)) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) ) + From 6bdb32a22b6293b61a62740ffe03925d1d827e15 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 21 Jul 2015 14:29:34 +0200 Subject: [PATCH 0095/1074] Resolves #607 HTML capable full description for payment methods displayed in checkout --- changelog.md | 1 + .../Domain/Payments/PaymentMethod.cs | 9 +- .../Mapping/Payments/PaymentMethodMap.cs | 2 + ...52098_PaymentMethodDescription.Designer.cs | 29 ++++ ...01507210952098_PaymentMethodDescription.cs | 44 ++++++ ...507210952098_PaymentMethodDescription.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 7 + .../Controllers/PaymentController.cs | 37 +++-- .../Models/Payments/PaymentMethodEditModel.cs | 42 +++++- .../Administration/Views/Payment/Edit.cshtml | 20 ++- .../Controllers/CheckoutController.cs | 11 +- .../Checkout/CheckoutPaymentMethodModel.cs | 2 + .../Themes/Alpha/Content/checkout.less | 3 +- .../Themes/Mobile/Content/styles.css | 2 +- .../Checkout/PaymentMethod.Mobile.cshtml | 17 ++- .../Views/Checkout/PaymentMethod.cshtml | 11 +- 16 files changed, 341 insertions(+), 22 deletions(-) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.resx diff --git a/changelog.md b/changelog.md index 69536b51f9..6012ba57f4 100644 --- a/changelog.md +++ b/changelog.md @@ -13,6 +13,7 @@ * #727 Web-API: Option to deactivate TimestampOlderThanLastRequest validation * #731 Web-API: Allow deletion and inserting of product category and manufacturer assignments * #733 Option to set a display order for homepage products +* #607 HTML capable full description for payment methods displayed in checkout ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs index 0567ad5dfe..5b81853884 100644 --- a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs +++ b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs @@ -1,5 +1,6 @@ using System.Runtime.Serialization; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Localization; namespace SmartStore.Core.Domain.Payments { @@ -7,7 +8,7 @@ namespace SmartStore.Core.Domain.Payments /// Represents a payment method /// [DataContract] - public partial class PaymentMethod : BaseEntity + public partial class PaymentMethod : BaseEntity, ILocalizedEntity { /// /// Gets or sets the payment method system name @@ -88,5 +89,11 @@ public AmountRestrictionContextType AmountRestrictionContext this.AmountRestrictionContextId = (int)value; } } + + /// + /// Gets or sets the full description + /// + [DataMember] + public string FullDescription { get; set; } } } diff --git a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs index c009204c13..59821c61a8 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Payments/PaymentMethodMap.cs @@ -19,6 +19,8 @@ public PaymentMethodMap() this.Property(x => x.MinimumOrderAmount).HasPrecision(18, 4); this.Property(x => x.MaximumOrderAmount).HasPrecision(18, 4); + this.Property(x => x.FullDescription).HasMaxLength(4000); + this.Ignore(x => x.CountryExclusionContext); this.Ignore(x => x.AmountRestrictionContext); } diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.Designer.cs new file mode 100644 index 0000000000..4412803c98 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class PaymentMethodDescription : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(PaymentMethodDescription)); + + string IMigrationMetadata.Id + { + get { return "201507210952098_PaymentMethodDescription"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs new file mode 100644 index 0000000000..9cc272131b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs @@ -0,0 +1,44 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class PaymentMethodDescription : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.PaymentMethod", "FullDescription", c => c.String(maxLength: 4000)); + } + + public override void Down() + { + DropColumn("dbo.PaymentMethod", "FullDescription"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.ShortDescription", + "Short description", + "Kurzbeschreibung", + "Specifies a short description of the payment method.", + "Legt eine Kurzbeschreibung der Zahlungsmethode fest."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.FullDescription", + "Full description", + "Langtext", + "Specifies a full description of the payment method. It appears in the payment list in checkout.", + "Legt eine vollstndige Beschreibung der Zahlungsmethode fest. Sie erscheint in der Zahlungsliste im Kassenbereich."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.resx b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.resx new file mode 100644 index 0000000000..04f8e677a2 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 134b800074..487120fe46 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -303,6 +303,10 @@ 201507200832223_SortFilterHomepageProducts.cs + + + 201507210952098_PaymentMethodDescription.cs + @@ -578,6 +582,9 @@ 201507200832223_SortFilterHomepageProducts.cs + + 201507210952098_PaymentMethodDescription.cs + diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs index f0bc5d51cd..e0abb761b8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/PaymentController.cs @@ -14,6 +14,7 @@ using SmartStore.Services.Shipping; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Mvc; using SmartStore.Web.Framework.Plugins; namespace SmartStore.Admin.Controllers @@ -32,6 +33,7 @@ public partial class PaymentController : AdminControllerBase private readonly ICustomerService _customerService; private readonly IShippingService _shippingService; private readonly ICountryService _countryService; + private readonly ILocalizedEntityService _localizedEntityService; #endregion @@ -46,7 +48,8 @@ public PaymentController( ILanguageService languageService, ICustomerService customerService, IShippingService shippingService, - ICountryService countryService) + ICountryService countryService, + ILocalizedEntityService localizedEntityService) { this._services = services; this._paymentService = paymentService; @@ -57,6 +60,7 @@ public PaymentController( this._customerService = customerService; this._shippingService = shippingService; this._countryService = countryService; + this._localizedEntityService = localizedEntityService; } #endregion @@ -102,6 +106,8 @@ private void PreparePaymentMethodEditModel(PaymentMethodEditModel model, Payment model.CountryExclusionContext = paymentMethod.CountryExclusionContext; model.AmountRestrictionContext = paymentMethod.AmountRestrictionContext; + + model.FullDescription = paymentMethod.FullDescription; } } @@ -165,12 +171,23 @@ public ActionResult Edit(string systemName) var provider = _paymentService.LoadPaymentMethodBySystemName(systemName); var paymentMethod = _paymentService.GetPaymentMethodBySystemName(systemName); - var model = _pluginMediator.ToProviderModel(provider, true); + var model = new PaymentMethodEditModel(); + var providerModel = _pluginMediator.ToProviderModel(provider, true); + + model.SystemName = providerModel.SystemName; + model.IconUrl = providerModel.IconUrl; + model.FriendlyName = providerModel.FriendlyName; + model.Description = providerModel.Description; AddLocales(_languageService, model.Locales, (locale, languageId) => { locale.FriendlyName = _pluginMediator.GetLocalizedFriendlyName(provider.Metadata, languageId, false); locale.Description = _pluginMediator.GetLocalizedDescription(provider.Metadata, languageId, false); + + if (paymentMethod != null) + { + locale.FullDescription = paymentMethod.GetLocalized(x => x.FullDescription, languageId, false, false); + } }); PreparePaymentMethodEditModel(model, paymentMethod); @@ -191,12 +208,6 @@ public ActionResult Edit(string systemName, bool continueEditing, PaymentMethodE _pluginMediator.SetSetting(provider.Metadata, "FriendlyName", model.FriendlyName); _pluginMediator.SetSetting(provider.Metadata, "Description", model.Description); - foreach (var localized in model.Locales) - { - _pluginMediator.SaveLocalizedValue(provider.Metadata, localized.LanguageId, "FriendlyName", localized.FriendlyName); - _pluginMediator.SaveLocalizedValue(provider.Metadata, localized.LanguageId, "Description", localized.Description); - } - var paymentMethod = _paymentService.GetPaymentMethodBySystemName(systemName); if (paymentMethod == null) @@ -212,11 +223,21 @@ public ActionResult Edit(string systemName, bool continueEditing, PaymentMethodE paymentMethod.CountryExclusionContext = model.CountryExclusionContext; paymentMethod.AmountRestrictionContext = model.AmountRestrictionContext; + paymentMethod.FullDescription = model.FullDescription; + if (paymentMethod.Id == 0) _paymentService.InsertPaymentMethod(paymentMethod); else _paymentService.UpdatePaymentMethod(paymentMethod); + foreach (var localized in model.Locales) + { + _pluginMediator.SaveLocalizedValue(provider.Metadata, localized.LanguageId, "FriendlyName", localized.FriendlyName); + _pluginMediator.SaveLocalizedValue(provider.Metadata, localized.LanguageId, "Description", localized.Description); + + _localizedEntityService.SaveLocalizedValue(paymentMethod, x => x.FullDescription, localized.FullDescription, localized.LanguageId); + } + NotifySuccess(_services.Localization.GetResource("Admin.Common.DataEditSuccess")); return (continueEditing ? diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs index 12abe357ea..1a84067969 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Payments/PaymentMethodEditModel.cs @@ -2,12 +2,27 @@ using System.Web.Mvc; using SmartStore.Core.Domain.Common; using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Localization; using SmartStore.Web.Framework.Mvc; namespace SmartStore.Admin.Models.Payments { - public class PaymentMethodEditModel : ProviderModel + public class PaymentMethodEditModel : EntityModelBase, ILocalizedModel { + public PaymentMethodEditModel() + { + Locales = new List(); + } + + public IList Locales { get; set; } + public string IconUrl { get; set; } + + [SmartResourceDisplayName("Common.SystemName")] + public string SystemName { get; set; } + + [SmartResourceDisplayName("Common.FriendlyName")] + public string FriendlyName { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.ExcludedCustomerRole")] public string[] ExcludedCustomerRoleIds { get; set; } public List AvailableCustomerRoles { get; set; } @@ -33,5 +48,30 @@ public class PaymentMethodEditModel : ProviderModel [SmartResourceDisplayName("Admin.Configuration.Restrictions.AmountRestrictionContext")] public AmountRestrictionContextType AmountRestrictionContext { get; set; } public List AvailableAmountRestrictionContextTypes { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.ShortDescription")] + [AllowHtml] + public string Description { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.FullDescription")] + [AllowHtml] + public string FullDescription { get; set; } + } + + + public class PaymentMethodLocalizedModel : ILocalizedModelLocal + { + public int LanguageId { get; set; } + + [SmartResourceDisplayName("Common.FriendlyName")] + public string FriendlyName { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.ShortDescription")] + [AllowHtml] + public string Description { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Payment.Methods.FullDescription")] + [AllowHtml] + public string FullDescription { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml index c891471a5d..6151ad6e0d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Payment/Edit.cshtml @@ -35,7 +35,7 @@ @helper TabGeneral() { - @(Html.LocalizedEditor("paymentmethod-general-localized", + @(Html.LocalizedEditor("paymentmethod-general-localized", @ + + + + + + + +
    @@ -55,6 +55,15 @@ @Html.ValidationMessageFor(model => model.Locales[item].Description)
    + @Html.SmartLabelFor(model => model.Locales[item].FullDescription) + + @Html.EditorFor(model => model.Locales[item].FullDescription, Html.RichEditorFlavor()) + @Html.ValidationMessageFor(model => model.Locales[item].FullDescription) +
    @Html.HiddenFor(model => model.Locales[item].LanguageId) @@ -81,6 +90,15 @@ @Html.ValidationMessageFor(model => model.Description)
    + @Html.SmartLabelFor(model => model.FullDescription) + + @Html.EditorFor(x => x.FullDescription, Html.RichEditorFlavor()) + @Html.ValidationMessageFor(model => model.FullDescription) +
    )) } diff --git a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs index 2112acc435..eb18e5bdae 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CheckoutController.cs @@ -282,12 +282,16 @@ protected CheckoutPaymentMethodModel PreparePaymentMethodModel(IList x.PaymentMethodSystemName.IsCaseInsensitiveEqual(pm.Metadata.SystemName)); - var pmModel = new CheckoutPaymentMethodModel.PaymentMethodModel() + var pmModel = new CheckoutPaymentMethodModel.PaymentMethodModel { Name = _pluginMediator.GetLocalizedFriendlyName(pm.Metadata), Description = _pluginMediator.GetLocalizedDescription(pm.Metadata), @@ -295,6 +299,11 @@ protected CheckoutPaymentMethodModel PreparePaymentMethodModel(IList x.FullDescription, _workContext.WorkingLanguage.Id); + } pmModel.BrandUrl = _pluginMediator.GetBrandImageUrl(pm.Metadata); diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentMethodModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentMethodModel.cs index 585658b0ad..8c54334466 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentMethodModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentMethodModel.cs @@ -24,12 +24,14 @@ public partial class PaymentMethodModel : ModelBase public string PaymentMethodSystemName { get; set; } public string Name { get; set; } public string Description { get; set; } + public string FullDescription { get; set; } public string BrandUrl { get; set; } public string Fee { get; set; } public bool Selected { get; set; } public RouteInfo PaymentInfoRoute { get; set; } public bool RequiresInteraction { get; set; } } + #endregion } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/checkout.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/checkout.less index ea2111083c..b826ee8add 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/checkout.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/checkout.less @@ -21,7 +21,8 @@ background-color: #f9f9f9; border-color: #f9f9f9; } - .opt-info { + .opt-info, + .opt-info-item { margin-top: 6px; margin-left: 32px; } diff --git a/src/Presentation/SmartStore.Web/Themes/Mobile/Content/styles.css b/src/Presentation/SmartStore.Web/Themes/Mobile/Content/styles.css index bbc2b1f597..41fe197f5b 100644 --- a/src/Presentation/SmartStore.Web/Themes/Mobile/Content/styles.css +++ b/src/Presentation/SmartStore.Web/Themes/Mobile/Content/styles.css @@ -156,7 +156,7 @@ img { max-width: 100% } .checkout-data .use-reward-points{margin:0;padding:10px;background:#F7F5E8;border:dotted 1px #d3d3d3;} .checkout-data .payment-methods{text-align:left;height:auto;} .checkout-data .payment-methods .payment-method-item{text-align:left;vertical-align:text-top;} -.checkout-data .payment-methods .payment-method-item .payment-method-desc{margin:0 0 14px 46px;} +.checkout-data .payment-methods .payment-method-item .payment-method-description{margin:0 0 15px 15px;} .checkout-data .payment-methods .select-button{text-align:left;} .checkout-data .payment-methods .message-error{text-align:left;} .checkout-data .payment-info{text-align:left;height:auto;} diff --git a/src/Presentation/SmartStore.Web/Views/Checkout/PaymentMethod.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Checkout/PaymentMethod.Mobile.cshtml index 5bc4697448..df97ab4bae 100644 --- a/src/Presentation/SmartStore.Web/Views/Checkout/PaymentMethod.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Checkout/PaymentMethod.Mobile.cshtml @@ -47,13 +47,13 @@ - @if (!String.IsNullOrWhiteSpace(paymentMethod.Description)) - { -
    - @Html.Raw(paymentMethod.Description) -
    - } + @if (paymentMethod.FullDescription.HasValue()) + { +
    + @Html.Raw(paymentMethod.FullDescription) +
    + } @if (!paymentMethod.RequiresInteraction || (paymentMethod.Selected && infoRoute != null)) {
    } - @Html.Action(infoRoute.Action, infoRoute.Controller, infoRoute.RouteValues) + @if (!(paymentMethod.FullDescription.HasValue() && !paymentMethod.RequiresInteraction)) + { + @Html.Action(infoRoute.Action, infoRoute.Controller, infoRoute.RouteValues) + }
    } diff --git a/src/Presentation/SmartStore.Web/Views/Checkout/PaymentMethod.cshtml b/src/Presentation/SmartStore.Web/Views/Checkout/PaymentMethod.cshtml index 0d8df1ae8a..569189379a 100644 --- a/src/Presentation/SmartStore.Web/Views/Checkout/PaymentMethod.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Checkout/PaymentMethod.cshtml @@ -57,6 +57,12 @@ + @if (paymentMethod.FullDescription.HasValue()) + { +
    + @Html.Raw(paymentMethod.FullDescription) +
    + } @if (!paymentMethod.RequiresInteraction || (paymentMethod.Selected && infoRoute != null)) {
    } - @Html.Action(infoRoute.Action, infoRoute.Controller, infoRoute.RouteValues) + @if(!(paymentMethod.FullDescription.HasValue() && !paymentMethod.RequiresInteraction)) + { + @Html.Action(infoRoute.Action, infoRoute.Controller, infoRoute.RouteValues) + }
    } From e2677c6b01b5eaefaec5427463a1c801c6cc3621 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 21 Jul 2015 17:22:48 +0200 Subject: [PATCH 0096/1074] Added headlines to widget zone chooser --- .../Shared/EditorTemplates/WidgetZone.cshtml | 188 +++++++++++++++++- 1 file changed, 178 insertions(+), 10 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/WidgetZone.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/WidgetZone.cshtml index bab1deb472..819aa95a63 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/WidgetZone.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shared/EditorTemplates/WidgetZone.cshtml @@ -23,16 +23,184 @@ } else { zones = [ - "head_html_tag", "body_start_html_tag_after", "header", "left_side_column_before", "left_side_column_after_category_navigation", - "left_side_column_after", "main_column_before", "content_before", "content_after", "main_column_after", "right_side_column_before", - "right_side_column_after", "footer", "body_end_html_tag_before", - "categorydetails_after_breadcrumb", "categorydetails_top", "categorydetails_before_subcategories", "categorydetails_before_featured_products", "categorydetails_after_featured_products", "categorydetails_before_product_list", "categorydetails_bottom", "categorydetails_before_filters", - "productdetails_top", "productdetails_before_pictures", "productdetails_after_pictures", "productdetails_overview_top", "productdetails_overview_bottom", "productdetails_bottom", - "order_summary_content_before", "order_summary_content_deals", "order_summary_content_after", "order_summary_content_totals_left", "order_summary_content_totals_bottom", - "orderdetails_page_aftertotal", - "checkout_billing_address_top", "checkout_billing_address_middle", "checkout_billing_address_bottom", "checkout_shipping_address_top", "checkout_shipping_address_middle", "checkout_shipping_address_bottom", - "checkout_payment_method_top", "checkout_payment_method_bottom", "checkout_shipping_method_top", "checkout_shipping_method_bottom", "checkout_payment_info_top", "checkout_payment_info_bottom", "checkout_confirm_top", "checkout_confirm_before_summary", "checkout_confirm_bottom", "checkout_completed_top", "checkout_completed_bottom", "checkout_progress_before", "checkout_progress_after", - "contactus_top", "contactus_bottom", "home_page_top", "home_page_bottom", "mini_shopping_cart_bottom" + { + text: "@T("Admin.ContentManagement.Blog")", children: [ + { id: 0, text: 'blogpost_page_before_body' }, + { id: 1, text: 'blogpost_page_before_comments' }, + { id: 2, text: 'blogpost_page_inside_comment' }, + { id: 3, text: 'blogpost_page_after_comments' }, + { id: 4, text: 'bloglist_page_before_posts' }, + { id: 5, text: 'bloglist_page_inside_post' }, + { id: 6, text: 'bloglist_page_after_posts' } + ] + }, + { + text: "@T("Admin.Catalog.Categories")", children: [ + { id: 7, text: 'categorydetails_after_breadcrumb' }, + { id: 8, text: 'categorydetails_top' }, + { id: 9, text: 'categorydetails_before_subcategories' }, + { id: 10, text: 'categorydetails_before_featured_products' }, + { id: 11, text: 'categorydetails_after_featured_products' }, + { id: 12, text: 'categorydetails_before_product_list' }, + { id: 13, text: 'categorydetails_bottom' }, + { id: 14, text: 'categorydetails_before_filters' } + ] + }, + { + text: "@T("Admin.Catalog.Products")", children: [ + { id: 15, text: 'productbox_add_info' }, + { id: 16, text: 'productsbytag_before_product_list' }, + { id: 17, text: 'productreviews_page_inside_review' }, + { id: 18, text: 'productdetails_overview_top' }, + { id: 19, text: 'productdetails_overview_bottom' }, + { id: 20, text: 'productsbytag_top' }, + { id: 21, text: 'productsbytag_bottom' }, + { id: 22, text: 'productdetails_add_info' }, + { id: 23, text: 'productdetails_top' }, + { id: 24, text: 'productdetails_before_pictures' }, + { id: 25, text: 'productdetails_after_pictures' }, + { id: 26, text: 'productdetails_bottom' } + ] + }, + { + text: "Navigation", children: [ + { id: 27, text: 'productbreadcrumb_before' }, + { id: 28, text: 'productbreadcrumb_after' }, + { id: 29, text: 'header_menu_before' }, + { id: 30, text: 'header_menu_after' }, + { id: 31, text: 'megamenu_before_first_item' }, + { id: 32, text: 'megamenu_after_last_item' }, + { id: 33, text: 'account_dropdown_before' }, + { id: 34, text: 'account_dropdown_after' }, + { id: 35, text: 'header_links_before' }, + { id: 36, text: 'header_links_after' }, + { id: 37, text: 'infoblock_before' }, + { id: 38, text: 'infoblock_after' }, + { id: 39, text: 'account_navigation_before' }, + { id: 40, text: 'account_navigation_after' }, + ] + }, + { + text: "PDF", children: [ + { id: 41, text: 'invoice_footer_before' }, + { id: 42, text: 'invoice_footer_after' }, + { id: 43, text: 'invoice_header_before' }, + { id: 44, text: 'invoice_header_right' }, + { id: 45, text: 'invoice_header_after' }, + { id: 46, text: 'invoice_top' }, + { id: 47, text: 'invoice_orderinfo_top' }, + { id: 48, text: 'invoice_orderinfotable_after' }, + { id: 49, text: 'invoice_orderinfo_bottom' }, + { id: 50, text: 'invoice_lines_before' }, + { id: 51, text: 'invoice_checkoutattributes_before' }, + { id: 52, text: 'invoice_ordertotals_before' }, + { id: 53, text: 'invoice_ordernotes_before' }, + { id: 54, text: 'invoice_bottom' }, + { id: 55, text: 'pdfcatalog_cover_top' }, + { id: 56, text: 'pdfcatalog_cover_logo_after' }, + { id: 57, text: 'pdfcatalog_cover_storename_after' }, + { id: 58, text: 'pdfcatalog_productdetail_top' }, + { id: 59, text: 'pdfcatalog_productdetail_fulldescription_before' }, + { id: 60, text: 'pdfcatalog_productdetail_picture_before' }, + { id: 61, text: 'pdfcatalog_productdetail_specificationattributes_before' }, + { id: 62, text: 'pdfcatalog_productdetail_bundleditems_before' }, + { id: 63, text: 'pdfcatalog_productdetail_associatedproducts_before' } + ] + }, + { + text: "@T("Admin.Catalog.Manufacturers")", children: [ + { id: 64, text: 'manufacturerdetails_top' }, + { id: 65, text: 'manufacturerdetails_before_featured_products' }, + { id: 66, text: 'manufacturerdetails_after_featured_products' }, + { id: 67, text: 'manufacturerdetails_before_filters' }, + { id: 68, text: 'manufacturerdetails_before_product_list' }, + { id: 69, text: 'manufacturerdetails_bottom' } + ] + }, + { + text: "@T("Common.Misc")", children: [ + { id: 70, text: 'compareproducts_row' }, + { id: 71, text: 'productsearch_page_advanced' }, + { id: 72, text: 'productsearch_page_basic' }, + { id: 73, text: 'productsearch_page_advanced' }, + { id: 74, text: 'searchbox' }, + { id: 75, text: 'footer' }, + { id: 76, text: 'contactus_top' }, + { id: 77, text: 'contactus_bottom' }, + { id: 78, text: 'productreviews_page_top' }, + { id: 79, text: 'productreviews_page_inside_review' }, + { id: 80, text: 'productreviews_page_bottom' }, + { id: 81, text: 'profile_page_info_userdetails' }, + { id: 82, text: 'profile_page_info_userstats' }, + { id: 83, text: 'notifications' }, + { id: 84, text: 'shipmentdetails_top' }, + { id: 85, text: 'shipmentdetails_orderinfo_top' }, + { id: 86, text: 'shipmentdetails_orderinfotable_after' }, + { id: 87, text: 'shipmentdetails_orderinfo_bottom' }, + { id: 88, text: 'shipmentdetails_lines_before' } + ] + }, + { + text: "Global", children: [ + { id: 89, text: 'home_page_top' }, + { id: 90, text: 'home_page_bottom' }, + { id: 91, text: 'main_column_before' }, + { id: 92, text: 'main_column_after' }, + { id: 93, text: 'left_side_column_before' }, + { id: 94, text: 'left_side_column_after_category_navigation' }, + { id: 95, text: 'left_side_column_after_manufacturer_navigation' }, + { id: 96, text: 'left_side_column_after_tags' }, + { id: 97, text: 'left_side_column_after_info' }, + { id: 98, text: 'left_side_column_after_poll' }, + { id: 99, text: 'left_side_column_after' }, + { id: 100, text: 'right_side_column_before' }, + { id: 101, text: 'right_side_column_after_recentlyviewed' }, + { id: 102, text: 'right_side_column_after_poll' }, + { id: 103, text: 'right_side_column_after' }, + { id: 104, text: 'body_start_html_tag_after' }, + { id: 105, text: 'content_before' }, + { id: 106, text: 'content_after' }, + { id: 107, text: 'body_end_html_tag_before' }, + { id: 108, text: 'head_html_tag' }, + { id: 109, text: 'admin_navbar_before' }, + { id: 110, text: 'admin_navbar_after' }, + { id: 111, text: 'admin_breadcrumb' }, + { id: 112, text: 'admin_content_before' }, + { id: 113, text: 'admin_content_after' }, + { id: 114, text: 'admin_menu_before' } + ] + }, + { + text: "@T("Admin.ContentManagement.News")", children: [ + { id: 115, text: 'newslist_page_before_items' }, + { id: 116, text: 'newslist_page_inside_item' }, + { id: 117, text: 'newslist_page_after_items' }, + { id: 118, text: 'newsitem_page_before_body' }, + { id: 119, text: 'newsitem_page_before_comments' }, + { id: 120, text: 'newsitem_page_inside_comment' }, + { id: 121, text: 'newsitem_page_after_comments' } + ] + }, + { + text: "@T("Admin.Orders")", children: [ + { id: 122, text: 'orderdetails_page_top' }, + { id: 123, text: 'orderdetails_page_overview' }, + { id: 124, text: 'orderdetails_page_beforeproducts' }, + { id: 125, text: 'orderdetails_page_afterproducts' }, + { id: 126, text: 'orderdetails_page_aftertotal' }, + { id: 127, text: 'orderdetails_page_bottom' } + ] + }, + { + text: "@T("Shoppingcart")", children: [ + { id: 128, text: 'mini_shopping_cart_bottom' }, + { id: 129, text: 'order_summary_content_before' }, + { id: 130, text: 'order_summary_content_totals_left' }, + { id: 131, text: 'order_summary_content_deals' }, + { id: 132, text: 'order_summary_content_totals_bottom' }, + { id: 133, text: 'order_summary_content_after' } + ] + } ]; } From f3e8bb80621cfe48b48f47757e04a44473b0ee92 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 21 Jul 2015 20:17:43 +0200 Subject: [PATCH 0097/1074] Resolves #715 HTML editor for shipping method description --- .../Views/Shipping/_CreateOrUpdateMethod.cshtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml index 9163a2f8db..3639eef59c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/_CreateOrUpdateMethod.cshtml @@ -30,7 +30,7 @@ @Html.SmartLabelFor(model => model.Locales[item].Description)
    - @Html.TextAreaFor(model => model.Locales[item].Description) + @Html.EditorFor(model => model.Locales[item].Description, Html.RichEditorFlavor()) @Html.ValidationMessageFor(model => model.Locales[item].Description)
    - @Html.TextAreaFor(model => model.Description) + @Html.EditorFor(model => model.Description, Html.RichEditorFlavor()) @Html.ValidationMessageFor(model => model.Description)
    + + diff --git a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs index bcaaadd658..eef3ac94e0 100644 --- a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs @@ -3,29 +3,32 @@ using System.Linq; using System.Web; using System.Web.Mvc; +using System.Web.SessionState; using SmartStore.Core.Domain.Tasks; using SmartStore.Services.Tasks; using SmartStore.Web.Framework.Controllers; using SmartStore.Services.Security; using SmartStore.Services; + namespace SmartStore.Web.Controllers { - + + [SessionState(SessionStateBehavior.ReadOnly)] public class TaskSchedulerController : Controller { - private readonly ITaskSweeper _taskSweeper; + private readonly ITaskScheduler _taskScheduler; private readonly IScheduleTaskService _scheduledTaskService; private readonly ITaskExecutor _taskExecutor; private readonly ICommonServices _services; public TaskSchedulerController( - ITaskSweeper taskSweeper, + ITaskScheduler taskScheduler, IScheduleTaskService scheduledTaskService, ITaskExecutor taskExecutor, ICommonServices services) { - this._taskSweeper = taskSweeper; + this._taskScheduler = taskScheduler; this._scheduledTaskService = scheduledTaskService; this._taskExecutor = taskExecutor; this._services = services; @@ -34,23 +37,41 @@ public TaskSchedulerController( [HttpPost] public ActionResult Sweep() { - if (!_taskSweeper.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) + if (!_taskScheduler.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) return new HttpUnauthorizedResult(); var pendingTasks = _scheduledTaskService.GetPendingTasks(); + var prevTaskStart = DateTime.UtcNow; + var count = 0; foreach (var task in pendingTasks) { - _taskExecutor.Execute(task); + var elapsedSincePrevTask = DateTime.UtcNow - prevTaskStart; + if (elapsedSincePrevTask >= _taskScheduler.SweepInterval) + { + // the previous Task execution in this loop took longer + // than the scheduler's sweep interval. Most likely a subsequent + // Sweep call executed it already in another HTTP request. + // To be able to determine this, we need to reload the entity from the database. + // The TaskExecutor will exit when the task should be in running state then. + _services.DbContext.ReloadEntity(task); + } + + if (task.IsPending) + { + prevTaskStart = DateTime.UtcNow; + _taskExecutor.Execute(task); + count++; + } } - return Content("{0} tasks executed".FormatInvariant(pendingTasks.Count)); + return Content("{0} tasks executed".FormatInvariant(count)); } [HttpPost] public ActionResult Execute(int id /* taskId */) { - if (!_taskSweeper.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) + if (!_taskScheduler.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) return new HttpUnauthorizedResult(); var task = _scheduledTaskService.GetTaskById(id); From 3c586efde97f3e33dc4b50fd50bda2bc7acc1628 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 24 Jul 2015 03:31:11 +0200 Subject: [PATCH 0113/1074] WebScheduler 7 --- src/Libraries/SmartStore.Core/Async/AsyncState.cs | 8 ++++++-- .../SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Async/AsyncState.cs b/src/Libraries/SmartStore.Core/Async/AsyncState.cs index 6ecbb7959a..64d4e91e14 100644 --- a/src/Libraries/SmartStore.Core/Async/AsyncState.cs +++ b/src/Libraries/SmartStore.Core/Async/AsyncState.cs @@ -76,6 +76,7 @@ private T Get(out CancellationTokenSource cancelTokenSource, string name = nu public void Set(T state, string name = null, bool neverExpires = false) { + Guard.ArgumentNotNull(() => state); this.Set(state, null, name, neverExpires); } @@ -112,14 +113,17 @@ private void Set(T state, CancellationTokenSource cancelTokenSource, string n if (value != null) { // exists already, so update - value.Progress = state; + if (state != null) + { + value.Progress = state; + } if (cancelTokenSource != null && value.CancellationTokenSource == null) { value.CancellationTokenSource = cancelTokenSource; } } - var policy = new CacheItemPolicy { SlidingExpiration = neverExpires ? TimeSpan.FromHours(24) : TimeSpan.FromMinutes(15) }; + var policy = new CacheItemPolicy { SlidingExpiration = neverExpires ? TimeSpan.Zero : TimeSpan.FromMinutes(15) }; _cache.Set( key, diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs index 872ff47290..b16a8aa604 100644 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs @@ -395,7 +395,7 @@ public void StartCreatingFeeds(Func createFeed, s stores.AddRange(storeService.GetAllStores()); } - var context = new FeedFileCreationContext() + var context = new FeedFileCreationContext { StoreCount = stores.Count, Progress = new Progress(x => From 4e6cc3ce4da417ad79360ca0c5a9246e54c0f01a Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 24 Jul 2015 15:06:00 +0200 Subject: [PATCH 0114/1074] Resolves #732 Product list: Option to display the pre-selected price instead of the lowest price --- .../Domain/Catalog/CatalogSettings.cs | 5 + .../Domain/Catalog/PriceDisplayType.cs | 29 ++ .../SmartStore.Core/SmartStore.Core.csproj | 1 + ...01507210952098_PaymentMethodDescription.cs | 22 ++ .../Catalog/IPriceCalculationService.cs | 3 +- .../Catalog/PriceCalculationService.cs | 184 +++-------- .../Controllers/OData/ProductsController.cs | 2 +- .../Controllers/SettingController.cs | 1 + .../Infrastructure/AutoMapperStartupTask.cs | 1 + .../Models/Settings/CatalogSettingsModel.cs | 4 + .../Views/Setting/Catalog.cshtml | 12 +- .../Controllers/CatalogHelper.cs | 299 ++++++++---------- 12 files changed, 255 insertions(+), 308 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/Catalog/PriceDisplayType.cs diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs index dd7d67edea..979fa85969 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs @@ -353,6 +353,11 @@ public CatalogSettings() ///
    public string DefaultPageSizeOptions { get; set; } + /// + /// Gets or sets the price display type for prices in product lists + /// + public PriceDisplayType PriceDisplayType { get; set; } + /// /// Gets or sets a value indicating whether to include "Short description" in compare products /// diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/PriceDisplayType.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/PriceDisplayType.cs new file mode 100644 index 0000000000..aeb4c24250 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/PriceDisplayType.cs @@ -0,0 +1,29 @@ + +namespace SmartStore.Core.Domain.Catalog +{ + /// + /// Represents types of product prices to display + /// + public enum PriceDisplayType + { + /// + /// The lowest possible price of a product (default) + /// + LowestPrice = 0, + + /// + /// The product price initially displayed on the product detail page + /// + PreSelectedPrice = 10, + + /// + /// The product price without associated data like discounts, tier prices, attributes or attribute combinations + /// + PriceWithoutDiscountsAndAttributes = 20, + + /// + /// Do not display a product price + /// + Hide = 30 + } +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 6035969f75..24da2a6e8d 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -157,6 +157,7 @@ + diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs index 9cc272131b..75e57c5d4b 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs @@ -39,6 +39,28 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Langtext", "Specifies a full description of the payment method. It appears in the payment list in checkout.", "Legt eine vollstndige Beschreibung der Zahlungsmethode fest. Sie erscheint in der Zahlungsliste im Kassenbereich."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.PriceDisplayType", + "Price display", + "Preisanzeige", + "Specifies whether or what type of price to be displayed in product lists.", + "Legt fest, ob bzw. welcher Typ von Preis in Produktlisten angezeigt werden soll."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.LowestPrice", + "Minimum feasible price", + "Minimal realisierbarer Preis"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.PreSelectedPrice", + "Preselected price", + "Vorgewhlter Preis"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.PriceWithoutDiscountsAndAttributes", + "Price without discounts and attributes", + "Preis ohne Rabatte und Attribute"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.Hide", + "No price indication", + "Keine Preisanzeige"); } } } diff --git a/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs index e2004625fd..3ae7d2bb7e 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs @@ -92,9 +92,10 @@ decimal GetFinalPrice(Product product, IEnumerable bundle /// Get the lowest possible price for a product. ///
    /// Product + /// Object with cargo data for better performance /// Whether to display the from message. /// The lowest price. - decimal GetLowestPrice(Product product, out bool displayFromMessage); + decimal GetLowestPrice(Product product, PriceCalculationContext context, out bool displayFromMessage); /// /// Get the lowest price of a grouped product. diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index e7be1e33d7..0c965dceb1 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -243,104 +243,13 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC return result; } - //protected virtual decimal GetPreselectedPriceOld(Product product, ProductBundleItemData bundleItem, IList bundleItems) - //{ - // var taxRate = decimal.Zero; - // var attributesTotalPriceBase = decimal.Zero; - // var preSelectedPriceAdjustmentBase = decimal.Zero; - // var isBundle = (product.ProductType == ProductType.BundledProduct); - // var isBundleItemPricing = (bundleItem != null && bundleItem.Item.BundleProduct.BundlePerItemPricing); - // var isBundlePricing = (bundleItem != null && !bundleItem.Item.BundleProduct.BundlePerItemPricing); - // var bundleItemId = (bundleItem == null ? 0 : bundleItem.Item.Id); - // var attributes = (isBundle ? new List() : _productAttributeService.GetProductVariantAttributesByProductId(product.Id)); - // var selectedAttributes = new NameValueCollection(); - // List selectedAttributeValues = null; - - // foreach (var attribute in attributes) - // { - // int preSelectedValueId = 0; - // ProductVariantAttributeValue defaultValue = null; - - // if (attribute.ShouldHaveValues()) - // { - // var pvaValues = _productAttributeService.GetProductVariantAttributeValues(attribute.Id); - // if (pvaValues.Count == 0) - // continue; - - // foreach (var pvaValue in pvaValues) - // { - // ProductBundleItemAttributeFilter attributeFilter = null; - - // if (bundleItem.FilterOut(pvaValue, out attributeFilter)) - // continue; - - // if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected) - // preSelectedValueId = attributeFilter.AttributeValueId; - - // if (!isBundlePricing && pvaValue.IsPreSelected) - // { - // decimal attributeValuePriceAdjustment = GetProductVariantAttributeValuePriceAdjustment(pvaValue); - // decimal priceAdjustmentBase = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, out taxRate); - - // preSelectedPriceAdjustmentBase = decimal.Add(preSelectedPriceAdjustmentBase, priceAdjustmentBase); - // } - // } - - // // value pre-selected by a bundle item filter discards the default pre-selection - // if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null) - // defaultValue.IsPreSelected = true; - - // if (defaultValue == null) - // defaultValue = pvaValues.FirstOrDefault(x => x.IsPreSelected); - - // if (defaultValue == null && attribute.IsRequired) - // defaultValue = pvaValues.First(); - - // if (defaultValue != null) - // selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId); - // } - // } - - // if (!isBundle && selectedAttributes.Count > 0) - // { - // string attributeXml = selectedAttributes.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _services.Localization, - // _downloadService, _catalogSettings, _httpRequestBase, new List(), true, bundleItemId); - - // selectedAttributeValues = _productAttributeParser.ParseProductVariantAttributeValues(attributeXml).ToList(); - - // var combinations = _productAttributeService.GetAllProductVariantAttributeCombinations(product.Id); - - // var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml)); - - // if (selectedCombination != null && selectedCombination.IsActive) - // product.MergeWithCombination(selectedCombination); - // } - - // if (_catalogSettings.EnableDynamicPriceUpdate && !isBundlePricing) - // { - // if (selectedAttributeValues != null) - // { - // selectedAttributeValues.Each(x => attributesTotalPriceBase += GetProductVariantAttributeValuePriceAdjustment(x)); - // } - // else - // { - // attributesTotalPriceBase = preSelectedPriceAdjustmentBase; - // } - // } - - // if (bundleItem != null) - // { - // bundleItem.AdditionalCharge = attributesTotalPriceBase; - // } - - // var result = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, attributesTotalPriceBase, true, 1, bundleItem); - // return result; - //} - public virtual PriceCalculationContext CreatePriceCalculationContext(IEnumerable productIds = null) { var context = new PriceCalculationContext(); + if (_catalogSettings.PriceDisplayType == PriceDisplayType.Hide || _catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes) + return context; + context.Attributes = new LazyMultimap(x => { "load {0}".FormatInvariant(string.Join(";", x)).Dump(); @@ -349,11 +258,14 @@ public virtual PriceCalculationContext CreatePriceCalculationContext(IEnumerable return result; }, productIds); - context.AttributeCombinations = new LazyMultimap(x => + if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice) { - var result = _productAttributeService.GetProductVariantAttributeCombinations(x); - return result; - }, productIds); + context.AttributeCombinations = new LazyMultimap(x => + { + var result = _productAttributeService.GetProductVariantAttributeCombinations(x); + return result; + }, productIds); + } return context; } @@ -527,9 +439,10 @@ public virtual decimal GetFinalPrice( /// Get the lowest possible price for a product. /// /// Product + /// Object with cargo data for better performance /// Whether to display the from message. /// The lowest price. - public virtual decimal GetLowestPrice(Product product, out bool displayFromMessage) + public virtual decimal GetLowestPrice(Product product, PriceCalculationContext context, out bool displayFromMessage) { if (product == null) throw new ArgumentNullException("product"); @@ -537,38 +450,16 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa if (product.ProductType == ProductType.GroupedProduct) throw Error.InvalidOperation("Choose the other override for products of type grouped product."); - displayFromMessage = false; + if (context == null) + context = CreatePriceCalculationContext(null); - IList bundleItems = null; bool isBundlePerItemPricing = (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing); - if (isBundlePerItemPricing) - { - bundleItems = _productService.GetBundleItems(product.Id); + displayFromMessage = isBundlePerItemPricing; - // sepcial case: one bundle item with one attribute and one attribute value and one attribute combination - if (bundleItems.Count == 1) - { - var firstBundleItem = bundleItems.First(); - if (firstBundleItem.Item.Product.ProductVariantAttributes.Count == 1) - { - var firstAttribute = firstBundleItem.Item.Product.ProductVariantAttributes.First(); - if (firstAttribute.ProductVariantAttributeValues.Count == 1) - { - var firstAttributeValue = firstAttribute.ProductVariantAttributeValues.First(); - firstBundleItem.AdditionalCharge = firstAttributeValue.PriceAdjustment; - - var combinations = _productAttributeService.GetAllProductVariantAttributeCombinations(firstBundleItem.Item.ProductId); - if (combinations.Count == 1) - { - firstBundleItem.Item.Product.MergeWithCombination(combinations.First()); - } - } - } - } - } + // TODO(?): attribute price adjustments were not regarded here cause of performance - decimal lowestPrice = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); + decimal lowestPrice = GetFinalPrice(product, null, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); if (product.LowestAttributeCombinationPrice.HasValue && product.LowestAttributeCombinationPrice.Value < lowestPrice) { @@ -581,6 +472,24 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa lowestPrice = product.LowestAttributeCombinationPrice ?? decimal.Zero; } + if (!displayFromMessage && product.ProductType != ProductType.BundledProduct) + { + var attributes = context.Attributes.Ensure(product.Id); + displayFromMessage = attributes.Any(x => x.ProductVariantAttributeValues.Any(y => y.PriceAdjustment != decimal.Zero)); + } + + if (!displayFromMessage && product.HasTierPrices && !isBundlePerItemPricing) + { + var tierPrices = product.TierPrices + .OrderBy(tp => tp.Quantity) + .FilterByStore(_services.StoreContext.CurrentStore.Id) + .FilterForCustomer(_services.WorkContext.CurrentCustomer) + .ToList() + .RemoveDuplicatedQuantities(); + + displayFromMessage = (tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices.First().Quantity <= 1)); + } + return lowestPrice; } @@ -602,7 +511,7 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa if (product.ProductType != ProductType.GroupedProduct) throw Error.InvalidOperation("Choose the other override for products not of type grouped product."); - lowestPriceProduct = product; + lowestPriceProduct = null; decimal? lowestPrice = null; foreach (var associatedProduct in associatedProducts) @@ -620,6 +529,10 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa lowestPriceProduct = associatedProduct; } } + + if (lowestPriceProduct == null) + lowestPriceProduct = associatedProducts.FirstOrDefault(); + return lowestPrice; } @@ -660,23 +573,6 @@ public virtual decimal GetPreselectedPrice(Product product, PriceCalculationCont result = GetPreselectedPrice(product, context, null, null); } - //if (product.ProductType == ProductType.BundledProduct) - //{ - // var bundleItems = _productService.GetBundleItems(product.Id); - - // foreach (var bundleItem in bundleItems.Where(x => x.Item.Product.CanBeBundleItem())) - // { - // // fetch bundleItems.AdditionalCharge for all bundle items - // var unused = GetPreselectedPriceOld(bundleItem.Item.Product, bundleItem, bundleItems); - // } - - // result = GetPreselectedPriceOld(product, null, bundleItems); - //} - //else - //{ - // result = GetPreselectedPriceOld(product, null, null); - //} - return result; } diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs index 24347a2f31..aec30f45cd 100644 --- a/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs @@ -266,7 +266,7 @@ public IQueryable GetProductBundleItems(int key) else { bool displayFromMessage; - result = _priceCalculationService.Value.GetLowestPrice(entity, out displayFromMessage); + result = _priceCalculationService.Value.GetLowestPrice(entity, null, out displayFromMessage); } } else diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs index 355f948bac..8f13a6c95a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs @@ -558,6 +558,7 @@ public ActionResult Catalog() StoreDependingSettings.GetOverrideKeys(catalogSettings, model, storeScope, _services.Settings); model.AvailableSubCategoryDisplayTypes = catalogSettings.SubCategoryDisplayType.ToSelectList(); + model.AvailablePriceDisplayTypes = catalogSettings.PriceDisplayType.ToSelectList(); model.AvailableDefaultViewModes.Add( new SelectListItem { Value = "grid", Text = _services.Localization.GetResource("Common.Grid"), Selected = model.DefaultViewMode.IsCaseInsensitiveEqual("grid") } diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index 35c6c808e1..40fd048a32 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -618,6 +618,7 @@ public void Execute() .ForMember(dest => dest.ReturnValidOptionsIfThereAreAny, mo => mo.Ignore()); Mapper.CreateMap() .ForMember(dest => dest.AvailableSubCategoryDisplayTypes, mo => mo.Ignore()) + .ForMember(dest => dest.AvailablePriceDisplayTypes, mo => mo.Ignore()) .ForMember(dest => dest.AvailableDefaultViewModes, mo => mo.Ignore()) .ForMember(dest => dest.AvailableDeliveryTimes, mo => mo.Ignore()); Mapper.CreateMap() diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/CatalogSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/CatalogSettingsModel.cs index ba76a185ea..46de364573 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/CatalogSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/CatalogSettingsModel.cs @@ -115,6 +115,10 @@ public CatalogSettingsModel() [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.DefaultPageSizeOptions")] public string DefaultPageSizeOptions { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.PriceDisplayType")] + public PriceDisplayType PriceDisplayType { get; set; } + public SelectList AvailablePriceDisplayTypes { get; set; } + #endregion #region Products diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml index a55ae23614..33f3b5ea30 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml @@ -163,8 +163,8 @@ { x.Add().Text(T("Admin.Configuration.Settings.Catalog.MiscSettings").Text).Content(@TabMiscSettings()).Selected(true); x.Add().Text(T("Admin.Configuration.Settings.Catalog.ProductListSettings").Text).Content(@TabProductListSettings()); - x.Add().Text(T("Admin.Configuration.Settings.Catalog.UserSettings").Text).Content(@TabUserSettings()); x.Add().Text(T("Admin.Configuration.Settings.Catalog.ProductDetailSettings").Text).Content(@TabProductDetailSettings()); + x.Add().Text(T("Admin.Configuration.Settings.Catalog.UserSettings").Text).Content(@TabUserSettings()); x.Add().Text(T("Admin.Configuration.Settings.Catalog.ProductSearchSettings").Text).Content(@TabProductSearchSettings()); })) @@ -453,6 +453,16 @@ @Html.ValidationMessageFor(model => model.DefaultPageSizeOptions) + + + @Html.SmartLabelFor(model => model.PriceDisplayType) + + + @Html.SettingOverrideCheckbox(model => Model.PriceDisplayType) + @Html.DropDownListFor(model => model.PriceDisplayType, Model.AvailablePriceDisplayTypes) + @Html.ValidationMessageFor(model => model.PriceDisplayType) + + diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index 2c76aa8069..16e7022c43 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -985,14 +985,18 @@ public IEnumerable PrepareProductOverviewModels( throw new ArgumentNullException("products"); // PERF!! + var currentStore = _services.StoreContext.CurrentStore; + var currentCustomer = _services.WorkContext.CurrentCustomer; + var workingCurrency = _services.WorkContext.WorkingCurrency; var displayPrices = _services.Permissions.Authorize(StandardPermissionProvider.DisplayPrices); var enableShoppingCart = _services.Permissions.Authorize(StandardPermissionProvider.EnableShoppingCart); var enableWishlist = _services.Permissions.Authorize(StandardPermissionProvider.EnableWishlist); - var currentCustomer = _services.WorkContext.CurrentCustomer; - var taxDisplayType = _services.WorkContext.GetTaxDisplayTypeFor(currentCustomer, _services.StoreContext.CurrentStore.Id); + var taxDisplayType = _services.WorkContext.GetTaxDisplayTypeFor(currentCustomer, currentStore.Id); string taxInfo = T(taxDisplayType == TaxDisplayType.IncludingTax ? "Tax.InclVAT" : "Tax.ExclVAT"); string shippingInfoLink = _urlHelper.RouteUrl("Topic", new { SystemName = "shippinginfo" }); var cachedManufacturerModels = new Dictionary(); + PriceCalculationContext priceCalculationContext = null; + var res = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "Products.CallForPrice", T("Products.CallForPrice") }, @@ -1004,14 +1008,13 @@ public IEnumerable PrepareProductOverviewModels( { "Common.AdditionalShippingSurcharge", T("Common.AdditionalShippingSurcharge") } }; - int[] productIds = products.Select(x => x.Id).ToArray(); - IList productIdsWithPriceAdjustments = null; + int[] productIds = products.Select(x => x.Id).ToArray(); var models = new List(); foreach (var product in products) { - var minPriceProduct = product; + var contextProduct = product; var model = new ProductOverviewModel { @@ -1026,181 +1029,156 @@ public IEnumerable PrepareProductOverviewModels( { #region Prepare product price + if (priceCalculationContext == null) + priceCalculationContext = _priceCalculationService.CreatePriceCalculationContext(productIds); + var priceModel = new ProductOverviewModel.ProductPriceModel { ForceRedirectionAfterAddingToCart = forceRedirectionAfterAddingToCart, ShowDiscountSign = _catalogSettings.ShowDiscountSign }; - switch (product.ProductType) + if (product.ProductType == ProductType.GroupedProduct) { - case ProductType.GroupedProduct: - { - #region Grouped product + #region Grouped product - var searchContext = new ProductSearchContext - { - StoreId = _services.StoreContext.CurrentStore.Id, - ParentGroupedProductId = product.Id, - PageSize = int.MaxValue, - VisibleIndividuallyOnly = false - }; + priceModel.DisableBuyButton = true; + priceModel.DisableWishListButton = true; + priceModel.AvailableForPreOrder = false; - var associatedProducts = _productService.SearchProducts(searchContext); + var searchContext = new ProductSearchContext + { + StoreId = currentStore.Id, + ParentGroupedProductId = product.Id, + PageSize = int.MaxValue, + VisibleIndividuallyOnly = false + }; - if (associatedProducts.Count <= 0) + var associatedProducts = _productService.SearchProducts(searchContext); + + if (associatedProducts.Count > 0) + { + contextProduct = associatedProducts.First(); + + if (displayPrices && _catalogSettings.PriceDisplayType != PriceDisplayType.Hide) + { + decimal? displayPrice = null; + + if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice) { - priceModel.OldPrice = null; - priceModel.Price = null; - priceModel.DisableBuyButton = true; - priceModel.DisableWishListButton = true; - priceModel.AvailableForPreOrder = false; + displayPrice = _priceCalculationService.GetPreselectedPrice(contextProduct, null); + } + else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes) + { + displayPrice = _priceCalculationService.GetFinalPrice(contextProduct, null, currentCustomer, decimal.Zero, false, 1, null); } else { - priceModel.DisableBuyButton = true; - priceModel.DisableWishListButton = true; - priceModel.AvailableForPreOrder = false; + displayPrice = _priceCalculationService.GetLowestPrice(product, associatedProducts, out contextProduct); + } - if (displayPrices) + if (contextProduct != null && !contextProduct.CustomerEntersPrice) + { + if (contextProduct.CallForPrice) { - decimal? minPossiblePrice = _priceCalculationService.GetLowestPrice(product, associatedProducts, out minPriceProduct); - - if (minPriceProduct != null && !minPriceProduct.CustomerEntersPrice) - { - if (minPriceProduct.CallForPrice) - { - priceModel.OldPrice = null; - priceModel.Price = res["Products.CallForPrice"]; - } - else if (minPossiblePrice.HasValue) - { - //calculate prices - decimal taxRate = decimal.Zero; - decimal oldPriceBase = _taxService.GetProductPrice(minPriceProduct, minPriceProduct.OldPrice, out taxRate); - decimal finalPriceBase = _taxService.GetProductPrice(minPriceProduct, minPossiblePrice.Value, out taxRate); - decimal finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, _services.WorkContext.WorkingCurrency); - - priceModel.OldPrice = null; - priceModel.Price = String.Format(res["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice)); - priceModel.HasDiscount = finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero; - } - else - { - //Actually it's not possible (we presume that minimalPrice always has a value) - //We never should get here - Debug.WriteLine(string.Format("Cannot calculate minPrice for product #{0}", product.Id)); - } - } + priceModel.OldPrice = null; + priceModel.Price = res["Products.CallForPrice"]; } - else + else if (displayPrice.HasValue) { - //hide prices + //calculate prices + decimal taxRate = decimal.Zero; + decimal oldPriceBase = _taxService.GetProductPrice(contextProduct, contextProduct.OldPrice, out taxRate); + decimal finalPriceBase = _taxService.GetProductPrice(contextProduct, displayPrice.Value, out taxRate); + decimal finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, workingCurrency); + priceModel.OldPrice = null; - priceModel.Price = null; + priceModel.Price = String.Format(res["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice)); + priceModel.HasDiscount = finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero; + } + else + { + // Actually it's not possible (we presume that displayPrice always has a value). We never should get here + Debug.WriteLine(string.Format("Cannot calculate displayPrice for product #{0}", product.Id)); } } + } + } + + #endregion + } + else + { + #region Simple product - #endregion + //add to cart button + priceModel.DisableBuyButton = product.DisableBuyButton || !enableShoppingCart || !displayPrices; + + //add to wishlist button + priceModel.DisableWishListButton = product.DisableWishlistButton || !enableWishlist || !displayPrices; + + //pre-order + priceModel.AvailableForPreOrder = product.AvailableForPreOrder; + + //prices + if (displayPrices && _catalogSettings.PriceDisplayType != PriceDisplayType.Hide && !product.CustomerEntersPrice) + { + if (product.CallForPrice) + { + //call for price + priceModel.OldPrice = null; + priceModel.Price = res["Products.CallForPrice"]; } - break; - case ProductType.SimpleProduct: - default: + else { - #region Simple product + //calculate prices + bool displayFromMessage = false; + decimal displayPrice = decimal.Zero; + + if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice) + { + displayPrice = _priceCalculationService.GetPreselectedPrice(product, priceCalculationContext); + } + else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes) + { + displayPrice = _priceCalculationService.GetFinalPrice(product, null, currentCustomer, decimal.Zero, false, 1, null); + } + else + { + displayPrice = _priceCalculationService.GetLowestPrice(product, priceCalculationContext, out displayFromMessage); + } - //add to cart button - priceModel.DisableBuyButton = product.DisableBuyButton || !enableShoppingCart || !displayPrices; + decimal taxRate = decimal.Zero; + decimal oldPriceBase = _taxService.GetProductPrice(product, product.OldPrice, out taxRate); + decimal finalPriceBase = _taxService.GetProductPrice(product, displayPrice, out taxRate); - //add to wishlist button - priceModel.DisableWishListButton = product.DisableWishlistButton || !enableWishlist || !displayPrices; + decimal oldPrice = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, workingCurrency); + decimal finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, workingCurrency); - //pre-order - priceModel.AvailableForPreOrder = product.AvailableForPreOrder; + priceModel.HasDiscount = (finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero); - //prices - if (displayPrices) + if (displayFromMessage) { - if (!product.CustomerEntersPrice) - { - if (product.CallForPrice) - { - //call for price - priceModel.OldPrice = null; - priceModel.Price = res["Products.CallForPrice"]; - } - else - { - //calculate prices - bool isBundlePerItemPricing = (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing); - - bool displayFromMessage = false; - decimal minPossiblePrice = _priceCalculationService.GetLowestPrice(product, out displayFromMessage); - - if (!displayFromMessage) - { - if (productIdsWithPriceAdjustments == null) - productIdsWithPriceAdjustments = _productAttributeService.GetProductIdsWithPriceAdjustments(productIds); - - displayFromMessage = productIdsWithPriceAdjustments.Contains(product.Id); - } - - decimal taxRate = decimal.Zero; - decimal oldPriceBase = _taxService.GetProductPrice(product, product.OldPrice, out taxRate); - decimal finalPriceBase = _taxService.GetProductPrice(product, minPossiblePrice, out taxRate); - - decimal oldPrice = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, _services.WorkContext.WorkingCurrency); - decimal finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, _services.WorkContext.WorkingCurrency); - - priceModel.HasDiscount = (finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero); - - // check tier prices - if (product.HasTierPrices && !isBundlePerItemPricing && !displayFromMessage) - { - var tierPrices = new List(); - - tierPrices.AddRange(product.TierPrices - .OrderBy(tp => tp.Quantity) - .FilterByStore(_services.StoreContext.CurrentStore.Id) - .FilterForCustomer(_services.WorkContext.CurrentCustomer) - .ToList() - .RemoveDuplicatedQuantities()); - - // When there is just one tier (with qty 1), there are no actual savings in the list. - displayFromMessage = (tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices[0].Quantity <= 1)); - } - - if (displayFromMessage) - { - priceModel.OldPrice = null; - priceModel.Price = String.Format(res["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice)); - } - else - { - if (priceModel.HasDiscount) - { - priceModel.OldPrice = _priceFormatter.FormatPrice(oldPrice); - priceModel.Price = _priceFormatter.FormatPrice(finalPrice); - } - else - { - priceModel.OldPrice = null; - priceModel.Price = _priceFormatter.FormatPrice(finalPrice); - } - } - } - } + priceModel.OldPrice = null; + priceModel.Price = String.Format(res["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice)); } else { - //hide prices - priceModel.OldPrice = null; - priceModel.Price = null; + if (priceModel.HasDiscount) + { + priceModel.OldPrice = _priceFormatter.FormatPrice(oldPrice); + priceModel.Price = _priceFormatter.FormatPrice(finalPrice); + } + else + { + priceModel.OldPrice = null; + priceModel.Price = _priceFormatter.FormatPrice(finalPrice); + } } - - #endregion } - break; + } + + #endregion } model.ProductPrice = priceModel; @@ -1219,7 +1197,7 @@ public IEnumerable PrepareProductOverviewModels( //prepare picture model var defaultProductPictureCacheKey = string.Format(ModelCacheEventConsumer.PRODUCT_DEFAULTPICTURE_MODEL_KEY, product.Id, pictureSize, true, - _services.WorkContext.WorkingLanguage.Id, _services.WebHelper.IsCurrentConnectionSecured(), _services.StoreContext.CurrentStore.Id); + _services.WorkContext.WorkingLanguage.Id, _services.WebHelper.IsCurrentConnectionSecured(), currentStore.Id); model.DefaultPictureModel = _services.Cache.Get(defaultProductPictureCacheKey, () => { @@ -1243,15 +1221,15 @@ public IEnumerable PrepareProductOverviewModels( model.SpecificationAttributeModels = PrepareProductSpecificationModel(product); } - model.MinPriceProductId = minPriceProduct.Id; + model.MinPriceProductId = contextProduct.Id; model.ShowSku = _catalogSettings.ShowProductSku; model.ShowWeight = _catalogSettings.ShowWeight; model.ShowDimensions = _catalogSettings.ShowDimensions; - model.Sku = minPriceProduct.Sku; + model.Sku = contextProduct.Sku; model.Dimensions = res["Products.DimensionsValue"].Text.FormatCurrent( - minPriceProduct.Width.ToString("F2"), - minPriceProduct.Height.ToString("F2"), - minPriceProduct.Length.ToString("F2") + contextProduct.Width.ToString("F2"), + contextProduct.Height.ToString("F2"), + contextProduct.Length.ToString("F2") ); model.DimensionMeasureUnit = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId).Name; model.ThumbDimension = _mediaSettings.ProductThumbPictureSize; @@ -1263,9 +1241,9 @@ public IEnumerable PrepareProductOverviewModels( model.ShowDeliveryTimes = _catalogSettings.ShowDeliveryTimesInProductLists; model.InvisibleDeliveryTime = (product.ProductType == ProductType.GroupedProduct); - model.IsShipEnabled = minPriceProduct.IsShipEnabled; - model.DisplayDeliveryTimeAccordingToStock = minPriceProduct.DisplayDeliveryTimeAccordingToStock(_catalogSettings); - model.StockAvailablity = minPriceProduct.FormatStockMessage(_localizationService); + model.IsShipEnabled = contextProduct.IsShipEnabled; + model.DisplayDeliveryTimeAccordingToStock = contextProduct.DisplayDeliveryTimeAccordingToStock(_catalogSettings); + model.StockAvailablity = contextProduct.FormatStockMessage(_localizationService); model.DisplayBasePrice = _catalogSettings.ShowBasePriceInProductLists; model.CompareEnabled = _catalogSettings.CompareProductsEnabled; @@ -1273,7 +1251,7 @@ public IEnumerable PrepareProductOverviewModels( if (model.ShowDeliveryTimes) { - var deliveryTime = _deliveryTimeService.GetDeliveryTime(minPriceProduct); + var deliveryTime = _deliveryTimeService.GetDeliveryTime(contextProduct); if (deliveryTime != null) { model.DeliveryTimeName = deliveryTime.GetLocalized(x => x.Name); @@ -1288,20 +1266,19 @@ public IEnumerable PrepareProductOverviewModels( if (_catalogSettings.ShowBasePriceInProductLists) { - model.BasePriceInfo = minPriceProduct.GetBasePriceInfo(_localizationService, _priceFormatter); + model.BasePriceInfo = contextProduct.GetBasePriceInfo(_localizationService, _priceFormatter); } - var addShippingPrice = _currencyService.ConvertCurrency(minPriceProduct.AdditionalShippingCharge, - _services.StoreContext.CurrentStore.PrimaryStoreCurrency, _services.WorkContext.WorkingCurrency); + var addShippingPrice = _currencyService.ConvertCurrency(contextProduct.AdditionalShippingCharge, currentStore.PrimaryStoreCurrency, workingCurrency); if (addShippingPrice > 0 && displayPrices) { model.TransportSurcharge = res["Common.AdditionalShippingSurcharge"].Text.FormatWith(_priceFormatter.FormatPrice(addShippingPrice, true, false)); } - if (minPriceProduct.Weight > 0) + if (contextProduct.Weight > 0) { - model.Weight = "{0} {1}".FormatCurrent(minPriceProduct.Weight.ToString("F2"), _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name); + model.Weight = "{0} {1}".FormatCurrent(contextProduct.Weight.ToString("F2"), _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name); } // IsNew From 7a3418f0797117a5e034a6840353d7ee2e014cb9 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Fri, 24 Jul 2015 15:43:46 +0200 Subject: [PATCH 0115/1074] New options for manufacturer display on the homepage --- changelog.md | 3 +- .../Domain/Catalog/CatalogSettings.cs | 12 ++++++ .../201506181858349_AclRecordCustomerRole.cs | 12 ++++++ .../Infrastructure/AutoMapperStartupTask.cs | 1 - .../Models/Settings/CatalogSettingsModel.cs | 9 ++++ .../Views/Setting/Catalog.cshtml | 43 +++++++++++++++++++ .../Controllers/CatalogController.cs | 7 ++- .../Catalog/ManufacturerNavigationModel.cs | 8 +++- .../Themes/Alpha/Content/pages.less | 14 ++++++ .../Catalog/ManufacturerNavigation.cshtml | 20 ++++++++- 10 files changed, 123 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 6e8c2f90ad..438a5a59e4 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,4 @@ -# Release Notes +# Release Notes ## SmartStore.NET 2.2.2 @@ -8,6 +8,7 @@ * Added zip code to shipping by weight computation method * Skrill payment plugin (distributed via Marketplace) * (Dev) DevTool plugin: added option to display all widget zones in public store +* New options for manufacturer display on the homepage ### Improvements * (Perf) several minor optimizations for faster app startup and page rendering diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs index dd7d67edea..d365513cb3 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs @@ -38,6 +38,8 @@ public CatalogSettings() ProductSearchAutoCompleteNumberOfProducts = 10; ProductSearchTermMinimumLength = 3; NumberOfBestsellersOnHomepage = 6; + ShowManufacturersOnHomepage = true; + ShowManufacturerPictures = false; SearchPageProductsPerPage = 6; ProductsAlsoPurchasedEnabled = true; ProductsAlsoPurchasedNumber = 6; @@ -283,6 +285,16 @@ public CatalogSettings() ///
    public int NumberOfBestsellersOnHomepage { get; set; } + /// + /// Gets or sets a value indicating whether to show manufacturers on home page + /// + public bool ShowManufacturersOnHomepage { get; set; } + + /// + /// Gets or sets a value indicating whether to show manufacturer pictures or names on home page + /// + public bool ShowManufacturerPictures { get; set; } + /// /// Gets or sets a number of products per page on search products page /// diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs index 9126926fe2..153e8be49e 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs @@ -119,6 +119,18 @@ before you can assign them to all subcategories and products.
    builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.RecurringPaymentType", "Recurring payments", "Wiederkehrende Zahlungen"); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowManufacturersOnHomepage", + "Show manufacturers on homepage", + "Zeige Hersteller auf der Homepage", + "Specifies whether manufacturers will be displayed on the homepage.", + "Bestimmt ob Hersteller auf der Homepage angezeigt werden."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowManufacturerPictures", + "Show manufacturer pictures on homepage", + "Zeige Herstellerbilder auf der Homepage", + "Specifies whether manufacturers will be displayed as images or textual links on the homepage.", + "Bestimmt ob Hersteller auf der Homepage als Bilder oder textuelle Links angezeigt werden."); } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs index d9331cdd05..60384337d9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs +++ b/src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs @@ -616,7 +616,6 @@ public void Execute() .ForMember(dest => dest.FileUploadMaximumSizeBytes, mo => mo.Ignore()) .ForMember(dest => dest.FileUploadAllowedExtensions, mo => mo.Ignore()) .ForMember(dest => dest.ProductSearchPageSize, mo => mo.Ignore()) - .ForMember(dest => dest.ManufacturersBlockItemsToDisplay, mo => mo.Ignore()) .ForMember(dest => dest.MostRecentlyUsedCategoriesMaxSize, mo => mo.Ignore()) .ForMember(dest => dest.MostRecentlyUsedManufacturersMaxSize, mo => mo.Ignore()); Mapper.CreateMap() diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/CatalogSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/CatalogSettingsModel.cs index ba76a185ea..14b966406f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/CatalogSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/CatalogSettingsModel.cs @@ -63,6 +63,15 @@ public CatalogSettingsModel() [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.ShowDefaultQuantityUnit")] public bool ShowDefaultQuantityUnit { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.ShowManufacturersOnHomepage")] + public bool ShowManufacturersOnHomepage { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.ManufacturersBlockItemsToDisplay")] + public int ManufacturersBlockItemsToDisplay { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Settings.Catalog.ShowManufacturerPictures")] + public bool ShowManufacturerPictures { get; set; } + #endregion #region Product lists diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml index a55ae23614..f8bdcda4bf 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/Catalog.cshtml @@ -23,6 +23,7 @@ $("#@Html.FieldIdFor(model => model.RecentlyViewedProductsEnabled)").click(toggleRecentlyViewedProducts); $("#@Html.FieldIdFor(model => model.RecentlyAddedProductsEnabled)").click(toggleRecentlyAddedProducts); $("#@Html.FieldIdFor(model => model.ShowBestsellersOnHomepage)").click(toggleBestsellersOnHomepage); + $("#@Html.FieldIdFor(model => model.ShowManufacturersOnHomepage)").click(toggleManufacturersOnHomepage); $("#@Html.FieldIdFor(model => model.ProductsAlsoPurchasedEnabled)").click(toggleProductsAlsoPurchasedNumber); $("#@Html.FieldIdFor(model => model.ProductsByTagAllowCustomersToSelectPageSize)").click(toggleTagPageSize); $("#@Html.FieldIdFor(model => model.ProductSearchAllowCustomersToSelectPageSize)").click(toggleSearchPageSize); @@ -43,6 +44,7 @@ toggleCompareProducts(); toggleHtmlTextCollapsedHeight(); toggleFilterEnabled(); + toggleManufacturersOnHomepage(); }); function toggleShowCategoryProductNumberIncludingSubcategories() { @@ -90,6 +92,17 @@ } } + function toggleManufacturersOnHomepage() { + if ($('#@Html.FieldIdFor(model => model.ShowManufacturersOnHomepage)').is(':checked')) { + $('#pnlShowManufacturerPictures').show(); + $('#pnlManufacturersBlockItemsToDisplay').show(); + } + else { + $('#pnlShowManufacturerPictures').hide(); + $('#pnlManufacturersBlockItemsToDisplay').hide(); + } + } + function toggleProductsAlsoPurchasedNumber() { if ($('#@Html.FieldIdFor(model => model.ProductsAlsoPurchasedEnabled)').is(':checked')) { $('#pnlProductsAlsoPurchasedNumber').show(); @@ -290,6 +303,36 @@ @Html.ValidationMessageFor(model => model.NumberOfBestsellersOnHomepage) + + + + @Html.SmartLabelFor(model => model.ShowManufacturersOnHomepage) + + + @Html.SettingEditorFor(model => model.ShowManufacturersOnHomepage) + @Html.ValidationMessageFor(model => model.ShowManufacturersOnHomepage) + + + + + @Html.SmartLabelFor(model => model.ManufacturersBlockItemsToDisplay) + + + @Html.SettingEditorFor(model => model.ManufacturersBlockItemsToDisplay) + @Html.ValidationMessageFor(model => model.ManufacturersBlockItemsToDisplay) + + + + + @Html.SmartLabelFor(model => model.ShowManufacturerPictures) + + + @Html.SettingEditorFor(model => model.ShowManufacturerPictures) + @Html.ValidationMessageFor(model => model.ShowManufacturerPictures) + + + + @Html.SmartLabelFor(model => model.EnableHtmlTextCollapser) diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs index 191bdc64fc..91410424af 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogController.cs @@ -606,7 +606,7 @@ private PictureModel PrepareManufacturerPictureModel(Manufacturer manufacturer, [ChildActionOnly] public ActionResult ManufacturerNavigation(int currentManufacturerId) { - if (_catalogSettings.ManufacturersBlockItemsToDisplay == 0) + if (_catalogSettings.ManufacturersBlockItemsToDisplay == 0 || _catalogSettings.ShowManufacturersOnHomepage == false) return Content(""); string cacheKey = string.Format(ModelCacheEventConsumer.MANUFACTURER_NAVIGATION_MODEL_KEY, currentManufacturerId, _services.WorkContext.WorkingLanguage.Id, _services.StoreContext.CurrentStore.Id); @@ -617,7 +617,9 @@ public ActionResult ManufacturerNavigation(int currentManufacturerId) var manufacturers = _manufacturerService.GetAllManufacturers(); var model = new ManufacturerNavigationModel() { - TotalManufacturers = manufacturers.Count + TotalManufacturers = manufacturers.Count, + DisplayManufacturers = _catalogSettings.ShowManufacturersOnHomepage, + DisplayImages = _catalogSettings.ShowManufacturerPictures }; foreach (var manufacturer in manufacturers.Take(_catalogSettings.ManufacturersBlockItemsToDisplay)) @@ -627,6 +629,7 @@ public ActionResult ManufacturerNavigation(int currentManufacturerId) Id = manufacturer.Id, Name = manufacturer.GetLocalized(x => x.Name), SeName = manufacturer.GetSeName(), + PictureUrl = _pictureService.GetPictureUrl(manufacturer.PictureId.GetValueOrDefault(), _mediaSettings.ManufacturerThumbPictureSize), IsActive = currentManufacturer != null && currentManufacturer.Id == manufacturer.Id, }; model.Manufacturers.Add(modelMan); diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerNavigationModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerNavigationModel.cs index dcbefd212d..1c03322e45 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerNavigationModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerNavigationModel.cs @@ -13,6 +13,10 @@ public ManufacturerNavigationModel() public IList Manufacturers { get; set; } public int TotalManufacturers { get; set; } + + public bool DisplayManufacturers { get; set; } + + public bool DisplayImages { get; set; } } public partial class ManufacturerBriefInfoModel : EntityModelBase @@ -20,7 +24,9 @@ public partial class ManufacturerBriefInfoModel : EntityModelBase public string Name { get; set; } public string SeName { get; set; } - + + public string PictureUrl { get; set; } + public bool IsActive { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/pages.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/pages.less index 4b7f87e7bf..11a472e78c 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/pages.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/pages.less @@ -167,3 +167,17 @@ vertical-align: top; } +/* Manufacturers on homepage +================================================ */ + +.block-manufacturer-navigation .manufacturer-pic { + float: left; + width: 50px; + height: 50px; + margin: 0 0 10px 10px; + + img { + max-width: 50px; + max-height: 50px; + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/ManufacturerNavigation.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/ManufacturerNavigation.cshtml index f408a7bf41..e5d653f039 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/ManufacturerNavigation.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/ManufacturerNavigation.cshtml @@ -13,10 +13,28 @@ + + @if (Model.DisplayImages) + { +
     
    + } + @if (Model.TotalManufacturers > Model.Manufacturers.Count) {
    From 5dd82b10215cf736ff59b3da7f865b4155258111 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Fri, 24 Jul 2015 20:53:21 +0200 Subject: [PATCH 0116/1074] WebScheduler 8 --- .../DependencyManagement/ContainerManager.cs | 8 +++--- .../Tasks/TaskExecutionContext.cs | 25 +++++++++++++++---- .../SmartStore.Services/Tasks/TaskExecutor.cs | 7 ++++-- .../Controllers/ScheduleTaskController.cs | 7 ++++-- .../Models/Tasks/ScheduleTaskModel.cs | 2 ++ 5 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs index 7bac9acb62..e15832df7f 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs @@ -21,9 +21,9 @@ public IContainer Container get { return _container; } } - public T Resolve(string key = "", ILifetimeScope scope = null) where T : class + public T Resolve(object key = null, ILifetimeScope scope = null) where T : class { - if (string.IsNullOrEmpty(key)) + if (key == null) { return (scope ?? Scope()).Resolve(); } @@ -45,9 +45,9 @@ public object ResolveNamed(string name, Type type, ILifetimeScope scope = null) return (scope ?? Scope()).ResolveNamed(name, type); } - public T[] ResolveAll(string key = "", ILifetimeScope scope = null) + public T[] ResolveAll(object key = null, ILifetimeScope scope = null) { - if (string.IsNullOrEmpty(key)) + if (key == null) { return (scope ?? Scope()).Resolve>().ToArray(); } diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs index 97824c3416..eb87adc407 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs @@ -13,11 +13,26 @@ namespace SmartStore.Services.Tasks ///
    public class TaskExecutionContext { - /// - /// The shared instance created - /// before the execution of the task's background thread. - /// - public object LifetimeScope { get; internal set; } + private readonly IComponentContext _componentContext; + + internal TaskExecutionContext(IComponentContext componentContext) + { + this._componentContext = componentContext; + } + + public T Resolve(object key = null) where T : class + { + if (key == null) + { + return _componentContext.Resolve(); + } + return _componentContext.ResolveKeyed(key); + } + + public T ResolveNamed(string name) where T : class + { + return _componentContext.ResolveNamed(name); + } /// /// A cancellation token for the running task. diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs index d94abd4b1b..7101c1d242 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs @@ -9,6 +9,7 @@ using SmartStore.Core.Async; using System.Threading; using SmartStore.Core.Plugins; +using Autofac; namespace SmartStore.Services.Tasks { @@ -18,11 +19,13 @@ public class TaskExecutor : ITaskExecutor private readonly IScheduleTaskService _scheduledTaskService; private readonly IDbContext _dbContext; private readonly Func _taskResolver; + private readonly IComponentContext _componentContext; - public TaskExecutor(IScheduleTaskService scheduledTaskService, IDbContext dbContext, Func taskResolver) + public TaskExecutor(IScheduleTaskService scheduledTaskService, IDbContext dbContext, IComponentContext componentContext, Func taskResolver) { this._scheduledTaskService = scheduledTaskService; this._dbContext = dbContext; + this._componentContext = componentContext; this._taskResolver = taskResolver; Logger = NullLogger.Instance; @@ -80,7 +83,7 @@ public void Execute(ScheduleTask task, bool throwOnError = false) }; AsyncState.Current.Set(taskProgressInfo, stateName, true); - var ctx = new TaskExecutionContext + var ctx = new TaskExecutionContext(_componentContext) { ScheduleTask = task.Clone(), CancellationToken = cts.Token diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs index 0c058cdda2..55814bf825 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs @@ -80,15 +80,17 @@ protected ScheduleTaskModel PrepareScheduleTaskModel(ScheduleTask task) } var nextRunStr = ""; + bool isOverdue = false; if (dueIn.HasValue) { if (dueIn.Value.TotalSeconds > 0) { - nextRunStr = dueIn.Value.Prettify(); + nextRunStr = "{0}".FormatCurrent(dueIn.Value.Prettify()); } else { - nextRunStr = T("Common.Waiting") + "..."; + nextRunStr = "{0}".FormatCurrent(T("Common.Waiting") + "..."); + isOverdue = true; } } @@ -107,6 +109,7 @@ protected ScheduleTaskModel PrepareScheduleTaskModel(ScheduleTask task) IsRunning = task.IsRunning, CancelUrl = task.IsRunning ? Url.Action("CancelJob", new { id = task.Id }) : "", ProgressInfo = task.IsRunning ? T("Admin.System.ScheduleTasks.RunNow.IsRunning").Text : "", + IsOverdue = isOverdue, Duration = "" }; diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs index 070618b167..1e33efda3a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs @@ -34,6 +34,8 @@ public partial class ScheduleTaskModel : EntityModelBase [SmartResourceDisplayName("Admin.System.ScheduleTasks.NextRun")] public string NextRunUtc { get; set; } + public bool IsOverdue { get; set; } + [SmartResourceDisplayName("Common.Error")] public string LastError { get; set; } From 80e8123c72f53bf21aa738a906f0d00621ac0110 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Sat, 25 Jul 2015 02:24:31 +0200 Subject: [PATCH 0117/1074] WebScheduler final --- .../Domain/Tasks/ScheduleTask.cs | 15 ++- .../Mapping/Tasks/ScheduleTaskMap.cs | 3 +- .../201507211743009_WebScheduler.resx | 126 ------------------ ... 201507242008201_WebScheduler.Designer.cs} | 2 +- ...ler.cs => 201507242008201_WebScheduler.cs} | 14 +- .../201507242008201_WebScheduler.resx | 126 ++++++++++++++++++ .../Setup/Builder/LocaleResourcesMigrator.cs | 2 +- .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../SmartStore.Services.csproj | 1 - .../Tasks/IScheduleTaskService.cs | 19 +++ .../Tasks/ITaskScheduler.cs | 38 +----- .../Tasks/ScheduleTaskService.cs | 45 ++++++- .../Tasks/TaskExecutionContext.cs | 36 +++-- .../SmartStore.Services/Tasks/TaskExecutor.cs | 24 ++-- .../Tasks/TaskProgressInfo.cs | 49 ------- .../Tasks/TaskScheduler.cs | 24 +--- .../Administration/Content/admin.less | 35 +++++ .../Controllers/ScheduleTaskController.cs | 51 +++---- .../Models/Tasks/ScheduleTaskModel.cs | 3 +- .../Administration/Scripts/admin.common.js | 63 ++++++++- .../Views/ScheduleTask/List.cshtml | 33 ++++- 21 files changed, 414 insertions(+), 305 deletions(-) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.resx rename src/Libraries/SmartStore.Data/Migrations/{201507211743009_WebScheduler.Designer.cs => 201507242008201_WebScheduler.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201507211743009_WebScheduler.cs => 201507242008201_WebScheduler.cs} (77%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.resx delete mode 100644 src/Libraries/SmartStore.Services/Tasks/TaskProgressInfo.cs diff --git a/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs b/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs index 7cfff3c974..5aa4f04e23 100644 --- a/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs +++ b/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs @@ -26,6 +26,7 @@ public class ScheduleTask : BaseEntity, ICloneable /// /// Gets or sets the type of appropriate ITask class /// + [Index("IX_Type")] public string Type { get; set; } /// @@ -42,8 +43,10 @@ public class ScheduleTask : BaseEntity, ICloneable [Index("IX_NextRun_Enabled", 0)] public DateTime? NextRunUtc { get; set; } + [Index("IX_LastStart_LastEnd", 0)] public DateTime? LastStartUtc { get; set; } + [Index("IX_LastStart_LastEnd", 1)] public DateTime? LastEndUtc { get; set; } public DateTime? LastSuccessUtc { get; set; } @@ -52,6 +55,16 @@ public class ScheduleTask : BaseEntity, ICloneable public bool IsHidden { get; set; } + /// + /// Gets or sets a value indicating the current percentual progress for a running task + /// + public int? ProgressPercent { get; set; } + + /// + /// Gets or sets the current progress message for a running task + /// + public string ProgressMessage { get; set; } + /// /// Gets a value indicating whether a task is running /// @@ -59,7 +72,7 @@ public bool IsRunning { get { - var result = (LastStartUtc.HasValue && LastStartUtc.Value > LastEndUtc.GetValueOrDefault()); + var result = LastStartUtc.HasValue && LastStartUtc.Value > LastEndUtc.GetValueOrDefault(); return result; } } diff --git a/src/Libraries/SmartStore.Data/Mapping/Tasks/ScheduleTaskMap.cs b/src/Libraries/SmartStore.Data/Mapping/Tasks/ScheduleTaskMap.cs index b23b152152..8d06abd923 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Tasks/ScheduleTaskMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Tasks/ScheduleTaskMap.cs @@ -10,9 +10,10 @@ public ScheduleTaskMap() this.ToTable("ScheduleTask"); this.HasKey(t => t.Id); this.Property(t => t.Name).HasMaxLength(500).IsRequired(); - this.Property(t => t.Type).HasMaxLength(1000).IsRequired(); + this.Property(t => t.Type).HasMaxLength(800).IsRequired(); this.Property(t => t.Alias).HasMaxLength(500); this.Property(t => t.LastError).HasMaxLength(1000); + this.Property(t => t.ProgressMessage).HasMaxLength(1000).IsOptional(); this.Ignore(t => t.IsRunning); this.Ignore(t => t.IsPending); diff --git a/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.resx b/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.resx deleted file mode 100644 index af5dcde47c..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.Designer.cs index 765d3e0a62..d9e3e0bca9 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class WebScheduler : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201507211743009_WebScheduler"; } + get { return "201507242008201_WebScheduler"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.cs b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.cs similarity index 77% rename from src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.cs rename to src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.cs index d49a775776..d9a437cb3c 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507211743009_WebScheduler.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.cs @@ -8,15 +8,27 @@ public partial class WebScheduler : DbMigration, ILocaleResourcesProvider, IData { public override void Up() { - AddColumn("dbo.ScheduleTask", "Alias", c => c.String(maxLength: 4000)); + AddColumn("dbo.ScheduleTask", "Alias", c => c.String(maxLength: 500)); AddColumn("dbo.ScheduleTask", "NextRunUtc", c => c.DateTime()); AddColumn("dbo.ScheduleTask", "IsHidden", c => c.Boolean(nullable: false)); + AddColumn("dbo.ScheduleTask", "ProgressPercent", c => c.Int()); + AddColumn("dbo.ScheduleTask", "ProgressMessage", c => c.String(maxLength: 1000)); + AlterColumn("dbo.ScheduleTask", "Name", c => c.String(nullable: false, maxLength: 500)); + AlterColumn("dbo.ScheduleTask", "Type", c => c.String(nullable: false, maxLength: 800)); + CreateIndex("dbo.ScheduleTask", "Type"); CreateIndex("dbo.ScheduleTask", new[] { "NextRunUtc", "Enabled" }, name: "IX_NextRun_Enabled"); + CreateIndex("dbo.ScheduleTask", new[] { "LastStartUtc", "LastEndUtc" }, name: "IX_LastStart_LastEnd"); } public override void Down() { + DropIndex("dbo.ScheduleTask", "IX_LastStart_LastEnd"); DropIndex("dbo.ScheduleTask", "IX_NextRun_Enabled"); + DropIndex("dbo.ScheduleTask", new[] { "Type" }); + //AlterColumn("dbo.ScheduleTask", "Type", c => c.String(nullable: false)); + //AlterColumn("dbo.ScheduleTask", "Name", c => c.String(nullable: false)); + DropColumn("dbo.ScheduleTask", "ProgressMessage"); + DropColumn("dbo.ScheduleTask", "ProgressPercent"); DropColumn("dbo.ScheduleTask", "IsHidden"); DropColumn("dbo.ScheduleTask", "NextRunUtc"); DropColumn("dbo.ScheduleTask", "Alias"); diff --git a/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.resx b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.resx new file mode 100644 index 0000000000..7795c02827 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy92XIcu5Ig+D5m8w8yPXWPVUtHuveY3bp2zrSRFCnRSguLpKSqeqGBkWAyLiMj8sTC5bb1l83DfNL8wgCIJbHvEZGZJ1+kZMDhABwOh7vD4fj//p//97f/+bzKXj3CskqL/PfX79788voVzJNikebL31839d3/+Nvr//l//5//x2+ni9Xzqx893F8wHKqZV7+/vq/r9d/fvq2Se7gC1ZtVmpRFVdzVb5Ji9RYsirfvf/nlX9++e/cWIhSvEa5Xr367bPI6XUHyB/rzpMgTuK4bkH0pFjCruu+o5IpgffUVrGC1Bgn8/fXVCpT1VV2U8M0HUIPXr46yFKBuXMHs7vUrkOdFDWrUyb9/r+BVXRb58mqNPoDs+mUNEdwdyCrYdf7vG3DbcfzyHo/j7aZijyppqrpYOSJ895eOMG/56l7kfT0QDpHuFJG4fsGjJuT7/fW/N4B8+p6n9etXfIN/P8lKDMxQ+ISQGYGl+ZsPaQkT9PXlDY3oX15x4P8ycMn7N+/f/PLml395ddJkdVPC33PY1CXI/uXVRXObpcm/wZfr4gHmv+dNltFdR51HZcwH9OmiLNawrF8u4V03oPPF61dv2Xpv+YpDNapOO8zzvP7L+9evvqLGwW0GB86gSEJG9RHmsAQ1XFyAuoZljnFAMn6hda4t/G/fGmJFtKRev/oCnj/DfFnf//76V7SGztJnuOg/dB1AZEULENWpywZKOqhv9AOskjJdtzwU2rahqbRaZ+Dlc5GALMJArRr7Vi5gaZpCPabz6gO8A4gnezTHRZFBkBsQ/fZ2s6IM6ww2cHGKFk12VNcguV8hdvFYcF9gVYElrN5IER4WnrotimDmZvWocE/QJGAeZ5YU2m3ecDMigDo2hYZ5r1lF7375JcY6OkszKBDFsPTIPtutlTQH5QvTMfRT3q8g6fjecrSORP6C1A7c5gQtfwWP6ZKwgmQKXr+6hBkprO7TdcdQ0oV+04KflcXqsshU8oVA3VwVTZngsRVG0GtQLmFt32kKlUPfmVqmIVBfLUdC15ANyFpmfyie8qwACy8xvUjBmx7BQSxr5EhHo49NOrTa/nZcxEi173F9LzO3bVzdLQqVRCoopZybFtO11YvR2EIVWVI1mgyDhIszFixGcr0Qj9PQ6TMaU6VXaOO0dF59hU/jq4WRlMGDrFG3dVGmRUngQrQ/vGNpDZtRdBTcqtF2jKELXhfTD+66mGRol3CdvUQZn1U7k4zp5GT0Jo6TZPQ2rprbf8CkHt/UOS4WL6NvGSclxALqW/69HkiHDCZ4na7cF8cV3rvLFFaBRitCo+iQYacl+nWSFE1eB1vOMF98AXkDsuzFWUVTmiEb5b+awgzpjQp7M6Q3XGwHRJPcNKIbFlg6EAZGZ0axgEHWE9stf92GxnNQbgzLVOfB+PXXUVzLrQvW5LixbFzf1qei0u0QI43woijrMKmHTNPSYBSN1XdQVU9FuZi+5dMcA19VwZY4tutb1zzaVclaQLVGMscuwAuW3V9gfV/4uH26+tUbBtFBaukYlCLU1UtVQ5OV81dbPdCVYZ+TrFnAxQmZdFjivfF8UY2u+Q7t4g2ufNE3+T6OEty3eYU0ijVqoyX/FKPtRkk6gFcA8U09B+uVX9I8XTUrchB4tGpVjk7LhUm6AkgKXZToVxfR8LfXr67w+STiJiNm8DwS5hbbJawQrZPalxb2sq0sFk1SHzf5AjE2WmdIVy3T26aGZ2lW4/NTZ3F3AmqQFcs3JtQHAahua0O00DUwED0aoh8ga4KxnVdofSCjBVn3cBHP5tvQTWogmVjyhq6/sZkcqglmlEvdIMtKaCjm0j2sVXVbHbFCV0RL7EjI+rirMCzIikti7m09vguIlkheI0M+1Awwa4UxvJD3yNazC5aKdlyGWHAQFI52jcRCThfw+r5Z3eaUM8AX2Q808bdZ8MwR4VDdewj/0aK9ovpnv68XAch0Tk1695B7NifY5nhvp88W6bapdy3YDfiGq6MZJAtq3r85eNfgGLdhWA3Avuu6TrsqGuHqxUGp0IjHlkS4uVBd4AKUqM2PZdGsUUfi6BfdJnCeL9LHdOF3cDPOVu569DT53o76N2V7R4tVmp8UqzayeOTGeq6FK7Qlh5ucaHKevuWfihW8iKAr9njiKQxfYA2Q0MCudJ2PLI4WihubknFwe9dprQ3XjzOyoywrngYHK3xM4VOwynu0XpfFI1xcImmcL6+aVdhMfy3qyBh7dNdow8i4QQf3MR7SLgLjujhKgi2Hz+kqrXHnyN4YPMVXD834iw7kzR1IsApSon20/oqMqI3UGK3Zj4jFRm/kvPqY3tUnoAw2wXo8MbSVS/hHk5bwW32PKN5uJ8Gc0uHcKD86aR0pouiowbpxnSZYNzpaLLg+BI/pvNoEoscJag6due951i7wHmHwGNGstAvu252A09Oj1aE5fV6nJVHUP4AXHqcdiqOkTh8Jihhs/wlUVwBpTTDWrLLYHK/xoN7g6ISjZQkhrTgGnNZvkF3D5/E10fPqEiZN2WIPlR4dopOXJINtp0JlHI3xApZpEbz6Bpxk7yeIA9fKeYUPgtuIjWB2PK/O0PT3J8vB2t1ikeKVB7Ie48k9dmnYO6qdu38Nnk+fkV0TvBbOq9MqmJyoNyfIwFoWODQg0IgBOTKKzvNHtDQRuv7QP/guZPIQ7RACm2sE49EjSFHdNKOwBvqNpT313rDSPOLIPxdP7ajxToOwhU4KMhDSuxfiEDgryr6PxxBZX4FHVyB5KLA5jXMyBJ8zY2sQYzxvaYkskMHoDdYoiNHfhYXEmaQWYxsOEgcjIQBcdMioCO/xlFW0FnAHj5uX46auN86FgLWFoX+m1X2WVnUcpN3izyBiXiTXGf+NL84TpJ0TdGkSfqJFI4m+A33LFuM20BkmJ1Q0bfQ2rtYID8gcB2KP86pGNnp/yuZxqYHGdZovAjD17qzTHJ/SReGvTmwxmOHITNEJtknbRMbHdQrbNRks8NEeCqt6OIw8KVa3ad6dy0VkQtTnPrihOlqvszRcY/4J0+X9eEuRtWOio/+ZLkbE/mlc2gw7Tag8GRCFCZN4Jxbxoi5gBn0i97Y35EIcYPoIyxdc2dF7Qie9cqx6DCrY7T5RzO4B3xcIqqaEbUIvTTR3jLuUfZtxA6MHtPgHi9qOtCQMgpxoGTxQcdzrXZgILHHkRSzHB4MUUyM2zqv7ovWngNLd06GOWmq3xGGLlEa/9KU3HfR1sfGVb8Jf1FBCTJIG1DUEiZYGutCdGxZQiNphylUBOyyQZ4DRJurHMkbMP2TKGAumCLFyHFHn8CIGsXpAvVtMEzrFg6gGIMB5dpw+RNT2nQbU9F8GphqDFNZzHBcpwaMdQgej6T0Hoeo4D+bZ5+EQXN3lFkTTYxZA1WEOyrO/xAK9S9u8cHQEsLr/8iqa8egrqMZnqOU53muw1A7uhoET5SlVrBSnNIynNP0ByhQpdTI7Utt9TT3NBFnUUs2STVXPqeJROw3cYbSuQ/QeF5vlVsODLKDIhHS5kgsZIFc25M+GNZ3lQcXushDKDnNgrl2mfTiS7g7FMs4QCgVeECFks2+f1G+46eKR7LhTaodfh7hmdVuGKN+RUnn2MxMjUuN7hW2lSPeX1Deioju1+qZcrXLnk9/OZeaTU6j1knnU7KKrqpOiWeMr04vgmRExyY/f4py+kZkh8ZFklYXy6AYTJp5rHIjJjL8uDKaYaHjTFXS2/AZO2Ja0wK6bk8TFMIZHwjwGwXlh7ZHoUHWcr05zNbQpryEZhwxQPRQpdNAFo97uDrhh1KM4bMXqtgxb8UgXbvD9l0gtmxz4092VOC5qxKeTXuvBT5mMvjP1yyjWhZ7DhZkoI2tv9MUKAOw8bY4nVfgm1VX6TxjWNnP1p7ou2owgPG7viJwOzzc2eCzA7rCIALoE+VIbsxUtKUHMu3Hx4xe2+ObQtp2C72UKA4FUJFvfjxQ+fdEbVZ7SOPbho4fJYj6AlNg31l7YVkxLe785qeqBNj3mywRNXgAIyw7Q98DzdYyu/kFx14ivlkRjPQxh8e7NX8e5iw8Li4ci/hLp8qPz8w2xT0jFpSqHMJ6Qcuvab9kyOMNzexyW8VR5w1Tq+3Q6iNeW5b0aFMdVqkXjuILjxjaY+hojHY/E/xblFIvCd1jF2nUT5Q0ECdkvmwxaJT+O47+4WsPRT4eO0yzD0YV9VuPAW4b95c846Pqku0RRZ/I9O3lGNmgGCa9zB8SZPKpROnf2lA33s2H2tsRuufMLOM7T6TMSVPSDlRPYops4g/FOapRWqPZcx2/vYaJdA96JphEddht1W4aNYJx3ok+KrCg/wWeS+Hny1nfi6WhXOyvCESeH6bBq1G1FsrRiHbicV2cQ4InoFYQZ/cfKnWrDoRax9htgdbD98ENhFImAI5hwPrcDTP2NYsVdiOH64bKBxnaQD6PLB5rcfwoZwXKr5b0WtpL+cgvzh2IdqiuMID9CbujY9D+KLIkkRA7SY5vjqCaNbKE44RAKtF2hQIfgnR0M3jnEs+xePIvXKRe7uYtnXLJyQVGQAsWwNtorq+F2Rosnmo7wCmd46Non0S2diCEv4eX16yl0eZP0juXCxoSbJCFqm7Y8jCifYLa+a7L/hBVJMhoF2dfCB1eIDu9631uhtytuhTt2tMXS0SKHVYXWqinFgVDnhlvPihEpa+ivtKurBZ0d9KvaR/z0Osfw62CfqNvqafSxSYdW298eWZwNwVmR8lGaXi2P1IzFO9iR3kXpGjoryhUIj/jpsF2BbPx9Y9L3YyKmWT66u0uzNIKhSrLvBlszkTTr86oNCDlKmIcZvWP0baJL4jzx/BlU9fn6aLFA9s74sQFR7Qbc9c/FMs09Lyfj+n0OZyUK/0u5LUkVKkMv/G8oMCo2XCgVo8NFEFdVpwv6GeZe100eVtJXFkTdYQ7Otde81aHrdgdzs9FpxH7zMILSpQR0vSlAxy4ZyM2BSqjNQKiJzYK50vr0Gas0IDtq6nus1LRJhi5h0noHJSPQ1ZBOg1UFYU7sarlOEFIDmtVFUSnuogzF0oGIpUKvJSBeXbwu1mmi6SMpV3eSLZb3koNx7SZxMcl7SIqknWNLhH5xxa5duoTIyshxjBVUTTADIu2iHELoqgLMvctPoFxcFGleV5/SqlYd+0vgFL1Xw0nGoAF2HUkfg2i11wjAEvHHwagFIA/onOGJSrypztrIQ0nJrwQSaK+GDDLtB4K6W/bI0CjyNx2Cg1WvbussLat6krhwrL5O0pDJ6o9kGhSrNchfJmhHHpRusMgQd+BEqY9pnrie6p1QT4+M6A8gS/PdVA29H72h/0rXWFcCmSHZUyRX0H2RQ+MzkpHeGu7fz9tye1ttybRrSLoV9hvtALPZALkiYdPmy533anqRajvHQYpdZACUHWWhwpIr9eQKiNbvcBy2Z3Vbhg3TNj2PT0RG1Tk+gj2oBFmszPXXT8VniIl4XhUGQfs+gkC6vi8htG3wLxEaRIIWlmnCNRb46PIPEOzijRcbEi2oIzT6RWPH8nfRhltwUluKhrnZVG7FG5f4wwwtsa6MVZztW3ojUAyL2Ssku6MUQOy8FCrILGTp4bED9Qi4qTvsQxqxtPfBqfHk0vkyR7RuX5INjsk7fU6yZoHWOnORWHfyFeecrVuppHm8BMhpwrP7mbOFkKXk5BTilVeOHSSyn7hidfcAfZnBdJBWRuYNfuh2HuX79raEjykwSL04mTm3Qa3zMts91RNh8WuVmKCAtOHAN0JcWofrsOY1a74jVfCNOYvgkjg3Bc5xikzEenv1/KExmiB+AITqLE0ZKeG1rI+zYjnErzkvaVy7ekPh2I4o964zk0SO48FjB3k8FbLHKGUpitY3G8ANO8nKBVaSAgWzUduVAB7CCA57gbqtzyBfNmAZHLMZ6/aGa3arYhHjAM7rGl7L7MFma7+zdfhOJM+suirjRR0fafsc3MiCb56nbA4XY7fxiuVIB5zUPiX3onjthrwvV7tl2na1l83KbhKsGyi2j0yhdLtmIYL26k0nnPdqkmYq/ScBftPjOWzZ6rbm8bX0M9NRXWvyjdE+qv1HA6/gFEeZZxlYnq/QYHFybONdjRhXRev9fbBhBG9Xm5munYxLWBHRJhfmMkipxNQCCuJdDx10ZCdDHSxVJTgPEtYs6yKktyW0NoiQkZ7g7Fs3JZEcyUg6r/DqusiaZZoLQsR4KbFoEpnwiaI6RRIKvEplJ0K8hMKF4nZ4rEQSFMrt8LYxvQtdhj9B1Q0wXuDLBXv/f8rUAdrsCOaMA14M+BU+Vf4uXVz7DYViO3is9+hOkndkSvcxpjS+WxLPfdxjlDI6NbE3G8ANW8vKBSaWAgWzbNsVf37F9Q+KkrqtHfceX90XZYzl6NjsGRFdU7cazaKbx0n7Z/S5b5VH9eA0jzIyP5Nl2BJlZopQKN1dWQjXCzjU/iz3tHhpAbxfRasq+FlORZb9KGpikiUk8ZCzNoBRVG94RNuhw+JeHeXVk0cwj9q0GXDK7RqOEDc0PGXMqMFEC0YDG2Y3U10LmPcWxUER1PPhyDGkI6lF7XXNb3eI/zY77BY96FdgEaFYht0SaWHYpUcVSZcbXe6cSJFbrorUieFyQkiSaCFTvOVEkIQ4yAZ1W7GMxHnkQ5uwrdN0x7+rHs1Ii/pYPTG+PpL0OtcFlpTbc7VxHmt0tAuVWiuASGuZBcAUSOW9v+a/kbFqOW+5EcnkuWyjCrpMgFFHuUmAER3kurot06nmr7+O4jwrIYx2Qz5W6lOEqJNoGA83BQbRGiXZaZ+ltGX+wK3DJkWp7exaSxlYrtKqMuQg5KHU2RT1kKIk0oOHKZccbp9r2DBpSoRVIMBBPnnLp1H1xXlk4+ZRwNFbDkiFGm0RC3qO3Zr3WsS6tKRB2oYO8WF1a3g90iXGaVLg9bPcju4unSBBWN9kp5hM2PI3zMuE+6Zp6ihJYFVN0+AFvgCNjFYrMR/7LXPtxdCR8jPzQtYtq7OXrB2SKXsIVlK32iR0PohQdVskE3TwE82R5HCkyChXu+nCfIU9TvqInb947pwjnZccmjTqth3cJDA3dJEGlHWSyoSu7iYFFC7Pus4ECTSC4yDR1G0RKm2NRMOzhRGEIuqSE+piUSxvIbmfjXZvJoR0/0cKnwJR4ITYXgkRFHhiTXGPr5W7bkcI+7EhuD1IIZW1ikcrnPYEUwc7IGnvyE9d11qA8C0gUPofBL+6LUKgj2XRrEc+ZR7prtaUwY1fN8/MBBEqyuaAJWgUO2Qft4g/16vOmzWsluY3NBAnzakyuTSnAcKledeJIJFOcBzkukbI7L003ss1PlW0TLuWwsWF9KE0mTzxEhfd3DpLivaptfa/g5BQt0UINNGzK6St4HedyYC3xU/BvtoZ7KxgX2VzfFCJkBdnmm2idSQOtgvwgm+lREXWptEe8yRJwTEnTVnCPHmZ5PmlvrFLsAkb/QCTdAWy168uSvSLSLHX7/72+tUVzqDw++u/ea8FNhArdJ5+gHpKsXLV3NZIJGbneZJdY7RWxPqr87CYxnDa+ikau8aNobkhr2hPNUKm0WlG2kmdaUbYNTbpyFBDDkvZvTFGOKJdJMUqAsjOIBybpuqWxyawuuWxqd3hHz+1J+Gh0Zm0X+vjtkLEymhNIMW7yRdwcbQadST0K8A/YQkR20VIr34Pk4eiqY9qxEe3TQ2nNKWFxqv/WE3wummnesS65nR0d5dmKVqT0eyD9eg0IPeDsFGDXzYuIZJfJ4i3WN3Jm6UQJjqqfryJxF2eRA0XaDNeIgNQPcCFakpGHeHJ4+P4L8nihk6f12lJHAlfiry+n7jN/4RgfHrS66t95OgDvE2Dr61QqI4Ssm9+KrLFBPwhNjwRY1INH4P8YRIDmGtzEhFDt3l+MmVzw/tC0zV5fgsmUC663ZQogEMqvLHXfYMMgrJL43pdgrwCCf65UQ0mb3qSJaNq/BJWTTY+2U/AGjvSpyW42OhEo71qbgcdfdohXzRlcg8qOKUD/wKkvpe++ddUx56XrjlsnyOBs27a05LJvcYfYAbrvXp5S2MJX0J89EbdLbY6tvgEqq/wqfPifC3wPZuEeZUw/KiTPaWRHnmSZXTDA26OPWXlQqSEFMg1Jk8bN9i2IAsZZEsUXfMOFOx9Q98rZKV/Squ6UDyYKAO86Q5xN51VQwnHyRpQ1zdBPqZ3xJAzDkIGePO9goufaX0vDMYMLQzKoorr4EgtnPNNw98kJZzQf65I6Cxf7tWzr22KKFXPcLGiZ5siec+octeeXcIFhCu4oIXYqfItUBrKyBRGYGEw5hrOz6+jvquTDvalItnZEulD8VSxT6/WVtJYgOSlHQegEHo8VFD4mlwQery23KKppALzELCibms4Bg308LZSLdRNPM47W5uTGNsddlPDsMn2H4W1ood21Rc6mTKGgmDVcVZyea10ubbgG4gmw3ZY5uq2enqFrlBmB42BjHkRJvrB4kgCpaemvba7qWFQdPuPwrrUQ7sKFE7RmkJptxqQXKcLEjjhQuYgWNRt9X4zSirInvuwk04xAuVGDlU4r/rOkmxpIII3qkd4UjTriZzal4gY6xQ7iKbw2g2tTZPg5grm2I6dYmRtU9MM6wsytqj8qaO1c15tuIO4D+f2t47kgHLfkq3cTsIGbjsauSTVjudGVUcckQJUuSur4IO2ZKqHQTdQDm8h2RjjiEjBt0Oi6PkX7eNvoWj+vQHd6IOMjjytL8o0GT2Ed2ho9IjdKUYzyUjGjjDufRutjjg2ydjWxqbdLGGu04a3fiie8qwAiwjPWZ1XPbJoavxntEDyCvZ4HU0gLK1/wnR572C6GO7SNfkig0jNAuMHMrQC/oTkyYvF30pF6aiqigRHJS96ZUV+6hFRS1JpfiatKty/63DQKD2ukRxEWiuk7awaujVAyTrWFWq61kOE65VfyVsQQXolRnHQK9VtRdEGv1JvdkyXXbG/illsgj220qY1SAK7g33pcpMc/HstNsnBelDWaQm+wxrU8F2kq/YtwWPgOAYZyBMYaJZVo98ym8qBNpJk0AayyaJdZGFtOjhBbGiB4584RQ4IshlNxOOmPozH50mNLqJmiCE6yD91W1F0kOsSJA+I4hMFepNLunGtO8Iz0Dd8/APM0kdYvnhWn1z3sQ6u4xe9IvbONeRPHQhKQ9xsZIDYQQZAGQTIQgWleqJRxhBKB6e7eUUSOkWJpJMdok/jLzcuhpjrQLVe5avF015B7Jhfwj/wm5H+DgIGzWEdaNZBjIRi0RZBLHMpzuHTJQRVkZ8VZctN07tBOv6FxO0d5YAgrAP6y1N2U9vdgB0/b8xVDe7uvhZTpKg5WqzS3Hy196+/RHkQhJFtcfLKbdEVO1+LmqKJwpaWQUjsTilYoLFZEOXsBG1CYfEUPKbDzqZb/xF2tgtQdvqN4wlhe57nUZGe4hgRltE8kHHCQuZJsYSWJCwRD+GwiNE8lnGUjl0QxRvmVlgXrJS6oeFpG0MJJrE01LBR7xgLDcn2EiWQud/eHlnd+a7QiuSYVwVj7nKUQ98OydUarbX+jvsgC3xOpEANsmL5Rov3sD2OLs/lhP+2ZhOBeO4VOHnVWZqhgUV4sx3x9dO3vBv2BXW05J8EyzsBv9cq17K6bMlbVRAfQ7aq5eyb1fCJx2j16GxJoMPiSBctqjDrQTtUb8GpQ3uQm64Cb+THo8YNsxlDgsnJpHjXfe6lzp/vRJAaYXJRruVp21XgoRRA9+qibuiBYwThF13sHQTen0E06bhXcV48/ZITzpoDlm2IpXYNluFmGUJyWFreS+uvkR4pM+3V2l35ZjOVlWS7pYtV+ygDE4M3f4AyBfkmXftJsbpNcxCoEZuRH3hZ3dbVQxOBlQ137+tUdwgap5EvIG/uQIInsbxAs22MOovTrKNv2nC7iXQkFraf6SIesk9xr02BChLKuUYjW6LFP1jUVoc4R1WVLnO0ilLCR+cL3Rn0uzjHwn2UIPbtO5459ScX+BKs6024ilzJC3am7eTxEhKZyUOcYx/i6/zW1N/uCNL2vNeZqOqkahRz6HZ7zeZ3w+IQNAHbqirHmnX9mCcnFm2rHasWtXwG6+tipVex72BZHE4jpqv6DJupH+OsiW8svmp40AdHF+gdmmiO1mv4XKNPq/X46fFxap4/mrQMv6xOrZe8LossRlzITKdX/BJyEK+uMtVbkPI85zMeqT/Ito7rCPXOVouh8ohJnketW0Ba40YpeY000NZXORbckMTwPETcTA67iMUucpSlwGA7RZDUM7m4R0v9EqopdWleY6tLBO2B29VtKegWHkezQ4vIEB1ZZEV59UcDSlhdLm9HH1TrW1r8A60EOrg/euxoe910gobOK4QJbeQwiZBEKUCH5DAR0RBDrf2c5g840HfOHHau2tb26FmWeqedsua1I12nsOxc4d7bz4DjsNfoJFuc+M8Ytyz6oGjMdJ6u61AvQ9SLAcbQczxQ6aofWPeGBd2sazmEsHIVYDF9p5smJDa8UKjpoc5Ot48Uwozoc3Mef6na/w7yQt3WRLEKXKvfS90pzkiNXlXZaY7hgxWkK5ggXokzCMOxalFp79RGOmT8XCyL4VBzNgckP/Z6lR0Xi5cp3lot8hqtl/486iusn4ryYYrgACSYXsgSPmnKEubJS7hnneA8fU7uQb6E5LFQX9Sa/UPZiDzgDo/wRluLCq8zAYvxq8Ya7hukODPmkXHgiiExUPqxsKBBG+mmWx4Pu+GntYvy5U2P5LCjqtsy7Ki/jrK39RNjeLjk11GySdhnC/+b73byucAIwslqY7CcFeUKTTp1N22s9j6nqxSx2HXRaqvBwTZ4gVX32+QA2qJrz/wYiWw7zRdoZqNrWG7mzRdAbuYGWjkdloNoVrfVkj9Uw2qxzGM4efhl7H1093AFidvvNvMxuUn96g2D5sCN6rYIoUa3MSLxqYWfX9PK+zhm6pjcfwySh/OcRGleNbfUEa63v1qB8bAkok7waC7wWBl25shErWA9adYTE6xgoRorxPRGqxqT+KYNoNbjiOK3pq+bXMMVUqeDgotk6A6CRN3WPNrZjxQ+oa7eT9+yr8Vm7z5C07AsypcIvMyjOvDxgY8n4+NOuEdgYw7TgYsPXDwZF5OpSJOgsOVitSryNzymAxur24rjPkIj+lgWzXp6tkQtz7AKDa6BkaKwx3QVHCXZJUwK/Gq1u8cWhw4gdG8GJIcVN/aKm9Nhq42Bcw7yPV9sDsHCbw8bw9YGHlWGrckhBFNbARZkYX8vQ1Zh8Waof1iA+7wAr7JGd447Uqux8id8BvmyAcuxdrKr5B4umgxeg+rB58QHVave0EgOa0ndljEwZBRONN0Ssm3WGBFZ5IvAlyxxXU1P/zYOgWLFhNbF+lt+WpZF8Ku2X+Fzfdn4vMbyGZCnQ8ras+5pvvBttUkSWFW+7dJkGy/M9bz6lC7Qao2Q1WZZotFeQKTlOOYQ6uuaH0IdN/Lk6O4uzVI/F9hQt9r8PEh+dVtHiwWe8uDQapjBCNf7PDUTpRnRjU5uQfTscTNAUcYDXyjaDQJE2KEcBBXiv/4R0IBAWAbTgfXVbRmUHtvrvK6b8UtVwxWiwxOxD6du/hKTbuyQ2PG8yx1zf0Cbd175xcAIK2VAdlgsh8WyT4vlrCibVWDEGMFRvRFQHdaKhmspOn1s0qHl9vdMsV5kBoNzmRXrNNnFqDOBf6XxZmooQf3TgAZmEkwfES0GE8x3wbJ4DqtVs1pjBHZiHoq1Uq+LWJgQf/4DJtoHYse584VzHk5/sIrTH4JgG/S86ozZ45ejpr4P95lRCC+R5rBOKb+ML86RZCjNxoocMbRYuWHh6VQwSjBJxhc1rGu47mbp2PSehlb2fQNk6jkFGbQFECcI+vS58Ll3hWot0Xp7Q2E5SH91WxSZcJNbE5lvfNp7JBk6kmDhyKw40h9gbgR4+lxfCSY53FfDRn3ElW5IJlRk5dreRhclLRljiBMMfxAp6rZmdloYPDXvt+io0iHEf7UG6dLHgdHtztWbHseBdb15Z6yASKOZMlLDOIXPrm2x/BF1SJ4GB7c7WUQBVxOGZcihOqxG79U4kiQ/TpJTNGVZd6wJdRE6tl0IXf+Rgiwirfdp4uvaSUgS/BRUeI7aqNlcrmC+wNc+QZa9jCRxvsKn6jPECybwAGMQPHKMB/mjkT9SigWfaBDG1gmVX0fJBRVnVUbdvMe8CXJyD5OHogl6P6J9E+yNgOqwaDSLZpZQ8p18ZOjqPl2vMXx3XzUW3vPqGjyfPkOKGr6oEKL+Tni0hwK340mlWFqL2l/GSw3NEz9y2BuJDNu41GzrCE/5WFcMer5H3kpEIXx428S0VfMUC11t84j2w4MgI0lAe8k1vczijwachZ2XzLrEN4AxX1+AF8wCn9IKB0r6Cy0FwoPUUrfFkyxUaJGZ2NKQLX6s0nWm4KEbsfJmndnWEdaZdcWo6yzeAjusLA0TvyQZZN+p91wNGNEFLNNiER7rVYOM4Au8oEiu1uElGcMvEcuFGelW0Hme1inItlmS0V20kmI3bA216GIAjfKKhXYNcVDu/1OLZd5kc5bnXmKZZHJP/0kecyNk8YqXIDgI8BsB4UE8q9uKk8/BLyuBBA/J6j9fQqSh/bmanio5klIY9TMplT7CyrrZgG/kjRpKEKQa0EBVLyOroc8J653Tj0V0ECTqti76JMvvwkTAgOf9PE5ae1djWVQVWhZZOJfxqA58tq185qDVhISRH8LHDXvl8jN8hFnwTZ37oqzNeTdGikg7Q+DxGjcYc+sh3cLIYUXKWHzDckRU0L+fGIcQiMlhWcJyirYmfOvIdE8O/tG0b72FXY8gjyJ+ApU+ha4P6fwuAKgC/7UB//EC/a9g9yqYR7Ld/C5dNmVrsXZ4DiJf3dY8UZl7mKuWiq3wSvD3/IbCcOBYb47d1UzjJBmBD+fgelX734FtNGuf3GOKdCXE5OFPsmYBz/OrFDUJBn+bfwTYBagqfP8KFdRRAg16hKPT4jqttc+JxmllklD4L7AG3T04nbofr7EPkAoVn6C9aeYqcvT+JcyRSD6qfqaL9pAlCFuL5b+KfHw6tE39LMG60/+FvtvUR6b2EzNvYSM/LvAGF0G+lGlREqkcdJ6MB3YNdGmlfeZCvSc3K2pHbq+s1DVI7vFpHGZXZExj13q7Is+rswwsq6FF/8sc+pai7eqIJmhysxdEQ3pW2Cn4Ale3sOzlalbcvn5FtPXfX/8iTBcDe5ZmkHgBkEEMh0rv9JXaZ2M62PfiNLUTQn88qqoiSQlhOhz/3sAGLjga3uDucEM7zRevWlNVXWVj1bYzh61hKTTiQkTzdI2ojFjp99f/lzBQq+aGs+FNcx+KpzwrcOoXtoVf3rx595pXxL7lbVjCKxzjgIMZT0CVgIW4tBAxF+yXbrLwATuSQBXimzSvRUUvzZN0DTLroXAYLJVF3MOhLb7kA1xjKZ/X1tNn0wkML+/I0B5HQhPFfntLcac1097Qd+NsWJapYGBYTzZlm5AwKdNnro2t4lLpSKblUel82XSBvzQ5N6dSi41mMTexRxNmOmFLtyphZ82K2Spu1o9oNtErmVObvlDVZmPv7rzyIiVvvt50/yt5Wg4uY2QW0oWDFW1I2FaBfH6W1Q9hAj7Vz5NNB7oqW8OYXTSELdPwbzGPwZjc+81iG9vPmOwQZmBMdp6sGHPz7PosjNkfUhhlJQ8oY8bNmYk9Gwp47SUjsaF4zF6MpOrEBCykousuSLUPadWqwUdrNCnYDdiNJoWVkpF0lWRM1cO7MJW2DQmDWTJuEGm6le5CmL7KeGQZWrAX+xFo0v/obtVjrdOCLLJaLpSJul/Z9k/mEhLhzJPoJdasSDeBjLMikU0/+vpz63E3iG/SR1i+kMAig4bFAGt0OA/ljUUt4zW6n6Ntn7reTKeFSelsxVVUvbk5a1AHhi3JwAJCBQ2H+ehnymYcttGtsRSUo5iOS5XzZdMFOuHLVnCppSHLw4/Moztsy6rGMAOD7qA1izP/3QFiFJVGi1YGLGNMGs6FK6X457BudR2ZgK90dN4FK7djamYYDE8YxJKyokYK+vKcsUkJ/+na2hq5aBzRdALSOJ82XaHrbRVnW+7osjoT8fMO7+66cczEwDu4y5PkjGm+/ALr+2JxcwkRthQH0p5g34DW+WiuKmNitpYL/1q0J7OjSGFEb+RVjZQ6NG2PiFHgTY9e2WkZtJQuNKATWaQt2FNi/gWtHcEES1k7R1amZFtltkXcP01tYkYOTsaGw61NewbksdqzXjy1XNGHCZhHQdNdYhtW9JimmV0tcVmIxS1hJK2UjM9O0v5MyFRSWtu0z1Sc70C8v/S6eWRCxQEiqPRQfLh663AoLmKWMJYd0/qM/TjNMqS19A0Yu8nCR6cCh96eFOLq8qBGd6Njc4fa1F++go4ew3URd7IIzcg2MQXZ51egTKOYQGKZ5stqP6QyOcwir9qUWO1lGmRekJ5vMk6peEhbS8avsgouTKtvUMK5m6RZ28a5VkOZgH2t5tCmH3Riull4+DgrlhdFVZv5VoCU8WoP5MKfIuKd4kll9yfgQ+Wc7AzvdU/a3gyMo+MSHljFgcM7uW5MKKCX8KGKwbeDD1UjmIgVVfNj03xfZ26P/CV8TOHTJ5it75osxzovU2Byzhuqa/z0Qk0PZ72pdbXfvhvd1nG128Cmc+RbzrODT7+tOBv742fdzmu4MisCAqSMqXsgFyYWEe+UIqDs/gRcqZyTnVAEcO/7vWNgHB2X8MAqDvRQBKToJXyoYvDt4EPVCCZiRdX82DTf15lPESiyzCwFGSjptl5kTrfGWYQ7JfmkXZ9iL5bNwU5IPNzzo7x6wlEAhZAojGUKCk7FZy2IK7fRiGWaoYSBt4PXJB2fiNskc2Gl4iH4WXntR1ETV1VSlIsbimN07KGoo+JBGtyVE1VNKbhSzu7bwZuGoUzEp4a5s+XZttZ8nAvLVVrhDE3dSHqXPx6o+mxMX03Kv1wNJ/7Vt6Y5GcIAI5wg2hFJDh79/HAmYpw+46yWIDtq6nvMi20GMG6ClLSxqi0jla6iC/nsOrBTh45OQ5pASjrNsU1/Zj+OPCvKZkXcrkYGF0Fl3DxAubCuBLUTn0YJyFF3YgLOUhN3d9iIpEG25CMWVslIXWJmR07ikM/ESvJeTMVLcgLvDjPdkH/bJ9O0k00BKtnImYNopBL2ofq2dXumqv9TMZ5kPmya3tTaBiHWco2FkGmHPIb4ajGrmG9L+U7S9WkFHjMf1ny3BeoXxS9mLYkacHwVjEKu4j4pX28JCyrGMKkOJ86PTfOkwmys2L7zaxlJLAOWsWL3ZIc9G0oR2wcQR9LfdL2YgJF01LVpnq05M0cZ7QEWLCIX7abPQ973ybhuJy2GPs/Ud5zSv3/Re8grpuISbS1dpjK6gk8+N3mDmtRj28elVkOZgGmt5tCmH7OnKpOOpJV8TvzULuOpuLdtTcK6Upm9pXzLDGIupmXmzaYTpMK8mzsJ09HzKAen3N5d4/54vLvDgoqeT7XDi3OxS8xmSnciQI7AcLuY0ETZ+0nZbgeTl3xM7+oTgAMiUJfvQQUXP9P6fsNBKnYx1JOxZV/FhStNzajEooz7491tt+zVBLxnOQ1WnCjFMDtjMkrEwEImfpHW0jGlr9aob1DCnqpVML8MtRrKhDytnUObfvR1touHv9NLzI2RmaqTcTPb6u4oovaDmYuppfNp0xmm4rxq69eihjY20gZOqbJiEGeVlcK7O6yp6PlUyqo4F9tvI13CJ7R8LgqEoOrXj9H3rqskY0MJvAtDapvbKS+9zUgm4Fab+dsJD75sIHaKgLGmtdiT2j8uDfktmKCkRzhhJbk1pycSC6bKmel67ZHDujvbi7zjE6xX+Txs/+bS97u1mXtWMfEFA61jOldfnLwBWS4/BVdvDwtKhzAhJ0rnyKb9AcG84QV9xl67iBUOOmKwAY85JOldkNas6slUurOKxrY8td6CyJVLWDdljl+9gjY3I+TgcnWAgnTTnKVN7JjOrBvDJNqybp52Qk/edNpS7qkqRL+0F1MAOmkmBWn2BJTtXnbc5IsMas9mNHXkWgoL7qapqJtSnx9SYxhts7Do2SRqiHEqbHqxqTWjisyNxLhtKGuMzoS7uX8YhzEHv+7kLiKMwhRWoaowOqfuYqyFaRBzsOkORl6wufFMHCqFNmZO9E6XuJOMqR3BBFypnaMdYsmrNUzSu+72/1Fdl+ltU0NbFtXX1rCsvKIHCxt6sIMsbTei6Vjcbo53geXlI/m2xn/eKDhSubu745IqGBo0TsqGR3dkPmarZTn/UgkY7hQaiz9vWHkWpRi2dCPRMrifbNeTd7YtR9st67UmX/rzr7jwsc++Y9nwjf/6a/HMvQr7bfkaLDX54URYzbrxWCEMZrUKhorjZTzrcP4AZQryepiWk2J1m+YE8AatmPQRli/X6UqT19YNj4ZwGhQeNLXukOzuJT3w0bywnh2dTi64zqlNz+h6cy9+3fgsDToLFFvB8Tts3zkMazuWxg5aehaj+vcGlSDO+J6nQauCxrMVS4PpkGR9MAOfczOQdXQ7OF42pzY9o+ttG+/77gAeYj8CQ++TgN8eqb5HorwfitlTZ4tgHgbXuuOEMe4ay8/hfXOdb4dFsDXONn5wP0DWDCMUuNWRNbXIHFYJwRNhqej7o142plW7tavHasDzrSQr/nBYVTyKuReXk2lgq//7eNG2SpOfWV3fC5385gqs1hn8UDzlWQHUmQ3k4JG5i0Mucxv2/Rydt+R9mZC75JS2Og1gas7GYdcpLNGoE8i8OKLkMDm4jMMGSBceU6B3fP6E8Nnce7R+KBOwqH6qbDpA19sCBjU5IgTIEdhyF90Lyt5PyoS760KgwvHbn5YeMVU9zX6svvRgsTMr29slZrUcy3RbvGkWbXrCVNwidnZn5OlY2Id5Y+qW6q7Mwnv7ID4HS/0szWqc3d18Tc0BhxVPctWDWFTTFZ9rbVsoe80jnGMtmFnAXibPe12uLkqsGKUrUL6cPif3IF/CS1DDk6ZETSQv6ihiU01pzDCu5BQcbGxFaph1fR9HOlv3aQLOtJ4FO2mtRLMdDEr+cONMpkp8lmTRz8yL0s5MzYRSgjtwH1N/NrY7BsnDeY76kjxcNbdVUqZtrK3xNrGpoowFFXVcmNLY7E5dMbYdzQS8bTufLs6sreNqkxFmqDcxT++iT8FyLDMy9A5ad0dJJnm3XcnFcnAZ8w6QLuyqQO94cDA/q+rHMQGH6udpZ04Nju7u0gx9gTem5EACpJQneyAnnhQwT/6In7ILU3CSirA2bc+d/Yy8XummfKqrKB8o9d2cNU3N9ND33Jqimfg7oSOi8T6iFfMFsT5YwpuzslgZ+U5TR+4SpcHdHKDqhqZnO4veTOKcNBLfphd0vW1hvuvClfU2NUZlPKqZ2dlO7Mv0TCeS3aYPm1ozmhB1+ogm53OxvKF+48nU2BHKOnJjYgBxMyfUrciUOK7zW2hWGMcziW1hnDsr3ZCtuhXsaxSVMuCRGHY33Y66EUzMmzupOp7cw+ShaPhwe+GzOkuuJQJp1lxpXaccuraty5haGOPWcbfr8CbgeNf5tloFfOUZ05cnTYlIsbwALySt/3meYrymh1Q0teTJzNkKbvnMdY3ZvyQSRa+16swEXGk1A1b9oOptDRf2b+YIbGPLIyoENrzp9ViVZfMSbjUtjfmFsuvoZmB/03zbdImvO9tq+FwkIEv/CRd9H28+g3zZYG+AigHVVWQcL0C78LqmKQl3Dz3fOq42j2MCPjbPm00n+jozcqyFaWcy6RxNOV8TbituPc1kve2I1XZKbpSiOjWqAcs+ym4Fyvrb7T9gUuMi+IzmOyEdA3le1ATL379X8CQrMRtUv7+uy0YUmRj1Fawl11er16/aYuUdYIEZeWSwgYvTFUgzpNmD5B5vI3KsEkAj+v4SpAzj5i6pfR8NPTOiavufJEUjHyVdbkTWbbpfYH1fSEfIAJjRGaKhpS0Yo+BdG7VqxRatBpmZddJKOU19mRHJCajhsihTKMPSFb6YR5MmdVNKcXRFtgTRYWIgrMmD33tKS6hathIwM2oqgaEUJ5M70m7g2olgYSzmo4X/AvLmDhBy6RYHDWZEbcLphKzfg6TMN+z1BiRdvISUcEOIiakjmAVUq4CUmYnev4ClFncshBkh2v/wzblHpAlIe8YAWBObbLTyxcCBGFEeZ8XyoqikuPoyI5Je05Uh2ZgaJiRY6YZXNbb1LmFF1CApQgmcEflX+FSpRH9fZl6TRZYd5dWTYikOpVaIVCismQDrjjoOaEMETT2B5SqtKqSjtXFz0l5xMGYN5BltyznIjpr6Hiuabc5odQM6eGNjJHZGxcFDoR2a62KdJko8pNQGEVBhsOvFx7Jo1spekFIjIuI4lOHovLCWO+93fETfenHkklUCaBazH9M7tBGWCyN2CaA9dh1CO/qpBMZQaIfma1FLRzcUGtGIb5DL6SV9q9xiz1NpVpvHly2RqCjGPhNtHC31yKd8mMwbrMa+sS9pyfvHv3hmp57Jk+JrFDXVcwymMWiS70vHo31lwasx+2ZsiUey9SspRdLk2yHSJLXVNKDNTezXsENrtk3Y4HZGKs1t59D57nzc0NiQPUWGmcpkY9ShC7k12V2/NKpL5D6gwjAYrljadOILIEJC2Zeu3EyYe2SkEpreylU4BsCswsuv5Ug1etXVKgeT8Rqu1hmQM6QMztaB8aJDzMNYyxgNTg7ErFjAHCKO1a5IHsZs+vY3VqS27+YykQHN91KDZig0s3lyDxdNBq9B9SBlc6rcPLT+CoV0aJs7KSbeg6BC/PQTpst7qTrAANii+5AifaRSLBMexk5vNy0+yaUJIxPTobJyHmbDko3cNsSJyfmNCt+zR0X8+np0bWCpURCs1iBdSonXl1nMLyGFVkqxIFbOg8+wRkaqaYrlkOaB84FHUgqIcWKuaJX7vCoCzqipy877VbaJIp7DsQ0b3Ha+JuqAV95lyYG8sbOYoRaaowEWwjyFZVFVqGKmQcnDWIxeuvptVj36VatUoLbIrP2AZ62nfFNuprfSYSP31VAHm4bjwZuzFGteVAXdGWELzZ/Abg7F1ZWGE/dhZOrzSuGI16qB/gyeaoA6seTP0VkKuVHvhj1Z1NKOhbUaGFPFQDdrarFIJbTiTlNj0ouaKeZ815bp6EqurEGTYEwWpNuRUFc3ZR7EZc8Xb4ZzRpGiCkj18OQVZLQTjkE1RFNglVBKhS4Clfpdw0wlWa4P7Xi4JB+RqMQl8RCxxqBSvwfpuEiAUY+BB5XRhN4WNeQQUI3LLr2L/+Zovc5SuLgu6H6KRNHCq0elqyYjFhU7oaGVFquEbuopiEK5DX/a0G2AdhlfXykmzQac4y65oWF54IeGZNIKFiOU1YtAOClamSImHWcsAc++/KoW75oXYmViWP4QrAVHmJHJSMQG6sSizSBDN6aGkj4irHFYQhUNnSylvhLz2FKMb9isLwig9qMyawye5JpGaaD93zrFQQqnHowMXEYiLrJLQx4pxknUTqZlNtRMyVDqOkYGUFbVsJg9GY2NSEiqxR6JruY1KgV3G6h5rYYRcpoly0b03VzCqi4R08MFFVAoUtGilnqw5soymgrBiRpyWrQg2zY2Iw4nKx3YeDMEYEooKQXUDE0GL6UXF3upI5cU58gU6vOKaWjDg6hHwEHK6EEF2WpIwSOaiAhcHKyaFCygeRzs1AaThUUnIY6e63z8EP3FIKqjEk+ECKVxIAjAUm/EJrJb54wQcUmooiRyCEGO0yxDMm4IENdQhQO1GA5bIwJ9OIQTEakLA99cA9RQSYA1j4qvoqPTJmjdglwCYpkcUk2AB71kQeWb+70SoukrqAeorScjnyIsXkNDfRMSQlLh+8GE7O8MaIknAqlHI8DKiETdYtAQRkQ1ATFOihU5CdlcppDTQ4DTj4MHD155UqQS+ihJ7W+6XMLHFD59gtn6rslyLB2ZAo0VY6ppNDgMCIKpatmMRrqpmvEgd3/RRbs2RSD16ARYGb2oqzcaQomoRl6buMGe3zc3gOT0EOD04+DBg7lIilRCHyWpfdZmkWVaRmEBNEuAhpM6C9rbULpVxKAYmTE297hu2vtY8qHTIPqeU5Cq4Q+3ygxEoFHJ3CIySnqS4EdRE/2BZFOn77bJyaEC149HUStc7GpwK+immAIf6nH35W64G3sSAupraMaprSjlNvHCn46Oevyabasbazxrz0hEBaSFaWYkmqOpNzmRdBcotaafXUX1kK3qyyhquCKqobJdkyObi8O9Ui11JVDqcYnAMrrRt101RJIgm4IiJOrSTBIOzDAMFlpJlD4U1EQVDt0UZLmhL+4qaELDGEZAgSqoAcxkoJFIaMBcRI7JHN09aC1ntDBW89iOJQ5PtLjkxBAoGiQ06OvkOrFBwdmsdWosMUQHhU7FIXICe9CmTZBp9uhK4dSDkYHLaNNfl9fQRYpqZC9u26ZOnnIQpu7rpKg1DaaSnbLcAjebtEjqcDB5BfWwtPV04WB8AgOL2DB5G5rYsNEo2WWCsCSjJPOweXxs4uERCMgmGzYys+8SJP4WJb14EMP62UAqV6HZXcZjmoYEmrASEcim85oQEmdCTBMu0mcQublAPb4HFVz8TOt7KiOISBpTFfXgDDVlZKOyn2ioZkKsYqdYzkVZYpebTXIWNQ3lFcwDldbT0c9BMunbkJBSOUexKPmdnlBrcrK1HMfLVB6TsGxDo8s9nJ/HIPopEIOc2kAqJV6XLMgk8ShMY5JAklBIq45q4dVD0lWTUUqRD0lDNG0LI+uxsraNK9RcyW2wnsvGEa/vXHnGbZIDMSUJOQj1uFhAVeyl+Qokh2fMhUkn1LrZpOlSE4EFNI+BgdeRxKyiyVHKYudUVPY2nfs4WKNHgQc02cAcfJA9zeMa2anAZE8zSHMppE5AyCrIpQKb400rdaRIRxbam86bWUgJa3FWZMFIjqdPE7MTnzrvhk6hLZNHanCdCFHWkssmIeWfVj6pkauNSSadeHwq6talGthhkLrVGUi/qdao0LDGP6GEdRiXxlsRSLFpfBdszJn5jhAHqAkTkMHHjZ2blkTyxJYWJDNUNA5WX19z1UqZtNNMYEObI1+/0mQqvVHlF5Usbw80mvXpjk0qFPRZW3UCwqMDMoXajimirxN9+lnXxaPF5svdegpPuMy0HbGeUwVTBSQPYJL0KqeMATOSgIYOzhxA41LLqLb/saiiyRlsm23BGoWRAraYNJTWZ042T4J1F6bL7KDrknn/tqkdRBXzTj7mnEyqROk6wj7g5TUdDIogqtCYZpoYpgvSRGnMg2hjTZHHCvFfFh5rwYvO83J937pWfbWu6z14raI6BrW1iikPMyL923fBFYUOc6HH40wmLTqHOepT+rpPlL4H6kkzckmA0mm5LTjKflsBb6d3ziSqb67Aap3BzYuSaupwkOYhsRWCKcShGzkD7fCSBHPvQkYfBaR6QPIKMvrQb11oKKRAOMEVkU3Lmi1eBLIZimYbdybLpFs15edvf5q1H2UV46pQ1dSsNs0Rg1MLUxPTiYw+BByTdDMRjXvU1nCK5lLdYfBqLFakFh/zdaG8pvHJTuHwKz6IA9IVKF9On5N7kC/hJUCm2vBOkMT1bKyk8fOa6soTWxWmjMlmvNItZ/NSUlxSkj+sachCWw6SqRSDaizCscmleJhJewxsrKMeqamqNMeK8pkpXVYRU0MjHxGr2tdsUaYq7oPVbFdRiTrN1jU8SmXUtxWQ6oHJK0iztlHPZunStskRTqBvD+9b3WgCh0QgzVB4WClZqCe3dGQRcI0cJCQ8fWW+JOwq0tSVlJch7VecBvnIAox94OvmrCxWOtLpwHW6mLKWXPHjniXTqnlq1NOS7rpwIBwFbD22TZ3IRKMQj0wy6sW2G+H1NpmAV4PrhLKyllzU02/WaYW9Gq9MvgkP2EUln47ZpHB2A9OxmBelJguolT4xdyN51U4SYGtbVz1kWxTSqDXVO3q6cFzb9mRklzwHGCHsm30j7+Y8T+sUZJobKLoK6pFr68ljwYUX/rTh4Dr0416Gkr5geCO+PmgmprKu/cBVKGxIbHtpyrJFCdWNk+qbpJV+j9GcoVUOrR6yupIyNyv/jKSGoBrsIye1M+1IljuRaQcy7jxj7Di/vW0R4KBikOawHMp+e4sfLF6B7sNvbxFIAtd1A7IvxQJmVV/Qv+y9qdl9eXW1BgkW5//j6vWr51WWV7+/vq/r9d/fvq0I6urNKk3Koiru6jdJsXoLFsXb97/88q9v3717u2pxvE0Yu+43rrdDS2htodnmSnG69QU8S8uq/gBqcAsqRPGTxUoAu1qBsv52+w+Y1CS6+pmTJb8NVO4b7B8kpI8rxZnDZVg/6mvh352LD7dI3GRvcNfe6A5lNxQ9Q4PEAoGMFyrOTcXqCMEVWjyg7JdO1/3zBSJHkTWrfPM3z3/q2vhftn77xR7DB0g980sjYgoc8KXVOgMvbQ5nDiNb5Iyz2+klKLsSe4zn1Qd4B5qs5oi/+Szi+u0txwE8r70VmI2TADwHW/K39CnLMEaXoPTieCs847A+1TiPiCuyx9mJMMyh4oIQCu3xXoD6nkXWfrHHgJ/C5YfZf3NYSGj2uQVEvkwpcL6kK9ja4zSWzdetWXibGI+QtaaKYrFYXuqq46yovr2PTcrhYUvsMX6vhiia72XG4uTL3PspoAzEd5zmAL9jI0PZl9lj7a6IiazOFLhJgFxYfZuv9phwBtK8EuQb9dllI/2KE9yzmyj5tDXrmHmjOdK2GbZZTrWgL8oUGck1x9Kbrw7MVxYrjvHIFzcM4uax+WqP6bpgceC/XWqLvei/2WO5hOvshe/I8NEZj9glpsBB6JxwsubEpfZxkrDVyQcH9akh5hunNvUfHfpRLDiebb840KGEoIaLb/n3mhsSW+IwNiyyW48TM7rNZzdckq5Rnx2EOdG+E5JakJcWfJlTDxf4LUOQZS9CJ6mSrRHy9FDDpDyNyUPM66uPI+fbTUWceg8bW5RETIE9vk/kqSAaUfvFYfcqSg5D+8VJ/SxFlWnz1cWAq6qnouRmafPVYa5ycJvBq4qfr81nN/W69VcgqbZA3JiCrBK1bAnI1qzbzrvevwkasnAZVB4r11B/JBWNbvTqpaqhREtSArno/EnWLOCCDhM6X1S8BaAA8minfX5T3QRV7o6dfR5W2YgEzMV+Iz0kuLBV1Dml+enWgLn4RPJ01ayIG/No1aaHZr0jYrkDdvCsxy4pt8fe1uhf6FUTSge3PeLIGBIeJKEM2H2EljPKceTYpgM8HrbEga/6gQiMRBd44COBDEqkQ6mLD+SihFcwg/iBat4XwhRtL59HZuwYnDydl4Q0zCOhPrsuAwVGodDlsKM9W+TPOfqvTnp+Im4Bm6/umC5gmaAJJVEMMpx0+ZQHDVf3yFxQHm+KpU6uWCRa6egmziXLlTpYTekCXt83q9tcsOi4InucP9IqveXPYoePDuukuc3S6p4XcdTnOU9043t8vq8XCoxsybYJ9Sii3F+ATyy28UgUorsvcrHGSjQy8mwUiXGS7gsKGOcFeZ4v0sd0IfGxSQH2RHQ2WaZELBQ6aHeLVZp3T8xymh1T4s5fcIXkkaiFSoqd6Pv0Lf+EbOwLYdvky1xcbm0dtXCVQzhYkrAG/wZfntp7S4wNyZS4YVTyg1Dohvc6rfltj/rswFtZVjwNPhGSzZMbvRzCoYX1uiwe4eIS4CdfrxrurE1S7CANitqAXg7h3vvrogaZnD5SCK8xqBtRAjkfYF0XRwmnfbEl9hg/p6u0xh3qr+/SSIVCh54+NFwH8QcXn1De3IGkbkpYoh2t/ooUS15aqGDsW/mIuInF2X5xsa03r+qwhvXmu0N/ujoypYEvcznE/aNJS/itvsdZQPp7quxprgzCuYWNuiHHz5Q7rN8GyS2AX6JFisbRYsFh49eyEdopDHNIB8TFYQ7f3eN4+Jmlvzuo/3nWLk8q1w9jBEjKnXyy7XL6dqfAL4dwp8bp8zotScTiB/BSySnDw7i3Qm5kEQyytaWGctBuQMVnkGJUG7HYQZoyNfnei6VOvcbnjUfLEkJRNxVL3Q43h4rXOFxeOOXkil3W5XD9hV+YVIGL/OoqnbwkGfwM8yUfDyuH8G3hApZpIcyjCsajFaJgEDSCJJZBuFAeH1q1p8GCUGSKXHCeIT7oD8N4pGyZi8W1SPFKBllf++Qe34fhrS8VlEv/r8Hz6TOytIRwfarABd9pJdCWfHIIIwPPJ8jsWxb4DJOLJmOLnHQyZJud549oxaLK/amloJTJgZyi3JMHuUeZK3J26JH6R48gzcBtmgno1VB+LckHIYdwOo3VYBdLHayB4qkde3d/mZ9cWbmTlZTevRB/x1lR9v07hsg2FSwlNaDDYQdIHgrsQsB30YTDDr7Q0d5WJ5YRDG/7HDTqNokrpDtml8+7HMK1hfaoXdcCD+FIN7joqgqhipJip1WH953j5uW4qWvhrphQ6oz5Z1rdZ2lVa9DzIA6UaWVNBhG7XyA7TPSMySEcjh+QNUSqpgkf7s+UOAVv86iccXzLFhI0m6/O3tATIaqPKXDYg/ArECCT9I4t8cN4VYMSXzeFODe/GGerhfRr8TRfWLXHwzlwWOdePM1xHIqM0WQAzjFIDBYoYx8toHNUkkV7OkAnS4zO5sqZYbpEr2qcaL+GlTQhvmQcRmCnsfSn69XRep2lvK0gBbDH/xOmy3tuofffHKgjsfPcLbuf6YJH0n1yoJdkPJ+cxzPsEXrxogHzaEsnWJRAcx7ERw0TgBkUYqqGj7sZHKAZ6/CcjOA/48rcA4dwUgLxmjRb5qL5V7DbziSOCrHUA/MXCKqmhG0ifSl2BsKjBVkorFDogRf/0OKmAVxDy8jhpejtEwqdQ9ZgiWPu5E4iBYhnG5gG+iYGCO9RbJ6n1I6EBtuaMJ5h4w67d95H9LkH8qirjhPJg/8Ni1fpeyw9e+DKnDzsqthGrmhbgib72jLxw5e5+As7PUa0bJgSe4ydviLgo787n45WJ0WzxtcKFsJdWrHcQXdQYPXD1s8COfonyr+KX1kIx4iD9oytfZhOiDigC7dG6nUuc+yWChF7vefdQ+ypq26r2MPxciKWzVcX5TNuFqjjokbGuhKrpNjFzZkCwbVJPrm469q5VkX3ycoPYXJ6XG1grOpUTCx1wJySICQB5eazSy+X8Cr9p3DDsv/qGRZYXRftNR85fhOse/+/yY5DhEJHd/MlfmaDx0kXzB7iOrLja3cCALfRzbLftzrU1CP363+k8OmLoCUKhVujcHXSM/C2SIvE57aIquY4ylbXnCzFF1fkcmLimslOKXZgIU/vxRS4RLhsfVau7twwDhcyuPyvLk3NkxEvnsZUkfzF+Mwes87QD0+QKkEY4EfTYhmHtfqmVc4FP2zUQC6bDKrSlViAOx2yy/1ZTIGDZZpmGfb59vlHOMNUKHXReLsARzlqSbGLi6tNm4F1RTY7C+/qUsP5tHahvHAgg/BqgU0ApGqFg/JpqZ8AqeWkAfObJSIMdNMzADi4TZ/rEog5fKnP2yOSqRPLQFlMYfIRwtrq2+rZQ3WL8hN8JtlIeL8zU+S8rW9JZvZ51c5I3mYWm4/T2Yhh+1VPlcfPz9d3Xp0hw77ZXCgT7ivwxfvPrfRFzCgMSyP0Z1o9lu1nXLr/kmsWTNmBgb0YOB7nBrLsHLwargbEPpajqaA6+lLBHI6/9LgOh1S7d0h1OJzZl8OZuaJWutXSvekRRTlr85b4q2Wq+tuvkElEsbMYbkcvRsjS3x2wkXw4HKbum8v1g2x912T/CStyK5y/h8AVOuP9WqjRDmXxl4yBu88r/Pvb3X8TQrTYNfPffUK1WBRT8XrfrGDpUt8dDIV190I916XNZxejo099xFsbm+9/TsHuKIOPs2LZJ4tz50tt7ZF4sm1OFHhMgcP5CBrCRVGJyWup77PPErPTdZIux0smcNPUohp1/2zbV+yim0J7vD9B1Y2GRUl/n30ev8Knyn+1aWuPu9pERYUtmW/9YqLI0rDT32ef94siy34UWI26hAl+QMVj3RpRjLReUbtHefUkagFsydaZKIFx9Yq3tR2Utam1NPEZS7bE6SJQpHeEYrzUFO8tor7OWVGugCTRMV/qjvkK8E8ssyUOjqzoCX5jp5U6urtLs1TiUWUKHPDhJEC8i677Nr376Lxq43f6p804inGFDlEziiAiv2ihzwBpqHK7iiua0xrCXflcLNNceglOLHXD3CePUiIXALZmr+pmJ/BUvp9j961KWXOcneosLataZH3qs9vMi6g2X6fdo5A4XoP8RdBo248ueKSxdH7xeTXid/TtMc0TQUYLhQ59FBJ5nbgm7mrZ7h2/r/VfnTG9l2J674Lpv9I1NvdBJt585YoctIL7IoeyTNNMgcP66VPkcutn83kKKT+XXk/WQPB92XYl+aj1qprbephOjjerLsJXcvK5KXLFKc+awZc5nIM8FZ9hXSNDsirE5SeWOmC+LyHU4ZaUO8xRg4yrNJFi5ss87uT9APKnpbuSmY5nox+rhh5KzySP2Mc2w6QSi8tDOJkQbKuMih3wE587z5c5InWbxJk/uWKLXOLap3mcdownXedabbS+GrjYaFQ+a01ffyxHfDzDIIJqcXtbwscUiOuWLdm1LWom5u7PGsP4usfieY4rrzoON38G+bLBad05LPT3acNojosFZ9S2X1wjD1u3rPS5rKHIAWcXzNDVPRE9kXIIB1mweURK3YgSyGGOwJIjSvvFyZ2x1Vm5/pxRwGNFlO6ce6IXXWEyvMfiIcPVVbdV+e97fNJkJA2BdCsYCh2OL/P0jwZeQYlVzhU5uN4ysDxfof7g9BTi0CXFDkGXNed+Jh/mX4N/ap2svRt6VZck4qIqmjLU7pBh9FnnVmh2QW/rey8uJ7bEHaPkGjFX5HIQfFYWq4usWfJvO7IlTgfxRZMI64r6vDWroI+iCuP8HotnzJu86i5weAzLhLw+zSm87SeH3avJuC2m/TLPXrDtmvzBktO1s30a/5/TIpvriv4Q9Rl4+WvA4xkMq6o8zr6AW5QFwE5tM/VP5P4oan7tcUV7rJtjwodznyff7aYmEs55bYBiJzVlsYtD0UxaxSgJeMmG/7GBVY20c7yyJPoAWzznYeW2a1Y7etRPH8HGuVaAMQVcLZBX31Y/n/o1Zt+3mBWB7F5h7KhSt9zE3LZ82dTB7H2cOZlvaQR6WzJ2+Plc+zwsV2mFQxLaO0+Bez6HzWf/N6LY1jUY99rBkL6NtdOGr1vDQafPNb60lB019T1qNE1IYEIMbtJh9uAsN3TjcFnc6/4xwup7qpwvME3uUl5PkpW7Y+9EvKkRCZh9W9/wxF4XD5BzGtDfHbEdJQmsKhVOptRBI8dxTUjrVMkLWfnWrPazomxW4YE0AxqPdaypO86ivS7WacKjGD7OtfjF692u97rPL+TZQi624kbbziVuInxJ2CLC2iB4fBeHovI4q4O0yKMYPs62OjAJZG83MgXONwaklwUcnYut9OT9it1Xe0z4/RcOTffJxQFW1bLMLPR3d2yqmZSVu2MnWbeleNuSg8xyk1kgXFj5yqlJRdTHsmjWUjk1lOzytYyvw97DS5b+8xxCCi9NqfrEFBwEliXPHPJtjqS2EREQQW0jeHzFoaLytvq7tv9i2TZx956d15C5CFsw7XS6rxVFvXGWCWlMlhGAKXDEJ6aRoj67HEVK3gPyeAMoruXVXXnvfAhCzkeh1OX4uT3GUqCWFDvOC7522Ah4uSL3/srRiqUOLsT27So5YqHQGW97xVnpn1QBuXPcSVOWME9exFsEcgiXFtp6l4CPJ2BL3PvMHliq1owI5WDZg1omcajPrnzd3NY4ZfN5nmSoYzL25iE8W8AXnPUtDBDuLZC008Nzg7qxyCEDW9SOTQ7p2mInEjRj4yE8W9CMhYfwbAHVFdeeHMJTPiE5n2IdE2RnEEpJZgEeo20pMS3AY7QtJbMFuFPwBq4iXC3tvzryh5zrfDitX20SdJsi196JWe/p7y7XZO6afAEXsmdG+TIXrE+gXFwUaV5XP2EJ0dzygX0KEId97h4mD0VTH9V1md42NVTaeXrIgBar/1hlhqZaEPfdWxXyKSt3CEWKnKdz0LzXCo187Rxgie0CJHSR4YvEwQliEZmKoYd0CV4pF2Ko1+arGyZRBd18dcQkGbPfCL+A6gEu9NRUwbj1+eTx8b3Y4/arG6bT53VakqCXL0Ve34tIBQBf/P8JgYTKfLkfB39IS5jUH+Btyt/uUQG5uKCGal3e2U9FJnFHqaBCWpJxkBrKq6VjkD+IppYUwBu/uFilAH74z0/UqHGZF9Y+66AK81Duhf38FvDuUb7QfV8gOok0c7UcwmGlNUhnLNN/kmV6XYK8Agn+KWxsGrjw1kQm1UOGt3gJq4bPK26CdZGOa5xhQUNPOURIC7IRqaGcIiEGLU8zIA2Yy+WVMrkHFVR6YaUALnZVKr97wRS4e/y6HIFSf19f5o4VG1w44XFTt3u01ktnXcnlwCdO3vddOJahzahLuAJpLtysUIDYt/EJVF/hU2esfy1wxGsiyfemAdua46De4P5eIdvpU1rV4Q+hS1D65BS2QzPO4dHggeTXDPXd0UEhPZxw3Cp2Le/Tx/SO2E8RmUuC0oe57NCMw1x92zwW+ruDBK3g4mda30uZTCh0wytJFUN9/hMwbhxeDeDPya7wd+oYxS2Sd8PUUO7cLzuD48scrAOJt9bdS3te9T0g1xGBoDNJAdzHjgzTtcxWkpW7aD5Juk6xqiHolFyRB07JjSW+zEEvhjnW+kXVl/ruik3SQabAwUMIq0q4JT98dOGmDdmJ8idykwRgj6XqIDEihB95pszS1B0xDAk3qAgd2hRNr09eRHyu+98bQKjMotp8dVA88rS+KNNEfjIslnpglp77iqUulFT117ev6n769lF64OxxrNzbQO32Kh20AsS3DSkZFCAOKoPxmDT0eFRzLOp9HPqheMqzAiwk+cu4IpeNqq+qVHskAC6RsgnMK9jjEIL1xWKHviP5+ROmy3v+FULqu0MIZJMvMoh3GS74kfruLF9P8I1XmYRtC7Zre/5KEmQFb88Yje/2LK875vYcvpV+FbIfffVLeHRdDE/kyiLp6eI91hRpD20cv5GI0cdtZIVlHE6NG+vdDoGTSt03VyzHqAS/9iJBNhS5+Z1k1jz9fXpbbudWED5FahOxhqyaHovnq1vyqtstya9LkDyggckOLfkyB6w4DFGmpzAFjieLUH4Eypc5nROmj7CUvxYsFP4JVk+4s4LGFLCKpnRZDG1KzsH77x4OEPnadPYfuzsaZtNh6qbML+EfJANmoPJCofJSW7T1R2KjSJfcYjNQXEUqnt/rEoKqyM+Ksp0t3tfOFbrgJdMOie3OuziEQm+86kgOLaD7vMmTz4ulLpwK7u6+ikmj6e8OXp/FKs2lIX5siQulqeUrvzqoANnN0J7ZNv2C/HmChG+MjZ/F5rX5m1Bst+S+AGWnuog3XekSV/+cDCNb4qLsbGgsO5KWlc9mtEc8rxnDN92PCrEwLOGCHFTIx81CzLHbHuRdzzdXa5gMkYmbuQ9LJ6xD7ZNb2A3fOGIx5vKTj+TbWhqQbYB1vI1zlmZo8QlBsXyZkwh9+pZ3ZFC9L8AUO3vFd+f5Dd1kBSoUGsw+yoUTupEUDWkf7Ph/8qRJ+8GJY/BgNO7boRRau8YNnfwlD0tH2NkRHv9tXFp57pmed15+gDJFSuywEk6K1W2ag/Bdw4zffx6dkI60gzw03GaBPzhE5Nb8w6XtF4cTRpA3dyDBt/NKZNZKbwOrYBzDwSRxYE5hODBf8pfH+2/2WH6mCx5J98nh/pTkIOyTe7AOqCAhguy4WCj0wIt/aHHTAA5aeFWlyxxZvynhiHP+AUZZufsZHk5RKlxf4srcDW8cJMlj5ctcAs9kTwFtvu6PawRJ0ORB7r3gihytuW9N/e2OoOgSO4pGnQiy7bvfKFtevH1uFx0OXSWlkSUrdwhvgM81+iQ+OkZ9d7s48UeTlrL7Ev13j+V8UuR1WWQyL68KZv8NgrhrLsJim3yVHWUpEMQm+TSpQemZk3m7BDe5GTqK9G7vnEYT4Qp0o8pxvg8KESwD2zVuRnWL8uqPBpSwulzecgcsfKGjGXS0+EdT1eLxulDoYNQQ40OFWCx12csuSngFM5hIblUwRVPsNSqMZDnINkamwOXGR/6Aj/ek+otQuIfBX9cpsvQxP4YJwwGNh+TT1N1+dTV2hnT8FKzqEL4vm+MY2sWvM9c5QvuCQdCxAf7pc0ogrze3q1gZAVBy7gLywYHpq+w0B7cZv1HQ3x2wwaQpodAn6rODw058VOiT84tCxbIYXFrcjsAWzbkTfqpX2XGxeOG7SH930YPyGjF273f7Cuunonzg1SE5jJMQQQvuhayWPkm+KIXlMM6tnD4n9yBfQpKeTN+YCnRrRFvXqdC7Zf3YvB6tV1XdViGne/nB78UH8Va6x5V0vNg/F6hQyGHKFLlqDmdFuQJ1LUTLiKUuynHYw0HKBdrcZml1z+8e1Oc5Bes2BdwpR13gZICn+QLNKDcvXNHWiDDCJt2nCEpaB+arqymrjyPN2uZ5HJuvrphE6Uh/H896mctIvYcrSNxNSLcMNFRpVD7Gqr7+OOxDGuUOLNpPU26okiR7zgn2doThjkHycJ6To0g6y3AY6ymQejChNaZx2DHatYuIfpi4Fxh27h4wHbhzDVdI8Qk9KJNh9GBVOzTbakPg584vAB9GtPm6x8euJ2iilkX5EoebeGw+FqgRxYGLto6L+kDaKEzEIQuI6z2w0O6w0EeYwzJNIsV/8Nh8Uh4bUWy7Eflv8KV9CZzBtPnqhElAcrAppHx8lGSXMClCc3UPaDw4V1N321k2rt9jnNPW8+p8wbt1+29bw4bfyyhsOKDxYENN3T8XG15lDeeub7/MEZiuerZS/1zlXM7k5B4umgxeg+oh0JlMYfJxJmurb6s2GSP27gqt4Jy/ETJ8dPBtCo94uj7gKQ1F8IlDqIv1t/y0LItS0CU2BQ7zBJ/ry0Z0IdHfXdYnyZdT1gI+tsQN42m+kOLrvzv2r0kSWFXyHlJljn0UZ4T67CIrP6WLBcx5Wdl/dXJcLks0mAtYJpLoTq7QHa80GahQuDXSeHiCOFCz7dH4aLbquuMI4aPFAk+GcD9j89npJlyUV+9kqoBaEZjLUw1B1ZSwDVUOdFHTqHx80/r627p7t08rIkP7CavQ7E7FFjmFtqSFENuCP+2xZ6mb/w8parIKPt7jsfkzpAbFgSf3nCfPirJZxTtzFtB5cKUFjnHYkm5TfJVILJ3rtJgQiEc1fHQwhYp1mvB4ho97fHp9UZK3WjrNNvSQiMbldUakRzASr0eKqTgri5WKu/kyF85U4WRLnNb2P2BSC0u6/ejQM2RMcz0iX1zMwksIJBe4gaPvt1PYj1/aR915hEKxF+7hHT4legpijyUGMWtQweciMJiUQuR1oKKpPZLhuWlSmiBALJ4tiEqWWtojq/QuMyfGHI1BiWM0iEnlGEba0UYwCcINFVdn8WzRV6s1SJeB2n+PxSvaSlV1a03QSBoFvjzHImm/zHmDJPQmzmwOFqJDRwpIZZF5uVcMGLaVtY+ThDwO3XmXeQaQFO/isol3lt1SIyHPrgqn/lzZ/Nfh8OvfOEwaZBmfcY0p2Zpl/RU+VZ9hXcMynqNKjtNjkdsiGmmtS1sXnVc6OEc+l7D3eIdG0215OxLVd3IPk4eiiZWeTEDno7qZcWzrRrfN6fnIa4XYTuiCyOW41VAu/b4Gz6fPUCADU+BAVfDcX54Q3HdskYPY2PJkhfGUjG0RLBFS1slxxhAxk6apE1oX/FUygCnl2CH9W9jqne0lzKQp8asyF+AFtxrrRW8ZVr9XvS0xjbPu+OZ5bLJye+yx3kXeOXcxT7a43BaBzSaT6y9JBmXJ/5kCR3wXsEyLhbBDsEUuJ6E1yEhtzgHAFLiYOWj65K9jMyVzuFFixSWe52mdgky6wPmyPV7nJLVT+k+SURQPJHRf4fH57CgWOMZZ66fRruT4XVxRYiP5t+QXJPkyD6wKhO64JBcnmYKt4fpLiH3tfRbd0L2NxuW1s+kRjMPrF31Ck3dCRP/w3QPbewW293uto5+URVUhaySLwlE8Nh9b2Ihif7lqtp00MOrHL9pnwigf1NRn+AgzYVOjvru4Louyll4qYkscwgybLJMiZAocVMR1d3jJEW3zea4oJvwQrJCbePjoYjzfwbKEpYCLKZjzxCV+msqzEv7RkKyxXBzq8NklmoxkH/4EKt44pAu2RkShDzjdauDl5BaJz71kVc1tPfn5EyUC2Zy5hFqA1OmNTypLXe1t5ZOd01fJ/Y3AacYofCZYXm+cqW1jOsUJpr+7uIySrFnA8/wqRbUBZ4iLpU4HHaCqcOApKqjlxx0igIu+0FbmFYb+q4OrMa35bDLdpymjsr7AGnSRupxyxpa4YVS+IiYUuuGV0Iz6PH+s1yXMkXg6qn6miyWseUWQLXM4FiQ1/qvIuaHT312x/SzBulOtZEiZYlfcyOp4ksyUUOiK97jAwp9f0HyZ0zEu2qT553M2Xx3XMn5OXFzO5Ov029VRVRVJSt7AFvYstJWS+Mibo/U6SzGnUwqLZqPS1+O3px5apYSgPXIh7v7KBm6uiqaUPkBltdsNqGXbHibm0JfAbl6DEi9vz272xHLs5m9vpfMdwhKD/82JITa1VOygcKNZkbnHvtW8MHQyjBM6NFMzAglwQ3+ibfW+WNxcwqouU6wkneBRmiSETW3BlmXqtIA2wsLcViCbcA1EYBaLLgeKj5Z6UzNN73q7oa4o6J4pEqHF94hamN4/aKatiDVw+geEESZe0rmwie7wzDbRx2mWoc+D+9Zitvkqqil3mWsWZyBNOWQxp51DHcaYzh1DivwixfP56rz62mTZ76/vQFZBx9EHM88FLFdphRPftOlBb+hUrFoeMtUUcjxw8DS4BXvpmwucPQF5BD4zdDhwT6FwzSZvrFlFVUMlbRxZQ45+G3eafWGBS/gEysVFkeZ11QXE3nyv4OJnWt93zmBdRImxshhDIlSx4AtjQ4EzwOKKwCfmDm/jJmUiQzyB06vqLhqOUCeGisMhDeQjHltMicPj3kYGMo8/XM3pDPfu/2uw1Os2MnAxaRUp3MDYaDEi4lDVxcslYd25KP4ShCn6DtX7WrFDHKQ5LHmQwZnbfRn+rvoPeELBEn4pFjCrNvVwfvEVICOq1iAhFvwCnqVlhUPDwS2oYAvy+hXq+2OKpF5/5NY5XP7ITrI2HVQP8AXk6R2s6uviAea/v37/y7v3r1+R/N84biC7e/3qeZXl1d8Tsm5Bnhc1Gfrvr+/rev33t28r0mL1ZpUmZVEVd/WbpFi9BYviLcL1l7fv3r2Fi9VbvnqH1grLL//aY6mqRUbPOHVw2s1z/5r99zzleOO3f4MCp/UzfAnvXqnkyG9v+Yq/SXgLd+H31ymmLFmN5FkYEl0K8L3uHENB0rPXr7C4wZdCB5HzVou+PS1tG8gfQZncA6SIfAHP7R2I31//+oszTuZQzRp1XYohGAJm9uXiMXBTelxHcsfR4wRpd6DJ6h7JbWpCQh+wGBgQNnDR5pWoa5Dci3dmdpYTqbFxLfHL++/n+QI+//76f5Gaf391/h83TOV/eUUm8e+vfnn1v5270UlHzGI0A/twQvteloZJ3/3yizObnqXtWzFu9GlrqQhjtTyQiO9bRWO5TXNQvvy3FXj+766YjCLn/S/uMudLuoLtaw5BiK1X4ofiKc8KsNiTxdcPp00L0jbU5OkfDUwJyrsUC0VHpMhC6vGSiFNbcajuHoWmn2AvFuzxHRMujsPWXYiCjAm98OElm0uWihey0+e6y/MdAxsyauDTuNvbnqyrTQCH/zaCc+kadB13eYmRWuh+ztvTdRG9q9fFGB29hOvsxa23DmjH6PHJSWyMx0kSG+WQzi2y2tPGEkaQXeyVhRYhvnJQp3jGXJVFLPA3gQh+6xsjMXbHSshz+ebcVES2dpgOzSSTi75N0D3dk32iy6Wm011//dVdbWpNWrPCzeK24bVPRaVf5D79vSjKOmQlIYWzlKlM4R0bYqojI27TAV9VQdox1rNblwMSboQDUa0R1l2Xo6ONGNqThceMib5AoJnov/7iocWcPpOLBMz5//miir3/Ds200VemFt57bMV9E2wE2Qhj6cZA2sO2C7GwnvmtzdlRkKerZkV2t6MV2UL6bRcm6Qpk2HuNflXEDf3ub4jlsLMRzbpr99HgJ2qpxd6H8PlRyl4KtIcbx02+QByM1suQ+gxZrDV/oLizgmEzPndViq4bpEgxWeX8eZ7NnReGi0vRFn+T4dlrT/jpos9u4MpMQ8UgTmrp6d0JrnpQV/pTtBAu7EPdx5Koww2B9mVVkmLAX0Gz0SicDW2cTkFz0ubrc0RsTiUYDhj0p3QBr++b1W1OmTY+iH6g+bzNgibgornN0ureRWCNd0AY1QPB5ktwQuYqkvdLEOMWwnbCC1CiLpAEXUOepzCMHacj8Zs+pgtH90m42LHz7YwidxB0bJxHi1WaD29ARUDYM073pkfYVOOrp9/yT8gSvAjcXHocscQTe9c67qYlXLmOMC3Upeu4nT3KsuJpMNfhYwqfgjbEo/W6LB7hAr8smy+vmlXILH0t6qj4emQktyg32MD+xULZHS1cF0dJkD4h3Kn3R3X10ERfIiBv7kBSNyUs0Q5Tf0Ua1GZBx2rlI2KZ2DjPq4/pXX0CyiAtq8cRvj937yF8q+9hecHcIPbrWf++wrDV68WjzynXUYMNsTpN8NZ/tFhwTQZ1/7waYlYiRGKETc33PGsXYY8uaGSI6O0q+XYn4PMyLjskp8/rtCQW8QfwosLoEm5C8iIThOHc/QlUVwBpIjDGrLKY3N0DfP2QQDM0MHyOc7QsIaR1N8+TkQ2i9rXeKOEvQ9ryMHnSIWFyjofIOxrfxZBxPAJGJuN4iO8QnxkMT2CGyLIzNKn9AUSQUrZoL2qArMd2co9j/30cS5Zdpx7WCaHAaRVEQu45ngB7AeQ49XX+iJYYQtafBgVpenWRPERyE2KbiOA7egQpqptmFM4AN5C0j167V5pHG+/n4qkda/cOb9g0IB0+vXshdvRZUfb9O4bILApBewySB5IhCd9ACTzYwCYaxnfe0pB9JDBgUsj21R0VxpiYFl97IBgDHxk4XHSoqACkaKooYnMMfNy8HDd1vbHVPZcMhv6ZVvdZWtXhCLu1nEHEl0gwMz4PH3wnSN8mqNIkzM9MI4i+dXzLFuM20JkZJ1RsT/Q2rtYID8i8B2J1NkK1Mbxtcp2uYIQgOxr3ab6IiLl3NZ3mNSyrYF7spBeDFY7MQJ2Em7RNZC9cp7Bdu0EyH22esKqplwRX+DYA3kpGZVbU//60seoSd4WMon2ZbTRqs2ZKdPQ/08WI2D+NS5thV4otcwbEcQVOrBODOKer/WNPFAq158E96mBbTl2lI08fYfmCZ9Xd9cLWDnG80LebfW5g0rVD+nEMKthtr8GOggHXFwiqpoTk5rY+TNG7u+PG+A3N4B9sUx4eyTaep00KK3GLhR4FdOFCsMQBXDHcNAxCTIaY+K7ui9bzAzbh5xEj2oZYpf2InzBGFfhc3+1pFO4X/17BOEFb6hCw6IpD35S/BLF0q9HPPIbpDp0mEgFTd8ZVnRTNGkcuL4JmTcSi8oj4hgSS42OyC4Yx6gYP3rod/OrWgkee7Xp/BY9POBOOPHJFbMUtkaNcjosaaWDRY6RwKp7YC6VnuziBUodwJCbcMM6ZzUVKAkw8gtH7iiEKPo5Wu0r/CUNGwARnVddFeyOBx+zlw+1wfGNPEWxUHbsoQqTDX4J8afDZ+4WEx4opjOuT2sLIrZ3wWexbxLmMguTe6o8UPn2R6GwWEtg+ir0VXXuiDHWjiZnAxiqF0l89IsZhocplw6D+i0/I4TiJaLqDsD1jmXlvoI2nc4woS52dPJ01u0d5+fqRebimh5qhM8eT9rLJoPqyvpf0u1rD0R0w3bsGw938oBipPlwtBrLN6y/XBZugIMDHvEF6oYyY9poqCjGdvSE28p7CCkMgEHunxAZR+PS5LgGdmHEMvYk+YNoTkWZ0+HgkvT0psqL8BJ+7p4TjIt++vLeuqtSe+SJn1qUUXiCL9jc1gzpwXp0hk7LZXE2JEFE7MgfSF6sOXBiDC2mKuveBrf2n4cY9ZMNRDmai++Upuh9OJuKeTBxOE4y9273ThIOzfbed7fZhAv3zc90b6/uxKfWj8lCRh5phSsmaea8r3po/r/rMCkGBMrvKpnvGn7FfXDAnwPW5DWbOT+yDVZVW1y89T4fsrChXIDARU4/rCmye8dmuZESRrhEf3d2lWRqsCpP7pkF60ti7+3nVnhf0acNDohk0WYK1XQ7LhvsZVLVyT5k/FT7u3udimeaRwkIxvv4aswVKl/MX+sFFN9VAQBBiuMjef3TrjojBvj/W+6702fud3XbJe4bRDg0xk0ZDJt1jPZ8iWq1BHum9DOn5oo0a3VcMWiMIPU47+5jmiYeDgase0pMT6sZ+oCpA1tO7mMjeR0H2X+n6oqhwphe/UCyJHnVf5FCewcwvT2Sf6Wnu/c/eamlXwZ5IT6On952Hp5c436puaw1SZgmiGNfNrp+KzxAT67wqjHdJ3rvy3fV9CaE9/r+44kdLBJZpwuEOSrn4AwSpzFuVf9nbsWm96NmXMf4sa38bTnmiPeK7zBH12lRgQa7viZ59ifBUij1300rVnjD3eFrujPvq7W0JH1MgW1yhd7xmFOjWfHqcFUusz+4Ji34G+bLBmfaceXRTM4hJpWfHgpS2c8TYvObocHLbOlajZOfucJ1oEizYLelNAuxYKK/BMo7jbzsvgh/iKeKfvE9h4vbiZU/k7Ch7cU+jkyYjN4r0R8Lu537k4PAKjmCsnmVgeb5CXcd3uIy0cQ8/vqz360rouDpNGwF+VeOkzJewKppyb1Tw2fWbnp5GJvdJcNMjl14P8FN9cBLsYnWRNctUlUzV8iS5aBI12wccHX2FT9UePeE3O4dG1MDJM05xUOEUKnEwRZHA26nc/pnslO3QXw8GRo/W+qJMkWVHefW0NzF2eEAeUemkVnR/np9I7B+2+VHUYW9vjH3JChFtT7hm9m0+Hve0oWqdzItzoh9li46WqIhsqx8bWNVIi8VrZBsOGLdTAxn/2JM+49oTWWC2BX/91V1hjvR2UZQIYISk43uMQ8H2VhpucAxwH6NL+GekAF311IUoTrBcpRU+d72ECZa0+8v8IfvQKItpSCwQhth6rk+fMVVBdtTU95iuCVEG9mreZ786FS8Stp+tc+pOTUS0neSMjP0b5q3r4gHGMSMJuqMkgVUVDymJ/0ATHJSFyXrRnRVls9qjs/zrYp0m7surqxaWOmTuxW31DKedvnBhc8PSJ4Pxrt2NJOuDcMeeLBAyIHcW7art+ALB84hbDkwQ18bu6n2HHrmovraSOMgZ9SP0LXh88Qb3IjAFf4dFMeWe2EiitEBjfTcl0D4Jn49l0aw9JVBXd9yQUK9nViKfUHztdp2gtRxDoOC1J1OqDmJlFA/nboonsiz3REbthHjYN3abw6neEm8/mJaMJeIFToIvagIVfU7e3bAf2CQFoUkOAjvDpSgIznEQdomb1MT3lxq+J57DioGrS2IdEVV77zBygvQhTVhTljBPXqJdEu8RXoLN8a0h9frfvFcle9wVRu0foI4tzJDRXqO1kJ3nSYa6akmOv/pJ4r4xfGtwisaucWPDowATjZBpdJqRdrJhmhF2jU06MtSQw2J1b4wRY0jwp3hvANkZhGPTVN3y2ARWtzw2tTv8ca6WET4ZnRGHJ3VHbYWIjtGaQJp6g7SdxchvjlzCJ1AuLgq0wVU/YQkRawUmjryHyUPR1Ed1Xaa3TQ1jW41CA9V/rCLlReqUAEWEn2vsWZzceYPWv44yRhIRh80Y/DZMCZEcOUHzz+opXtOOsNARQmETgbsUTTEVxheYKLx6gAsV6YJ7evL4GCdbE0Z2+rxOS2I5fSny+n4EvP8JQZyx03z5IUXCrf4ACR+GxGsOaLq0jp+KbBFprkTkERmBQn4M8odophSHN9oSo/Gen8RG2efIioz2/BZE2pA6CU2UgphJXHFgDloQ/2xfAS9BXoGEfVh8FPTR2E3VwCWsmkiJc0/AGl+Yjk8cEXHEXiO7c9CJ4nf9osF1KxjbnXoB0ljB5lwGrCg07VBiWwUnuGxal+Eovq6xsxFv74EGbS5cwhVIcypI3SMq/BPAT7R2xu3XArvlEyYjUcSjkt4q/F4h3f5TiqZrbxIvzv4IJ6nq3npXLSwga4IcJh/TO6Ls7yHr9ENzn7xNzaD5+17Bxc+0vvdkIa56cFeYDAzR3S1TMuueMGivzlCzjPZyj3u7CjwhB4Y9qcMPi0Z2851XfVfJPSzAay+eQgOZZuuIBsMlGuw6xZpALE1twBjvzsgVzLFeHauHLbp43fsCq4q6NRv4ishmRohuNtubQm7xMHuUVGYYT9Q4lhnVtYt5HyX99wZ0E+Evq7/naU1e1hv7uHFoaPTTxSlGM8lIxj4N7e2ldr8em2Rsa2PTbrQju/hHdR+KpzwrwCI4GdF51aOKohh9RiyeV7DHqdQJrXZfJPV/wnR576UW2rRw3OSLDH4ANYjjIOzecscXMePwqNu2/xUn+NinbX+WDforlSYl7AJmH0lXDG8zbrnySHs398vLM3vUcUvUoOBVguEYZAC/KxCivlWjR9XENMLiHgbQ/g+PJ+X4+iM8KIcPclb789DwjJL8ugTJQ5ovI54Bkpi3cZUScpAHY500foBZ+ghLmzcit+VNsH4B7JEXYxiS1/2OtmaE8ynRbzy698BB96ibMr+Ef+Bsdfsy7eHXpSJN3Oz6Twy/0yUEVZGfFWXLK3GU9I7jILF/Lex9H6S2IQhO94y4ZMmhL57c3X0tYkW5657z5pPzur+IQAuKGLfCtiXaxGGDLEiozwko92qTDJeWF6DsFIcgz1PrF/I7ZqXrhj1/vZnk8OPV2eX/zMce412WQKsTloj9sXN/NHs6xu65c2Kum/mrNaJhHxY3zOOeyLyZl4Wctt/WbDSuta2ixRa2fvH1iLM0Q+QOzArcJtfuyBeaX3vkrPE6gu7JApAPMRbvbU2m+VkYZU9YZGdmoRMq12C5x5R3fNPalXg/QJkiXWfgYWRF3qY52CeJ99C40NQqDLNO9U8Y+7zYA/LmDiT4ElCJzCrF9b7QVrzVZqsnHUi/xsL+M12Mh/zTuHEPoIKE8v7HgE7N4B9sUz4PKFRVuszRCkwJU5peiX/n4VrqD0twLkGPqyRM7RDbvzf3cPybez/Y2iH9OK/CX63YO8Mf7QfJQwyDnNg035r62x1BSQY5Roo8xc66J9tpKH/1/w90ufkCiONtw4A3tN44cOM7fy9YgJ0jYgjONo8+UY/kBAfM/9GkZVgQIaX85XVZZOHuT6XiPwGfvDdOi+tK3rclfJSlIPojBRGtxqBo4FAx3d7H24+JVgzRWwpKaaUqjCnH5+NYq6OJIivKqz8aUMLqcnkbu5+t5bD4B5om+oA3+qFHG2Y1QUPnFcJ0BTOYBEa/R9hmorC0ecsR+04aCt9pP6f5Az4Nkyll2xNsdJ3CsnU97JVgne0YKV5aaPy4of8hdVs7hukdFIUQ8SzY/ggAz8GesHMEv7PkyLoU7P9gnFdVdppj+KBt4womTQkd+2flRaTfDYnmJftcLIvBCTeKVeaI51O9yo6LxUus1FfI6kSM27vzvsL6qSgfRvB8r0D5QpZOn+LbR37LsARG6hCUp89olPkSknxSof2TI3PopsMjyy32P4sk9HihTJehnsXtHvc6Zo76Tlx8LjACB6LYR3OdFeUKTRkVYRIJvfc7KJLlGeOF+f1/eeZDgZOzneYLNJmhW6CbDta5BfdEALVjDNvnWxyjKHXOloe9iXgPV5AY3AjVnkwmGVNsRcZ1Xm1wMknIVO93OWMdj1mOQfJwnpNjPDq36Z6wTYzA/HkdFLOHv09xb5KO2LmGK7TB780J0Sh7B35lF3VNSAsfjHjkMMMTRNNlUb4c5nh/57gTe4cp3t8pJnRNk307zI9hMKAhtI/Rxp5ShDg+/8l0Vb9Ig/EU1KMku4RJsTdJcbfcLJ3iNMvyaPt8sXGWRQwq/F4eGGpKP0fW6H2SPkhjhPf6vBVm709L7uGiyeA1qB72hM8sHPruE2kOR/rVw1uClne+CEpZhmuK3bKQgIQH/jczgr950EV2NmvR+lf4XF82+U1XPShSDPHP+lt+WpZFUPa/rktS70HAiDwCJD4DknWjrH37MiAgv07z4N4gFPH78s6TMk2SwKqKkOeFdIhmm2jn9+fVp3SB5FfgrY4lfm/8ApYJFZrnca2nx6RIGTjWUc3wOuWe7CveD8jHecde9iKU6wgcdRF7vygEVVPCLmvffky3UY1456NkklfC0MiesF4fG/sl5sCxgwPGctZ0PPQBCfK82p+TnQMbTctGZ0XZrPbxhJAaUtSHOmY/uCMzFuYWuC7WaTJbijqHIweS/r/Xw/aEMcOPrs/KYuXPhmztsLuahX836Lphof7N7T9gYsjq6BGUiC+ixnGi4zuoIEgTPa86dfb4pX3CNxKy4TGpEHxTiAKiiqNPn4t9CWOjRoRb8TCTeAQ7Ho9i+Uz3NrIk8SruB1uOqyobtfv3kXyqseJaVmuQLvdFJ5ZR3/NYWL7n+iHDF2VmX/YSd6dvhLyDCU8U2z9bSI3PGj9OEvIgZ+cbFLOC61qwOluy0CJ9XNtWzD1V5qOWhInsYfKpFofsVC9f4EBRkGUvIyyyr/Cp+gwxU++hl0M+uKj+Duk7uJZHfE9VJnTuhiC86cxg9nSLXsK/ut/1Cl8gUTcQmaUfm2wRU/mc3MPkoWj2LpfPKNEvW5mlirzThOG7WN0YOM+ra/B8+gypkfqgQUj6IPGwjWfCTFyjxy75L819SsEkDM7DBSGiiJ5lO1hkHJIUxV2BDu94JU2Jk/RfgBdMkP16R5QfnfvqETFEeNht6w+X+FHvCTucvCQZZNNMe80ARnMBy7RQv5hteURUg4xgC4rbJCFxFi9GThZlHCG86P9v78qa5LaR9F+Z8OM+WDuz+6jZiFbrsCIkW6NuWbH7wqCqoG6G2cUOkqVjfv2S4IUjE0iQAEGW9GKrCwnk9SGJM/H6lNVZms98jlSuvfmroDxHRvZvnoiN876Q/gae0qec81TtkVw3s4nijB/4XHL43Y9A/z1HIJ4bBb8+5Uey/1JWD+aMz0ZJQwn5D29Czr7g5fB1zHn/6CaSF9JX3w039/++5FM0tvKP9Wed9BljWVRVMzbPf3rQjwcdPnSXckKh0eQN+8LyZQPAm/uirJGj9PN2+V425NQGSYtvj/2uku89pZBnKkgXGRoLATkcZxmpQSorS1b6ai9Kni6KYC/L9h3fNl/fkulTl7Dxt7SyJQHwdHnkhnVJ4i4j8gTZQt7FrXhhnfxH8eUGE2Hw89EXYv/uQBfp6A/pY3k65Ocje326yZpm03FGN29v6V1aVe1Bs6agXryMPDTmRc/brNZTes5qydsJkLesTvuDedpQZXaDy54Sgdv0ZzuPx0zes2aUVV5VH7PjHVu0l9m18H/FyY+OXXMfy/SxHzUgstHbah8UlnwwX8tnRRtiF/bLMivKhQnsuTrtM6buFidH/eajwk9GLfkAD20k+pcApB94AfT2L4fEzG2CIVRdtnQsyu84x5mqhki7PWi4YAHE1Zk9q736UhTfTYKpZghP8mMtzeSm+bTcF8frVtV5nVNuiNxFO4azvApwdLOs1sDCOxaTKo6ddawZJkV+t9wxrMPM8O3QBNWrPatZXpV4zVvYWepJUXw3CaaaITz5jpUPWdUeLulycYmJw+a4VW2P3GkFvrN8DDJ2jIp6E16uaI06zYNeXz1kP17qddfOvNjbG+jR2/du/5Xv/9cOxud0aHSMZCJvmM3rxesOaVABBvlnydBVDujR9+xLxr7+xvLHz+f8NPMD7GHpi3LqxYs7OoVnO2SovkiUj2nVWzzAgeFneXE3XKi9VF/2+pGu6ZPW6RqbvSuqGQcop5ohOml7H+RH8aW3hUPf4Gid8Lpmat4V4nWermaQCF7k+Z9Fu/UXNfftCpG7UfTqVH2ds5su1g3+Gb1cD8R9MMVfbOj85C00tOm/pufZZr0W2Y0D/pdV/LS0h6Z+LxxbwrB+VVXFIeOe7Tn868zO7NjdJK7r9HDfxtnkZabN9F6cjn9rZyPty2dfT3kxZcC5YfnnX6cf357zOnvMs0PD/5+//Oevv/79F7XL/HHqzlv/rT243V5cuU6rQ3rUzdGoccTEACWXZEIoZAH/Q2PKz8a027Npfl2cqrpMG4PrvT47HbLHNFeNohASA0Sr69ikWvKcPba7XafaqDmFcetXmPnIQ3GAzRhPnwiYIkMtEa+uo0CTiETHygWyP8OjDcNYIGThpgqOLhI7NQtBbGwJYQxVZZljf4iA5gqDaDFNqBkNfsNaWvdoddL/H8XcUC76dvxtFazJAsuCKEVB0AVaKAyyFH0oHIXHxzcBJ3DPW3Mm5MUfBU6QhbYDp2mqFQVO49EMj3GJj+tV300tjYduxKamH/ceU+AzRZj7I0eT8UDJ1WNj8vb4XS9+xqrkpjiXB8Ncr68rz/XGH1cJLtpBLkiWwNgaVV4BXOaDawhP8+Gm6DC7Tcv2mKaXcHHBMHNyeQyYGQ44RoNZ/3ndVSyDhmxa2cVEMpfh2RYD2YgwSxiLPxCPj68Vh+Jz4GU8sLIquoZ/9Gnd2vUO9aTGNmOXIDAojlR+MTFM1MoljsVeREgaz2dfWPn9tr09i/pWJJKcKhU4zQEdoqEvXKCqhsGG03dNkC02JsZRHHI3ZlsDc0VoCE8XNCxXNXIZlW8GV7tZsYwIqvXXLN1WrSIvWrY5xD+nfOWsXHHhUmQrNScX7H0BU9JmD4uYPRwlVOBKLHVo2KCDigSWB4Gas//9RCBntmKFTWFvN1+4DYBt/S+de3iL/LVTLoa+Z01rWZtBo7upSdipkVuQPK0WrQI/+JovLtZIEQSCiglWQCLhmjPCmHKveSOYtG3rAF5H/PxDoNAFBdHgh1+QXwt3dTNPaeT60qjKElD0bWFMlFfGllyye0xJ6jhgKRqUhtvxHkFkmT8quSd5S+NvewcAmNBh4643gHZ5H94cGNy76IqQkISLdxpuuOE/Pj5oG1oPNeTwMP64ykdGzakCiRI4zgwKr4AqYwYZhKU5y0QkZFkGyA4B4mJx5eLjCLDCMwutjapnWZ43I3o4q9IsTNkO8brEvf2igcRLNn58NPTJJRNYiY1+vJSMmJIoY9nFfLwGjVw+XtFw1b1EclOXPPdAxQdEyfD8DAqukUD06PTjKuCCJJflAQmCwAw2WBiYgWpR+IqPCkXB2pBgZR/4GqSVZJh+3D2ORlV2gZ0h/8o+sDNIK8kw/bh77Iyq7AI7beKYfeCmlVTerOU/7B4vXI3dYKVLMpToQrt6KiBKOhk1CYafw+znU73oAS29IhRuLXk8vKjZYcUMntYVRrW27E+tcB10mXL/muSTCcMgUDXJGmgk50LG8ElKfrwBsNp29TEgmBz/A4LUGSCxAWrJu7z2eqdTBN3UMpetg6wIvlUXvOYCbnNg21EE3CLo1op4i4EXN9K9+NY+BpfmV+f6vm3xwAuVT/KmI55JAzljn5Fw9xHQqJ4LIKNh8WVRnh/4oqxv4OH7iyNPqSXh193jYtJlPyDgr2WujYLuiU4NBv3Pl4ED4BnSTQMh4f99VRbnRxQFAonmvP7nVT5EnKEuQiDoYIYJCB4So0muLYQQQG53j4XES4SgQ/fluhGHk29g8IGJvcR1ISG0+ujF0a+rjl+4WNFAxB8jCHBIzjR2kV4s5430v+z9bFynBoWRbPDI3t/FpHld0Kw5zKWjJvoId0jP9KFK79hvWSNN+T2B80ptNA2XKDkoj0xwMYm4JLUofKNn4gKxBvQV9xjxA0CMHlNi4YtLGPfDx0/EbRlRo5S6BAGPwq2GnUmRPQFm+zlM4sBmxXwlbsCJnaXkVfa5vk7LY/Lu3D6wVrHjx6y+R3SY70bLtaRBCqmx6cdwkYTsp4WgGHUhYQJ0RXSISGMdWKG5Lg0UayDJQXlWGPQ4IcAT2pzHPUPFbWHtg9gVNjoa2hLUVhsjzcaZ5NG4w6bfi5ptf5zdSqlL0P26bwxNimx/nP2efW3Q/q5oGqiG4LSL9UlAcEkcsHz3a5eQVrtYyYRw5vUjaBmObwcuq4WhuViR3BI3sR9/H3XLX7JBSC1ZX8B3JVYD0KjH9j9jg6h8xQiWe67XAiNHW3CQC4LlGSU71hOIyMsSY4W4m7RDasr1Etn83Kb/RTF6xNFKfS5P7WM6LMBZ40DjYUFkZWgjlVzAGFjUZxej3/ECz/pR5Wd6LDS8xBzbFlyQ67TshizPzqdjzozbE/22ikAJ7HiJpU4wUSVShiRqYcgdLcwWYQCk6UbhOYm4HQjt4iu1BZit+a2aha7onysNW9vfg98CsFbckZ+Fq9gb8z3/m0d2yD73tw+v6rrMPp1rtgOMGeWH5MIo944+s3p7gCIs+h+P7Z8JRS8x9NjxQANCqNBo0JUg5UAYZiVqPoSWRlCTsqTJBNjARoMrXdvQwPkhY/NisEUP2CYNYmN+GDrcpnf2HGZbGUVMMkOyiKUXMloQVHIYIURMPwaAy5Jxx+xTwJk/AsSoDo+JsoY8OtD+TMssPdVjbL0uHj5lJ06Y4E/Gi/dhRCLpHoxU4LQsaJcNgpaRPMwVL9RAQdFmUpQihSj2lvG3m7n55oG6/nd3KUZjT9UJ8PzXuSlpvPThlOEYlYhELMgFFxkecQNtGnqi2FvD335jIgWSFxv99hzyBsjZlyQ1QsDlay9DbhaNqy47eoDlZtYaVSX+TPPzCFKzhmFwsS5yuboUMXvCkBiehacwUO60dcCz2kBsWEcfTlKGDPseGO5u9JfcpA+POXtefD3lRYpfER4JpPWX8ceNowFWLz4SZONHw8JtxspGvwOT8rBbz1txImr+dY6JIF+xUXpJFuHXi0i2PulDYSZKtwFYbX9KGQdEK04b3fCzkYnidBy1P0i8fSBpkrudZt4fsHSVKEwld24IZl4BZh0C/USJmenm8DHO5V5med3muw1+vWGtMKVoZhZSI76caxNWXenRLe41iroo24FX9pCW3198O9ynpzv2Pq3Z9blsWBy+G4b3PYE8tB9+pAc5LoJ8nq77JdCAHNIrDEg6PWgRDHXANqDB//iJiQiYkCwf7zX49PDX61Mjy+Gvm/On6lBm3VnxXdy6QoSX34rHaHZ/BwvTzGWBYHO42/4Mb3ugW3EcvwRzsUfzV4cceHDX7zJnIMyNossX56dfL2KNc9JnN2ucV58/Z3nzC0tWevNkZCg3NP2698QHkyoUZrETqvAneoIOnHAoaLz1p5AubMSj67SLsU6j35cG0G8boKZ3LHlZFg/roURmroyb5KLd40NRiMJRdMZWAHJb/ITHRuAxuSLisLXOvjQmf1PcJcK/W0fhgw2FTh41KmUrjWBHrpg0ocYuJpuFAZqoFGkUI4u4CajtYgEoHqrWjFuucIoesq7v2eGv4qyeoNV+xrGlUUog00tXQRusllm0kGdkLfYMA0ZEQxIu1aoR82AezmWj8d279DvPxfz6lLXtekrJjA+3VMZKQku1cN95ljV9SDwFT2wGH0Nmd7NGvvwcLJMqqJRRtLAp4+cBxC8oXTLIq3Wj4fNNcUjz7N/sOMiYvElPd2dtViN4fyQQ3T39uAoCNbFlYfTSIKiDTRUGbbpOFKaDhBHx5XsCEO78tzr2v4wx/27G+v2u3nv2JWNff2P54+dzfmqTELcumRrnq54jpprf63bYdVskWH0r7Po2QPSNZc5HMnU5gJ1mgIhwA2YR5gaNVlkmo3jEiXdMHEoFtnMFPRXq82iI8ntUADLGBsEkVY53VCUv7q6LBz5PJAY1ocracUxkLR1JEX+/oGiFmtqJ3cowav/9rlBfeVC8yAlUF3Y/rnPQyR1JnqIUbJ5t4GeQLRqOfmdfK8dwJFRZOxyJrMUmpd8vKByhpnZitzKM2n8bL7GMBKoLV7yyMgNJnsIRbJ5t4GeQLd64u8jzP4s6O931hyup8z6l3urzPZW/NCrXCi8oRJkt78QzBr7aH65O1VfDypRAonp1+HmdW3ZLMOZrxoeYa0PYmkTcxurBrKWrqOtV9AWLfUcuT6sXqwNq+7daZsJpfzdY3DG07r2VFzw3VNupmhqsHJb5iyN7mZVV/Tyt009ppe/ztbVuWA3kmPrlb10pmsvr5nDPHtJ//nL8VDSeTz/lWgNaFFK5sTM7vnhIs/yqrtPDfTcYB9iCdDB/kNQiyJSRSuM9FUHsplK6qmYFrWpZWXXKHw7FGTSmXAwxkyks3Pot7besvi8g+ynlED+FxMbQmlVAl8FaBRTLWstVUopoRFmozHGWRkb2HpNVGMCmIrDHjKUWDtdpze74GRKNw1QEcZhKbSbKDvW5vUSum2goAU00FNI8YOCiEBj8kfREyduUv3NH9k/7LHBWMiSwglQmr0mENhGkZxZ03lIxyFSioFnbgBqNwmTvgYps8L7i2/R0/pxyXxkikUxlkkOkJMtiEcLOXaawdVR1MqL3V5UC7LYqEZGtgZ+ZkZXDeM1SYzCWQO2PhTYF2g4Fx7ehBBR/KLQ0PzzujH6ZVQKImUpj41k33aaB7pdmUA31eaUc5CiTWBhOW1sar6kIYjOVWjhMR900DlMRxGEqtXFoz3qxm7rkqx9V914XwA0kAzmDlBYpplV5jfNUBHFrS+3RUVhC04OiUAjGQqGcwAfhgLdNDjXdzX003HTFppDTUdh0YOVDVlXN/G5Y4NP10UhA3TQq28zhWzOsPaX51bm+b+eg3et2qBRmcnBmYaxhkY7f4kU6u1AG8eXFVULq8Jz2tnjMDhifvtDAqKegcMKYGNvvKSjtvyqL8yPGpC80cOopLJz6+wwak/53qP2+iDiM/dDevBwPlaPjWJnMNJCVKS1SvMo+N8PG8miRAiaDpIApiVIYOJu50dyIfASEMtSdpIkpp/y9qKFIKpShTLpiC5P37Guj8LsiO9UV7jCQCmIMEhLGX8i0ayrCxlykCdZAiHhMLjZxIvntPWumA6d2AsjAEKyUw2aUSKzqqa/UAyqqJLCaKhVtLoc9iYvN6jB60/wOeZ+YOtMzvzSs28tIDtrOWGOWdGS5XCSi+pQ/74k5kBcavMXLaXyMb5ph/I2VDHIZ682Tly6kZd1KeaPHdT2FIBBNEmekIK/WUM3Skzt4ra9hkU7ILa+JIpRBfIVi6zy+AFcs+9/heXtBWBOdcn8Cs6ihCJ5BDaUU0UeQwRqMxagiVJTeNvUZd+QncGqolINekUlsCx5YhkB9/QOjBJdDMGKHlcZb9vCYp2BPhclsK48TJXGrwCCBTmLaOiBzHj4MOGONwvR9obJ9xU6s6cim4KiTgFMDjcq2JjrlDtRXRacycF10KrYw+VDiTIQyiIlQbAsUTe3jOWe3afUXFCikYjBQSBQ2u02Z9nS7TWWg3aZiW29kadV0nI8su7uHhuhKOdj/ZBIaw+dZM4uo4DCkkxjYClSUtQ1LBARoDCsdTnFPzXEFdHuZwLQqpZBae6CQowbog0Ip3AsFAjqrLuWTiV1HYWHZEVnD+cNjmt1BLp2K4PA9lFpxy21t+mKpFDBqFSLCGvsbVtestCAXI8TW3yFam5H1ZDi6tXUa0Ow6mStzbHCNEZLEoA2o0dQVwAoHQgmvdSDEjuIQ5KAJQNuHkvMoaKwBGnQHSiazqt32oCN+akUlgFWWaWwoLIuqahrPca46CYg8jcpqaih2ozGbEqubf9XIlGcoAQcxQ6FtopN+MxytkErBSY5IYGOF7L0Ytl1o+y3D2r9BEZ3EtImQXD0+5hk73hY9fcbsW6FDZRx0GgVNhp7cLoG8qY8fQ0Do7OcE3rOqCcH8VDHhGES/N4qfttAoTFusPRHBEer2qGWX10xO2X9NWlLyAth4Hoa2+UzfhJbS2Luux1GWUYmrqclE5yoFkPYAEwYgNcgEUBNOoIzXCPVFGLEUO4cyEhCGjzgrqRQbKFJZ6ZeMdPtqJNj5CpnKxcM2txJ8qTEUzs9bTqInL7O2LwkVTOfRO2r1oP90U0I9Y94wx8+PSzWNx+R5M7RT709k1d3Mksinwo1GkWlxxaCT6lwf0wl0zDSYQfyaQfC3xIMKErGSV7U2ghj5THMynm3W7YNQ4kopB6m5GshZbOiKElhdKfKu/jCCs6sP32SC7nrp8m9G/fHUtMHvGo1/j6sDfF4RnX+4q2ka/yc3/XlLXXNKNcP3Q7lx0X0/kNsUYE3QLHphWPPcpuUdA3sEpZonn2/MPMPMzQk7aqWQyIFij1YW0jAuqFEr+Q+pkcwCXMKpjCYBK4TECXDbSGrEdH1o9sc2ke8JoZ9amc6gDHBvqdPCcB9pLq7mqz1+R6fQhKqu04YIpMgVLFF9j2FUVc0+1tJIgw22VjKBdDnMMOQC6fwPu6BrZ7yy8TrZbM8rV+NEFigE8Dqe1YJQgTYElgcxk72TgOTBOsrKJpGXqZNhnZr1i9vm4Tu9Mq42fCmPa2y+amdoRVnABxrDrgwGMSA+VKNXNnydAGUR9bZiMvFCYzK2C5gHJAxgCuiSZmcC491Ld9X7vRiT0iqJf3WVfSVeD7uiO19FxXS4ojKhdy+tqPq4nzRuuRmCJ05s8Lhyw7tzOXJ7G6wJGUArC2EIPAjixF78uAUzPMvyvAmkY8sGIyik4UxAwtACpYf0blPTuNYabcguoGRlkBrAUi24mwG6cj69LQPYwlwBV0u9js/1wa7ayzUN1+y7VijX5t1NM2QaMJpDJwphAjVbAq+JZkJwV3VIFGBUVScKoaqazoDXnH5cPrkq8tyopkwQQkUx10E3Z4JyGcxTrUu3kHQtwsqJJAuF1GrIqSLGekgSiBkqqidzxCMxpmEMraJBOSS3Q6eiJV+DsSXomBDYqjEXhXdT4gMhWkX7B05T2KTgJk0IHswiDaYd0edhNGEz+jqmIQyvV0dTLBOZcqoYh6O0iiHQRMkzw1tzyhfjbroxa4zRTgBVCKNo6W14VeFXP+ryo9J2fRWyYApLh70njeED3TNVTsRcN4i+Io1FZCmjziQymClHr61X9OvZvkmjWzuaxYLG8SbviWKzph4r0HkUfeV+y9PeEFZVQDr/SypSsideC87lNFdRU2xSKEKEpXDqQbmnkul8BX6QA65gOMGw+CAHlOlKasWYucqTaXq7E+0CPk/u7tdNmGPMpoXbQCXxq7iWCWyq52kBZZLfsCetE/nfiQ6v6pB/LXnXzM/u04odP2b1vcBBV9xWxZs6Ul01wxyvimaPm28Iqd9O7eNmgCt4UgSsifZ4Uuo+T6b5IPqdbB+5lt+4EMs8Y+Y/S0AUSAIERDFr4VQPTEjoriKQY9A4FDLShxgYGXIq8kYoSRL9mMXaL+yV/KIjjmmG9I14n1Ao/CqtJri8GU7ReDreK2anTKZ2cS1lQk+CgzW176sxk+bcidBwIsk65VMJ9zTnk3KCWgIeSBkm1AG5TvuebEphumCBm+BslNa/v0Mfm1BTsibiyzZQD8fJrTMC/f0dcW6AP6mj9Hw4GW3f+y0JZj0YyNQzcOIQnSO6KQwTRpTW/7xxbTMYkwwTDnZbKvo3ECmLstgaMbPvDAQZkhgjGZhBcM1oxoAfu11oBiG0KieENrSNJHb2jVYzc1cIG1tb2VQb7QF6yhXjKRecOliY0BPLiC2IpUGMYTinglNblUK0AdTYhkkMicSptyzJTRhW3X1dwCQkYRct6pJGPYiJ7R9xSu1gXXRv5pTfop1lU6kJ3EDQs7ncFKbncPdq4hkwXR+bFGuFN5FxOEmua1XeqDVt3LhJM/IErgnKlmxSczurGIXSrpQE19Q4nNh2/kCIGChXj4ZhEygkN+nDY86mFGy44gqlYegyO8lbWJXHpz+kc7GQygilfSFp/slZ7UkTXh1/rWSJ+oZvl07k/2sVXlVtWbNfK7V/tNEqwT7ac1dmvZjFySAXbQrlXXvLWrxL9XXW5m0SmZvWiD3c+C94Rr/sIS2/v/h2uE9Pd+x92gzPx0eMgMVFayVTCJZfVerDL/xikrwGJj701C12ge84LTQC/4OsvUy9L7WRh5SM2zfWOiF2cSwPSfGGqK9C+TOTISjbqvgPzXFNND6XZB2yIZQhh2zaM1DdzjL6wtMM9YdXjxLDjrhO5H8rXHu5qauJPso081oDOVoYqEPECfShpZvxmoNn4MvvISUvy+LBZA8TeQiDwE8/9UHF+JLTYlPcFg6GEIj3bgbhAalEe0wKioc4uSmkgY9d9YHN+IIV1g7WhmeTmEAB0oXAwzpqw288JcALVMDxKWpdg3mwR7M6O9newTK3pS//EV+0mnPoTn4bKnl9yuoszQ0Hak0VcCXnHaaFX8C66c7fWV61Wm6M4cCwzspuF7RuIHWNLcEnkWnPks1MASS++WXP/wNT4wouTP4DvW3WNWF9rmyOOcyBOXhAVgOxnwDcz5u0d3KS9rt4XZyqukyz9jGUZhg26jckvLotEqy+YaXJPy+7uWdkzYKmnOg7ReIc1P7mkEc3SQVORpdrElXH9d20+YRXmahgkx5yAlYvlrUYHrHAO1bdAofhgaplhp0Sj5nNNdKZhScnNougtvD0FtX70mtduoEWthgeT8BjZbwN0ytkyww7ZXczm2ukMwtPzh4XQW31VTXyF1F7jQ34APhqe4WvLPJKXfd5sL0858HsYlI6giUFcrNSTvnv4ppE/AjPGphZByHzWl15jEcf6Cw2sn3jWiEMtmntUfWnT7pGWsM3XmblWPb0SffGY/9D82czYW3me2+LI8sr/uvTJ+/PTe0H1v31nFXZ3dTE06bNE+Ov0U6NDjSvT5+LYdanSDSQDMXDoxusTo9pnV6VddY+TdAUH5pRJ3+9lK/PtM8XfmLH16c/zvXjuW5UZg+fcmlO+fSJmf/TJ5rMT7v7BpUPFRoxs0YF9sfp2TnLj6PcL9O8UubRWBPXjfVfseb3zpdN16zZ3fexpd+LE7Gh3nzP2SM7HZsud8seHttXvKs/TjfpFzZHtg8Ve8Pu0sP3d22SdL7chDVid4Rs9qfPs/SuTB+qvo2pfvNng+Hjw7f/+X8qczC97EkIAA== + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesMigrator.cs b/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesMigrator.cs index cdef6d5f8d..9a1d698396 100644 --- a/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesMigrator.cs +++ b/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesMigrator.cs @@ -102,7 +102,7 @@ public void Migrate(IEnumerable entries, bool updateTouched toUpdate.Each(x => _ctx.Entry(x).State = System.Data.Entity.EntityState.Modified); // save now - _ctx.SaveChanges(); + int affectedRows = _ctx.SaveChanges(); } } diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index f828c8a076..fe9dcc8e8a 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -303,9 +303,9 @@ 201507200832223_SortFilterHomepageProducts.cs - - - 201507211743009_WebScheduler.cs + + + 201507242008201_WebScheduler.cs @@ -582,8 +582,8 @@ 201507200832223_SortFilterHomepageProducts.cs - - 201507211743009_WebScheduler.cs + + 201507242008201_WebScheduler.cs diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index d1392d9548..0c76cbc078 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -449,7 +449,6 @@ - diff --git a/src/Libraries/SmartStore.Services/Tasks/IScheduleTaskService.cs b/src/Libraries/SmartStore.Services/Tasks/IScheduleTaskService.cs index a8391c3064..2de26a49ad 100644 --- a/src/Libraries/SmartStore.Services/Tasks/IScheduleTaskService.cs +++ b/src/Libraries/SmartStore.Services/Tasks/IScheduleTaskService.cs @@ -41,6 +41,25 @@ public partial interface IScheduleTaskService /// Tasks IList GetPendingTasks(); + /// + /// Gets a value indicating whether at least one task is running currently. + /// + /// + bool HasRunningTasks(); + + /// + /// Gets a value indicating whether a task is currently running + /// + /// A identifier + /// true if the task is running, false otherwise + bool IsTaskRunning(int taskId); + + /// + /// Gets a list of currently running instances. + /// + /// Tasks + IList GetRunningTasks(); + /// /// Inserts a task /// diff --git a/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs index 5a1b753ed0..99a5d554c5 100644 --- a/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs @@ -31,28 +31,6 @@ public interface ITaskScheduler /// bool IsActive { get; } - /// - /// Gets a value indicating whether a task is currently running - /// - /// A identifier - /// true if the task is running, false otherwise - bool IsTaskRunning(int scheduleTaskId); - - /// - /// Gets a sequence of instances containing - /// metadata and progress information about currently running tasks. - /// - /// A sequence of task info objects if any task is running, an empty enumerable otherwise. - IEnumerable GetAllRunningTasks(); - - /// - /// Gets a instance containing - /// metadata and progress information about a currently running task. - /// - /// A identifier - /// A task info object if the task is running, null otherwise - TaskProgressInfo GetRunningTask(int scheduleTaskId); - /// /// Gets a instance used /// to signal a task cancellation request. @@ -93,22 +71,7 @@ public interface ITaskScheduler public static class ITaskSchedulerExtensions { - ///// The type of the task (must implement ) - //public static bool IsTaskRunning(this ITaskScheduler scheduler) where TTask : ITask - //{ - // return scheduler.IsTaskRunning(typeof(TTask)); - //} - - //public static TaskProgressInfo GetRunningTask(this ITaskScheduler scheduler) where TTask : ITask - //{ - // return scheduler.GetRunningTask(typeof(TTask)); - //} - //public static CancellationTokenSource GetCancelTokenSourceFor(this ITaskScheduler scheduler) where TTask : ITask - //{ - // return scheduler.GetCancelTokenSourceFor(typeof(TTask)); - //} - internal static void SetBaseUrl(this ITaskScheduler scheduler, IStoreService storeService, HttpContextBase httpContext) { var path = VirtualPathUtility.ToAbsolute("~/TaskScheduler"); @@ -130,5 +93,6 @@ internal static void SetBaseUrl(this ITaskScheduler scheduler, IStoreService sto scheduler.BaseUrl = url; } + } } diff --git a/src/Libraries/SmartStore.Services/Tasks/ScheduleTaskService.cs b/src/Libraries/SmartStore.Services/Tasks/ScheduleTaskService.cs index 87c17389c9..bd6e295107 100644 --- a/src/Libraries/SmartStore.Services/Tasks/ScheduleTaskService.cs +++ b/src/Libraries/SmartStore.Services/Tasks/ScheduleTaskService.cs @@ -89,13 +89,45 @@ public virtual IList GetPendingTasks() var now = DateTime.UtcNow; var query = from t in _taskRepository.Table - where t.Enabled && t.NextRunUtc.HasValue && t.NextRunUtc <= now + where t.NextRunUtc.HasValue && t.NextRunUtc <= now && t.Enabled orderby t.NextRunUtc, t.Seconds select t; return query.ToList(); } + public virtual bool HasRunningTasks() + { + var query = GetRunningTasksQuery(); + return query.Any(); + } + + public virtual bool IsTaskRunning(int taskId) + { + if (taskId <= 0) + return false; + + var query = GetRunningTasksQuery(); + query.Where(t => t.Id == taskId); + return query.Any(); + } + + public virtual IList GetRunningTasks() + { + return GetRunningTasksQuery().ToList(); + } + + private IQueryable GetRunningTasksQuery() + { + var query = from t in _taskRepository.Table + where t.LastStartUtc.HasValue && t.LastStartUtc.Value > (t.LastEndUtc ?? DateTime.MinValue) + orderby t.LastStartUtc + select t; + + return query; + } + + public virtual void InsertTask(ScheduleTask task) { if (task == null) @@ -122,10 +154,15 @@ public void CalculateNextRunTimes(IEnumerable tasks, bool isAppSta foreach (var task in tasks) { task.NextRunUtc = task.Enabled ? now.AddSeconds(task.Seconds) : (DateTime?)null; - if (isAppStart && task.LastEndUtc.GetValueOrDefault() < task.LastStartUtc) + if (isAppStart) { - task.LastEndUtc = task.LastStartUtc; - task.LastError = T("Admin.System.ScheduleTasks.AbnormalAbort"); + 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); } diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs index eb87adc407..7113794245 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutionContext.cs @@ -4,6 +4,7 @@ using System.Threading; using Autofac; using SmartStore.Core.Async; +using SmartStore.Core.Data; using SmartStore.Core.Domain.Tasks; namespace SmartStore.Services.Tasks @@ -14,10 +15,12 @@ namespace SmartStore.Services.Tasks public class TaskExecutionContext { private readonly IComponentContext _componentContext; + private readonly ScheduleTask _originalTask; - internal TaskExecutionContext(IComponentContext componentContext) + internal TaskExecutionContext(IComponentContext componentContext, ScheduleTask originalTask) { this._componentContext = componentContext; + this._originalTask = originalTask; } public T Resolve(object key = null) where T : class @@ -42,18 +45,35 @@ public T ResolveNamed(string name) where T : class public ScheduleTask ScheduleTask { get; set; } - public void SetProgress(float? progress, string message) + /// + /// Persists a task's progress information information to the database + /// + /// Percentual progress. Can be null or a value between 0 and 100. + /// Progress message. Can be null. + /// if true, saves the updated task entity immediately, or lazily with the next database commit otherwise. + public void SetProgress(int? progress, string message, bool immediately = false) { if (progress.HasValue) Guard.ArgumentInRange(progress.Value, 0, 100, "progress"); - var stateName = ScheduleTask.Id.ToString(); + // update cloned entity + ScheduleTask.ProgressPercent = progress; + ScheduleTask.ProgressMessage = message; - AsyncState.Current.Update(x => - { - x.Progress = progress; - x.Message = message; - }, stateName); + // update attached entity + _originalTask.ProgressPercent = progress; + _originalTask.ProgressMessage = message; + + if (immediately) + { + try // dont't let this abort the task on failure + { + var dbContext = _componentContext.Resolve(); + dbContext.ChangeState(_originalTask, System.Data.Entity.EntityState.Modified); + dbContext.SaveChanges(); + } + catch { } + } } } } diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs b/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs index 7101c1d242..86e695a704 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskExecutor.cs @@ -42,6 +42,7 @@ public void Execute(ScheduleTask task, bool throwOnError = false) return; bool faulted = false; + bool canceled = false; string lastError = null; ITask instance = null; string stateName = null; @@ -73,21 +74,12 @@ public void Execute(ScheduleTask task, bool throwOnError = false) // create & set a composite CancellationTokenSource which also contains the global app shoutdown token var cts = CancellationTokenSource.CreateLinkedTokenSource(AsyncRunner.AppShutdownCancellationToken, new CancellationTokenSource().Token); - AsyncState.Current.SetCancelTokenSource(cts, stateName); + AsyncState.Current.SetCancelTokenSource(cts, stateName); - // tell AsyncState about a new running task - var taskProgressInfo = new TaskProgressInfo - { - ScheduleTaskId = task.Id, - TaskType = instance.GetType() - }; - AsyncState.Current.Set(taskProgressInfo, stateName, true); - - var ctx = new TaskExecutionContext(_componentContext) + var ctx = new TaskExecutionContext(_componentContext, task) { ScheduleTask = task.Clone(), CancellationToken = cts.Token - // TODO: Remove LifetimeScope }; instance.Execute(ctx); @@ -95,6 +87,7 @@ public void Execute(ScheduleTask task, bool throwOnError = false) catch (Exception ex) { faulted = true; + canceled = ex is OperationCanceledException; Logger.Error(string.Format("Error while running scheduled task '{0}'. {1}", task.Name, ex.Message), ex); lastError = ex.Message.Truncate(995, "..."); if (throwOnError) @@ -107,16 +100,19 @@ public void Execute(ScheduleTask task, bool throwOnError = false) // remove from AsyncState if (stateName.HasValue()) { - AsyncState.Current.Remove(stateName); + AsyncState.Current.Remove(stateName); } - + + task.ProgressPercent = null; + task.ProgressMessage = null; + var now = DateTime.UtcNow; task.LastError = lastError; task.LastEndUtc = now; if (faulted) { - if (task.StopOnError || instance == null) + if ((!canceled && task.StopOnError) || instance == null) { task.Enabled = false; } diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskProgressInfo.cs b/src/Libraries/SmartStore.Services/Tasks/TaskProgressInfo.cs deleted file mode 100644 index b07d1fd830..0000000000 --- a/src/Libraries/SmartStore.Services/Tasks/TaskProgressInfo.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; - -namespace SmartStore.Services.Tasks -{ - /// - /// Contains information about a task's progress - /// - [Serializable] - public class TaskProgressInfo : ICloneable - { - /// - /// The ScheduleTask identifier - /// - public int ScheduleTaskId { get; set; } - - /// - /// The type of the concrete implementation currently running - /// - public Type TaskType { get; set; } - - /// - /// Gets the current progress percentage of the task - /// - public float? Progress { get; set; } - - /// - /// Gets the current progress message of the task - /// - public string Message { get; set; } - - public string StateName - { - get - { - return ScheduleTaskId.ToString(); - } - } - - public TaskProgressInfo Clone() - { - return (TaskProgressInfo)this.MemberwiseClone(); - } - - object ICloneable.Clone() - { - return this.MemberwiseClone(); - } - } -} diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs index 4422c99008..ff1b736ffb 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using System.Web.Hosting; using SmartStore.Core.Async; +using SmartStore.Core.Domain.Tasks; namespace SmartStore.Services.Tasks { @@ -66,30 +67,9 @@ public bool IsActive get { return _timer.Enabled; } } - public IEnumerable GetAllRunningTasks() - { - var tasks = AsyncState.Current.GetAll(); - return tasks.Select(x => x.Clone()); - } - - public bool IsTaskRunning(int scheduleTaskId) - { - var exists = AsyncState.Current.Exists(scheduleTaskId.ToString()); - return exists; - } - - public TaskProgressInfo GetRunningTask(int scheduleTaskId) - { - var info = AsyncState.Current.Get(scheduleTaskId.ToString()); - if (info != null) - return info.Clone(); - - return null; - } - public CancellationTokenSource GetCancelTokenSourceFor(int scheduleTaskId) { - var cts = AsyncState.Current.GetCancelTokenSource(scheduleTaskId.ToString()); + var cts = AsyncState.Current.GetCancelTokenSource(scheduleTaskId.ToString()); return cts; } diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index c3bf87312d..75d3bfcdb8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -326,6 +326,41 @@ header { to {left: 0; width: 100%;} } +.loading-bar { + height: 4px; + width: 100%; + position: relative; + overflow: hidden; + background-color: #ddd; +} +.loading-bar:before { + display: block; + position: absolute; + content: ""; + left: -200px; + width: 200px; + height: 4px; + background-color: #2980b9; + animation: loadingbar 2s linear infinite; + -webkit-animation: loadingbar 2s linear infinite; +} +@keyframes loadingbar { + from {left: -200px; width: 30%;} + 50% {width: 30%;} + 70% {width: 70%;} + 80% { left: 50%;} + 95% {left: 120%;} + to {left: 100%;} +} +@-webkit-keyframes loadingbar { + from {left: -200px; width: 30%;} + 50% {width: 30%;} + 70% {width: 70%;} + 80% { left: 50%;} + 95% {left: 120%;} + to {left: 100%;} +} + #content { position: relative; height: auto; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs index 55814bf825..0de794588b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs @@ -94,6 +94,8 @@ protected ScheduleTaskModel PrepareScheduleTaskModel(ScheduleTask task) } } + var isRunning = task.IsRunning; + var model = new ScheduleTaskModel { Id = task.Id, @@ -106,9 +108,10 @@ protected ScheduleTaskModel PrepareScheduleTaskModel(ScheduleTask task) LastSuccessUtc = task.LastSuccessUtc.HasValue ? _dateTimeHelper.ConvertToUserTime(task.LastSuccessUtc.Value, DateTimeKind.Utc).ToString("G") : "", NextRunUtc = nextRunStr, LastError = task.LastError.EmptyNull(), - IsRunning = task.IsRunning, - CancelUrl = task.IsRunning ? Url.Action("CancelJob", new { id = task.Id }) : "", - ProgressInfo = task.IsRunning ? T("Admin.System.ScheduleTasks.RunNow.IsRunning").Text : "", + IsRunning = isRunning, + CancelUrl = isRunning ? Url.Action("CancelJob", new { id = task.Id }) : "", + ProgressPercent = task.ProgressPercent, + ProgressMessage = task.ProgressMessage, IsOverdue = isOverdue, Duration = "" }; @@ -149,30 +152,11 @@ public ActionResult List(GridCommand command) var models = _scheduleTaskService.GetAllTasks(true) .Where(IsTaskVisible) .Select(PrepareScheduleTaskModel) + .OrderByDescending(x => x.IsRunning) + .ThenByDescending(x => x.IsOverdue) + .ThenBy(x => x.Seconds) .ToList(); - foreach (var item in models) - { - if (!item.IsRunning) - continue; - - TaskProgressInfo info; - info = _taskScheduler.GetRunningTask(item.Id); - if (info == null) - continue; - - if (info.Progress.HasValue || info.Message.HasValue()) - { - var tokens = new List(); - if (info.Progress.HasValue) - tokens.Add(string.Format("{0:p0}", (info.Progress.Value / 100))); - if (info.Message.HasValue()) - tokens.Add(info.Message.ToString()); - - item.ProgressInfo += " ({0})".FormatCurrent(string.Join(" - ", tokens)); - } - } - var model = new GridModel { Data = models, @@ -235,6 +219,23 @@ public ActionResult TaskUpdate(ScheduleTaskModel model, GridCommand command) return List(command); } + [HttpPost] + public ActionResult GetRunningTasks() + { + if (!_scheduleTaskService.HasRunningTasks()) + return Json(null); + + var runningTasks = from t in _scheduleTaskService.GetRunningTasks() + select new + { + id = t.Id, + percent = t.ProgressPercent, + message = t.ProgressMessage, + }; + + return Json(runningTasks.ToArray()); + } + public ActionResult RunJob(int id, string returnUrl = "") { if (!_permissionService.Authorize(StandardPermissionProvider.ManageScheduleTasks)) diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs index 1e33efda3a..b303fbb6ee 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs @@ -42,8 +42,9 @@ public partial class ScheduleTaskModel : EntityModelBase public string Duration { get; set; } public bool IsRunning { get; set; } + public int? ProgressPercent { get; set; } + public string ProgressMessage { get; set; } public string CancelUrl { get; set; } - public string ProgressInfo { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js b/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js index 5451a1ad70..4958bcdf53 100644 --- a/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js +++ b/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js @@ -54,7 +54,68 @@ var Admin = { } } }); - } + }, + + TaskWatcher: (function () { + var interval; + + return { + startWatching: function (opts) { + function poll() { + $.ajax({ + cache: false, + type: 'POST', + global: false, + url: opts.pollUrl, + dataType: 'json', + success: function (data) { + data = data || []; + var runningElements = []; + $.each(data, function (i, task) { + var el = $(opts.elementsSelector + '[data-task-id=' + task.id + ']'); + if (el.length) { + runningElements.push(el[0]); + if (el.data('running')) { + // already running + el.find('.text').text(task.message || opts.defaultProgressMessage); + el.find('.percent').text(task.percent >> 0 ? task.percent + ' %' : ""); + } + else { + // new task + var row1 = $('
    ').appendTo(el); + row1.append($('
    ' + (task.message || opts.defaultProgressMessage) + '
    ')); + row1.append($('
    ' + (task.percent >> 0 ? task.percent + ' %' : "") + '
    ')); + var row2 = $('
    ').appendTo(el); + el.attr('data-running', 'true').data('running', true); + if (_.isFunction(opts.onTaskStarted)) { + opts.onTaskStarted(task, el); + } + el.removeClass('hide'); + } + } + }); + + // remove runningElements for finished tasks (the ones currently running but are not in 'runningElements' + var currentlyRunningElements = opts.context.find(opts.elementsSelector + '[data-running=true]'); + $.each(currentlyRunningElements, function (i, el) { + var shouldRun = _.find(runningElements, function (val) { return val == el; }); + if (!shouldRun) { + // restore element to it's init state + var jel = $(el); + jel.addClass('hide').html('').attr('data-running', 'false').data('running', false); + if (_.isFunction(opts.onTaskCompleted)) { + opts.onTaskCompleted(jel.data('task-id'), jel); + } + } + }); + } + }); + } + window.setTimeout(poll, 500); + interval = window.setInterval(poll, 1000); + } + } + })() }; diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml index e79ee6d5a7..b6ec8f00be 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml @@ -37,14 +37,15 @@ .Width(100); columns.Bound(x => x.Id) .ClientTemplate( - "<# if (LastStartUtc.length) {#>
    " + @T("Admin.System.ScheduleTasks.LastStart") + ": <#= LastStartUtc #>
    <# } #>" + - "<# if (NextRunUtc) {#>
    " + @T("Admin.System.ScheduleTasks.NextRun") + ": <#= NextRunUtc #>
    <# } #>" + + "<# if (LastStartUtc.length) {#>
    " + @T("Admin.System.ScheduleTasks.LastStart") + ": <#= LastStartUtc #>
    <# } #>" + + "<# if (NextRunUtc) {#>
    " + @T("Admin.System.ScheduleTasks.NextRun") + ": <#= NextRunUtc #>
    <# } #>" + "<# if (!LastEndUtc && !IsRunning) {#>
    " + @T("Admin.System.ScheduleTasks.LastStart") + ": " + @T("Common.Never") + "
    <# } #>" + - "<# if (Duration.length) {#>
    " + @T("Common.Duration") + ": <#= Duration #>
    <# } #>" + + "<# if (Duration.length) {#>
    " + @T("Common.Duration") + ": <#= Duration #>
    <# } #>" + "<# if (LastError.length) {#>
    " + @T("Common.Error") + ": <#= LastError #>
    <# } #>" + - "<# if (LastSuccessUtc != LastEndUtc) {#>
    " + @T("Admin.System.ScheduleTasks.LastSuccess") + ": <#= LastSuccessUtc #>
    <# } #>" + - "<# if (!IsRunning) {#> " + @T("Admin.System.ScheduleTasks.RunNow") + "<# } #>" + - "<# if (IsRunning) {#>
     <#= ProgressInfo #>" + @T("Common.Cancel") + "
    <# } #>") + "<# if (LastSuccessUtc != LastEndUtc) {#>
    " + @T("Admin.System.ScheduleTasks.LastSuccess") + ": <#= LastSuccessUtc #>
    <# } #>" + + "' data-task-id='<#= Id #>' style='margin-top: 12px'> " + @T("Admin.System.ScheduleTasks.RunNow") + "" + + "' data-task-id='<#= Id #>' style='margin-top: 12px'>" + @T("Common.Cancel") + "" + + "
    ") .Title(T("Common.Execution").Text) .ReadOnly(); columns.Command(commands => @@ -75,12 +76,30 @@ From 113591587ecd33c9b76c342cd39b4b22262685e8 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Sat, 25 Jul 2015 02:35:37 +0200 Subject: [PATCH 0118/1074] Minor fix --- .../SmartStore.Web/Administration/Scripts/admin.common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js b/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js index 4958bcdf53..1387de0d25 100644 --- a/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js +++ b/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js @@ -112,7 +112,7 @@ var Admin = { }); } window.setTimeout(poll, 500); - interval = window.setInterval(poll, 1000); + interval = window.setInterval(poll, 5000); } } })() From 993b31ddbdab4341f8d8b7cd11c19e7132013399 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Sat, 25 Jul 2015 03:11:20 +0200 Subject: [PATCH 0119/1074] Fixed migration errors --- ...507072138058_MessageTemplateAttachments.cs | 6 +- .../201507092146153_DownloadGuidIndex.cs | 2 +- .../201507102159496_TransientMedia.cs | 12 +- .../Migrations/201507202149123_Merge2.resx | 126 ------------------ ....cs => 201507250039446_Merge2.Designer.cs} | 2 +- ...23_Merge2.cs => 201507250039446_Merge2.cs} | 0 .../Migrations/201507250039446_Merge2.resx | 126 ++++++++++++++++++ .../Migrations/MigrationsConfiguration.cs | 1 + .../SmartStore.Data/SmartStore.Data.csproj | 14 +- 9 files changed, 145 insertions(+), 144 deletions(-) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.resx rename src/Libraries/SmartStore.Data/Migrations/{201507202149123_Merge2.Designer.cs => 201507250039446_Merge2.Designer.cs} (93%) rename src/Libraries/SmartStore.Data/Migrations/{201507202149123_Merge2.cs => 201507250039446_Merge2.cs} (100%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.resx diff --git a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs index 448a071417..d83d2520df 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs @@ -15,9 +15,9 @@ public override void Up() public override void Down() { - DropColumn("dbo.MessageTemplate", "Attachment3FileId"); - DropColumn("dbo.MessageTemplate", "Attachment2FileId"); - DropColumn("dbo.MessageTemplate", "Attachment1FileId"); + DropColumn("dbo.MessageTemplate", "Attachment3FileId"); + DropColumn("dbo.MessageTemplate", "Attachment2FileId"); + DropColumn("dbo.MessageTemplate", "Attachment1FileId"); } public bool RollbackOnFailure diff --git a/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs index ff65fd3814..803e4557f6 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs @@ -12,7 +12,7 @@ public override void Up() public override void Down() { - DropIndex("dbo.Download", new[] { "DownloadGuid" }); + DropIndex("dbo.Download", new[] { "DownloadGuid" }); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs index 509169153e..52ac730bf1 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs @@ -19,12 +19,12 @@ public override void Up() public override void Down() { - DropIndex("dbo.Picture", "IX_UpdatedOn_IsTransient"); - DropIndex("dbo.Download", "IX_UpdatedOn_IsTransient"); - DropColumn("dbo.Picture", "UpdatedOnUtc"); - DropColumn("dbo.Picture", "IsTransient"); - DropColumn("dbo.Download", "UpdatedOnUtc"); - DropColumn("dbo.Download", "IsTransient"); + DropIndex("dbo.Picture", "IX_UpdatedOn_IsTransient"); + DropIndex("dbo.Download", "IX_UpdatedOn_IsTransient"); + DropColumn("dbo.Picture", "UpdatedOnUtc"); + DropColumn("dbo.Picture", "IsTransient"); + DropColumn("dbo.Download", "UpdatedOnUtc"); + DropColumn("dbo.Download", "IsTransient"); } public bool RollbackOnFailure diff --git a/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.resx b/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.resx deleted file mode 100644 index 19402f07d2..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.Designer.cs similarity index 93% rename from src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.Designer.cs index 7bb45d2585..8830d1f8ac 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class Merge2 : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201507202149123_Merge2"; } + get { return "201507250039446_Merge2"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.cs b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.cs similarity index 100% rename from src/Libraries/SmartStore.Data/Migrations/201507202149123_Merge2.cs rename to src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.cs diff --git a/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.resx b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.resx new file mode 100644 index 0000000000..483dbdf042 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy92XIcObIo+D5m8w8yPd0ZO1cqqbvM+rZVzTWSIiXa0cImKemc80IDI8FkNCMjsmLh0mP3y+ZhPml+YQDEktj3iMjMyhcpGXA4AIfD4e5wOP6//+f//e1/Pq+yV4+wrNIi//31uze/vH4F86RYpPny99dNffff//b6f/5f//v/9tvpYvX86kcP9xcMh2rm1e+v7+t6/fe3b6vkHq5A9WaVJmVRFXf1m6RYvQWL4u37X375H2/fvXsLEYrXCNerV79dNnmdriD5A/15UuQJXNcNyL4UC5hV3XdUckWwvvoKVrBagwT+/vpqBcr6qi5K+OYDqMHrV0dZClA3rmB29/oVyPOiBjXq5N+/V/CqLot8ebVGH0B2/bKGCO4OZBXsOv/3DbjtOH55j8fxdlOxR5U0VV2sHBG++0tHmLd8dS/yvh4Ih0h3ikhcv+BRE/L9/vofDSCfvudp/foV3+DfT7ISAzMUPiFkRmBp/uZDWsIEfX15QyP6t1cc+L8NXPL+zfs3v7z55d9enTRZ3ZTw9xw2dQmyf3t10dxmafLv8OW6eID573mTZXTXUedRGfMBfbooizUs65dLeNcN6Hzx+tVbtt5bvuJQjarTDvM8r//y/vWrr6hxcJvBgTMokpBRfYQ5LEENFxegrmGZYxyQjF9onWsL/9u3hlgRLanXr76A588wX9b3v7/+Fa2hs/QZLvoPXQcQWdECRHXqsoGSDuob/QCrpEzXLQ+Ftm1oKq3WGXj5XCQgizBQq8a+lQtYmqZQj+m8+gDvAOLJHs1xUWQQ5AZEv73drCjDOoMNXJyiRZMd1TVI7leIXTwW3BdYVWAJqzdShIeFp26LIpi5WT0q3BM0CZjHmSWFdps33IwIoI5NoWHea1bRu19+ibGOztIMCkQxLD2yz3ZrJc1B+cJ0DP2U9ytIOr63HK0jkb8gtQO3OUHLX8FjuiSsIJmC168uYUYKq/t03TGUdKHftOBnZbG6LDKVfCFQN1dFUyZ4bIUR9BqUS1jbd5pC5dB3ppZpCNRXy5HQNWQDspbZH4qnPCvAwktML1LwpkdwEMsaOdLR6GOTDq22vx0XMVLte1zfy8xtG1d3i0IlkQpKKeemxXRt9WI0tlBFllSNJsMg4eKMBYuRXC/E4zR0+ozGVOkV2jgtnVdf4VMoP51X1yVA/SVaXxiq7+sFXmnf8u910uNCuzG8TlemDchHXY2kpB5koLqtizItSgIXopXinVRrcI2iO+FWjTZtDB31uph+cNfFJEO7hOvsJcr4rNqZZEwnJ6M3cZwko7dx1dz+Eyb1+CbYcbF4GX0rOymh79YhIQ3WKcoUVoHGNEKj6JBBAyB6f5IUTV4HW/QwX3wBeQOy7MV5f1aaRxujpJrCPOqNHXvzqDeobAdEk9w0ohsWWDoQBkZn3rGAQVYd2y1/3YbGc1BuDMtU51n59ddRXN6ta9jkULJsXN/Wp6LS7RAjjfCiKOswqYdM5tJgrI3Vd1BVT0W5mL7l0xwDX1XBHgLsb2iPDNCuStYCqjXS6cEFeMGy+wus7wsfd1RXv3rDIDpILR2DUoS6eqlqaLJy/mqrB7oy7HOSNQu4OCGTDku8N54vqtE136FdvMGVL/om38dRgvs2r5BGsUZttOSfYrTdKEkH8AogPrPnYL3yS5qnq2ZFDiiPVq3K0Wm5MElXAEmhixL96iIt/vb61RU+N0XcZMQMnkfC3GK7hBWidVLHo8UZArc7iLZeSn7CtCwWTVIfN/kCrSS0sJFyXKa3TQ3P0qzGB8nO8vUE1CArlm9MqA8SV93WhmihjDYQPRqiHyBrgrGdV2hBIisJJog88YzMDd2kFpmJJW/o+hsjzaGaYLe51A0y5YSGYi7dw1pVt9URK3RFtMSOhKwPQAvDgszGJOZm2uO7gGiJ5DVYwlC7w6yGxnB73iPj0m6zjnZuiFhwEBSOhpTEJE8X8Pq+Wd3mlPfBF9kPNPG3WfDMEeFQ3XsI/9HC3qI6hAMOJg1eVHr3kLtSJ9jmePeqzxbptql3LdgN+IaroxkkC2revzl41yght2FYDcC+67pOuyoa4erFQanQiMeWRLi5UF3gApSozY9l0axRR+LoF90mcJ4v0sd04XdSNM5W7nrWNfnebm34x2nvaLFK85NitaKCbUZrrOdauEJbcrjJiSbn6Vv+qVjBiwi6Yo8nnsLwBdYACQ3su9c55eJoobixKRkHt3ed1tp7C3FGdpRlxdPg0YWPKXwKVnmP1uuyeISLSySN8+VVswqb6a9FHRljj+4abRgZN+jgPsZD2oV8XBdHSbDl8DldpTXuHNkbg6f46qEZf9GBvLkDCVZBSrSP1l+REbWRGqM1+xGx2OiNnFcf07v6BJTBJliPJ4a2cgn/aNISfqvvEcXb7SSYUzqcG+VHJ60jhTAdNVg3rtME60ZHiwXXh+AxnVebiPw40d2hM/c9z9oF3iMMHiOalXbBfbsTcHp6tDo0p8/rtCSK+gfwwuO0Q3GU1OkjQRGD7T+B6gogrQnGmlUWm+N9JtQbHA5xtCwhpBXHgPCADbJr+Dy+JnpeXcKkKVvsodKjQ3TykmSw7VSojKMxXsAyLYJX34CT7P0EceBaOa/wyXMbIhLMjufVGZr+/ig7WLtbLFK88kDWYzy5xy4Ne0e1+40F8Hz6jOya4LVwXp1WweREvTlBBtaywLEIgUYMyJFRdJ4/oqWJ0PVRBoFqY10kD9EOIbC5RjAePYIU1U0zCmug31jaU+8NK80jjvxz8dSOGu80CFvopCADIb17IQ6Bs6Ls+3gMkfUVeHQFkocCm9M4OUXwOTO2BjHG85aWyAIZjN5gjYIY/V0cSpxJajG28SdxMBICwEWHjAopH09ZRWsBd/C4eTlu6nrjXAhYWxj6Z1rdZ2lVx0HaLf4MIuZFcp3x3/jiPEHaOUGXJuEnWjSS6DvQt2wxbgOdYXJChe9Gb+NqjfCAzHEg9jivamSj96dsHrcoaFyn+SIAU+/OOs3xKV0U/urEFoMZjswUnWCbtE1kfFynsF2TwQIf7aGwqofDyJNidZvm3blcRCZEfe6DG6qj9TpLwzXmnzBd3o+3FFk7Jjr6n+liROyfxqXNsNOEypMBUZgwiXdiES/qAmbQJ3Jve0MuxAGmj7B8wZUdvSd09i/Hqseggt3uE8XsHvB9gaBqSthmNlOqk1HyUA1txo3EHtDiHyxqO9KSMAhyomXwQMVxr3dhIrDEkRexHB8MUkyN2Div7ovWnwJKd0+HOmqp3RKHLVIa/dKX3nTQ18XGV74Jf1FDCTFJGlDXECRaGuhCd25YQCFqhylXBeywQJ4BRpuoH8sYMf+QKWMsmCLEynFEncOLGMTqAfVuMU3oFA+iGoAA59lx+hBR23caUNN/GZhqDFJYz3FcpASPdggdjKb3HISq4zyYZ5+HQ3B1l1sQTY9ZAFWHOSjP/hIL9C5tE+TREcDq/suraMajr6Aan6GW53ivwVI7uBsGTpSnVLFSnNIwntL0ByhTpNTJ7Eht9zX1NBNkUUs1SzZVPaeKR+00cIfRug7Re1xsul8ND7KAIhPS5UouZIBc2ZA/G9Z0lgcVu8tCKDvMgbl2mfbhSLo7FMs4QygUeEGEkM2+fXbD4aaLR9bnTqkdfh3imtVtGaJ8R8pp2s9MjEiN7xW2lSLdX1LfiIru1OqbcrXKnU9+O5eZTxKj1kvmUbOLrqpOimaN72gvgmdGxCQ/fotz+kZmhsRHklUWyqMbTJh4rnEgJjP+ujCYYqLhTVfQ2fIbOGFb0gK7bk4SF8MYHgnzGATnhbVHokPVcb46r9bQpryGZBwyQPVQpNBBF4x6uzvghlGP4rAVq9sybMUjXbjB918itWxy4E93V+K4qBGfTnqtB7/pMvrO1C+jWBd6DhdmooysvdEXKwCw87Q5nlThm1RX6b9gWNvM1Z/qumgzgvC4vSNyOjzf2OCxALvDIgLoEuRLbcxWtKQEMe/GxY9f2OKbQ9t2Cr6XKQwEUpH0gD9S+PRFb1R5SuPYh48eJov5AFJi31h7YVsxLe395qSqB9r0mC8TNHkBICw7QN8Dz2dCuvoHxV0jvloSjfVChsUDQH8d5y4+LCxezPhLpMuPe/OOReyTW1GEyCGMJ7ecvPETJwzO8JwjB/EyVT4zlVkxnW7ktZV6rwbFMZpq0Tiu4LgxF6a+xkgTJPELRjldo/AdVrF23UR5DEJC9ssmg1ZZoOP4Va7WcPRTq+M0y3DUY5/eOfD2Y38pNQ66PvswMSCYxNdOHpsNmkHC69wUcSaPapROIj5lw/1smL1AsVvu/BWO83T6jAQV/aLoBDbyJv5hvBMkpXWsPW/y23uYKNyAh7xpRIfdRt2WYSMY5yHvkyIryk/wmSSknrz1nXjb29XOinD0ymE6rBp1W5EsrVgHQefVGQR4InoFYUa/tnKn2nCoxR2ADbD6EsDwQ2EUiYAjmHA+txZM/Y1ixV2I1wjCZQON7SAfRpcPNLn/FDKC5VbL+zZsJf2lG+YPxTpUVxhBfoTcHLLpfxRZEkmIHKTHNsd3TRpxQ3HCIURpu0KUDkFFOxhUdIiz2b04G69TLnZzF8+4ZOWCoiAFimFttFdpw+2MFk80HeEVzjzRtU+ibjoRQ54EzOvXU+jyJukdy4WNCTdJotY2nXoYUT7BbH3XZP8JK5L8NAqyr4UPrhAd3vUeukJvV9xWd+xoi6WjRQ6rCq1VU+oFoc4Nt54VI1LW0F+1V1cLOjvoV7WP+Ol1juHXwT5Rt9XT6GOTDq22vz2ySxuCxiK9Amx4vT1OKxbPgcdt6KwoVyA83qfDdgUyfYqpKNn1p3zVJmLy56O7uzRLI5ipJCdwsC0TSa8+r9pwkKOEeS7S++aATWxJHD76DKr6fH20WCBrZ4LrVDGtBtz1z8UyzT2vTOP6fWZpJQr/q8ItSRUKQy/6bygwKmJdKBVj1kUQV0WnC/kZ5l7XTR5W0lcWRN1hDs6117zNoet2B3Oz0WjEfvMwgsqlBHS9v0BHLhnIzYFKqM1AqInNgrnS+vQZKzQgO2rqe6zStKmPLmHS+gYlI9DVkE6DVQVhTuxquU4QUgOa1UVRKW7IDMXSgYilQq8lIF5dvC7WaaLpIylXd5ItlveSg3HtJnEwyXtIiqSdY0uEfnHFrl26hMjGyHGEFVRNMAMi7aIcQuiqAsy9y0+gXFwUaV5Xn9KqVh36S+AUvVfDScagAXYdSR+BaLXXCMAS8cfBqAUgD+icd4pKB6rOJclDScmvBBJor4YMMuwHgrrb9cjQKPI3HYKDTa9u6ywtq3qSqHCsvk7SkMnoj9MKYrE1yF8maEcekm6wyBB34PStj2meuJ7pnVAPooz4yi1Zmu+mauj96A39V7rGuhLIDCmoIj3ce1/k0Pi4ZaQXkPtX/cZn9iB7W23JtGtIuhX2G+0As9kAuSJh0+bLnfdqepFqO8dBil1kAJQdZaHCUj715AqI1e9wHLZndVuGDdPWy+UTj1F1jo9gDypBFiuf/vVT8RliIp5XhUHQvo8gkK7vSwhtG/xLhAaRoIVlmnCNBT4F/QMEu3jjRYZEC+kIjX3R2LH8TbThDpzUlqJhbjaVW/HGpSMxQ0usK2MVZ/uW3ggUw2L2CsnuKAUQOy+FCjILWXp47EA9Am7qDvuQRiztfWhqPLl0vswRrdv3bYMj8k6fk6xZoLXOXCPWnXzFOWfrVippHi8Bcprw7H7mbCFkKTk5hXjllWMHiewnrljdPUBfZjAdpJWReYOf351H+b69LeFjCgxSL84B9zaodV5mu6d6Iix+rRITFI42HPhGiErrcB3WvGbNd6QKvi9nEVwS557AOU7ciVhvrx5lNEYTxA+AUJ2lKSMlvJb1cVYsh/g15yWNa1dvKBzbEePedWaSuHE8eOwgj6dC9hilLEXR+mYDuGEnWbnASlKgYDZquxLAQxjBYS9Qt/UZ5MsGLINjNmPd3XDNbVUsYhzAeV3Ca5k92Gztd7YO34nk8VdXZbyo4yNtH6kbWfDN88DO4VrsNl6wHOmAk9qn5F4Ur92Q9+Vqt0zbrvayWdlNgnUDxfaRKZRu1yxE0F696YTzXk2STKX/IsBvejyHLVvd1jy+ln5mOqprTb4x2ke1/2jgFZziKPMsA8vzFRosTtltvKsR46Jovb/PSIzg7Wrz0rWTcQkrItrkwlwGKZWYWkBBvOuhg47sZKiDpaoE50HCmmVdhOS2hNYGETLSw6B966YUkiMZSecVXl0XWbNMc0GIGC8lFk0iEz5RVKdIQoFXqexEiJdQuFDcDY+VRoJCuR3eNqZ3ocvwJ6i6AcYLfLlgb/9PmThAmxvBnG/AiwG/wqfK36WLa7+hUGwHj/Ue3UmyjkzpPsaUxndL4rmPe4xSRqcm9mYDuGFrWbnAxFKgYJZtu+LPr7j+QVFSt7Xj3uOr+6KMsRwdmz0jomvqVqNZdPM4af+MPvet8qgenOZRRuZnsgxbosxMEQqluysL4XoBh9qf5Z4WLy2A96toVQU/y6nIsh9FTUyyhCQectYGMIrqDY9oO3RY3KujvHryCOZRmzYDTrldwxHihoanjBk1mGjBaGDD7GaqawHz3qI4KIJ6Phw5hnQktai9rvntDvHfZofdouf8CiwiFMuwWyItDLv0qCLpcqPLndMocstVkTgxXE4IKRItZIq3nAiSEAfZoG4rlpE4j3xoE7Z1mu74d9WjGWn3xdO3/BNSJC6IthhoL2Hj6yNJr3NdYEm5PVcb57FGR7tQqbUCiLSWWQBMgVTe+2v+GxmrlvOWG5FMnss2qqDLBBh1lJsEGNFBrqvbMp1q/vrrKM6zEsJoN+RjpT5FiDqJhvFwU2AQrVGSnfZZSlvmD9w6bFKU2s6utZSB5SqtKkMOQh5KnU1RDylKIj14mHLJ4fa5hg2TpkRYBQIc5JO3fBpVX5xHNm6eBBy95YBUqNEWsaDn2K15r0WsS0sapG3oEB9Wt4bXI11inCYFXj/L7eju0gkShPVNdorJhC1/w7xMuG+apo6SBFbVNA1e4AvQyGi1EvOxXzLXXgwdKT8zL2Tdsjp7ydohmbKHYCV1q01C54MIVbdFMkEHP9AcSQ5HioxytZsudvJ9hDkunjvnSOclhyaNum0HNwnMDV2kAWWdpDKhq7tJAYXLs64zQQKN4DhINHVbhEpbI9HwbGEEoYi65IS6WBTLW0juZ6Pdmwkh3f+RwqdAFDghtldCBAWeWFPc42vlrtsRwn5sCG4PUkhlreLRCqc9wdTBDkjaO/JT17UWIHwLCJT+B8GvbosQ6GNZNOuRT5lHuqs1ZXDj180zM0GEirI5YAkaxQ7Zxy3iz/Wm82YNq6X5DQ3ESXOqTC7NaYBwad51IkikExwHua4RMnsvjfdyjU8VLdOupXBxIX0oTSZPvMRFN7fOkqJ9aq397yAk1G0RAk307AppK/hVZzLgbfFTsK92Bjsr2FfZHB9UIuTFmWabaB2Jg+0CvOBbKVGRtWm0xzxJUnDMSVOWME9eJnl+qW/sEmzCRj/AJF2B7PWrixL9IlLs9bu/vX51hTMo/P76b95rgQ3ECp2nH6CeUqxcNbc1EonZeZ5k1xitFbH+6jwspjGctn6Kxq5xY2huyCvaU42QaXSakXZSZ5oRdo1NOjLUkMNSdm+MEY5oF0mxigCyMwjHpqm65bEJrG55bGp3+MdP7Ul4aHQm7df6uK0QsTJaE0jxbvIFXBytRh0J/QrwT1hCxHYR0qvfw+ShaOqjGvHRbVPDKU1pofHqP1YTvG7aqR6xrjkd3d2lWYrWZDT7YD06Dcj9IGzU4JeNS4jk1wniLVZ38mYphImOqh9vInGXJ1HDBdqMl8gAVA9woZqSUUd48vg4/kuyuKHT53VaEkfClyKv7ydu8z8hGJ+e9PpqHzn6AG/T4GsrFKqjhOybn4psMQF/iA1PxJhUw8cgf5jEAObanETE0G2en0zZ3PC+0HRNnt+CCZSLbjclCuCQCm/sdd8gg6Ds0rhelyCvQIJ/blSDyZueZMmoGr+EVZONT/YTsMaO9GkJLjY60WivmttBR592yBdNmdyDCk7pwL8Aqe+lb/411bHnpWsO2+dI4Kyb9rRkcq/xB5jBeq9e3tJYwpcQH71Rd4utji0+georfOq8OF8LfM8mYV4lDD/qZE9ppEeeZBnd8ICbY09ZuRApIQVyjcnTxg22LchCBtkSRde8AwV739D3Clnpn9KqLhQPJsoAb7pD3E1n1VDCcbIG1PVNkI/pHTHkjIOQAd58r+DiZ1rfC4MxQwuDsqjiOjhSC+d80/A3SQkn9J8rEjrLl3v17GubIkrVM1ys6NmmSN4zqty1Z5dwAeEKLmghdqp8C5SGMjKFEVgYjLmG8/PrqO/qpIN9qUh2tkT6UDxV7NOrtZU0FiB5accBKIQeDxUUviYXhB6vLbdoKqnAPASsqNsajkEDPbytVAt1E4/zztbmJMZ2h93UMGyy/UdhreihXfWFTqaMoSBYdZyVXF4rXa4t+AaiybAdlrm6rZ5eoSuU2UFjIGNehIl+sDiSQOmpaa/tbmoYFN3+o7Au9dCuAoVTtKZQ2q0GJNfpggROuJA5CBZ1W73fjJIKsuc+7KRTjEC5kUMVzqu+syRbGojgjeoRnhTNeiKn9iUixjrFDqIpvHZDa9MkuLmCObZjpxhZ29Q0w/qCjC0qf+po7ZxXG+4g7sO5/a0jOaDct2Qrt5OwgduORi5JteO5UdURR6QAVe7KKvigLZnqYdANlMNbSDbGOCJS8O2QKHr+Rfv4WyiafzSgG32Q0ZGn9UWZJqOH8A4NjR6xO8VoJhnJ2BHGvW+j1RHHJhnb2ti0myXMddrw1g/FU54VYBHhOavzqkcWTY3/jBZIXsEer6MJhKX1T5gu7x1MF8NduiZfZBCpWWD8QIZWwJ+QPHmx+FupKB1VVZHgqORFr6zITz0iakkqzc+kVYX7dx0OGqXHNZKDSGuFtJ1VQ7cGKFnHukJN13qIcL3yK3kLIkivxCgOeqW6rSja4FfqzY7psiv2VzGLTbDHVtq0Bklgd7AvXW6Sg3+vxSY5WA/KOi3Bd1iDGr6LdNW+JXgMHMcgA3kCA82yavRbZlM50EaSDNpANlm0iyysTQcniA0tcPwTp8gBQTajiXjc1Ifx+Dyp0UXUDDFEB/mnbiuKDnJdguQBUXyiQG9ySTeudUd4BvqGj3+AWfoIyxfP6pPrPtbBdfyiV8TeuYb8qQNBaYibjQwQO8gAKIMAWaigVE80yhhC6eB0N69IQqcokXSyQ/Rp/OXGxRBzHajWq3y1eNoriB3zS/gHfjPS30HAoDmsA806iJFQLNoiiGUuxTl8uoSgKvKzomy5aXo3SMe/kLi9oxwQhHVAf3nKbmq7G7Dj5425qsHd3ddiihQ1R4tVmpuv9v71lygPgjCyLU5euS26YudrUVM0UdjSMgiJ3SkFCzQ2C6KcnaBNKCyegsd02Nl06z/CznYByk6/cTwhbM/zPCrSUxwjwjKaBzJOWMg8KZbQkoQl4iEcFjGaxzKO0rELonjD3ArrgpVSNzQ8bWMowSSWhho26h1joSHZXqIEMvfb2yOrO98VWpEc86pgzF2OcujbIblao7XW33EfZIHPiRSoQVYs32jxHrbH0eW5nPDf1mwiEM+9AievOkszNLAIb7Yjvn76lnfDvqCOlvyTYHkn4Pda5VpWly15qwriY8hWtZx9sxo+8RitHp0tCXRYHOmiRRVmPWiH6i04dWgPctNV4I38eNS4YTZjSDA5mRTvus+91PnznQhSI0wuyrU8bbsKPJQC6F5d1A09cIwg/KKLvYPA+zOIJh33Ks6Lp19ywllzwLINsdSuwTLcLENIDkvLe2n9NdIjZaa9Wrsr32ymspJst3Sxah9lYGLw5g9QpiDfpGs/KVa3aQ4CNWIz8gMvq9u6emgisLLh7n2d6g5B4zTyBeTNHUjwJJYXaLaNUWdxmnX0TRtuN5GOxML2M13EQ/Yp7rUpUEFCOddoZEu0+AeL2uoQ56iq0mWOVlFK+Oh8oTuDfhfnWLiPEsS+fcczp/7kAl+Cdb0JV5ErecHOtJ08XkIiM3mIc+xDfJ3fmvrbHUHanvc6E1WdVI1iDt1ur9n8blgcgiZgW1XlWLOuH/PkxKJttWPVopbPYH1drPQq9h0si8NpxHRVn2Ez9WOcNfGNxVcND/rg6AK9QxPN0XoNn2v0abUePz0+Ts3zR5OW4ZfVqfWS12WRxYgLmen0il9CDuLVVaZ6C1Ke53zGI/UH2dZxHaHe2WoxVB4xyfOodQtIa9woJa+RBtr6KseCG5IYnoeIm8lhF7HYRY6yFBhspwiSeiYX92ipX0I1pS7Na2x1iaA9cLu6LQXdwuNodmgRGaIji6wor/5oQAmry+Xt6INqfUuLf6KVQAf3R48dba+bTtDQeYUwoY0cJhGSKAXokBwmIhpiqLWf0/wBB/rOmcPOVdvaHj3LUu+0U9a8dqTrFJadK9x7+xlwHPYanWSLE/8Z45ZFHxSNmc7TdR3qZYh6McAYeo4HKl31A+vesKCbdS2HEFauAiym73TThMSGFwo1PdTZ6faRQpgRfW7O4y9V+99BXqjbmihWgWv1e6k7xRmp0asqO80xfLCCdAUTxCtxBmE4Vi0q7Z3aSIeMn4tlMRxqzuaA5Mder7LjYvEyxVurRV6j9dKfR32F9VNRPkwRHIAE0wtZwidNWcI8eQn3rBOcp8/JPciXkDwW6otas38oG5EH3OER3mhrUeF1JmAxftVYw32DFGfGPDIOXDEkBko/FhY0aCPddMvjYTf8tHZRvrzpkRx2VHVbhh3111H2tn5iDA+X/DpKNgn7bOF/891OPhcYQThZbQyWs6JcoUmn7qaN1d7ndJUiFrsuWm01ONgGL7DqfpscQFt07ZkfI5Ftp/kCzWx0DcvNvPkCyM3cQCunw3IQzeq2WvKHalgtlnkMJw+/jL2P7h6uIHH73WY+JjepX71h0By4Ud0WIdToNkYkPrXw82taeR/HTB2T+49B8nCekyjNq+aWOsL19lcrMB6WRNQJHs0FHivDzhyZqBWsJ816YoIVLFRjhZjeaFVjEt+0AdR6HFH81vR1k2u4Qup0UHCRDN1BkKjbmkc7+5HCJ9TV++lb9rXY7N1HaBqWRfkSgZd5VAc+PvDxZHzcCfcIbMxhOnDxgYsn42IyFWkSFLZcrFZF/obHdGBjdVtx3EdoRB/LollPz5ao5RlWocE1MFIU9piugqMku4RJgV+tdvfY4tABhO7NgOSw4sZecXM6bLUxcM5BvueLzSFY+O1hY9jawKPKsDU5hGBqK8CCLOzvZcgqLN4M9Q8LcJ8X4FXW6M5xR2o1Vv6EzyBfNmA51k52ldzDRZPBa1A9+Jz4oGrVGxrJYS2p2zIGhozCiaZbQrbNGiMii3wR+JIlrqvp6d/GIVCsmNC6WH/LT8uyCH7V9it8ri8bn9dYPgPydEhZe9Y9zRe+rTZJAqvKt12abOOFuZ5Xn9IFWq0RstosSzTaC4i0HMccQn1d80Oo40aeHN3dpVnq5wIb6labnwfJr27raLHAUx4cWg0zGOF6n6dmojQjutHJLYiePW4GKMp44AtFu0GACDuUg6BC/Nc/AhoQCMtgOrC+ui2D0mN7ndd1M36parhCdHgi9uHUzV9i0o0dEjued7lj7g9o884rvxgYYaUMyA6L5bBY9mmxnBVlswqMGCM4qjcCqsNa0XAtRaePTTq03P6eKdaLzGBwLrNinSa7GHUm8K803kwNJah/GtDATILpI6LFYIL5LlgWz2G1alZrjMBOzEOxVup1EQsT4s9/wkT7QOw4d75wzsPpD1Zx+kMQbIOeV50xe/xy1NT34T4zCuEl0hzWKeWX8cU5kgyl2ViRI4YWKzcsPJ0KRgkmyfiihnUN190sHZve09DKvm+ATD2nIIO2AOIEQZ8+Fz73rlCtJVpvbygsB+mvbosiE25yayLzjU97jyRDRxIsHJkVR/oDzI0AT5/rK8Ekh/tq2KiPuNINyYSKrFzb2+iipCVjDHGC4Q8iRd3WzE4Lg6fm/RYdVTqE+K/WIF36ODC63bl60+M4sK4374wVEGk0U0ZqGKfw2bUtlj+iDsnT4OB2J4so4GrCsAw5VIfV6L0aR5Lkx0lyiqYs6441oS5Cx7YLoes/UpBFpPU+TXxdOwlJgp+CCs9RGzWbyxXMF/jaJ8iyl1BcR3UNknts7Lw7S52TcW5qvw+q/RdjbWtZ+RU+VZ8hXuqBRy+DyJRjPEhOdVtyigWfxZAlqROHv46SxSqOPImqdox5h+XkHiYPRRP08kX7mtkbAdVh0WgWzSxB8Dv5PNLVfbpeY/iL9qZtLLzn1TV4Pn2GFDV8USFE/W32aE8cbsdjULH0LbWnj5camseJ5LA3Ehm2cQba1hEeIbKuGPTwkLyViEL48CqLaavmKRa62uYR7YenTEaSgPaSa3qZxR9qOAs7L5l1ie8uY76+AC+YBT6lFQ7x9BdaCoQHqaVuiydZqNAiM7GlwWb8WKXrTMFDN2LlzTqzrSOsM+uKUddZvAV2WFkaJn5JMthuzYGrASO6gGVaLMKj1GqQEXyBVyvJpUC8JGP4JWI5XyPdZzrP0zoF2TZLMrqLVlLshq2hFl0MoFFesdCuwRnK/X9qscybbM7y3Esskxz06b/IM3SELF6RHgQHAX4jIDyIZ3VbcTJR+OVTkOAh7xHMl8ppaH+upqdK66QURv1MSqWPsLJuNuAbeaOGEgSpBjRQ1cvIauiz2XpnI2QRHQSJuq2LPj30uzARMOB5P4+T1t7VWBZVhZZFFs5lPKoDn20rnzloNSEB8IfAd8NeufwMH2EWfMfovihrc8aQkWLpzhB4vMYNxtx6SBQxckCU8haBYTkiKuhffoxDCMTksCxhOUVbE77SZLrhB/9o2lfqwi52kOccP4FKn/zXh3R+VxdUVxa0VxXiXVG4gt17Zh5pgvO7dNmUrcXa4TmIfHVb88ST7mGWXSq2wis14fMbCsOBY705dldzpJM0Cj6cg+tV7X8HttGsfXIDK9JlFpOHP8maBTzPr1LUJBj8bf4RYBegqvDNMVRQRwk06BGOTovrtNY+hBqnlUmC+L/AGnQ3+HTqfrzGPkAqVHyC9qaZq8j3Di5hjkTyUfUzXbSHLEHYWiz/VeTj06Ft6mcJ1p3+L/Tdpj4ytZ+YeQsb+XGBN7gI8qVMi5JI5aDzZDywa6BLiO0zF+o9uVlRO3J72Wa4DoLZFRnT2LXersjz6iwDy2po0f8yh76laLs6ogma3OwF0ZCeFXYKvsDVLSx7uZoVt69fEW3999e/CNPFwOLbMsQLgAxiOFR6p6/UPnjTwUpu17QTQn88qqoiSQlhOhz/aGADFxwNb3B3uKGd5otXramqrrKxatuZw9awFBpxIaJ5ukZURqz0++v/UxioVXPD2fCmuQ/FU54VOGkN28Ivb968e80rYt/yNizhFY5xwMGMJ6BKwEJcWoiYC/ZLN1n4gB1JoArxTZrXoqKX5km6Bpn1UDgMlsoi7uHQFl/yAa6xlM9r6+mz6UR/vUvsyNAeR0ITxX57S3GnNdPe0Lf6bFiWqWBgWE82ZZuQMCnTZ66NreJS6Uim5VHpfNl0gb/uOTenUouNZjE3sUcTZjphS7cqYWfNitkqbtaPaDbRK5lTm75Q1WZj7+688iIlr9XedP8reVoOLmNkFtKFgxVtSNhWgXx+ltUPYQI+1c+TTQe6KlvDmF00hC3T8K9Ij8GY3MvTYhvbz5jsEGZgTHaerBhz82D8LIzZH1IYZSUPKGPGzZmJPRsKeO0lI7GheMxejKTqxAQspKLrLki1D2nVqsFHazQp2A3YjSaFlZKRdJVkTNXDuzCVtg0Jg1kybhBpupXuQpi+ynhkGVqwF/sRaNL/6G7VY63TgiyyWi6Uibpf2fZP5hIS4cyT6CXWrEg3gYyzIpFNP/r6c+txN4hv0kdYvpDAIoOGxQBrdDgP5Y1FLeM1up+jbZ+63kynhUnpbMVVVL25OWtQB4YtycACQgUNh/noZ8pmHLbRrbEUlKOYjkuV82XTBTrhy1ZwqaUhy8OPzKM7bMuqxjADg+6gNYtzFt4BYhSVRotWBixjTBrOhSul+OewbnUdmYCvdHTeBSu3Y2pmGAxPGMSSsqJGCvrynLFJCf/p2toauWgc0XQC0jifNl2h620VZ1vu6LI6E/HzDu/uunHMxMA7uMuT5IxpvvwC6/ticXMJEbYUB9KeYN+A1vloripjYraWC/9atCezo0hhRG/kVY2UOjRtj4hR4E2PXtlpGbSULjSgE1mkLdhTYv4FrR3BBEtZO0dWpmRbZbZF3D+qbWJGDk7GhsOtTXsG5LHas148tVzRhwmYR0HTXWIbVvSYppldLXFZiMUtYSStlIzPTtL+TMhUUlrbtM9UnO9AvL/0unkeQ8UBIqj0UHy4eutwKC5iljCWHdP6jP04zTKktfQNGLvJwkenAofenhTi6vKgRnejY3OH2tRfvoKOHsN1EXeyCM3INjEF2edXoEyjmEBimebLaj+kMjnMIq/alFjtZRpkXpCebzJOqXhIW0vGr7IKLkyrb1DCuZukWdvGuVZDmYB9rebQph90YrpZePg4K5YXRVWb+VaAlPFqD+TCnyLineJJZfcn4EPlnOwM73WP8d4MjKPjEh5YxYHDC79uTCigl/ChisG3gw9VI5iIFVXzY9N8X2duj/wlfEzh0yeYre+aLMc6L1Ngcs4bqmv89EJND2e9qXW1374b3dZxtdvApnPkW86zg0+/rTgb++Nn3c5ruDIrAgKkjKl7IBcmFhHvlCKg7P4EXKmck51QBHDv+71jYBwdl/DAKg70UASk6CV8qGLw7eBD1QgmYkXV/Ng039eZTxEosswsBRko6bZeZE63xlmEOyX5pF2fYi+WzcFOSDzc86O8esJRAIWQKIxlCgpOxWctiCu30YhlmqGEgbeD1yQdn4jbJHNhpeIh+Fl57UdRE1dVUpSLG4pjdOyhqKPiQRrclRNVTSm4Us7u28GbhqFMxKeGubPl2bbWfJwLy1Va4QxN3Uh6lz8eqPpsTF9Nyr9cDSf+1bemORnCACOcINoRSQ4e/fxwJmKcPuOsliA7aup7zIttBjBugpS0saotI5Wuogv57DqwU4eOTkOaQEo6zbFNf2Y/jjwrymZF3K5GBhdBZdw8QLmwrgS1E59GCchRd2ICzlITd3fYiKRBtuQjFlbJSF1iZkdO4pDPxEryXkzFS3IC7w4z3ZB/2yfTtJNNASrZyJmDaKQS9qH6tnV7pqr/UzGeZD5smt7U2gYh1nKNhZBphzyG+Goxq5hvS/lO0vVpBR4zH9Z8twXqF8UvZi2JGnB8FYxCruI+KV9vCQsqxjCpDifOj03zpMJsrNi+82sZSSwDlrFi92SHPRtKEdsHEEfS33S9mICRdNS1aZ6tOTNHGe0BFiwiF+2mz0Pe98m4bicthj7P1Hec0r9/0XvIK6biEm0tXaYyuoJPPjd5g5rUY9vHpVZDmYBprebQph+zpyqTjqSVfE781C7jqbi3bU3CulKZvaV8ywxiLqZl5s2mE6TCvJs7CdPR8ygHp9zeXeP+eLy7w4KKnk+1w4tzsUvMZkp3IkCOwHC7mNBE2ftJ2W4Hk5d8TO/qE4ADIlCX70EFFz/T+n7DQSp2MdSTsWVfxYUrTc2oxKKM++Pdbbfs1QS8ZzkNVpwoxTA7YzJKxMBCJn6R1tIxpa/WqG9Qwp6qVTC/DLUayoQ8rZ1Dm370dbaLh7/TS8yNkZmqk3Ez2+ruKKL2g5mLqaXzadMZpuK8auvXooY2NtIGTqmyYhBnlZXCuzusqej5VMqqOBfbbyNdwie0fC4KhKDq14/R966rJGNDCbwLQ2qb2ykvvc1IJuBWm/nbCQ++bCB2ioCxprXYk9o/Lg35LZigpEc4YSW5NacnEgumypnpeu2Rw7o724u84xOsV/k8bP/m0ve7tZl7VjHxBQOtYzpXX5y8AVkuPwVXbw8LSocwISdK58im/QHBvOEFfcZeu4gVDjpisAGPOSTpXZDWrOrJVLqzisa2PLXegsiVS1g3ZY5fvYI2NyPk4HJ1gIJ005ylTeyYzqwbwyTasm6edkJP3nTaUu6pKkS/tBdTADppJgVp9gSU7V523OSLDGrPZjR15FoKC+6mqaibUp8fUmMYbbOw6NkkaohxKmx6sak1o4rMjcS4bShrjM6Eu7l/GIcxB7/u5C4ijMIUVqGqMDqn7mKshWkQc7DpDkZesLnxTBwqhTZmTvROl7iTjKkdwQRcqZ2jHWLJqzVM0rvu9v9RXZfpbVNDWxbV19awrLyiBwsberCDLG03oulY3G6Od4Hl5SP5tsZ/3ig4Urm7u+OSKhgaNE7Khkd3ZD5mq2U5/1IJGO4UGos/b1h5FqUYtnQj0TK4n2zXk3e2LUfbLeu1Jl/686+48LHPvmPZ8I3/+mvxzL0K+235Giw1+eFEWM268VghDGa1CoaK42U863D+AGUK8nqYlpNidZvmBPAGrZj0EZYv1+lKk9fWDY+GcBoUHjS17pDs7iU98NG8sJ4dnU4uuM6pTc/oenMvft34LA06CxRbwfE7bN85DGs7lsYOWnoWo/pHg0oQZ3zP06BVQePZiqXBdEiyPpiBz7kZyDq6HRwvm1ObntH1to33fXcAD7EfgaH3ScBvj1TfI1HeD8XsqbNFMA+Da91xwhh3jeXn8L65zrfDItgaZxs/uB8ga4YRCtzqyJpaZA6rhOCJsFT0/VEvG9Oq3drVYzXg+VaSFX84rCoexdyLy8k0sNX/fbxoW6XJz6yu74VOfnMFVusMfiie8qwA6swGcvDI3MUhl7kN+36OzlvyvkzIXXJKW50GMDVn47DrFJZo1AlkXhxRcpgcXMZhA6QLjynQOz5/Qvhs7j1aP5QJWFQ/VTYdoOttAYOaHBEC5AhsuYvuBWXvJ2XC3XUhUOH47U9Lj5iqnmY/Vl96sNiZle3tErNajmW6Ld40izY9YSpuETu7M/J0LOzDvDF1S3VXZuG9fRCfg6V+lmY1zu5uvqbmgMOKJ7nqQSyq6YrPtbYtlL3mEc6xFswsYC+T570uVxclVozSFShfTp+Te5Av4SWo4UlToiaSF3UUsammNGYYV3IKDja2IjXMur6PI52t+zQBZ1rPgp20VqLZDgYlf7hxJlMlPkuy6GfmRWlnpmZCKcEduI+pPxvbHYPk4TxHfUkerprbKinTNtbWeJvYVFHGgoo6LkxpbHanrhjbjmYC3radTxdn1tZxtckIM9SbmKd30adgOZYZGXoHrbujJJO8267kYjm4jHkHSBd2VaB3PDiYn1X145iAQ/XztDOnBkd3d2mGvsAbU3IgAVLKkz2QE08KmCd/xE/ZhSk4SUVYm7bnzn5GXq90Uz7VVZQPlPpuzpqmZnroe25N0Uz8ndAR0Xgf0Yr5glgfLOHNWVmsjHynqSN3idLgbg5QdUPTs51FbyZxThqJb9MLut62MN914cp6mxqjMh7VzOxsJ/ZleqYTyW7Th02tGU2IOn1Ek/O5WN5Qv/FkauwIZR25MTGAuJkT6lZkShzX+S00K4zjmcS2MM6dlW7IVt0K9jWKShnwSAy7m25H3Qgm5s2dVB1P7mHyUDR8uL3wWZ0l1xKBNGuutK5TDl3b1mVMLYxx67jbdXgTcLzrfFutAr7yjOnLk6ZEpFhegBeS1v88TzFe00MqmlryZOZsBbd85rrG7F8SiaLXWnVmAq60mgGrflD1toYL+zdzBLax5REVAhve9HqsyrJ5Cbealsb8Qtl1dDOwv2m+bbrE151tNXwuEpCl/4KLvo83n0G+bLA3QMWA6ioyjhegXXhd05SEu4eebx1Xm8cxAR+b582mE32dGTnWwrQzmXSOppyvCbcVt55mst52xGo7JTdKUZ0a1YBlH2W3AmX97fafMKlxEXxG852QjoE8L2qC5e/fK3iSlZgNqt9f12UjikyM+grWkuur1etXbbHyDrDAjDwy2MDF6QqkGdLsQXKPtxE5VgmgEX1/CVKGcXOX1L6Php4ZUbX9T5KikY+SLjci6zbdL7C+L6QjZADM6AzR0NIWjFHwro1atWKLVoPMzDpppZymvsyI5ATUcFmUKZRh6QpfzKNJk7oppTi6IluC6DAxENbkwe89pSVULVsJmBk1lcBQipPJHWk3cO1EsDAW89HCfwF5cwcIuXSLgwYzojbhdELW70FS5hv2egOSLl5CSrghxMTUEcwCqlVAysxE71/AUos7FsKMEO1/+ObcI9IEpD1jAKyJTTZa+WLgQIwoj7NieVFUUlx9mRFJr+nKkGxMDRMSrHTDqxrbepewImqQFKEEzoj8K3yqVKK/LzOvySLLjvLqSbEUh1IrRCoU1kyAdUcdB7QhgqaewHKVVhXS0dq4OWmvOBizBvKMtuUcZEdNfY8VzTZntLoBHbyxMRI7o+LgodAOzXWxThMlHlJqgwioMNj14mNZNGtlL0ipERFxHMpwdF5Yy533Oz6ib704cskqATSL2Y/pHdoIy4URuwTQHrsOoR39VAJjKLRD87WopaMbCo1oxDfI5fSSvlVuseepNKvN48uWSFQUY5+JNo6WeuRTPkzmDVZj39iXtOT94188s1PP5EnxNYqa6jkG0xg0yfel49G+suDVmH0ztsQj2fqVlCJp8u0QaZLaahrQ5ib2a9ihNdsmbHA7I5XmtnPofHc+bmhsyJ4iw0xlsjHq0IXcmuyuXxrVJXIfUGEYDFcsbTrxBRAhoexLV24mzD0yUglNb+UqHANgVuHl13KkGr3qapWDyXgNV+sMyBlSBmfrwHjRIeZhrGWMBicHYlYsYA4Rx2pXJA9jNn37GytS23dzmciA5nupQTMUmtk8uYeLJoPXoHqQsjlVbh5af4VCOrTNnRQT70FQIX76CdPlvVQdYABs0X1IkT5SKZYJD2Ont5sWn+TShJGJ6VBZOQ+zYclGbhvixOT8RoXv2aMifn09ujaw1CgIVmuQLqXE68ss5peQQiulWBAr58FnWCMj1TTFckjzwPnAIykFxDgxV7TKfV4VAWfU1GXn/SrbRBHP4diGDW47XxN1wCvvsuRA3thZzFALzdEAC2GewrKoKlQx06DkYSxGL139Nqse/apVKlBbZNZ+wLPWU74pN9Nb6bCR+2qog03D8eDNWYo1L6qC7oywheZPYDeH4upKw4n7MDL1eaVwxGvVQH8GTzVAnVjy5+gshdyod8OeLGppx8JaDYypYqCbNbVYpBJacaepMelFzRRzvmvLdHQlV9agSTAmC9LtSKirmzIP4rLnizfDOaNIUQWkenjyCjLaCcegGqIpsEoopUIXgUr9rmGmkizXh3Y8XJKPSFTikniIWGNQqd+DdFwkwKjHwIPKaEJvixpyCKjGZZfexX9ztF5nKVxcF3Q/RaJo4dWj0lWTEYuKndDQSotVQjf1FESh3IY/beg2QLuMr68Uk2YDznGX3NCwPPBDQzJpBYsRyupFIJwUrUwRk44zloBnX35Vi3fNC7EyMSx/CNaCI8zIZCRiA3Vi0WaQoRtTQ0kfEdY4LKGKhk6WUl+JeWwpxjds1hcEUPtRmTUGT3JNozTQ/m+d4iCFUw9GBi4jERfZpSGPFOMkaifTMhtqpmQodR0jAyiraljMnozGRiQk1WKPRFfzGpWCuw3UvFbDCDnNkmUj+m4uYVWXiOnhggooFKloUUs9WHNlGU2F4EQNOS1akG0bmxGHk5UObLwZAjAllJQCaoYmg5fSi4u91JFLinNkCvV5xTS04UHUI+AgZfSggmw1pOARTUQELg5WTQoW0DwOdmqDycKikxBHz3U+foj+YhDVUYknQoTSOBAEYKk3YhPZrXNGiLgkVFESOYQgx2mWIRk3BIhrqMKBWgyHrRGBPhzCiYjUhYFvrgFqqCTAmkfFV9HRaRO0bkEuAbFMDqkmwINesqDyzf1eCdH0FdQD1NaTkU8RFq+hob4JCSGp8P1gQvZ3BrTEE4HUoxFgZUSibjFoCCOimoAYJ8WKnIRsLlPI6SHA6cfBgwevPClSCX2UpPY3XS7hYwqfPsFsfddkOZaOTIHGijHVNBocBgTBVLVsRiPdVM14kLu/6KJdmyKQenQCrIxe1NUbDaFEVCOvTdxgz++bG0Byeghw+nHw4MFcJEUqoY+S1D5rs8gyLaOwAJolQMNJnQXtbSjdKmJQjMwYm3tcN+19LPnQaRB9zylI1fCHW2UGItCoZG4RGSU9SfCjqIn+QLKp03fb5ORQgevHo6gVLnY1uBV0U0yBD/W4+3I33I09CQH1NTTj1FaUcpt44U9HRz1+zbbVjTWetWckogLSwjQzEs3R1JucSLoLlFrTz66ieshW9WUUNVwR1VDZrsmRzcXhXqmWuhIo9bhEYBnd6NuuGiJJkE1BERJ1aSYJB2YYBgutJEofCmqiCoduCrLc0Bd3FTShYQwjoEAV1ABmMtBIJDRgLiLHZI7uHrSWM1oYq3lsxxKHJ1pccmIIFA0SGvR1cp3YoOBs1jo1lhiig0Kn4hA5gT1o0ybINHt0pXDqwcjAZbTpr8tr6CJFNbIXt21TJ085CFP3dVLUmgZTyU5ZboGbTVokdTiYvIJ6WNp6unAwPoGBRWyYvA1NbNholOwyQViSUZJ52Dw+NvHwCARkkw0bmdl3CRJ/i5JePIhh/WwglavQ7C7jMU1DAk1YiQhk03lNCIkzIaYJF+kziNxcoB7fgwoufqb1PZURRCSNqYp6cIaaMrJR2U80VDMhVrFTLOeiLLHLzSY5i5qG8grmgUrr6ejnIJn0bUhIqZyjWJT8Tk+oNTnZWo7jZSqPSVi2odHlHs7PYxD9FIhBTm0glRKvSxZkkngUpjFJIEkopFVHtfDqIemqySilyIekIZq2hZH1WFnbxhVqruQ2WM9l44jXd6484zbJgZiShByEelwsoCr20nwFksMz5sKkE2rdbNJ0qYnAAprHwMDrSGJW0eQoZbFzKip7m859HKzRo8ADmmxgDj7InuZxjexUYLKnGaS5FFInIGQV5FKBzfGmlTpSpCML7U3nzSykhLU4K7JgJMfTp4nZiU+dd0On0JbJIzW4ToQoa8llk5DyTyuf1MjVxiSTTjw+FXXrUg3sMEjd6gyk31RrVGhY459QwjqMS+OtCKTYNL4LNubMfEeIA9SECcjg48bOTUsieWJLC5IZKhoHq6+vuWqlTNppJrChzZGvX2kyld6o8otKlrcHGs36dMcmFQr6rK06AeHRAZlCbccU0deJPv2s6+LRYvPlbj2FJ1xm2o5Yz6mCqQKSBzBJepVTxoAZSUBDB2cOoHGpZVTb/1hU0eQMts22YI3CSAFbTBpK6zMnmyfBugvTZXbQdcm8f9vUDqKKeScfc04mVaJ0HWEf8PKaDgZFEFVoTDNNDNMFaaI05kG0sabIY4X4LwuPteBF53m5vm9dq75a1/UevFZRHYPaWsWUhxmR/u274IpCh7nQ43Emkxadwxz1KX3dJ0rfA/WkGbkkQOm03BYcZb+tgLfTO2cS1TdXYLXO4OZFSTV1OEjzkNgKwRTi0I2cgXZ4SYK5dyGjjwJSPSB5BRl96LcuNBRSIJzgisimZc0WLwLZDEWzjTuTZdKtmvLztz/N2o+yinFVqGpqVpvmiMGphamJ6URGHwKOSbqZiMY9ams4RXOp7jB4NRYrUouP+bpQXtP4ZKdw+BUfxAHpCpQvp8/JPciX8BIgU214J0jiejZW0vh5TXXlia0KU8ZkM17plrN5KSkuKckf1jRkoS0HyVSKQTUW4djkUjzMpD0GNtZRj9RUVZpjRfnMlC6riKmhkY+IVe1rtihTFffBararqESdZusaHqUy6tsKSPXA5BWkWduoZ7N0advkCCfQt4f3rW40gUMikGYoPKyULNSTWzqyCLhGDhISnr4yXxJ2FWnqSsrLkPYrToN8ZAHGPvB1c1YWKx3pdOA6XUxZS674cc+SadU8NeppSXddOBCOArYe26ZOZKJRiEcmGfVi243weptMwKvBdUJZWUsu6uk367TCXo1XJt+EB+yikk/HbFI4u4HpWMyLUpMF1EqfmLuRvGonCbC1rasesi0KadSa6h09XTiubXsyskueA4wQ9s2+kXdznqd1CjLNDRRdBfXItfXkseDCC3/acHAd+nEvQ0lfMLwRXx80E1NZ137gKhQ2JLa9NGXZooTqxkn1TdJKv8doztAqh1YPWV1JmZuVf0ZSQ1AN9pGT2pl2JMudyLQDGXeeMXac3962CHBQMUhzWA5lv73FDxavQPfht7cIJIHrugHZl2IBs6ov6F/23tTsvry6WoMEi/P/fvX61fMqy6vfX9/X9frvb99WBHX1ZpUmZVEVd/WbpFi9BYvi7ftffvkfb9+9e7tqcbxNGLvuN663Q0tobaHZ5kpxuvUFPEvLqv4AanALKkTxk8VKALtagbL+dvtPmNQkuvqZkyW/DVTuG+wfJKSPK8WZw2VYP+pr4d+diw+3SNxkb3DX3ugOZTcUPUODxAKBjBcqzk3F6gjBFVo8oOyXTtf98wUiR5E1q3zzN89/6tr4X7Z++8UewwdIPfNLI2IKHPCl1ToDL20OZw4jW+SMs9vpJSi7EnuM59UHeAearOaIv/ks4vrtLccBPK+9FZiNkwA8B1vyt/QpyzBGl6D04ngrPOOwPtU4j4grssfZiTDMoeKCEArt8V6A+p5F1n6xx4CfwuWH2X9zWEho9rkFRL5MKXC+pCvY2uM0ls3XrVl4mxiPkLWmimKxWF7qquOsqL69j03K4WFL7DF+r4Yomu9lxuLky9z7KaAMxHec5gC/YyND2ZfZY+2uiImszhS4SYBcWH2br/aYcAbSvBLkG/XZZSP9ihPcs5so+eSC47oEqGVierKYqAIHrlsv8BP13/LvdcLxHFOyNZKGeUU60sYetp1PJXIuyhSZ8TW36DZfHZZHWay4pUG+uGEQt7fNV3tM1wWLA//tUlvsRf/NHsslXGcvfEeGj854xC4xBQ5i8YSThicutY8TbkWTDw4KXkMMTE6x6z869KNYcDzbfnGgQwkVQootcRgb3lRanxgzus1nN1ySrlGfHbYbYh8kJPkhLy34MqceLvBriyDLXoROUiVbI+TpoYZJeRqTh5jXVx9Hzrebijj1Hl4AURIxBfb4PpHHjGhE7ReH3asoOQztFycFuRSVus1XFxOzqp6KkpulzVeHucrBbQavKn6+Np/dDIDWo4Kk2gJxYwqyShisDGRr1m3n/+9fLQ1ZuAwqj5VrqD+SikY3evVS1VCiJSmBXKySJGsWcEEHMp0vKt5GUQB5tNM+EKpugip3x84+YKtsRALmYmGSHhJc2G7r3Ob8dGvAXLw2ebpqVsTRerRqE1iz/hux3AE7eNZjl5TbY29r9G8Iqwmlg3MwI5osUzrVhcLtEXPGYPggyWfA7iMMnVGOIx83HeDxsCUO/NoPRGBQusADHwnhUCIdSl08NxclvIIZxE9z874bpmh7+TwyY8fg5Om8L6RhHgn12XUZKDAKhS7HPO2pKn/C0391sh8ScWvZfHXHdAHLBE0oid+Q4aTLpzxiubpHZohyDxJLnZzQSLTScV2cM5ordbDG0gW8vm9Wt7lgKXJF9jh/pFV6y59CDx8d1klzm6XVPS/iqM9znmXH9yTtnAN9uB0SQZT7C/CJxTYeiUJ090UuVl6JRkYezCLRXdJ9QQHjvCDP80X6mC4kvjspwJ6IzkC7QKndLVZp3j2uy2l2TIk7f8EVkkeiFiopdqLv07f8E7LdL4Rtky9zceW1ddTCVQ7hYKHCGvw7fHlqb2wxtilT4oZRyQ9CoRve67Tmtz3qswNvZVnxNPhaSB5TbvRyCIcW1uuyeISLS4Afu71quDM8SbGDNChqA3o5hHvvr4saZHL6SCG8xqBuRAnkfDB2XRwlnPbFlthj/Jyu0hp3qL+4TCMVCh16+tBwHcQfXHxNeXMHkropYYl2tPorUix5aaGCsW/lI+ImFmf7xcW23rwnxBrWm+8O/enqyJQGvszlcPiPJi3ht/oe5z/pb+iyp8QyCOcWNuqGHD9T7rB+GyS3AH6DFykaR4sFh41fy0ZopwDUIRESF4E6fHePYOJnlv7uoP7nWbs8qSxHjBEgKXfy9bbL6dudAr8cwp0ap8/rtCSxmh/ASyWnDA/j3gq5i0YwyNaWGspBuwEVnzuLUW3EYgdpytTkey+WOvUan2MeLUsIRd1ULHU7NB0qXuOLAsLpKVfssi6Hiz/8wqQKXORXV+nkJcngZ5gv+UhgOYRvCxewTAthHlUwHq0QBYOgESSxDMKF8vgwrD1lFoQiU+SC8wzxQX/IxiNly1wsrkWKVzLI+ton9/gmEG99qaCcIiPB8+kzsrTEyMhNgQu+00qgLfnkEJ4Gnk+Q2bcs8NkoF6XGFjnpZMg2O88f0YpFlfvTUEEpkwM5xfcnD3KPMlfk7NAj9Y8eQZqB2zQT0Kuh/FqSD0IO4XTKq8EuljpYA8VTO/bu5jY/ubJyJyspvXsh/o6zouz7dwyRbSpYSmpAh8MOkDwU2IWAb+EJhx18oaO9rU6pIxje9tl31G0SV0h3fC+fdzmEawvtEb6uBR7CkW5w0VUVQiAlxU6rDu87x83LcVPXwi05odQZ88+0us/Sqtag50EcKNPKmgwidr9AdpjoGZNDOBw/IGuIVE0T/qIDU+IUFM6jcsbxLVtI0Gy+OntDT4RoQabAYQ/C71+ATNI7tsQP41UNSnzRFuJXCcT4XS2kX4un+cKqPR7OgcM69+JpjuNQZIwmA3CObWKwQBn7aAGdo50s2tMBOllidB5bzgzTpbhV40T7NaykTwFIxmEEdhpLf7peHa3XWcrbClIAe/w/Ybq85xZ6/82BOhI7z92y+5kueCTdJwd6ScbzyXk8wx6hFy8aMI+2dIJFCTTnQXzUMAGYQSGmavi4m8EBmrEOD+kI/jOuzD1wCKdjEC+Is2Uumn8Fu+1M4qgQSz0wf4GgakrYPiEgxc5AeLQgC7EVCj3w4h9a3DSAa2gZObwUvX1CoXPIGixxzJ3cSaQA8WwD00DfxADhPYrNw5zakdBgWxPGM2zcYTfu+4g+90AeddVxInnwv2HxKn2PpWcPXJmTh10V28gVbUvQZF9bJn74Mhd/YafHiJYNU2KPsdNXBHz0d+fT0eqkaNb4usJCuKMrljvoDgqsftj6WSBH/0T5V/ErC+EYcdCesbVP8gkRB3Th1ki9zmWO3VIhYq/3vHuIPXXVbRV7OF5OxLL56qJ8xs1/dVzUyFhXYpUUu7g5UyC4NsknF3ddO9eq6D5Z+SFMTo+rDYxVnYqJpQ6YUxKEJKDcfHbp5RJepf8Sbm72Xz3DAqvror3mI8dvgnXv/zfZcYhQ6OhuvsQPjPA46YLZQ1xHdnztTgDgNrpZ9vtWh5p65N7+jxQ+fRG0RKFwaxSuTnoG3hZpkfjcFlHVHEfZ6pqTJTfjilxOTFxz+CnFDizkic2YApcIl0M+MrHc7zpVnHXC4PK/XDX1qol4NTamEue/0czs0+tcEeHJayUIAzx9WizjsFbftMr94YeNGshlk0FVohYLcKcwALnHjSlwsJ3TLMNe6T7zCmc6C6UuOnkXgilHLSl2ccK1CUOwNsvmpeGdcWo4n9YulFciZBBeLbCpj1StcFA+LfUTILXtNGB+s0SEgW56BgAHx+5zXQIxvzL1eXtEMnWmGiiLKUw+QlhbfVt9j6huUX6CzyRfCu8ZZ4qct/UtyZo/r9oZyR/OYvNxixsxbL/qqfJJ+nkjz6szCLDO2u8swo0Kvnj/uZW+KhqFYWmE/kyrx7L9jEv3X3IRhCk7MLAXA8fj3ECWnYNXw9WA2AeHNBVUh3MqmMMBnR7X4Rht947RDsdH+3J8NFdcTbdauvdWoihnbWYVf7VMVX/7FTKJKHYWw+3oxRhe+rsDNpKxh8PUfXO5IJGt75rsP2FF7q3zNyW4Qme8Xws12qEs/pIxcPd5hX9/u/tvQhAZu2b+D59gMhbFVLzeNytYutR3B0NhfbRYoI2F23aozy5GR5+cibc2Nt//nILdUQYfZ8WyT2fnzpfa2iPxZNucKPCYAofzETSEi6IS0+tS32efJWan6yRdjpdM4KapRTXq/tm2r9hFN4X2eH+CqhsNi5L+Pvs8foVPlf9q09Yed7WJigpbMt/6xUSRJYqnv88+7xdFlv0osBp1CRP8dIzHujWiGGm9onaP8upJ1ALYkq0zUQIj/xXvnjsoa1NraeITo2yJ01WlSC8oxXijKt4rTH2ds6JcAUkqZr7UHfMV4J+/ZkscHFnRUxDHTnx1dHeXZqnEo8oUOODDaYp4F133bXr30XnVxu/0j7pxFOMKHaJmFEFEftFCnwHSUOV2FVc0pzWEu/K5WKa59JqeWOqGuU9vpUQuAGzNXtXNTuCpfD/H7luVsuY4O9VZWla1yPrUZ7eZF1Ftvk67RyFxvAb5i6DRth9d8Ehj6fzi82rE7+jbY5ongowWCh36KKQaO3FNLday3Tt+X+u/OmN6L8X03gXTf6VrbO6DTLybyxU5aAX3RQ5lubCZAof10yfx5dbP5vMUUn4uvZ6sgeAbve1K8lHrVTW39TCdHG9WXYSv5ORzU+SKU57Xgy9zOAd5Kj7DukaGZFWIy08sdcB8X0Kowy0pd5ijBhlXaSLFzJd53Br8AeSPanclMx3PRj9WDT2Unkkesc+MhkklFpeHcDIh2FYZFTvgJz53ni9zROo2zTR/csUWucS1T/Ms7xiP2c612mh9NXCx0ah81pq+/liO+HiGQQTV4va2hI8pENctW7JrW9RMzN2fNYbxdY/F8xxXXnUcbv4M8mWDE89zWOjv04bRHBcLzqhtv7hGHrZuWemDXkORA84umKGreyJ6IuUQDrJg88yVuhElkMMcgSVHlPaLkztjq/OG/TmjgMeKKN0590QvusJkeI/FQ4arq26r8t/3+KTJSBoC6VYwFDocX+bpHw28ghKrnCtycL1lYHm+Qv3BCTTEoUuKHYIua879TD7Mvwb/1DpZezf0qi5JxEVVNGWo3SHD6LPOrdDsgt7W915cTmyJO0bJNWKuyOUg+KwsVhdZs+Rfn2RLnA7iiyYR1hX1eWtWQR9FFcb5PRbPmDd51V3g8BiWCXkfm1N4208Ou1eTcVtM+2WevWDbNfmDJadrZ/s0/j+nRTbXFf0h6jPw8teAxzMYVlV5nH0BtygLgJ3aZuof8f1R1Pza44r2WDfHhA/nPk++201NJJzz2gDFTmrKYheHopm0ilFSBJMN/2MDqxpp53hlSfQBtnjOw8pt16x29KifPoKNc60AYwq4WiCvvq1+PvV70b6vRSsC2b3C2FGlbrmJ2Xf5sqmD2fs4czLf0gj0tmTs8PO59nlYrtIKhyS0d54C93wOm8/+b0SxrWsw7rWDIX0ba6cNX7eGg06fa3xpKTtq6nvUaJqQwIQY3KTD7MFZbujG4bK41/1jhNX3VDlfYJrcpbyeJCt3x96JeFMjEjD7tr7hib0uHiDnNKC/O2I7ShJYVSqcTKmDRo7jmpDWqZIXsvKtWe1nRdmswgNpBjQe61hTd5xFe12s04RHMXyca/GL17td73WfX8izhVxsxY22nUvcRPiSsEWEtUHw+C4OReVxVgdpkUcxfJxtdWASyF6XZAqcbwxILws4Ohdb6cn7Fbuv9pjwCzUcmu6TiwOsqmWZWejv7thUMykrd8dOsm5L8bYlB5nlJrNAuLDylVOTiqiPZdGspXJqKNnlaxlfh72Hlyz95zmEFF6aUvWJKTgILEueOeTbHEltIyIggtpG8PiKQ0XlbfV3bf/Fsm3i7j07ryFzEbZg2ul0XyuKeuMsE9KYLCMAU+CIT0wjRX12OYqUvAfk8QZQXMuru/Le+RCEnI9Cqcvxc3uMpUAtKXacF3ztsBHwckXu/ZWjFUsdXIjt21VyxEKhM972irPSP6kCcue4k6YsYZ68iLcI5BAuLbT1LgEfT8CWuPeZPbBUrRkRysGyB7VM4lCfXfm6ua1xyubzPMlQx2TszUN4toAvOOtbGCDcWyBpp4fnBnVjkUMGtqgdmxzStcVOJGjGxkN4tqAZCw/h2QKqK649OYSnfEJyPsU6JsjOIJSSzAI8RttSYlqAx2hbSmYLcKfgDVxFuFraf3XkDznX+XBav9ok6DZFrr0Ts97T312uydw1+QIuZM+M8mUuWJ9Aubgo0ryufsISornlA/sUIA773D1MHoqmPqrrMr1taqi08/SQAS1W/7HKDE21IO67tyrkU1buEIoUOU/noHmvFRr52jnAEtsFSOgiwxeJgxPEIjIVQw/pErxSLsRQr81XN0yiCrr56ohJMma/EX4B1QNc6KmpgnHr88nj43uxx+1XN0ynz+u0JEEvX4q8vheRCgC++P8TAgmV+XI/Dv6QljCpP8DblL/dowJycUEN1bq8s5+KTOKOUkGFtCTjIDWUV0vHIH8QTS0pgDd+cbFKAfzwn5+oUeMyL6x91kEV5qHcC/v5LeDdo3yh+75AdBJp5mo5hMNKa5DOWKb/Isv0ugR5BRL8U9jYNHDhrYlMqocMb/ESVg2fV9wE6yId1zjDgoaecoiQFmQjUkM5RUIMWp5mQBowl8srZXIPKqj0wkoBXOyqVH73gilw9/h1OQKl/r6+zB0rNrhwwuOmbvdorZfOupLLgU+cvO+7cCxDm1GXcAXSXLhZoQCxb+MTqL7Cp85Y/1rgiNdEku9NA7Y1x0G9wf29QrbTp7Sqwx9Cl6D0ySlsh2acw6PBA8mvGeq7o4NCejjhuFXsWt6nj+kdsZ8iMpcEpQ9z2aEZh7n6tnks9HcHCVrBxc+0vpcymVDohleSKob6/Cdg3Di8GsCfk13h79Qxilsk74apody5X3YGx5c5WAcSb627l/a86ntAriMCQWeSAriPHRmma5mtJCt30XySdJ1iVUPQKbkiD5ySG0t8mYNeDHOs9YuqL/XdFZukg0yBg4cQVpVwS3746MJNG7IT5U/kJgnAHkvVQWJECD/yTJmlqTtiGBJuUBE6tCmaXp+8iPhc9z8aQKjMotp8dVA88rS+KNNEfjIslnpglp77iqUulFT117ev6n769lF64OxxrNzbQO32Kh20AsS3DSkZFCAOKoPxmDT0eFRzLOp9HPqheMqzAiwk+cu4IpeNqq+qVHskAC6RsgnMK9jjEIL1xWKHviP5+ROmy3v+FULqu0MIZJMvMoh3GS74kfruLF9P8I1XmYRtC7Zre/5KEmQFb88Yje/2LK875vYcvpV+FbIfffVLeHRdDE/kyiLp6eI91hRpD20cv5GI0cdtZIVlHE6NG+vdDoGTSt03VyzHqAS/9iJBNhS5+Z1k1jz9fXpbbudWED5FahOxhqyaHovnq1vyqtstya9LkDyggckOLfkyB6w4DFGmpzAFjieLUH4Eypc5nROmj7CUvxYsFP4JVk+4s4LGFLCKpnRZDG1KzsH77x4OEPnadPYfuzsaZtNh6qbML+EfJANmoPJCofJSW7T1R2KjSJfcYjNQXEUqnt/rEoKqyM+Ksp0t3tfOFbrgJdMOie3OuziEQm+86kgOLaD7vMmTz4ulLpwK7u6+ikmj6e8OXp/FKs2lIX5siQulqeUrvzqoANnN0J7ZNv2C/HmChG+MjZ/F5rX5m1Bst+S+AGWnuog3XekSV/+cDCNb4qLsbGgsO5KWlc9mtEc8rxnDN92PCrEwLOGCHFTIx81CzLHbHuRdzzdXa5gMkYmbuQ9LJ6xD7ZNb2A3fOGIx5vKTj+TbWhqQbYB1vI1zlmZo8QlBsXyZkwh9+pZ3ZFC9L8AUO3vFd+f5Dd1kBSoUGsw+yoUTupEUDWkf7Ph/8qRJ+8GJY/BgNO7boRRau8YNnfwlD0tH2NkRHv9tXFp57pmed15+gDJFSuywEk6K1W2ag/Bdw4zffx6dkI60gzw03GaBPzhE5Nb8w6XtF4cTRpA3dyDBt/NKZNZKbwOrYBzDwSRxYE5hODBf8pfH+2/2WH6mCx5J98nh/pTkIOyTe7AOqCAhguy4WCj0wIt/aHHTAA5aeFWlyxxZvynhiHP+AUZZufsZHk5RKlxf4srcDW8cJMlj5ctcAs9kTwFtvu6PawRJ0ORB7r3gihytuW9N/e2OoOgSO4pGnQiy7bvfKFtevH1uFx0OXSWlkSUrdwhvgM81+iQ+OkZ9d7s48UeTlrL7Ev13j+V8UuR1WWQyL68KZv8NgrhrLsJim3yVHWUpEMQm+TSpQemZk3m7BDe5GTqK9G7vnEYT4Qp0o8pxvg8KESwD2zVuRnWL8uqPBpSwulzecgcsfKGjGXS0+GdT1eLxulDoYNQQ40OFWCx12csuSngFM5hIblUwRVPsNSqMZDnINkamwOXGR/6Aj/ek+otQuIfBX9cpsvQxP4YJwwGNh+TT1N1+dTV2hnT8FKzqEL4vm+MY2sWvM9c5QvuCQdCxAf7pc0ogrze3q1gZAVBy7gLywYHpq+w0B7cZv1HQ3x2wwaQpodAn6rODw058VOiT84tCxbIYXFrcjsAWzbkTfqpX2XGxeOG7SH930YPyGjF273f7Cuunonzg1SE5jJMQQQvuhayWPkm+KIXlMM6tnD4n9yBfQpKeTN+YCnRrRFvXqdC7Zf3YvB6tV1XdViGne/nB78UH8Va6x5V0vNg/F6hQyGHKFLlqDmdFuQJ1LUTLiKUuynHYw0HKBdrcZml1z+8e1Oc5Bes2BdwpR13gZICn+QLNKDcvXNHWiDDCJt2nCEpaB+arqymrjyPN2uZ5HJuvrphE6Uh/H896mctIvYcrSNxNSLcMNFRpVD7Gqr7+OOxDGuUOLNpPU26okiR7zgn2doThjkHycJ6To0g6y3AY6ymQejChNaZx2DHatYuIfpi4Fxh27h4wHbhzDVdI8Qk9KJNh9GBVOzTbakPg584vAB9GtPm6x8euJ2iilkX5EoebeGw+FqgRxYGLto6L+kDaKEzEIQuI6z2w0O6w0EeYwzJNIsV/8Nh8Uh4bUWy7Efnv8KV9CZzBtPnqhElAcrAppHx8lGSXMClCc3UPaDw4V1N321k2rt9jnNPW8+p8wbt1+29bw4bfyyhsOKDxYENN3T8XG15lDeeub7/MEZiuerZS/1zlXM7k5B4umgxeg+oh0JlMYfJxJmurb6s2GSP27gqt4Jy/ETJ8dPBtCo94uj7gKQ1F8IlDqIv1t/y0LItS0CU2BQ7zBJ/ry0Z0IdHfXdYnyZdT1gI+tsQN42m+kOLrvzv2r0kSWFXyHlJljn0UZ4T67CIrP6WLBcx5Wdl/dXJcLks0mAtYJpLoTq7QHa80GahQuDXSeHiCOFCz7dH4aLbquuMI4aPFAk+GcD9j89npJlyUV+9kqoBaEZjLUw1B1ZSwDVUOdFHTqHx80/r627p7t08rIkP7CavQ7E7FFjmFtqSFENuCP+2xZ6mb/w8parIKPt7jsfkzpAbFgSf3nCfPirJZxTtzFtB5cKUFjnHYkm5TfJVILJ3rtJgQiEc1fHQwhYp1mvB4ho97fHp9UZK3WjrNNvSQiMbldUakRzASr0eKqTgri5WKu/kyF85U4WRLnNb2P2FSC0u6/ejQM2RMcz0iX1zMwksIJBe4gaPvt1PYj1/aR915hEKxF+7hHT4legpijyUGMWtQweciMJiUQuR1oKKpPZLhuWlSmiBALJ4tiEqWWtojq/QuMyfGHI1BiWM0iEnlGEba0UYwCcINFVdn8WzRV6s1SJeB2n+PxSvaSlV1a03QSBoFvjzHImm/zHmDJPQmzmwOFqJDRwpIZZF5uVcMGLaVtY+ThDwO3XmXeQaQFO/isol3lt1SIyHPrgqn/lzZ/Nfh8OvfOEwaZBmfcY0pcdAR6xok93gNvDtLxQgXSbEP7vd63O9DcP9Fj/svatwzibqv8Kn6DOsalvGcd3KcHoLPFtFI8k/auujQ08E5rn3Jkh/vIG06NWBHIh1P7mHyUDSxUrYJ6HzUWTOObd38tzllIXnBEdtOXWC9HLcayqXf1+D59BkKZGAKHKgKnvsLJYJLky1y2r62OoFjPMVrWwRLhDR+cpwxRMykqfuE1gUfngxgSjl2SIkXtnpnex00aUr80s4FeMGtxnrlXIbV76VzS0zjrDu+eR6brNwee6y3onfOhc6TLS63RWCzyeT6S5JB2YMITIEjvgtYpsVC2CHYIpfT4RpkpDbnFGEKXMwcNH3yF8OZkjlcS7FiNc/ztE5BJl3gfNker3OS7ir9F8myigcSuq/w+Hx2FAsc46z102jXlPwu8yixkZxk8kujfJkHVgVCd1ySy6RMwdZw/SXE5w99ZuHQvY3G5bWz6RGMw+sXfZKXd8Ith+G7B7b3Cmzv91pHPymLqkLWSBaFo3hsPrawEcX+ctVsO2lgJJRfBNSEkU+oqc/wEWbCpkZ9d3FdFmUtvWjFljiEXjZZJkXIFDioiOvuQJcj2ubzXJFd+HFcIV/z8NHFeL6DZQlLARdTMOeJS/zUnWcl/KMhmXS52Nzhs0uEHcnI/AlUvHFIF2yNiEIfcArawAvbLRKfu9qqmtt68vMnSo6yOXMJtQCp0xuf9J662tvKJzunr5I7LYHTjFH4TLC83jhT28a5ihNMf3dxGSVZs4Dn+VWKagPOEBdLnQ46QFXhYFxUUMuPO0QAF32hrcwrDP1XB1djWvMZdrpPU0aqfYE16KKXOeWMLXHDqHxZTSh0wyuhGfV5/vi3S5gj8XRU/UwXS1jziiBb5nAsSGr8V5FzQ6e/u2L7WYJ1p1rJkDLFrriR1fEkmSmh0BXvcYGFP7+g+TKnY1y0SfNPCm2+Oq5l/MS6uJzJ1+m3q6OqKpKUvAsu7FloKyUxozdH63WWYk6nFBbNRqWvx29PPbRKCUF75ELc/ZUN3FwVTSl9lMtqtxtQy7Y9TMyhL4HdvAYlXt6e3eyJ5djN395K5zuEJQb/mxNDbGqp2EHhRrMic499q3lh6GQYJ3RopmYEEuCG/kTb6n2xuLmEVV2mWEk6waM0SQib2oIty9RpAW2EhbmtQDbhGojALBZdDhQfLfWmZpre9XZDXdvQPd0kQotvNLUwvX/QTFsRa+D0DwgjTLykc2ET3eGZbaKP0yxDnwf3rcVs81VUU+4y1yzOQJpyyGJOO4c6jDGdO4YU+UWK5/PVefW1ybLfX9+BrIKOow9mngtYrtIKJwNqU6be0OlptTxkqinkveDgaXAL9tI3Fzh7AvIIfGbocOCeQuGaTd5Ys4qqhkraOLKGHP027jT7wgKX8AmUi4sizeuqC4i9+V7Bxc+0vu+cwbqIEmNlMYZEqGLBF8aGAmeAxRWBT8wd3sZNykSGeAKnV9VdNByhTgwVh0MayEc8tpgSh8e9jQxkHn+4mtMZ7t3/12Cp121k4GIiL1K4gbHRYkTEoaqLl0vCunNR/CUIU/Qdqve1Yoc4SHNY8iCDM7f7Mvxd9R/whIIl/FIsYFZt6uGc6ytARlStQUIs+AU8S8sKh4aDW1DBFuT1K9T3xxRJvf7IrXO4/JGdZG2KrB7gC8jTO1jV18UDzH9//f6Xd+9fvyI50XHcQHb3+tXzKsurvydk3YI8L2oy9N9f39f1+u9v31akxerNKk3Koiru6jdJsXoLFsVbhOsvb9+9ewsXq7d89Q6tFZZf/kePpaoWGT3j1MFpN8//aAD59D1POd747d+hwGn9DF/Cu1cqOfLbW77ibxLewl34/XWKKUtWI3kqh0SXAnyvO8dQkPTs9SssbvCl0EHkvNWib09L2wbyR1Am9wApIl/Ac3sH4vfXv/7ijJM5VLNGXZdiCIaAmX3NeQzclB7Xkdxx9Dhp3B1osrpHcpuakNAHLAYGhA1ctLk2hqwNe8KJ1Ni4lvjl/ffzfAGff3/9f5Oaf391/h83TOV/e0Um8e+vfnn1v5y70UlHzGI0A/twQvuGmIZJ3/3yizOb9ik63OjT1lIRxmp5IBHft4rGcpvmoHz5byvw/H+4YjKKnPe/uMucL+kKti9cBCG2Xokfiqc8K8BiTxZfP5w2LUjbUJOnfzQwJSjvUiwU1Yzmvs6Q+dQ3SsJRbWWluu8Umn72vfizx3dMWDwOz3fxCzIO9cKH13MuWUdeyE6f6y4xegxsyOKBTyHzeV5dlwD1h2iSFBoLMTdED99QSAap986HTZl45LY3+EudYuIHd8m8Q/noBnsilDbRL/57ME7ObFAU3TcbjNRCcXbe26+L6F29Lsbo6CVcZy9uvXVAO0aPT05iYzxOktgoh/yAkXXGNhAzgmxn73vw0tBV08Yb4iaKw299YyTG7lhtglwCQzf9mq0dZoAw2Qmjm5B0T/dkn+gS0ekU/19/dVcrW3+A2Vphcdvw2qei0i9yn/5eFGUdspKQQl7KVMrwjg0B6ZERt/mlr6og6wHbIa2/Bgk3woGo1gjrrktw0oZb7cnCY8ZE377QTPRff/HQYk6fyS0MJnjifFHF3n+HZtrQNVML7z224r4JNvxuhLF0YyDtYduOWKDP/Nbm7GXJ01WzIrvb0YpsIf22C5N0BTLs+ke/KuLDf/c3xHLYU4tm3bX7aPATtdRi7+MfY1EKX0629YPzS0Lstb2UaU+ejpt8gVYIWo9DXrqzNKv5096dFTyb8bmranTdIEWNSfnnzylsYsMwXFz+vPibGM9ee8JPF33qCVdmGioGcVJLT+9OcNWDutIfcYZwYX8PYSyJPVzfaJ8CJvkf/BVAG43F2ZDHuS404t/X54vYnMr+HDDoT+kCXt83q9ucMp18EP1A83mbBU3ARXObpdW9i8Aa7/Q2qodD7zyOKpL3SxDjFsJ2wgtQoi6Q7GlDEq4wjB2nI/GbPqYLR/dMuNix8x2NInf0qqwXzqPFKs2HR8siIOwZp3uEJmyq8b3gb/knZGleBG4uPY5Y4om9CB930xLuw0eYFupGfNzOHmVZ8TS4A+BjCp+CNsSj9bosHuECP4WcL6+aVcgsfS3qqPh6ZCTxKzfYwP7FQtkdXVwXR0mQPiEkPPBHdfXQRF8iIG/uQFI3JSzRDlN/RRrUZkHHauUjYpnYOM+rj+ldfQLKIC2rxxG+P3ePVXyr72F5wVzv9utZ//jFsNXrxaPPKdpRgw2xOk3w1n+0WHBNBnX/vBoCiiJEwoRNzfc8axdhjy5oZIjo7Sr5difg8zIuOySnz+u0JBbxB/CiwugS7kOSVhOE4dz9CVRXAGkiMMasspjc3QN8/ZAoQDQwfE50tCwhXPEBOh4HTgOi9nnpKOFHQ075MHnSIWESwofIOxrfxZAOPgJGJh18iO8Qn0kMb7aGyLIzNKn9AUeQUrZob9GArMd2co8vZvg4lmxDzzavHoVQ4LQKIiH3VlKAvQBynJc8f0RLDCHrT5uCNL26SB4iuQmxTUTwHT2CFNVNMwpngBtI2kev3SvNo433c/HUjrV7ODpsGpAOn969EDv6rCj7/h1DZBaFoD0GyQNJX4WvBwUebGATDeM7b2nIvuAYMClk++qOImNMTIuvPXCMgY8MHC46VFSAUzRVFLE5Bj5uXo6but7Y6p5LBkP/TKv7LK3qcITdWs4g4kskmBmfhw++E6RvE1RpEuZnphFE3zq+ZYtxG+jMjBMqdih6G1drhAdk3gOxOhuh2hgenrlOVzBCEB+N+zRfRMTcu5pO8xqWVTAvdtKLwQpHZqBOwk3aJrIXrlPYrt0gmY82T1jV1DOPK3wbA28lozIr6n9/2lh1WdVCRtE+mzcatVkzJTr6n+liROyfxqXNsCvFljkD4rgCJ9aJQZzT1f4lLgpFzMtg23LqKh15+gjLFzyr7q4XtnaI44W+eu5zPZauHdKPY1DBbnsNdhQMuL5AUDUlJNfq9WGQ3t0dN4ZwaAb/YJvy8Ei28Txtxl6JWyz0KKALF4IlDuCK4aZhEGIyxMR3dV+0nh+wCW+PGNE2xCrtR/yEMarA5251T6Nwv/j3CsYJ2lKHgEVXHPqm/CWIpVuNfoMzTHfoNJEImLozruqkaNY4MnoRNGsiFpVHxDckkBwfk10wjFE3ePDW7eBXtxY88lTk+yt4fMKZcOSRK2Irbokc5XJc1EgDix4jhfMkxV4oPdvFCZQ6hCMx4YZxzmwuUhJg4hGM3lcMUfBxtNpV+i8YMgImOKu6LtobCTxmLx9uh+Mbe4pgo+rYRREiHf4S5EuDz94vJDxWTGFcn9QWRm7thM9i3yLOZRQk92J/pPDpi0Rns5DA9lHsrejaE2WoG03MBEJW+a3+6hExDgtVLiEG9V98Qg4PiYDmSATUHRTu2ZKa94beeDrZiHuNsxOss/b3KKlkPzIP1/1QM3TmeNJeNhlUJ0vw2h2u1nB0B1X3KMeQGyEohqwP54uBbPN00XXBJogI8MFvkF4oI8q9popCTGfPiI28p7DCUArE3in5QRQ+fa5LQGcVHUOvpA/g9kSkGR1iHhmbT4qsKD/B5+4d7LjIty9ps6sqtWe+2pl1KYWXzKL9Tc2gDpxXZ8jkbjZXdyJEHI/MgfTFswMXxuBCmqLufWBr/2m4cQ/ZcJSDq+jnFhTdDyc3cU9uDqctxt7t3mnL4TBitw8j7MMo+rcT2wT7e7Ip9aPyUJGHmmFKyZp5bC7emj+v+swTQYFEu8qme8af+udC3IMDzQmIfbK6GtNDeyC1SmocgPesKFcgMGNVj+sKbB6jitXP6AmcIl29Prq7S7M0WD0md3SDdKexd/zzqj1D6FO5h0SAaDI3a7scxkKfQVXb7TM+cW4xdwjc08/FMs0jRdVifP0tcAuULscz9GOibpqDgCDErpG9berWHRGDfX+st+We+fZjVyZvdUY7U8RMGg2ZdA/2fElrtQZ5pOdMpMePNlp2XzFojSD0OGvvY5onHv4HrnpIT06ohAeBaR3JenoXE9n7KMj+K11fFBVOlOMXySbRru6LHMoTwPml2ewTZcVhbf/9z96oaVfBnkhPoyP4nYcjmPjmqm5rDdJrCaIYt/Wun4rPEBPrvCqMV3Heu/Ld9X0JoT3+v7jiR0sElmnC4Q7KWPkDBGnPW5W+2tvvab3o2YdL/ixrfxsOgaI9UL3MEfXaTGpBnvGJXuWJ8JKNPXfTStWeMPd4Wu6M++rtbQkfUyBbXKGugxkFujWfHmfFEuuze8Kin0G+bHCiQmce3dQMYlLp0bIgpe0cMTaPbToc7LY+1ijJzTtcJ5r8FHZLepM/PBbKa7CME6S6nffoD+EW8Q/mpzBxe/GyJ3J2lL24p9FJk5ELR/oTY/djQXKueAVHMFbPMrA8X6Gu4ytwRtq4Rydf1vt1o3ZcnaYNEL+qcU7rS1gVTbk3Kvjs+k1PTyOT++QH6pFLbw/4qT44h3ixusiaZarKRWt5qFw0iZrtA46OvsKnao9eQJydQyNq4OQVrDiocAaaOJiiSODtVG7/THbKduivBwOjR2t9j6bIsqO8etqbEDw8II+gdVIruj/PTyT27wL9KOqwp0vGvoOFiLYnXDP7Nh+Pe9qotU7mxTnRj7JFR8vzRLbVjw2saqTF4jWyDQeM26mBjH/sSZ9x7YksMNuCv/7qrjBHevopSjAwQtLxPcahYHsrDTc4HLgP1yX8M1KsrnrqQhQnWK7SCp+7XsIES9r9Zf6QfWiUxTTkHQhDbD3Xp8+YqiA7aup7TNeEKAN7Ne+z36yKFwnbz9Y5deUmItpOckbG/g3z1nXxAOOYkQTdUZLAqoqHlMR/oAkOStJkvejOirJZ7dFZ/nWxThP35dVVC8ssMvfitnrF1E5fuNiFizFTXJ0k64Nwx54sEDIgdxbtqu34AsHziFsOzB/Xxu7qfYceqaq+tpI4yBmF0+UGIcAXb3AvAl8w6LAoptwTG8mjFmis76YE2ifh87EsmrWnBOrqjhsS6vVKTeQTiq/drhO0lmMIFLz2ZErVQayM4uHcTfFEluWeyKidEA/7xm5zONVb4u0H05KxRLzASfBFza+iT9m7G/YDm6QgNMlBYGe4FAXBOQ7CLnGTmvj+UsP3xHNYMXB1Oa4jomrvHUbOnz5kEWvKEubJS7RL4j3CS7A5vjVkZv+b96pkj7vCqP0D1LGFGTLaa7QWsvM8yVBXLcnxVz9J3DeGbw1O0dg1bmx4M2CiETKNTjPSTjZMM8KusUlHhhpyWKzujTFiDAn+FO8NIDuDcGyaqlsem8Dqlsemdoc/ztUywiejM+LwIvGorRDRMVoTSFNvkLazGPlJkkv4BMrFRYE2uOonLCFircC8kvcweSia+qiuy/S2qWFsq1FooPqPVaS8SJ0SoIjwc409i5NGb9D611HGSCLisBmDn44pIZIjJ2j+WT3Fa9oRFjpCKGwicJeiKabC+ALziFcPcKEiXXBPTx4f42RrwshOn9dpSSynL0Ve34+A9z8hiDN2mi8/pEi41R8g4cOQeM0BTZfh8VORLSLNlYg8IiNQyI9B/hDNlOLwRltiNN7zk9go+xxZkdGe34JIG1InoYlSEDOfKw7MQQviX+0j6vi9Q5Cw77KPgj4au6kauIRVI6bT9ZRGa3xhOj5xRMQRe43szkEnit/1iwbXrWBsd+oFSGMFm3MZsKLQtEOJbRWc4LJpXYaj+LrGTky8vQcatLlwCVcgzakgdY+o8E8Av3DbGbdfC+yWT5iMRBGPSnqr8HuFdPtPKZquvUm8OPsbnaSqe+tdtbCArAlymHxM74iyv4es0w/NffI2NYPm73sFFz/T+t6ThbjqwV1hMjBEd7dMyax7wqC9OkPNMtrLPe7tKvCEHBj2pA4/LBrZzXde9V0l97AAr714Cg1kmq0jGgyXaLBr/KZ7NE1twBjvzsgVzLFeHauHLbp43fsCq4q6NRv4oMhmRohuNtuTQ27xMHuUVGYYT9Q4lhnVtYt53yz9RwO6ifCX1d/ztCYP74193Dg0NPrp4hSjmWQkY5+G9vZSu1+PTTK2tbFpN9qRXfyjug/FU54VYBGcjOi86lFFUYw+IxbPK9jjVOqEVrsvkvo/Ybq891ILbVo4bvJFBj+AGsRxEHZPveOLmHF41G3b/4oTfOzTtj/LBv2VSpMSdgGzj6Qrhqcbt1x5pL2b++XlmT3quCVqUPAqwXAMMoDfFQhR36rRo2piGmFxDwNo/4fHk3J8/REelMMHOav9eYd4Rkl+XYLkIc2XEc8ASczbuEoJOciDsU4aP8AsfYSlzRuR2/ImWL8A9siLMQzJ635HWzPC+ZToNx7de+Cge9RNmV/CP3C2un2Z9vDrUpEmbnb9J4bf6RKCqsjPirLllThKesdxkNi/Fva+D1LbEASne0ZcsuTQF0/u7r4WsaLcdS9788l53V9EoAVFjFth2xJt4rBBFiTU5wSUe7VJhkvLC1B2ikOQ56n1C/kds9J1w56/3kxy+PHq7PJ/5mOP8S5LoNUJS8T+2Lk/mj0dY/fcOTHXzfzVGtGwD4sb5nFPZN7My0JO229rNhrX2lbRYgtbv/h6xFmaIXIHZgVuk2t35AvNrz1y1ngdQfdkAciHGIv3tibT/CyMsicssjOz0AmVa7DcY8o7vmntSrwfoEyRrjPwMLIib9Mc7JPEe2hcaGoVhlmn+ieMfV7sAXlzBxJ8CahEZpXiel9oK95qs9WTDqRfY2H/mS7GQ/5p3LgHUEFCef9jQKdm8A+2KZ8HFKoqXeZoBaaEKU2vxL/zcC31hyU4l6DHVRKmdojt35t7OP7NvR9s7ZB+nFfhr1bsneGP9oPkIYZBTmyab0397Y6gJIMcI0WeYmfdk+00lL/6/we63HwBxPG2YcAbWm8cuPGdvxcswM4RMQRnm0efqEdyggPm/2jSMiyIkFL+8rossnD3p1Lxn4BP3hunxXUl79sSPspSEP2RgohWY1A0cKiYbu/j7cdEK4boLQWltFIVxpTj83Gs1dFEkRXl1R8NKGF1ubyN3c/Wclj8E00TfcAb/dCjDbOaoKHzCmG6ghlMAqPfI2wzUVjavOWIfScNhe+0n9P8AZ+GyZSy7Qk2uk5h2boe9kqwznaMFC8tNH7c0P+Quq0dw/QOikKIeBZsfwSA52BP2DmC31lyZF0K9n8wzqsqO80xfNC2cQWTpoSO/bPyItLvhkTzkn0ulsXghBvFKnPE86leZcfF4iVW6itkdSLG7d15X2H9VJQPI3i+V6B8IUunT/HtI79lWAIjdQjK02c0ynwJST6p0P7JkTl00+GR5Rb7n0USerxQpstQz+J2j3sdM0d9Jy4+FxiBA1Hso7nOinKFpoyKMImE3vsdFMnyjPHC/P6/PPOhwMnZTvMFmszQLdBNB+vcgnsigNoxhu3zLY5RlDpny8PeRLyHK0gMboRqTyaTjCm2IuM6rzY4mSRkqve7nLGOxyzHIHk4z8kxHp3bdE/YJkZg/rwOitnD36e4N0lH7FzDFdrg9+aEaJS9A7+yi7ompIUPRjxymOEJoumyKF8Oc7y/c9yJvcMU7+8UE7qmyb4d5scwGNAQ2sdoY08pQhyf/2S6ql+kwXgK6lGSXcKk2JukuFtulk5xmmV5tH2+2DjLIgYVfi8PDDWlnyNr9D5JH6Qxwnt93gqz96cl93DRZPAaVA97wmcWDn33iTSHI/3q4S1ByztfBKUswzXFbllIQMID/4sZwd886CI7m7Vo/St8ri+b/KarHhQphvhn/S0/LcsiKPtf1yWp9yBgRB4BEp8BybpR1r59GRCQX6d5cG8Qivh9eedJmSZJYFVFyPNCOkSzTbTz+/PqU7pA8ivwVscSvzd+AcuECs3zuNbTY1KkDBzrqGZ4nXJP9hXvB+TjvGMvexHKdQSOuoi9XxSCqilhl7VvP6bbqEa881EyySthaGRPWK+Pjf0Sc+DYwQFjOWs6HvqABHle7c/JzoGNpmWjs6JsVvt4QkgNKepDHbMf3JEZC3MLXBfrNJktRZ3DkQNJ/9/rYXvCmOFH12dlsfJnQ7Z22F3Nwr8bdN2wUP/m9p8wMWR19AhKxBdR4zjR8R1UEKSJnledOnv80j7hGwnZ8JhUCL4pRAFRxdGnz8W+hLFRI8KteJhJPIIdj0exfKZ7G1mSeBX3gy3HVZWN2v37SD7VWHEtqzVIl/uiE8uo73ksLN9z/ZDhizKzL3uJu9M3Qt7BhCeK7Z8tpMZnjR8nCXmQs/MNilnBdS1YnS1ZaJE+rm0r5p4q81FLwkT2MPlUi0N2qpcvcKAoyLKXEDxHdQ2Se6xDvDtLhSAHN2JvcL2PiOsvjrisBcnX/7+9K2uOG0fSf6XDj/vQ3pndffNshCwf7QjbrZHkdsy+MOgqSGKYKlaQLMueX78keOHIBBIkwKPsl26rkEBeH5I4E+ypeM/qjnuGKzmwcl7XdMC3fonbmE9FqgkX8Qajdqov7+CJYep/3O+zTQ8CXj+S0GqGb7N5TFd0+cB2X7PT2eUrCnLCZ5WZuPhbVDV9ex7ZR5vvitv4++vvTNB0TDNVI91B+Gkf1xmzjQU/nzW+a55TmilNuRHLLHoT3jOJTw4ZvxIx+e2BDm+V7U55/RDBVfyjNsh5vZWqaufee/QWPDxet/oNNFXrM4HD5Y9dyuRU2qM8UDdzxfIkw18FJ26DlXHKW5t0NpUf+yO8ijnbSWoPR6jeHZIyidORT67KtVd/3ZXnAUn+zZPNcd5n0t/AmwiUs6yqPaLLajaRnfBDrVMO+PsR6L/HCMTzv+BXxPxI9l/K6sGY8VkvaSgh/+5NyNGX2By+jinvH81E8kz66lWXneBvUz5FfSt/n3/WSZ8x5llRVGPz9JcH/XjQ4UN3LqcwKk3es28snTYAvHnI8hK5LjBuJ/NNRU5tkLT4dmx3znzvm4U8N0K6rFFZCMhTOcpIFVJZnrPcV3uL5CKjCPYmr98qrnMSTpk+NUkp/4gLW6IDT7tcN6xJhHcekSfINvkmbv4L6+Q/iy9XmOyDnwE/E/s3h9ZIx5tIH8vDLj3t2bvDTVI1G/czunF7S1dxUdSH6aqCcvIycteYFz1vk1JPWzqqJW+nXD6wMm4PH2pDldENTnsuBW7Tn+08HqW5ZtUoK78oPif7ezZpL7Np4f+ygx8dm+Y+5/GxHTUgstHbqh9NlnwwXsuXWR1iJ/bLPMnyiUn6uTr1U63uFidH/eqjwk9/TfkAd21E+pcApO94AfT2L4fEzG2CIVSdtnQsyu84xxmqhkgt3mk4YQHE1Zktq636UhTfTYKhZghP8mMt1eSm+rQ8ZPvLWtVxnVNuiNxFG4ajvApwdLOs1sDEeySDKo6dta8Z5hmAZrmjW4cZ4duuCapXW1ajvCrxGrewM9WTovhuEgw1Q3jyiuWPSVEfLmnyjYnJ0ca4VW2P3GkFvqN8DDJ2jIp6E16uofU6jYNeWz1kP57qddfOPNnbK+jR6/du+5Vv/1cPxsd0aHSMZCKvmI3rxfMOaVABOvlHydBUDujRa/YtYU9/sPR4d0oPIz/AHpa+KKdevLijUXi0Q7rqk0T5HBetxQMcGH6ZZvfdpeFz9WWrHykVAWmdrrLZVVaMOEA51AzRSev7ID+LL70tHPoGR+2EdyVTc8sQr/M0NYNE8CxN/8rqrb9F8/vOELkrRS8OxdOY3XSxbvDP6Pl6YNlHYfzFhsZP3kJDneJseIJu1IuYzTjgX6zgp6U9NPUxc2wJw/pFUWS7hHu25fDPEzuxfXNbur+9G9W3dxXkvz7sf6tnI/Xrbk+HNBuy/Nyw9O734ccPp7RMjmmyq/j/49l//v77356pXebPQ3Pe+rf64HZ9ceUyLnbxXjdHpcYeEwOUXJIJoZAF/A+NKT8bU2/PxulldijKPK4Mrvf65LBLjnGqGkUhJAaIWte+SbXkFTvWu12H0qg5hXF3K1tn3vNQHGAzxovnAqbIUIvE6/ko0CQi0bFygezP8GjDMBYIWbipgqOLxE7NtLA0toQwhqoyzbE/RUBzhcFiMU2ouRj8urW05mHuqP0/irmuXPRt/9ssWJMFlgVRioKgC7RQGGQp+lA4Cg+srwJO4J635kzIiz8LnCALrQdOw1RrETj1RzM8xiU+rld9N7TUH7oRmxp+3HpMgc8UYe5fOJr0B0oujpXJ6+N3rfgJK6Kb7JTvDHO9tq481+t/nCW4aAe5IFkCY6tXeQZwmQ+uITzNh5sWh9ltnNfHNL2EizOGmZPLl4CZ4YDjYjBrP6+bimXQkE0rO5tI5jI8W2Mg6xFmCWPLD8SXx9eMQ/Ex8DIeWJkVXd0/2rRu9XqHelJjnbFLEBgURyo/mxgmauUSx5ZeRIgqzyffWP7jtr49i/pWJJKcKhU4zQEdoqEvXKCqhsGG03dNkG1pTPSjOORuzLoG5orQEJ7OaFiuauQyKl8NrjazYrkgqOZfs3RbtVp40bLOk34X85WzfMaFS5Gt1JxcsPUFTEmbLSxitnCUUIErMdWhYYMOKhJYHgRqzv73E4Gc2YoVVoW9zXzhVgC2+b907uFt4a+dcjH0mlWtJXUGjeamJmGnRm5B8rRaNAv84Gu+uFg9RRAIKiaYAYmEa84IY8q95pVg0ratA3gd8fNPgUIXFCwGP/yC/Fy4K6t5SiXXt0pVFoGirwtjorwytuSSzWNKUscBS4tBqbsd7xFElvmjknuSt9T/tnUAgAkdVu56A2in9+HVgcG9i84ICUm45U7DdTf8+wcWbUPrroYcHvofZ/nIqDlVIFECx5lO4RlQZcwgg7A0Z5lYCFmWAbJDgDhbXLn4eAFY4ZmF5kbVyyRNqxE9nFVpFKZsh3hd4t520UDiJRt/eTS0ySUjWImVfryUjJiSKH3Z2Xy8Oo1cPl6L4ap5ieSmzHnugYIPiKLu+RkUXD2B6NHhx1nABUkuywMSBIEZbLAwMAPVovAVHxVaBGtdgpVt4KuTVpJh+HHzOOpV2QR2uvwr28BOJ60kw/Dj5rHTq7IJ7NSJY7aBm1pSebOW/7B5vHA1NoOVJslQpAvt6qmAKGlk1CTofg6zn0/1oge0tIpQuNXky+FFzQ4rZvC0rjCqtWV/aoXzoMuU+9ckn0wYBoGqSeZAIzkXMoZPUvLjFYDVtquPAcHk+J8QpM4AWRqglrzLc693OkXQVS1z2TrIjOCbdcFrLOBWB7YNRcA1gm6uiDcZeMtGutff68fg4vTiVD7ULe54ofJJXnXEM2kgZ+wzEm4+AhrVcwHkYlh8k+WnR74o6xt4+P5iz1NqSfh187gYdNkOCPhrmXOjoHmiU4NB+/N54AB4hnTVQIj4f9/m2emIokAg0ZzX/jzLh4gz1EUIBB3MMAHBQ2I0yLWGEALI7e6xkHhZIOjQfTlvxOHkKxh8YGJPcV1ICM0+enH066zjFy7WYiDijxEEOCRnGrtIL5bzRtpftn42rlGDwkg2+MLe38SkeV7QzDnMpaNm8RFul57pUxHfsz+SSpr8RwTnlVppGi5RclAemeBsEnFJalH4Lp6JC8Qa0FfcY8RPADF6TFkKX1zCZT98/ETcmhHVS6lLEPAo3GzYGRTZEmDWn8NkGdjMmK/EDThLZyl5m9yVl3G+j65O9QNrBdt/TsoHRIfxbrRcS+qkkBobfgwXSch+mgiKXhcSJkBXLA4RaawDKzTWpYFiDSQ5KM8Mgx4nBHhCm/O4p6u4Lqx9ErvCSkdDa4LabGOk0TiTPLrssOljVrL1j7NrKXUJml+3jaFBkfWPs6/ZU4X2q6xqoOiC0ybWJwHBJXHA8s2vXUJabWIlE8KZ14+gZTi+HrjMFobGYkVyy7KJ/fj7qGv+knVCasn6Ar4rMRuAej3W/xnrROUrRrDcY70WGDnagoNcECzPKNmxnkBEXpboKyy7Sdulppwvkc2vbfpnitEXHK2Up/xQP6bDApw1DjQeFkRWhjZSyRmMgUV9NjH67S/wzB9VfqXHQsPLkmPbjAtyGefNkOXl6bBPmXF7ot1WESiBHS+x1AkmqkTKkEQtDLmjhdkiDIA03Sg8BxHXA6FNfKXWALM5v1Wj0LX450rD1vr34NcArBl35EfhaumN+Zb/zZHtkrv29uFFWebJl1PJNoAxo/yQXBjl1tFnVm8LUIRF//NY/xlR9BJDjx0PNCCECo0GXQlSdoRhVqLGQ2hqBDUpS5pMgA2sNLjStQ0NnJ8yNk8G2+IB26TB0pjvhg638b09h9laRhGDzJAsYumZjBYElRxGCAumHwPAZcm4Y/Yp4MyfAWJUhy+Jsop8caD9FedJfCj72HqZPX5JDpwwwp+MF+/DiETSPRipwGlZ0C4bBC0jeZgrXqiBgqLNpChFClHsNeNvM3Pz1QN1/u/uVIwuPVUnwPOfp6qk8tKnQ4JjVCISsSAXnGV4xA20auiJYq8Nf9uNiRRInm3023LI6yBnX5LUCAGXz70MuVo0zrrs6AGWq1lrVJX4K05PPUjNGobBxbzI5epSxGwJQ2J4FJ7CQLnR1gHPagNLw3rx4SRlyLDtgeHmRn/RTfx4TNmr7OmQZjF+RbgnkNZf+h9XjgZYveWRIBt/MSzcJiyv9NsxKQ+79bwVJ6LmX+eYCPIV66WXZBF+PYtk64M+FGaidCuA1fqnlMuAaMZpoxt+VjJRHI6jtgeJ1w8kTXK308zbA5auEoWp5M4VwcwrwKxDoF8oMTNdHT76udybJC3rfLfBrzfMFaYUzcxCasTnc23Cqis9ui17jaLM8nrglTzG+Y/X33cP8eGeXccluzzlFYvdD8PwviWQh/bdj/Qgx0WQz9M1vwQakEN6hQFJowctgqEOWAc0+B+/MLEAJiTLL/cafLz7+u5QybL7enP6UuzypDkrvolbV4jw8lvxGM3m72BhmrksEKwOd+uf4a0PdDOO46dgbunR/MUuBR7c9bvMGQhzvejyxfnh17NY4xz02cwa58XdXZJWv7BopjdPeoZyQ8OvW098MKhCYbZ0QhX+RE/QgRMOBY23/hTSmY14dJ02Mdap9PtWAfpDBdT4nkVv8uxxPpTIzJVxk1y0eXwoClE4is5YC0Bus1/wWAk8BlcsOGwtk2+Vyd9n95Hw79pR+GBDoZNHjUrZTCPYnismTaixi8lmYYAmKkUaxcgirgJqm1gAWg5Vc8YtVzgtHrIuH9jua3ZST9BqP+PY0iglkOmls6ANVsssWsgzshZ7hgEjoiEJl2rVBfNg7k55pfH9VfyD52J+d0jqdj2lZMaHWypjJaGlWrjtPMuaPiSegidWg48us7tZI19+DpZJFVTKKFrYlPHjAOIXlC4Z5NW6i+HzfbaL0+TfbN/JGL2PD/cnbVYjeL8nEN09/DgLAjWxZWH00iCog00VBm26ThSmnYQL4sv3BCDc+W917H8eY/7NjPXbXb1r9i1hT3+w9Hh3Sg91EuLaJUPjfNWzx1T1e1kPu26zCKtvhV3bBoi+vsz5SKYuB7DTDBARbsBMwlyn0SzLZBSPOPFeEodSge1cQUuF+nwxRPk9KgAZY4Vgkiovd1Qlze4vs0c+TyQGNaHK3HFMZC0dSRF/P6NohZraid3MMKr/fZWprzwoXuQEqgubH+c56OSOJE9RCjbPOvDTybYYjj6yp8IxHAlV5g5HImuxSen3MwpHqKmd2M0Mo/rfxkssPYHqwhmvrIxAkqdwBJtnHfjpZFtu3J2l6V9ZmRzu28OV1HmfUm/2+Z7KXxqVa4VnFKLMlnfiuQS+6h8uDsWTYWVKIFG92v08zy27KRjzNeNDzLUibA0irmP1YNTS1aLrVfQFi21HLk+rF7MDav23WkbCaXs3WNwxNO+9ldc8N1TdqaoaLO+W+bM9e5PkRfkqLuMvcaHv89W1blgJ5Jh69ltTiubyutk9sMf4H8/2X7LK8/GXVGtAi0IqN3Zi+9ePcZJelGW8e2gG4wBbkA7mD5JaBBkyUmm8hyKI3VBKV9WsoFUtK6tG+d0uO4HGlIshZjKFhVu7pf2BlQ8ZZD+lHOKnkNgYWrMK6DJYq4BiWWu5SkoRjSgLlTnO0sjI3mOSAgPYUAT2mL7UwuEyLtk9P0OicRiKIA5Dqc1Eya481ZfIdRN1JaCJukKaBwxcFAKDP6KWKPoQ83fuyP6pnwVOcoYEVpDK5DWJ0CaC9MyCzlsqBplKFDRrG1CjUZjs3VGRDd5W/BAfTncx95UhEslUJjlESrIsFiHs3GUKW0dVJyN6f1UpwG6rEhHZGviZGVk59NcsNQZ9CdR+X2hToO5QcHzrSkDxu0JL893jzuiXWSWAmKk0Np5l1W0q6H6rBtVQn1fKQY4yiYXhsLWl8RqKIDZDqYXDcNRN4zAUQRyGUhuH+qwXuylzvvpRNO91AdxAMpAzSGmRYliV1zgPRRC3utQeHYUlND0oCoVgLBTKCXwQDnjb5FDT3NxHw01TbAo5DYVNB5Y/JkVRze+6BT5dH40E1E2jss0cvlfD2kOcXpzKh3oO2rxuh0phJgdnFsYaFun4LV6kswtlEF9eXESkDs9pb7NjssP4tIUGRi0FhRPGxNh+S0Fp/22enY4Yk7bQwKmlsHBq7zNoTNrfofbbIuIw9lN987I/VI6OY2Uy00BWprRI8Ta5q4aN+d4iBUwGSQFTEqUwcDZzo7kR+QgIZag7SRNTTvkxK6FIKpShTJpiC5Nr9lQpfJUlh7LAHQZSQYxBQsL4C5l2DUXYmIs0weoIEY/JxSZOJL9ds2o6cKgngAwMwUo5bEaJxKqe+ko9oKJKAqupUtHmctiTuNisDqM3ze+Q94mpMz3zS8O6vYzkoO2MNUZJR5bLRSKqT/nznpgDeaHBW7ycxsf4phnG31jJIJex3jh56UJa1q2UN3pc11MIAtEkcUYK8moN1SwtuYPX2hoW6YTc8pooQhnEVyi2zuMzcMWy/R2et2eENdEh9ycwi+qK4BlUV0oRvQcZrEFfjCpCReltVZ9xR34Bp4ZKOegVmcS24IFlCNTXPzBKcDkEI3ZYabxlj8c0BnsqTGZbeRwoiVsFBgl0EtPWAZlz92HAGWsUpu8Lle1bdmBVRzYFR50EnBpoVLY10SF3oL4qOpSB66JDsYXJpxxnIpRBTIRiW6Coau9PKbuNi69QoJCKwUAhUdjsNmTa0+02lIF2G4ptvZHFRdVxPrPk/gEaoivlYP+TSWgMXyXVLKKAw5BOYmArUFHWNiwREKAxrHQ4xT01xxXQ7WUC06qUQmrtgUKOGqAPCqVwLxQI6KyalE8mdg2FhWVDZA3nj8c4uYdcOhTB4bsrteKW29r0xVIpYNQqRIQ19vesLFluQS5GiK2/Q7Q2I+vJcHRr6zSg2XUyV+bY4BojJIlBG1CjqSuAFQ6EEl7rQIgdxSHIQROAtg8l51HQWAM06A6UTGZVu+5Be/zUikoAqyzT2FCYZ0VRNZ7iXHUSEHkaldXUUOxGYzYlVlf/KpEpT1cCDmK6QttEJ/5uOFohlYKTHJHAxgrZezFsu9D2W7q1f4MiOolpEyG6OB7ThO1vs5Y+Yfat0K4yDjqNgiZDS26XQN7Ux48hIHT2cwLXrKhCMD9VTDgG0e6N4qctNArTFmtLRHCEuj1q2eU1k1P2X6OalLwA1p+HoW0+0zehpTT2rutxlGVU4mpqNNC5SgGkPcCEAUgNMgHUhBMo/TVCfRFGLMXOofQEhOEjzkoqxQaKVFb6JSPdvhoJdr5CpnLxsM2tBF9qDIXz85aT6NGbpO5LQgXTefSGWj3oP9yUUM+YV8zx8+NSTeMxed4M7dT7c1l1N7NE8qlwo1FkWlwx6KQ618d0Ah0zDWYQv2YQ/C3xoIJErORVrZUgRj7THPVnm3X7IJS4UspBaq4GchYbuqIEVleKvKvfjeDs6sM3maC7Xrr8q1G/PzVt8LtG49/j6gCfV0TnH+5qmsb/0U173lLXnFLN8P1Qblw03w/kNgVYEzSLXhjWPLdxfs/AHkGp5snnKzNPN3Nzwo5aKSRyoNijlYU0jAtq1Er+Q+pCZgEu4RRGk4AVQuIEuG0kNWK6PjT6YxvJ94TQT61MZ1AGuLfUaGG4jzQWV+PV7r+jQ2hCVddpQwRS5AqWqL7HMKqqZh9raaTBBlszmUC6HGYYcoF0/odd0LUzXtl4nWy055WrcSILFAJ4Hc9qQahAGwLLg5jJ3klA8mAdZWaTyMvUUbdOzdrFbfPwnV4ZVxu+lMc1Nl+1M7SiLOADjWFXBoMYEB+q0Ssbvk6Asoh6azGZeKEx6tsFzAMSBjAFdEmzMYHx7qW76u1ejElplcS/usq+Eq+HXdEdr6JiOlxRmdC7l2ZUvd9P6rfcDMETJzZ4XLnh3bgcub0N1oQMoJWFMAQeBHFiL35cgxleJmlaBdK+ZYMRFNJwJiBhaILSXXq3oWlca402ZBdQsjJIDWCpFtzNAF05H96WAWxhroCrpV7H5/pgV+3lmoZr9k0rlGvz7qbpMg0YzaEThTCBmi2B10QzIbir2iUKMKqqE4VQVU1nwGsOP06fXGVpalRTJgihopjroJkzQbkMxqnWpFuImhZh5USSiUJqNeRUEX09JAnECBXVkznikRjTMIZW0aAcktuhUdGSr8HYEnRMCGzVmIvCuynxgRCtov0DpylsUnCVJgQPZpEG047o8zCasBl9HtMQhtezo2kpE5lyqhiHo7SKIdBEyTPDW3PKF+Nuuj5rjNFOAFUIo2jpbXhV4Vc/6vKj0nZ9FbJgCkuHvQeN4QPdI1WOxFw3iL4ijUVkKaPOIDKYKUevrVf069m2SaNbG5rJgi7jTd4TxWZNPVag8yj6zP2Wp70hrKqAdP6XVKRkT7wWnMtprKKm2KRQhAhL4dSDck9Fw/kK/CAHXMFwgmHyQQ4o05XUijFzlSfTtHYn2gV8ntzdr6swR59NC7eBSuJXcS0T2FDP0wLKIL9hT1on8r8THV7VLv9adFXNzx7igu0/J+WDwEFX3FbFmzpSXTXDHK+KZo8bbwip3w7t42aAK3hSBKyJ9nhS6j5Ppvkk+p1sH7mW37iwlHn6zH+WgCiQBAiIYtbCoR6YkNBdRSDHoHEoZKQPMTAy5FTkjVCSJPoxi7Vf2Cv5RccypunSN+J9QqHwq7Sa4PKmO0Xj6XivmJ0yGtrFtZQJPQkO1tS+r8ZMmmMnQt2JJOuUTyXc0pxPyglqCXggZZhQB+Q6bXuyKYXphAVugrNRWv/+Dn1sQk3JGokv20A9HCe3zgj093fEuQH+pI7S8+FktG3vtySY9WAgU8/AiUN0jsVNYZgworT+541zm8GYZJhwsNtS0b+BSFmUxdaImX1HIMiQxBjJwAyCa0QzBvzY7UIzCKFVOSG0oW0ksbNvtJqZu0LY2NrMplppD9BTrhhPueDUwcKEnlhGbEEsDWIMwzkVnNqqFKINoMY6TGJIJE69ZUluwrDq7usCJiEJu2hRlzTqQUxs/4hTagfrolszp/wW7SibSk3gBoKezeWmMD2Hu1UTj4Dp/NikWCu8iYzDSXJdq/JGrWnjxlWakSdwjVC2ZJOa25nFKJR2pSS4psbhxLbjB0LEQDl7NAybQCG6iR+PKRtSsOGKK5SGocvoJG9hVe6f/pDOxUIqI5T2haTxJ2e1J014dfy1kinqG75dOpH/r1V4VbVlzXat1P7RRqsE+2iPXZn1YhYng5y1KZR37S1r8S7V51mbt0lkbloj9nDjP+MZ/ZLHOP/x+vvuIT7cs+u4Gp73jxgBi4vWSqYQLL+q1IZf+MUkeQ1MfOipWewC33GaaAT+B1l7mXpbaiMPKRm3b6x1QuziWB6S4g1RX4XyZyZDULZV8R+alzVR/1ySdciGUIYcsmnPQDU7y+gLTyPU7149igw74jqR/61w7eWmpib6KNPIaw3kaGGgDhEn0IeWbvprDp6BL7+HFL3Js0eTPUzkIQwCP/3UBhXjS06TTXGbORhCIN66GYQHpCLtMSkoHuLkppAGPnbVBjbjC1ZYO1gbnk1iAgVIFwIP86gNv/EUAS9QAcenqHUN5sEezWrsZHsHy9yWvvxHfNFqzKE7+W2o6N0hKZM4NRyoNVXAlRx3mBZ+AeumOX9nedVqujG6A8M6K7td0LqB1DW2BJ9Epj1LNjIFkPjmlz3/D0yNKzgx+Q/0tlnThPW5sjHmMAfm4AFZDcR+AnA7b9LeyYnq7+JldijKPE7qx1CqYVivX5fw6jaLsPqGlSb/vOzmHpE1C5pyou8UiXNQ+5tDHt0kFTgZXa5JVB3Xd9XmE15looJNesgJWL2Y1mJ4xALvWDULHIYHqqYZdkg8ZjZXT2cWnpzYbAG1hae3qN6XXuvSDTSxxfB4Ah4r422YXiGbZtghu5vZXD2dWXhy9rgF1FZfVSN/EbXX2IAPgK+2Z/jKIq/UNZ8H28tzHswuJqUjWFIgNyvllP9uWZOIH+FRAzPrIGRcqzOP8egDnclGtm9cK4TBNq09qv7iedNIbfjKyyzvy148b954bH+o/qwmrNV870O2Z2nBf33x/PpU1X5kzV+vWJHcD028qNo8MP4a7dBoR/PucJd1sz5Foo6kK+4e3WBlvI/L+CIvk/ppgqp4V406+eulfH2mfr7wC9u/O/x5Ko+nslKZPX5JpTnli+dm/i+eazK/aO4bFD5UqMRMKhXYn4eXpyTd93K/idNCmUdjTVxW1n/Lqt8bX1Zds2T3P/qWPmYHYkOt+V6xIzvsqy53yx6P9SvexZ+Hm/gbGyPbp4K9Z/fx7sdVnSSdLzdhjdgdIZv9xaskvs/jx6JtY6hf/VlheP/4/X//Hxvl9Z21UggA + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs b/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs index ea5109256d..49ae7dd7a8 100644 --- a/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs +++ b/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs @@ -10,6 +10,7 @@ public sealed class MigrationsConfiguration : DbMigrationsConfiguration 201507200832223_SortFilterHomepageProducts.cs - - - 201507202149123_Merge2.cs - 201507210952098_PaymentMethodDescription.cs @@ -331,6 +327,10 @@ 201507242008201_WebScheduler.cs + + + 201507250039446_Merge2.cs + @@ -618,15 +618,15 @@ 201507200832223_SortFilterHomepageProducts.cs - - 201507202149123_Merge2.cs - 201507210952098_PaymentMethodDescription.cs 201507242008201_WebScheduler.cs + + 201507250039446_Merge2.cs + From fe8e8ff7441fc58f4101dacf40b4e1e8c86aed85 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 25 Jul 2015 12:16:49 +0200 Subject: [PATCH 0120/1074] Reduce database round trips initiated by AreProductAttributesEqual --- ...01507210952098_PaymentMethodDescription.cs | 4 +- .../Catalog/IProductAttributeParser.cs | 27 ++-- .../Catalog/IProductAttributeService.cs | 21 +-- .../Catalog/PriceCalculationService.cs | 2 +- .../Catalog/ProductAttributeParser.cs | 147 +++++++----------- .../Catalog/ProductAttributeService.cs | 53 +++---- .../Orders/ShoppingCartService.cs | 2 +- .../Controllers/ProductController.cs | 4 +- .../Controllers/CatalogHelper.cs | 4 +- 9 files changed, 114 insertions(+), 150 deletions(-) diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs index 75e57c5d4b..b71dd98ac0 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs @@ -51,8 +51,8 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Minimal realisierbarer Preis"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.PreSelectedPrice", - "Preselected price", - "Vorgewhlter Preis"); + "Price preselected on detail page", + "Auf der Detailseite vorgewhlter Preis"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.PriceWithoutDiscountsAndAttributes", "Price without discounts and attributes", diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs index 21fd8bcdc7..69a506fc8c 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs @@ -25,13 +25,6 @@ public partial interface IProductAttributeParser /// Selected product variant attributes IList ParseProductVariantAttributes(string attributes); - /// - /// Gets selected product variant attributes - /// - /// The attribute ids - /// Selected product variant attributes - IEnumerable ParseProductVariantAttributes(ICollection ids); - /// /// Get product variant attribute values /// @@ -59,19 +52,29 @@ public partial interface IProductAttributeParser /// /// Are attributes equal /// - /// The attributes of the first product - /// The attributes of the second product + /// The attributes of the first product + /// The attributes of the second product + /// Collection of already loaded product attribute mappings to reduce database rountrips /// Result - bool AreProductAttributesEqual(string attributes1, string attributes2); + bool AreProductAttributesEqual(string attributeXml1, string attributeXml2, IEnumerable attributes = null); /// /// Finds a product variant attribute combination by attributes stored in XML /// /// Product /// Attributes in XML format + /// Collection of already loaded product attribute mappings to reduce database rountrips /// Found product variant attribute combination - ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml); - ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml); + ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml, IEnumerable attributes = null); + + /// + /// Finds a product variant attribute combination by attributes stored in XML + /// + /// Product identifier + /// Attributes in XML format + /// Collection of already loaded product attribute mappings to reduce database rountrips + /// Found product variant attribute combination + ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml, IEnumerable attributes = null); /// /// Deserializes attribute data from an URL query string diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs index 732eacbb59..ce0394d014 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs @@ -74,12 +74,14 @@ public partial interface IProductAttributeService /// Product variant attribute mapping ProductVariantAttribute GetProductVariantAttributeById(int productVariantAttributeId); - /// - /// Gets multiple product variant attribute mappings by their keys - /// - /// a list of keys - /// Product variant attribute mappings - IEnumerable GetProductVariantAttributesByIds(params int[] ids); + + /// + /// Gets a product variant attribute mappings + /// + /// Enumerable of product variant attribute mapping identifiers + /// Collection of already loaded product attribute mappings to reduce database rountrips + /// List of product variant attribute mapping + IList GetProductVariantAttributesByIds(IEnumerable productVariantAttributeIds, IEnumerable attributes = null); /// /// Inserts a product variant attribute mapping @@ -136,13 +138,6 @@ public partial interface IProductAttributeService /// The product variant attribute value void UpdateProductVariantAttributeValue(ProductVariantAttributeValue productVariantAttributeValue); - /// - /// Gets a list of product identifiers which have price adjustments - /// - /// Array of product identifiers - /// List of product identifiers - IList GetProductIdsWithPriceAdjustments(int[] productIds); - #endregion #region Product variant attribute combinations (ProductVariantAttributeCombination) diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index 0c965dceb1..acf2e3c933 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -214,7 +214,7 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC var combinations = context.AttributeCombinations.Ensure(product.Id); - var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml)); + var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml, attributes)); if (selectedCombination != null && selectedCombination.IsActive && selectedCombination.Price.HasValue) { diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs index 1546a5e9d7..aa190121c6 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs @@ -1,12 +1,12 @@ using System; -using System.Linq; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using System.Web; using System.Xml; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Collections; using Newtonsoft.Json; -using System.Web; +using SmartStore.Collections; +using SmartStore.Core.Domain.Catalog; namespace SmartStore.Services.Catalog { @@ -104,33 +104,9 @@ public virtual Multimap DeserializeProductVariantAttributes(string /// Selected product variant attributes public virtual IList ParseProductVariantAttributes(string attributes) { - var pvaCollection = new List(); - - // codehint: sm-edit var ids = ParseProductVariantAttributeIds(attributes); - return this.ParseProductVariantAttributes(ids.ToList()).ToList(); - } - - public virtual IEnumerable ParseProductVariantAttributes(ICollection ids) - { - if (ids != null) - { - if (ids.Count == 1) - { - var pva = _productAttributeService.GetProductVariantAttributeById(ids.ElementAt(0)); - if (pva != null) - { - return new ProductVariantAttribute[] { pva }; - } - } - else - { - return _productAttributeService.GetProductVariantAttributesByIds(ids.ToArray()).ToList(); - } - } - - return Enumerable.Empty(); + return _productAttributeService.GetProductVariantAttributesByIds(ids); } /// @@ -143,17 +119,20 @@ public virtual IEnumerable ParseProductVariantAttr var pvaValues = Enumerable.Empty(); var attrs = DeserializeProductVariantAttributes(attributes); - var pvaCollection = ParseProductVariantAttributes(attrs.Keys); + var pvaCollection = _productAttributeService.GetProductVariantAttributesByIds(attrs.Keys); foreach (var pva in pvaCollection) { if (!pva.ShouldHaveValues()) continue; - var pvaValuesStr = attrs[pva.Id]; //ParseValues(attributes, pva.Id); - var ids = from id in pvaValuesStr - where id.HasValue() - select id.ToInt(); + var pvaValuesStr = attrs[pva.Id]; + + var ids = + from id in pvaValuesStr + where id.HasValue() + select id.ToInt(); + var values = _productAttributeService.GetProductVariantAttributeValuesByIds(ids.ToArray()); pvaValues = pvaValues.Concat(values); @@ -218,82 +197,72 @@ public virtual string AddProductAttribute(string attributes, ProductVariantAttri return pva.AddProductAttribute(attributes, value); } - /// - /// Are attributes equal - /// - /// The attributes of the first product - /// The attributes of the second product - /// Result - public virtual bool AreProductAttributesEqual(string attributes1, string attributes2) + public virtual bool AreProductAttributesEqual(string attributeXml1, string attributeXml2, IEnumerable attributes = null) { - var attrs1 = DeserializeProductVariantAttributes(attributes1); - var attrs2 = DeserializeProductVariantAttributes(attributes2); + if (attributeXml1.IsCaseInsensitiveEqual(attributeXml2)) + return true; - if (attrs1.Count == attrs2.Count) - { - var pva1Collection = ParseProductVariantAttributes(attrs2.Keys); - var pva2Collection = ParseProductVariantAttributes(attrs1.Keys); - foreach (var pva1 in pva1Collection) - { - foreach (var pva2 in pva2Collection) - { - if (pva1.Id == pva2.Id) - { - var pvaValues1Str = attrs2[pva1.Id]; // ParseValues(attributes2, pva1.Id); - var pvaValues2Str = attrs1[pva2.Id]; // ParseValues(attributes1, pva2.Id); - if (pvaValues1Str.Count == pvaValues2Str.Count) - { - foreach (string str1 in pvaValues1Str) - { - bool hasAttribute = pvaValues2Str.Any(x => x.IsCaseInsensitiveEqual(str1)); - if (!hasAttribute) - { - return false; - } - } - } - else - { - return false; - } - } - } - } - } - else - { - return false; - } + var attributes1 = DeserializeProductVariantAttributes(attributeXml1); + var attributes2 = DeserializeProductVariantAttributes(attributeXml2); + + if (attributes1.Count != attributes2.Count) + return false; + + IEnumerable pvaCollection1 = null; + IEnumerable pvaCollection2 = null; + + pvaCollection1 = _productAttributeService.GetProductVariantAttributesByIds(attributes2.Keys, attributes); + + if (attributes2.Keys.SequenceEqual(attributes1.Keys)) // often the case + pvaCollection2 = pvaCollection1; + else + pvaCollection2 = _productAttributeService.GetProductVariantAttributesByIds(attributes1.Keys, attributes); + + foreach (var pva1 in pvaCollection1) + { + foreach (var pva2 in pvaCollection2) + { + if (pva1.Id == pva2.Id) + { + var pvaValues1 = attributes2[pva1.Id]; + var pvaValues2 = attributes1[pva2.Id]; + + if (pvaValues1.Count != pvaValues2.Count) + return false; + + foreach (string value1 in pvaValues1) + { + string str1 = value1.TrimSafe(); + + if (!pvaValues2.Any(x => x.TrimSafe().IsCaseInsensitiveEqual(str1))) + return false; + } + } + } + } return true; } - /// - /// Finds a product variant attribute combination by attributes stored in XML - /// - /// Product - /// Attributes in XML format - /// Found product variant attribute combination - public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml) + public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml, IEnumerable attributes = null) { if (product == null) throw new ArgumentNullException("product"); - return FindProductVariantAttributeCombination(product.Id, attributesXml); + return FindProductVariantAttributeCombination(product.Id, attributesXml, attributes); } - public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml) + public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml, IEnumerable attributes = null) { if (attributesXml.HasValue()) { - //existing combinations var combinations = _productAttributeService.GetAllProductVariantAttributeCombinations(productId); if (combinations.Count == 0) return null; foreach (var combination in combinations) { - bool attributesEqual = AreProductAttributesEqual(combination.AttributesXml, attributesXml); + bool attributesEqual = AreProductAttributesEqual(combination.AttributesXml, attributesXml, attributes); if (attributesEqual) return combination; } diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs index 95cad54978..9d05fa4d4e 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs @@ -210,20 +210,36 @@ public virtual ProductVariantAttribute GetProductVariantAttributeById(int produc return null; string key = string.Format(PRODUCTVARIANTATTRIBUTES_BY_ID_KEY, productVariantAttributeId); - return _cacheManager.Get(key, () => { + + return _cacheManager.Get(key, () => + { return _productVariantAttributeRepository.GetById(productVariantAttributeId); }); } - public virtual IEnumerable GetProductVariantAttributesByIds(params int[] ids) - { - if (ids == null || ids.Length == 0) - { - return Enumerable.Empty(); - } + public virtual IList GetProductVariantAttributesByIds(IEnumerable productVariantAttributeIds, IEnumerable attributes = null) + { + var result = new List(); - return _productVariantAttributeRepository.GetMany(ids); - } + if (productVariantAttributeIds != null) + { + foreach (var id in productVariantAttributeIds) + { + ProductVariantAttribute pva = null; + + if (attributes != null) + pva = attributes.FirstOrDefault(x => x.Id == id); + + if (pva == null) + pva = GetProductVariantAttributeById(id); + + if (pva != null) + result.Add(pva); + } + } + + return result; + } public virtual IEnumerable GetProductVariantAttributeValuesByIds(params int[] productVariantAttributeValueIds) { @@ -340,25 +356,6 @@ public virtual void UpdateProductVariantAttributeValue(ProductVariantAttributeVa _eventPublisher.EntityUpdated(productVariantAttributeValue); } - public virtual IList GetProductIdsWithPriceAdjustments(int[] productIds) - { - var queryMappings = - from m in _productVariantAttributeRepository.TableUntracked - where productIds.Contains(m.ProductId) - select new { m.Id, m.ProductId }; - - var query = - from v in _productVariantAttributeValueRepository.TableUntracked - join m in queryMappings on v.ProductVariantAttributeId equals m.Id - where v.PriceAdjustment != 0 - group v by m.ProductId into grp - select grp.Key; - - var result = query.ToList(); - - return result; - } - #endregion #region Product variant attribute combinations (ProductVariantAttributeCombination) diff --git a/src/Libraries/SmartStore.Services/Orders/ShoppingCartService.cs b/src/Libraries/SmartStore.Services/Orders/ShoppingCartService.cs index 5882bda05e..847cce099d 100644 --- a/src/Libraries/SmartStore.Services/Orders/ShoppingCartService.cs +++ b/src/Libraries/SmartStore.Services/Orders/ShoppingCartService.cs @@ -548,7 +548,7 @@ public virtual IList GetShoppingCartItemAttributeWarnings(Customer custo { var combination = product .ProductVariantAttributeCombinations - .FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, selectedAttributes)); + .FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, selectedAttributes, pva1Collection)); if (combination != null && !combination.IsActive) { diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 2a973ca37d..49c2a5a928 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -4280,7 +4280,7 @@ public ActionResult AttributeCombinationCreatePopup(string btnId, string formId, warnings.AddRange(_shoppingCartService.GetShoppingCartItemAttributeWarnings(_workContext.CurrentCustomer, ShoppingCartType.ShoppingCart, product, attributeXml)); - if (null != _productAttributeParser.FindProductVariantAttributeCombination(product, attributeXml)) + if (null != _productAttributeParser.FindProductVariantAttributeCombination(product, attributeXml, variantAttributes)) { warnings.Add(_localizationService.GetResource("Admin.Catalog.Products.ProductVariantAttributes.AttributeCombinations.CombiExists")); } @@ -4411,7 +4411,7 @@ public ActionResult CombinationExistenceNote(int productId, FormCollection form) string attributeXml = form.CreateSelectedAttributesXml(productId, attributes, _productAttributeParser, _localizationService, _downloadService, _catalogSettings, this.Request, warnings, false); - bool exists = (null != _productAttributeParser.FindProductVariantAttributeCombination(productId, attributeXml)); + bool exists = (null != _productAttributeParser.FindProductVariantAttributeCombination(productId, attributeXml, attributes)); if (!exists) { diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index 16e7022c43..4fe5dcaa57 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -591,7 +591,7 @@ public ProductDetailsModel PrepareProductDetailModel( } model.CombinationSelected = model.Combinations - .FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml)); + .FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml, variantAttributes)); if (model.CombinationSelected != null && model.CombinationSelected.IsActive == false) { @@ -1050,7 +1050,7 @@ public IEnumerable PrepareProductOverviewModels( { StoreId = currentStore.Id, ParentGroupedProductId = product.Id, - PageSize = int.MaxValue, + PageSize = (_catalogSettings.PriceDisplayType == PriceDisplayType.LowestPrice ? int.MaxValue : 1), VisibleIndividuallyOnly = false }; From 8a855d00265ca64dfe1ff8fce089ba1f0ee20be9 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 25 Jul 2015 19:06:16 +0200 Subject: [PATCH 0121/1074] Changed some things of last commit Preselected price was wrong for product attributes with multiple preselected values (same on product detail page) --- .../Catalog/IProductAttributeParser.cs | 50 ++++--- .../Catalog/IProductAttributeService.cs | 7 +- .../Catalog/PriceCalculationService.cs | 34 +++-- .../Catalog/ProductAttributeParser.cs | 90 ++++++------- .../Catalog/ProductAttributeService.cs | 61 ++++++--- .../Controllers/ProductController.cs | 4 +- .../Controllers/CatalogHelper.cs | 125 +++++++++--------- 7 files changed, 209 insertions(+), 162 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs index 69a506fc8c..4ac7e9b945 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs @@ -14,47 +14,47 @@ public partial interface IProductAttributeParser /// /// Gets selected product variant attributes as a map of integer ids with their corresponding values. /// - /// Attributes XML + /// XML formatted attributes /// The deserialized map - Multimap DeserializeProductVariantAttributes(string attributes); + Multimap DeserializeProductVariantAttributes(string attributesXml); - /// - /// Gets selected product variant attributes - /// - /// Attributes - /// Selected product variant attributes - IList ParseProductVariantAttributes(string attributes); + /// + /// Gets selected product variant attributes + /// + /// XML formatted attributes + /// Selected product variant attributes + IList ParseProductVariantAttributes(string attributesXml); /// /// Get product variant attribute values /// - /// Attributes + /// XML formatted attributes /// Product variant attribute values - IEnumerable ParseProductVariantAttributeValues(string attributes); + IEnumerable ParseProductVariantAttributeValues(string attributesXml); /// /// Gets selected product variant attribute value /// - /// Attributes + /// XML formatted attributes /// Product variant attribute identifier /// Product variant attribute value - IList ParseValues(string attributes, int productVariantAttributeId); + IList ParseValues(string attributesXml, int productVariantAttributeId); /// /// Adds an attribute /// - /// Attributes + /// XML formatted attributes /// Product variant attribute /// Value /// Attributes - string AddProductAttribute(string attributes, ProductVariantAttribute pva, string value); + string AddProductAttribute(string attributesXml, ProductVariantAttribute pva, string value); /// /// Are attributes equal /// /// The attributes of the first product /// The attributes of the second product - /// Collection of already loaded product attribute mappings to reduce database rountrips + /// Collection of already loaded product attribute mappings to reduce database round trips /// Result bool AreProductAttributesEqual(string attributeXml1, string attributeXml2, IEnumerable attributes = null); @@ -62,19 +62,17 @@ public partial interface IProductAttributeParser /// Finds a product variant attribute combination by attributes stored in XML /// /// Product - /// Attributes in XML format - /// Collection of already loaded product attribute mappings to reduce database rountrips + /// XML formatted attributes /// Found product variant attribute combination - ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml, IEnumerable attributes = null); + ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml); /// /// Finds a product variant attribute combination by attributes stored in XML /// /// Product identifier - /// Attributes in XML format - /// Collection of already loaded product attribute mappings to reduce database rountrips + /// XML formatted attributes /// Found product variant attribute combination - ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml, IEnumerable attributes = null); + ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml); /// /// Deserializes attribute data from an URL query string @@ -87,7 +85,7 @@ public partial interface IProductAttributeParser /// Serializes attribute data /// /// Product identifier - /// Attribute XML string + /// XML formatted attributes /// Whether to URL encode /// Json string with attribute data string SerializeQueryData(int productId, string attributesXml, bool urlEncode = true); @@ -99,26 +97,26 @@ public partial interface IProductAttributeParser /// /// Add gift card attrbibutes /// - /// Attributes + /// XML formatted attributes /// Recipient name /// Recipient email /// Sender name /// Sender email /// Message /// Attributes - string AddGiftCardAttribute(string attributes, string recipientName, + string AddGiftCardAttribute(string attributesXml, string recipientName, string recipientEmail, string senderName, string senderEmail, string giftCardMessage); /// /// Get gift card attrbibutes /// - /// Attributes + /// XML formatted attributes /// Recipient name /// Recipient email /// Sender name /// Sender email /// Message - void GetGiftCardAttribute(string attributes, out string recipientName, + void GetGiftCardAttribute(string attributesXml, out string recipientName, out string recipientEmail, out string senderName, out string senderEmail, out string giftCardMessage); diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs index ce0394d014..36874a566a 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs @@ -74,13 +74,12 @@ public partial interface IProductAttributeService /// Product variant attribute mapping ProductVariantAttribute GetProductVariantAttributeById(int productVariantAttributeId); - /// - /// Gets a product variant attribute mappings + /// Gets product variant attribute mappings /// /// Enumerable of product variant attribute mapping identifiers - /// Collection of already loaded product attribute mappings to reduce database rountrips - /// List of product variant attribute mapping + /// Collection of already loaded product attribute mappings to reduce database round trips + /// IList GetProductVariantAttributesByIds(IEnumerable productVariantAttributeIds, IEnumerable attributes = null); /// diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index acf2e3c933..a343b360be 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -164,7 +164,7 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC var bundleItemId = (bundleItem == null ? 0 : bundleItem.Item.Id); var selectedAttributes = new NameValueCollection(); - List selectedAttributeValues = null; + var selectedAttributeValues = new List(); var attributes = context.Attributes.Ensure(product.Id); // 1. fill selectedAttributes with initially selected attributes @@ -172,6 +172,7 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC { int preSelectedValueId = 0; ProductVariantAttributeValue defaultValue = null; + var selectedValueIds = new List(); var pvaValues = attribute.ProductVariantAttributeValues; foreach (var pvaValue in pvaValues) @@ -193,15 +194,30 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC } } - // value pre-selected by a bundle item filter discards the default pre-selection - if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null) - defaultValue.IsPreSelected = true; + //if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null) + // defaultValue.IsPreSelected = true; - if (defaultValue == null) - defaultValue = pvaValues.FirstOrDefault(x => x.IsPreSelected); + //if (defaultValue == null) + // defaultValue = pvaValues.FirstOrDefault(x => x.IsPreSelected); - if (defaultValue != null) + //if (defaultValue != null) + // selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId); + + // value pre-selected by a bundle item filter discards the default pre-selection + if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null) + { + //defaultValue.IsPreSelected = true; + selectedAttributeValues.Add(defaultValue); selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId); + } + else + { + foreach (var value in pvaValues.Where(x => x.IsPreSelected)) + { + selectedAttributeValues.Add(value); + selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, value.Id, product.Id, bundleItemId); + } + } } // 2. find attribute combination for selected attributes and merge it @@ -210,8 +226,6 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC string attributeXml = selectedAttributes.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _services.Localization, _downloadService, _catalogSettings, _httpRequestBase, new List(), true, bundleItemId); - selectedAttributeValues = _productAttributeParser.ParseProductVariantAttributeValues(attributeXml).ToList(); - var combinations = context.AttributeCombinations.Ensure(product.Id); var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml, attributes)); @@ -224,7 +238,7 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC if (_catalogSettings.EnableDynamicPriceUpdate && !isBundlePricing) { - if (selectedAttributeValues != null) + if (selectedAttributeValues.Count > 0) { selectedAttributeValues.Each(x => attributesTotalPriceBase += GetProductVariantAttributeValuePriceAdjustment(x)); } diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs index aa190121c6..3d454b3822 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs @@ -22,23 +22,23 @@ public ProductAttributeParser(IProductAttributeService productAttributeService) this._productAttributeService = productAttributeService; } - #region Product attributes + #region Product attributes - /// + /// /// Gets selected product variant attribute identifiers /// - /// Attributes + /// Attributes /// Selected product variant attribute identifiers - private IEnumerable ParseProductVariantAttributeIds(string attributes) + private IEnumerable ParseProductVariantAttributeIds(string attributesXml) { var ids = new List(); - if (String.IsNullOrEmpty(attributes)) + if (String.IsNullOrEmpty(attributesXml)) yield break; try { var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); var nodeList = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute"); foreach (var node in nodeList.Cast()) @@ -55,19 +55,18 @@ private IEnumerable ParseProductVariantAttributeIds(string attributes) } } finally { } - } - public virtual Multimap DeserializeProductVariantAttributes(string attributes) + public virtual Multimap DeserializeProductVariantAttributes(string attributesXml) { var attrs = new Multimap(); - if (String.IsNullOrEmpty(attributes)) + if (String.IsNullOrEmpty(attributesXml)) return attrs; try { var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute"); foreach (var node1 in nodeList1.Cast()) @@ -100,26 +99,22 @@ public virtual Multimap DeserializeProductVariantAttributes(string /// /// Gets selected product variant attributes /// - /// Attributes + /// Attributes /// Selected product variant attributes - public virtual IList ParseProductVariantAttributes(string attributes) - { - var ids = ParseProductVariantAttributeIds(attributes); + public virtual IList ParseProductVariantAttributes(string attributesXml) + { + var ids = ParseProductVariantAttributeIds(attributesXml); - return _productAttributeService.GetProductVariantAttributesByIds(ids); - } + return _productAttributeService.GetProductVariantAttributesByIds(ids.ToList()); + } - /// - /// Get product variant attribute values - /// - /// Attributes - /// Product variant attribute values - public virtual IEnumerable ParseProductVariantAttributeValues(string attributes) + public virtual IEnumerable ParseProductVariantAttributeValues(string attributeXml) { - var pvaValues = Enumerable.Empty(); + //var pvaValues = Enumerable.Empty(); - var attrs = DeserializeProductVariantAttributes(attributes); - var pvaCollection = _productAttributeService.GetProductVariantAttributesByIds(attrs.Keys); + var allIds = new List(); + var attrs = DeserializeProductVariantAttributes(attributeXml); + var pvaCollection = _productAttributeService.GetProductVariantAttributesByIds(attrs.Keys); foreach (var pva in pvaCollection) { @@ -133,27 +128,32 @@ from id in pvaValuesStr where id.HasValue() select id.ToInt(); - var values = _productAttributeService.GetProductVariantAttributeValuesByIds(ids.ToArray()); + allIds.AddRange(ids); - pvaValues = pvaValues.Concat(values); + //var values = _productAttributeService.GetProductVariantAttributeValuesByIds(ids.ToArray()); + //pvaValues = pvaValues.Concat(values); } - return pvaValues; + int[] allDistinctIds = allIds.Distinct().ToArray(); + + var values = _productAttributeService.GetProductVariantAttributeValuesByIds(allDistinctIds); + + return values; } /// /// Gets selected product variant attribute value /// - /// Attributes + /// Attributes /// Product variant attribute identifier /// Product variant attribute value - public virtual IList ParseValues(string attributes, int productVariantAttributeId) + public virtual IList ParseValues(string attributesXml, int productVariantAttributeId) { var selectedProductVariantAttributeValues = new List(); try { var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute"); foreach (XmlNode node1 in nodeList1) @@ -188,13 +188,13 @@ public virtual IList ParseValues(string attributes, int productVariantAt /// /// Adds an attribute /// - /// Attributes + /// Attributes /// Product variant attribute /// Value /// Attributes - public virtual string AddProductAttribute(string attributes, ProductVariantAttribute pva, string value) + public virtual string AddProductAttribute(string attributesXml, ProductVariantAttribute pva, string value) { - return pva.AddProductAttribute(attributes, value); + return pva.AddProductAttribute(attributesXml, value); } public virtual bool AreProductAttributesEqual(string attributeXml1, string attributeXml2, IEnumerable attributes = null) @@ -244,15 +244,15 @@ public virtual bool AreProductAttributesEqual(string attributeXml1, string attri return true; } - public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml, IEnumerable attributes = null) + public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml) { if (product == null) throw new ArgumentNullException("product"); - return FindProductVariantAttributeCombination(product.Id, attributesXml, attributes); + return FindProductVariantAttributeCombination(product.Id, attributesXml); } - public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml, IEnumerable attributes = null) + public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml) { if (attributesXml.HasValue()) { @@ -262,7 +262,7 @@ public virtual ProductVariantAttributeCombination FindProductVariantAttributeCom foreach (var combination in combinations) { - bool attributesEqual = AreProductAttributesEqual(combination.AttributesXml, attributesXml, attributes); + bool attributesEqual = AreProductAttributesEqual(combination.AttributesXml, attributesXml); if (attributesEqual) return combination; } @@ -328,14 +328,14 @@ public virtual string SerializeQueryData(int productId, string attributesXml, bo /// /// Add gift card attrbibutes /// - /// Attributes + /// Attributes /// Recipient name /// Recipient email /// Sender name /// Sender email /// Message /// Attributes - public string AddGiftCardAttribute(string attributes, string recipientName, + public string AddGiftCardAttribute(string attributesXml, string recipientName, string recipientEmail, string senderName, string senderEmail, string giftCardMessage) { string result = string.Empty; @@ -347,14 +347,14 @@ public string AddGiftCardAttribute(string attributes, string recipientName, senderEmail = senderEmail.Trim(); var xmlDoc = new XmlDocument(); - if (String.IsNullOrEmpty(attributes)) + if (String.IsNullOrEmpty(attributesXml)) { var element1 = xmlDoc.CreateElement("Attributes"); xmlDoc.AppendChild(element1); } else { - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); } var rootElement = (XmlElement)xmlDoc.SelectSingleNode(@"//Attributes"); @@ -398,13 +398,13 @@ public string AddGiftCardAttribute(string attributes, string recipientName, /// /// Get gift card attrbibutes /// - /// Attributes + /// Attributes /// Recipient name /// Recipient email /// Sender name /// Sender email /// Message - public void GetGiftCardAttribute(string attributes, out string recipientName, + public void GetGiftCardAttribute(string attributesXml, out string recipientName, out string recipientEmail, out string senderName, out string senderEmail, out string giftCardMessage) { @@ -417,7 +417,7 @@ public void GetGiftCardAttribute(string attributes, out string recipientName, try { var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); var recipientNameElement = (XmlElement)xmlDoc.SelectSingleNode(@"//Attributes/GiftCardInfo/RecipientName"); var recipientEmailElement = (XmlElement)xmlDoc.SelectSingleNode(@"//Attributes/GiftCardInfo/RecipientEmail"); diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs index 9d05fa4d4e..47dafa0dfc 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs @@ -71,14 +71,36 @@ public ProductAttributeService(ICacheManager cacheManager, #endregion - //// Autowired Dependency (is a proptery dependency to avoid circularity) - //public virtual IProductAttributeParser AttributeParser { get; set; } + #region Utilities - #region Methods + private IList GetSwitchedLoadedAttributeMappings(ICollection productVariantAttributeIds) + { + if (productVariantAttributeIds != null && productVariantAttributeIds.Count > 0) + { + if (productVariantAttributeIds.Count == 1) + { + var pva = GetProductVariantAttributeById(productVariantAttributeIds.ElementAt(0)); + if (pva != null) + { + return new List { pva }; + } + } + else + { + return _productVariantAttributeRepository.GetMany(productVariantAttributeIds).ToList(); + } + } - #region Product attributes + return new List(); + } + + #endregion - public virtual void DeleteProductAttribute(ProductAttribute productAttribute) + #region Methods + + #region Product attributes + + public virtual void DeleteProductAttribute(ProductAttribute productAttribute) { if (productAttribute == null) throw new ArgumentNullException("productAttribute"); @@ -219,26 +241,33 @@ public virtual ProductVariantAttribute GetProductVariantAttributeById(int produc public virtual IList GetProductVariantAttributesByIds(IEnumerable productVariantAttributeIds, IEnumerable attributes = null) { - var result = new List(); - if (productVariantAttributeIds != null) { - foreach (var id in productVariantAttributeIds) + if (attributes != null) { - ProductVariantAttribute pva = null; + var ids = new List(); + var result = new List(); - if (attributes != null) - pva = attributes.FirstOrDefault(x => x.Id == id); + foreach (var id in productVariantAttributeIds) + { + var pva = attributes.FirstOrDefault(x => x.Id == id); + if (pva == null) + ids.Add(id); + else + result.Add(pva); + } - if (pva == null) - pva = GetProductVariantAttributeById(id); + var newLoadedMappings = GetSwitchedLoadedAttributeMappings(ids); - if (pva != null) - result.Add(pva); + result.AddRange(newLoadedMappings); + + return result; } + + return GetSwitchedLoadedAttributeMappings(productVariantAttributeIds.ToList()); } - return result; + return new List(); } public virtual IEnumerable GetProductVariantAttributeValuesByIds(params int[] productVariantAttributeValueIds) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 49c2a5a928..2a973ca37d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -4280,7 +4280,7 @@ public ActionResult AttributeCombinationCreatePopup(string btnId, string formId, warnings.AddRange(_shoppingCartService.GetShoppingCartItemAttributeWarnings(_workContext.CurrentCustomer, ShoppingCartType.ShoppingCart, product, attributeXml)); - if (null != _productAttributeParser.FindProductVariantAttributeCombination(product, attributeXml, variantAttributes)) + if (null != _productAttributeParser.FindProductVariantAttributeCombination(product, attributeXml)) { warnings.Add(_localizationService.GetResource("Admin.Catalog.Products.ProductVariantAttributes.AttributeCombinations.CombiExists")); } @@ -4411,7 +4411,7 @@ public ActionResult CombinationExistenceNote(int productId, FormCollection form) string attributeXml = form.CreateSelectedAttributesXml(productId, attributes, _productAttributeParser, _localizationService, _downloadService, _catalogSettings, this.Request, warnings, false); - bool exists = (null != _productAttributeParser.FindProductVariantAttributeCombination(productId, attributeXml, attributes)); + bool exists = (null != _productAttributeParser.FindProductVariantAttributeCombination(productId, attributeXml)); if (!exists) { diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index 4fe5dcaa57..8d70852acd 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -443,9 +443,7 @@ public ProductDetailsModel PrepareProductDetailModel( { foreach (var attribute in variantAttributes) { - int preSelectedValueId = 0; - - var pvaModel = new ProductDetailsModel.ProductVariantAttributeModel() + var pvaModel = new ProductDetailsModel.ProductVariantAttributeModel { Id = attribute.Id, ProductId = attribute.ProductId, @@ -470,76 +468,74 @@ public ProductDetailsModel PrepareProductDetailModel( } } - if (attribute.ShouldHaveValues()) - { - var pvaValues = _productAttributeService.GetProductVariantAttributeValues(attribute.Id); + int preSelectedValueId = 0; + var pvaValues = (attribute.ShouldHaveValues() ? _productAttributeService.GetProductVariantAttributeValues(attribute.Id) : new List()); - foreach (var pvaValue in pvaValues) - { - ProductBundleItemAttributeFilter attributeFilter = null; + foreach (var pvaValue in pvaValues) + { + ProductBundleItemAttributeFilter attributeFilter = null; - if (productBundleItem.FilterOut(pvaValue, out attributeFilter)) - continue; + if (productBundleItem.FilterOut(pvaValue, out attributeFilter)) + continue; - if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected) - preSelectedValueId = attributeFilter.AttributeValueId; + if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected) + preSelectedValueId = attributeFilter.AttributeValueId; - var linkedProduct = _productService.GetProductById(pvaValue.LinkedProductId); + var linkedProduct = _productService.GetProductById(pvaValue.LinkedProductId); - var pvaValueModel = new ProductDetailsModel.ProductVariantAttributeValueModel(); - pvaValueModel.Id = pvaValue.Id; - pvaValueModel.Name = pvaValue.GetLocalized(x => x.Name); - pvaValueModel.Alias = pvaValue.Alias; - pvaValueModel.ColorSquaresRgb = pvaValue.ColorSquaresRgb; //used with "Color squares" attribute type - pvaValueModel.IsPreSelected = pvaValue.IsPreSelected; + var pvaValueModel = new ProductDetailsModel.ProductVariantAttributeValueModel(); + pvaValueModel.Id = pvaValue.Id; + pvaValueModel.Name = pvaValue.GetLocalized(x => x.Name); + pvaValueModel.Alias = pvaValue.Alias; + pvaValueModel.ColorSquaresRgb = pvaValue.ColorSquaresRgb; //used with "Color squares" attribute type + pvaValueModel.IsPreSelected = pvaValue.IsPreSelected; - if (linkedProduct != null && linkedProduct.VisibleIndividually) - pvaValueModel.SeName = linkedProduct.GetSeName(); + if (linkedProduct != null && linkedProduct.VisibleIndividually) + pvaValueModel.SeName = linkedProduct.GetSeName(); - if (hasSelectedAttributes) - pvaValueModel.IsPreSelected = false; // explicitly selected always discards pre-selected by merchant + if (hasSelectedAttributes) + pvaValueModel.IsPreSelected = false; // explicitly selected always discards pre-selected by merchant - // display price if allowed - if (displayPrices && !isBundlePricing) - { - decimal taxRate = decimal.Zero; - decimal attributeValuePriceAdjustment = _priceCalculationService.GetProductVariantAttributeValuePriceAdjustment(pvaValue); - decimal priceAdjustmentBase = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, out taxRate); - decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _services.WorkContext.WorkingCurrency); - - if (priceAdjustmentBase > decimal.Zero) - pvaValueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment, true, false); - else if (priceAdjustmentBase < decimal.Zero) - pvaValueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment, true, false); - - if (pvaValueModel.IsPreSelected) - { - preSelectedPriceAdjustmentBase = decimal.Add(preSelectedPriceAdjustmentBase, priceAdjustmentBase); - preSelectedWeightAdjustment = decimal.Add(preSelectedWeightAdjustment, pvaValue.WeightAdjustment); - } + // display price if allowed + if (displayPrices && !isBundlePricing) + { + decimal taxRate = decimal.Zero; + decimal attributeValuePriceAdjustment = _priceCalculationService.GetProductVariantAttributeValuePriceAdjustment(pvaValue); + decimal priceAdjustmentBase = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, out taxRate); + decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _services.WorkContext.WorkingCurrency); - if (_catalogSettings.ShowLinkedAttributeValueQuantity && pvaValue.ValueType == ProductVariantAttributeValueType.ProductLinkage) - { - pvaValueModel.QuantityInfo = pvaValue.Quantity; - } + if (priceAdjustmentBase > decimal.Zero) + pvaValueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment, true, false); + else if (priceAdjustmentBase < decimal.Zero) + pvaValueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment, true, false); - pvaValueModel.PriceAdjustmentValue = priceAdjustment; - } - - if (!_catalogSettings.ShowVariantCombinationPriceAdjustment) + if (pvaValueModel.IsPreSelected) { - pvaValueModel.PriceAdjustment = ""; + preSelectedPriceAdjustmentBase = decimal.Add(preSelectedPriceAdjustmentBase, priceAdjustmentBase); + preSelectedWeightAdjustment = decimal.Add(preSelectedWeightAdjustment, pvaValue.WeightAdjustment); } - if (_catalogSettings.ShowLinkedAttributeValueImage && pvaValue.ValueType == ProductVariantAttributeValueType.ProductLinkage) + if (_catalogSettings.ShowLinkedAttributeValueQuantity && pvaValue.ValueType == ProductVariantAttributeValueType.ProductLinkage) { - var linkagePicture = _pictureService.GetPicturesByProductId(pvaValue.LinkedProductId, 1).FirstOrDefault(); - if (linkagePicture != null) - pvaValueModel.ImageUrl = _pictureService.GetPictureUrl(linkagePicture, _mediaSettings.AutoCompleteSearchThumbPictureSize, false); + pvaValueModel.QuantityInfo = pvaValue.Quantity; } - pvaModel.Values.Add(pvaValueModel); + pvaValueModel.PriceAdjustmentValue = priceAdjustment; + } + + if (!_catalogSettings.ShowVariantCombinationPriceAdjustment) + { + pvaValueModel.PriceAdjustment = ""; + } + + if (_catalogSettings.ShowLinkedAttributeValueImage && pvaValue.ValueType == ProductVariantAttributeValueType.ProductLinkage) + { + var linkagePicture = _pictureService.GetPicturesByProductId(pvaValue.LinkedProductId, 1).FirstOrDefault(); + if (linkagePicture != null) + pvaValueModel.ImageUrl = _pictureService.GetPictureUrl(linkagePicture, _mediaSettings.AutoCompleteSearchThumbPictureSize, false); } + + pvaModel.Values.Add(pvaValueModel); } // we need selected attributes to get initially displayed combination images @@ -552,14 +548,25 @@ public ProductDetailsModel PrepareProductDetailModel( pvaModel.Values.Each(x => x.IsPreSelected = false); if ((defaultValue = pvaModel.Values.FirstOrDefault(v => v.Id == preSelectedValueId)) != null) + { defaultValue.IsPreSelected = true; + selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId); + } } if (defaultValue == null) - defaultValue = pvaModel.Values.FirstOrDefault(v => v.IsPreSelected); + { + foreach (var value in pvaModel.Values.Where(x => x.IsPreSelected)) + { + selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, value.Id, product.Id, bundleItemId); + } + } + + //if (defaultValue == null) + // defaultValue = pvaModel.Values.FirstOrDefault(v => v.IsPreSelected); - if (defaultValue != null) - selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId); + //if (defaultValue != null) + // selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId); } model.ProductVariantAttributes.Add(pvaModel); From 474d6a037864c783b32a7d18fc055553f82d62fb Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 25 Jul 2015 20:49:55 +0200 Subject: [PATCH 0122/1074] Updated changelog --- changelog.md | 2 ++ .../Extensions/NameValueCollectionExtensions.cs | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index d3059c982a..f1153fdf11 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ * #731 Web-API: Allow deletion and inserting of product category and manufacturer assignments * #733 Option to set a display order for homepage products * #607 HTML capable full description for payment methods displayed in checkout +* #732 Product list: Option to display the pre-selected price instead of the lowest price ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. @@ -30,6 +31,7 @@ ### Bugfixes * #523 Redirecting to payment provider performed by core instead of plugin +* Preselected price was wrong for product attributes with multiple preselected values (same on product detail page) ## SmartStore.NET 2.2.2 diff --git a/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs b/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs index d4846ddf04..68d8f8dda6 100644 --- a/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs +++ b/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs @@ -67,9 +67,6 @@ public static string CreateSelectedAttributesXml(this NameValueCollection collec HttpRequestBase request, List warnings, bool formatWithProductId = true, int bundleItemId = 0) - public static string CreateSelectedAttributesXml(this NameValueCollection collection, int productId, IEnumerable variantAttributes, - IProductAttributeParser productAttributeParser, ILocalizationService localizationService, IDownloadService downloadService, CatalogSettings catalogSettings, - HttpRequestBase request, List warnings, bool formatWithProductId = true, int bundleItemId = 0) { if (collection == null) return ""; From 0afb4e7fb47cadb40c6aaa94d6d7a4b660e2cf45 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sun, 26 Jul 2015 18:04:06 +0200 Subject: [PATCH 0123/1074] Reduce database round trips initiated by price calculation --- .../Collections/LazyMultimap.cs | 85 +++++++--- .../SmartStore.Core/Domain/Catalog/Product.cs | 2 +- .../Catalog/IPriceCalculationService.cs | 30 ++-- .../Catalog/IProductService.cs | 11 ++ .../Catalog/PriceCalculationContext.cs | 84 +++++++++- .../Catalog/PriceCalculationService.cs | 148 ++++++++---------- .../Catalog/ProductService.cs | 28 ++++ .../Controllers/OData/ProductsController.cs | 2 +- .../Controllers/CatalogHelper.cs | 102 ++++++------ 9 files changed, 312 insertions(+), 180 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs b/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs index e3c4ea8d35..803ff63ded 100644 --- a/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs +++ b/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs @@ -6,28 +6,72 @@ namespace SmartStore.Collections { /// - /// Structure that combines early and lazy data loading + /// Structure that manages data keys and offers the combination of early and lazy data loading /// public class LazyMultimap : Multimap { private Func> _load; - private List _loaded; // to avoid database rountrips with empty results + private List _loaded; // to avoid database round trips with empty results + private List _collect; + private int _roundTripCount; - public LazyMultimap(Func> load, IEnumerable initial = null) + /// + /// Constructor + /// + /// int[] keys like Entity.Id, Multimap> delegate to load data + /// Keys of early loaded data + public LazyMultimap(Func> load, IEnumerable collect = null) { _load = load; _loaded = new List(); - Load(initial); + if (collect == null) + _collect = new List(); + else + _collect = new List(collect); } - public virtual ICollection Ensure(int key) + protected virtual void Load(IEnumerable keys) { - if (!_loaded.Contains(key)) + if (keys != null) { - if (typeof(T).Name == "ProductVariantAttribute") - "lazy load {0}".FormatInvariant(key).Dump(); + var loadKeys = (_collect.Count == 0 ? keys : _collect.Concat(keys)) + .Distinct() + .Except(_loaded) + .ToArray(); + + _collect.Clear(); // invalidate, do not load again + + if (loadKeys.Any()) + { + ++_roundTripCount; + + Debug.WriteLine("Round trip {0} of {1}: {2}", _roundTripCount, typeof(T).Name, string.Join(",", loadKeys.OrderBy(x => x))); + + var items = _load(loadKeys); + + _loaded.AddRange(loadKeys); + + if (items != null) + { + foreach (var range in items) + { + base.AddRange(range.Key, range.Value); + } + } + } + } + } + /// + /// Get data. Load it if not already loaded yet. + /// + /// Data key + /// Collection of data + public virtual ICollection Load(int key) + { + if (!_loaded.Contains(key)) + { Load(new int[] { key }); } @@ -39,26 +83,15 @@ public virtual ICollection Ensure(int key) return result; } - protected virtual void Load(IEnumerable keys) + /// + /// Collect keys for combined loading + /// + /// Data keys + public virtual void Collect(IEnumerable keys) { - if (keys != null) + if (keys != null && keys.Any()) { - var loadKeys = keys.Distinct().Except(_loaded).ToArray(); - - if (loadKeys.Any()) - { - var items = _load(loadKeys); - - //if (typeof(T).Name == "ProductVariantAttribute") - // "call load {0}".FormatInvariant(string.Join(";", loadKeys)).Dump(); - - _loaded.AddRange(loadKeys); - - foreach (var range in items) - { - base.AddRange(range.Key, range.Value); - } - } + _collect = _collect.Union(keys).ToList(); } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs index 1d142e5e09..a815e7d4b8 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs @@ -565,7 +565,7 @@ public decimal Price /// Gets or sets a value indicating whether this product has tier prices configured /// The same as if we run this.TierPrices.Count > 0 /// We use this property for performance optimization: - /// if this property is set to false, then we do not need to load tier prices navifation property + /// if this property is set to false, then we do not need to load tier prices navigation property /// /// [DataMember] diff --git a/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs index 3ae7d2bb7e..090a301e8d 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs @@ -14,9 +14,9 @@ public partial interface IPriceCalculationService /// /// Creates a price calculation context /// - /// Product identifieres. null to lazy load data if required. - /// - PriceCalculationContext CreatePriceCalculationContext(IEnumerable productIds = null); + /// Products. null to lazy load data if required. + /// Price calculation context + PriceCalculationContext CreatePriceCalculationContext(IEnumerable products = null); /// /// Get product special price (is valid) @@ -66,13 +66,15 @@ decimal GetFinalPrice(Product product, /// A value indicating whether include discounts or not for final price computation /// Shopping cart item quantity /// A product bundle item + /// Object with cargo data for better performance /// Final price decimal GetFinalPrice(Product product, Customer customer, decimal additionalCharge, bool includeDiscounts, int quantity, - ProductBundleItemData bundleItem = null); + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null); /// /// Gets the final price including bundle per-item pricing @@ -84,9 +86,16 @@ decimal GetFinalPrice(Product product, /// A value indicating whether include discounts or not for final price computation /// Shopping cart item quantity /// A product bundle item + /// Object with cargo data for better performance /// Final price - decimal GetFinalPrice(Product product, IEnumerable bundleItems, - Customer customer, decimal additionalCharge, bool includeDiscounts, int quantity, ProductBundleItemData bundleItem = null); + decimal GetFinalPrice(Product product, + IEnumerable bundleItems, + Customer customer, + decimal additionalCharge, + bool includeDiscounts, + int quantity, + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null); /// /// Get the lowest possible price for a product. @@ -100,11 +109,12 @@ decimal GetFinalPrice(Product product, IEnumerable bundle /// /// Get the lowest price of a grouped product. /// - /// Grouped product. - /// Products associated to product. - /// The associated product with the lowest price. + /// Grouped product + /// Object with cargo data for better performance + /// Products associated to product + /// The associated product with the lowest price /// The lowest price. - decimal? GetLowestPrice(Product product, IEnumerable associatedProducts, out Product lowestPriceProduct); + decimal? GetLowestPrice(Product product, PriceCalculationContext context, IEnumerable associatedProducts, out Product lowestPriceProduct); /// /// Get the initial price including preselected attributes diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductService.cs index e080a437b5..2ae693aa22 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductService.cs @@ -3,8 +3,10 @@ using System.Linq; using System.Linq.Expressions; using System.Web.Mvc; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; using SmartStore.Utilities; @@ -273,6 +275,15 @@ public partial interface IProductService /// Tier price TierPrice GetTierPriceById(int tierPriceId); + /// + /// Gets tier prices by product identifiers + /// + /// Product identifiers + /// Filter tier prices by customer + /// Filter tier prices by store + /// Map of tier prices + Multimap GetTierPrices(int[] productIds, Customer customer = null, int storeId = 0); + /// /// Inserts a tier price /// diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs index 41f5025c95..0f594e6fdc 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs @@ -1,11 +1,89 @@ -using SmartStore.Collections; +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; using SmartStore.Core.Domain.Catalog; namespace SmartStore.Services.Catalog { + /// + /// Cargo data to reduce database round trips during price calculation + /// public class PriceCalculationContext { - public LazyMultimap Attributes { get; set; } - public LazyMultimap AttributeCombinations { get; set; } + private List _productIds; + private List _productIdsTierPrices; + + private Func> _funcAttributes; + private Func> _funcAttributeCombinations; + private Func> _funcTierPrices; + + private LazyMultimap _attributes; + private LazyMultimap _attributeCombinations; + private LazyMultimap _tierPrices; + + public PriceCalculationContext(IEnumerable products, + Func> attributes, + Func> attributeCombinations, + Func> tierPrices) + { + if (products == null) + { + _productIds = new List(); + _productIdsTierPrices = new List(); + } + else + { + _productIds = new List(products.Select(x => x.Id)); + _productIdsTierPrices = new List(products.Where(x => x.HasTierPrices).Select(x => x.Id)); + } + + _funcAttributes = attributes; + _funcAttributeCombinations = attributeCombinations; + _funcTierPrices = tierPrices; + } + + public LazyMultimap Attributes + { + get + { + if (_attributes == null) + { + _attributes = new LazyMultimap(keys => _funcAttributes(keys), _productIds); + } + return _attributes; + } + } + + public LazyMultimap AttributeCombinations + { + get + { + if (_attributeCombinations == null) + { + _attributeCombinations = new LazyMultimap(keys => _funcAttributeCombinations(keys), _productIds); + } + return _attributeCombinations; + } + } + + public LazyMultimap TierPrices + { + get + { + if (_tierPrices == null) + { + _tierPrices = new LazyMultimap(keys => _funcTierPrices(keys), _productIdsTierPrices); + } + return _tierPrices; + } + } + + public void Collect(IEnumerable productIds) + { + Attributes.Collect(productIds); + AttributeCombinations.Collect(productIds); + TierPrices.Collect(productIds); + } } } diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index a343b360be..aaa8825d56 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -123,20 +123,33 @@ protected virtual IList GetAllowedDiscounts(Product product, Customer /// Customer /// Quantity /// Price - protected virtual decimal? GetMinimumTierPrice(Product product, Customer customer, int quantity) + protected virtual decimal? GetMinimumTierPrice(Product product, Customer customer, int quantity, PriceCalculationContext context = null) { if (!product.HasTierPrices) return decimal.Zero; - var tierPrices = product.TierPrices - .OrderBy(tp => tp.Quantity) - .FilterByStore(_services.StoreContext.CurrentStore.Id) - .FilterForCustomer(customer) - .ToList() - .RemoveDuplicatedQuantities(); + IEnumerable tierPrices = null; + + if (context == null) + { + tierPrices = product.TierPrices + .OrderBy(tp => tp.Quantity) + .FilterByStore(_services.StoreContext.CurrentStore.Id) + .FilterForCustomer(customer) + .ToList() + .RemoveDuplicatedQuantities(); + } + else + { + tierPrices = context.TierPrices.Load(product.Id); + } + + if (tierPrices == null) + return decimal.Zero; int previousQty = 1; decimal? previousPrice = null; + foreach (var tierPrice in tierPrices) { //check quantity @@ -165,7 +178,7 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC var selectedAttributes = new NameValueCollection(); var selectedAttributeValues = new List(); - var attributes = context.Attributes.Ensure(product.Id); + var attributes = context.Attributes.Load(product.Id); // 1. fill selectedAttributes with initially selected attributes foreach (var attribute in attributes.Where(x => x.ProductVariantAttributeValues.Count > 0 && x.ShouldHaveValues())) @@ -226,7 +239,7 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC string attributeXml = selectedAttributes.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _services.Localization, _downloadService, _catalogSettings, _httpRequestBase, new List(), true, bundleItemId); - var combinations = context.AttributeCombinations.Ensure(product.Id); + var combinations = context.AttributeCombinations.Load(product.Id); var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml, attributes)); @@ -253,33 +266,17 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC bundleItem.AdditionalCharge = attributesTotalPriceBase; } - var result = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, attributesTotalPriceBase, true, 1, bundleItem); + var result = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, attributesTotalPriceBase, true, 1, bundleItem, context); return result; } - public virtual PriceCalculationContext CreatePriceCalculationContext(IEnumerable productIds = null) + public virtual PriceCalculationContext CreatePriceCalculationContext(IEnumerable products = null) { - var context = new PriceCalculationContext(); - - if (_catalogSettings.PriceDisplayType == PriceDisplayType.Hide || _catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes) - return context; - - context.Attributes = new LazyMultimap(x => - { - "load {0}".FormatInvariant(string.Join(";", x)).Dump(); - - var result = _productAttributeService.GetProductVariantAttributesByProductIds(x, null); - return result; - }, productIds); - - if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice) - { - context.AttributeCombinations = new LazyMultimap(x => - { - var result = _productAttributeService.GetProductVariantAttributeCombinations(x); - return result; - }, productIds); - } + var context = new PriceCalculationContext(products, + x => _productAttributeService.GetProductVariantAttributesByProductIds(x, null), + x => _productAttributeService.GetProductVariantAttributeCombinations(x), + x => _productService.GetTierPrices(x, _services.WorkContext.CurrentCustomer, _services.StoreContext.CurrentStore.Id) + ); return context; } @@ -362,23 +359,14 @@ public virtual decimal GetFinalPrice(Product product, return GetFinalPrice(product, customer, additionalCharge, includeDiscounts, 1); } - /// - /// Gets the final price - /// - /// Product - /// The customer - /// Additional charge - /// A value indicating whether include discounts or not for final price computation - /// Shopping cart item quantity - /// A product bundle item - /// Final price public virtual decimal GetFinalPrice( Product product, Customer customer, decimal additionalCharge, bool includeDiscounts, int quantity, - ProductBundleItemData bundleItem = null) + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null) { //initial price decimal result = product.Price; @@ -391,7 +379,7 @@ public virtual decimal GetFinalPrice( //tier prices if (product.HasTierPrices && !bundleItem.IsValid()) { - decimal? tierPrice = GetMinimumTierPrice(product, customer, quantity); + decimal? tierPrice = GetMinimumTierPrice(product, customer, quantity, context); if (tierPrice.HasValue) result = Math.Min(result, tierPrice.Value); } @@ -407,22 +395,13 @@ public virtual decimal GetFinalPrice( { result = result + additionalCharge; } + if (result < decimal.Zero) result = decimal.Zero; + return result; } - /// - /// Gets the final price including bundle per-item pricing - /// - /// Product - /// Bundle items - /// The customer - /// Additional charge - /// A value indicating whether include discounts or not for final price computation - /// Shopping cart item quantity - /// A product bundle item - /// Final price public virtual decimal GetFinalPrice( Product product, IEnumerable bundleItems, @@ -430,7 +409,8 @@ public virtual decimal GetFinalPrice( decimal additionalCharge, bool includeDiscounts, int quantity, - ProductBundleItemData bundleItem = null) + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null) { if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing) { @@ -439,14 +419,14 @@ public virtual decimal GetFinalPrice( foreach (var itemData in items.Where(x => x.IsValid())) { - decimal itemPrice = GetFinalPrice(itemData.Item.Product, customer, itemData.AdditionalCharge, includeDiscounts, 1, itemData); + decimal itemPrice = GetFinalPrice(itemData.Item.Product, customer, itemData.AdditionalCharge, includeDiscounts, 1, itemData, context); result = result + decimal.Multiply(itemPrice, itemData.Item.Quantity); } return (result < decimal.Zero ? decimal.Zero : result); } - return GetFinalPrice(product, customer, additionalCharge, includeDiscounts, quantity, bundleItem); + return GetFinalPrice(product, customer, additionalCharge, includeDiscounts, quantity, bundleItem, context); } /// @@ -465,7 +445,7 @@ public virtual decimal GetLowestPrice(Product product, PriceCalculationContext c throw Error.InvalidOperation("Choose the other override for products of type grouped product."); if (context == null) - context = CreatePriceCalculationContext(null); + context = CreatePriceCalculationContext(); bool isBundlePerItemPricing = (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing); @@ -473,7 +453,7 @@ public virtual decimal GetLowestPrice(Product product, PriceCalculationContext c // TODO(?): attribute price adjustments were not regarded here cause of performance - decimal lowestPrice = GetFinalPrice(product, null, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); + decimal lowestPrice = GetFinalPrice(product, null, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue, null, context); if (product.LowestAttributeCombinationPrice.HasValue && product.LowestAttributeCombinationPrice.Value < lowestPrice) { @@ -488,18 +468,20 @@ public virtual decimal GetLowestPrice(Product product, PriceCalculationContext c if (!displayFromMessage && product.ProductType != ProductType.BundledProduct) { - var attributes = context.Attributes.Ensure(product.Id); + var attributes = context.Attributes.Load(product.Id); displayFromMessage = attributes.Any(x => x.ProductVariantAttributeValues.Any(y => y.PriceAdjustment != decimal.Zero)); } if (!displayFromMessage && product.HasTierPrices && !isBundlePerItemPricing) { - var tierPrices = product.TierPrices - .OrderBy(tp => tp.Quantity) - .FilterByStore(_services.StoreContext.CurrentStore.Id) - .FilterForCustomer(_services.WorkContext.CurrentCustomer) - .ToList() - .RemoveDuplicatedQuantities(); + //var tierPrices = product.TierPrices + // .OrderBy(tp => tp.Quantity) + // .FilterByStore(_services.StoreContext.CurrentStore.Id) + // .FilterForCustomer(_services.WorkContext.CurrentCustomer) + // .ToList() + // .RemoveDuplicatedQuantities(); + + var tierPrices = context.TierPrices.Load(product.Id); displayFromMessage = (tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices.First().Quantity <= 1)); } @@ -507,14 +489,7 @@ public virtual decimal GetLowestPrice(Product product, PriceCalculationContext c return lowestPrice; } - /// - /// Get the lowest price of a grouped product. - /// - /// Grouped product. - /// Products associated to product. - /// The associated product with the lowest price. - /// The lowest price. - public virtual decimal? GetLowestPrice(Product product, IEnumerable associatedProducts, out Product lowestPriceProduct) + public virtual decimal? GetLowestPrice(Product product, PriceCalculationContext context, IEnumerable associatedProducts, out Product lowestPriceProduct) { if (product == null) throw new ArgumentNullException("product"); @@ -527,10 +502,14 @@ public virtual decimal GetLowestPrice(Product product, PriceCalculationContext c lowestPriceProduct = null; decimal? lowestPrice = null; + var customer = _services.WorkContext.CurrentCustomer; + + if (context == null) + context = CreatePriceCalculationContext(); foreach (var associatedProduct in associatedProducts) { - var tmpPrice = GetFinalPrice(associatedProduct, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); + var tmpPrice = GetFinalPrice(associatedProduct, customer, decimal.Zero, true, int.MaxValue, null, context); if (associatedProduct.LowestAttributeCombinationPrice.HasValue && associatedProduct.LowestAttributeCombinationPrice.Value < tmpPrice) { @@ -563,27 +542,28 @@ public virtual decimal GetPreselectedPrice(Product product, PriceCalculationCont var result = decimal.Zero; + if (context == null) + context = CreatePriceCalculationContext(); + if (product.ProductType == ProductType.BundledProduct) { var bundleItems = _productService.GetBundleItems(product.Id); - var ids = bundleItems.Select(x => x.Item.ProductId).ToList(); - ids.Add(product.Id); - var bundleContext = CreatePriceCalculationContext(ids); + var productIds = bundleItems.Select(x => x.Item.ProductId).ToList(); + productIds.Add(product.Id); + + context.Collect(productIds); foreach (var bundleItem in bundleItems.Where(x => x.Item.Product.CanBeBundleItem())) { // fetch bundleItems.AdditionalCharge for all bundle items - var unused = GetPreselectedPrice(bundleItem.Item.Product, bundleContext, bundleItem, bundleItems); + var unused = GetPreselectedPrice(bundleItem.Item.Product, context, bundleItem, bundleItems); } - result = GetPreselectedPrice(product, bundleContext, null, bundleItems); + result = GetPreselectedPrice(product, context, null, bundleItems); } else { - if (context == null) - context = CreatePriceCalculationContext(null); - result = GetPreselectedPrice(product, context, null, null); } diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs index efc889d9f4..fd762a1f2b 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs @@ -5,11 +5,13 @@ using System.Linq.Expressions; using System.ServiceModel.Syndication; using System.Web.Mvc; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Orders; @@ -1639,6 +1641,32 @@ public virtual TierPrice GetTierPriceById(int tierPriceId) return tierPrice; } + public virtual Multimap GetTierPrices(int[] productIds, Customer customer = null, int storeId = 0) + { + Guard.ArgumentNotNull(() => productIds); + + var query = + from x in _tierPriceRepository.TableUntracked + where productIds.Contains(x.ProductId) + select x; + + if (storeId != 0) + query = query.Where(x => x.StoreId == 0 || x.StoreId == storeId); + + query = query.OrderBy(x => x.ProductId).ThenBy(x => x.Quantity); + + var list = query.ToList(); + + if (customer != null) + list = list.FilterForCustomer(customer).ToList(); + + var map = list + .RemoveDuplicatedQuantities() + .ToMultimap(x => x.ProductId, x => x); + + return map; + } + /// /// Inserts a tier price /// diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs index aec30f45cd..232a326378 100644 --- a/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs @@ -261,7 +261,7 @@ public IQueryable GetProductBundleItems(int key) Product lowestPriceProduct; var associatedProducts = Service.PrepareProductSearchQuery(searchContext); - result = _priceCalculationService.Value.GetLowestPrice(entity, associatedProducts, out lowestPriceProduct); + result = _priceCalculationService.Value.GetLowestPrice(entity, null, associatedProducts, out lowestPriceProduct); } else { diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index 8d70852acd..2c1ec945ce 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -1002,7 +1002,6 @@ public IEnumerable PrepareProductOverviewModels( string taxInfo = T(taxDisplayType == TaxDisplayType.IncludingTax ? "Tax.InclVAT" : "Tax.ExclVAT"); string shippingInfoLink = _urlHelper.RouteUrl("Topic", new { SystemName = "shippinginfo" }); var cachedManufacturerModels = new Dictionary(); - PriceCalculationContext priceCalculationContext = null; var res = new Dictionary(StringComparer.OrdinalIgnoreCase) { @@ -1015,7 +1014,7 @@ public IEnumerable PrepareProductOverviewModels( { "Common.AdditionalShippingSurcharge", T("Common.AdditionalShippingSurcharge") } }; - int[] productIds = products.Select(x => x.Id).ToArray(); + var cargoData = _priceCalculationService.CreatePriceCalculationContext(products); var models = new List(); @@ -1036,9 +1035,6 @@ public IEnumerable PrepareProductOverviewModels( { #region Prepare product price - if (priceCalculationContext == null) - priceCalculationContext = _priceCalculationService.CreatePriceCalculationContext(productIds); - var priceModel = new ProductOverviewModel.ProductPriceModel { ForceRedirectionAfterAddingToCart = forceRedirectionAfterAddingToCart, @@ -1057,7 +1053,7 @@ public IEnumerable PrepareProductOverviewModels( { StoreId = currentStore.Id, ParentGroupedProductId = product.Id, - PageSize = (_catalogSettings.PriceDisplayType == PriceDisplayType.LowestPrice ? int.MaxValue : 1), + PageSize = int.MaxValue, VisibleIndividuallyOnly = false }; @@ -1065,23 +1061,25 @@ public IEnumerable PrepareProductOverviewModels( if (associatedProducts.Count > 0) { - contextProduct = associatedProducts.First(); + contextProduct = associatedProducts.OrderBy(x => x.DisplayOrder).First(); if (displayPrices && _catalogSettings.PriceDisplayType != PriceDisplayType.Hide) { decimal? displayPrice = null; + bool displayFromMessage = false; if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice) { - displayPrice = _priceCalculationService.GetPreselectedPrice(contextProduct, null); + displayPrice = _priceCalculationService.GetPreselectedPrice(contextProduct, cargoData); } else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes) { - displayPrice = _priceCalculationService.GetFinalPrice(contextProduct, null, currentCustomer, decimal.Zero, false, 1, null); + displayPrice = _priceCalculationService.GetFinalPrice(contextProduct, null, currentCustomer, decimal.Zero, false, 1, null, cargoData); } else { - displayPrice = _priceCalculationService.GetLowestPrice(product, associatedProducts, out contextProduct); + displayFromMessage = true; + displayPrice = _priceCalculationService.GetLowestPrice(product, cargoData, associatedProducts, out contextProduct); } if (contextProduct != null && !contextProduct.CustomerEntersPrice) @@ -1100,8 +1098,13 @@ public IEnumerable PrepareProductOverviewModels( decimal finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, workingCurrency); priceModel.OldPrice = null; - priceModel.Price = String.Format(res["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice)); - priceModel.HasDiscount = finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero; + + if (displayFromMessage) + priceModel.Price = String.Format(res["Products.PriceRangeFrom"], _priceFormatter.FormatPrice(finalPrice)); + else + priceModel.Price = _priceFormatter.FormatPrice(finalPrice); + + priceModel.HasDiscount = (finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero); } else { @@ -1144,15 +1147,15 @@ public IEnumerable PrepareProductOverviewModels( if (_catalogSettings.PriceDisplayType == PriceDisplayType.PreSelectedPrice) { - displayPrice = _priceCalculationService.GetPreselectedPrice(product, priceCalculationContext); + displayPrice = _priceCalculationService.GetPreselectedPrice(product, cargoData); } else if (_catalogSettings.PriceDisplayType == PriceDisplayType.PriceWithoutDiscountsAndAttributes) { - displayPrice = _priceCalculationService.GetFinalPrice(product, null, currentCustomer, decimal.Zero, false, 1, null); + displayPrice = _priceCalculationService.GetFinalPrice(product, null, currentCustomer, decimal.Zero, false, 1, null, cargoData); } else { - displayPrice = _priceCalculationService.GetLowestPrice(product, priceCalculationContext, out displayFromMessage); + displayPrice = _priceCalculationService.GetLowestPrice(product, cargoData, out displayFromMessage); } decimal taxRate = decimal.Zero; @@ -1194,6 +1197,35 @@ public IEnumerable PrepareProductOverviewModels( #endregion } + // color squares + if (prepareColorAttributes && _catalogSettings.ShowColorSquaresInLists) + { + #region Prepare color attributes + + var attributes = cargoData.Attributes.Load(contextProduct.Id); + var colorAttribute = attributes.FirstOrDefault(x => x.AttributeControlType == AttributeControlType.ColorSquares); + + if (colorAttribute != null) + { + var colorValues = + from a in colorAttribute.ProductVariantAttributeValues.Take(50) + where (a.ColorSquaresRgb.HasValue() && !a.ColorSquaresRgb.IsCaseInsensitiveEqual("transparent")) + select new ProductOverviewModel.ColorAttributeModel + { + Color = a.ColorSquaresRgb, + Alias = a.Alias, + FriendlyName = a.GetLocalized(l => l.Name) + }; + + if (colorValues.Any()) + { + model.ColorAttributes.AddRange(colorValues.Distinct()); + } + } + + #endregion + } + // picture if (preparePictureModel) { @@ -1297,46 +1329,6 @@ public IEnumerable PrepareProductOverviewModels( models.Add(model); } - // Color squares - // Perf: Loading all applicable attributes in one go is definitely faster - // than fetching them one by one withing the above loop. - if (prepareColorAttributes && _catalogSettings.ShowColorSquaresInLists) - { - #region Prepare color attributes - - var minPriceProductIds = models.Select(x => x.MinPriceProductId).ToArray(); - var allAttrs = _productAttributeService.GetProductVariantAttributesByProductIds(minPriceProductIds, AttributeControlType.ColorSquares); - - foreach (var model in models) - { - if (!allAttrs.ContainsKey(model.MinPriceProductId)) - continue; - - // get the FIRST color type attribute - ProductVariantAttribute colorAttr = allAttrs[model.MinPriceProductId].FirstOrDefault(x => x.AttributeControlType == AttributeControlType.ColorSquares); - - if (colorAttr != null) - { - var colorValues = - from a in colorAttr.ProductVariantAttributeValues.Take(50) - where (a.ColorSquaresRgb.HasValue() && !a.ColorSquaresRgb.IsCaseInsensitiveEqual("transparent")) - select new ProductOverviewModel.ColorAttributeModel - { - Color = a.ColorSquaresRgb, - Alias = a.Alias, - FriendlyName = a.GetLocalized(l => l.Name) - }; - - if (colorValues.Any()) - { - model.ColorAttributes.AddRange(colorValues.Distinct()); - } - } - } - - #endregion - } - return models; } From cea2e962979d3d7d27b0ee435af29d960f4f7f67 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 27 Jul 2015 10:47:11 +0200 Subject: [PATCH 0124/1074] Removed odd extension method --- .../Catalog/PriceCalculationService.cs | 23 ++++++++----------- .../Discounts/DiscountExtentions.cs | 16 ------------- .../Orders/OrderProcessingService.cs | 9 ++++---- .../Orders/OrderTotalCalculationService.cs | 23 +++++++++++-------- 4 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index aaa8825d56..7cff4b8abb 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -67,26 +67,23 @@ public PriceCalculationService( /// Discounts protected virtual IList GetAllowedDiscounts(Product product, Customer customer) { - var allowedDiscounts = new List(); + var result = new List(); if (_catalogSettings.IgnoreDiscounts) - return allowedDiscounts; + return result; if (product.HasDiscountsApplied) { //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls foreach (var discount in product.AppliedDiscounts) { - if (_discountService.IsDiscountValid(discount, customer) && - discount.DiscountType == DiscountType.AssignedToSkus && - !allowedDiscounts.ContainsDiscount(discount)) + if (discount.DiscountType == DiscountType.AssignedToSkus && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer)) { - allowedDiscounts.Add(discount); + result.Add(discount); } } } - //performance optimization - //load all category discounts just to ensure that we have at least one + //performance optimization. load all category discounts just to ensure that we have at least one if (_discountService.GetAllDiscounts(DiscountType.AssignedToCategories).Any()) { var productCategories = _categoryService.GetProductCategoriesByProductId(product.Id); @@ -100,20 +97,20 @@ protected virtual IList GetAllowedDiscounts(Product product, Customer { //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls var categoryDiscounts = category.AppliedDiscounts; + foreach (var discount in categoryDiscounts) { - if (_discountService.IsDiscountValid(discount, customer) && - discount.DiscountType == DiscountType.AssignedToCategories && - !allowedDiscounts.ContainsDiscount(discount)) + if (discount.DiscountType == DiscountType.AssignedToCategories && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer)) { - allowedDiscounts.Add(discount); + result.Add(discount); } } } } } } - return allowedDiscounts; + + return result; } /// diff --git a/src/Libraries/SmartStore.Services/Discounts/DiscountExtentions.cs b/src/Libraries/SmartStore.Services/Discounts/DiscountExtentions.cs index d8c29939db..ccc62d5921 100644 --- a/src/Libraries/SmartStore.Services/Discounts/DiscountExtentions.cs +++ b/src/Libraries/SmartStore.Services/Discounts/DiscountExtentions.cs @@ -29,7 +29,6 @@ public static decimal GetDiscountAmount(this Discount discount, decimal amount) return result; } - public static Discount GetPreferredDiscount(this IList discounts, decimal amount) { @@ -47,20 +46,5 @@ public static Discount GetPreferredDiscount(this IList discounts, deci return preferredDiscount; } - - public static bool ContainsDiscount(this IList discounts, Discount discount) - { - if (discounts == null) - throw new ArgumentNullException("discounts"); - - if (discount == null) - throw new ArgumentNullException("discount"); - - foreach (var dis1 in discounts) - if (discount.Id == dis1.Id) - return true; - - return false; - } } } diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index 54d3a2f8d1..97e13a1ece 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -649,7 +649,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR orderSubTotalDiscountInclTax = orderSubTotalDiscountAmount1; //discount history - if (orderSubTotalAppliedDiscount1 != null && !appliedDiscounts.ContainsDiscount(orderSubTotalAppliedDiscount1)) + if (orderSubTotalAppliedDiscount1 != null && !appliedDiscounts.Any(x => x.Id == orderSubTotalAppliedDiscount1.Id)) appliedDiscounts.Add(orderSubTotalAppliedDiscount1); //sub total (excl tax) @@ -712,7 +712,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR if (!orderShippingTotalInclTax.HasValue || !orderShippingTotalExclTax.HasValue) throw new SmartException("Shipping total couldn't be calculated"); - if (shippingTotalDiscount != null && !appliedDiscounts.ContainsDiscount(shippingTotalDiscount)) + if (shippingTotalDiscount != null && !appliedDiscounts.Any(x => x.Id == shippingTotalDiscount.Id)) appliedDiscounts.Add(shippingTotalDiscount); } else @@ -783,7 +783,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR throw new SmartException("Order total couldn't be calculated"); //discount history - if (orderAppliedDiscount != null && !appliedDiscounts.ContainsDiscount(orderAppliedDiscount)) + if (orderAppliedDiscount != null && !appliedDiscounts.Any(x => x.Id == orderAppliedDiscount.Id)) appliedDiscounts.Add(orderAppliedDiscount); } else @@ -1089,7 +1089,8 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR decimal discountAmount = _priceCalculationService.GetDiscountAmount(sc, out scDiscount); decimal discountAmountInclTax = _taxService.GetProductPrice(sc.Item.Product, discountAmount, true, customer, out taxRate); decimal discountAmountExclTax = _taxService.GetProductPrice(sc.Item.Product, discountAmount, false, customer, out taxRate); - if (scDiscount != null && !appliedDiscounts.ContainsDiscount(scDiscount)) + + if (scDiscount != null && !appliedDiscounts.Any(x => x.Id == scDiscount.Id)) appliedDiscounts.Add(scDiscount); //attributes diff --git a/src/Libraries/SmartStore.Services/Orders/OrderTotalCalculationService.cs b/src/Libraries/SmartStore.Services/Orders/OrderTotalCalculationService.cs index 294db65762..4aef87d01f 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderTotalCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderTotalCalculationService.cs @@ -355,8 +355,7 @@ public virtual decimal GetOrderSubtotalDiscount(Customer customer, { foreach (var discount in allDiscounts) { - if (_discountService.IsDiscountValid(discount, customer) && discount.DiscountType == DiscountType.AssignedToOrderSubTotal && - !allowedDiscounts.ContainsDiscount(discount)) + if (discount.DiscountType == DiscountType.AssignedToOrderSubTotal && !allowedDiscounts.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer)) { allowedDiscounts.Add(discount); } @@ -668,12 +667,17 @@ public virtual decimal GetShippingDiscount(Customer customer, decimal shippingTo var allDiscounts = _discountService.GetAllDiscounts(DiscountType.AssignedToShipping); var allowedDiscounts = new List(); - if (allDiscounts != null) - foreach (var discount in allDiscounts) - if (_discountService.IsDiscountValid(discount, customer) && - discount.DiscountType == DiscountType.AssignedToShipping && - !allowedDiscounts.ContainsDiscount(discount)) - allowedDiscounts.Add(discount); + + if (allDiscounts != null) + { + foreach (var discount in allDiscounts) + { + if (discount.DiscountType == DiscountType.AssignedToShipping && !allowedDiscounts.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer)) + { + allowedDiscounts.Add(discount); + } + } + } appliedDiscount = allowedDiscounts.GetPreferredDiscount(shippingTotal); if (appliedDiscount != null) @@ -1068,8 +1072,7 @@ public virtual decimal GetOrderTotalDiscount(Customer customer, decimal orderTot { foreach (var discount in allDiscounts) { - if (_discountService.IsDiscountValid(discount, customer) && discount.DiscountType == DiscountType.AssignedToOrderTotal && - !allowedDiscounts.ContainsDiscount(discount)) + if (discount.DiscountType == DiscountType.AssignedToOrderTotal && !allowedDiscounts.Any(x => x.Id == discount.Id) &&_discountService.IsDiscountValid(discount, customer)) { allowedDiscounts.Add(discount); } From e283be263cd9014f2d32b6881c62bfe3cfe540e5 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Mon, 27 Jul 2015 12:02:29 +0200 Subject: [PATCH 0125/1074] Added optional customer number field --- changelog.md | 1 + .../Domain/Customers/CustomerSettings.cs | 6 ++++++ .../Customers/SystemCustomerAttributeNames.cs | 1 + .../201506181858349_AclRecordCustomerRole.cs | 12 ++++++++++++ .../Controllers/CustomerController.cs | 9 ++++++++- .../Models/Customers/CustomerModel.cs | 6 ++++++ .../Models/Settings/CustomerUserSettingsModel.cs | 3 +++ .../Views/Customer/_CreateOrUpdate.cshtml | 14 ++++++++++++++ .../Views/Setting/CustomerUser.cshtml | 9 +++++++++ .../Controllers/CustomerController.cs | 11 +++++++++++ .../Models/Customer/CustomerInfoModel.cs | 5 +++++ .../SmartStore.Web/Views/Customer/Info.cshtml | 7 ++++++- 12 files changed, 82 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 438a5a59e4..499f044df1 100644 --- a/changelog.md +++ b/changelog.md @@ -9,6 +9,7 @@ * Skrill payment plugin (distributed via Marketplace) * (Dev) DevTool plugin: added option to display all widget zones in public store * New options for manufacturer display on the homepage +* Added optional customer number field ### Improvements * (Perf) several minor optimizations for faster app startup and page rendering diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs index f37d102711..3b2f13bb66 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs @@ -8,6 +8,7 @@ public class CustomerSettings : ISettings public CustomerSettings() { UsernamesEnabled = true; + CustomerNumberEnabled = true; DefaultPasswordFormat = PasswordFormat.Hashed; HashedPasswordFormat = "SHA1"; PasswordMinLength = 6; @@ -29,6 +30,11 @@ public CustomerSettings() /// public bool UsernamesEnabled { get; set; } + /// + /// Gets or sets a value indicating whether customers can enter a customer id + /// + public bool CustomerNumberEnabled { get; set; } + /// /// Gets or sets a value indicating whether users can check the availability of usernames (when registering or changing in 'My Account') /// diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerAttributeNames.cs b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerAttributeNames.cs index ea0bb24d01..e7c43c19da 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerAttributeNames.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerAttributeNames.cs @@ -20,6 +20,7 @@ public static partial class SystemCustomerAttributeNames public static string VatNumber { get { return "VatNumber"; } } public static string VatNumberStatusId { get { return "VatNumberStatusId"; } } public static string TimeZoneId { get { return "TimeZoneId"; } } + public static string CustomerNumber { get { return "CustomerNumber"; } } //Other attributes public static string DiscountCouponCode { get { return "DiscountCouponCode"; } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs index 153e8be49e..d6c9752fbd 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs @@ -131,6 +131,18 @@ before you can assign them to all subcategories and products.
    "Zeige Herstellerbilder auf der Homepage", "Specifies whether manufacturers will be displayed as images or textual links on the homepage.", "Bestimmt ob Hersteller auf der Homepage als Bilder oder textuelle Links angezeigt werden."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerNumberEnabled", + "Customers can enter a customer number", + "Kunden knnen Kundennummer hinterlegen", + "Specifies whether customers can enter a customer number.", + "Bestimmt ob Kunden eine Kundennummer hinterlegen knnen."); + + builder.AddOrUpdate("Account.Fields.CustomerNumber", + "Customer number", + "Kundennummer"); + + } } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs index 0a8e0c6858..11786ceaf6 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CustomerController.cs @@ -234,6 +234,7 @@ protected CustomerModel PrepareCustomerModelForList(Customer customer) Username = customer.Username, FullName = customer.GetFullName(), Company = customer.GetAttribute(SystemCustomerAttributeNames.Company), + CustomerNumber = customer.GetAttribute(SystemCustomerAttributeNames.CustomerNumber), Phone = customer.GetAttribute(SystemCustomerAttributeNames.Phone), ZipPostalCode = customer.GetAttribute(SystemCustomerAttributeNames.ZipPostalCode), CustomerRoleNames = GetCustomerRolesNames(customer.CustomerRoles.ToList()), @@ -281,7 +282,8 @@ private void PrepareCustomerModelForCreate(CustomerModel model) model.StateProvinceEnabled = _customerSettings.StateProvinceEnabled; model.PhoneEnabled = _customerSettings.PhoneEnabled; model.FaxEnabled = _customerSettings.FaxEnabled; - + model.CustomerNumberEnabled = _customerSettings.CustomerNumberEnabled; + if (_customerSettings.CountryEnabled) { model.AvailableCountries.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Address.SelectCountry"), Value = "0" }); @@ -607,6 +609,7 @@ public ActionResult Edit(int id) model.Gender = customer.GetAttribute(SystemCustomerAttributeNames.Gender); model.DateOfBirth = customer.GetAttribute(SystemCustomerAttributeNames.DateOfBirth); model.Company = customer.GetAttribute(SystemCustomerAttributeNames.Company); + model.CustomerNumber = customer.GetAttribute(SystemCustomerAttributeNames.CustomerNumber); model.StreetAddress = customer.GetAttribute(SystemCustomerAttributeNames.StreetAddress); model.StreetAddress2 = customer.GetAttribute(SystemCustomerAttributeNames.StreetAddress2); model.ZipPostalCode = customer.GetAttribute(SystemCustomerAttributeNames.ZipPostalCode); @@ -619,6 +622,7 @@ public ActionResult Edit(int id) model.GenderEnabled = _customerSettings.GenderEnabled; model.DateOfBirthEnabled = _customerSettings.DateOfBirthEnabled; model.CompanyEnabled = _customerSettings.CompanyEnabled; + model.CustomerNumberEnabled = _customerSettings.CustomerNumberEnabled; model.StreetAddressEnabled = _customerSettings.StreetAddressEnabled; model.StreetAddress2Enabled = _customerSettings.StreetAddress2Enabled; model.ZipPostalCodeEnabled = _customerSettings.ZipPostalCodeEnabled; @@ -765,6 +769,8 @@ public ActionResult Edit(CustomerModel model, bool continueEditing, FormCollecti _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.DateOfBirth, model.DateOfBirth); if (_customerSettings.CompanyEnabled) _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Company, model.Company); + if (_customerSettings.CustomerNumberEnabled) + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Company, model.CustomerNumber); if (_customerSettings.StreetAddressEnabled) _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.StreetAddress, model.StreetAddress); if (_customerSettings.StreetAddress2Enabled) @@ -835,6 +841,7 @@ public ActionResult Edit(CustomerModel model, bool continueEditing, FormCollecti //form fields model.GenderEnabled = _customerSettings.GenderEnabled; model.DateOfBirthEnabled = _customerSettings.DateOfBirthEnabled; + model.CustomerNumberEnabled = _customerSettings.CustomerNumberEnabled; model.CompanyEnabled = _customerSettings.CompanyEnabled; model.StreetAddressEnabled = _customerSettings.StreetAddressEnabled; model.StreetAddress2Enabled = _customerSettings.StreetAddress2Enabled; diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Customers/CustomerModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Customers/CustomerModel.cs index 4cf4e2a992..72f0f78fb3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Customers/CustomerModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Customers/CustomerModel.cs @@ -62,6 +62,12 @@ public CustomerModel() [AllowHtml] public string Company { get; set; } + public bool CustomerNumberEnabled { get; set; } + [SmartResourceDisplayName("Account.Fields.CustomerNumber")] + [AllowHtml] + public string CustomerNumber { get; set; } + + public bool StreetAddressEnabled { get; set; } [SmartResourceDisplayName("Admin.Customers.Customers.Fields.StreetAddress")] [AllowHtml] diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Settings/CustomerUserSettingsModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Settings/CustomerUserSettingsModel.cs index 56f374c6a6..04c6344582 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Settings/CustomerUserSettingsModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Settings/CustomerUserSettingsModel.cs @@ -25,6 +25,9 @@ public partial class CustomerSettingsModel [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.UsernamesEnabled")] public bool UsernamesEnabled { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.CustomerNumberEnabled")] + public bool CustomerNumberEnabled { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Settings.CustomerUser.AllowUsersToChangeUsernames")] public bool AllowUsersToChangeUsernames { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml index 5f224792df..6c72eae453 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml @@ -200,6 +200,20 @@ } + + @if (Model.CustomerNumberEnabled) + { + + + @Html.SmartLabelFor(model => model.CustomerNumber) + + + @Html.EditorFor(model => model.CustomerNumber) + @Html.ValidationMessageFor(model => model.CustomerNumber) + + + } + @if (Model.StreetAddressEnabled) { diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Setting/CustomerUser.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Setting/CustomerUser.cshtml index 4fcee50d11..6acbacd0b7 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Setting/CustomerUser.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Setting/CustomerUser.cshtml @@ -77,6 +77,15 @@ @Html.ValidationMessageFor(model => model.CustomerSettings.UsernamesEnabled) + + + @Html.SmartLabelFor(model => model.CustomerSettings.CustomerNumberEnabled) + + + @Html.SettingEditorFor(model => model.CustomerSettings.CustomerNumberEnabled) + @Html.ValidationMessageFor(model => model.CustomerSettings.CustomerNumberEnabled) + + @Html.SmartLabelFor(model => model.CustomerSettings.AllowUsersToChangeUsernames) diff --git a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs index a7b162f8cd..e9716f4573 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs @@ -241,6 +241,7 @@ protected void PrepareCustomerInfoModel(CustomerInfoModel model, Customer custom model.StateProvinceId = customer.GetAttribute(SystemCustomerAttributeNames.StateProvinceId); model.Phone = customer.GetAttribute(SystemCustomerAttributeNames.Phone); model.Fax = customer.GetAttribute(SystemCustomerAttributeNames.Fax); + model.CustomerNumber = customer.GetAttribute(SystemCustomerAttributeNames.CustomerNumber); //newsletter var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(customer.Email, _storeContext.CurrentStore.Id); @@ -311,6 +312,7 @@ protected void PrepareCustomerInfoModel(CustomerInfoModel model, Customer custom model.AllowUsersToChangeUsernames = _customerSettings.AllowUsersToChangeUsernames; model.CheckUsernameAvailabilityEnabled = _customerSettings.CheckUsernameAvailabilityEnabled; model.SignatureEnabled = _forumSettings.ForumsEnabled && _forumSettings.SignaturesEnabled; + model.CustomerNumberEnabled = _customerSettings.CustomerNumberEnabled; //external authentication foreach (var ear in _openAuthenticationService.GetExternalIdentifiersFor(customer)) @@ -1002,9 +1004,18 @@ public ActionResult Info(CustomerInfoModel model) //form fields if (_customerSettings.GenderEnabled) + { _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Gender, model.Gender); + } + + if (_customerSettings.CustomerNumberEnabled) + { + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CustomerNumber, model.CustomerNumber); + } + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.FirstName, model.FirstName); _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastName, model.LastName); + if (_customerSettings.DateOfBirthEnabled) { DateTime? dateOfBirth = null; diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerInfoModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerInfoModel.cs index ed98738e60..3b1f96f544 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerInfoModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerInfoModel.cs @@ -22,6 +22,11 @@ public CustomerInfoModel() [AllowHtml] public string Email { get; set; } + [SmartResourceDisplayName("Account.Fields.CustomerNumber")] + [AllowHtml] + public string CustomerNumber { get; set; } + public bool CustomerNumberEnabled { get; set; } + public bool CheckUsernameAvailabilityEnabled { get; set; } public bool AllowUsersToChangeUsernames { get; set; } public bool UsernamesEnabled { get; set; } diff --git a/src/Presentation/SmartStore.Web/Views/Customer/Info.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/Info.cshtml index aeb7d5df5e..2e75e5f05e 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/Info.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/Info.cshtml @@ -60,7 +60,6 @@
    @T("Account.YourPersonalDetails") - @*codehint: sm-edit begin*@ @if (Model.GenderEnabled) {
    @@ -134,6 +133,12 @@ }
    } + + @if(Model.CustomerNumberEnabled) + { + @Html.ControlGroupFor(model => model.CustomerNumber, required: false) + } +
    if (Model.AssociatedExternalAuthRecords.Count > 0) From 55d130406d16f38a6873ef1e59d3bc0856ebba3d Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 27 Jul 2015 12:18:26 +0200 Subject: [PATCH 0126/1074] Fixed paging issue in product list of a category (backend) --- .../Catalog/CategoryService.cs | 76 +++++++++++-------- .../Controllers/CategoryController.cs | 42 +++++----- 2 files changed, 69 insertions(+), 49 deletions(-) diff --git a/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs b/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs index d563031d2b..d85423e343 100644 --- a/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs @@ -400,24 +400,27 @@ public virtual IPagedList GetProductCategoriesByCategoryId(int if (categoryId == 0) return new PagedList(new List(), pageIndex, pageSize); - string key = string.Format(PRODUCTCATEGORIES_ALLBYCATEGORYID_KEY, showHidden, categoryId, pageIndex, pageSize, _workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id); + int storeId = _storeContext.CurrentStore.Id; + string key = string.Format(PRODUCTCATEGORIES_ALLBYCATEGORYID_KEY, showHidden, categoryId, pageIndex, pageSize, _workContext.CurrentCustomer.Id, storeId); + return _cacheManager.Get(key, () => { var query = from pc in _productCategoryRepository.Table join p in _productRepository.Table on pc.ProductId equals p.Id - where pc.CategoryId == categoryId && - !p.Deleted && - (showHidden || p.Published) - orderby pc.DisplayOrder + where pc.CategoryId == categoryId && !p.Deleted && (showHidden || p.Published) select pc; if (!showHidden) { - query = ApplyHiddenProductCategoriesFilter(query); - query = query.OrderBy(pc => pc.DisplayOrder); + query = ApplyHiddenProductCategoriesFilter(query, storeId); } + query = query + .OrderBy(pc => pc.DisplayOrder) + .ThenBy(pc => pc.Id); // required for paging! + var productCategories = new PagedList(query, pageIndex, pageSize); + return productCategories; }); } @@ -465,35 +468,46 @@ orderby pc.DisplayOrder }); } - protected virtual IQueryable ApplyHiddenProductCategoriesFilter(IQueryable query) + protected virtual IQueryable ApplyHiddenProductCategoriesFilter(IQueryable query, int storeId = 0) { + bool group = false; + //ACL (access control list) - var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles - .Where(cr => cr.Active).Select(cr => cr.Id).ToList(); + if (!QuerySettings.IgnoreAcl) + { + group = true; + var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles.Where(cr => cr.Active).Select(cr => cr.Id).ToList(); - query = from pc in query - join c in _categoryRepository.Table on pc.CategoryId equals c.Id - join acl in _aclRepository.Table - on new { c1 = c.Id, c2 = "Category" } equals new { c1 = acl.EntityId, c2 = acl.EntityName } into c_acl - from acl in c_acl.DefaultIfEmpty() - where !c.SubjectToAcl || allowedCustomerRolesIds.Contains(acl.CustomerRoleId) - select pc; + query = from pc in query + join c in _categoryRepository.Table on pc.CategoryId equals c.Id + join acl in _aclRepository.Table + on new { c1 = c.Id, c2 = "Category" } equals new { c1 = acl.EntityId, c2 = acl.EntityName } into c_acl + from acl in c_acl.DefaultIfEmpty() + where !c.SubjectToAcl || allowedCustomerRolesIds.Contains(acl.CustomerRoleId) + select pc; + } //Store mapping - var currentStoreId = _storeContext.CurrentStore.Id; - query = from pc in query - join c in _categoryRepository.Table on pc.CategoryId equals c.Id - join sm in _storeMappingRepository.Table - on new { c1 = c.Id, c2 = "Category" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into c_sm - from sm in c_sm.DefaultIfEmpty() - where !c.LimitedToStores || currentStoreId == sm.StoreId - select pc; - - //only distinct categories (group by ID) - query = from pc in query - group pc by pc.Id into pcGroup - orderby pcGroup.Key - select pcGroup.FirstOrDefault(); + if (!QuerySettings.IgnoreMultiStore && storeId > 0) + { + group = true; + query = from pc in query + join c in _categoryRepository.Table on pc.CategoryId equals c.Id + join sm in _storeMappingRepository.Table + on new { c1 = c.Id, c2 = "Category" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into c_sm + from sm in c_sm.DefaultIfEmpty() + where !c.LimitedToStores || storeId == sm.StoreId + select pc; + } + + if (group) + { + //only distinct categories (group by ID) + query = from pc in query + group pc by pc.Id into pcGroup + orderby pcGroup.Key + select pcGroup.FirstOrDefault(); + } return query; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs index 94dddf36f5..6c24f4f22b 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/CategoryController.cs @@ -764,29 +764,35 @@ public ActionResult ProductList(GridCommand command, int categoryId) if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog)) return AccessDeniedView(); - var productCategories = _categoryService.GetProductCategoriesByCategoryId(categoryId, - command.Page - 1, command.PageSize, true); + var productCategories = _categoryService.GetProductCategoriesByCategoryId(categoryId, command.Page - 1, command.PageSize, true); + + var products = _productService.GetProductsByIds(productCategories.Select(x => x.ProductId).ToArray()); var model = new GridModel { - Data = productCategories - .Select(x => + Data = productCategories.Select(x => { - var product = _productService.GetProductById(x.ProductId); + var productModel = new CategoryModel.CategoryProductModel + { + Id = x.Id, + CategoryId = x.CategoryId, + ProductId = x.ProductId, + IsFeaturedProduct = x.IsFeaturedProduct, + DisplayOrder1 = x.DisplayOrder + }; - return new CategoryModel.CategoryProductModel() - { - Id = x.Id, - CategoryId = x.CategoryId, - ProductId = x.ProductId, - ProductName = product.Name, - Sku = product.Sku, - ProductTypeName = product.GetProductTypeLabel(_localizationService), - ProductTypeLabelHint = product.ProductTypeLabelHint, - Published = product.Published, - IsFeaturedProduct = x.IsFeaturedProduct, - DisplayOrder1 = x.DisplayOrder - }; + var product = products.FirstOrDefault(y => y.Id == x.ProductId); + + if (product != null) + { + productModel.ProductName = product.Name; + productModel.Sku = product.Sku; + productModel.ProductTypeName = product.GetProductTypeLabel(_localizationService); + productModel.ProductTypeLabelHint = product.ProductTypeLabelHint; + productModel.Published = product.Published; + } + + return productModel; }), Total = productCategories.TotalCount }; From a0a4d1a4fdcfda5598ec56913793b90228b9c9d9 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Mon, 27 Jul 2015 12:44:18 +0200 Subject: [PATCH 0127/1074] Implemented function to show widget zone with a filter instead of widget --- .../DependencyRegistrar.cs | 3 +- .../Filters/WidgetZoneFilter.cs | 123 ++++++++++ .../SmartStore.DevTools.csproj | 2 +- .../Views/DevTools/WidgetZone.cshtml | 2 +- .../Widgets/ShowZonesWidget.cs | 220 ------------------ 5 files changed, 127 insertions(+), 223 deletions(-) create mode 100644 src/Plugins/SmartStore.DevTools/Filters/WidgetZoneFilter.cs delete mode 100644 src/Plugins/SmartStore.DevTools/Widgets/ShowZonesWidget.cs diff --git a/src/Plugins/SmartStore.DevTools/DependencyRegistrar.cs b/src/Plugins/SmartStore.DevTools/DependencyRegistrar.cs index e562ef1d9f..91f0a57419 100644 --- a/src/Plugins/SmartStore.DevTools/DependencyRegistrar.cs +++ b/src/Plugins/SmartStore.DevTools/DependencyRegistrar.cs @@ -26,7 +26,8 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b { // intercept ALL public store controller actions builder.RegisterType().AsActionFilterFor(); - + builder.RegisterType().AsActionFilterFor(); + //// intercept CatalogController's Product action //builder.RegisterType().AsResultFilterFor(x => x.Product(default(int), default(string))).InstancePerRequest(); //builder.RegisterType().AsActionFilterFor().InstancePerRequest(); diff --git a/src/Plugins/SmartStore.DevTools/Filters/WidgetZoneFilter.cs b/src/Plugins/SmartStore.DevTools/Filters/WidgetZoneFilter.cs new file mode 100644 index 0000000000..253fdd0b60 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Filters/WidgetZoneFilter.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core.Logging; +using SmartStore.Core.Localization; +using SmartStore.DevTools.Services; +using SmartStore.Core; +using SmartStore.Services; +using SmartStore.Services.Customers; +using SmartStore.Web.Framework.UI; +using SmartStore.Utilities; +using System.IO; + +namespace SmartStore.DevTools.Filters +{ + public class WidgetZoneFilter : IActionFilter, IResultFilter + { + private readonly ICommonServices _services; + private readonly Lazy _widgetProvider; + private readonly ProfilerSettings _profilerSettings; + + public WidgetZoneFilter( + ICommonServices services, + Lazy widgetProvider, + ProfilerSettings profilerSettings) + { + this._services = services; + this._widgetProvider = widgetProvider; + this._profilerSettings = profilerSettings; + } + + public void OnActionExecuting(ActionExecutingContext filterContext) + { + if (!_profilerSettings.DisplayWidgetZones) + return; + } + + public void OnActionExecuted(ActionExecutedContext filterContext) + { + if (!_profilerSettings.DisplayWidgetZones) + return; + } + + public void OnResultExecuting(ResultExecutingContext filterContext) + { + if (!_profilerSettings.DisplayWidgetZones) + return; + + // should only run on a full view rendering result + var result = filterContext.Result as ViewResultBase; + if (result == null) + { + return; + } + + if (!this.ShouldRender(filterContext.HttpContext)) + { + return; + } + + if (!filterContext.IsChildAction) + { + _widgetProvider.Value.RegisterAction( + new Wildcard("*"), + "WidgetZone", + "DevTools", + new { area = "SmartStore.DevTools" }); + } + + var viewName = result.ViewName; + + if (viewName.IsEmpty()) + { + string action = (filterContext.RouteData.Values["action"] as string).EmptyNull(); + viewName = action; + + if (action == "WidgetsByZone") + { + var model = result.Model as WidgetZoneModel; + + filterContext.Result = new ViewResult + { + ViewName = "~/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml", + }; + filterContext.RouteData.Values.Add("widgetZone", model.WidgetZone); + } + } + } + + public void OnResultExecuted(ResultExecutedContext filterContext) + { + if (!_profilerSettings.DisplayWidgetZones) + return; + + // should only run on a full view rendering result + if (!(filterContext.Result is ViewResultBase)) + { + return; + } + + if (!this.ShouldRender(filterContext.HttpContext)) + { + return; + } + } + + private bool ShouldRender(HttpContextBase ctx) + { + if (!_services.WorkContext.CurrentCustomer.IsAdmin()) + { + return ctx.Request.IsLocal; + } + + return true; + } + + } +} diff --git a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj index 2db1f156da..78718fe893 100644 --- a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj +++ b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj @@ -144,6 +144,7 @@ + @@ -155,7 +156,6 @@ - diff --git a/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml b/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml index 2dcf0c42a0..222fe683e0 100644 --- a/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml +++ b/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml @@ -1,3 +1,3 @@ - + Widget Zone diff --git a/src/Plugins/SmartStore.DevTools/Widgets/ShowZonesWidget.cs b/src/Plugins/SmartStore.DevTools/Widgets/ShowZonesWidget.cs deleted file mode 100644 index f9834ae0d6..0000000000 --- a/src/Plugins/SmartStore.DevTools/Widgets/ShowZonesWidget.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System.Collections.Generic; -using System.Web; -using System.Web.Routing; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Plugins; -using SmartStore.Services; -using SmartStore.Services.Cms; -using SmartStore.Services.Common; - -namespace SmartStore.DevTools.Widgets -{ - [SystemName("Widgets.ShowZones")] - [FriendlyName("Show Zones")] - public class ShowZonesWidget : IWidget - { - private readonly ICommonServices _services; - private readonly HttpContextBase _httpContext; - - public ShowZonesWidget(ICommonServices services, - HttpContextBase httpContext, - IGenericAttributeService genericAttributeService) - { - _services = services; - _httpContext = httpContext; - } - - public IList GetWidgetZones() - { - return new List() - { - //Blogs - "blogpost_page_before_body", "mobile_blogpost_page_before_body", - "blogpost_page_before_comments", "mobile_blogpost_page_before_comments", - "blogpost_page_inside_comment", "mobile_blogpost_page_inside_comment", - "blogpost_page_after_comments", "mobile_blogpost_page_after_comments", - "bloglist_page_before_posts", "mobile_bloglist_page_before_posts", - "bloglist_page_inside_post", "mobile_bloglist_page_inside_post", - "bloglist_page_after_posts", "mobile_bloglist_page_after_posts", - - //Categories - "categorydetails_after_breadcrumb", - "categorydetails_top", "mobile_categorydetails_top", - "categorydetails_before_subcategories", "mobile_categorydetails_before_subcategories", - "categorydetails_before_featured_products", "mobile_categorydetails_before_featured_products", - "categorydetails_after_featured_products", - "categorydetails_before_product_list", "mobile_categorydetails_before_product_list", - "categorydetails_bottom", "mobile_categorydetails_bottom", - "categorydetails_before_filters", - - //Products - "productbox_add_info", - "productsbytag_before_product_list", - "productreviews_page_inside_review", - "productdetails_overview_top", - "productdetails_overview_bottom", - "productsbytag_top", "mobile_productsbytag_top", - "productsbytag_bottom", "mobile_productsbytag_bottom", - "productdetails_add_info", "mobile_productdetails_add_info", - "productdetails_top", "mobile_productdetails_top", - "productdetails_before_pictures", "mobile_productdetails_before_pictures", - "productdetails_after_pictures", "mobile_productdetails_after_pictures", - "productdetails_bottom", "mobile_productdetails_bottom", - - //Navigation - "productbreadcrumb_before", - "productbreadcrumb_after", - "header_menu_before", - "header_menu_after", - "megamenu_before_first_item", - "megamenu_after_last_item", - "account_dropdown_before", - "account_dropdown_after", - "header_links_before", "mobile_header_links_before", - "header_links_after", "mobile_header_links_after", - "infoblock_before", "mobile_infoblock_before", - "infoblock_after", "mobile_infoblock_after", - "account_navigation_before", "mobile_account_navigation_before", - "account_navigation_after", "mobile_account_navigation_after", - - //Checkout - "checkout_progress_before", - "checkout_progress_after", - "checkout_billing_address_top", "mobile_checkout_billing_address_top", - "checkout_billing_address_middle", "mobile_checkout_billing_address_middle", - "checkout_billing_address_bottom", "mobile_checkout_billing_address_bottom", - "checkout_completed_top", "mobile_checkout_completed_top", - "checkout_completed_bottom", "mobile_checkout_completed_bottom", - "checkout_confirm_top", "mobile_checkout_confirm_top", - "checkout_confirm_before_summary", "mobile_checkout_confirm_before_summary", - "checkout_confirm_bottom", "mobile_checkout_confirm_bottom", - "checkout_payment_method_top", "mobile_checkout_payment_method_top", - "checkout_payment_method_bottom", "mobile_checkout_payment_method_bottom", - "checkout_shipping_address_top", "mobile_checkout_shipping_address_top", - "checkout_shipping_address_middle", "mobile_checkout_shipping_address_middle", - "checkout_shipping_address_bottom", "mobile_checkout_shipping_address_bottom", - "checkout_shipping_method_top", "mobile_checkout_shipping_method_top", - "checkout_shipping_method_bottom", "mobile_checkout_shipping_method_bottom", - - //PDF - "invoice_footer_before", - "invoice_footer_after", - "invoice_header_before", - "invoice_header_right", - "invoice_header_after", - "invoice_top", - "invoice_orderinfo_top", - "invoice_orderinfotable_after", - "invoice_orderinfo_bottom", - "invoice_lines_before", - "invoice_checkoutattributes_before", - "invoice_ordertotals_before", - "invoice_ordernotes_before", - "invoice_bottom", - "pdfcatalog_cover_top", - "pdfcatalog_cover_logo_after", - "pdfcatalog_cover_storename_after", - "pdfcatalog_productdetail_top", - "pdfcatalog_productdetail_fulldescription_before", - "pdfcatalog_productdetail_picture_before", - "pdfcatalog_productdetail_specificationattributes_before", - "pdfcatalog_productdetail_bundleditems_before", - "pdfcatalog_productdetail_associatedproducts_before", - - //Manufacturer - "manufacturerdetails_top", "mobile_manufacturerdetails_top", - "manufacturerdetails_before_featured_products", "mobile_manufacturerdetails_before_featured_products", - "manufacturerdetails_after_featured_products", - "manufacturerdetails_before_filters", - "manufacturerdetails_before_product_list", "mobile_manufacturerdetails_before_product_list", - "manufacturerdetails_bottom", "mobile_manufacturerdetails_bottom", - - //Misc - "compareproducts_row", "mobile_compareproducts_row", - "productsearch_page_advanced", - "productsearch_page_basic", - "productsearch_page_advanced", - "searchbox", "mobile_searchbox", - "footer", "mobile_footer", - "contactus_top", "mobile_contactus_top", - "contactus_bottom", "mobile_contactus_bottom", - "productreviews_page_top", "mobile_productreviews_page_top", - "productreviews_page_inside_review", "mobile_productreviews_page_inside_review", - "productreviews_page_bottom", "mobile_productreviews_page_bottom", - "profile_page_info_userdetails", "mobile_profile_page_info_userdetails", - "profile_page_info_userstats", "mobile_profile_page_info_userstats", - "notifications", "mobile_notifications", - "shipmentdetails_top", - "shipmentdetails_orderinfo_top", - "shipmentdetails_orderinfotable_after", - "shipmentdetails_orderinfo_bottom", - "shipmentdetails_lines_before", - - //Global - "home_page_top", "mobile_home_page_top", - "home_page_bottom", "mobile_home_page_bottom", - "main_column_before", - "main_column_after", - "left_side_column_before", - "left_side_column_after_category_navigation", - "left_side_column_after_manufacturer_navigation", - "left_side_column_after_tags", - "left_side_column_after_info", - "left_side_column_after_poll", - "left_side_column_after", - "right_side_column_before", - "right_side_column_after_recentlyviewed", - "right_side_column_after_poll", - "right_side_column_after", - "body_start_html_tag_after", "mobile_body_start_html_tag_after", - "content_before", "mobile_content_before", - "content_after", "mobile_content_after", - "body_end_html_tag_before", "mobile_body_end_html_tag_after", - "head_html_tag", "mobile_head_html_tag", - "admin_navbar_before", - "admin_navbar_after", - "admin_breadcrumb", - "admin_content_before", - "admin_content_after", - "admin_menu_before", - - //News - "newslist_page_before_items", "mobile_newslist_page_before_items", - "newslist_page_inside_item", "mobile_newslist_page_inside_item", - "newslist_page_after_items", "mobile_newslist_page_after_items", - "newsitem_page_before_body", "mobile_newsitem_page_before_body", - "newsitem_page_before_comments", "mobile_newsitem_page_before_comments", - "newsitem_page_inside_comment", "mobile_newsitem_page_inside_comment", - "newsitem_page_after_comments", "mobile_newsitem_page_after_comments", - - //Orders - "orderdetails_page_top", "mobile_orderdetails_page_top", - "orderdetails_page_overview", "mobile_orderdetails_page_overview", - "orderdetails_page_beforeproducts", "mobile_orderdetails_page_beforeproducts", - "orderdetails_page_afterproducts", "mobile_orderdetails_page_afterproducts", - "orderdetails_page_aftertotal", "mobile_orderdetails_page_aftertotal", - "orderdetails_page_bottom", "mobile_orderdetails_page_bottom", - - //Shopping Cart - "mini_shopping_cart_bottom", - "order_summary_content_before", "mobile_order_summary_content_before", - "order_summary_content_totals_left", "mobile_order_summary_content_totals_left", - "order_summary_content_deals", "mobile_order_summary_content_deals", - "order_summary_content_totals_bottom", "mobile_order_summary_content_totals_bottom", - "order_summary_content_after", "mobile_order_summary_content_after" - }; - } - - public void GetDisplayWidgetRoute(string widgetZone, object model, int storeId, out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - controllerName = "DevTools"; - actionName = "WidgetZone"; - routeValues = new RouteValueDictionary() - { - { "Namespaces", "SmartStore.DevTools.Controllers" }, - { "area", "SmartStore.DevTools" }, - { "widgetZone", widgetZone } - }; - } - } -} \ No newline at end of file From 69853f2ddb015053973d131c189581b3d0e72ad7 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 27 Jul 2015 15:46:29 +0200 Subject: [PATCH 0128/1074] Reduce database round trips initiated by price calculation --- changelog.md | 1 + src/Libraries/SmartStore.Core/PagedList`T.cs | 7 ++- .../Catalog/CategoryService.cs | 29 ++++++++++++ .../Catalog/ICategoryService.cs | 10 +++++ .../Catalog/IPriceCalculationService.cs | 4 +- .../Catalog/PriceCalculationContext.cs | 19 +++++++- .../Catalog/PriceCalculationService.cs | 45 ++++++++----------- 7 files changed, 85 insertions(+), 30 deletions(-) diff --git a/changelog.md b/changelog.md index f1153fdf11..999f0e404b 100644 --- a/changelog.md +++ b/changelog.md @@ -28,6 +28,7 @@ * #709 News feed produced invalid RSS feed. Added content:encoded. Added maximum news age setting for feed export. * #735 Include SKUs of attribute combinations when filtering the backend product list * Filter for homepage and published\unpublished products in backend product list +* Reduce database round trips initiated by price calculation ### Bugfixes * #523 Redirecting to payment provider performed by core instead of plugin diff --git a/src/Libraries/SmartStore.Core/PagedList`T.cs b/src/Libraries/SmartStore.Core/PagedList`T.cs index 63db21a70d..7d5c66a94b 100644 --- a/src/Libraries/SmartStore.Core/PagedList`T.cs +++ b/src/Libraries/SmartStore.Core/PagedList`T.cs @@ -19,7 +19,11 @@ public class PagedList : List, IPagedList public PagedList(IQueryable source, int pageIndex, int pageSize) { Guard.ArgumentNotNull(source, "source"); - Init(source.Skip(pageIndex * pageSize).Take(pageSize), pageIndex, pageSize, source.Count()); + + if (pageIndex == 0 && pageSize == int.MaxValue) // avoid unnecessary SQL + Init(source, pageIndex, pageSize, source.Count()); + else + Init(source.Skip(pageIndex * pageSize).Take(pageSize), pageIndex, pageSize, source.Count()); } /// @@ -31,6 +35,7 @@ public PagedList(IQueryable source, int pageIndex, int pageSize) public PagedList(IList source, int pageIndex, int pageSize) { Guard.ArgumentNotNull(source, "source"); + Init(source.Skip(pageIndex * pageSize).Take(pageSize), pageIndex, pageSize, source.Count); } diff --git a/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs b/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs index d85423e343..ea0bc201ae 100644 --- a/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; @@ -468,6 +469,34 @@ orderby pc.DisplayOrder }); } + public virtual Multimap GetProductCategoriesByProductIds(int[] productIds, bool? hasDiscountsApplied = null, bool showHidden = false) + { + Guard.ArgumentNotNull(() => productIds); + + var query = + from pc in _productCategoryRepository.TableUntracked.Expand(x => x.Category) + join c in _categoryRepository.Table on pc.CategoryId equals c.Id + where productIds.Contains(pc.ProductId) && !c.Deleted && (showHidden || c.Published) + orderby pc.DisplayOrder + select pc; + + if (hasDiscountsApplied.HasValue) + { + query = query.Where(x => x.Category.HasDiscountsApplied == hasDiscountsApplied); + } + + var list = query.ToList(); + + if (!showHidden) + { + list = list.Where(x => _aclService.Authorize(x.Category) && _storeMappingService.Authorize(x.Category)).ToList(); + } + + var map = list.ToMultimap(x => x.ProductId, x => x); + + return map; + } + protected virtual IQueryable ApplyHiddenProductCategoriesFilter(IQueryable query, int storeId = 0) { bool group = false; diff --git a/src/Libraries/SmartStore.Services/Catalog/ICategoryService.cs b/src/Libraries/SmartStore.Services/Catalog/ICategoryService.cs index 6b7650d69b..209507a66d 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ICategoryService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ICategoryService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; @@ -96,6 +97,15 @@ IPagedList GetProductCategoriesByCategoryId(int categoryId, /// Product category mapping collection IList GetProductCategoriesByProductId(int productId, bool showHidden = false); + /// + /// Gets product category mappings + /// + /// Product identifiers + /// A value indicating whether to filter categories with applied discounts + /// A value indicating whether to show hidden records + /// Map with product category mappings + Multimap GetProductCategoriesByProductIds(int[] productIds, bool? hasDiscountsApplied = null, bool showHidden = false); + /// /// Gets a product category mapping /// diff --git a/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs index 090a301e8d..e3c7b9d5a6 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs @@ -181,13 +181,15 @@ decimal GetDiscountAmount(Product product, /// Product quantity /// Applied discount /// A product bundle item + /// Object with cargo data for better performance /// Discount amount decimal GetDiscountAmount(Product product, Customer customer, decimal additionalCharge, int quantity, out Discount appliedDiscount, - ProductBundleItemData bundleItem = null); + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null); /// diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs index 0f594e6fdc..ee316d42c6 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs @@ -17,15 +17,18 @@ public class PriceCalculationContext private Func> _funcAttributes; private Func> _funcAttributeCombinations; private Func> _funcTierPrices; + private Func> _funcProductCategories; private LazyMultimap _attributes; private LazyMultimap _attributeCombinations; private LazyMultimap _tierPrices; + private LazyMultimap _productCategories; public PriceCalculationContext(IEnumerable products, Func> attributes, Func> attributeCombinations, - Func> tierPrices) + Func> tierPrices, + Func> productCategories) { if (products == null) { @@ -41,6 +44,7 @@ public PriceCalculationContext(IEnumerable products, _funcAttributes = attributes; _funcAttributeCombinations = attributeCombinations; _funcTierPrices = tierPrices; + _funcProductCategories = productCategories; } public LazyMultimap Attributes @@ -79,11 +83,24 @@ public LazyMultimap TierPrices } } + public LazyMultimap ProductCategories + { + get + { + if (_productCategories == null) + { + _productCategories = new LazyMultimap(keys => _funcProductCategories(keys), _productIds); + } + return _productCategories; + } + } + public void Collect(IEnumerable productIds) { Attributes.Collect(productIds); AttributeCombinations.Collect(productIds); TierPrices.Collect(productIds); + ProductCategories.Collect(productIds); } } } diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index 7cff4b8abb..9fef3cf937 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -1,9 +1,9 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Web; -using SmartStore.Collections; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Discounts; @@ -65,7 +65,7 @@ public PriceCalculationService( /// Product /// Customer /// Discounts - protected virtual IList GetAllowedDiscounts(Product product, Customer customer) + protected virtual IList GetAllowedDiscounts(Product product, Customer customer, PriceCalculationContext context = null) { var result = new List(); if (_catalogSettings.IgnoreDiscounts) @@ -86,7 +86,13 @@ protected virtual IList GetAllowedDiscounts(Product product, Customer //performance optimization. load all category discounts just to ensure that we have at least one if (_discountService.GetAllDiscounts(DiscountType.AssignedToCategories).Any()) { - var productCategories = _categoryService.GetProductCategoriesByProductId(product.Id); + IEnumerable productCategories = null; + + if (context == null) + productCategories = _categoryService.GetProductCategoriesByProductId(product.Id); + else + productCategories = context.ProductCategories.Load(product.Id); + if (productCategories != null) { foreach (var productCategory in productCategories) @@ -272,7 +278,8 @@ public virtual PriceCalculationContext CreatePriceCalculationContext(IEnumerable var context = new PriceCalculationContext(products, x => _productAttributeService.GetProductVariantAttributesByProductIds(x, null), x => _productAttributeService.GetProductVariantAttributeCombinations(x), - x => _productService.GetTierPrices(x, _services.WorkContext.CurrentCustomer, _services.StoreContext.CurrentStore.Id) + x => _productService.GetTierPrices(x, _services.WorkContext.CurrentCustomer, _services.StoreContext.CurrentStore.Id), + x => _categoryService.GetProductCategoriesByProductIds(x, true) ); return context; @@ -385,7 +392,7 @@ public virtual decimal GetFinalPrice( if (includeDiscounts) { Discount appliedDiscount = null; - decimal discountAmount = GetDiscountAmount(product, customer, additionalCharge, quantity, out appliedDiscount, bundleItem); + decimal discountAmount = GetDiscountAmount(product, customer, additionalCharge, quantity, out appliedDiscount, bundleItem, context); result = result + additionalCharge - discountAmount; } else @@ -471,13 +478,6 @@ public virtual decimal GetLowestPrice(Product product, PriceCalculationContext c if (!displayFromMessage && product.HasTierPrices && !isBundlePerItemPricing) { - //var tierPrices = product.TierPrices - // .OrderBy(tp => tp.Quantity) - // .FilterByStore(_services.StoreContext.CurrentStore.Id) - // .FilterForCustomer(_services.WorkContext.CurrentCustomer) - // .ToList() - // .RemoveDuplicatedQuantities(); - var tierPrices = context.TierPrices.Load(product.Id); displayFromMessage = (tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices.First().Quantity <= 1)); @@ -649,23 +649,14 @@ public virtual decimal GetDiscountAmount(Product product, return GetDiscountAmount(product, customer, additionalCharge, 1, out appliedDiscount); } - /// - /// Gets discount amount - /// - /// Product - /// The customer - /// Additional charge - /// Product quantity - /// Applied discount - /// A product bundle item - /// Discount amount public virtual decimal GetDiscountAmount( Product product, Customer customer, decimal additionalCharge, int quantity, out Discount appliedDiscount, - ProductBundleItemData bundleItem = null) + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null) { appliedDiscount = null; decimal appliedDiscountAmount = decimal.Zero; @@ -675,14 +666,14 @@ public virtual decimal GetDiscountAmount( { if (bundleItem.Item.Discount.HasValue && bundleItem.Item.BundleProduct.BundlePerItemPricing) { - appliedDiscount = new Discount() + appliedDiscount = new Discount { UsePercentage = bundleItem.Item.DiscountPercentage, DiscountPercentage = bundleItem.Item.Discount.Value, DiscountAmount = bundleItem.Item.Discount.Value }; - finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem); + finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem, context); appliedDiscountAmount = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount); } } @@ -694,13 +685,13 @@ public virtual decimal GetDiscountAmount( return appliedDiscountAmount; } - var allowedDiscounts = GetAllowedDiscounts(product, customer); + var allowedDiscounts = GetAllowedDiscounts(product, customer, context); if (allowedDiscounts.Count == 0) { return appliedDiscountAmount; } - finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem); + finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem, context); appliedDiscount = allowedDiscounts.GetPreferredDiscount(finalPriceWithoutDiscount); if (appliedDiscount != null) From f0daa77c8d6be0004542ac111482b6317247d381 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 27 Jul 2015 20:15:21 +0200 Subject: [PATCH 0129/1074] Web-API: requests always led to new guest customers though HMAC authentication. Core is now informed through new principal about the authentication. IWorkContext.set_CurrentCustomer useless in this scenario. --- .../Collections/LazyMultimap.cs | 2 +- .../SmartStore.Core/SmartNetPrincipal.cs | 29 +++++++++++++++ .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../FormsAuthenticationService.cs | 28 ++++++++++----- .../Catalog/PriceCalculationService.cs | 15 ++------ .../WebApi/Security/HmacAuthentication.cs | 3 +- .../Security/WebApiAuthenticateAttribute.cs | 36 +++++++++---------- .../WebApi/WebApiCore.cs | 4 +-- 8 files changed, 75 insertions(+), 43 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/SmartNetPrincipal.cs diff --git a/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs b/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs index 803ff63ded..9aa3d30a8c 100644 --- a/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs +++ b/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs @@ -46,7 +46,7 @@ protected virtual void Load(IEnumerable keys) { ++_roundTripCount; - Debug.WriteLine("Round trip {0} of {1}: {2}", _roundTripCount, typeof(T).Name, string.Join(",", loadKeys.OrderBy(x => x))); + //Debug.WriteLine("Round trip {0} of {1}: {2}", _roundTripCount, typeof(T).Name, string.Join(",", loadKeys.OrderBy(x => x))); var items = _load(loadKeys); diff --git a/src/Libraries/SmartStore.Core/SmartNetPrincipal.cs b/src/Libraries/SmartStore.Core/SmartNetPrincipal.cs new file mode 100644 index 0000000000..0fae852141 --- /dev/null +++ b/src/Libraries/SmartStore.Core/SmartNetPrincipal.cs @@ -0,0 +1,29 @@ +using System.Security.Principal; +using System.Web.Security; +using SmartStore.Core.Domain.Customers; + +namespace SmartStore.Core +{ + public interface ISmartNetPrincipal : IPrincipal + { + int CustomerId { get; set; } + } + + + public class SmartNetPrincipal : ISmartNetPrincipal + { + public SmartNetPrincipal(Customer customer, string type) + { + this.Identity = new GenericIdentity(customer.Username, type); + this.CustomerId = customer.Id; + } + + public bool IsInRole(string role) + { + return Identity != null && Identity.IsAuthenticated && role.HasValue() && Roles.IsUserInRole(Identity.Name, role); + } + + public IIdentity Identity { get; private set; } + public int CustomerId { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 8a063d5b66..f1c102b6d5 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -357,6 +357,7 @@ + diff --git a/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs b/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs index c43d075957..657f93cd69 100644 --- a/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs +++ b/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs @@ -1,6 +1,7 @@ using System; using System.Web; using System.Web.Security; +using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Services.Customers; @@ -77,18 +78,29 @@ public virtual Customer GetAuthenticatedCustomer() if (_cachedCustomer != null) return _cachedCustomer; - if (_httpContext == null || - _httpContext.Request == null || - !_httpContext.Request.IsAuthenticated || - !(_httpContext.User.Identity is FormsIdentity)) + if (_httpContext == null || _httpContext.Request == null || !_httpContext.Request.IsAuthenticated) { return null; } - var formsIdentity = (FormsIdentity)_httpContext.User.Identity; - var customer = GetAuthenticatedCustomerFromTicket(formsIdentity.Ticket); - if (customer != null && customer.Active && !customer.Deleted && customer.IsRegistered()) - _cachedCustomer = customer; + Customer customer = null; + FormsIdentity formsIdentity = null; + SmartNetPrincipal smartNetPrincipal = null; + + if ((formsIdentity = _httpContext.User.Identity as FormsIdentity) != null) + { + customer = GetAuthenticatedCustomerFromTicket(formsIdentity.Ticket); + } + else if ((smartNetPrincipal = _httpContext.User as SmartNetPrincipal) != null) + { + customer = _customerService.GetCustomerById(smartNetPrincipal.CustomerId); + } + + if (customer != null && customer.Active && !customer.Deleted && customer.IsRegistered()) + { + _cachedCustomer = customer; + } + return _cachedCustomer; } diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index 9fef3cf937..082bc2ad23 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -210,15 +210,6 @@ protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationC } } - //if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null) - // defaultValue.IsPreSelected = true; - - //if (defaultValue == null) - // defaultValue = pvaValues.FirstOrDefault(x => x.IsPreSelected); - - //if (defaultValue != null) - // selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId); - // value pre-selected by a bundle item filter discards the default pre-selection if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null) { @@ -448,6 +439,8 @@ public virtual decimal GetLowestPrice(Product product, PriceCalculationContext c if (product.ProductType == ProductType.GroupedProduct) throw Error.InvalidOperation("Choose the other override for products of type grouped product."); + // note: attribute price adjustments were never regarded here cause of many reasons + if (context == null) context = CreatePriceCalculationContext(); @@ -455,9 +448,7 @@ public virtual decimal GetLowestPrice(Product product, PriceCalculationContext c displayFromMessage = isBundlePerItemPricing; - // TODO(?): attribute price adjustments were not regarded here cause of performance - - decimal lowestPrice = GetFinalPrice(product, null, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue, null, context); + var lowestPrice = GetFinalPrice(product, null, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue, null, context); if (product.LowestAttributeCombinationPrice.HasValue && product.LowestAttributeCombinationPrice.Value < lowestPrice) { diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/Security/HmacAuthentication.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/Security/HmacAuthentication.cs index 0cdab6e3c7..b661d994ec 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/Security/HmacAuthentication.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/Security/HmacAuthentication.cs @@ -150,6 +150,7 @@ public enum HmacResult : int UserUnknown, UserDisabled, UserInvalid, - UserHasNoPermission + UserHasNoPermission, + UserIsInactive } } diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/Security/WebApiAuthenticateAttribute.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/Security/WebApiAuthenticateAttribute.cs index 06f25a322e..00dc7563de 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/Security/WebApiAuthenticateAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/Security/WebApiAuthenticateAttribute.cs @@ -21,20 +21,11 @@ namespace SmartStore.Web.Framework.WebApi.Security [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] public class WebApiAuthenticateAttribute : System.Web.Http.AuthorizeAttribute { - private readonly IWorkContext _workContext; - private readonly IPermissionService _permissionService; - protected HmacAuthentication _hmac = new HmacAuthentication(); - public WebApiAuthenticateAttribute() - { - var engine = EngineContext.Current; - - _workContext = engine.Resolve(); - _permissionService = engine.Resolve(); - } - - /// The system name of the permission + /// + /// The system name of the permission + /// public string Permission { get; set; } protected string CreateContentMd5Hash(HttpRequestMessage request) @@ -54,14 +45,18 @@ protected virtual bool HasPermission(HttpActionContext actionContext, Customer c try { - if (Permission.HasValue() && _permissionService.GetPermissionRecordBySystemName(Permission) != null) + if (Permission.HasValue()) { - result = _permissionService.Authorize(Permission, customer); + var permissionService = EngineContext.Current.Resolve(); + + if (permissionService.GetPermissionRecordBySystemName(Permission) != null) + { + result = permissionService.Authorize(Permission, customer); + } } } - catch (Exception) - { - } + catch { } + return result; } protected virtual void LogUnauthorized(HttpActionContext actionContext, HmacResult result, Customer customer) @@ -177,6 +172,9 @@ protected virtual HmacResult IsAuthenticated(HttpActionContext actionContext, Da if (customer == null) return HmacResult.UserUnknown; + if (!customer.Active || customer.Deleted) + return HmacResult.UserIsInactive; + if (!HasPermission(actionContext, customer)) return HmacResult.UserHasNoPermission; @@ -206,13 +204,15 @@ public override void OnAuthorization(HttpActionContext actionContext) if (result == HmacResult.Success) { - _workContext.CurrentCustomer = customer; + // inform core about the authentication. note you cannot use IWorkContext.set_CurrentCustomer here. + HttpContext.Current.User = new SmartNetPrincipal(customer, HmacAuthentication.Scheme1); var response = HttpContext.Current.Response; response.AddHeader(WebApiGlobal.Header.Version, cacheControllingData.Version); response.AddHeader(WebApiGlobal.Header.MaxTop, WebApiGlobal.MaxTop.ToString()); response.AddHeader(WebApiGlobal.Header.Date, now.ToString("o")); + response.AddHeader(WebApiGlobal.Header.CustomerId, customer.Id.ToString()); response.Cache.SetCacheability(HttpCacheability.NoCache); } diff --git a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiCore.cs b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiCore.cs index 9f97de2d1b..7d9db0fd44 100644 --- a/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiCore.cs +++ b/src/Presentation/SmartStore.Web.Framework/WebApi/WebApiCore.cs @@ -1,5 +1,4 @@ using System.Text; -using Microsoft.Data.OData; namespace SmartStore.Web.Framework.WebApi { @@ -13,8 +12,6 @@ public static class WebApiGlobal public static string MostRecentOdataPath { get { return "odata/v1"; } } public static string PluginSystemName { get { return "SmartStore.WebApi"; } } - public static ODataVersion ODataVersion { get { return ODataVersion.V3; } } - /// see http://tools.ietf.org/html/rfc6648 public static class Header { @@ -24,6 +21,7 @@ public static class Header public static string PublicKey { get { return Prefix + "PublicKey"; } } public static string MaxTop { get { return Prefix + "MaxTop"; } } public static string Version { get { return Prefix + "Version"; } } + public static string CustomerId { get { return Prefix + "CustomerId"; } } public static string HmacResultId { get { return Prefix + "HmacResultId"; } } public static string HmacResultDescription { get { return Prefix + "HmacResultDesc"; } } //public static string LastRequest { get { return Prefix + "LastRequest"; } } From 2302f8bb32b6946ca75c40022c6888e0274ceda2 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 28 Jul 2015 11:29:56 +0200 Subject: [PATCH 0130/1074] Some changes to last commit --- .../SmartStore.Core/SmartNetPrincipal.cs | 26 ++++++++++++++----- .../FormsAuthenticationService.cs | 13 ++++------ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/Libraries/SmartStore.Core/SmartNetPrincipal.cs b/src/Libraries/SmartStore.Core/SmartNetPrincipal.cs index 0fae852141..bcbcb35043 100644 --- a/src/Libraries/SmartStore.Core/SmartNetPrincipal.cs +++ b/src/Libraries/SmartStore.Core/SmartNetPrincipal.cs @@ -1,4 +1,6 @@ -using System.Security.Principal; +using System.Security; +using System.Security.Claims; +using System.Security.Principal; using System.Web.Security; using SmartStore.Core.Domain.Customers; @@ -6,7 +8,21 @@ namespace SmartStore.Core { public interface ISmartNetPrincipal : IPrincipal { - int CustomerId { get; set; } + } + + + public class SmartNetIdentity : ClaimsIdentity + { + [SecuritySafeCritical] + public SmartNetIdentity(int customerId, string name, string type) + : base(new GenericIdentity(name, type)) + { + CustomerId = customerId; + } + + public int CustomerId { get; private set; } + + public override bool IsAuthenticated { get { return CustomerId != 0; } } } @@ -14,16 +30,14 @@ public class SmartNetPrincipal : ISmartNetPrincipal { public SmartNetPrincipal(Customer customer, string type) { - this.Identity = new GenericIdentity(customer.Username, type); - this.CustomerId = customer.Id; + this.Identity = new SmartNetIdentity(customer.Id, customer.Username, type); } public bool IsInRole(string role) { - return Identity != null && Identity.IsAuthenticated && role.HasValue() && Roles.IsUserInRole(Identity.Name, role); + return (Identity != null && Identity.IsAuthenticated && role.HasValue() && Roles.IsUserInRole(Identity.Name, role)); } public IIdentity Identity { get; private set; } - public int CustomerId { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs b/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs index 657f93cd69..7e8924468c 100644 --- a/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs +++ b/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs @@ -25,8 +25,7 @@ public partial class FormsAuthenticationService : IAuthenticationService /// HTTP context /// Customer service /// Customer settings - public FormsAuthenticationService(HttpContextBase httpContext, - ICustomerService customerService, CustomerSettings customerSettings) + public FormsAuthenticationService(HttpContextBase httpContext, ICustomerService customerService, CustomerSettings customerSettings) { this._httpContext = httpContext; this._customerService = customerService; @@ -78,22 +77,20 @@ public virtual Customer GetAuthenticatedCustomer() if (_cachedCustomer != null) return _cachedCustomer; - if (_httpContext == null || _httpContext.Request == null || !_httpContext.Request.IsAuthenticated) - { + if (_httpContext == null || _httpContext.Request == null || !_httpContext.Request.IsAuthenticated || _httpContext.User == null) return null; - } Customer customer = null; FormsIdentity formsIdentity = null; - SmartNetPrincipal smartNetPrincipal = null; + SmartNetIdentity smartNetIdentity = null; if ((formsIdentity = _httpContext.User.Identity as FormsIdentity) != null) { customer = GetAuthenticatedCustomerFromTicket(formsIdentity.Ticket); } - else if ((smartNetPrincipal = _httpContext.User as SmartNetPrincipal) != null) + else if ((smartNetIdentity = _httpContext.User.Identity as SmartNetIdentity) != null) { - customer = _customerService.GetCustomerById(smartNetPrincipal.CustomerId); + customer = _customerService.GetCustomerById(smartNetIdentity.CustomerId); } if (customer != null && customer.Active && !customer.Deleted && customer.IsRegistered()) From 8e0e471d0d7c9d97ab8678103b05a43aef81467b Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 28 Jul 2015 13:24:56 +0200 Subject: [PATCH 0131/1074] Increased version number to 2.2.2 --- SmartStoreNET.Tasks.Targets | 2 +- src/AssemblyVersionInfo.cs | 2 +- .../Localization/App/de/all.smres.xml | 170 +++++++++++++++--- .../App_Data/Localization/App/de/head.txt | 2 +- .../Localization/App/en/all.smres.xml | 154 +++++++++++++--- .../App_Data/Localization/App/en/head.txt | 2 +- 6 files changed, 280 insertions(+), 52 deletions(-) diff --git a/SmartStoreNET.Tasks.Targets b/SmartStoreNET.Tasks.Targets index 980f2060e3..4cc8cafa8a 100644 --- a/SmartStoreNET.Tasks.Targets +++ b/SmartStoreNET.Tasks.Targets @@ -44,7 +44,7 @@ x86 $(BUILD_NUMBER) - 2.2.1 + 2.2.2 $(StageFolder) .$(Version) diff --git a/src/AssemblyVersionInfo.cs b/src/AssemblyVersionInfo.cs index 8cf3480af0..0c8dfa2cfb 100644 --- a/src/AssemblyVersionInfo.cs +++ b/src/AssemblyVersionInfo.cs @@ -12,4 +12,4 @@ [assembly: AssemblyVersion("2.2.0.0")] [assembly: AssemblyFileVersion("2.2.0.0")] -[assembly: AssemblyInformationalVersion("2.2.1.0")] +[assembly: AssemblyInformationalVersion("2.2.2.0")] diff --git a/src/Presentation/SmartStore.Web/App_Data/Localization/App/de/all.smres.xml b/src/Presentation/SmartStore.Web/App_Data/Localization/App/de/all.smres.xml index b492367ecf..37af334470 100644 --- a/src/Presentation/SmartStore.Web/App_Data/Localization/App/de/all.smres.xml +++ b/src/Presentation/SmartStore.Web/App_Data/Localization/App/de/all.smres.xml @@ -240,6 +240,9 @@ Land + + Kundennummer + Geburtsdatum @@ -783,6 +786,9 @@ Telefonnummer wird benötigt + + * Eingabefelder mit Sternchen sind Pflichfelder und müssen ausgefüllt werden. + Bundesland/Region @@ -2932,6 +2938,15 @@ Auf Aktualisierung prüfen + + Unbekannter Fehler beim Paket-Download. Bitte versuchen Sie es später erneut. + + + AutoUpdate möglich + + + <p>Dieses Update kann automatisch installiert werden. Hierfür lädt SmartStore.NET ein Installationspaket auf Ihren Webserver herunter, führt die Installation durch und startet die Anwendung neu. Vor der Installation wird der Verzeichnisinhalt Ihres Shops gesichert, mit Ausnahme der Ordner <i>App_Data</i> und <i>Media</i> sowie der SQL Server Datenbank. </p><p>Klicken Sie die Schaltfläche <b>Jetzt aktualisieren</b>, um das Paket downzuloaden und zu installieren. Alternativ hierzu können Sie weiter unten das Paket auf Ihren lokalen PC downloaden und die Installation zu einem späteren Zeitpunkt manuell durchführen.</p> + Aktuelle Version @@ -2947,23 +2962,14 @@ Update verfügbar - - Ihre Version - Jetzt aktualisieren - - AutoUpdate möglich - - - Unbekannter Fehler beim Paket-Download. Bitte versuchen Sie es später erneut. - - - <p>Dieses Update kann automatisch installiert werden. Hierfür lädt SmartStore.NET ein Installationspaket auf Ihren Webserver herunter, führt die Installation durch und startet die Anwendung neu. Vor der Installation wird der Verzeichnisinhalt Ihres Shops gesichert, mit Ausnahme der Ordner <i>App_Data</i> und <i>Media</i> sowie der SQL Server Datenbank. </p><p>Klicken Sie die Schaltfläche <b>Jetzt aktualisieren</b>, um das Paket downzuloaden und zu installieren. Alternativ hierzu können Sie weiter unten das Paket auf Ihren lokalen PC downloaden und die Installation zu einem späteren Zeitpunkt manuell durchführen.</p> + + Ihre Version - Über + Über SmartStore.NET Aktionen @@ -3064,6 +3070,9 @@ Die eindeutige nummerische ID des Datensatzes + + Fehler beim Senden einer E-Mail + Excel-Datei @@ -3214,6 +3223,9 @@ Suchen + + Jetzt senden + Suchmaschinen (SEO) @@ -3286,6 +3298,9 @@ Zugriffsrechte + + Es sind keine Kundengruppen definiert + Zugriffsrecht @@ -3346,6 +3361,24 @@ Die Ereignistypen wurden erfolgreich bearbeitet. + + Diese Konfiguration für Kindelemente übernehmen + + + Diese Funktion übernimmt die Zugriffsrecht-Konfiguration dieser Warengruppe für alle Unterwarengruppen und Produkte.<br/> + Bitte beachten Sie, dass die Änderungen der Zugriffsrechte zunächst gespeichert werden müssen, <br /> + bevor diese für Unterkategorien und Produkte übernommen werden können. <br /> + <b>Vorsicht:</b> Bitte beachten Sie, <b>dass vorhandene Zugriffsrechte überschrieben bzw. gelöscht werden</b>. + + + Diese Konfiguration für Kindelemente übernehmen + + + Diese Funktion übernimmt die Shop-Konfiguration dieser Warengruppe für alle Unterwarengruppen und Produkte.<br/> + Bitte beachten Sie, dass die Änderungen an der Store-Konfiguration zunächst gespeichert werden müssen, <br /> + bevor diese für Unterkategorien und Produkte übernommen werden können. <br /> + <b>Vorsicht:</b> Bitte beachten Sie, <b>dass vorhandene Store-Konfiguration überschrieben bzw. gelöscht werden</b>. + Content Slider @@ -4115,7 +4148,7 @@ Zahlung - Das Plugin erlaubt keine Aktivierung dieser Zahlungsmethode. + Das Plugin erlaubt keine Aktivierung dieser Zahlungsart. Zahlungsarten @@ -4127,10 +4160,10 @@ Konfiguration - Wiederkehrender Zahlungstyp + Wiederkehrende Zahlungen - Unterstützt Capture + Buchung möglich Teilerstattung möglich @@ -4139,7 +4172,7 @@ Erstattung möglich - Kann storniert werden + Stornierung möglich Plugins @@ -4756,6 +4789,18 @@ Legt fest, ob die Hersteller-Produktnummer im Shop angezeigt werden soll. + + Zeige Herstellerbilder auf der Homepage + + + Bestimmt ob Hersteller auf der Homepage als Bilder oder textuelle Links angezeigt werden. + + + Zeige Hersteller auf der Homepage + + + Bestimmt ob Hersteller auf der Homepage angezeigt werden. + Produktbilder bei der Autovervollständigung anzeigen @@ -4804,6 +4849,12 @@ Zeigt das Gewicht des Produktes an. + + Unterwarengruppen anzeigen + + + Legt fest, ob und wo Unterwarengruppen auf einer Warengruppenseite angezeigt werden sollen. + SKU Suche unterdrücken @@ -4996,6 +5047,12 @@ Legt die maximale Länge des angezeigten Benutzernamens fest. + + Kunden können Kundennummer hinterlegen + + + Bestimmt ob Kunden eine Kundennummer hinterlegen können. + Kundeneinstellungen @@ -7039,6 +7096,12 @@ Ein Name für die Forengruppe ist erforderlich + + URL-Alias + + + Legt einen Suchmaschinen-freundlichen Seitennamen für das Forum fest. 'Tolles Forum' resultiert bspw. in '~/tolles-forum'. Standard ist der Name des Forums. + Das Forum wurde erfolgreich aktualisiert @@ -7084,6 +7147,12 @@ Ein Name für die Forengruppe ist erforderlich + + URL-Alias + + + Legt einen Suchmaschinen-freundlichen Seitennamen für die Forengruppe fest. 'Tolle Forengruppe' resultiert bspw. in '~/tolle-forengruppe'. Standard ist der Name der Forengruppe. + Die Forengruppe wurde erfolgreich aktualisert. @@ -7144,6 +7213,12 @@ Der Name der Vorlage (Schreibgeschützt) + + Nur manuell senden + + + Legt fest, ob E-Mails, die von dieser Nachrichtenvorlage abgeleitet sind, ausschließlich manuell gesendet werden sollen. + Betreff @@ -8386,8 +8461,11 @@ Hilfe + + Dokumentation + - Community-Forum + Community SmartStore.NET ist ein Fork der ASP.NET Open-Source E-Commerce-Lösung {0}. @@ -8759,10 +8837,10 @@ Setzt den Zahlungsstatus auf 'Bezahlt' ohne dabei den Zahlungsanbieter zu kontaktieren. - Auftrags-GUID + Bestellreferenznummer - Interne Referenz für den Auftrag. + Die interne Bestellreferenznummer. Im Gegensatz zur Auftragsnummer existiert diese bereits im Kassenbereich, d.h. vor der eigentlichen Erstelllung des Auftrags. Auftragsnummer @@ -8858,10 +8936,10 @@ Setzt den Zahlungsstatus auf 'Teilweise erstattet' samt Erstattungsbetrag, ohne dabei den Zahlungsanbieter zu kontaktieren. - Zahlungsmethode + Zahlungsart - Die Zahlungsmethode für diese Transaktion + Die Zahlungsart für diese Transaktion Die Zahlungsgebühr (netto) für diesen Auftrag @@ -9100,6 +9178,12 @@ Notiz + + Neue IPN + + + In den Auftragsnotizen ist eine neue Benachrichtigung vom Zahlungsanbieter eingetroffen. + Auftrag als PDF @@ -9502,6 +9586,9 @@ Plugins verwalten + + Bitte beachten Sie, dass der tatsächliche Grundpreis von verschiedenen Faktoren abhängig ist und erst im Shop zuverlässig berechnet werden kann. + Promotion Feeds @@ -10360,6 +10447,12 @@ Priorität eingeben + + Nur manuell senden + + + Legt fest, ob die E-Mail ausschließlich manuell gesendet werden soll. + Gesendet um @@ -10421,7 +10514,7 @@ Lade nur noch nicht gesendete E-Mails - Zeige E-Mails nur aus der Warteschlange. + Lade nur noch nicht gesendete E-Mails. Maximale Sendeversuche @@ -10429,6 +10522,12 @@ Gibt die Anzahl der Zustellversuche an. + + Lade nur manuell zu sendende E-Mails + + + Lade nur manuell zu sendende E-Mails. + Anfangsdatum @@ -10445,7 +10544,7 @@ Wiederholen - Die Nachricht wird erneut gesendet + Die Nachricht wurde erfolgreich neu eingereiht. Die E-Mail wurde erfolgreich bearbeitet @@ -10643,10 +10742,10 @@ '{0}' Plugin ist nicht kompatibel mit Ihrer SmartStore.NET-Version. Löschen Sie es oder installieren Sie die richtige Version. - Es gibt keine aktiven Zahlungsmethoden. + Es existieren keine aktiven Zahlungsarten. - Die Zahlungsmethoden sind OK. + Die Zahlungsarten sind OK. Die Hauptwährung für den Shop wurde nicht festgelegt. @@ -11150,7 +11249,7 @@ Weiter - Keine Zahlungsmethoden verfügbar. + Es sind keine Zahlungsarten verfügbar. Ihre Bestellung ist angekommen @@ -11168,7 +11267,7 @@ Zahlungsinformation - Zahlungsmethode + Zahlungsarten Bestelldetails @@ -11386,6 +11485,9 @@ Fehler + + Die gewählte Zahlungsart verursachte leider einen Fehler. Bitte korrigieren Sie Ihre Eingaben, versuchen Sie es erneut oder wählen Sie eine andere Zahlungsart. + Fehler beim Versenden der Email. Bitte versuchen Sie es später erneut. @@ -11815,6 +11917,15 @@ Jahre + + Über der Produktliste + + + Am Seitenende + + + Nicht anzeigen + Benutze CONTAINS und AND mit prefix_term @@ -12762,7 +12873,7 @@ Gesamtsumme - Zahlungsmethode + Zahlungsart Zahlungsgebühr @@ -13370,6 +13481,9 @@ {0} am Lager. + + Nicht im Sortiment + Nicht am Lager diff --git a/src/Presentation/SmartStore.Web/App_Data/Localization/App/de/head.txt b/src/Presentation/SmartStore.Web/App_Data/Localization/App/de/head.txt index 9e3f271712..afe64e4f3b 100644 --- a/src/Presentation/SmartStore.Web/App_Data/Localization/App/de/head.txt +++ b/src/Presentation/SmartStore.Web/App_Data/Localization/App/de/head.txt @@ -1 +1 @@ -201504232202590_AutoUpdateRes \ No newline at end of file +201506181858349_AclRecordCustomerRole \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/all.smres.xml b/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/all.smres.xml index 45d1081077..c6d776abb6 100644 --- a/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/all.smres.xml +++ b/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/all.smres.xml @@ -240,6 +240,9 @@ Country + + Customer number + Date of birth @@ -783,6 +786,9 @@ Phone number is required. + + * Input elements with asterisk are required and have to be filled out. + State / province @@ -3025,6 +3031,15 @@ Check for update + + Unknown error during package download. Please try again later. + + + AutoUpdate possible + + + <p>This update can be installed automatically. For this SmartStore.NET downloads an installation package to your webserver, executes it and restarts the application. Before the installation your shop directory is backed up, except the folders <i>App_Data</i> and <i>Media</i>, as well as the SQL Server database file. </p><p>Click the <b>Update now</b> button to download and install the package. As an alternative to this, you can download the package to your local PC further below and perform the installation at a later time manually.</p> + Current version @@ -3040,26 +3055,17 @@ Update available - - Your version - Update now - - AutoUpdate possible - - - Unknown error during package download. Please try again later. - - - <p>This update can be installed automatically. For this SmartStore.NET downloads an installation package to your webserver, executes it and restarts the application. Before the installation your shop directory is backed up, except the folders <i>App_Data</i> and <i>Media</i>, as well as the SQL Server database file. </p><p>Click the <b>Update now</b> button to download and install the package. As an alternative to this, you can download the package to your local PC further below and perform the installation at a later time manually.</p> + + Your version Actions - About + About SmartStore.NET Actions @@ -3160,6 +3166,9 @@ The unique numeric id of the entity + + Error sending an email + Excel file @@ -3310,6 +3319,9 @@ Search + + Send now + Search engines (SEO) @@ -3382,6 +3394,9 @@ Access control list + + No customer roles defined + Permission name @@ -3445,6 +3460,24 @@ The types have been updated successfully. + + Transfer this ACL configuration to children + + + This function assigns the ACL configuration of this category to all subcategories and products included in this category.<br /> + Please keep in mind you have to save changes in the ACL configuration <br/> + before you can assign them to all subcategories and products. <br/> + <b>Attention:</b> Please keep in mind that <b>existing ACL records will be deleted</b> + + + Transfer this store configuration to children + + + This function assigns the store configuration of this category to all subcategories and products included in this category.<br /> + Please keep in mind you have to save changes in the store configuration <br/> + before you can assign them to all subcategories and products. <br/> + <b>Attention:</b> Please keep in mind that <b>existing store mappings will be deleted</b> + Content Slider @@ -4271,19 +4304,19 @@ Display order - Recurring support + Recurring payments Supports capture - Partial refund + Supports partial refund - Refund + Supports refund - Void + Supports void Plugins @@ -4912,6 +4945,18 @@ Check to show manufacturer part numbers in public store. + + Show manufacturer pictures on homepage + + + Specifies whether manufacturers will be displayed as images or textual links on the homepage. + + + Show manufacturers on homepage + + + Specifies whether manufacturers will be displayed on the homepage. + Show product images in autocomplete box @@ -4960,6 +5005,12 @@ Check to display the weight. When enabled, customers will see the weight of the product. + + Show subcategories + + + Indicates whether and where to show subcategories on a category page. + Suppress SKU search @@ -5152,6 +5203,12 @@ Determines the maximum length of the displayed customer name. + + Customers can enter a customer number + + + Specifies whether customers can enter a customer number. + Customer settings @@ -7235,6 +7292,12 @@ Forum group name is required. + + URL-Alias + + + Set a search engine friendly page name e.g. 'the-best-forum' to make your page URL 'http://www.yourStore.com/the-best-forum'. Leave empty to generate it automatically based on the name of the forum. + The forum has been updated successfully. @@ -7283,6 +7346,12 @@ Forum Group Name is required. + + URL-Alias + + + Set a search engine friendly page name e.g. 'the-best-forumgroup' to make your page URL 'http://www.yourStore.com/the-best-forumgroup'. Leave empty to generate it automatically based on the name of the forum group. + The forum group has been updated successfully. @@ -7346,6 +7415,12 @@ The name of this template (read only). + + Only send manually + + + Indicates whether emails derived from this message template should only be send manually. + Subject @@ -8657,8 +8732,11 @@ Help + + Documentation + - Community forums + Community SmartStore.NET is a fork of the ASP.NET open source e-commerce solution {0}. @@ -9042,10 +9120,10 @@ Sets the payment status to 'paid' without contacting the payment provider. - Order GUID + Order reference number - Internal reference for order. + The internal order reference number. In contrast to the order number it already exists during checkout that is before order creation. Order Number @@ -9389,6 +9467,12 @@ Note + + New IPN + + + A new notification from the payment provider has arrived in the order notes. + Order as PDF @@ -9800,6 +9884,9 @@ Manage plugins + + Please keep in mind, the base price is depending on several factors and will therefore only be calculated reliable in the front end. + Promotion feeds @@ -10691,6 +10778,12 @@ Enter priority. + + Only send manually + + + Indicates whether the email should only be send manually. + Sent on @@ -10755,7 +10848,7 @@ Load not sent emails only - Only load emails into queue that have not yet been sent. + Load not sent emails only. Maximum send attempts @@ -10763,6 +10856,12 @@ The maximum number of attempts to send a message. + + Load emails manually send only + + + Load emails manually send only. + Start date @@ -11762,6 +11861,9 @@ Error + + Unfortunately the selected payment method caused an error. Please correct your entries, try it again or select another payment method. + Error while sending the email. Please try again later. @@ -12188,6 +12290,15 @@ Years + + Above product list + + + At bottom of page + + + Do not display + Using CONTAINS and AND with prefix_term @@ -13720,6 +13831,9 @@ {0} in stock + + Not in assortment + Out of stock diff --git a/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/head.txt b/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/head.txt index 9e3f271712..afe64e4f3b 100644 --- a/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/head.txt +++ b/src/Presentation/SmartStore.Web/App_Data/Localization/App/en/head.txt @@ -1 +1 @@ -201504232202590_AutoUpdateRes \ No newline at end of file +201506181858349_AclRecordCustomerRole \ No newline at end of file From cbef8d05c7f16d4eb9d8859809ab6efd83b92962 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 28 Jul 2015 18:57:48 +0200 Subject: [PATCH 0132/1074] Display base price in CompactProductBox --- .../SmartStore.Web/Controllers/CatalogHelper.cs | 5 +++-- .../SmartStore.Web/Controllers/ProductController.cs | 4 ++-- .../Views/Shared/_ProductBoxCompact.cshtml | 12 +++++++++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs index bd9c4354af..fb877fd0b3 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CatalogHelper.cs @@ -986,7 +986,8 @@ public IEnumerable PrepareProductOverviewModels( bool prepareSpecificationAttributes = false, bool forceRedirectionAfterAddingToCart = false, bool prepareColorAttributes = false, - bool prepareManufacturers = false) + bool prepareManufacturers = false, + bool isCompact = false) { if (products == null) throw new ArgumentNullException("products"); @@ -1315,7 +1316,7 @@ from a in colorAttr.ProductVariantAttributeValues.Take(50) if (_catalogSettings.ShowBasePriceInProductLists) { - model.BasePriceInfo = minPriceProduct.GetBasePriceInfo(_localizationService, _priceFormatter); + model.BasePriceInfo = minPriceProduct.GetBasePriceInfo(_localizationService, _priceFormatter, 0, isCompact); } var addShippingPrice = _currencyService.ConvertCurrency( diff --git a/src/Presentation/SmartStore.Web/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Controllers/ProductController.cs index ff7660fd01..4fcfdf40ec 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ProductController.cs @@ -445,7 +445,7 @@ public ActionResult RelatedProducts(int productId, int? productThumbPictureSize) if (products.Count == 0) return Content(""); - var model = _helper.PrepareProductOverviewModels(products, true, true, productThumbPictureSize).ToList(); + var model = _helper.PrepareProductOverviewModels(products, true, true, productThumbPictureSize, false, false, false, false, true).ToList(); return PartialView(model); } @@ -472,7 +472,7 @@ public ActionResult ProductsAlsoPurchased(int productId, int? productThumbPictur return Content(""); // prepare model - var model = _helper.PrepareProductOverviewModels(products, true, true, productThumbPictureSize).ToList(); + var model = _helper.PrepareProductOverviewModels(products, true, true, productThumbPictureSize, false, false, false, false, true).ToList(); return PartialView(model); } diff --git a/src/Presentation/SmartStore.Web/Views/Shared/_ProductBoxCompact.cshtml b/src/Presentation/SmartStore.Web/Views/Shared/_ProductBoxCompact.cshtml index 682c3fe67a..ed3cffd7f8 100644 --- a/src/Presentation/SmartStore.Web/Views/Shared/_ProductBoxCompact.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Shared/_ProductBoxCompact.cshtml @@ -25,6 +25,16 @@
    -
    @Model.ProductPrice.Price
    +
    + @Model.ProductPrice.Price +
    +
    + @if (Model.DisplayBasePrice && !String.IsNullOrEmpty(Model.BasePriceInfo)) + { + + @Model.BasePriceInfo + + } +
    \ No newline at end of file From 8ab3417a87c0ac4371d13fdf348e55e9d3a61be9 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 28 Jul 2015 19:07:32 +0200 Subject: [PATCH 0133/1074] Minor CSS change --- src/Presentation/SmartStore.Web/Content/bootstrap/media.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Presentation/SmartStore.Web/Content/bootstrap/media.less b/src/Presentation/SmartStore.Web/Content/bootstrap/media.less index 1decab71de..8b89ef39df 100644 --- a/src/Presentation/SmartStore.Web/Content/bootstrap/media.less +++ b/src/Presentation/SmartStore.Web/Content/bootstrap/media.less @@ -38,7 +38,7 @@ // ------------------------- .media .pull-left { - margin-right: 10px; + margin-right: 25px; } .media .pull-right { margin-left: 10px; From 4399ea6f8a3c6f0683b7ac071dbaaba9c590ee15 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Wed, 29 Jul 2015 13:41:01 +0200 Subject: [PATCH 0134/1074] Minor change --- .../Administration/Controllers/ProductController.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index 3258627c81..f419909ac5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -20,6 +20,7 @@ using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Seo; using SmartStore.Core.Events; using SmartStore.Core.Infrastructure; using SmartStore.Core.Localization; @@ -97,6 +98,7 @@ public partial class ProductController : AdminControllerBase private readonly IGenericAttributeService _genericAttributeService; private readonly IPdfConverter _pdfConverter; private readonly ICommonServices _services; + private readonly SeoSettings _seoSettings; #endregion @@ -147,7 +149,8 @@ public ProductController( IEventPublisher eventPublisher, IGenericAttributeService genericAttributeService, IPdfConverter pdfConverter, - ICommonServices services) + ICommonServices services, + SeoSettings seoSettings) { this._productService = productService; this._productTemplateService = productTemplateService; @@ -193,6 +196,7 @@ public ProductController( this._genericAttributeService = genericAttributeService; _pdfConverter = pdfConverter; _services = services; + _seoSettings = seoSettings; } #endregion @@ -559,7 +563,7 @@ private void UpdateDataOfExistingProduct(Product product, ProductModel model, bo MediaHelper.UpdateDownloadTransientStateFor(p, x => x.SampleDownloadId); // SEO - m.SeName = p.ValidateSeName(m.SeName, p.Name, true); + m.SeName = p.ValidateSeName(m.SeName, p.Name, true, _urlRecordService, _seoSettings); _urlRecordService.SaveSlug(p, m.SeName, 0); foreach (var localized in model.Locales) @@ -569,7 +573,7 @@ private void UpdateDataOfExistingProduct(Product product, ProductModel model, bo _localizedEntityService.SaveLocalizedValue(product, x => x.FullDescription, localized.FullDescription, localized.LanguageId); // search engine name - var localizedSeName = p.ValidateSeName(localized.SeName, localized.Name, false, localized.LanguageId); + var localizedSeName = p.ValidateSeName(localized.SeName, localized.Name, false, _urlRecordService, _seoSettings, localized.LanguageId); _urlRecordService.SaveSlug(p, localizedSeName, localized.LanguageId); } From 34a1a9517c1c8206a149050342145f7e8637f08c Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 30 Jul 2015 22:44:10 +0200 Subject: [PATCH 0135/1074] New export profile entity --- .../Customers/SystemCustomerRoleNames.cs | 1 - .../Domain/Export/ExportProfile.cs | 73 ++++++++++ .../SmartStore.Core/SmartStore.Core.csproj | 2 + .../Mapping/Export/ExportProfileMap.cs | 27 ++++ ...01507301550466_ExportFramework.Designer.cs | 29 ++++ .../201507301550466_ExportFramework.cs | 105 +++++++++++++++ .../201507301550466_ExportFramework.resx | 126 ++++++++++++++++++ .../Setup/Builder/PermissionMigrator.cs | 55 ++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 9 ++ .../ExportImport/ExportService.cs | 79 +++++++++++ .../ExportImport/IExportService.cs | 33 +++++ .../Security/StandardPermissionProvider.cs | 3 + .../SmartStore.Services.csproj | 2 + .../DependencyRegistrar.cs | 2 + .../Controllers/ExportController.cs | 73 ++++++++++ .../Models/Export/ExportProfileModel.cs | 31 +++++ .../Administration/SmartStore.Admin.csproj | 3 + .../Administration/Views/Export/List.cshtml | 59 ++++++++ .../Administration/sitemap.config | 2 + 19 files changed, 713 insertions(+), 1 deletion(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs create mode 100644 src/Libraries/SmartStore.Data/Mapping/Export/ExportProfileMap.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.resx create mode 100644 src/Libraries/SmartStore.Data/Setup/Builder/PermissionMigrator.cs create mode 100644 src/Libraries/SmartStore.Services/ExportImport/ExportService.cs create mode 100644 src/Libraries/SmartStore.Services/ExportImport/IExportService.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerRoleNames.cs b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerRoleNames.cs index 760d14d9be..214fd18191 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerRoleNames.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerRoleNames.cs @@ -3,7 +3,6 @@ namespace SmartStore.Core.Domain.Customers { public static partial class SystemCustomerRoleNames { - /// codehint: sm-add public static string SuperAdministrators { get { return "SuperAdmins"; } } public static string Administrators { get { return "Administrators"; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs b/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs new file mode 100644 index 0000000000..bca569da98 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs @@ -0,0 +1,73 @@ +using System; +using SmartStore.Core.Domain.Tasks; + +namespace SmartStore.Core.Domain +{ + public class ExportProfile : BaseEntity + { + /// + /// The name of the profile + /// + public string Name { get; set; } + + /// + /// Whether the export profile is enabled + /// + public bool Enabled { get; set; } + + /// + /// The system name of the export provider + /// + public string ProviderSystemName { get; set; } + + /// + /// The entity type to be exported + /// + public string EntityType { get; set; } + + /// + /// Number of hours after the profile is automatically executed by scheduling + /// + public int SchedulingHours { get; set; } + + /// + /// The scheduling task identifier + /// + public int SchedulingTaskId { get; set; } + + /// + /// The profile GUID is the folder name in the file system + /// + public Guid ProfileGuid { get; set; } + + /// + /// XML with partioning information + /// + public string Partitioning { get; set; } + + /// + /// XML with filtering information + /// + public string Filtering { get; set; } + + /// + /// Last start time the profile has been executed + /// + public DateTime? LastExecutionStartUtc { get; set; } + + /// + /// /// Last end time the profile has been executed + /// + public DateTime? LastExecutionEndUtc { get; set; } + + /// + /// Message of the last execution + /// + public string LastExecutionMessage { get; set; } + + /// + /// The scheduling task + /// + public virtual ScheduleTask ScheduleTask { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index f1c102b6d5..e4f7dc5af8 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -159,6 +159,7 @@ + @@ -595,6 +596,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Setup/Builder/PermissionMigrator.cs b/src/Libraries/SmartStore.Data/Setup/Builder/PermissionMigrator.cs new file mode 100644 index 0000000000..fe509e1cdf --- /dev/null +++ b/src/Libraries/SmartStore.Data/Setup/Builder/PermissionMigrator.cs @@ -0,0 +1,55 @@ +using System.Data.Entity; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Security; + +namespace SmartStore.Data.Setup +{ + internal class PermissionMigrator + { + private readonly SmartObjectContext _ctx; + private readonly DbSet _permissionRecords; + private readonly IQueryable _customerRoles; + + public PermissionMigrator(SmartObjectContext ctx) + { + Guard.ArgumentNotNull(() => ctx); + + _ctx = ctx; + _permissionRecords = _ctx.Set(); + _customerRoles = _ctx.Set().Expand(x => x.PermissionRecords); + } + + public void AddPermission(PermissionRecord permission, string[] rolesToMap) + { + Guard.ArgumentNotNull(() => permission); + Guard.ArgumentNotNull(() => rolesToMap); + + if (permission.SystemName.IsEmpty()) + return; + + var permissionRecord = _permissionRecords.FirstOrDefault(x => x.SystemName == permission.SystemName); + + if (permissionRecord == null) + { + _permissionRecords.Add(permission); + + _ctx.SaveChanges(); + } + + permissionRecord = _permissionRecords.FirstOrDefault(x => x.SystemName == permission.SystemName); + + foreach (var roleName in rolesToMap) + { + var role = _customerRoles.FirstOrDefault(x => x.SystemName == roleName); + if (role != null && !role.PermissionRecords.Any(x => x.SystemName == permission.SystemName)) + { + role.PermissionRecords.Add(permissionRecord); + } + } + + _ctx.SaveChanges(); + } + } +} diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index a6fce9f98b..9bde1ba879 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -121,6 +121,7 @@ + @@ -331,6 +332,11 @@ 201507250039446_Merge2.cs + + + 201507301550466_ExportFramework.cs + + @@ -627,6 +633,9 @@ 201507250039446_Merge2.cs + + 201507301550466_ExportFramework.cs + diff --git a/src/Libraries/SmartStore.Services/ExportImport/ExportService.cs b/src/Libraries/SmartStore.Services/ExportImport/ExportService.cs new file mode 100644 index 0000000000..c19a63129a --- /dev/null +++ b/src/Libraries/SmartStore.Services/ExportImport/ExportService.cs @@ -0,0 +1,79 @@ +using System; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain; +using SmartStore.Core.Events; +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.ExportImport +{ + public partial class ExportService : IExportService + { + private readonly IRepository _exportProfileRepository; + private readonly IEventPublisher _eventPublisher; + private readonly Lazy _scheduleTaskService; + + public ExportService( + IRepository exportProfileRepository, + IEventPublisher eventPublisher, + Lazy scheduleTaskService) + { + _exportProfileRepository = exportProfileRepository; + _eventPublisher = eventPublisher; + _scheduleTaskService = scheduleTaskService; + } + + #region Export profiles + + public virtual void InsertExportProfile(ExportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + _exportProfileRepository.Insert(profile); + + _eventPublisher.EntityInserted(profile); + } + + public virtual void UpdateExportProfile(ExportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + _exportProfileRepository.Update(profile); + + _eventPublisher.EntityUpdated(profile); + } + + public virtual void DeleteExportProfile(ExportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + if (profile.ScheduleTask != null) + { + _scheduleTaskService.Value.DeleteTask(profile.ScheduleTask); + } + + _exportProfileRepository.Delete(profile); + + _eventPublisher.EntityDeleted(profile); + } + + public virtual IQueryable GetExportProfiles(bool? enabled = null) + { + var query = + from x in _exportProfileRepository.Table.Expand(x => x.ScheduleTask) + select x; + + if (enabled.HasValue) + { + query = query.Where(x => x.Enabled == enabled.Value); + } + + return query.OrderBy(x => x.Name); + } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Services/ExportImport/IExportService.cs b/src/Libraries/SmartStore.Services/ExportImport/IExportService.cs new file mode 100644 index 0000000000..0e8389011b --- /dev/null +++ b/src/Libraries/SmartStore.Services/ExportImport/IExportService.cs @@ -0,0 +1,33 @@ +using System.Linq; +using SmartStore.Core.Domain; + +namespace SmartStore.Services.ExportImport +{ + public interface IExportService + { + /// + /// Inserts an export profile + /// + /// Export profile + void InsertExportProfile(ExportProfile profile); + + /// + /// Updates an export profile + /// + /// Export profile + void UpdateExportProfile(ExportProfile profile); + + /// + /// Deletes an export profile + /// + /// Export profile + void DeleteExportProfile(ExportProfile profile); + + /// + /// Get queryable export profiles + /// + /// Whether to filter enabled or disabled profiles + /// + IQueryable GetExportProfiles(bool? enabled = null); + } +} diff --git a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs index 01b83e6a38..7018c51146 100644 --- a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs +++ b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs @@ -49,6 +49,7 @@ public partial class StandardPermissionProvider : IPermissionProvider public static readonly PermissionRecord ManageMaintenance = new PermissionRecord { Name = "Admin area. Manage Maintenance", SystemName = "ManageMaintenance", Category = "Configuration" }; public static readonly PermissionRecord UploadPictures = new PermissionRecord { Name = "Admin area. Upload Pictures", SystemName = "UploadPictures", Category = "Configuration" }; public static readonly PermissionRecord ManageScheduleTasks = new PermissionRecord { Name = "Admin area. Manage Schedule Tasks", SystemName = "ManageScheduleTasks", Category = "Configuration" }; + public static readonly PermissionRecord ManageExports = new PermissionRecord { Name = "Admin area. Manage Exports", SystemName = "ManageExports", Category = "Configuration" }; //public store permissions @@ -103,6 +104,7 @@ public virtual IEnumerable GetPermissions() ManageMaintenance, UploadPictures, ManageScheduleTasks, + ManageExports, DisplayPrices, EnableShoppingCart, EnableWishlist, @@ -160,6 +162,7 @@ public virtual IEnumerable GetDefaultPermissions() ManageMaintenance, UploadPictures, ManageScheduleTasks, + ManageExports, DisplayPrices, EnableShoppingCart, EnableWishlist, diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 49e1c86d78..33484e0895 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -162,6 +162,8 @@ + + diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 99d42a6b9c..29357d57db 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -223,6 +223,8 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b .InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs new file mode 100644 index 0000000000..839265dfef --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -0,0 +1,73 @@ +using System.Linq; +using System.Web.Mvc; +using SmartStore.Admin.Models.Export; +using SmartStore.Core; +using SmartStore.Core.Domain; +using SmartStore.Services; +using SmartStore.Services.ExportImport; +using SmartStore.Services.Security; +using SmartStore.Web.Framework.Controllers; +using Telerik.Web.Mvc; + +namespace SmartStore.Admin.Controllers +{ + [AdminAuthorize] + public class ExportController : AdminControllerBase + { + private readonly ICommonServices _services; + private readonly IExportService _exportService; + + public ExportController( + ICommonServices services, + IExportService exportService) + { + _services = services; + _exportService = exportService; + } + + public ActionResult Index() + { + return RedirectToAction("List"); + } + + public ActionResult List() + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + return View(); + } + + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult List(GridCommand command) + { + var model = new GridModel(); + + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + { + var query = _exportService.GetExportProfiles(); + var profiles = query.ToList(); + + model.Total = profiles.Count; + + model.Data = profiles.Select(x => + { + var profileModel = new ExportProfileModel + { + Name = x.Name, + ProviderSystemName = x.ProviderSystemName, + EntityType = x.EntityType, + Enabled = x.Enabled, + FileType = "", // TODO + SchedulingHours = x.SchedulingHours, + LastExecution = "" // TODO + }; + + return profileModel; + }); + } + + return new JsonResult { Data = model }; + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs new file mode 100644 index 0000000000..c95bd05837 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs @@ -0,0 +1,31 @@ +using System.Web.Mvc; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Mvc; + +namespace SmartStore.Admin.Models.Export +{ + public partial class ExportProfileModel : EntityModelBase + { + [SmartResourceDisplayName("Admin.Configuration.Export.Name")] + public string Name { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.ProviderSystemName")] + public string ProviderSystemName { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.EntityType")] + public string EntityType { get; set; } + + [SmartResourceDisplayName("Common.Enabled")] + public bool Enabled { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.FileType")] + public string FileType { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.SchedulingHours")] + public int SchedulingHours { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.LastExecution")] + [AllowHtml] + public string LastExecution { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 209e12c89f..0f7013c4e4 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -175,6 +175,7 @@ + @@ -247,6 +248,7 @@ + @@ -498,6 +500,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml new file mode 100644 index 0000000000..17122852e5 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -0,0 +1,59 @@ +@using SmartStore.Admin.Models.Export +@using Telerik.Web.Mvc.UI +@{ + ViewBag.Title = T("Common.Export").Text; +} + +
    +
    + + @T("Common.Export") +
    + +
    + + + +
    + + + + +
    + @(Html.Telerik().Grid() + .Name("export-profile-grid") + .DataKeys(x => + { + x.Add(y => y.Id).RouteKey("Id"); + }) + .Columns(columns => + { + columns.Bound(x => x.Name) + .Width(400) + .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) + .ClientTemplate("\"><#= Name #>"); + columns.Bound(x => x.ProviderSystemName); + columns.Bound(x => x.EntityType); + columns.Bound(x => x.Enabled) + .Width(100) + .Template(item => @Html.SymbolForBool(item.Enabled)) + .ClientTemplate(@Html.SymbolForBool("Enabled")) + .Centered(); + columns.Bound(x => x.FileType); + columns.Bound(x => x.SchedulingHours); + columns.Bound(x => x.LastExecution) + .ReadOnly(); + }) + .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "Export")) + .ClientEvents(events => events.OnRowDataBound("onRowDataBound_ExportProfiles")) + .EnableCustomBinding(true)) +
    +
    diff --git a/src/Presentation/SmartStore.Web/Administration/sitemap.config b/src/Presentation/SmartStore.Web/Administration/sitemap.config index 33a9fd264f..0ba3a9156e 100644 --- a/src/Presentation/SmartStore.Web/Administration/sitemap.config +++ b/src/Presentation/SmartStore.Web/Administration/sitemap.config @@ -127,6 +127,8 @@ + + From 0b29a2a3f87f43d8acc49d252995bc5d80e463b2 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 31 Jul 2015 00:02:29 +0200 Subject: [PATCH 0136/1074] Changing an object state is only possible if an object state exists --- src/Libraries/SmartStore.Data/ObjectContextBase.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Libraries/SmartStore.Data/ObjectContextBase.cs b/src/Libraries/SmartStore.Data/ObjectContextBase.cs index fd6ad01650..48dd480551 100644 --- a/src/Libraries/SmartStore.Data/ObjectContextBase.cs +++ b/src/Libraries/SmartStore.Data/ObjectContextBase.cs @@ -19,6 +19,7 @@ using Microsoft.SqlServer.Management.Smo; using SmartStore.Core.Infrastructure; using SmartStore.Core.Events; +using System.Data.Entity.Core.Objects; namespace SmartStore.Data { @@ -532,7 +533,12 @@ public int DetachAll() public void ChangeState(TEntity entity, System.Data.Entity.EntityState newState) { - ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.ChangeObjectState(entity, newState); + var objectStateManager = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager; + + ObjectStateEntry entry; + + if (objectStateManager.TryGetObjectStateEntry(entity, out entry)) + objectStateManager.ChangeObjectState(entity, newState); } public bool SetToUnchanged(TEntity entity) From 44cafbe8c955705239913cef97ae3cc96b23bf31 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Fri, 31 Jul 2015 13:41:21 +0200 Subject: [PATCH 0137/1074] Altered systemname of purchase order number payment plugin --- .../Administration/Controllers/OrderController.cs | 2 +- src/Presentation/SmartStore.Web/Controllers/OrderController.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs index c4157b9b0a..7f7a8b5db3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/OrderController.cs @@ -346,7 +346,7 @@ protected void PrepareOrderDetailsModel(OrderModel model, Order order) var pm = _paymentService.LoadPaymentMethodBySystemName(order.PaymentMethodSystemName); if (pm != null) { - if (pm.Metadata.SystemName.Equals("Payments.PurchaseOrder", StringComparison.InvariantCultureIgnoreCase)) + if (pm.Metadata.SystemName.Equals("SmartStore.PurchaseOrderNumber", StringComparison.InvariantCultureIgnoreCase)) { model.DisplayPurchaseOrderNumber = true; model.PurchaseOrderNumber = order.PurchaseOrderNumber; diff --git a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs index 57c7c32649..f84d4e14bc 100644 --- a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs @@ -171,7 +171,7 @@ protected OrderDetailsModel PrepareOrderDetailsModel(Order order) model.CanRePostProcessPayment = _paymentService.CanRePostProcessPayment(order); //purchase order number (we have to find a better to inject this information because it's related to a certain plugin) - if (paymentMethod != null && paymentMethod.Metadata.SystemName.Equals("Payments.PurchaseOrder", StringComparison.InvariantCultureIgnoreCase)) + if (paymentMethod != null && paymentMethod.Metadata.SystemName.Equals("SmartStore.PurchaseOrderNumber", StringComparison.InvariantCultureIgnoreCase)) { model.DisplayPurchaseOrderNumber = true; model.PurchaseOrderNumber = order.PurchaseOrderNumber; From 14827cd5b33cbb2cc61d12dbe8704cce4d802532 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Mon, 3 Aug 2015 10:06:00 +0200 Subject: [PATCH 0138/1074] Editing an export profile --- .../Domain/Export/ExportCore.cs | 54 +++++ .../Domain/Export/ExportProfile.cs | 27 ++- .../SmartStore.Core/SmartStore.Core.csproj | 1 + src/Libraries/SmartStore.Core/XmlHelper.cs | 41 ++++ .../Mapping/Export/ExportProfileMap.cs | 4 +- .../201507301550466_ExportFramework.cs | 105 --------- .../201507301550466_ExportFramework.resx | 126 ----------- ...1508011828241_ExportFramework.Designer.cs} | 2 +- .../201508011828241_ExportFramework.cs | 157 ++++++++++++++ .../201508011828241_ExportFramework.resx | 126 +++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../Export/ExportExtensions.cs | 16 ++ .../Export/ExportService.cs | 146 +++++++++++++ .../Export/IExportProvider.cs | 16 ++ .../Export/IExportService.cs | 58 +++++ .../ExportImport/ExportService.cs | 79 ------- .../ExportImport/IExportService.cs | 33 --- .../SmartStore.Services.csproj | 6 +- .../DependencyRegistrar.cs | 6 + .../Administration/Content/admin.less | 1 - .../Controllers/ExportController.cs | 205 ++++++++++++++++-- .../Models/Export/ExportProfileModel.cs | 45 +++- .../Administration/SmartStore.Admin.csproj | 2 + .../Administration/Views/Export/Create.cshtml | 27 +++ .../Administration/Views/Export/Edit.cshtml | 135 ++++++++++++ .../Administration/Views/Export/List.cshtml | 115 +++++++++- .../Administration/sitemap.config | 2 +- 27 files changed, 1154 insertions(+), 391 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/Export/ExportCore.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.resx rename src/Libraries/SmartStore.Data/Migrations/{201507301550466_ExportFramework.Designer.cs => 201508011828241_ExportFramework.Designer.cs} (92%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.resx create mode 100644 src/Libraries/SmartStore.Services/Export/ExportExtensions.cs create mode 100644 src/Libraries/SmartStore.Services/Export/ExportService.cs create mode 100644 src/Libraries/SmartStore.Services/Export/IExportProvider.cs create mode 100644 src/Libraries/SmartStore.Services/Export/IExportService.cs delete mode 100644 src/Libraries/SmartStore.Services/ExportImport/ExportService.cs delete mode 100644 src/Libraries/SmartStore.Services/ExportImport/IExportService.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml diff --git a/src/Libraries/SmartStore.Core/Domain/Export/ExportCore.cs b/src/Libraries/SmartStore.Core/Domain/Export/ExportCore.cs new file mode 100644 index 0000000000..b5cca2b555 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Export/ExportCore.cs @@ -0,0 +1,54 @@ +using System; + +namespace SmartStore.Core.Domain.Export +{ + public enum ExportFileType + { + Xml = 0, + Xls, + Csv, + Txt, + Pdf + } + + + public enum ExportEntityType + { + Product = 0, + Category, + Manufacturer, + Customer, + Order + } + + + [Serializable] + public class ExportPartition + { + public ExportPartition() + { + Limit = 100; + BatchSize = 1000; + } + + /// + /// The number of records to be skipped + /// + public int Offset { get; set; } + + /// + /// How many records to be loaded per database round-trip + /// + public int Limit { get; set; } + + /// + /// The maximum number of records of one processed batch + /// + public int BatchSize { get; set; } + + /// + /// Whether to start a separate run-through for each store + /// + public bool PerStore { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs b/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs index bca569da98..ed71e475a0 100644 --- a/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs @@ -1,4 +1,5 @@ using System; +using SmartStore.Core.Domain.Export; using SmartStore.Core.Domain.Tasks; namespace SmartStore.Core.Domain @@ -11,24 +12,34 @@ public class ExportProfile : BaseEntity public string Name { get; set; } /// - /// Whether the export profile is enabled + /// The system name of the export provider /// - public bool Enabled { get; set; } + public string ProviderSystemName { get; set; } /// - /// The system name of the export provider + /// Whether the export profile is enabled /// - public string ProviderSystemName { get; set; } + public bool Enabled { get; set; } /// - /// The entity type to be exported + /// The export file type identifier /// - public string EntityType { get; set; } + public int FileTypeId { get; set; } /// - /// Number of hours after the profile is automatically executed by scheduling + /// The export file type /// - public int SchedulingHours { get; set; } + public ExportFileType FileType + { + get + { + return (ExportFileType)FileTypeId; + } + set + { + FileTypeId = (int)value; + } + } /// /// The scheduling task identifier diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index e4f7dc5af8..21718e5f5a 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -159,6 +159,7 @@ + diff --git a/src/Libraries/SmartStore.Core/XmlHelper.cs b/src/Libraries/SmartStore.Core/XmlHelper.cs index d8fd64a6ce..7f546eba8a 100644 --- a/src/Libraries/SmartStore.Core/XmlHelper.cs +++ b/src/Libraries/SmartStore.Core/XmlHelper.cs @@ -115,6 +115,47 @@ public static DateTime DeserializeDateTime(string dateTime) } } + /// + /// Serializes an object instance to a XML formatted string + /// + /// Object type + /// Object instance + /// XML + public static string Serialize(T instance) + { + if (instance != null) + { + using (var writer = new StringWriter()) + { + var xmlSerializer = new XmlSerializer(typeof(T)); + + xmlSerializer.Serialize(writer, instance); + return writer.ToString(); + } + } + return null; + } + + /// + /// Deserializes a XML formatted string to an object instance + /// + /// Object type + /// XML + /// Object instance + public static T Deserialize(string xml) + { + if (xml.HasValue()) + { + using (var reader = new StringReader(xml)) + { + var serializer = new XmlSerializer(typeof(T)); + + return (T)serializer.Deserialize(reader); + } + } + return (T)Activator.CreateInstance(typeof(T)); + } + #endregion } } diff --git a/src/Libraries/SmartStore.Data/Mapping/Export/ExportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/Export/ExportProfileMap.cs index 96538c9c74..a6e66ad885 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Export/ExportProfileMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/Export/ExportProfileMap.cs @@ -12,12 +12,12 @@ public ExportProfileMap() this.Property(x => x.Name).IsRequired().HasMaxLength(100); this.Property(x => x.ProviderSystemName).IsRequired().HasMaxLength(4000); - this.Property(x => x.EntityType).IsRequired().HasMaxLength(100); - this.Property(x => x.EntityType).IsRequired().HasMaxLength(100); this.Property(x => x.Partitioning).IsMaxLength(); this.Property(x => x.Filtering).IsMaxLength(); this.Property(x => x.LastExecutionMessage).HasMaxLength(4000); + this.Ignore(x => x.FileType); + this.HasRequired(x => x.ScheduleTask) .WithMany() .HasForeignKey(x => x.SchedulingTaskId) diff --git a/src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.cs deleted file mode 100644 index f4c69b6734..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.cs +++ /dev/null @@ -1,105 +0,0 @@ -namespace SmartStore.Data.Migrations -{ - using System.Data.Entity.Migrations; - using SmartStore.Core.Domain.Customers; - using SmartStore.Core.Domain.Security; - using SmartStore.Data.Setup; - - public partial class ExportFramework : DbMigration, ILocaleResourcesProvider, IDataSeeder - { - public override void Up() - { - CreateTable( - "dbo.ExportProfile", - c => new - { - Id = c.Int(nullable: false, identity: true), - Name = c.String(nullable: false, maxLength: 100), - Enabled = c.Boolean(nullable: false), - ProviderSystemName = c.String(nullable: false, maxLength: 4000), - EntityType = c.String(nullable: false, maxLength: 100), - SchedulingHours = c.Int(nullable: false), - SchedulingTaskId = c.Int(nullable: false), - ProfileGuid = c.Guid(nullable: false), - Partitioning = c.String(), - Filtering = c.String(), - LastExecutionStartUtc = c.DateTime(), - LastExecutionEndUtc = c.DateTime(), - LastExecutionMessage = c.String(maxLength: 4000), - }) - .PrimaryKey(t => t.Id) - .ForeignKey("dbo.ScheduleTask", t => t.SchedulingTaskId) - .Index(t => t.SchedulingTaskId); - - } - - public override void Down() - { - DropForeignKey("dbo.ExportProfile", "SchedulingTaskId", "dbo.ScheduleTask"); - DropIndex("dbo.ExportProfile", new[] { "SchedulingTaskId" }); - DropTable("dbo.ExportProfile"); - } - - public bool RollbackOnFailure - { - get { return false; } - } - - public void Seed(SmartObjectContext context) - { - context.MigrateLocaleResources(MigrateLocaleResources); - - var permissionMigrator = new PermissionMigrator(context); - - permissionMigrator.AddPermission(new PermissionRecord - { - Name = "Admin area. Manage Exports", - SystemName = "ManageExports", - Category = "Configuration" - }, new string[] { SystemCustomerRoleNames.Administrators }); - } - - public void MigrateLocaleResources(LocaleResourcesBuilder builder) - { - builder.AddOrUpdate("Common.Enabled", - "Enabled", - "Aktiviert"); - - builder.AddOrUpdate("Admin.Configuration.Export.Name", - "Profile name", - "Profilname", - "Specifies the name of the export profile.", - "Legt den Namen des Exportprofils fest."); - - builder.AddOrUpdate("Admin.Configuration.Export.ProviderSystemName", - "Provider name", - "Provider-Name", - "Specifies the name of the export provider.", - "Legt den Namen des Export-Providers fest."); - - builder.AddOrUpdate("Admin.Configuration.Export.EntityType", - "Entity type", - "Entittstyp", - "Specifies the type of the entity to be exported.", - "Legt den Typ der zu exportierenden Entitt fest."); - - builder.AddOrUpdate("Admin.Configuration.Export.FileType", - "File type", - "Dateityp", - "The file type of the exported data.", - "Der Dateityp der exportierten Daten."); - - builder.AddOrUpdate("Admin.Configuration.Export.SchedulingHours", - "Hours (interval)", - "Stunden (Intervall)", - "Specifies the interval in hours to which the export should execute automatically.", - "Legt das Intervall in Stunden fest, zu dem der Export automatisch erfolgen soll."); - - builder.AddOrUpdate("Admin.Configuration.Export.LastExecution", - "Last execution", - "Letzte Ausfhrung", - "Information about the last execution of the export.", - "Informationen zur letzten Ausfhrung des Exports."); - } - } -} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.resx deleted file mode 100644 index a08ee1d639..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.Designer.cs index 4e2831a004..0e3246e714 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201507301550466_ExportFramework.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class ExportFramework : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201507301550466_ExportFramework"; } + get { return "201508011828241_ExportFramework"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.cs new file mode 100644 index 0000000000..86c6f7c509 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.cs @@ -0,0 +1,157 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Customers; + using SmartStore.Core.Domain.Security; + using SmartStore.Data.Setup; + + public partial class ExportFramework : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.ExportProfile", + c => new + { + Id = c.Int(nullable: false, identity: true), + Name = c.String(nullable: false, maxLength: 100), + ProviderSystemName = c.String(nullable: false, maxLength: 4000), + Enabled = c.Boolean(nullable: false), + FileTypeId = c.Int(nullable: false), + SchedulingTaskId = c.Int(nullable: false), + ProfileGuid = c.Guid(nullable: false), + Partitioning = c.String(), + Filtering = c.String(), + LastExecutionStartUtc = c.DateTime(), + LastExecutionEndUtc = c.DateTime(), + LastExecutionMessage = c.String(maxLength: 4000), + }) + .PrimaryKey(t => t.Id) + .ForeignKey("dbo.ScheduleTask", t => t.SchedulingTaskId) + .Index(t => t.SchedulingTaskId); + + } + + public override void Down() + { + DropForeignKey("dbo.ExportProfile", "SchedulingTaskId", "dbo.ScheduleTask"); + DropIndex("dbo.ExportProfile", new[] { "SchedulingTaskId" }); + DropTable("dbo.ExportProfile"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var permissionMigrator = new PermissionMigrator(context); + + permissionMigrator.AddPermission(new PermissionRecord + { + Name = "Admin area. Manage Exports", + SystemName = "ManageExports", + Category = "Configuration" + }, new string[] { SystemCustomerRoleNames.Administrators }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Enabled", "Enabled", "Aktiviert"); + builder.AddOrUpdate("Common.Provider", "Provider", "Provider"); + builder.AddOrUpdate("Common.Profile", "Profile", "Profil"); + builder.AddOrUpdate("Common.Partition", "Partition", "Aufteilung"); + builder.AddOrUpdate("Common.Image", "Image", "Bild"); + + + builder.AddOrUpdate("Admin.Configuration.Export.ProviderSystemName.Validate", + "There were no export provider found for system name \"{0}\". A provider is mandatory for an export profile.", + "Es wurde kein Export-Provider mit dem Systemnamen \"{0}\" gefunden. Ein Provider ist fr ein Exportprofil zwingend erforderlich."); + + builder.AddOrUpdate("Admin.Configuration.Export.NoProfiles", + "There were no export profiles found.", + "Es wurden keine Exportprofile gefunden."); + + + builder.AddOrUpdate("Admin.Configuration.Export.ProviderSystemName", + "Provider", + "Provider", + "Specifies the export provider. It is responsible for the individual formatting of the export data.", + "Legt den Export-Provider fest. Er ist fr die individuelle Formatierung der zu exportierenden Daten zustndig."); + + builder.AddOrUpdate("Admin.Configuration.Export.EntityType", + "Entity", + "Entitt", + "The entity type the provider processes.", + "Der Entittstyp, den der Provider verarbeitet."); + + + builder.AddOrUpdate("Admin.Configuration.Export.Name", + "Name of profile", + "Name des Profils", + "Specifies the name of the export profile.", + "Legt den Namen des Exportprofils fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.FileType", + "File type", + "Dateityp", + "The file type of the exported data.", + "Der Dateityp der exportierten Daten."); + + builder.AddOrUpdate("Admin.Configuration.Export.SchedulingHours", + "Hours (interval)", + "Stunden (Intervall)", + "Specifies the interval in hours to which the export should execute automatically.", + "Legt das Intervall in Stunden fest, zu dem der Export automatisch erfolgen soll."); + + builder.AddOrUpdate("Admin.Configuration.Export.LastExecution", + "Last execution", + "Letzte Ausfhrung", + "Information about the last execution of the export.", + "Informationen zur letzten Ausfhrung des Exports."); + + + builder.AddOrUpdate("Admin.Configuration.Export.Segmentation.Offset", + "Offset", + "Abstand", + "Specifies the number of records to be skipped.", + "Legt die Anzahl der zu berspringenden Datenstze fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Segmentation.Limit", + "Limit", + "Begrenzung", + "Specifies how many records to be loaded per database round-trip.", + "Legt die Anzahl der Datenstze fest, die pro Datenbankaufruf geladen werden sollen."); + + builder.AddOrUpdate("Admin.Configuration.Export.Segmentation.BatchSize", + "Batch size", + "Stapelgre", + "Specifies the maximum number of records of one processed batch.", + "Legt die maximale Anzahl der Datenstze eines Vearbeitungsstapels fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Segmentation.PerStore", + "Per store", + "Per Shop", + "Specifies whether to start a separate run-through for each store.", + "Legt fest, ob fr jeden Shop ein separater Verarbeitungsdurchlauf erfolgen soll."); + + + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Xml", "XML (Extensible Markup Language)", "XML (Extensible Markup Language)"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Xls", "XLS (Microsoft Excel)", "XLS (Microsoft Excel)"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Csv", "CSV (Delimiter Separated Values)", "CSV (Trennzeichen getrennt)"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Txt", "TXT (Plain text)", "TXT (Einfacher Text)"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Pdf", "PDF (Portable Document Format)", "PDF (Portables Dokumentenformat)"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Product", "Product", "Produkt"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Category", "Category", "Warengruppe"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Manufacturer", "Manufacturer", "Hersteller"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Customer", "Customer", "Kunde"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Order", "Order", "Auftrag"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.resx new file mode 100644 index 0000000000..ce78c71be0 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 9bde1ba879..b39ffa09d7 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -332,9 +332,9 @@ 201507250039446_Merge2.cs - - - 201507301550466_ExportFramework.cs + + + 201508011828241_ExportFramework.cs @@ -633,8 +633,8 @@ 201507250039446_Merge2.cs - - 201507301550466_ExportFramework.cs + + 201508011828241_ExportFramework.cs diff --git a/src/Libraries/SmartStore.Services/Export/ExportExtensions.cs b/src/Libraries/SmartStore.Services/Export/ExportExtensions.cs new file mode 100644 index 0000000000..3ea12ec406 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Export/ExportExtensions.cs @@ -0,0 +1,16 @@ +using System.Linq; +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.Export +{ + public static class ExportExtensions + { + public static bool IsValid(this Provider provider) + { + return ( + provider != null && + provider.Value.SupportedFileTypes != null && provider.Value.SupportedFileTypes.Any() + ); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Export/ExportService.cs b/src/Libraries/SmartStore.Services/Export/ExportService.cs new file mode 100644 index 0000000000..14be36fc7e --- /dev/null +++ b/src/Libraries/SmartStore.Services/Export/ExportService.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Events; +using SmartStore.Core.Plugins; +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.Export +{ + public partial class ExportService : IExportService + { + private const int _defaultSchedulingHours = 6; + + private readonly IRepository _exportProfileRepository; + private readonly IEventPublisher _eventPublisher; + private readonly IScheduleTaskService _scheduleTaskService; + private readonly IProviderManager _providerManager; + + public ExportService( + IRepository exportProfileRepository, + IEventPublisher eventPublisher, + IScheduleTaskService scheduleTaskService, + IProviderManager providerManager) + { + _exportProfileRepository = exportProfileRepository; + _eventPublisher = eventPublisher; + _scheduleTaskService = scheduleTaskService; + _providerManager = providerManager; + } + + #region Export profiles + + public virtual ExportProfile InsertExportProfile(Provider provider) + { + if (provider == null) + throw new ArgumentNullException("provider"); + + var guid = Guid.NewGuid(); + var name = provider.Metadata.FriendlyName; + var systemName = provider.Metadata.SystemName; + var taskType = "SmartStore.Services.ExportImport.{0}Task.{1}, SmartStore.Services".FormatInvariant(systemName, guid.ToString().Replace("-", "")); + + if (name.IsEmpty()) + name = systemName; + + var task = new ScheduleTask + { + Name = string.Concat(name, " Export Task"), + Seconds = _defaultSchedulingHours * 3600, + Type = taskType, + Enabled = false, + StopOnError = false, + IsHidden = true + }; + + _scheduleTaskService.InsertTask(task); + + var profile = new ExportProfile + { + Name = name, + Enabled = true, + ProviderSystemName = systemName, + ProfileGuid = guid, + SchedulingTaskId = task.Id, + FileType = provider.Value.SupportedFileTypes.FirstOrDefault() + }; + + _exportProfileRepository.Insert(profile); + + task.Alias = profile.Id.ToString(); + _scheduleTaskService.UpdateTask(task); + + _eventPublisher.EntityInserted(profile); + + return profile; + } + + public virtual void UpdateExportProfile(ExportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + _exportProfileRepository.Update(profile); + + _eventPublisher.EntityUpdated(profile); + } + + public virtual void DeleteExportProfile(ExportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + int scheduleTaskId = profile.SchedulingTaskId; + + _exportProfileRepository.Delete(profile); + + var scheduleTask = _scheduleTaskService.GetTaskById(scheduleTaskId); + _scheduleTaskService.DeleteTask(scheduleTask); + + _eventPublisher.EntityDeleted(profile); + } + + public virtual IQueryable GetExportProfiles(bool? enabled = null) + { + var query = + from x in _exportProfileRepository.Table.Expand(x => x.ScheduleTask) + select x; + + if (enabled.HasValue) + { + query = query.Where(x => x.Enabled == enabled.Value); + } + + return query.OrderBy(x => x.Name); + } + + public virtual ExportProfile GetExportProfileById(int id) + { + if (id == 0) + return null; + + return _exportProfileRepository.GetById(id); + } + + + public virtual IEnumerable> LoadAllExportProviders(int storeId = 0) + { + var allProviders = _providerManager.GetAllProviders(storeId) + .Where(x => x.IsValid()); + + return allProviders; + } + + public virtual Provider LoadProvider(string systemName, int storeId = 0) + { + var provider = _providerManager.GetProvider(systemName, storeId); + + return (provider.IsValid() ? provider : null); + } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Services/Export/IExportProvider.cs b/src/Libraries/SmartStore.Services/Export/IExportProvider.cs new file mode 100644 index 0000000000..752f6096ed --- /dev/null +++ b/src/Libraries/SmartStore.Services/Export/IExportProvider.cs @@ -0,0 +1,16 @@ +using System.IO; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Export; +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.Export +{ + public partial interface IExportProvider : IProvider, IUserEditable + { + MemoryStream Execute(ExportProfile profile); + + ExportFileType[] SupportedFileTypes { get; } + + ExportEntityType EntityType { get; } + } +} diff --git a/src/Libraries/SmartStore.Services/Export/IExportService.cs b/src/Libraries/SmartStore.Services/Export/IExportService.cs new file mode 100644 index 0000000000..3e8e2e60df --- /dev/null +++ b/src/Libraries/SmartStore.Services/Export/IExportService.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core.Domain; +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.Export +{ + public interface IExportService + { + /// + /// Inserts an export profile + /// + /// Export provider + /// New export profile + ExportProfile InsertExportProfile(Provider provider); + + /// + /// Updates an export profile + /// + /// Export profile + void UpdateExportProfile(ExportProfile profile); + + /// + /// Deletes an export profile + /// + /// Export profile + void DeleteExportProfile(ExportProfile profile); + + /// + /// Get queryable export profiles + /// + /// Whether to filter enabled or disabled profiles + /// Export profiles + IQueryable GetExportProfiles(bool? enabled = null); + + /// + /// Gets an export profile by identifier + /// + /// Export profile identifier + /// Export profile + ExportProfile GetExportProfileById(int id); + + /// + /// Load all export providers + /// + /// Store identifier + /// Export providers + IEnumerable> LoadAllExportProviders(int storeId = 0); + + /// + /// Load export provider by system name + /// + /// Provider system name + /// Store identifier + /// Export provider + Provider LoadProvider(string systemName, int storeId = 0); + } +} diff --git a/src/Libraries/SmartStore.Services/ExportImport/ExportService.cs b/src/Libraries/SmartStore.Services/ExportImport/ExportService.cs deleted file mode 100644 index c19a63129a..0000000000 --- a/src/Libraries/SmartStore.Services/ExportImport/ExportService.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Linq; -using SmartStore.Core.Data; -using SmartStore.Core.Domain; -using SmartStore.Core.Events; -using SmartStore.Services.Tasks; - -namespace SmartStore.Services.ExportImport -{ - public partial class ExportService : IExportService - { - private readonly IRepository _exportProfileRepository; - private readonly IEventPublisher _eventPublisher; - private readonly Lazy _scheduleTaskService; - - public ExportService( - IRepository exportProfileRepository, - IEventPublisher eventPublisher, - Lazy scheduleTaskService) - { - _exportProfileRepository = exportProfileRepository; - _eventPublisher = eventPublisher; - _scheduleTaskService = scheduleTaskService; - } - - #region Export profiles - - public virtual void InsertExportProfile(ExportProfile profile) - { - if (profile == null) - throw new ArgumentNullException("profile"); - - _exportProfileRepository.Insert(profile); - - _eventPublisher.EntityInserted(profile); - } - - public virtual void UpdateExportProfile(ExportProfile profile) - { - if (profile == null) - throw new ArgumentNullException("profile"); - - _exportProfileRepository.Update(profile); - - _eventPublisher.EntityUpdated(profile); - } - - public virtual void DeleteExportProfile(ExportProfile profile) - { - if (profile == null) - throw new ArgumentNullException("profile"); - - if (profile.ScheduleTask != null) - { - _scheduleTaskService.Value.DeleteTask(profile.ScheduleTask); - } - - _exportProfileRepository.Delete(profile); - - _eventPublisher.EntityDeleted(profile); - } - - public virtual IQueryable GetExportProfiles(bool? enabled = null) - { - var query = - from x in _exportProfileRepository.Table.Expand(x => x.ScheduleTask) - select x; - - if (enabled.HasValue) - { - query = query.Where(x => x.Enabled == enabled.Value); - } - - return query.OrderBy(x => x.Name); - } - - #endregion - } -} diff --git a/src/Libraries/SmartStore.Services/ExportImport/IExportService.cs b/src/Libraries/SmartStore.Services/ExportImport/IExportService.cs deleted file mode 100644 index 0e8389011b..0000000000 --- a/src/Libraries/SmartStore.Services/ExportImport/IExportService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Linq; -using SmartStore.Core.Domain; - -namespace SmartStore.Services.ExportImport -{ - public interface IExportService - { - /// - /// Inserts an export profile - /// - /// Export profile - void InsertExportProfile(ExportProfile profile); - - /// - /// Updates an export profile - /// - /// Export profile - void UpdateExportProfile(ExportProfile profile); - - /// - /// Deletes an export profile - /// - /// Export profile - void DeleteExportProfile(ExportProfile profile); - - /// - /// Get queryable export profiles - /// - /// Whether to filter enabled or disabled profiles - /// - IQueryable GetExportProfiles(bool? enabled = null); - } -} diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 33484e0895..db5a654dd3 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -162,8 +162,10 @@ - - + + + + diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index 29357d57db..e361097cc9 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -41,6 +41,7 @@ using SmartStore.Services.Directory; using SmartStore.Services.Discounts; using SmartStore.Services.Events; +using SmartStore.Services.Export; using SmartStore.Services.ExportImport; using SmartStore.Services.Filter; using SmartStore.Services.Forums; @@ -794,6 +795,7 @@ protected override void Load(ContainerBuilder builder) RegisterAsSpecificProvider(type, systemName, registration); RegisterAsSpecificProvider(type, systemName, registration); RegisterAsSpecificProvider(type, systemName, registration); + RegisterAsSpecificProvider(type, systemName, registration); } } @@ -919,6 +921,10 @@ private string ProviderTypeToKnownGroupName(Type implType) { return "CMS"; } + else if (typeof(IExportProvider).IsAssignableFrom(implType)) + { + return "Exporting"; + } return null; } diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index 75d3bfcdb8..dcb332fcb7 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -738,7 +738,6 @@ td.adminTitle > .ctl-label { label { display: inline-block; padding-right: 20px; - margin-top: 1px; margin-bottom: 0; } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 839265dfef..cd8bf2190a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -1,12 +1,18 @@ -using System.Linq; +using System; +using System.Collections.Generic; +using System.Linq; using System.Web.Mvc; using SmartStore.Admin.Models.Export; using SmartStore.Core; using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Export; +using SmartStore.Core.Plugins; using SmartStore.Services; -using SmartStore.Services.ExportImport; +using SmartStore.Services.Export; +using SmartStore.Services.Media; using SmartStore.Services.Security; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Plugins; using Telerik.Web.Mvc; namespace SmartStore.Admin.Controllers @@ -16,13 +22,62 @@ public class ExportController : AdminControllerBase { private readonly ICommonServices _services; private readonly IExportService _exportService; + private readonly PluginMediator _pluginMediator; + private readonly IPictureService _pictureService; public ExportController( ICommonServices services, - IExportService exportService) + IExportService exportService, + PluginMediator pluginMediator, + IPictureService pictureService) { _services = services; _exportService = exportService; + _pluginMediator = pluginMediator; + _pictureService = pictureService; + } + + private void PrepareExportProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) + { + var partition = XmlHelper.Deserialize(profile.Partitioning); + + model.AvailableFileTypes = new List(); + + model.Id = profile.Id; + model.Name = profile.Name; + model.ProviderSystemName = profile.ProviderSystemName; + model.Enabled = profile.Enabled; + model.FileType = profile.FileType; + model.FileTypeName = profile.FileType.ToString().ToUpper(); + model.SchedulingHours = profile.ScheduleTask.Seconds / 3600; + + model.Offset = partition.Offset; + model.Limit = partition.Limit; + model.BatchSize = partition.BatchSize; + model.PerStore = partition.PerStore; + + if (provider != null) + { + model.ThumbnailUrl = _pluginMediator.GetIconUrl(provider.Metadata); + + if (model.ThumbnailUrl.IsEmpty()) + model.ThumbnailUrl = _pictureService.GetDefaultPictureUrl(48); + else + model.ThumbnailUrl = Url.Content(model.ThumbnailUrl); + + model.ProviderFriendlyName = _pluginMediator.GetLocalizedFriendlyName(provider.Metadata); + + model.EntityType = T("Enums.SmartStore.Core.Domain.ExportEntityType." + provider.Value.EntityType.ToString()); + + foreach (var fileType in provider.Value.SupportedFileTypes) + { + model.AvailableFileTypes.Add(new SelectListItem + { + Text = T("Enums.SmartStore.Core.Domain.ExportFileType." + fileType.ToString()), + Value = ((int)fileType).ToString() + }); + } + } } public ActionResult Index() @@ -45,6 +100,7 @@ public ActionResult List(GridCommand command) if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) { + var providers = _exportService.LoadAllExportProviders().ToList(); var query = _exportService.GetExportProfiles(); var profiles = query.ToList(); @@ -52,16 +108,8 @@ public ActionResult List(GridCommand command) model.Data = profiles.Select(x => { - var profileModel = new ExportProfileModel - { - Name = x.Name, - ProviderSystemName = x.ProviderSystemName, - EntityType = x.EntityType, - Enabled = x.Enabled, - FileType = "", // TODO - SchedulingHours = x.SchedulingHours, - LastExecution = "" // TODO - }; + var profileModel = new ExportProfileModel(); + PrepareExportProfileModel(profileModel, x, providers.FirstOrDefault(y => y.Metadata.SystemName == x.ProviderSystemName)); return profileModel; }); @@ -69,5 +117,136 @@ public ActionResult List(GridCommand command) return new JsonResult { Data = model }; } + + public ActionResult Create() + { + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + { + var model = new ExportProfileModel(); + + model.AvailableExportProviders = _exportService.LoadAllExportProviders() + .Select(x => + { + var item = new SelectListItem + { + Text = x.Metadata.FriendlyName, + Value = x.Metadata.SystemName + }; + + return item; + }).ToList(); + + return PartialView(model); + } + + return Content(T("Admin.AccessDenied.Description")); + } + + [HttpPost] + public ActionResult Create(ExportProfileModel model) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + if (model.ProviderSystemName.HasValue()) + { + var provider = _exportService.LoadProvider(model.ProviderSystemName); + if (provider != null) + { + var profile = _exportService.InsertExportProfile(provider); + + PrepareExportProfileModel(model, profile, provider); + + return RedirectToAction("Edit", new { id = profile.Id }); + } + } + + NotifyError(T("Admin.Configuration.Export.ProviderSystemName.Validate", model.ProviderSystemName.NaIfEmpty())); + + return RedirectToAction("List"); + } + + public ActionResult Edit(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var profile = _exportService.GetExportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + var provider = _exportService.LoadProvider(profile.ProviderSystemName); + + var model = new ExportProfileModel(); + + PrepareExportProfileModel(model, profile, provider); + + return View(model); + } + + [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] + [FormValueRequired("save", "save-continue")] + public ActionResult Edit(ExportProfileModel model, bool continueEditing) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var profile = _exportService.GetExportProfileById(model.Id); + if (profile == null) + return RedirectToAction("List"); + + if (ModelState.IsValid) + { + var partition = new ExportPartition + { + Offset = model.Offset, + Limit = model.Limit, + BatchSize = model.BatchSize, + PerStore = model.PerStore + }; + + profile.Name = model.Name; + profile.Enabled = model.Enabled; + profile.ScheduleTask.Seconds = model.SchedulingHours * 3600; + profile.FileType = model.FileType; + profile.Partitioning = XmlHelper.Serialize(partition); + + _exportService.UpdateExportProfile(profile); + + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + + return (continueEditing ? RedirectToAction("Edit", new { id = profile.Id }) : RedirectToAction("List")); + } + + PrepareExportProfileModel(model, profile, _exportService.LoadProvider(model.ProviderSystemName)); + + return View(model); + } + + [HttpPost, ActionName("Delete")] + public ActionResult DeleteConfirmed(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var profile = _exportService.GetExportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + try + { + _exportService.DeleteExportProfile(profile); + + NotifySuccess(T("Admin.Common.TaskSuccessfullyProcessed")); + + return RedirectToAction("List"); + } + catch (Exception exc) + { + NotifyError(exc); + } + + return RedirectToAction("Edit", new { id = profile.Id }); + } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs index c95bd05837..547211434c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs @@ -1,4 +1,6 @@ -using System.Web.Mvc; +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Core.Domain.Export; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Mvc; @@ -6,20 +8,42 @@ namespace SmartStore.Admin.Models.Export { public partial class ExportProfileModel : EntityModelBase { - [SmartResourceDisplayName("Admin.Configuration.Export.Name")] - public string Name { get; set; } + [SmartResourceDisplayName("Common.Image")] + public string ThumbnailUrl { get; set; } + public string ThumbnailClasses + { + get + { + return "grid-icon"; + } + } [SmartResourceDisplayName("Admin.Configuration.Export.ProviderSystemName")] public string ProviderSystemName { get; set; } + public List AvailableExportProviders { get; set; } + + [SmartResourceDisplayName("Common.Provider")] + public string ProviderFriendlyName { get; set; } [SmartResourceDisplayName("Admin.Configuration.Export.EntityType")] public string EntityType { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Export.SupportedFileTypes")] + public string SupportedFileTypes { get; set; } + + + [SmartResourceDisplayName("Admin.Configuration.Export.Name")] + public string Name { get; set; } + [SmartResourceDisplayName("Common.Enabled")] public bool Enabled { get; set; } [SmartResourceDisplayName("Admin.Configuration.Export.FileType")] - public string FileType { get; set; } + public ExportFileType FileType { get; set; } + public List AvailableFileTypes { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.FileType")] + public string FileTypeName { get; set; } [SmartResourceDisplayName("Admin.Configuration.Export.SchedulingHours")] public int SchedulingHours { get; set; } @@ -27,5 +51,18 @@ public partial class ExportProfileModel : EntityModelBase [SmartResourceDisplayName("Admin.Configuration.Export.LastExecution")] [AllowHtml] public string LastExecution { get; set; } + + + [SmartResourceDisplayName("Admin.Configuration.Export.Segmentation.Offset")] + public int Offset { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Segmentation.Limit")] + public int Limit { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Segmentation.BatchSize")] + public int BatchSize { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Segmentation.PerStore")] + public bool PerStore { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 0f7013c4e4..ef978b7e3a 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -501,6 +501,8 @@ + + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml new file mode 100644 index 0000000000..b6f318d5b4 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml @@ -0,0 +1,27 @@ +@using SmartStore.Admin.Models.Export +@model ExportProfileModel +@{ + Layout = null; +} + +
    + @if(Model.AvailableExportProviders.Count > 0) + { +
    + + + + + +
    + @Html.SmartLabelFor(model => model.ProviderSystemName) + + @Html.DropDownListFor(model => model.ProviderSystemName, Model.AvailableExportProviders) +
    +
    + } + else + { + @T("Admin.Configuration.Export.NoProfiles") + } +
    \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml new file mode 100644 index 0000000000..1a594c0333 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -0,0 +1,135 @@ +@model ExportProfileModel +@using SmartStore.Core.Domain.Export; +@using SmartStore.Admin.Models.Export; +@{ + var title = string.Concat(T("Admin.Common.Edit"), " ", T("Common.Profile")); + ViewBag.Title = title; +} + +@using (Html.BeginForm()) +{ +
    +
    + + @title - @Model.Name @Html.ActionLink("(" + T("Admin.Common.BackToList") + ")", "List") +
    +
    + + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.ProviderFriendlyName) + + @Model.ProviderFriendlyName.NaIfEmpty() (@(Model.ProviderSystemName.NaIfEmpty())) +
    + @Html.SmartLabelFor(model => model.Name) + + @Html.EditorFor(model => model.Name) + @Html.ValidationMessageFor(model => model.Name) +
    + @Html.SmartLabelFor(model => model.Enabled) + + @Html.EditorFor(model => model.Enabled) + @Html.ValidationMessageFor(model => model.Enabled) +
    + @Html.SmartLabelFor(model => model.EntityType) + + @Html.DisplayFor(model => model.EntityType) +
    + @Html.SmartLabelFor(model => model.FileType) + + @Html.DropDownListFor(model => model.FileType, Model.AvailableFileTypes) + @Html.ValidationMessageFor(model => model.FileType) +
    + @Html.SmartLabelFor(model => model.SchedulingHours) + + @Html.EditorFor(model => model.SchedulingHours) + @Html.ValidationMessageFor(model => model.SchedulingHours) +
    +
    +
    + @T("Common.Partition") +
    +
    +
    + @Html.SmartLabelFor(model => model.Offset) + + @Html.EditorFor(model => model.Offset) + @Html.ValidationMessageFor(model => model.Offset) +
    + @Html.SmartLabelFor(model => model.Limit) + + @Html.EditorFor(model => model.Limit) + @Html.ValidationMessageFor(model => model.Limit) +
    + @Html.SmartLabelFor(model => model.BatchSize) + + @Html.EditorFor(model => model.BatchSize) + @Html.ValidationMessageFor(model => model.BatchSize) +
    + @Html.SmartLabelFor(model => model.PerStore) + + @Html.EditorFor(model => model.PerStore) + @Html.ValidationMessageFor(model => model.PerStore) +
    +
    +} + +@Html.DeleteConfirmation("export-profile-delete") + + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index 17122852e5..e559017485 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -1,16 +1,17 @@ -@using SmartStore.Admin.Models.Export -@using Telerik.Web.Mvc.UI +@using SmartStore.Core.Domain.Export; +@using SmartStore.Admin.Models.Export; +@using Telerik.Web.Mvc.UI; @{ ViewBag.Title = T("Common.Export").Text; } @@ -34,26 +35,118 @@ }) .Columns(columns => { + columns.Bound(x => x.ThumbnailUrl) + .Width(70) + .Centered() + .Template( + @ + @item.Id + + ) + .ClientTemplate("<#= Id #>"); columns.Bound(x => x.Name) .Width(400) .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) .ClientTemplate("\"><#= Name #>"); - columns.Bound(x => x.ProviderSystemName); - columns.Bound(x => x.EntityType); + columns.Bound(x => x.ProviderSystemName) + .Template(x => "{0} ({1})".FormatInvariant(x.ProviderFriendlyName, x.ProviderSystemName)) + .ClientTemplate("<#= ProviderFriendlyName #> (<#= ProviderSystemName #>)"); columns.Bound(x => x.Enabled) .Width(100) .Template(item => @Html.SymbolForBool(item.Enabled)) .ClientTemplate(@Html.SymbolForBool("Enabled")) .Centered(); - columns.Bound(x => x.FileType); - columns.Bound(x => x.SchedulingHours); + columns.Bound(x => x.EntityType); + columns.Bound(x => x.FileTypeName) + .Centered(); + columns.Bound(x => x.SchedulingHours) + .Centered(); columns.Bound(x => x.LastExecution) .ReadOnly(); }) - .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "Export")) - .ClientEvents(events => events.OnRowDataBound("onRowDataBound_ExportProfiles")) - .EnableCustomBinding(true)) + .DataBinding(dataBinding => dataBinding.Ajax().Select("List", "Export")) + .ClientEvents(events => events.OnRowDataBound("onRowDataBound_ExportProfiles")) + .EnableCustomBinding(true)) + + + + diff --git a/src/Presentation/SmartStore.Web/Administration/sitemap.config b/src/Presentation/SmartStore.Web/Administration/sitemap.config index 0ba3a9156e..6a43d810d8 100644 --- a/src/Presentation/SmartStore.Web/Administration/sitemap.config +++ b/src/Presentation/SmartStore.Web/Administration/sitemap.config @@ -127,7 +127,7 @@ - + From 47324752b9fd841535ab02093b83c25fd3ee8c6b Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Mon, 3 Aug 2015 21:34:23 +0200 Subject: [PATCH 0139/1074] Fixed compilation errors --- .../Orders/OrderProcessingService.cs | 6 +- .../Services/AmazonPayApi.cs | 18 ++-- .../Services/AmazonPayService.cs | 6 +- .../Views/Shipping/Restrictions.cshtml | 91 ------------------- .../Controllers/ProductController.cs | 2 + 5 files changed, 18 insertions(+), 105 deletions(-) delete mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Shipping/Restrictions.cshtml diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index 64ac5318b2..4995d1bd38 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -796,14 +796,14 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR #endregion #region Addresses & pre payment workflow - + // give payment processor the opportunity to fullfill billing address var preProcessPaymentResult = _paymentService.PreProcessPayment(processPaymentRequest); if (!preProcessPaymentResult.Success) { result.Errors.AddRange(preProcessPaymentResult.Errors); - result.Errors.Add(T("Common.Error.PreProcessPayment")); + result.Errors.Add(_localizationService.GetResource("Common.Error.PreProcessPayment")); return result; } @@ -1338,7 +1338,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR #region Notifications, notes and attributes //notes, messages - order.OrderNotes.Add(new OrderNote() + order.OrderNotes.Add(new OrderNote { Note = TNote("OrderPlaced"), DisplayToCustomer = false, diff --git a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs index 6e69b3596c..a6241f8409 100644 --- a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs +++ b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs @@ -23,6 +23,7 @@ using SmartStore.Core.Plugins; using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Domain.Stores; namespace SmartStore.AmazonPay.Api { @@ -221,7 +222,7 @@ public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, st if (orderTotalAmount.HasValue) { - attributes.OrderTotal = new OrderTotal() + attributes.OrderTotal = new OrderTotal { Amount = orderTotalAmount.Value.ToString("0.00", CultureInfo.InvariantCulture), CurrencyCode = currencyCode ?? "EUR" @@ -230,7 +231,7 @@ public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, st if (orderGuid.HasValue()) { - attributes.SellerOrderAttributes = new SellerOrderAttributes() + attributes.SellerOrderAttributes = new SellerOrderAttributes { SellerOrderId = orderGuid, StoreName = storeName @@ -264,10 +265,10 @@ public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, st if (shoppingCartTotalBase.HasValue) { - var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); - + var currency = (Currency)null; // TODO: Merge _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); return SetOrderReferenceDetails(client, orderReferenceId, shoppingCartTotalBase, currency.CurrencyCode); } + return null; } @@ -435,14 +436,15 @@ public void Capture(AmazonPayClient client, CapturePaymentRequest capture, Captu result.NewPaymentStatus = capture.Order.PaymentStatus; var request = new CaptureRequest(); - var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var store = (Store)null; // TODO: MERGE _storeService.GetStoreById(capture.Order.StoreId); + var currency = _currencyService.GetCurrencyById(store.PrimaryStoreCurrencyId); request.SellerId = client.Settings.SellerId; request.AmazonAuthorizationId = capture.Order.AuthorizationTransactionId; request.CaptureReferenceId = GetRandomId("Capture"); //request.SellerCaptureNote = client.Settings.SellerNoteCapture.Truncate(255); - request.CaptureAmount = new Price() + request.CaptureAmount = new Price { Amount = capture.Order.OrderTotal.ToString("0.00", CultureInfo.InvariantCulture), CurrencyCode = currency.CurrencyCode @@ -532,7 +534,7 @@ public string Refund(AmazonPayClient client, RefundPaymentRequest refund, Refund result.NewPaymentStatus = refund.Order.PaymentStatus; string amazonRefundId = null; - var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var currency = (Currency)null; // TODO: MERGE _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); var request = new RefundRequest(); request.SellerId = client.Settings.SellerId; @@ -540,7 +542,7 @@ public string Refund(AmazonPayClient client, RefundPaymentRequest refund, Refund request.RefundReferenceId = GetRandomId("Refund"); //request.SellerRefundNote = client.Settings.SellerNoteRefund.Truncate(255); - request.RefundAmount = new Price() + request.RefundAmount = new Price { Amount = refund.AmountToRefund.ToString("0.00", CultureInfo.InvariantCulture), CurrencyCode = currency.CurrencyCode diff --git a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs index 04c34acd1c..722877beed 100644 --- a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs +++ b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs @@ -453,7 +453,7 @@ public AmazonPayViewModel ProcessPluginRequest(AmazonPayRequestType type, TempDa //model.IsOrderConfirmed = state.IsOrderConfirmed; } - var currency = _services.WorkContext.WorkingCurrency; + var currency = store.PrimaryStoreCurrency; var settings = _services.Settings.LoadSetting(store.Id); model.SellerId = settings.SellerId; @@ -903,7 +903,7 @@ public PreProcessPaymentResult PreProcessPayment(ProcessPaymentRequest request) var orderGuid = request.OrderGuid.ToString(); var store = _storeService.GetStoreById(request.StoreId); var customer = _customerService.GetCustomerById(request.CustomerId); - var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var currency = store.PrimaryStoreCurrency; var settings = _services.Settings.LoadSetting(store.Id); var state = _httpContext.GetAmazonPayState(_services.Localization); var client = new AmazonPayClient(settings); @@ -972,7 +972,7 @@ public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest request) { var orderGuid = request.OrderGuid.ToString(); var store = _storeService.GetStoreById(request.StoreId); - var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var currency = store.PrimaryStoreCurrency; var settings = _services.Settings.LoadSetting(store.Id); var state = _httpContext.GetAmazonPayState(_services.Localization); var client = new AmazonPayClient(settings); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Restrictions.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Restrictions.cshtml deleted file mode 100644 index d7936aacde..0000000000 --- a/src/Presentation/SmartStore.Web/Administration/Views/Shipping/Restrictions.cshtml +++ /dev/null @@ -1,91 +0,0 @@ -@model ShippingMethodRestrictionModel -@{ - ViewBag.Title = T("Admin.Configuration.Shipping.Restrictions").Text; -} -@using (Html.BeginForm()) -{ -
    -
    - - @T("Admin.Configuration.Shipping.Restrictions") -
    -
    - -
    -
    - -
    - - @T("Admin.Configuration.Shipping.Restrictions.Description") -
    - - - - - -
    - @if (Model.AvailableCountries.Count == 0) - { - No countries defined - } - else if (Model.AvailableShippingMethods.Count == 0) - { - No shipping methods available - } - else - { - - -
    - - - - - @foreach (var sm in Model.AvailableShippingMethods) - { - - } - - - - @foreach (var c in Model.AvailableCountries) - { - - - @foreach (var sm in Model.AvailableShippingMethods) - { - var restricted = Model.Restricted.ContainsKey(c.Id) && Model.Restricted[c.Id][sm.Id]; - - } - - } - -
    - @T("Admin.Configuration.Shipping.Restrictions.Country") - - - -
    - @c.Name - - -
    -
    - } -
    -} diff --git a/src/Presentation/SmartStore.Web/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Controllers/ProductController.cs index 257885df19..2a8df6a0cb 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ProductController.cs @@ -122,6 +122,8 @@ public ProductController( this._localizationSettings = localizationSettings; this._captchaSettings = captchaSettings; this._helper = helper; + this._downloadService = downloadService; + this._localizationService = localizationService; } #endregion From c7836dcb5e6a7ff030357b31f2d953a8158a490c Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Mon, 3 Aug 2015 23:07:57 +0200 Subject: [PATCH 0140/1074] Fixed installation errors --- src/Libraries/SmartStore.Core/Domain/Media/Download.cs | 7 ++++++- src/Libraries/SmartStore.Core/Domain/Media/Picture.cs | 7 ++++++- .../SmartStore.Data/Setup/SeedData/InvariantSeedData.cs | 6 +++--- .../SmartStore.Web/Controllers/InstallController.cs | 2 +- .../Infrastructure/Installation/InstallDataSeeder.cs | 1 + 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Domain/Media/Download.cs b/src/Libraries/SmartStore.Core/Domain/Media/Download.cs index 88fb804395..0082cbfc67 100644 --- a/src/Libraries/SmartStore.Core/Domain/Media/Download.cs +++ b/src/Libraries/SmartStore.Core/Domain/Media/Download.cs @@ -10,7 +10,12 @@ namespace SmartStore.Core.Domain.Media [DataContract] public partial class Download : BaseEntity, ITransient { - /// + public Download() + { + this.UpdatedOnUtc = DateTime.UtcNow; + } + + /// /// Gets or sets a GUID /// [DataMember] diff --git a/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs b/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs index c47fc53836..f527b7d693 100644 --- a/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs +++ b/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs @@ -12,7 +12,12 @@ namespace SmartStore.Core.Domain.Media [DataContract] public partial class Picture : BaseEntity, ITransient { - private ICollection _productPictures; + public Picture() + { + this.UpdatedOnUtc = DateTime.UtcNow; + } + + private ICollection _productPictures; /// /// Gets or sets the picture binary /// diff --git a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs index 3bc2bee247..6aee45953b 100644 --- a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs +++ b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs @@ -56,7 +56,7 @@ public void Initialize(SmartObjectContext context) public IList Pictures() { - var entities = new List() + var entities = new List { CreatePicture(File.ReadAllBytes(_sampleImagesPath + "company_logo.png"), "image/png", GetSeName("company-logo")), CreatePicture(File.ReadAllBytes(_sampleImagesPath + "clouds.png"), "image/png", GetSeName("slider-bg")), @@ -7914,7 +7914,7 @@ public IList Products() #region Antonio Vivaldi: then spring - var productInstantDownloadVivaldi = new Product() + var productInstantDownloadVivaldi = new Product { ProductType = ProductType.SimpleProduct, VisibleIndividually = true, @@ -7938,7 +7938,7 @@ public IList Products() AllowBackInStockSubscriptions = false, IsDownload = true, HasSampleDownload = true, - SampleDownload = new Download() + SampleDownload = new Download { DownloadGuid = Guid.NewGuid(), ContentType = "audio/mp3", diff --git a/src/Presentation/SmartStore.Web/Controllers/InstallController.cs b/src/Presentation/SmartStore.Web/Controllers/InstallController.cs index 1ed1d7d418..e0bef97946 100644 --- a/src/Presentation/SmartStore.Web/Controllers/InstallController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/InstallController.cs @@ -545,7 +545,7 @@ protected virtual InstallationResult InstallCore(ILifetimeScope scope, InstallMo var pluginsCount = plugins.Count; var idx = 0; - using (var dbScope = new DbContextScope(autoDetectChanges: false)) { + using (var dbScope = new DbContextScope(autoDetectChanges: false, hooksEnabled: false)) { foreach (var plugin in plugins) { try diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs index 55ad836c04..4e964cc565 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs @@ -539,6 +539,7 @@ public virtual void Seed(SmartObjectContext context) _ctx.Configuration.AutoDetectChangesEnabled = false; _ctx.Configuration.ValidateOnSaveEnabled = false; + _ctx.HooksEnabled = false; _config.ProgressMessageCallback("Progress.CreatingRequiredData"); From 7f515674d323e56f1266548f6957563d7755605d Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 4 Aug 2015 00:52:26 +0200 Subject: [PATCH 0141/1074] Implemented logging for TaskScheduler --- .../Logging/LoggingExtensions.cs | 2 +- .../SmartStore.Core/Logging/TraceLogger.cs | 13 +++++++++--- .../Tasks/InitializeSchedulerFilter.cs | 11 ++++++---- .../Tasks/TaskScheduler.cs | 21 ++++++++++++++----- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs b/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs index 922ba78a78..cbcaec0d05 100644 --- a/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs +++ b/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs @@ -39,7 +39,7 @@ public static void Error(this ILogger logger, Exception exception, Customer cust private static void FilteredLog(ILogger logger, LogLevel level, string message, Exception exception = null, Customer customer = null) { - //don't log thread abort exception + // don't log thread abort exception if ((exception != null) && (exception is System.Threading.ThreadAbortException)) return; diff --git a/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs b/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs index 8bf32d705b..9cc515b7f2 100644 --- a/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs +++ b/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs @@ -5,6 +5,7 @@ using SmartStore.Core.Domain.Logging; using SmartStore.Core.Domain.Customers; using System.Diagnostics; +using SmartStore.Utilities; namespace SmartStore.Core.Logging { @@ -12,7 +13,7 @@ public class TraceLogger : DisposableObject, ILogger { private readonly TraceSource _traceSource; - public TraceLogger() : this("SmartStore.log") + public TraceLogger() : this(CommonHelper.MapPath("~/SmartStore.log")) { } @@ -85,12 +86,17 @@ public IList GetLogByIds(int[] logIds) public void InsertLog(LogContext context) { var type = LogLevelToEventType(context.LogLevel); - _traceSource.TraceEvent(type, (int)type, "{0}: {1}".FormatCurrent(type.ToString().ToUpper(), context.ShortMessage)); + var msg = context.ShortMessage; + if (context.FullMessage.HasValue()) + { + msg += "\r\n{0}".FormatCurrent(context.FullMessage); + } + _traceSource.TraceEvent(type, (int)type, "{0}: {1}".FormatCurrent(type.ToString().ToUpper(), msg)); } public void InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null) { - var context = new LogContext() + var context = new LogContext { LogLevel = logLevel, ShortMessage = shortMessage, @@ -120,6 +126,7 @@ private TraceEventType LogLevelToEventType(LogLevel level) public void Flush() { + _traceSource.Flush(); } protected override void OnDispose(bool disposing) diff --git a/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs b/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs index 1ab5570df6..9175b7a0bc 100644 --- a/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs +++ b/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs @@ -26,24 +26,27 @@ public void OnAuthorization(AuthorizationContext filterContext) { s_initializing = true; + var logger = EngineContext.Current.Resolve(); + try { var taskService = EngineContext.Current.Resolve(); var storeService = EngineContext.Current.Resolve(); var eventPublisher = EngineContext.Current.Resolve(); - var taskManager = EngineContext.Current.Resolve(); + var taskScheduler = EngineContext.Current.Resolve(); var tasks = taskService.GetAllTasks(true); taskService.CalculateNextRunTimes(tasks, true /* isAppStart */); - taskManager.SetBaseUrl(storeService, filterContext.HttpContext); - taskManager.Start(); + taskScheduler.SetBaseUrl(storeService, filterContext.HttpContext); + taskScheduler.Start(); + + logger.Information("Initialized TaskScheduler with base url '{0}'".FormatInvariant(taskScheduler.BaseUrl)); eventPublisher.Publish(new AppInitScheduledTasksEvent { ScheduledTasks = tasks }); } catch (Exception ex) { - var logger = EngineContext.Current.Resolve(); logger.Error("Error while initializing Task Scheduler", ex); } finally diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs index ff1b736ffb..79ae357366 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs @@ -9,6 +9,7 @@ using System.Web.Hosting; using SmartStore.Core.Async; using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Logging; namespace SmartStore.Services.Tasks { @@ -122,11 +123,21 @@ protected internal virtual void CallEndpoint(string url) req.GetResponseAsync().ContinueWith(t => { - if (t.IsFaulted) - { - // TODO: Now what?! Disable timer? - } - t.Result.Dispose(); + if (t.IsFaulted) + { + // TODO: Now what?! Disable timer? + using (var logger = new TraceLogger()) + { + foreach (var ex in t.Exception.InnerExceptions) + { + logger.Error("Error while calling TaskScheduler endpoint (URL: {0})".FormatInvariant(url), ex); + } + } + } + else + { + t.Result.Dispose(); + } }); } From c323360a559b9f993dbd27056e0f830f4cef86f1 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 4 Aug 2015 00:53:40 +0200 Subject: [PATCH 0142/1074] Minor fix for last commit --- src/Libraries/SmartStore.Core/Logging/TraceLogger.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs b/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs index 9cc515b7f2..c54d0e2adf 100644 --- a/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs +++ b/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs @@ -13,7 +13,7 @@ public class TraceLogger : DisposableObject, ILogger { private readonly TraceSource _traceSource; - public TraceLogger() : this(CommonHelper.MapPath("~/SmartStore.log")) + public TraceLogger() : this(CommonHelper.MapPath("~/App_Data/SmartStore.log")) { } From c01cce0526f11e417a62552df9f8e3e55256bdc2 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 4 Aug 2015 10:45:30 +0200 Subject: [PATCH 0143/1074] Some changes to new export framework --- .../Domain/DataExchange/ExportCore.cs | 14 + .../Domain/DataExchange/ExportFilter.cs | 121 +++++++ .../{Export => DataExchange}/ExportProfile.cs | 53 ++- .../Domain/Export/ExportCore.cs | 54 ---- .../SmartStore.Core/SmartStore.Core.csproj | 5 +- .../ExportProfileMap.cs | 7 +- .../201508011828241_ExportFramework.resx | 126 -------- ...1508040836122_ExportFramework.Designer.cs} | 2 +- ....cs => 201508040836122_ExportFramework.cs} | 150 ++++++++- .../201508040836122_ExportFramework.resx | 126 ++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 12 +- .../DataExchange/ExportExtensions.cs | 15 + .../{Export => DataExchange}/ExportService.cs | 13 +- .../IExportProvider.cs | 9 +- .../IExportService.cs | 2 +- .../Export/ExportExtensions.cs | 16 - .../SmartStore.Services.csproj | 8 +- .../DependencyRegistrar.cs | 2 +- .../Controllers/ExportController.cs | 203 ++++++++---- .../Models/DataExchange/ExportProfileModel.cs | 158 +++++++++ .../Models/Export/ExportProfileModel.cs | 68 ---- .../Administration/SmartStore.Admin.csproj | 2 +- .../Administration/Views/Export/Create.cshtml | 8 +- .../Administration/Views/Export/Edit.cshtml | 306 +++++++++++++++--- .../Administration/Views/Export/List.cshtml | 22 +- .../Administration/Views/Plugin/List.cshtml | 2 +- 26 files changed, 1042 insertions(+), 462 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs create mode 100644 src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs rename src/Libraries/SmartStore.Core/Domain/{Export => DataExchange}/ExportProfile.cs (62%) delete mode 100644 src/Libraries/SmartStore.Core/Domain/Export/ExportCore.cs rename src/Libraries/SmartStore.Data/Mapping/{Export => DataExchange}/ExportProfileMap.cs (75%) delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.resx rename src/Libraries/SmartStore.Data/Migrations/{201508011828241_ExportFramework.Designer.cs => 201508040836122_ExportFramework.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201508011828241_ExportFramework.cs => 201508040836122_ExportFramework.cs} (53%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.resx create mode 100644 src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs rename src/Libraries/SmartStore.Services/{Export => DataExchange}/ExportService.cs (90%) rename src/Libraries/SmartStore.Services/{Export => DataExchange}/IExportProvider.cs (55%) rename src/Libraries/SmartStore.Services/{Export => DataExchange}/IExportService.cs (97%) delete mode 100644 src/Libraries/SmartStore.Services/Export/ExportExtensions.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs delete mode 100644 src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs new file mode 100644 index 0000000000..2f513eab63 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs @@ -0,0 +1,14 @@ +using System; + +namespace SmartStore.Core.Domain.DataExchange +{ + public enum ExportEntityType + { + Product = 0, + Category, + Manufacturer, + Customer, + Order, + NewsletterSubscriber + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs new file mode 100644 index 0000000000..a192083317 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; + +namespace SmartStore.Core.Domain.DataExchange +{ + [Serializable] + public class ExportFilter + { + /// + /// Store identifier; 0 to load all records + /// + public int StoreId { get; set; } + + /// + /// Entity created from + /// + public DateTime? CreatedFrom { get; set; } + + /// + /// Entity created to + /// + public DateTime? CreatedTo { get; set; } + + #region Product + + /// + /// Minimum price + /// + public decimal? PriceMinimum { get; set; } + + /// + /// Maximum price + /// + public decimal? PriceMaximum { get; set; } + + /// + /// Minimum product availability + /// + public int? AvailabilityMinimum { get; set; } + + /// + /// Maximum product availability + /// + public int? AvailabilityMaximum { get; set; } + + /// + /// A value indicating whether to load only published or non published products + /// + public bool? IsPublished { get; set; } + + /// + /// Category identifiers + /// + public int[] CategoryIds { get; set; } + + /// + /// A value indicating whether to load products without any catgory mapping + /// + public bool? WithoutCategories { get; set; } + + /// + /// Manufacturer identifiers + /// + public int[] ManufacturerIds { get; set; } + + /// + /// A value indicating whether to load products without any manufacturer mapping + /// + public bool? WithoutManufacturers { get; set; } + + /// + /// Identifiers of product tags + /// + public int? ProductTagIds { get; set; } + + /// + /// A value indicating whether loaded products are marked as featured + /// + public bool? IncludeFeaturedProducts { get; set; } + + /// + /// A value indicating whether to load only featured products + /// + public bool? OnlyFeaturedProducts { get; set; } + + /// + /// Filter by product type + /// + public ProductType? ProductType { get; set; } + + #endregion + + #region Order + + /// + /// Filter by order status + /// + public OrderStatus? OrderStatus { get; set; } + + /// + /// Filter by payment status + /// + public PaymentStatus? PaymentStatus { get; set; } + + /// + /// Filter by shipping status + /// + public ShippingStatus? ShippingStatus { get; set; } + + /// + /// Identifiers of customer roles + /// + public int[] CustomerRoleIds { get; set; } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs similarity index 62% rename from src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs rename to src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs index ed71e475a0..fdd4eb5e34 100644 --- a/src/Libraries/SmartStore.Core/Domain/Export/ExportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs @@ -1,16 +1,27 @@ using System; -using SmartStore.Core.Domain.Export; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Tasks; namespace SmartStore.Core.Domain { public class ExportProfile : BaseEntity { + public ExportProfile() + { + Limit = 100; + BatchSize = 1000; + } + /// /// The name of the profile /// public string Name { get; set; } + /// + /// The name of the folder (file system) + /// + public string FolderName { get; set; } + /// /// The system name of the export provider /// @@ -21,26 +32,6 @@ public class ExportProfile : BaseEntity /// public bool Enabled { get; set; } - /// - /// The export file type identifier - /// - public int FileTypeId { get; set; } - - /// - /// The export file type - /// - public ExportFileType FileType - { - get - { - return (ExportFileType)FileTypeId; - } - set - { - FileTypeId = (int)value; - } - } - /// /// The scheduling task identifier /// @@ -52,29 +43,29 @@ public ExportFileType FileType public Guid ProfileGuid { get; set; } /// - /// XML with partioning information + /// XML with filtering information /// - public string Partitioning { get; set; } + public string Filtering { get; set; } /// - /// XML with filtering information + /// The number of records to be skipped /// - public string Filtering { get; set; } + public int Offset { get; set; } /// - /// Last start time the profile has been executed + /// How many records to be loaded per database round-trip /// - public DateTime? LastExecutionStartUtc { get; set; } + public int Limit { get; set; } /// - /// /// Last end time the profile has been executed + /// The maximum number of records of one processed batch /// - public DateTime? LastExecutionEndUtc { get; set; } + public int BatchSize { get; set; } /// - /// Message of the last execution + /// Whether to start a separate run-through for each store /// - public string LastExecutionMessage { get; set; } + public bool PerStore { get; set; } /// /// The scheduling task diff --git a/src/Libraries/SmartStore.Core/Domain/Export/ExportCore.cs b/src/Libraries/SmartStore.Core/Domain/Export/ExportCore.cs deleted file mode 100644 index b5cca2b555..0000000000 --- a/src/Libraries/SmartStore.Core/Domain/Export/ExportCore.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; - -namespace SmartStore.Core.Domain.Export -{ - public enum ExportFileType - { - Xml = 0, - Xls, - Csv, - Txt, - Pdf - } - - - public enum ExportEntityType - { - Product = 0, - Category, - Manufacturer, - Customer, - Order - } - - - [Serializable] - public class ExportPartition - { - public ExportPartition() - { - Limit = 100; - BatchSize = 1000; - } - - /// - /// The number of records to be skipped - /// - public int Offset { get; set; } - - /// - /// How many records to be loaded per database round-trip - /// - public int Limit { get; set; } - - /// - /// The maximum number of records of one processed batch - /// - public int BatchSize { get; set; } - - /// - /// Whether to start a separate run-through for each store - /// - public bool PerStore { get; set; } - } -} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 21718e5f5a..8e4537dd4c 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -159,8 +159,9 @@ - - + + + diff --git a/src/Libraries/SmartStore.Data/Mapping/Export/ExportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs similarity index 75% rename from src/Libraries/SmartStore.Data/Mapping/Export/ExportProfileMap.cs rename to src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs index a6e66ad885..22d4cc1c4f 100644 --- a/src/Libraries/SmartStore.Data/Mapping/Export/ExportProfileMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs @@ -1,7 +1,7 @@ using System.Data.Entity.ModelConfiguration; using SmartStore.Core.Domain; -namespace SmartStore.Data.Mapping.Export +namespace SmartStore.Data.Mapping.DataExchange { public partial class ExportProfileMap : EntityTypeConfiguration { @@ -11,12 +11,9 @@ public ExportProfileMap() this.HasKey(x => x.Id); this.Property(x => x.Name).IsRequired().HasMaxLength(100); + this.Property(x => x.FolderName).IsRequired().HasMaxLength(100); this.Property(x => x.ProviderSystemName).IsRequired().HasMaxLength(4000); - this.Property(x => x.Partitioning).IsMaxLength(); this.Property(x => x.Filtering).IsMaxLength(); - this.Property(x => x.LastExecutionMessage).HasMaxLength(4000); - - this.Ignore(x => x.FileType); this.HasRequired(x => x.ScheduleTask) .WithMany() diff --git a/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.resx deleted file mode 100644 index ce78c71be0..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.Designer.cs index 0e3246e714..24f974b961 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class ExportFramework : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201508011828241_ExportFramework"; } + get { return "201508040836122_ExportFramework"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs similarity index 53% rename from src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.cs rename to src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs index 86c6f7c509..84a392c3ff 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508011828241_ExportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs @@ -1,6 +1,5 @@ namespace SmartStore.Data.Migrations { - using System; using System.Data.Entity.Migrations; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Security; @@ -16,16 +15,16 @@ public override void Up() { Id = c.Int(nullable: false, identity: true), Name = c.String(nullable: false, maxLength: 100), + FolderName = c.String(nullable: false, maxLength: 100), ProviderSystemName = c.String(nullable: false, maxLength: 4000), Enabled = c.Boolean(nullable: false), - FileTypeId = c.Int(nullable: false), SchedulingTaskId = c.Int(nullable: false), ProfileGuid = c.Guid(nullable: false), - Partitioning = c.String(), Filtering = c.String(), - LastExecutionStartUtc = c.DateTime(), - LastExecutionEndUtc = c.DateTime(), - LastExecutionMessage = c.String(maxLength: 4000), + Offset = c.Int(nullable: false), + Limit = c.Int(nullable: false), + BatchSize = c.Int(nullable: false), + PerStore = c.Boolean(nullable: false), }) .PrimaryKey(t => t.Id) .ForeignKey("dbo.ScheduleTask", t => t.SchedulingTaskId) @@ -66,6 +65,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Common.Profile", "Profile", "Profil"); builder.AddOrUpdate("Common.Partition", "Partition", "Aufteilung"); builder.AddOrUpdate("Common.Image", "Image", "Bild"); + builder.AddOrUpdate("Common.Filter", "Filter", "Filter"); + builder.AddOrUpdate("Common.Projection", "Projection", "Projektion"); + builder.AddOrUpdate("Common.Publishing", "Publishing", "Verffentlichung"); + builder.AddOrUpdate("Common.Website", "Website", "Web-Seite"); builder.AddOrUpdate("Admin.Configuration.Export.ProviderSystemName.Validate", @@ -115,43 +118,156 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Informationen zur letzten Ausfhrung des Exports."); - builder.AddOrUpdate("Admin.Configuration.Export.Segmentation.Offset", + builder.AddOrUpdate("Admin.Configuration.Export.Offset", "Offset", "Abstand", "Specifies the number of records to be skipped.", "Legt die Anzahl der zu berspringenden Datenstze fest."); - builder.AddOrUpdate("Admin.Configuration.Export.Segmentation.Limit", + builder.AddOrUpdate("Admin.Configuration.Export.Limit", "Limit", "Begrenzung", "Specifies how many records to be loaded per database round-trip.", "Legt die Anzahl der Datenstze fest, die pro Datenbankaufruf geladen werden sollen."); - builder.AddOrUpdate("Admin.Configuration.Export.Segmentation.BatchSize", + builder.AddOrUpdate("Admin.Configuration.Export.BatchSize", "Batch size", "Stapelgre", "Specifies the maximum number of records of one processed batch.", "Legt die maximale Anzahl der Datenstze eines Vearbeitungsstapels fest."); - builder.AddOrUpdate("Admin.Configuration.Export.Segmentation.PerStore", + builder.AddOrUpdate("Admin.Configuration.Export.PerStore", "Per store", "Per Shop", "Specifies whether to start a separate run-through for each store.", "Legt fest, ob fr jeden Shop ein separater Verarbeitungsdurchlauf erfolgen soll."); - - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Xml", "XML (Extensible Markup Language)", "XML (Extensible Markup Language)"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Xls", "XLS (Microsoft Excel)", "XLS (Microsoft Excel)"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Csv", "CSV (Delimiter Separated Values)", "CSV (Trennzeichen getrennt)"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Txt", "TXT (Plain text)", "TXT (Einfacher Text)"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportFileType.Pdf", "PDF (Portable Document Format)", "PDF (Portables Dokumentenformat)"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Product", "Product", "Produkt"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Category", "Category", "Warengruppe"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Manufacturer", "Manufacturer", "Hersteller"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Customer", "Customer", "Kunde"); builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Order", "Order", "Auftrag"); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.StoreId", + "Store", + "Shop", + "Filter by store.", + "Nach Shop filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.CreatedFrom", + "Created from", + "Erstellt ab", + "Filter by created date.", + "Nach dem Erstellungsdatum filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.CreatedTo", + "Created to", + "Erstellt bis", + "Filter by created date.", + "Nach dem Erstellungsdatum filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.PriceMinimum", + "Price from", + "Preis von", + "Filter by price.", + "Nach dem Preis filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.PriceMaximum", + "Price to", + "Preis bis", + "Filter by price.", + "Nach dem Preis filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.AvailabilityMinimum", + "Availability from", + "Verfgbar von", + "Filter by availability quantity.", + "Nach der Verfgbarkeitsmenge filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.AvailabilityMaximum", + "Availability to", + "Verfgbar bis", + "Filter by availability quantity.", + "Nach der Verfgbarkeitsmenge filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.IsPublished", + "Published", + "Verffentlicht", + "Filter by publishing.", + "Nach Verffentlichung filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.CategoryIds", + "Categories", + "Warengruppen", + "Filter by categtories.", + "Nach Warengruppen filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.WithoutCategories", + "Without category mapping", + "Ohne Warengruppenzuordnung", + "Filter by missing category mapping.", + "Nach fehlender Warengruppenzuordnung filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.ManufacturerIds", + "Manufacturers", + "Hersteller", + "Filter by manufacturers.", + "Nach Hersteller filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.WithoutManufacturers", + "Without manufacturer mapping", + "Ohne Herstellerzuordnung", + "Filter by missing manufacturer mapping.", + "Nach fehlender Herstellerzuordnung filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.ProductTagIds", + "Product tags", + "Produkt-Tags", + "Filter by product tags.", + "Nach Produkt-Tags filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.IncludeFeaturedProducts", + "Include featured products", + "Empfohlene Produkte einbeziehen", + "Specifies whether to include featured products.", + "Legt fest, ob empfohlene Produkte einbezogen werden sollen."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.OnlyFeaturedProducts", + "Only featured products", + "Nur empfohlene Produkte", + "Filter by featured products.", + "Nach empfohlenen Produkten filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.ProductType", + "Product type", + "Produkttyp", + "Filter by product type.", + "Nach Produkttyp filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.OrderStatus", + "Order status", + "Auftragsstatus", + "Filter by order status.", + "Nach Auftragsstaus filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.PaymentStatus", + "Payment status", + "Zahlungsstatus", + "Filter by payment status.", + "Nach Zahlungsstatus filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.ShippingStatus", + "Shipping status", + "Versandstatus", + "Filter by shipping status.", + "Nach Versandstatus filtern."); + + builder.AddOrUpdate("Admin.Configuration.Export.Filter.CustomerRoleIds", + "Customer roles", + "Kundengruppen", + "Filter by customer roles.", + "Nach Kundengruppen filtern."); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.resx new file mode 100644 index 0000000000..c1ffae86af --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index b39ffa09d7..bbd83bec0a 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -121,7 +121,7 @@ - + @@ -332,9 +332,9 @@ 201507250039446_Merge2.cs - - - 201508011828241_ExportFramework.cs + + + 201508040836122_ExportFramework.cs @@ -633,8 +633,8 @@ 201507250039446_Merge2.cs - - 201508011828241_ExportFramework.cs + + 201508040836122_ExportFramework.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs new file mode 100644 index 0000000000..3c0c8472f9 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportExtensions.cs @@ -0,0 +1,15 @@ +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.DataExchange +{ + public static class ExportExtensions + { + public static bool IsValid(this Provider provider) + { + return ( + provider != null && + provider.Value.FileType.HasValue() + ); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Export/ExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs similarity index 90% rename from src/Libraries/SmartStore.Services/Export/ExportService.cs rename to src/Libraries/SmartStore.Services/DataExchange/ExportService.cs index 14be36fc7e..2b8a2f2ba1 100644 --- a/src/Libraries/SmartStore.Services/Export/ExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs @@ -7,8 +7,9 @@ using SmartStore.Core.Events; using SmartStore.Core.Plugins; using SmartStore.Services.Tasks; +using SmartStore.Utilities; -namespace SmartStore.Services.Export +namespace SmartStore.Services.DataExchange { public partial class ExportService : IExportService { @@ -38,14 +39,15 @@ public virtual ExportProfile InsertExportProfile(Provider provi if (provider == null) throw new ArgumentNullException("provider"); - var guid = Guid.NewGuid(); var name = provider.Metadata.FriendlyName; var systemName = provider.Metadata.SystemName; - var taskType = "SmartStore.Services.ExportImport.{0}Task.{1}, SmartStore.Services".FormatInvariant(systemName, guid.ToString().Replace("-", "")); if (name.IsEmpty()) name = systemName; + var folderName = SeoHelper.GetSeName(name, true, false).ToValidPath(); + var taskType = "SmartStore.Services.DataExchange.{0}Task.{1}, SmartStore.Services".FormatInvariant(systemName, CommonHelper.GenerateRandomDigitCode(10)); + var task = new ScheduleTask { Name = string.Concat(name, " Export Task"), @@ -61,11 +63,10 @@ public virtual ExportProfile InsertExportProfile(Provider provi var profile = new ExportProfile { Name = name, + FolderName = folderName, Enabled = true, ProviderSystemName = systemName, - ProfileGuid = guid, - SchedulingTaskId = task.Id, - FileType = provider.Value.SupportedFileTypes.FirstOrDefault() + SchedulingTaskId = task.Id }; _exportProfileRepository.Insert(profile); diff --git a/src/Libraries/SmartStore.Services/Export/IExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs similarity index 55% rename from src/Libraries/SmartStore.Services/Export/IExportProvider.cs rename to src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs index 752f6096ed..318c0e2586 100644 --- a/src/Libraries/SmartStore.Services/Export/IExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs @@ -1,16 +1,17 @@ using System.IO; using SmartStore.Core.Domain; -using SmartStore.Core.Domain.Export; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Plugins; -namespace SmartStore.Services.Export +namespace SmartStore.Services.DataExchange { public partial interface IExportProvider : IProvider, IUserEditable { + // TODO: a more complex result type is required. e.g. IEnumerable.... MemoryStream Execute(ExportProfile profile); - ExportFileType[] SupportedFileTypes { get; } - ExportEntityType EntityType { get; } + + string FileType { get; } } } diff --git a/src/Libraries/SmartStore.Services/Export/IExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs similarity index 97% rename from src/Libraries/SmartStore.Services/Export/IExportService.cs rename to src/Libraries/SmartStore.Services/DataExchange/IExportService.cs index 3e8e2e60df..bc6ca8b092 100644 --- a/src/Libraries/SmartStore.Services/Export/IExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs @@ -3,7 +3,7 @@ using SmartStore.Core.Domain; using SmartStore.Core.Plugins; -namespace SmartStore.Services.Export +namespace SmartStore.Services.DataExchange { public interface IExportService { diff --git a/src/Libraries/SmartStore.Services/Export/ExportExtensions.cs b/src/Libraries/SmartStore.Services/Export/ExportExtensions.cs deleted file mode 100644 index 3ea12ec406..0000000000 --- a/src/Libraries/SmartStore.Services/Export/ExportExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Linq; -using SmartStore.Core.Plugins; - -namespace SmartStore.Services.Export -{ - public static class ExportExtensions - { - public static bool IsValid(this Provider provider) - { - return ( - provider != null && - provider.Value.SupportedFileTypes != null && provider.Value.SupportedFileTypes.Any() - ); - } - } -} diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index db5a654dd3..cf282b9d21 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -160,12 +160,12 @@ + - - - - + + + diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index e361097cc9..b003f82cef 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -41,7 +41,7 @@ using SmartStore.Services.Directory; using SmartStore.Services.Discounts; using SmartStore.Services.Events; -using SmartStore.Services.Export; +using SmartStore.Services.DataExchange; using SmartStore.Services.ExportImport; using SmartStore.Services.Filter; using SmartStore.Services.Forums; diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index cd8bf2190a..510772fdb3 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -1,16 +1,18 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Web.Mvc; -using SmartStore.Admin.Models.Export; +using SmartStore.Admin.Models.DataExchange; using SmartStore.Core; using SmartStore.Core.Domain; -using SmartStore.Core.Domain.Export; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Plugins; using SmartStore.Services; -using SmartStore.Services.Export; +using SmartStore.Services.Catalog; +using SmartStore.Services.DataExchange; using SmartStore.Services.Media; using SmartStore.Services.Security; +using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Plugins; using Telerik.Web.Mvc; @@ -24,60 +26,108 @@ public class ExportController : AdminControllerBase private readonly IExportService _exportService; private readonly PluginMediator _pluginMediator; private readonly IPictureService _pictureService; + private readonly ICategoryService _categoryService; public ExportController( ICommonServices services, IExportService exportService, PluginMediator pluginMediator, - IPictureService pictureService) + IPictureService pictureService, + ICategoryService categoryService) { _services = services; _exportService = exportService; _pluginMediator = pluginMediator; _pictureService = pictureService; + _categoryService = categoryService; } private void PrepareExportProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) { - var partition = XmlHelper.Deserialize(profile.Partitioning); - - model.AvailableFileTypes = new List(); + model.Providing = new ExportProfileModel.Provider + { + SystemName = profile.ProviderSystemName + }; model.Id = profile.Id; model.Name = profile.Name; - model.ProviderSystemName = profile.ProviderSystemName; model.Enabled = profile.Enabled; - model.FileType = profile.FileType; - model.FileTypeName = profile.FileType.ToString().ToUpper(); model.SchedulingHours = profile.ScheduleTask.Seconds / 3600; - model.Offset = partition.Offset; - model.Limit = partition.Limit; - model.BatchSize = partition.BatchSize; - model.PerStore = partition.PerStore; - if (provider != null) { - model.ThumbnailUrl = _pluginMediator.GetIconUrl(provider.Metadata); + model.Providing.ThumbnailUrl = _pluginMediator.GetIconUrl(provider.Metadata); - if (model.ThumbnailUrl.IsEmpty()) - model.ThumbnailUrl = _pictureService.GetDefaultPictureUrl(48); + if (model.Providing.ThumbnailUrl.IsEmpty()) + model.Providing.ThumbnailUrl = _pictureService.GetDefaultPictureUrl(48); else - model.ThumbnailUrl = Url.Content(model.ThumbnailUrl); + model.Providing.ThumbnailUrl = Url.Content(model.Providing.ThumbnailUrl); + + model.Providing.Url = provider.Metadata.PluginDescriptor.Url; + model.Providing.ConfigurationUrl = Url.Action("ConfigurePlugin", new { systemName = provider.Metadata.SystemName }); + model.Providing.FriendlyName = _pluginMediator.GetLocalizedFriendlyName(provider.Metadata); + model.Providing.Author = provider.Metadata.PluginDescriptor.Author; + model.Providing.Version = provider.Metadata.PluginDescriptor.Version.ToString(); + model.Providing.Description = _pluginMediator.GetLocalizedDescription(provider.Metadata); + + model.Providing.EntityType = provider.Value.EntityType; + model.Providing.EntityTypeName = T("Enums.SmartStore.Core.Domain.ExportEntityType." + provider.Value.EntityType.ToString()); + model.Providing.FileType = provider.Value.FileType.ToUpper(); + } + } - model.ProviderFriendlyName = _pluginMediator.GetLocalizedFriendlyName(provider.Metadata); + private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportProfile profile, Provider provider) + { + var filter = XmlHelper.Deserialize(profile.Filtering); - model.EntityType = T("Enums.SmartStore.Core.Domain.ExportEntityType." + provider.Value.EntityType.ToString()); + var allStores = _services.StoreService.GetAllStores(); + var allCategories = _categoryService.GetAllCategories(showHidden: true); + var mappedCategories = allCategories.ToDictionary(x => x.Id); - foreach (var fileType in provider.Value.SupportedFileTypes) - { - model.AvailableFileTypes.Add(new SelectListItem - { - Text = T("Enums.SmartStore.Core.Domain.ExportFileType." + fileType.ToString()), - Value = ((int)fileType).ToString() - }); - } - } + var yes = T("Admin.Common.Yes").Text; + var no = T("Admin.Common.No").Text; + + model.StoreCount = allStores.Count; + model.AllString = T("Admin.Common.All"); + model.UnspecifiedString = T("Common.Unspecified"); + model.Offset = profile.Offset; + model.Limit = profile.Limit; + model.BatchSize = profile.BatchSize; + model.PerStore = profile.PerStore; + + model.Filtering = new ExportProfileModel.Filter + { + StoreId = filter.StoreId, + CreatedFrom = filter.CreatedFrom, + CreatedTo = filter.CreatedTo, + PriceMinimum = filter.PriceMinimum, + PriceMaximum = filter.PriceMaximum, + AvailabilityMinimum = filter.AvailabilityMinimum, + AvailabilityMaximum = filter.AvailabilityMaximum, + IsPublished = filter.IsPublished, + CategoryIds = filter.CategoryIds, + WithoutCategories = filter.WithoutCategories, + ManufacturerIds = filter.ManufacturerIds, + WithoutManufacturers = filter.WithoutManufacturers, + ProductTagIds = filter.ProductTagIds, + IncludeFeaturedProducts = filter.IncludeFeaturedProducts, + OnlyFeaturedProducts = filter.OnlyFeaturedProducts, + ProductType = filter.ProductType, + OrderStatus = filter.OrderStatus, + PaymentStatus = filter.PaymentStatus, + ShippingStatus = filter.ShippingStatus, + CustomerRoleIds = filter.CustomerRoleIds + }; + + model.Filtering.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); + + model.Filtering.AvailableStores = allStores + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + model.Filtering.AvailableCategories = allCategories + .Select(x => new SelectListItem { Text = x.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = x.Id.ToString() }) + .ToList(); } public ActionResult Index() @@ -123,8 +173,9 @@ public ActionResult Create() if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) { var model = new ExportProfileModel(); + model.Providing = new ExportProfileModel.Provider(); - model.AvailableExportProviders = _exportService.LoadAllExportProviders() + model.Providing.AvailableExportProviders = _exportService.LoadAllExportProviders() .Select(x => { var item = new SelectListItem @@ -148,20 +199,18 @@ public ActionResult Create(ExportProfileModel model) if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) return AccessDeniedView(); - if (model.ProviderSystemName.HasValue()) + if (model.Providing.SystemName.HasValue()) { - var provider = _exportService.LoadProvider(model.ProviderSystemName); + var provider = _exportService.LoadProvider(model.Providing.SystemName); if (provider != null) { var profile = _exportService.InsertExportProfile(provider); - PrepareExportProfileModel(model, profile, provider); - return RedirectToAction("Edit", new { id = profile.Id }); } } - NotifyError(T("Admin.Configuration.Export.ProviderSystemName.Validate", model.ProviderSystemName.NaIfEmpty())); + NotifyError(T("Admin.Configuration.Export.ProviderSystemName.Validate", model.Providing.SystemName.NaIfEmpty())); return RedirectToAction("List"); } @@ -180,6 +229,7 @@ public ActionResult Edit(int id) var model = new ExportProfileModel(); PrepareExportProfileModel(model, profile, provider); + PrepareExportProfileModelForEdit(model, profile, provider); return View(model); } @@ -195,32 +245,60 @@ public ActionResult Edit(ExportProfileModel model, bool continueEditing) if (profile == null) return RedirectToAction("List"); - if (ModelState.IsValid) - { - var partition = new ExportPartition - { - Offset = model.Offset, - Limit = model.Limit, - BatchSize = model.BatchSize, - PerStore = model.PerStore - }; - - profile.Name = model.Name; - profile.Enabled = model.Enabled; - profile.ScheduleTask.Seconds = model.SchedulingHours * 3600; - profile.FileType = model.FileType; - profile.Partitioning = XmlHelper.Serialize(partition); - - _exportService.UpdateExportProfile(profile); - - NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + var provider = _exportService.LoadProvider(profile.ProviderSystemName); - return (continueEditing ? RedirectToAction("Edit", new { id = profile.Id }) : RedirectToAction("List")); + if (!ModelState.IsValid) + { + PrepareExportProfileModel(model, profile, provider); + PrepareExportProfileModelForEdit(model, profile, provider); + return View(model); } - PrepareExportProfileModel(model, profile, _exportService.LoadProvider(model.ProviderSystemName)); - - return View(model); + var filter = new ExportFilter + { + StoreId = model.Filtering.StoreId ?? 0, + CreatedFrom = model.Filtering.CreatedFrom, + CreatedTo = model.Filtering.CreatedTo, + PriceMinimum = model.Filtering.PriceMinimum, + PriceMaximum = model.Filtering.PriceMaximum, + AvailabilityMinimum = model.Filtering.AvailabilityMinimum, + AvailabilityMaximum = model.Filtering.AvailabilityMaximum, + IsPublished = model.Filtering.IsPublished, + CategoryIds = model.Filtering.CategoryIds, + WithoutCategories = model.Filtering.WithoutCategories, + ManufacturerIds = model.Filtering.ManufacturerIds, + WithoutManufacturers = model.Filtering.WithoutManufacturers, + ProductTagIds = model.Filtering.ProductTagIds, + IncludeFeaturedProducts = model.Filtering.IncludeFeaturedProducts, + OnlyFeaturedProducts = model.Filtering.OnlyFeaturedProducts, + ProductType = model.Filtering.ProductType, + OrderStatus = model.Filtering.OrderStatus, + PaymentStatus = model.Filtering.PaymentStatus, + ShippingStatus = model.Filtering.ShippingStatus, + CustomerRoleIds = model.Filtering.CustomerRoleIds + }; + + profile.Name = model.Name; + profile.Enabled = model.Enabled; + profile.ScheduleTask.Seconds = model.SchedulingHours * 3600; + profile.Offset = model.Offset; + profile.Limit = model.Limit; + profile.BatchSize = model.BatchSize; + profile.PerStore = model.PerStore; + + if (profile.Name.IsEmpty()) + profile.Name = provider.Metadata.FriendlyName; + + if (profile.Name.IsEmpty()) + profile.Name = provider.Metadata.SystemName; + + profile.Filtering = XmlHelper.Serialize(filter); + + _exportService.UpdateExportProfile(profile); + + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + + return (continueEditing ? RedirectToAction("Edit", new { id = profile.Id }) : RedirectToAction("List")); } [HttpPost, ActionName("Delete")] @@ -248,5 +326,10 @@ public ActionResult DeleteConfirmed(int id) return RedirectToAction("Edit", new { id = profile.Id }); } + + public ActionResult Execute(int id) + { + return null; + } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs new file mode 100644 index 0000000000..ca98c7ab9b --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Mvc; + +namespace SmartStore.Admin.Models.DataExchange +{ + public partial class ExportProfileModel : EntityModelBase + { + [SmartResourceDisplayName("Admin.Configuration.Export.Name")] + public string Name { get; set; } + + [SmartResourceDisplayName("Common.Enabled")] + public bool Enabled { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.SchedulingHours")] + public int SchedulingHours { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.LastExecution")] + [AllowHtml] + public string LastExecution { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Offset")] + public int Offset { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Limit")] + public int Limit { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.BatchSize")] + public int BatchSize { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.PerStore")] + public bool PerStore { get; set; } + + public Provider Providing { get; set; } + public Filter Filtering { get; set; } + + public int StoreCount { get; set; } + public string AllString { get; set; } + public string UnspecifiedString { get; set; } + + + public class Provider + { + [SmartResourceDisplayName("Common.Image")] + public string ThumbnailUrl { get; set; } + + [SmartResourceDisplayName("Common.Website")] + public string Url { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Plugins.Fields.Configure")] + public string ConfigurationUrl { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.ProviderSystemName")] + public string SystemName { get; set; } + public List AvailableExportProviders { get; set; } + + [SmartResourceDisplayName("Common.Provider")] + public string FriendlyName { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Plugins.Fields.Author")] + public string Author { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Plugins.Fields.Version")] + public string Version { get; set; } + + [SmartResourceDisplayName("Common.Description")] + [AllowHtml] + public string Description { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.EntityType")] + public ExportEntityType EntityType { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.EntityType")] + public string EntityTypeName { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.FileType")] + public string FileType { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.SupportedFileTypes")] + public string SupportedFileTypes { get; set; } + } + + + public class Filter + { + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.StoreId")] + public int? StoreId { get; set; } + public List AvailableStores { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.IsPublished")] + public bool? IsPublished { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ProductType")] + public ProductType? ProductType { get; set; } + public List AvailableProductTypes { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CreatedFrom")] + public DateTime? CreatedFrom { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CreatedTo")] + public DateTime? CreatedTo { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PriceMinimum")] + public decimal? PriceMinimum { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PriceMaximum")] + public decimal? PriceMaximum { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.AvailabilityMinimum")] + public int? AvailabilityMinimum { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.AvailabilityMaximum")] + public int? AvailabilityMaximum { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CategoryIds")] + public int[] CategoryIds { get; set; } + public List AvailableCategories { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.WithoutCategories")] + public bool? WithoutCategories { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ManufacturerIds")] + public int[] ManufacturerIds { get; set; } + public List AvailableManufacturers { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.WithoutManufacturers")] + public bool? WithoutManufacturers { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ProductTagIds")] + public int? ProductTagIds { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.IncludeFeaturedProducts")] + public bool? IncludeFeaturedProducts { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.OnlyFeaturedProducts")] + public bool? OnlyFeaturedProducts { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.OrderStatus")] + public OrderStatus? OrderStatus { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PaymentStatus")] + public PaymentStatus? PaymentStatus { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ShippingStatus")] + public ShippingStatus? ShippingStatus { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CustomerRoleIds")] + public int[] CustomerRoleIds { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs deleted file mode 100644 index 547211434c..0000000000 --- a/src/Presentation/SmartStore.Web/Administration/Models/Export/ExportProfileModel.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Core.Domain.Export; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Admin.Models.Export -{ - public partial class ExportProfileModel : EntityModelBase - { - [SmartResourceDisplayName("Common.Image")] - public string ThumbnailUrl { get; set; } - public string ThumbnailClasses - { - get - { - return "grid-icon"; - } - } - - [SmartResourceDisplayName("Admin.Configuration.Export.ProviderSystemName")] - public string ProviderSystemName { get; set; } - public List AvailableExportProviders { get; set; } - - [SmartResourceDisplayName("Common.Provider")] - public string ProviderFriendlyName { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.EntityType")] - public string EntityType { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.SupportedFileTypes")] - public string SupportedFileTypes { get; set; } - - - [SmartResourceDisplayName("Admin.Configuration.Export.Name")] - public string Name { get; set; } - - [SmartResourceDisplayName("Common.Enabled")] - public bool Enabled { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.FileType")] - public ExportFileType FileType { get; set; } - public List AvailableFileTypes { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.FileType")] - public string FileTypeName { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.SchedulingHours")] - public int SchedulingHours { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.LastExecution")] - [AllowHtml] - public string LastExecution { get; set; } - - - [SmartResourceDisplayName("Admin.Configuration.Export.Segmentation.Offset")] - public int Offset { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Segmentation.Limit")] - public int Limit { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Segmentation.BatchSize")] - public int BatchSize { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Segmentation.PerStore")] - public bool PerStore { get; set; } - } -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index ef978b7e3a..0188006d32 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -248,7 +248,7 @@ - + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml index b6f318d5b4..e8b3dc3b2d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml @@ -1,20 +1,20 @@ -@using SmartStore.Admin.Models.Export +@using SmartStore.Admin.Models.DataExchange @model ExportProfileModel @{ Layout = null; }
    - @if(Model.AvailableExportProviders.Count > 0) + @if(Model.Providing.AvailableExportProviders.Count > 0) {
    - @Html.SmartLabelFor(model => model.ProviderSystemName) + @Html.SmartLabelFor(model => model.Providing.SystemName) - @Html.DropDownListFor(model => model.ProviderSystemName, Model.AvailableExportProviders) + @Html.DropDownListFor(model => model.Providing.SystemName, Model.Providing.AvailableExportProviders)
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml index 1a594c0333..15e1640b40 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -1,16 +1,22 @@ @model ExportProfileModel -@using SmartStore.Core.Domain.Export; -@using SmartStore.Admin.Models.Export; +@using SmartStore.Core.Domain.DataExchange; +@using SmartStore.Admin.Models.DataExchange; @{ - var title = string.Concat(T("Admin.Common.Edit"), " ", T("Common.Profile")); + var title = string.Concat(T("Admin.Common.Edit"), " ", T("Common.Profile")); ViewBag.Title = title; } @using (Html.BeginForm()) { + @Html.HiddenFor(model => model.Id) +
    - + @if (Model.Providing.ThumbnailUrl.HasValue()) + { + + } +   @title - @Model.Name @Html.ActionLink("(" + T("Admin.Common.BackToList") + ")", "List")
    @@ -22,109 +28,323 @@
    -
    - + @Html.ValidationSummary(false) + + @Html.SmartStore().TabStrip().Name("export-profile-edit").Items(x => + { + x.Add().Text(T("Common.General").Text).Content(TabGeneral()).Selected(true); + x.Add().Text(T("Common.Filter").Text).Content(TabFilter()); + x.Add().Text(T("Common.Projection").Text).Content(TabProjection()); + x.Add().Text(T("Common.Partition").Text).Content(TabPartition()); + x.Add().Text(T("Admin.Configuration").Text).Content(TabConfiguration()); + x.Add().Text(T("Common.Publishing").Text).Content(TabDeployment()); + + EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "export-profile-edit", this.Html, this.Model)); + }) +} + +@helper TabGeneral() +{ +
    + + + + + + + + + + + + + @if (Model.Providing.Url.HasValue()) + { + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.Providing.FriendlyName) + + @Model.Providing.FriendlyName.NaIfEmpty() + (@(Model.Providing.SystemName.NaIfEmpty())) +
    + @Html.SmartLabelFor(model => model.Providing.Author) + + @Html.DisplayFor(model => model.Providing.Author) +
    + @Html.SmartLabelFor(model => model.Providing.Version) + + @Html.DisplayFor(model => model.Providing.Version) +
    - @Html.SmartLabelFor(model => model.ProviderFriendlyName) + @Html.SmartLabelFor(model => model.Providing.Url) - @Model.ProviderFriendlyName.NaIfEmpty() (@(Model.ProviderSystemName.NaIfEmpty())) + @Model.Providing.Url
    + @Html.SmartLabelFor(model => model.Providing.EntityTypeName) + + @Html.DisplayFor(model => model.Providing.EntityTypeName) +
    + @Html.SmartLabelFor(model => model.Providing.FileType) + + @Html.DisplayFor(model => model.Providing.FileType) +
    + @Html.SmartLabelFor(model => model.Providing.Description) + + @if (Model.Providing.Description.HasValue()) + { + @Html.Raw(Model.Providing.Description) + } + else + { + @("".NaIfEmpty()) + } +
     
    + @Html.SmartLabelFor(model => model.Name) + + @Html.EditorFor(model => model.Name) + @Html.ValidationMessageFor(model => model.Name) +
    + @Html.SmartLabelFor(model => model.Enabled) + + @Html.EditorFor(model => model.Enabled) + @Html.ValidationMessageFor(model => model.Enabled) +
    + @Html.SmartLabelFor(model => model.SchedulingHours) + + @Html.EditorFor(model => model.SchedulingHours) + @Html.ValidationMessageFor(model => model.SchedulingHours) +
    +} + +@helper TabFilter() +{ + + @if (Model.StoreCount > 1) + { + } + + @if (Model.Providing.EntityType == ExportEntityType.Product) + { + + + + + + + + + + + + - - + + + + + + //TODO manus + //TODO product tags + } + else if (Model.Providing.EntityType == ExportEntityType.Order) + { + } +
    - @Html.SmartLabelFor(model => model.Name) + @Html.SmartLabelFor(model => model.Filtering.StoreId) - @Html.EditorFor(model => model.Name) - @Html.ValidationMessageFor(model => model.Name) + @Html.DropDownListFor(model => model.Filtering.StoreId, Model.Filtering.AvailableStores, Model.AllString) + @Html.ValidationMessageFor(model => model.Filtering.StoreId)
    - @Html.SmartLabelFor(model => model.Enabled) + @Html.SmartLabelFor(model => model.Filtering.IsPublished) - @Html.EditorFor(model => model.Enabled) - @Html.ValidationMessageFor(model => model.Enabled) + @Html.EditorFor(model => model.Filtering.IsPublished) + @Html.ValidationMessageFor(model => model.Filtering.IsPublished)
    - @Html.SmartLabelFor(model => model.EntityType) + @Html.SmartLabelFor(model => model.Filtering.ProductType) - @Html.DisplayFor(model => model.EntityType) + @Html.DropDownListFor(model => model.Filtering.ProductType, Model.Filtering.AvailableProductTypes, Model.AllString)
    - @Html.SmartLabelFor(model => model.FileType) + @Html.SmartLabelFor(model => model.Filtering.CreatedFrom) - @Html.DropDownListFor(model => model.FileType, Model.AvailableFileTypes) - @Html.ValidationMessageFor(model => model.FileType) + @Html.EditorFor(model => model.Filtering.CreatedFrom) + @Html.ValidationMessageFor(model => model.Filtering.CreatedFrom)
    - @Html.SmartLabelFor(model => model.SchedulingHours) + @Html.SmartLabelFor(model => model.Filtering.CreatedTo) - @Html.EditorFor(model => model.SchedulingHours) - @Html.ValidationMessageFor(model => model.SchedulingHours) + @Html.EditorFor(model => model.Filtering.CreatedTo) + @Html.ValidationMessageFor(model => model.Filtering.CreatedTo) +
    + @Html.SmartLabelFor(model => model.Filtering.PriceMinimum) + + @Html.EditorFor(model => model.Filtering.PriceMinimum) + @Html.ValidationMessageFor(model => model.Filtering.PriceMinimum) +
    + @Html.SmartLabelFor(model => model.Filtering.PriceMaximum) + + @Html.EditorFor(model => model.Filtering.PriceMaximum) + @Html.ValidationMessageFor(model => model.Filtering.PriceMaximum) +
    + @Html.SmartLabelFor(model => model.Filtering.AvailabilityMinimum) + + @Html.EditorFor(model => model.Filtering.AvailabilityMinimum) + @Html.ValidationMessageFor(model => model.Filtering.AvailabilityMinimum)
    -
    -
    - @T("Common.Partition") -
    -
    +
    + @Html.SmartLabelFor(model => model.Filtering.AvailabilityMaximum) + + @Html.EditorFor(model => model.Filtering.AvailabilityMaximum) + @Html.ValidationMessageFor(model => model.Filtering.AvailabilityMaximum) +
    + @Html.SmartLabelFor(model => model.Filtering.CategoryIds) + + @Html.ListBoxFor(model => model.Filtering.CategoryIds, + new MultiSelectList(Model.Filtering.AvailableCategories, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.Filtering.CategoryIds)
    - @Html.SmartLabelFor(model => model.Offset) + @Html.SmartLabelFor(model => model.Filtering.WithoutCategories) - @Html.EditorFor(model => model.Offset) - @Html.ValidationMessageFor(model => model.Offset) + @Html.EditorFor(model => model.Filtering.WithoutCategories) + @Html.ValidationMessageFor(model => model.Filtering.WithoutCategories)
    - @Html.SmartLabelFor(model => model.Limit) + @Html.SmartLabelFor(model => model.Filtering.WithoutManufacturers) - @Html.EditorFor(model => model.Limit) - @Html.ValidationMessageFor(model => model.Limit) + @Html.EditorFor(model => model.Filtering.WithoutManufacturers) + @Html.ValidationMessageFor(model => model.Filtering.WithoutManufacturers)
    - @Html.SmartLabelFor(model => model.BatchSize) + @Html.SmartLabelFor(model => model.Filtering.IncludeFeaturedProducts) - @Html.EditorFor(model => model.BatchSize) - @Html.ValidationMessageFor(model => model.BatchSize) + @Html.EditorFor(model => model.Filtering.IncludeFeaturedProducts) + @Html.ValidationMessageFor(model => model.Filtering.IncludeFeaturedProducts)
    - @Html.SmartLabelFor(model => model.PerStore) + @Html.SmartLabelFor(model => model.Filtering.OnlyFeaturedProducts) - @Html.EditorFor(model => model.PerStore) - @Html.ValidationMessageFor(model => model.PerStore) + @Html.EditorFor(model => model.Filtering.OnlyFeaturedProducts) + @Html.ValidationMessageFor(model => model.Filtering.OnlyFeaturedProducts)
    +} - -
    +@helper TabProjection() +{ +} + +@helper TabPartition() +{ + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.Offset) + + @Html.EditorFor(model => model.Offset) + @Html.ValidationMessageFor(model => model.Offset) +
    + @Html.SmartLabelFor(model => model.Limit) + + @Html.EditorFor(model => model.Limit) + @Html.ValidationMessageFor(model => model.Limit) +
    + @Html.SmartLabelFor(model => model.BatchSize) + + @Html.EditorFor(model => model.BatchSize) + @Html.ValidationMessageFor(model => model.BatchSize) +
    + @Html.SmartLabelFor(model => model.PerStore) + + @Html.EditorFor(model => model.PerStore) + @Html.ValidationMessageFor(model => model.PerStore) +
    +} + +@helper TabConfiguration() +{ +} + +@helper TabDeployment() +{ } @Html.DeleteConfirmation("export-profile-delete") diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index e559017485..a38c3a9ed5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -1,5 +1,5 @@ -@using SmartStore.Core.Domain.Export; -@using SmartStore.Admin.Models.Export; +@using SmartStore.Core.Domain.DataExchange; +@using SmartStore.Admin.Models.DataExchange; @using Telerik.Web.Mvc.UI; @{ ViewBag.Title = T("Common.Export").Text; @@ -35,29 +35,29 @@ }) .Columns(columns => { - columns.Bound(x => x.ThumbnailUrl) + columns.Bound(x => x.Providing.ThumbnailUrl) .Width(70) .Centered() .Template( @ - @item.Id + @item.Id ) - .ClientTemplate("<#= Id #>"); + .ClientTemplate("<#= Id #>"); columns.Bound(x => x.Name) .Width(400) .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) .ClientTemplate("\"><#= Name #>"); - columns.Bound(x => x.ProviderSystemName) - .Template(x => "{0} ({1})".FormatInvariant(x.ProviderFriendlyName, x.ProviderSystemName)) - .ClientTemplate("<#= ProviderFriendlyName #> (<#= ProviderSystemName #>)"); + columns.Bound(x => x.Providing.SystemName) + .Template(x => "{0} ({1})".FormatInvariant(x.Providing.FriendlyName, x.Providing.SystemName)) + .ClientTemplate("<#= Providing.FriendlyName #> (<#= Providing.SystemName #>)"); columns.Bound(x => x.Enabled) .Width(100) .Template(item => @Html.SymbolForBool(item.Enabled)) .ClientTemplate(@Html.SymbolForBool("Enabled")) .Centered(); - columns.Bound(x => x.EntityType); - columns.Bound(x => x.FileTypeName) + columns.Bound(x => x.Providing.EntityTypeName); + columns.Bound(x => x.Providing.FileType) .Centered(); columns.Bound(x => x.SchedulingHours) .Centered(); @@ -115,7 +115,7 @@ smallIcon: dialog.find('.modal-body'), callbackSuccess: function (resp) { dialog.find('.modal-body').html(resp); - $('#ProviderSystemName').selectWrapper(); + $('select[name="Providing.SystemName"]').selectWrapper(); }, callbackComplete: function () { showPrimaryButton(true); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Plugin/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Plugin/List.cshtml index ea9c2f4f27..6458d88ec1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Plugin/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Plugin/List.cshtml @@ -67,7 +67,7 @@ { - Website + @T("Common.Website") } @if (plugin.Author.HasValue()) From d9903ef1c91f0ee06b00dd2ffb584df3d229a97a Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 4 Aug 2015 11:33:41 +0200 Subject: [PATCH 0144/1074] Fixed merging issues with payment plugins --- .../Services/AmazonPayApi.cs | 54 +++++++++---------- .../Services/AmazonPayService.cs | 11 ++-- .../Services/IAmazonPayApi.cs | 6 +-- 3 files changed, 30 insertions(+), 41 deletions(-) diff --git a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs index a6241f8409..59e41a1e2b 100644 --- a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs +++ b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs @@ -1,29 +1,28 @@ using System; +using System.Collections.Generic; +using System.Globalization; using System.IO; -using System.Web; using System.Linq; using System.Text; -using System.Globalization; -using System.Collections.Generic; +using System.Web; using OffAmazonPaymentsService; using OffAmazonPaymentsService.Model; -using SmartStore.Utilities; -using SmartStore.AmazonPay.Services; using SmartStore.AmazonPay.Extensions; +using SmartStore.AmazonPay.Services; using SmartStore.AmazonPay.Settings; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Orders; -using SmartStore.Services.Payments; -using SmartStore.Services.Directory; -using SmartStore.Services.Orders; -using SmartStore.Services.Localization; -using SmartStore.Services.Common; -using SmartStore.Services.Helpers; using SmartStore.Core.Infrastructure; using SmartStore.Core.Plugins; -using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Discounts; -using SmartStore.Core.Domain.Stores; +using SmartStore.Services; +using SmartStore.Services.Common; +using SmartStore.Services.Directory; +using SmartStore.Services.Helpers; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Utilities; namespace SmartStore.AmazonPay.Api { @@ -32,33 +31,30 @@ public class AmazonPayApi : IAmazonPayApi private readonly ICountryService _countryService; private readonly IStateProvinceService _stateProvinceService; private readonly IOrderService _orderService; - private readonly ILocalizationService _localizationService; private readonly IAddressService _addressService; private readonly IDateTimeHelper _dateTimeHelper; - private readonly ICurrencyService _currencyService; private readonly CurrencySettings _currencySettings; private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly ICommonServices _services; public AmazonPayApi( ICountryService countryService, IStateProvinceService stateProvinceService, IOrderService orderService, - ILocalizationService localizationService, IAddressService addressService, IDateTimeHelper dateTimeHelper, - ICurrencyService currencyService, CurrencySettings currencySettings, - IOrderTotalCalculationService orderTotalCalculationService) + IOrderTotalCalculationService orderTotalCalculationService, + ICommonServices services) { _countryService = countryService; _stateProvinceService = stateProvinceService; _orderService = orderService; - _localizationService = localizationService; _addressService = addressService; _dateTimeHelper = dateTimeHelper; - _currencyService = currencyService; _currencySettings = currencySettings; _orderTotalCalculationService = orderTotalCalculationService; + _services = services; } private string GetRandomId(string prefix) @@ -252,7 +248,7 @@ public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, st return null; } - public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, Customer customer, List cart) + public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, string currencyCode, List cart) { decimal orderTotalDiscountAmountBase = decimal.Zero; Discount orderTotalAppliedDiscount = null; @@ -265,8 +261,7 @@ public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, st if (shoppingCartTotalBase.HasValue) { - var currency = (Currency)null; // TODO: Merge _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); - return SetOrderReferenceDetails(client, orderReferenceId, shoppingCartTotalBase, currency.CurrencyCode); + return SetOrderReferenceDetails(client, orderReferenceId, shoppingCartTotalBase, currencyCode); } return null; @@ -436,8 +431,7 @@ public void Capture(AmazonPayClient client, CapturePaymentRequest capture, Captu result.NewPaymentStatus = capture.Order.PaymentStatus; var request = new CaptureRequest(); - var store = (Store)null; // TODO: MERGE _storeService.GetStoreById(capture.Order.StoreId); - var currency = _currencyService.GetCurrencyById(store.PrimaryStoreCurrencyId); + var store = _services.StoreService.GetStoreById(capture.Order.StoreId); request.SellerId = client.Settings.SellerId; request.AmazonAuthorizationId = capture.Order.AuthorizationTransactionId; @@ -447,7 +441,7 @@ public void Capture(AmazonPayClient client, CapturePaymentRequest capture, Captu request.CaptureAmount = new Price { Amount = capture.Order.OrderTotal.ToString("0.00", CultureInfo.InvariantCulture), - CurrencyCode = currency.CurrencyCode + CurrencyCode = store.PrimaryStoreCurrency.CurrencyCode }; var response = client.Service.Capture(request); @@ -534,7 +528,7 @@ public string Refund(AmazonPayClient client, RefundPaymentRequest refund, Refund result.NewPaymentStatus = refund.Order.PaymentStatus; string amazonRefundId = null; - var currency = (Currency)null; // TODO: MERGE _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var store = _services.StoreService.GetStoreById(refund.Order.StoreId); var request = new RefundRequest(); request.SellerId = client.Settings.SellerId; @@ -545,7 +539,7 @@ public string Refund(AmazonPayClient client, RefundPaymentRequest refund, Refund request.RefundAmount = new Price { Amount = refund.AmountToRefund.ToString("0.00", CultureInfo.InvariantCulture), - CurrencyCode = currency.CurrencyCode + CurrencyCode = store.PrimaryStoreCurrency.CurrencyCode }; var response = client.Service.Refund(request); @@ -631,7 +625,7 @@ public string ToInfoString(AmazonPayApiData data) try { - string[] strings = _localizationService.GetResource("Plugins.Payments.AmazonPay.MessageStrings").SplitSafe(";"); + string[] strings = _services.Localization.GetResource("Plugins.Payments.AmazonPay.MessageStrings").SplitSafe(";"); string state = data.State.Grow(data.ReasonCode, " "); if (data.ReasonDescription.HasValue()) diff --git a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs index 722877beed..6ce88f3eb8 100644 --- a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs +++ b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs @@ -19,7 +19,6 @@ using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Logging; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; @@ -35,7 +34,6 @@ using SmartStore.Services.Messages; using SmartStore.Services.Orders; using SmartStore.Services.Payments; -using SmartStore.Services.Stores; using SmartStore.Services.Tasks; namespace SmartStore.AmazonPay.Services @@ -51,7 +49,6 @@ public class AmazonPayService : IAmazonPayService private readonly ICurrencyService _currencyService; private readonly CurrencySettings _currencySettings; private readonly ICustomerService _customerService; - private readonly IStoreService _storeService; private readonly IPriceFormatter _priceFormatter; private readonly OrderSettings _orderSettings; private readonly RewardPointsSettings _rewardPointsSettings; @@ -71,7 +68,6 @@ public AmazonPayService( ICurrencyService currencyService, CurrencySettings currencySettings, ICustomerService customerService, - IStoreService storeService, IPriceFormatter priceFormatter, OrderSettings orderSettings, RewardPointsSettings rewardPointsSettings, @@ -90,7 +86,6 @@ public AmazonPayService( _currencyService = currencyService; _currencySettings = currencySettings; _customerService = customerService; - _storeService = storeService; _priceFormatter = priceFormatter; _orderSettings = orderSettings; _rewardPointsSettings = rewardPointsSettings; @@ -534,7 +529,7 @@ public AmazonPayViewModel ProcessPluginRequest(AmazonPayRequestType type, TempDa _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.SelectedPaymentMethod, AmazonPayCore.SystemName, store.Id); var client = new AmazonPayClient(settings); - var unused = _api.SetOrderReferenceDetails(client, model.OrderReferenceId, customer, cart); + var unused = _api.SetOrderReferenceDetails(client, model.OrderReferenceId, store.PrimaryStoreCurrency.CurrencyCode, cart); // this is ugly... var paymentRequest = _httpContext.Session["OrderPaymentInfo"] as ProcessPaymentRequest; @@ -901,7 +896,7 @@ public PreProcessPaymentResult PreProcessPayment(ProcessPaymentRequest request) try { var orderGuid = request.OrderGuid.ToString(); - var store = _storeService.GetStoreById(request.StoreId); + var store = _services.StoreService.GetStoreById(request.StoreId); var customer = _customerService.GetCustomerById(request.CustomerId); var currency = store.PrimaryStoreCurrency; var settings = _services.Settings.LoadSetting(store.Id); @@ -971,7 +966,7 @@ public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest request) try { var orderGuid = request.OrderGuid.ToString(); - var store = _storeService.GetStoreById(request.StoreId); + var store = _services.StoreService.GetStoreById(request.StoreId); var currency = store.PrimaryStoreCurrency; var settings = _services.Settings.LoadSetting(store.Id); var state = _httpContext.GetAmazonPayState(_services.Localization); diff --git a/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayApi.cs b/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayApi.cs index df245dd32f..70d72d9aa1 100644 --- a/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayApi.cs +++ b/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayApi.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Web; using OffAmazonPaymentsService.Model; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Orders; using SmartStore.AmazonPay.Services; using SmartStore.AmazonPay.Settings; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; using SmartStore.Services.Payments; namespace SmartStore.AmazonPay.Api @@ -21,7 +21,7 @@ public partial interface IAmazonPayApi OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, decimal? orderTotalAmount, string currencyCode, string orderGuid = null, string storeName = null); - OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, Customer customer, List cart); + OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, string currencyCode, List cart); void ConfirmOrderReference(AmazonPayClient client, string orderReferenceId); From 3cea57b1a3ddf944fc0b5356caffb41a2bd976ee Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 4 Aug 2015 12:21:41 +0200 Subject: [PATCH 0145/1074] Nullable bool input properties can surprisingly be rendered through EditorFor (DropDownListFor not necessary). --- .../Controllers/ProductController.cs | 14 -------------- .../Models/Catalog/ProductListModel.cs | 8 -------- .../Administration/Views/Product/List.cshtml | 17 ++++++++--------- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs index f419909ac5..0aa775ff8f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ProductController.cs @@ -870,8 +870,6 @@ public ActionResult List(ProductListModel model) return AccessDeniedView(); var allStores = _storeService.GetAllStores(); - var yes = T("Admin.Common.Yes").Text; - var no = T("Admin.Common.No").Text; model.DisplayProductPictures = _adminAreaSettings.DisplayProductPictures; model.DisplayPdfExport = _pdfSettings.Enabled; @@ -897,18 +895,6 @@ public ActionResult List(ProductListModel model) model.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); - model.AvailableWithoutCategories.Add(new SelectListItem { Text = yes, Value = "true" }); - model.AvailableWithoutCategories.Add(new SelectListItem { Text = no, Value = "false" }); - - model.AvailableWithoutManufacturers.Add(new SelectListItem { Text = yes, Value = "true" }); - model.AvailableWithoutManufacturers.Add(new SelectListItem { Text = no, Value = "false" }); - - model.AvailableIsPublished.Add(new SelectListItem { Text = yes, Value = "true" }); - model.AvailableIsPublished.Add(new SelectListItem { Text = no, Value = "false" }); - - model.AvailableHomePageProducts.Add(new SelectListItem { Text = yes, Value = "true" }); - model.AvailableHomePageProducts.Add(new SelectListItem { Text = no, Value = "false" }); - return View(model); } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Catalog/ProductListModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Catalog/ProductListModel.cs index a13db2730d..912c5fe33c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Catalog/ProductListModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Catalog/ProductListModel.cs @@ -14,10 +14,6 @@ public ProductListModel() AvailableManufacturers = new List(); AvailableStores = new List(); AvailableProductTypes = new List(); - AvailableIsPublished = new List(); - AvailableHomePageProducts = new List(); - AvailableWithoutCategories = new List(); - AvailableWithoutManufacturers = new List(); } public GridModel Products { get; set; } @@ -62,10 +58,6 @@ public ProductListModel() public IList AvailableCategories { get; set; } public IList AvailableManufacturers { get; set; } public IList AvailableStores { get; set; } - public IList AvailableWithoutCategories { get; set; } - public IList AvailableWithoutManufacturers { get; set; } public IList AvailableProductTypes { get; set; } - public IList AvailableIsPublished { get; set; } - public IList AvailableHomePageProducts { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml index 6352375f48..8dd9c04a99 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Product/List.cshtml @@ -9,7 +9,6 @@ @{ var trueTemplate = "#if (Published) {# #} #"; var allString = T("Admin.Common.All").Text; - var unspecifiedString = T("Common.Unspecified").Text; ViewBag.Title = T("Admin.Catalog.Products.Manage").Text; } @@ -109,7 +108,7 @@ @Html.SmartLabelFor(model => model.SearchProductTypeId) - @Html.DropDownList("SearchProductTypeId", Model.AvailableProductTypes, allString) + @Html.DropDownListFor(model => model.SearchProductTypeId, Model.AvailableProductTypes, allString) @if (Model.StoreCount > 1) @@ -119,7 +118,7 @@ @Html.SmartLabelFor(model => model.SearchStoreId) - @Html.DropDownList("SearchStoreId", Model.AvailableStores, allString) + @Html.DropDownListFor(model => model.SearchStoreId, Model.AvailableStores, allString) } @@ -128,7 +127,7 @@ @Html.SmartLabelFor(model => model.SearchWithoutCategories) - @Html.DropDownList("SearchWithoutCategories", Model.AvailableWithoutCategories, unspecifiedString) + @Html.EditorFor(model => model.SearchWithoutCategories) @@ -136,7 +135,7 @@ @Html.SmartLabelFor(model => model.SearchCategoryId) - @Html.DropDownList("SearchCategoryId", Model.AvailableCategories, allString) + @Html.DropDownListFor(model => model.SearchCategoryId, Model.AvailableCategories, allString) @@ -144,7 +143,7 @@ @Html.SmartLabelFor(model => model.SearchWithoutManufacturers) - @Html.DropDownList("SearchWithoutManufacturers", Model.AvailableWithoutManufacturers, unspecifiedString) + @Html.EditorFor(model => model.SearchWithoutManufacturers) @@ -152,7 +151,7 @@ @Html.SmartLabelFor(model => model.SearchManufacturerId) - @Html.DropDownList("SearchManufacturerId", Model.AvailableManufacturers, allString) + @Html.DropDownListFor(model => model.SearchManufacturerId, Model.AvailableManufacturers, allString) @@ -160,7 +159,7 @@ @Html.SmartLabelFor(model => model.SearchIsPublished) - @Html.DropDownList("SearchIsPublished", Model.AvailableIsPublished, unspecifiedString) + @Html.EditorFor(model => model.SearchIsPublished) @@ -168,7 +167,7 @@ @Html.SmartLabelFor(model => model.SearchHomePageProducts) - @Html.DropDownList("SearchHomePageProducts", Model.AvailableHomePageProducts, unspecifiedString) + @Html.EditorFor(model => model.SearchHomePageProducts) From 72f2e7b68e7773b516d8252e3bae284a3f2a35c4 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 4 Aug 2015 13:16:41 +0200 Subject: [PATCH 0146/1074] Google Analytics: added support for mobile devices --- changelog.md | 1 + .../SmartStore.GoogleAnalytics/Description.txt | 2 +- .../GoogleAnalyticPlugin.cs | 13 ++++++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 50347c769c..dafb9d59ad 100644 --- a/changelog.md +++ b/changelog.md @@ -29,6 +29,7 @@ * #735 Include SKUs of attribute combinations when filtering the backend product list * Filter for homepage and published\unpublished products in backend product list * Reduce database round trips initiated by price calculation +* Google Analytics: added support for mobile devices ### Bugfixes * #523 Redirecting to payment provider performed by core instead of plugin diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Description.txt b/src/Plugins/SmartStore.GoogleAnalytics/Description.txt index 4a7c23c2ff..c19a7f4113 100644 --- a/src/Plugins/SmartStore.GoogleAnalytics/Description.txt +++ b/src/Plugins/SmartStore.GoogleAnalytics/Description.txt @@ -1,7 +1,7 @@ FriendlyName: Google Analytics SystemName: SmartStore.GoogleAnalytics Group: Analytics -Version: 2.2.0 +Version: 2.2.2.1 MinAppVersion: 2.2.0 DisplayOrder: 1 FileName: SmartStore.GoogleAnalytics.dll diff --git a/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs b/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs index 0c798730ff..61d434af55 100644 --- a/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs +++ b/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs @@ -31,9 +31,16 @@ public GoogleAnalyticPlugin(ISettingService settingService, /// Widget zones public IList GetWidgetZones() { - return !string.IsNullOrWhiteSpace(_googleAnalyticsSettings.WidgetZone) - ? new List() { _googleAnalyticsSettings.WidgetZone } - : new List() { "head_html_tag" }; + var zones = new List() { "head_html_tag", "mobile_head_html_tag" }; + if(!string.IsNullOrWhiteSpace(_googleAnalyticsSettings.WidgetZone)) + { + zones = new List() { + _googleAnalyticsSettings.WidgetZone, + _googleAnalyticsSettings.WidgetZone == "head_html_tag" ? "mobile_head_html_tag" : "mobile_body_end_html_tag_after" + }; + } + + return zones; } /// From f081152dab4f0b6e2487d74033937c24d081d0d0 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Tue, 4 Aug 2015 17:43:17 +0200 Subject: [PATCH 0147/1074] More about export profile data filtering --- .../Domain/DataExchange/ExportFilter.cs | 17 +- .../201508040836122_ExportFramework.cs | 14 +- .../Controllers/ExportController.cs | 180 +++++++++++----- .../Models/DataExchange/ExportFilterModel.cs | 88 ++++++++ .../Models/DataExchange/ExportProfileModel.cs | 73 +------ .../Administration/SmartStore.Admin.csproj | 1 + .../Administration/Views/Export/Edit.cshtml | 199 +++++++++++++----- 7 files changed, 372 insertions(+), 200 deletions(-) create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs index a192083317..db02950efb 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs @@ -75,17 +75,12 @@ public class ExportFilter /// /// Identifiers of product tags /// - public int? ProductTagIds { get; set; } + public int[] ProductTagIds { get; set; } /// - /// A value indicating whether loaded products are marked as featured + /// A value indicating whether to load products that are marked as featured (relates only to categories and manufacturers) /// - public bool? IncludeFeaturedProducts { get; set; } - - /// - /// A value indicating whether to load only featured products - /// - public bool? OnlyFeaturedProducts { get; set; } + public bool? FeaturedProducts { get; set; } /// /// Filter by product type @@ -99,17 +94,17 @@ public class ExportFilter /// /// Filter by order status /// - public OrderStatus? OrderStatus { get; set; } + public OrderStatus[] OrderStatus { get; set; } /// /// Filter by payment status /// - public PaymentStatus? PaymentStatus { get; set; } + public PaymentStatus[] PaymentStatus { get; set; } /// /// Filter by shipping status /// - public ShippingStatus? ShippingStatus { get; set; } + public ShippingStatus[] ShippingStatus { get; set; } /// /// Identifiers of customer roles diff --git a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs index 84a392c3ff..b62177e5a4 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs @@ -157,7 +157,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Configuration.Export.Filter.CreatedFrom", "Created from", - "Erstellt ab", + "Erstellt von", "Filter by created date.", "Nach dem Erstellungsdatum filtern."); @@ -227,17 +227,11 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Filter by product tags.", "Nach Produkt-Tags filtern."); - builder.AddOrUpdate("Admin.Configuration.Export.Filter.IncludeFeaturedProducts", - "Include featured products", - "Empfohlene Produkte einbeziehen", - "Specifies whether to include featured products.", - "Legt fest, ob empfohlene Produkte einbezogen werden sollen."); - - builder.AddOrUpdate("Admin.Configuration.Export.Filter.OnlyFeaturedProducts", + builder.AddOrUpdate("Admin.Configuration.Export.Filter.FeaturedProducts", "Only featured products", "Nur empfohlene Produkte", - "Filter by featured products.", - "Nach empfohlenen Produkten filtern."); + "Filter by featured products. Is only applied when the filtering by categories and manufacturers.", + "Nach empfohlenen Produkten filtern. Wird nur bei der Filterung nach Warengruppen und Hersteller angewendet."); builder.AddOrUpdate("Admin.Configuration.Export.Filter.ProductType", "Product type", diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 510772fdb3..ce04e4a736 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -6,9 +6,13 @@ using SmartStore.Core.Domain; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Plugins; using SmartStore.Services; using SmartStore.Services.Catalog; +using SmartStore.Services.Customers; using SmartStore.Services.DataExchange; using SmartStore.Services.Media; using SmartStore.Services.Security; @@ -27,19 +31,28 @@ public class ExportController : AdminControllerBase private readonly PluginMediator _pluginMediator; private readonly IPictureService _pictureService; private readonly ICategoryService _categoryService; + private readonly IManufacturerService _manufacturerService; + private readonly IProductTagService _productTagService; + private readonly ICustomerService _customerService; public ExportController( ICommonServices services, IExportService exportService, PluginMediator pluginMediator, IPictureService pictureService, - ICategoryService categoryService) + ICategoryService categoryService, + IManufacturerService manufacturerService, + IProductTagService productTagService, + ICustomerService customerService) { _services = services; _exportService = exportService; _pluginMediator = pluginMediator; _pictureService = pictureService; _categoryService = categoryService; + _manufacturerService = manufacturerService; + _productTagService = productTagService; + _customerService = customerService; } private void PrepareExportProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) @@ -81,53 +94,88 @@ private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportPr var filter = XmlHelper.Deserialize(profile.Filtering); var allStores = _services.StoreService.GetAllStores(); - var allCategories = _categoryService.GetAllCategories(showHidden: true); - var mappedCategories = allCategories.ToDictionary(x => x.Id); - var yes = T("Admin.Common.Yes").Text; - var no = T("Admin.Common.No").Text; - - model.StoreCount = allStores.Count; model.AllString = T("Admin.Common.All"); - model.UnspecifiedString = T("Common.Unspecified"); + //model.UnspecifiedString = T("Common.Unspecified"); + model.StoreCount = allStores.Count; model.Offset = profile.Offset; model.Limit = profile.Limit; model.BatchSize = profile.BatchSize; model.PerStore = profile.PerStore; - model.Filtering = new ExportProfileModel.Filter + Action initModelBase = x => { - StoreId = filter.StoreId, - CreatedFrom = filter.CreatedFrom, - CreatedTo = filter.CreatedTo, - PriceMinimum = filter.PriceMinimum, - PriceMaximum = filter.PriceMaximum, - AvailabilityMinimum = filter.AvailabilityMinimum, - AvailabilityMaximum = filter.AvailabilityMaximum, - IsPublished = filter.IsPublished, - CategoryIds = filter.CategoryIds, - WithoutCategories = filter.WithoutCategories, - ManufacturerIds = filter.ManufacturerIds, - WithoutManufacturers = filter.WithoutManufacturers, - ProductTagIds = filter.ProductTagIds, - IncludeFeaturedProducts = filter.IncludeFeaturedProducts, - OnlyFeaturedProducts = filter.OnlyFeaturedProducts, - ProductType = filter.ProductType, - OrderStatus = filter.OrderStatus, - PaymentStatus = filter.PaymentStatus, - ShippingStatus = filter.ShippingStatus, - CustomerRoleIds = filter.CustomerRoleIds + x.StoreId = filter.StoreId; + x.CreatedFrom = filter.CreatedFrom; + x.CreatedTo = filter.CreatedTo; + + x.AvailableStores = allStores + .Select(y => new SelectListItem { Text = y.Name, Value = y.Id.ToString() }) + .ToList(); }; - model.Filtering.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); + if (model.Providing.EntityType == ExportEntityType.Product) + { + var allCategories = _categoryService.GetAllCategories(showHidden: true); + var mappedCategories = allCategories.ToDictionary(x => x.Id); + var allManufacturers = _manufacturerService.GetAllManufacturers(true); + var allProductTags = _productTagService.GetAllProductTags(); - model.Filtering.AvailableStores = allStores - .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) - .ToList(); + model.ProductFiltering = new ExportProductFilterModel + { + PriceMinimum = filter.PriceMinimum, + PriceMaximum = filter.PriceMaximum, + AvailabilityMinimum = filter.AvailabilityMinimum, + AvailabilityMaximum = filter.AvailabilityMaximum, + IsPublished = filter.IsPublished, + CategoryIds = filter.CategoryIds, + WithoutCategories = filter.WithoutCategories, + ManufacturerIds = filter.ManufacturerIds, + WithoutManufacturers = filter.WithoutManufacturers, + ProductTagIds = filter.ProductTagIds, + FeaturedProducts = filter.FeaturedProducts, + ProductType = filter.ProductType + }; + + model.ProductFiltering.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); + + model.ProductFiltering.AvailableCategories = allCategories + .Select(x => new SelectListItem { Text = x.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = x.Id.ToString() }) + .ToList(); + + model.ProductFiltering.AvailableManufacturers = allManufacturers + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + model.ProductFiltering.AvailableProductTags = allProductTags + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + initModelBase(model.ProductFiltering); + } + else if (model.Providing.EntityType == ExportEntityType.Order) + { + var allCustomerRoles = _customerService.GetAllCustomerRoles(true); - model.Filtering.AvailableCategories = allCategories - .Select(x => new SelectListItem { Text = x.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = x.Id.ToString() }) - .ToList(); + model.OrderFiltering = new ExportOrderFilterModel + { + OrderStatus = filter.OrderStatus, + PaymentStatus = filter.PaymentStatus, + ShippingStatus = filter.ShippingStatus, + CustomerRoleIds = filter.CustomerRoleIds + }; + + model.OrderFiltering.AvailableOrderStates = OrderStatus.Pending.ToSelectList(false).ToList(); + model.OrderFiltering.AvailablePaymentStates = PaymentStatus.Pending.ToSelectList(false).ToList(); + model.OrderFiltering.AvailableShippingStates = ShippingStatus.NotYetShipped.ToSelectList(false).ToList(); + + model.OrderFiltering.AvailableCustomerRoles = allCustomerRoles + .OrderBy(x => x.Name) + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + initModelBase(model.OrderFiltering); + } } public ActionResult Index() @@ -254,30 +302,48 @@ public ActionResult Edit(ExportProfileModel model, bool continueEditing) return View(model); } - var filter = new ExportFilter + ExportFilter filter = null; + + Action getFromModelBase = x => { - StoreId = model.Filtering.StoreId ?? 0, - CreatedFrom = model.Filtering.CreatedFrom, - CreatedTo = model.Filtering.CreatedTo, - PriceMinimum = model.Filtering.PriceMinimum, - PriceMaximum = model.Filtering.PriceMaximum, - AvailabilityMinimum = model.Filtering.AvailabilityMinimum, - AvailabilityMaximum = model.Filtering.AvailabilityMaximum, - IsPublished = model.Filtering.IsPublished, - CategoryIds = model.Filtering.CategoryIds, - WithoutCategories = model.Filtering.WithoutCategories, - ManufacturerIds = model.Filtering.ManufacturerIds, - WithoutManufacturers = model.Filtering.WithoutManufacturers, - ProductTagIds = model.Filtering.ProductTagIds, - IncludeFeaturedProducts = model.Filtering.IncludeFeaturedProducts, - OnlyFeaturedProducts = model.Filtering.OnlyFeaturedProducts, - ProductType = model.Filtering.ProductType, - OrderStatus = model.Filtering.OrderStatus, - PaymentStatus = model.Filtering.PaymentStatus, - ShippingStatus = model.Filtering.ShippingStatus, - CustomerRoleIds = model.Filtering.CustomerRoleIds + filter.StoreId = x.StoreId ?? 0; + filter.CreatedFrom = x.CreatedFrom; + filter.CreatedTo = x.CreatedTo; }; + if (model.ProductFiltering != null && provider.Value.EntityType == ExportEntityType.Product) + { + filter = new ExportFilter + { + PriceMinimum = model.ProductFiltering.PriceMinimum, + PriceMaximum = model.ProductFiltering.PriceMaximum, + AvailabilityMinimum = model.ProductFiltering.AvailabilityMinimum, + AvailabilityMaximum = model.ProductFiltering.AvailabilityMaximum, + IsPublished = model.ProductFiltering.IsPublished, + CategoryIds = model.ProductFiltering.CategoryIds, + WithoutCategories = model.ProductFiltering.WithoutCategories, + ManufacturerIds = model.ProductFiltering.ManufacturerIds, + WithoutManufacturers = model.ProductFiltering.WithoutManufacturers, + ProductTagIds = model.ProductFiltering.ProductTagIds, + FeaturedProducts = model.ProductFiltering.FeaturedProducts, + ProductType = model.ProductFiltering.ProductType + }; + + getFromModelBase(model.ProductFiltering); + } + else if (model.OrderFiltering != null && provider.Value.EntityType == ExportEntityType.Order) + { + filter = new ExportFilter + { + OrderStatus = model.OrderFiltering.OrderStatus, + PaymentStatus = model.OrderFiltering.PaymentStatus, + ShippingStatus = model.OrderFiltering.ShippingStatus, + CustomerRoleIds = model.OrderFiltering.CustomerRoleIds + }; + + getFromModelBase(model.OrderFiltering); + } + profile.Name = model.Name; profile.Enabled = model.Enabled; profile.ScheduleTask.Seconds = model.SchedulingHours * 3600; diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs new file mode 100644 index 0000000000..ca812df0b6 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Web.Framework; + +namespace SmartStore.Admin.Models.DataExchange +{ + public class ExportFilterModelBase + { + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.StoreId")] + public int? StoreId { get; set; } + public List AvailableStores { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CreatedFrom")] + public DateTime? CreatedFrom { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CreatedTo")] + public DateTime? CreatedTo { get; set; } + } + + + public class ExportProductFilterModel : ExportFilterModelBase + { + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.IsPublished")] + public bool? IsPublished { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ProductType")] + public ProductType? ProductType { get; set; } + public List AvailableProductTypes { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PriceMinimum")] + public decimal? PriceMinimum { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PriceMaximum")] + public decimal? PriceMaximum { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.AvailabilityMinimum")] + public int? AvailabilityMinimum { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.AvailabilityMaximum")] + public int? AvailabilityMaximum { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CategoryIds")] + public int[] CategoryIds { get; set; } + public List AvailableCategories { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.WithoutCategories")] + public bool? WithoutCategories { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ManufacturerIds")] + public int[] ManufacturerIds { get; set; } + public List AvailableManufacturers { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.WithoutManufacturers")] + public bool? WithoutManufacturers { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ProductTagIds")] + public int[] ProductTagIds { get; set; } + public List AvailableProductTags { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.FeaturedProducts")] + public bool? FeaturedProducts { get; set; } + } + + + public class ExportOrderFilterModel : ExportFilterModelBase + { + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.OrderStatus")] + public OrderStatus[] OrderStatus { get; set; } + public List AvailableOrderStates { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PaymentStatus")] + public PaymentStatus[] PaymentStatus { get; set; } + public List AvailablePaymentStates { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ShippingStatus")] + public ShippingStatus[] ShippingStatus { get; set; } + public List AvailableShippingStates { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CustomerRoleIds")] + public int[] CustomerRoleIds { get; set; } + public List AvailableCustomerRoles { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index ca98c7ab9b..4dd20aa2e1 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -39,11 +39,12 @@ public partial class ExportProfileModel : EntityModelBase public bool PerStore { get; set; } public Provider Providing { get; set; } - public Filter Filtering { get; set; } + + public ExportProductFilterModel ProductFiltering { get; set; } + public ExportOrderFilterModel OrderFiltering { get; set; } public int StoreCount { get; set; } public string AllString { get; set; } - public string UnspecifiedString { get; set; } public class Provider @@ -86,73 +87,5 @@ public class Provider [SmartResourceDisplayName("Admin.Configuration.Export.SupportedFileTypes")] public string SupportedFileTypes { get; set; } } - - - public class Filter - { - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.StoreId")] - public int? StoreId { get; set; } - public List AvailableStores { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.IsPublished")] - public bool? IsPublished { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ProductType")] - public ProductType? ProductType { get; set; } - public List AvailableProductTypes { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CreatedFrom")] - public DateTime? CreatedFrom { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CreatedTo")] - public DateTime? CreatedTo { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PriceMinimum")] - public decimal? PriceMinimum { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PriceMaximum")] - public decimal? PriceMaximum { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.AvailabilityMinimum")] - public int? AvailabilityMinimum { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.AvailabilityMaximum")] - public int? AvailabilityMaximum { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CategoryIds")] - public int[] CategoryIds { get; set; } - public List AvailableCategories { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.WithoutCategories")] - public bool? WithoutCategories { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ManufacturerIds")] - public int[] ManufacturerIds { get; set; } - public List AvailableManufacturers { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.WithoutManufacturers")] - public bool? WithoutManufacturers { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ProductTagIds")] - public int? ProductTagIds { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.IncludeFeaturedProducts")] - public bool? IncludeFeaturedProducts { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.OnlyFeaturedProducts")] - public bool? OnlyFeaturedProducts { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.OrderStatus")] - public OrderStatus? OrderStatus { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.PaymentStatus")] - public PaymentStatus? PaymentStatus { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ShippingStatus")] - public ShippingStatus? ShippingStatus { get; set; } - - [SmartResourceDisplayName("Admin.Configuration.Export.Filter.CustomerRoleIds")] - public int[] CustomerRoleIds { get; set; } - } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 0188006d32..0d06106427 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -247,6 +247,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml index 15e1640b40..ad73a907f4 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -151,144 +151,228 @@ @helper TabFilter() { - @if (Model.StoreCount > 1) + @if (Model.ProductFiltering != null) { + if (Model.StoreCount > 1) + { + + + + + } - } - - @if (Model.Providing.EntityType == ExportEntityType.Product) - { - + - //TODO manus - + - //TODO product tags } - else if (Model.Providing.EntityType == ExportEntityType.Order) + else if (Model.OrderFiltering != null) { + if (Model.StoreCount > 1) + { + + + + + } + + + + + + + + + + + + + + + + + + + + + + + + }
    + @Html.SmartLabelFor(model => model.ProductFiltering.StoreId) + + @Html.DropDownListFor(model => model.ProductFiltering.StoreId, Model.ProductFiltering.AvailableStores, Model.AllString) + @Html.ValidationMessageFor(model => model.ProductFiltering.StoreId) +
    - @Html.SmartLabelFor(model => model.Filtering.StoreId) + @Html.SmartLabelFor(model => model.ProductFiltering.CreatedFrom) - @Html.DropDownListFor(model => model.Filtering.StoreId, Model.Filtering.AvailableStores, Model.AllString) - @Html.ValidationMessageFor(model => model.Filtering.StoreId) + @Html.EditorFor(model => model.ProductFiltering.CreatedFrom) + @Html.ValidationMessageFor(model => model.ProductFiltering.CreatedFrom)
    - @Html.SmartLabelFor(model => model.Filtering.IsPublished) + @Html.SmartLabelFor(model => model.ProductFiltering.CreatedTo) - @Html.EditorFor(model => model.Filtering.IsPublished) - @Html.ValidationMessageFor(model => model.Filtering.IsPublished) + @Html.EditorFor(model => model.ProductFiltering.CreatedTo) + @Html.ValidationMessageFor(model => model.ProductFiltering.CreatedTo)
    - @Html.SmartLabelFor(model => model.Filtering.ProductType) + @Html.SmartLabelFor(model => model.ProductFiltering.ProductType) - @Html.DropDownListFor(model => model.Filtering.ProductType, Model.Filtering.AvailableProductTypes, Model.AllString) + @Html.DropDownListFor(model => model.ProductFiltering.ProductType, Model.ProductFiltering.AvailableProductTypes, Model.AllString)
    - @Html.SmartLabelFor(model => model.Filtering.CreatedFrom) + @Html.SmartLabelFor(model => model.ProductFiltering.IsPublished) - @Html.EditorFor(model => model.Filtering.CreatedFrom) - @Html.ValidationMessageFor(model => model.Filtering.CreatedFrom) + @Html.EditorFor(model => model.ProductFiltering.IsPublished) + @Html.ValidationMessageFor(model => model.ProductFiltering.IsPublished)
    - @Html.SmartLabelFor(model => model.Filtering.CreatedTo) + @Html.SmartLabelFor(model => model.ProductFiltering.PriceMinimum) - @Html.EditorFor(model => model.Filtering.CreatedTo) - @Html.ValidationMessageFor(model => model.Filtering.CreatedTo) + @Html.EditorFor(model => model.ProductFiltering.PriceMinimum) + @Html.ValidationMessageFor(model => model.ProductFiltering.PriceMinimum)
    - @Html.SmartLabelFor(model => model.Filtering.PriceMinimum) + @Html.SmartLabelFor(model => model.ProductFiltering.PriceMaximum) - @Html.EditorFor(model => model.Filtering.PriceMinimum) - @Html.ValidationMessageFor(model => model.Filtering.PriceMinimum) + @Html.EditorFor(model => model.ProductFiltering.PriceMaximum) + @Html.ValidationMessageFor(model => model.ProductFiltering.PriceMaximum)
    - @Html.SmartLabelFor(model => model.Filtering.PriceMaximum) + @Html.SmartLabelFor(model => model.ProductFiltering.AvailabilityMinimum) - @Html.EditorFor(model => model.Filtering.PriceMaximum) - @Html.ValidationMessageFor(model => model.Filtering.PriceMaximum) + @Html.EditorFor(model => model.ProductFiltering.AvailabilityMinimum) + @Html.ValidationMessageFor(model => model.ProductFiltering.AvailabilityMinimum)
    - @Html.SmartLabelFor(model => model.Filtering.AvailabilityMinimum) + @Html.SmartLabelFor(model => model.ProductFiltering.AvailabilityMaximum) - @Html.EditorFor(model => model.Filtering.AvailabilityMinimum) - @Html.ValidationMessageFor(model => model.Filtering.AvailabilityMinimum) + @Html.EditorFor(model => model.ProductFiltering.AvailabilityMaximum) + @Html.ValidationMessageFor(model => model.ProductFiltering.AvailabilityMaximum)
    - @Html.SmartLabelFor(model => model.Filtering.AvailabilityMaximum) + @Html.SmartLabelFor(model => model.ProductFiltering.WithoutCategories) - @Html.EditorFor(model => model.Filtering.AvailabilityMaximum) - @Html.ValidationMessageFor(model => model.Filtering.AvailabilityMaximum) + @Html.EditorFor(model => model.ProductFiltering.WithoutCategories) + @Html.ValidationMessageFor(model => model.ProductFiltering.WithoutCategories)
    - @Html.SmartLabelFor(model => model.Filtering.CategoryIds) + @Html.SmartLabelFor(model => model.ProductFiltering.CategoryIds) - @Html.ListBoxFor(model => model.Filtering.CategoryIds, - new MultiSelectList(Model.Filtering.AvailableCategories, "Value", "Text"), + @Html.ListBoxFor(model => model.ProductFiltering.CategoryIds, + new MultiSelectList(Model.ProductFiltering.AvailableCategories, "Value", "Text"), new { multiple = "multiple", @class = "control-xlarge" }) - @Html.ValidationMessageFor(model => model.Filtering.CategoryIds) + @Html.ValidationMessageFor(model => model.ProductFiltering.CategoryIds)
    - @Html.SmartLabelFor(model => model.Filtering.WithoutCategories) + @Html.SmartLabelFor(model => model.ProductFiltering.WithoutManufacturers) - @Html.EditorFor(model => model.Filtering.WithoutCategories) - @Html.ValidationMessageFor(model => model.Filtering.WithoutCategories) + @Html.EditorFor(model => model.ProductFiltering.WithoutManufacturers) + @Html.ValidationMessageFor(model => model.ProductFiltering.WithoutManufacturers)
    - @Html.SmartLabelFor(model => model.Filtering.WithoutManufacturers) + @Html.SmartLabelFor(model => model.ProductFiltering.ManufacturerIds) - @Html.EditorFor(model => model.Filtering.WithoutManufacturers) - @Html.ValidationMessageFor(model => model.Filtering.WithoutManufacturers) + @Html.ListBoxFor(model => model.ProductFiltering.ManufacturerIds, + new MultiSelectList(Model.ProductFiltering.AvailableManufacturers, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ProductFiltering.ManufacturerIds)
    - @Html.SmartLabelFor(model => model.Filtering.IncludeFeaturedProducts) + @Html.SmartLabelFor(model => model.ProductFiltering.ProductTagIds) - @Html.EditorFor(model => model.Filtering.IncludeFeaturedProducts) - @Html.ValidationMessageFor(model => model.Filtering.IncludeFeaturedProducts) + @Html.ListBoxFor(model => model.ProductFiltering.ProductTagIds, + new MultiSelectList(Model.ProductFiltering.AvailableProductTags, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ProductFiltering.ProductTagIds)
    - @Html.SmartLabelFor(model => model.Filtering.OnlyFeaturedProducts) + @Html.SmartLabelFor(model => model.ProductFiltering.FeaturedProducts) - @Html.EditorFor(model => model.Filtering.OnlyFeaturedProducts) - @Html.ValidationMessageFor(model => model.Filtering.OnlyFeaturedProducts) + @Html.EditorFor(model => model.ProductFiltering.FeaturedProducts) + @Html.ValidationMessageFor(model => model.ProductFiltering.FeaturedProducts)
    + @Html.SmartLabelFor(model => model.OrderFiltering.StoreId) + + @Html.DropDownListFor(model => model.OrderFiltering.StoreId, Model.OrderFiltering.AvailableStores, Model.AllString) + @Html.ValidationMessageFor(model => model.OrderFiltering.StoreId) +
    + @Html.SmartLabelFor(model => model.OrderFiltering.CreatedFrom) + + @Html.EditorFor(model => model.OrderFiltering.CreatedFrom) + @Html.ValidationMessageFor(model => model.OrderFiltering.CreatedFrom) +
    + @Html.SmartLabelFor(model => model.OrderFiltering.CreatedTo) + + @Html.EditorFor(model => model.OrderFiltering.CreatedTo) + @Html.ValidationMessageFor(model => model.OrderFiltering.CreatedTo) +
    + @Html.SmartLabelFor(model => model.OrderFiltering.OrderStatus) + + @Html.ListBoxFor(model => model.OrderFiltering.OrderStatus, + new MultiSelectList(Model.OrderFiltering.AvailableOrderStates, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.OrderFiltering.OrderStatus) +
    + @Html.SmartLabelFor(model => model.OrderFiltering.PaymentStatus) + + @Html.ListBoxFor(model => model.OrderFiltering.PaymentStatus, + new MultiSelectList(Model.OrderFiltering.AvailablePaymentStates, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.OrderFiltering.PaymentStatus) +
    + @Html.SmartLabelFor(model => model.OrderFiltering.ShippingStatus) + + @Html.ListBoxFor(model => model.OrderFiltering.ShippingStatus, + new MultiSelectList(Model.OrderFiltering.AvailableShippingStates, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.OrderFiltering.ShippingStatus) +
    + @Html.SmartLabelFor(model => model.OrderFiltering.CustomerRoleIds) + + @Html.ListBoxFor(model => model.OrderFiltering.CustomerRoleIds, + new MultiSelectList(Model.OrderFiltering.AvailableCustomerRoles, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.OrderFiltering.CustomerRoleIds) +
    } @@ -351,5 +435,16 @@ From 2f78cf063cbda3ecea28c32975720aaeeb35c765 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Tue, 4 Aug 2015 19:02:03 +0200 Subject: [PATCH 0148/1074] Payment plugin Purchase Order Number was included in Offline Payment Plugin --- changelog.md | 1 + .../Migrations/201410091620122_NewRes.cs | 8 +-- .../Controllers/OfflinePaymentController.cs | 43 +++++++++++- .../SmartStore.OfflinePayment/Description.txt | 2 +- .../Localization/resources.de-de.xml | 16 +++++ .../Localization/resources.en-us.xml | 22 +++++- .../Models/ConfigurationModel.cs | 4 ++ .../Models/PaymentInfoModel.cs | 6 ++ .../SmartStore.OfflinePayment/Plugin.cs | 6 ++ .../Providers/PurchaseOrderNumberProvider.cs | 69 +++++++++++++++++++ .../Settings/OfflinePaymentSettings.cs | 5 ++ .../SmartStore.OfflinePayment.csproj | 7 ++ ...rchaseOrderNumberPaymentInfo.Mobile.cshtml | 10 +++ .../PurchaseOrderNumberPaymentInfo.cshtml | 20 ++++++ 14 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 src/Plugins/SmartStore.OfflinePayment/Providers/PurchaseOrderNumberProvider.cs create mode 100644 src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.Mobile.cshtml create mode 100644 src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.cshtml diff --git a/changelog.md b/changelog.md index dafb9d59ad..f262cce186 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,7 @@ * #733 Option to set a display order for homepage products * #607 HTML capable full description for payment methods displayed in checkout * #732 Product list: Option to display the pre-selected price instead of the lowest price +* New payment provider for Offline Payment Plugin: Purchase Order Number ### Improvements * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. diff --git a/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.cs b/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.cs index 8d3ab6ca6e..4c637b9c9d 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.cs @@ -91,15 +91,15 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Gltig bis"); builder.Update("Plugins.Payment.CashOnDelivery.PaymentInfoDescription") - .Value("en", "Once your order is placed, you will be contacted by our stuff to confirm the order.") + .Value("en", "Once your order is placed, you will be contacted by our staff to confirm the order.") .Value("de", "Sobald Ihre Bestellung abgeschloen ist, werden Sie persnlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu besttigen."); builder.Update("Plugins.Payment.Invoice.PaymentInfoDescription") - .Value("en", "Once your order is placed, you will be contacted by our stuff to confirm the order.") + .Value("en", "Once your order is placed, you will be contacted by our staff to confirm the order.") .Value("de", "Sobald Ihre Bestellung abgeschloen ist, werden Sie persnlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu besttigen."); builder.Update("Plugins.Payment.DirectDebit.PaymentInfoDescription") - .Value("en", "Once your order is placed, you will be contacted by our stuff to confirm the order.") + .Value("en", "Once your order is placed, you will be contacted by our staff to confirm the order.") .Value("de", "Sobald Ihre Bestellung abgeschloen ist, werden Sie persnlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu besttigen."); builder.Update("Plugins.Payment.PayInStore.PaymentInfoDescription") @@ -107,7 +107,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) .Value("de", "Reservieren Sie Produkte und zahlen Sie an der Kasse in unserem Ladenlokal."); builder.Update("Plugins.Payment.Prepayment.PaymentInfoDescription") - .Value("en", "Once your order is placed, you will be contacted by our stuff to confirm the order.") + .Value("en", "Once your order is placed, you will be contacted by our staff to confirm the order.") .Value("de", "Sobald Ihre Bestellung abgeschloen ist, werden Sie persnlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu besttigen."); } diff --git a/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs b/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs index d1c5369d54..def82d68f8 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs +++ b/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs @@ -191,6 +191,10 @@ public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) paymentInfo.DirectDebitCountry = form["DirectDebitCountry"]; paymentInfo.DirectDebitIban = form["DirectDebitIban"]; } + else if (type == "PurchaseOrderNumber") + { + paymentInfo.PurchaseOrderNumber = form["PurchaseOrderNumber"]; + } } return paymentInfo; @@ -229,6 +233,10 @@ public override string GetPaymentSummary(FormCollection form) return number.Mask(8); } } + else if (type == "PurchaseOrderNumber") + { + return form["PurchaseOrderNumber"]; + } } return null; @@ -495,5 +503,38 @@ public ActionResult ManualPaymentInfo() #endregion - } + #region PurchaseOrderNumber + + [AdminAuthorize] + [ChildActionOnly] + public ActionResult PurchaseOrderNumberConfigure() + { + var model = ConfigureGet(); + + return View("GenericConfigure", model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly, ValidateInput(false)] + public ActionResult PurchaseOrderNumberConfigure(PurchaseOrderNumberConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return InvoiceConfigure(); + + ConfigurePost(model, form); + + return PurchaseOrderNumberConfigure(); + } + + public ActionResult PurchaseOrderNumberPaymentInfo() + { + var model = PaymentInfoGet(); + + var form = this.GetPaymentData(); + model.PurchaseOrderNumber = form["PurchaseOrderNumber"]; + + return PartialView("PurchaseOrderNumberPaymentInfo", model); + } + + #endregion + } } \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Description.txt b/src/Plugins/SmartStore.OfflinePayment/Description.txt index 869d27cb75..33f0f72b71 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Description.txt +++ b/src/Plugins/SmartStore.OfflinePayment/Description.txt @@ -2,7 +2,7 @@ Description: Contains common offline payment methods like Direct Debit, Invoice, Prepayment etc. Group: Payment SystemName: SmartStore.OfflinePayment -Version: 2.2.0 +Version: 2.2.2.1 MinAppVersion: 2.2.0 DisplayOrder: 0 FileName: SmartStore.OfflinePayment.dll diff --git a/src/Plugins/SmartStore.OfflinePayment/Localization/resources.de-de.xml b/src/Plugins/SmartStore.OfflinePayment/Localization/resources.de-de.xml index 2effbe1ecb..2568394d3b 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Localization/resources.de-de.xml +++ b/src/Plugins/SmartStore.OfflinePayment/Localization/resources.de-de.xml @@ -211,5 +211,21 @@ + + + Bestellnummer + + + + + + + + + + Bestellnummer + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Localization/resources.en-us.xml b/src/Plugins/SmartStore.OfflinePayment/Localization/resources.en-us.xml index 7f21d92f8a..5063cd088b 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Localization/resources.en-us.xml +++ b/src/Plugins/SmartStore.OfflinePayment/Localization/resources.en-us.xml @@ -33,7 +33,7 @@ @@ -96,7 +96,7 @@ @@ -137,7 +137,7 @@ @@ -207,5 +207,21 @@ + + + Purchase order + + + + + + + + + + PO Number + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Models/ConfigurationModel.cs b/src/Plugins/SmartStore.OfflinePayment/Models/ConfigurationModel.cs index 5a2b5690b5..369cb30b9a 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Models/ConfigurationModel.cs +++ b/src/Plugins/SmartStore.OfflinePayment/Models/ConfigurationModel.cs @@ -45,4 +45,8 @@ public class PayInStoreConfigurationModel : ConfigurationModelBase public class PrepaymentConfigurationModel : ConfigurationModelBase { } + + public class PurchaseOrderNumberConfigurationModel : ConfigurationModelBase + { + } } \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Models/PaymentInfoModel.cs b/src/Plugins/SmartStore.OfflinePayment/Models/PaymentInfoModel.cs index a48704604d..d120d787c7 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Models/PaymentInfoModel.cs +++ b/src/Plugins/SmartStore.OfflinePayment/Models/PaymentInfoModel.cs @@ -97,4 +97,10 @@ public class PrepaymentPaymentInfoModel : PaymentInfoModelBase { } + public class PurchaseOrderNumberPaymentInfoModel : PaymentInfoModelBase + { + [SmartResourceDisplayName("Plugins.Payment.PurchaseOrder.PurchaseOrderNumber")] + [AllowHtml] + public string PurchaseOrderNumber { get; set; } + } } \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Plugin.cs b/src/Plugins/SmartStore.OfflinePayment/Plugin.cs index 1fd3c082ee..f496f22698 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Plugin.cs +++ b/src/Plugins/SmartStore.OfflinePayment/Plugin.cs @@ -41,12 +41,18 @@ public override void Install() }); settings.SaveSetting(new ManualPaymentSettings { + DescriptionText = "@Plugins.Payments.Manual.PaymentInfoDescription", TransactMode = TransactMode.Pending }); settings.SaveSetting(new DirectDebitPaymentSettings { DescriptionText = "@Plugins.Payments.DirectDebit.PaymentInfoDescription" }); + settings.SaveSetting(new PurchaseOrderNumberPaymentSettings + { + DescriptionText = "@Plugins.Payments.PurchaseOrderNumber.PaymentInfoDescription", + TransactMode = TransactMode.Pending + }); // add resources loc.ImportPluginResourcesFromXml(this.PluginDescriptor); diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/PurchaseOrderNumberProvider.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/PurchaseOrderNumberProvider.cs new file mode 100644 index 0000000000..10bc19c582 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/PurchaseOrderNumberProvider.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Web.Routing; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Plugins; +using SmartStore.OfflinePayment.Settings; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; +using SmartStore.Services.Payments; + +namespace SmartStore.OfflinePayment +{ + [SystemName("SmartStore.PurchaseOrderNumber")] + [FriendlyName("Purchase Order Number")] + [DisplayOrder(10)] + public class PurchaseOrderNumberProvider : OfflinePaymentProviderBase, IConfigurable + { + private readonly ISettingService _settingService; + private readonly ILocalizationService _localizationService; + + public PurchaseOrderNumberProvider(ISettingService settingService, ILocalizationService localizationService) + { + _settingService = settingService; + _localizationService = localizationService; + } + + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + var settings = CommonServices.Settings.LoadSetting(processPaymentRequest.StoreId); + + result.AllowStoringCreditCardNumber = true; + switch (settings.TransactMode) + { + case TransactMode.Pending: + result.NewPaymentStatus = PaymentStatus.Pending; + break; + case TransactMode.Authorize: + result.NewPaymentStatus = PaymentStatus.Authorized; + break; + case TransactMode.AuthorizeAndCapture: + result.NewPaymentStatus = PaymentStatus.Paid; + break; + default: + { + result.AddError(T("Common.Payment.TranactionTypeNotSupported")); + return result; + } + } + + return result; + } + + public override bool RequiresInteraction + { + get + { + return true; + } + } + + protected override string GetActionPrefix() + { + return "PurchaseOrderNumber"; + } + + } +} diff --git a/src/Plugins/SmartStore.OfflinePayment/Settings/OfflinePaymentSettings.cs b/src/Plugins/SmartStore.OfflinePayment/Settings/OfflinePaymentSettings.cs index 7344b3ca56..c4f4fc9758 100644 --- a/src/Plugins/SmartStore.OfflinePayment/Settings/OfflinePaymentSettings.cs +++ b/src/Plugins/SmartStore.OfflinePayment/Settings/OfflinePaymentSettings.cs @@ -29,6 +29,11 @@ public class ManualPaymentSettings : PaymentSettingsBase, ISettings public TransactMode TransactMode { get; set; } } + public class PurchaseOrderNumberPaymentSettings : PaymentSettingsBase, ISettings + { + public TransactMode TransactMode { get; set; } + } + public class PayInStorePaymentSettings : PaymentSettingsBase, ISettings { } diff --git a/src/Plugins/SmartStore.OfflinePayment/SmartStore.OfflinePayment.csproj b/src/Plugins/SmartStore.OfflinePayment/SmartStore.OfflinePayment.csproj index 015c3b66c5..01c44a1163 100644 --- a/src/Plugins/SmartStore.OfflinePayment/SmartStore.OfflinePayment.csproj +++ b/src/Plugins/SmartStore.OfflinePayment/SmartStore.OfflinePayment.csproj @@ -145,6 +145,7 @@ + @@ -214,6 +215,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.Mobile.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.Mobile.cshtml new file mode 100644 index 0000000000..87191ec5e0 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.Mobile.cshtml @@ -0,0 +1,10 @@ +@{ + Layout = ""; +} +@using SmartStore.Web.Framework; +@using SmartStore.OfflinePayment.Models; +@model PurchaseOrderNumberPaymentInfoModel + +@Html.SmartLabelFor(model => model.PurchaseOrderNumber, false) +@Html.TextBoxFor(model => model.PurchaseOrderNumber, new { autocomplete = "off" }) +@Html.ValidationMessageFor(model => model.PurchaseOrderNumber) diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.cshtml new file mode 100644 index 0000000000..0d21481f2d --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.cshtml @@ -0,0 +1,20 @@ +@using SmartStore.Web.Framework; +@using SmartStore.OfflinePayment.Models; + +@model PurchaseOrderNumberPaymentInfoModel + +@{ + Layout = ""; +} + +@Html.Hidden("OfflinePaymentMethodType", "PurchaseOrderNumber") + +
    +
    + @Html.LabelFor(model => model.PurchaseOrderNumber, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.PurchaseOrderNumber, new { style = "width: 165px;", autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.PurchaseOrderNumber) +
    +
    +
    \ No newline at end of file From 2a5b3db711fb67cee52ed18d6f699ed00f671e1e Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Tue, 4 Aug 2015 23:30:05 +0200 Subject: [PATCH 0149/1074] Proper error handling for TaskScheduler and several other fixes & enhancements --- changelog.md | 16 +++++--- .../SmartStore.Core/Logging/TraceLogger.cs | 2 +- .../Messages/QueuedMessagesSendTask.cs | 5 ++- .../ChangeTaskSchedulerBaseUrlConsumer.cs | 17 +++++++-- .../Tasks/ITaskScheduler.cs | 5 +-- .../Tasks/InitializeSchedulerFilter.cs | 16 +++++++- .../Tasks/TaskScheduler.cs | 37 ++++++++++++++++--- .../Administration/Scripts/admin.common.js | 3 ++ .../Views/ScheduleTask/List.cshtml | 5 --- .../Controllers/TaskSchedulerController.cs | 4 +- src/Presentation/SmartStore.Web/Web.config | 8 +++- 11 files changed, 90 insertions(+), 28 deletions(-) diff --git a/changelog.md b/changelog.md index f262cce186..4643e9ae8f 100644 --- a/changelog.md +++ b/changelog.md @@ -4,13 +4,15 @@ ### New Features * #141 Payment and shipping methods by customer roles -* #67 Restrict payment methods to certain countries -* #94 Restrict payment methods to certain shipping methods -* #526 Min\max amount option for which the payment method should be offered during checkout +* #67 Restrict payment methods to countries +* #94 Restrict payment methods to shipping methods +* #584 Email attachment support for message templates +* Attach order invoice PDF automatically to order notification emails +* #526 Min/Max amount option for which the payment method should be offered during checkout * #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" * #702 Facebook and Twitter external authentication suitable for multi-stores -* New scheduled task: clear e-mail queue -* New scheduled task: clear uploadeded transient media files +* New scheduled task: Clear e-mail queue +* New scheduled task: Clear uploadeded transient media files * #704 Make primary store currency suitable for multi-stores * #727 Web-API: Option to deactivate TimestampOlderThanLastRequest validation * #731 Web-API: Allow deletion and inserting of product category and manufacturer assignments @@ -23,7 +25,9 @@ * (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. * (Perf) Significantly reduced number of database reads during product list rendering. Increases request speed by up to 10%. * (Perf) Implemented 2nd level cache for infrequently changed entities. Increases request speed by up to 10%. -* #721 Message Queue: implemented "Delete all" +* TaskScheduler: Rewritten from scratch to be suitable for Web Farms +* TaskScheduler: Editing tasks does not require app restart anymore +* TaskScheduler: Enhanced UI * #721 Message Queue: implemented "Delete all" * #725 Prevent LowestProductPrice being 0 * #709 News feed produced invalid RSS feed. Added content:encoded. Added maximum news age setting for feed export. diff --git a/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs b/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs index c54d0e2adf..610b2c57f1 100644 --- a/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs +++ b/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs @@ -89,7 +89,7 @@ public void InsertLog(LogContext context) var msg = context.ShortMessage; if (context.FullMessage.HasValue()) { - msg += "\r\n{0}".FormatCurrent(context.FullMessage); + msg += "{0}{1}".FormatCurrent(Environment.NewLine, context.FullMessage); } _traceSource.TraceEvent(type, (int)type, "{0}: {1}".FormatCurrent(type.ToString().ToUpper(), msg)); } diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs index b3058c31a8..a37e7e82c4 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs @@ -16,7 +16,7 @@ public QueuedMessagesSendTask(IQueuedEmailService queuedEmailService) public void Execute(TaskExecutionContext ctx) { - const int pageSize = 100; + const int pageSize = 1000; const int maxTries = 3; for (int i = 0; i < 9999999; ++i) @@ -26,7 +26,8 @@ public void Execute(TaskExecutionContext ctx) MaxSendTries = maxTries, PageIndex = i, PageSize = pageSize, - Expand = "Attachments" + Expand = "Attachments", + UnsentOnly = true }; var queuedEmails = _queuedEmailService.SearchEmails(q); diff --git a/src/Libraries/SmartStore.Services/Tasks/ChangeTaskSchedulerBaseUrlConsumer.cs b/src/Libraries/SmartStore.Services/Tasks/ChangeTaskSchedulerBaseUrlConsumer.cs index ea67030e61..a79a13c4ec 100644 --- a/src/Libraries/SmartStore.Services/Tasks/ChangeTaskSchedulerBaseUrlConsumer.cs +++ b/src/Libraries/SmartStore.Services/Tasks/ChangeTaskSchedulerBaseUrlConsumer.cs @@ -7,6 +7,7 @@ using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; using SmartStore.Services.Stores; +using SmartStore.Utilities; namespace SmartStore.Services.Tasks { @@ -18,27 +19,37 @@ public class ChangeTaskSchedulerBaseUrlConsumer : private readonly ITaskScheduler _taskScheduler; private readonly IStoreService _storeService; private readonly HttpContextBase _httpContext; + private readonly bool _shouldChange; public ChangeTaskSchedulerBaseUrlConsumer(ITaskScheduler taskScheduler, IStoreService storeService, HttpContextBase httpContext) { this._taskScheduler = taskScheduler; this._storeService = storeService; this._httpContext = httpContext; + this._shouldChange = CommonHelper.GetAppSetting("sm:TaskSchedulerBaseUrl").IsWebUrl() == false; } public void HandleEvent(EntityInserted eventMessage) { - _taskScheduler.SetBaseUrl(_storeService, _httpContext); + HandleEventCore(); } public void HandleEvent(EntityUpdated eventMessage) { - _taskScheduler.SetBaseUrl(_storeService, _httpContext); + HandleEventCore(); } public void HandleEvent(EntityDeleted eventMessage) { - _taskScheduler.SetBaseUrl(_storeService, _httpContext); + HandleEventCore(); } + + private void HandleEventCore() + { + if (_shouldChange) + { + _taskScheduler.SetBaseUrl(_storeService, _httpContext); + } + } } } diff --git a/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs index 99a5d554c5..15d4b31df9 100644 --- a/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/ITaskScheduler.cs @@ -74,7 +74,6 @@ public static class ITaskSchedulerExtensions internal static void SetBaseUrl(this ITaskScheduler scheduler, IStoreService storeService, HttpContextBase httpContext) { - var path = VirtualPathUtility.ToAbsolute("~/TaskScheduler"); string url = ""; if (!httpContext.Request.IsLocal) @@ -82,13 +81,13 @@ internal static void SetBaseUrl(this ITaskScheduler scheduler, IStoreService sto var defaultStore = storeService.GetAllStores().FirstOrDefault(x => storeService.IsStoreDataValid(x)); if (defaultStore != null) { - url = defaultStore.Url; + url = defaultStore.Url.EnsureEndsWith("/") + "TaskScheduler"; } } if (url.IsEmpty()) { - url = WebHelper.GetAbsoluteUrl(path, httpContext.Request); + url = WebHelper.GetAbsoluteUrl(VirtualPathUtility.ToAbsolute("~/TaskScheduler"), httpContext.Request); } scheduler.BaseUrl = url; diff --git a/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs b/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs index 9175b7a0bc..849916d622 100644 --- a/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs +++ b/src/Libraries/SmartStore.Services/Tasks/InitializeSchedulerFilter.cs @@ -10,6 +10,7 @@ using System.Web.Mvc; using SmartStore.Core.Data; using SmartStore.Core.Logging; +using SmartStore.Utilities; namespace SmartStore.Services.Tasks { @@ -38,7 +39,20 @@ public void OnAuthorization(AuthorizationContext filterContext) var tasks = taskService.GetAllTasks(true); taskService.CalculateNextRunTimes(tasks, true /* isAppStart */); - taskScheduler.SetBaseUrl(storeService, filterContext.HttpContext); + var baseUrl = CommonHelper.GetAppSetting("sm:TaskSchedulerBaseUrl"); + if (baseUrl.IsWebUrl()) + { + taskScheduler.BaseUrl = baseUrl; + } + else + { + // autoresolve base url + taskScheduler.SetBaseUrl(storeService, filterContext.HttpContext); + } + + var sweepInterval = CommonHelper.GetAppSetting("sm:TaskSchedulerSweepInterval", 60); + taskScheduler.SweepInterval = TimeSpan.FromSeconds(sweepInterval); + taskScheduler.Start(); logger.Information("Initialized TaskScheduler with base url '{0}'".FormatInvariant(taskScheduler.BaseUrl)); diff --git a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs index 79ae357366..acf2e7c692 100644 --- a/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs +++ b/src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs @@ -19,6 +19,7 @@ public class DefaultTaskScheduler : DisposableObject, ITaskScheduler, IRegistere private string _baseUrl; private System.Timers.Timer _timer; private bool _shuttingDown; + private int _errCount; private readonly ConcurrentDictionary _authTokens = new ConcurrentDictionary(); public DefaultTaskScheduler() @@ -115,7 +116,7 @@ protected internal virtual void CallEndpoint(string url) req.UserAgent = "SmartStore.NET"; req.Method = "POST"; req.ContentType = "text/plain"; - req.ContentLength = 0; + req.ContentLength = 0; string authToken = Guid.NewGuid().ToString(); _authTokens.TryAdd(authToken, true); @@ -125,22 +126,48 @@ protected internal virtual void CallEndpoint(string url) { if (t.IsFaulted) { - // TODO: Now what?! Disable timer? - using (var logger = new TraceLogger()) + HandleException(t.Exception, url); + _errCount++; + if (_errCount >= 10) { - foreach (var ex in t.Exception.InnerExceptions) + // 10 failed attempts in succession. Stop the timer! + this.Stop(); + using (var logger = new TraceLogger()) { - logger.Error("Error while calling TaskScheduler endpoint (URL: {0})".FormatInvariant(url), ex); + logger.Information("Stopping TaskScheduler sweep timer. Too many failed requests in succession."); } } } else { + _errCount = 0; t.Result.Dispose(); } }); } + private void HandleException(AggregateException exception, string url) + { + using (var logger = new TraceLogger()) + { + string msg = "Error while calling TaskScheduler endpoint '{0}'.".FormatInvariant(url); + var wex = exception.InnerExceptions.OfType().FirstOrDefault(); + + if (wex == null) + { + logger.Error(msg, exception); + } + else + { + using (var response = wex.Response as HttpWebResponse) + { + msg += " HTTP {0}, {1}".FormatCurrent((int)response.StatusCode, response.StatusDescription); + logger.Error(msg); + } + } + } + } + private void CheckUrl(string url) { if (!url.IsWebUrl()) diff --git a/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js b/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js index 1387de0d25..e1ae7ea26e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js +++ b/src/Presentation/SmartStore.Web/Administration/Scripts/admin.common.js @@ -108,6 +108,9 @@ var Admin = { } } }); + }, + error: function (xhr, ajaxOptions, thrownError) { + window.clearInterval(interval); } }); } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml index b6ec8f00be..20e6437c3c 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml @@ -83,11 +83,6 @@ } }); - function refreshGrid() { - var grid = $("#schedule-tasks-grid").data("tGrid"); - grid.ajaxRequest(); - } - Admin.TaskWatcher.startWatching({ context: $('#schedule-tasks-grid'), elementsSelector: '.task-progress', diff --git a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs index eef3ac94e0..c67a3949f3 100644 --- a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs @@ -44,6 +44,8 @@ public ActionResult Sweep() var prevTaskStart = DateTime.UtcNow; var count = 0; + return new HttpStatusCodeResult(System.Net.HttpStatusCode.Unauthorized, "YOOO, this is not authorized dude. WTF?!"); + foreach (var task in pendingTasks) { var elapsedSincePrevTask = DateTime.UtcNow - prevTaskStart; @@ -80,7 +82,7 @@ public ActionResult Execute(int id /* taskId */) _taskExecutor.Execute(task); - return Content("Task '{0}' executed".FormatCurrent(task.Name)); + return Content("Task '{0}' executed".FormatCurrent(task.Name)); } } diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index cf1a8fedd3..ca8993dab2 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -81,12 +81,18 @@ + + + + - + From 893bfb962088aa95b2c5a9acf186681369a9d914 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 5 Aug 2015 00:03:14 +0200 Subject: [PATCH 0150/1074] Minor fixes for last commit --- .../Administration/Views/ScheduleTask/List.cshtml | 3 ++- src/Presentation/SmartStore.Web/Web.config | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml index 20e6437c3c..0bd33e4cc9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml @@ -26,7 +26,8 @@ .Columns(columns => { columns.Bound(x => x.Name).ClientTemplate("<#= Name #>"); - columns.Bound(x => x.Seconds); + columns.Bound(x => x.Seconds) + .ClientTemplate("<#= _.formatTime(Seconds) #>"); columns.Bound(x => x.Enabled) .ClientTemplate(@Html.SymbolForBool("Enabled")) .Centered() diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index ca8993dab2..cabadacd9d 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -92,7 +92,7 @@ - + From c0cdd409956bbab4261c219c6675d16b42c068ae Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 5 Aug 2015 00:16:04 +0200 Subject: [PATCH 0151/1074] Removed KeepAlive Task. Not necessary anymore: the TaskScheduler sweeper does the job now. --- ...01508042207146_RemoveKeepAlive.Designer.cs | 29 ++++ .../201508042207146_RemoveKeepAlive.cs | 35 +++++ .../201508042207146_RemoveKeepAlive.resx | 126 ++++++++++++++++++ .../Setup/SeedData/InvariantSeedData.cs | 8 -- .../SmartStore.Data/SmartStore.Data.csproj | 7 + .../Common/KeepAliveTask.cs | 20 --- .../SmartStore.Services.csproj | 1 - .../Installation/DeDESeedData.cs | 4 - 8 files changed, 197 insertions(+), 33 deletions(-) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.Designer.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs create mode 100644 src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.resx delete mode 100644 src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs diff --git a/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.Designer.cs new file mode 100644 index 0000000000..fbd14a355a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class RemoveKeepAlive : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(RemoveKeepAlive)); + + string IMigrationMetadata.Id + { + get { return "201508042207146_RemoveKeepAlive"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs new file mode 100644 index 0000000000..5955672869 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs @@ -0,0 +1,35 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class RemoveKeepAlive : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + Sql("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.Services.Common.KeepAliveTask, SmartStore.Services'"); + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.System.ScheduleTasks", + "Scheduled Tasks", + "Geplante Aufgaben"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.resx b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.resx new file mode 100644 index 0000000000..483dbdf042 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs index 6aee45953b..a38b7a8533 100644 --- a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs +++ b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs @@ -4777,14 +4777,6 @@ public IList ScheduleTasks() StopOnError = false, }, new ScheduleTask - { - Name = "Keep alive", - Seconds = 300, - Type = "SmartStore.Services.Common.KeepAliveTask, SmartStore.Services", - Enabled = true, - StopOnError = false, - }, - new ScheduleTask { Name = "Delete guests", Seconds = 600, diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index a6fce9f98b..0c98484c4a 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -331,6 +331,10 @@ 201507250039446_Merge2.cs + + + 201508042207146_RemoveKeepAlive.cs + @@ -627,6 +631,9 @@ 201507250039446_Merge2.cs + + 201508042207146_RemoveKeepAlive.cs +
    diff --git a/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs b/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs deleted file mode 100644 index a7ae21aa9a..0000000000 --- a/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using SmartStore.Core; -using SmartStore.Services.Tasks; - -namespace SmartStore.Services.Common -{ - /// - /// Represents a task for keeping the site alive - /// - public partial class KeepAliveTask : ITask - { - - public void Execute(TaskExecutionContext ctx) - { - // do absolutely nothing - } - } -} diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 49e1c86d78..de9c015e87 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -244,7 +244,6 @@ - diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs index bf7c9b7940..fbc4191d29 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs @@ -2525,10 +2525,6 @@ protected override void Alter(IList entities) { x.Name = "Temporäre Uploads bereinigen"; }) - .Alter("SmartStore.Services.Common.KeepAliveTask, SmartStore.Services", x => - { - x.Name = "Keep alive"; - }) .Alter("SmartStore.Services.Customers.DeleteGuestsTask, SmartStore.Services", x => { x.Name = "Gastbenutzer löschen"; From 7996b6a407025dc33b4a64f83e975aab295af339 Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Wed, 5 Aug 2015 00:20:42 +0200 Subject: [PATCH 0152/1074] Updated changelog --- changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.md b/changelog.md index 4643e9ae8f..06341a80cf 100644 --- a/changelog.md +++ b/changelog.md @@ -35,6 +35,8 @@ * Filter for homepage and published\unpublished products in backend product list * Reduce database round trips initiated by price calculation * Google Analytics: added support for mobile devices +* (Dev) TaskScheduler: Tasks can propagate progress info (percentage & message) +* (Dev) TaskScheduler: Cancellation request is sent to tasks on app shutdown ### Bugfixes * #523 Redirecting to payment provider performed by core instead of plugin From 829d9eeb4fdde4e231bd194ee91874de8b75ed8e Mon Sep 17 00:00:00 2001 From: Murat Cakir Date: Thu, 6 Aug 2015 01:24:05 +0200 Subject: [PATCH 0153/1074] Minor UI fix for TaskScheduler --- .../Administration/Controllers/ScheduleTaskController.cs | 1 + .../Administration/Models/Tasks/ScheduleTaskModel.cs | 1 + .../Administration/Views/ScheduleTask/List.cshtml | 2 +- src/Presentation/SmartStore.Web/Web.config | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs index 0de794588b..28c0c267f9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ScheduleTaskController.cs @@ -101,6 +101,7 @@ protected ScheduleTaskModel PrepareScheduleTaskModel(ScheduleTask task) Id = task.Id, Name = task.Name, Seconds = task.Seconds, + PrettySeconds = TimeSpan.FromSeconds(task.Seconds).Prettify(), Enabled = task.Enabled, StopOnError = task.StopOnError, LastStartUtc = task.LastStartUtc.HasValue ? task.LastStartUtc.Value.RelativeFormat(true, "f") : "", diff --git a/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs index b303fbb6ee..c4b5883759 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/Tasks/ScheduleTaskModel.cs @@ -15,6 +15,7 @@ public partial class ScheduleTaskModel : EntityModelBase [SmartResourceDisplayName("Admin.System.ScheduleTasks.Seconds")] public int Seconds { get; set; } + public string PrettySeconds { get; set; } [SmartResourceDisplayName("Admin.System.ScheduleTasks.Enabled")] public bool Enabled { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml index 0bd33e4cc9..ddbd401aad 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/ScheduleTask/List.cshtml @@ -27,7 +27,7 @@ { columns.Bound(x => x.Name).ClientTemplate("<#= Name #>"); columns.Bound(x => x.Seconds) - .ClientTemplate("<#= _.formatTime(Seconds) #>"); + .ClientTemplate("<#= PrettySeconds #>"); columns.Bound(x => x.Enabled) .ClientTemplate(@Html.SymbolForBool("Enabled")) .Centered() diff --git a/src/Presentation/SmartStore.Web/Web.config b/src/Presentation/SmartStore.Web/Web.config index cabadacd9d..ca8993dab2 100644 --- a/src/Presentation/SmartStore.Web/Web.config +++ b/src/Presentation/SmartStore.Web/Web.config @@ -92,7 +92,7 @@ - + From a120191a6410a17407d44eef557c2471d4c47cdd Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Thu, 6 Aug 2015 11:40:54 +0200 Subject: [PATCH 0154/1074] Disable field for customer number in frontend according to customer setting --- .../SmartStore.Web/Views/Customer/Info.cshtml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Views/Customer/Info.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/Info.cshtml index 2e75e5f05e..e32a12bef9 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/Info.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/Info.cshtml @@ -134,10 +134,12 @@
    } - @if(Model.CustomerNumberEnabled) - { - @Html.ControlGroupFor(model => model.CustomerNumber, required: false) - } +
    + @Html.LabelFor(model => model.CustomerNumber, new { @class = "control-label", @for = "CustomerNumber" }) +
    + @Html.TextBoxFor(model => model.CustomerNumber, !Model.CustomerNumberEnabled ? new { @readonly = "true" } : null) +
    +
    From 9abd1a948fba58983429cc26f6a18fea8daed453 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Thu, 6 Aug 2015 11:40:54 +0200 Subject: [PATCH 0155/1074] Disable field for customer number in frontend according to customer setting --- .../Views/Customer/_CreateOrUpdate.cshtml | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml index 6c72eae453..508b65a07d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Customer/_CreateOrUpdate.cshtml @@ -201,18 +201,15 @@ } - @if (Model.CustomerNumberEnabled) - { - - - @Html.SmartLabelFor(model => model.CustomerNumber) - - - @Html.EditorFor(model => model.CustomerNumber) - @Html.ValidationMessageFor(model => model.CustomerNumber) - - - } + + + @Html.SmartLabelFor(model => model.CustomerNumber) + + + @Html.EditorFor(model => model.CustomerNumber) + @Html.ValidationMessageFor(model => model.CustomerNumber) + + @if (Model.StreetAddressEnabled) { From aa4a544b9c34c383df7ca54e0dfc6459c4d56f15 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Thu, 6 Aug 2015 15:07:26 +0200 Subject: [PATCH 0156/1074] Export framework manages provider specific configuration data --- .../Domain/DataExchange/ExportProfile.cs | 13 +- .../Domain/DataExchange/ExportProjection.cs | 18 + .../SmartStore.Core/SmartStore.Core.csproj | 1 + src/Libraries/SmartStore.Core/XmlHelper.cs | 45 ++- .../Mapping/DataExchange/ExportProfileMap.cs | 2 + .../201508040836122_ExportFramework.resx | 126 ------- ...1508051818404_ExportFramework.Designer.cs} | 2 +- ....cs => 201508051818404_ExportFramework.cs} | 21 +- .../201508051818404_ExportFramework.resx | 126 +++++++ .../SmartStore.Data/SmartStore.Data.csproj | 10 +- .../DataExchange/IExportProvider.cs | 17 +- .../Messages/QueuedMessagesSendTask.cs | 3 +- .../Controllers/ExportController.cs | 264 +++++++++---- .../Models/DataExchange/ExportFilterModel.cs | 2 +- .../Models/DataExchange/ExportPreviewModel.cs | 10 + .../Models/DataExchange/ExportProfileModel.cs | 25 +- .../DataExchange/ExportProjectionModel.cs | 17 + .../Administration/SmartStore.Admin.csproj | 3 + .../Administration/Views/Export/Create.cshtml | 6 +- .../Administration/Views/Export/Edit.cshtml | 357 ++++++++++-------- .../Administration/Views/Export/List.cshtml | 18 +- .../Views/Export/Preview.cshtml | 20 + 22 files changed, 698 insertions(+), 408 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.resx rename src/Libraries/SmartStore.Data/Migrations/{201508040836122_ExportFramework.Designer.cs => 201508051818404_ExportFramework.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201508040836122_ExportFramework.cs => 201508051818404_ExportFramework.cs} (92%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.resx create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportPreviewModel.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProjectionModel.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs index fdd4eb5e34..907701cc2b 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs @@ -38,14 +38,19 @@ public ExportProfile() public int SchedulingTaskId { get; set; } /// - /// The profile GUID is the folder name in the file system + /// XML with filtering information /// - public Guid ProfileGuid { get; set; } + public string Filtering { get; set; } /// - /// XML with filtering information + /// XML with projection information /// - public string Filtering { get; set; } + public string Projection { get; set; } + + /// + /// Provider specific configuration data + /// + public string ProviderConfigData { get; set; } /// /// The number of records to be skipped diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs new file mode 100644 index 0000000000..3020a71b1c --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs @@ -0,0 +1,18 @@ +using System; + +namespace SmartStore.Core.Domain.DataExchange +{ + [Serializable] + public class ExportProjection + { + /// + /// The language to be applied to the export + /// + public int LanguageId { get; set; } + + /// + /// The currency to be applied to the export + /// + public int CurrencyId { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 8e4537dd4c..4dbef97117 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -157,6 +157,7 @@ + diff --git a/src/Libraries/SmartStore.Core/XmlHelper.cs b/src/Libraries/SmartStore.Core/XmlHelper.cs index 7f546eba8a..b73c914f03 100644 --- a/src/Libraries/SmartStore.Core/XmlHelper.cs +++ b/src/Libraries/SmartStore.Core/XmlHelper.cs @@ -120,7 +120,7 @@ public static DateTime DeserializeDateTime(string dateTime) /// /// Object type /// Object instance - /// XML + /// XML string public static string Serialize(T instance) { if (instance != null) @@ -136,11 +136,32 @@ public static string Serialize(T instance) return null; } + /// + /// Serializes an object instance to a XML formatted string + /// + /// Object instance + /// Object type + /// XML string + public static string Serialize(object instance, Type type) + { + if (instance != null) + { + using (var writer = new StringWriter()) + { + var xmlSerializer = new XmlSerializer(type); + + xmlSerializer.Serialize(writer, instance); + return writer.ToString(); + } + } + return null; + } + /// /// Deserializes a XML formatted string to an object instance /// /// Object type - /// XML + /// XML string /// Object instance public static T Deserialize(string xml) { @@ -156,6 +177,26 @@ public static T Deserialize(string xml) return (T)Activator.CreateInstance(typeof(T)); } + /// + /// Deserializes a XML formatted string to an object instance + /// + /// XML string + /// Object type + /// Object instance + public static object Deserialize(string xml, Type type) + { + if (xml.HasValue()) + { + using (var reader = new StringReader(xml)) + { + var serializer = new XmlSerializer(type); + + return serializer.Deserialize(reader); + } + } + return Activator.CreateInstance(type); + } + #endregion } } diff --git a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs index 22d4cc1c4f..c64b24cefe 100644 --- a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs @@ -14,6 +14,8 @@ public ExportProfileMap() this.Property(x => x.FolderName).IsRequired().HasMaxLength(100); this.Property(x => x.ProviderSystemName).IsRequired().HasMaxLength(4000); this.Property(x => x.Filtering).IsMaxLength(); + this.Property(x => x.Projection).IsMaxLength(); + this.Property(x => x.ProviderConfigData).IsMaxLength(); this.HasRequired(x => x.ScheduleTask) .WithMany() diff --git a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.resx deleted file mode 100644 index c1ffae86af..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.Designer.cs index 24f974b961..ebbd4a40ae 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class ExportFramework : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201508040836122_ExportFramework"; } + get { return "201508051818404_ExportFramework"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs rename to src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.cs index b62177e5a4..af3d696b92 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508040836122_ExportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.cs @@ -19,8 +19,9 @@ public override void Up() ProviderSystemName = c.String(nullable: false, maxLength: 4000), Enabled = c.Boolean(nullable: false), SchedulingTaskId = c.Int(nullable: false), - ProfileGuid = c.Guid(nullable: false), Filtering = c.String(), + Projection = c.String(), + ProviderConfigData = c.String(), Offset = c.Int(nullable: false), Limit = c.Int(nullable: false), BatchSize = c.Int(nullable: false), @@ -79,6 +80,11 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "There were no export profiles found.", "Es wurden keine Exportprofile gefunden."); + builder.AddOrUpdate("Admin.Configuration.Export.NoProviderConfigurationRequired", + "The export provider {0} requires no further configuration.", + "Der Export-Provider {0} bentigt keine weitergehende Konfiguration."); + + builder.AddOrUpdate("Admin.Configuration.Export.ProviderSystemName", "Provider", @@ -262,6 +268,19 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Kundengruppen", "Filter by customer roles.", "Nach Kundengruppen filtern."); + + + builder.AddOrUpdate("Admin.Configuration.Export.Projection.LanguageId", + "Language", + "Sprache", + "Specifies the language to be applied to the export.", + "Legt die auf den Export anzuwendende Sprache fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Projection.CurrencyId", + "Currency", + "Whrung", + "Specifies the currency to be applied to the export.", + "Legt die auf den Export anzuwendende Whrung fest."); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.resx new file mode 100644 index 0000000000..3219191ea2 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index bbd83bec0a..a203443917 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -332,9 +332,9 @@ 201507250039446_Merge2.cs - - - 201508040836122_ExportFramework.cs + + + 201508051818404_ExportFramework.cs @@ -633,8 +633,8 @@ 201507250039446_Merge2.cs - - 201508040836122_ExportFramework.cs + + 201508051818404_ExportFramework.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs index 318c0e2586..1f3877ae3a 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportProvider.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using SmartStore.Core.Domain; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Plugins; @@ -7,11 +8,19 @@ namespace SmartStore.Services.DataExchange { public partial interface IExportProvider : IProvider, IUserEditable { - // TODO: a more complex result type is required. e.g. IEnumerable.... - MemoryStream Execute(ExportProfile profile); - ExportEntityType EntityType { get; } string FileType { get; } + + /// + /// Get configuration information + /// + /// The partial view name for the configuration + /// Type of the view model + /// Whether configuration is required + bool RequiresConfiguration(out string partialViewName, out Type modelType); + + // TODO: a more complex result type is required. e.g. IEnumerable.... + MemoryStream Execute(ExportProfile profile); } } diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs index b3058c31a8..7d4c8ab9e8 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs @@ -26,7 +26,8 @@ public void Execute(TaskExecutionContext ctx) MaxSendTries = maxTries, PageIndex = i, PageSize = pageSize, - Expand = "Attachments" + Expand = "Attachments", + UnsentOnly = true }; var queuedEmails = _queuedEmailService.SearchEmails(q); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index ce04e4a736..6f7ac50ab8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -1,6 +1,11 @@ using System; +using System.Globalization; +using System.IO; using System.Linq; +using System.Text; using System.Web.Mvc; +using System.Web.Routing; +using System.Xml.Serialization; using SmartStore.Admin.Models.DataExchange; using SmartStore.Core; using SmartStore.Core.Domain; @@ -14,6 +19,8 @@ using SmartStore.Services.Catalog; using SmartStore.Services.Customers; using SmartStore.Services.DataExchange; +using SmartStore.Services.Directory; +using SmartStore.Services.Localization; using SmartStore.Services.Media; using SmartStore.Services.Security; using SmartStore.Web.Framework; @@ -34,6 +41,8 @@ public class ExportController : AdminControllerBase private readonly IManufacturerService _manufacturerService; private readonly IProductTagService _productTagService; private readonly ICustomerService _customerService; + private readonly ILanguageService _languageService; + private readonly ICurrencyService _currencyService; public ExportController( ICommonServices services, @@ -43,7 +52,9 @@ public ExportController( ICategoryService categoryService, IManufacturerService manufacturerService, IProductTagService productTagService, - ICustomerService customerService) + ICustomerService customerService, + ILanguageService languageService, + ICurrencyService currencyService) { _services = services; _exportService = exportService; @@ -53,56 +64,98 @@ public ExportController( _manufacturerService = manufacturerService; _productTagService = productTagService; _customerService = customerService; + _languageService = languageService; + _currencyService = currencyService; } - private void PrepareExportProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) + #region Utilities + + private string GetThumbnailUrl(Provider provider) { - model.Providing = new ExportProfileModel.Provider - { - SystemName = profile.ProviderSystemName - }; + var url = _pluginMediator.GetIconUrl(provider.Metadata); + + if (url.IsEmpty()) + url = _pictureService.GetDefaultPictureUrl(48); + else + url = Url.Content(url); + return url; + } + + private void PrepareExportProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) + { model.Id = profile.Id; model.Name = profile.Name; model.Enabled = profile.Enabled; model.SchedulingHours = profile.ScheduleTask.Seconds / 3600; + model.Provider = new ExportProfileModel.ProviderModel + { + SystemName = profile.ProviderSystemName + }; + if (provider != null) { - model.Providing.ThumbnailUrl = _pluginMediator.GetIconUrl(provider.Metadata); - - if (model.Providing.ThumbnailUrl.IsEmpty()) - model.Providing.ThumbnailUrl = _pictureService.GetDefaultPictureUrl(48); - else - model.Providing.ThumbnailUrl = Url.Content(model.Providing.ThumbnailUrl); - - model.Providing.Url = provider.Metadata.PluginDescriptor.Url; - model.Providing.ConfigurationUrl = Url.Action("ConfigurePlugin", new { systemName = provider.Metadata.SystemName }); - model.Providing.FriendlyName = _pluginMediator.GetLocalizedFriendlyName(provider.Metadata); - model.Providing.Author = provider.Metadata.PluginDescriptor.Author; - model.Providing.Version = provider.Metadata.PluginDescriptor.Version.ToString(); - model.Providing.Description = _pluginMediator.GetLocalizedDescription(provider.Metadata); - - model.Providing.EntityType = provider.Value.EntityType; - model.Providing.EntityTypeName = T("Enums.SmartStore.Core.Domain.ExportEntityType." + provider.Value.EntityType.ToString()); - model.Providing.FileType = provider.Value.FileType.ToUpper(); + model.Provider.ThumbnailUrl = GetThumbnailUrl(provider); + + model.Provider.Url = provider.Metadata.PluginDescriptor.Url; + model.Provider.ConfigurationUrl = Url.Action("ConfigurePlugin", new { systemName = provider.Metadata.SystemName }); + model.Provider.FriendlyName = _pluginMediator.GetLocalizedFriendlyName(provider.Metadata); + model.Provider.Author = provider.Metadata.PluginDescriptor.Author; + model.Provider.Version = provider.Metadata.PluginDescriptor.Version.ToString(); + model.Provider.Description = _pluginMediator.GetLocalizedDescription(provider.Metadata); + + model.Provider.EntityType = provider.Value.EntityType; + model.Provider.EntityTypeName = T("Enums.SmartStore.Core.Domain.ExportEntityType." + provider.Value.EntityType.ToString()); + model.Provider.FileType = provider.Value.FileType.ToUpper(); } } private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportProfile profile, Provider provider) { var filter = XmlHelper.Deserialize(profile.Filtering); + var projection = XmlHelper.Deserialize(profile.Projection); var allStores = _services.StoreService.GetAllStores(); + var allLanguages = _languageService.GetAllLanguages(true); + var allCurrencies = _currencyService.GetAllCurrencies(true); model.AllString = T("Admin.Common.All"); - //model.UnspecifiedString = T("Common.Unspecified"); + model.UnspecifiedString = T("Common.Unspecified"); model.StoreCount = allStores.Count; model.Offset = profile.Offset; model.Limit = profile.Limit; model.BatchSize = profile.BatchSize; model.PerStore = profile.PerStore; + if (provider != null) + { + string partialName; + Type dataType; + if (provider.Value.RequiresConfiguration(out partialName, out dataType)) + { + model.Provider.ConfigPartialViewName = partialName; + model.Provider.ConfigDataType = dataType; + model.Provider.ConfigData = XmlHelper.Deserialize(profile.ProviderConfigData, dataType); + } + } + + // projection + model.Projection = new ExportProjectionModel + { + LanguageId = projection.LanguageId, + CurrencyId = projection.CurrencyId + }; + + model.Projection.AvailableLanguages = allLanguages + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + model.Projection.AvailableCurrencies = allCurrencies + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + // filtering Action initModelBase = x => { x.StoreId = filter.StoreId; @@ -114,14 +167,14 @@ private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportPr .ToList(); }; - if (model.Providing.EntityType == ExportEntityType.Product) + if (model.Provider.EntityType == ExportEntityType.Product) { var allCategories = _categoryService.GetAllCategories(showHidden: true); var mappedCategories = allCategories.ToDictionary(x => x.Id); var allManufacturers = _manufacturerService.GetAllManufacturers(true); var allProductTags = _productTagService.GetAllProductTags(); - model.ProductFiltering = new ExportProductFilterModel + model.ProductFilter = new ExportProductFilterModel { PriceMinimum = filter.PriceMinimum, PriceMaximum = filter.PriceMaximum, @@ -137,27 +190,27 @@ private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportPr ProductType = filter.ProductType }; - model.ProductFiltering.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); + model.ProductFilter.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); - model.ProductFiltering.AvailableCategories = allCategories + model.ProductFilter.AvailableCategories = allCategories .Select(x => new SelectListItem { Text = x.GetCategoryNameWithPrefix(_categoryService, mappedCategories), Value = x.Id.ToString() }) .ToList(); - model.ProductFiltering.AvailableManufacturers = allManufacturers + model.ProductFilter.AvailableManufacturers = allManufacturers .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) .ToList(); - model.ProductFiltering.AvailableProductTags = allProductTags + model.ProductFilter.AvailableProductTags = allProductTags .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) .ToList(); - initModelBase(model.ProductFiltering); + initModelBase(model.ProductFilter); } - else if (model.Providing.EntityType == ExportEntityType.Order) + else if (model.Provider.EntityType == ExportEntityType.Order) { var allCustomerRoles = _customerService.GetAllCustomerRoles(true); - model.OrderFiltering = new ExportOrderFilterModel + model.OrderFilter = new ExportOrderFilterModel { OrderStatus = filter.OrderStatus, PaymentStatus = filter.PaymentStatus, @@ -165,20 +218,22 @@ private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportPr CustomerRoleIds = filter.CustomerRoleIds }; - model.OrderFiltering.AvailableOrderStates = OrderStatus.Pending.ToSelectList(false).ToList(); - model.OrderFiltering.AvailablePaymentStates = PaymentStatus.Pending.ToSelectList(false).ToList(); - model.OrderFiltering.AvailableShippingStates = ShippingStatus.NotYetShipped.ToSelectList(false).ToList(); + model.OrderFilter.AvailableOrderStates = OrderStatus.Pending.ToSelectList(false).ToList(); + model.OrderFilter.AvailablePaymentStates = PaymentStatus.Pending.ToSelectList(false).ToList(); + model.OrderFilter.AvailableShippingStates = ShippingStatus.NotYetShipped.ToSelectList(false).ToList(); - model.OrderFiltering.AvailableCustomerRoles = allCustomerRoles + model.OrderFilter.AvailableCustomerRoles = allCustomerRoles .OrderBy(x => x.Name) .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) .ToList(); - initModelBase(model.OrderFiltering); + initModelBase(model.OrderFilter); } } - public ActionResult Index() + #endregion + + public ActionResult Index() { return RedirectToAction("List"); } @@ -221,9 +276,9 @@ public ActionResult Create() if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) { var model = new ExportProfileModel(); - model.Providing = new ExportProfileModel.Provider(); + model.Provider = new ExportProfileModel.ProviderModel(); - model.Providing.AvailableExportProviders = _exportService.LoadAllExportProviders() + model.Provider.AvailableExportProviders = _exportService.LoadAllExportProviders() .Select(x => { var item = new SelectListItem @@ -247,9 +302,9 @@ public ActionResult Create(ExportProfileModel model) if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) return AccessDeniedView(); - if (model.Providing.SystemName.HasValue()) + if (model.Provider.SystemName.HasValue()) { - var provider = _exportService.LoadProvider(model.Providing.SystemName); + var provider = _exportService.LoadProvider(model.Provider.SystemName); if (provider != null) { var profile = _exportService.InsertExportProfile(provider); @@ -258,7 +313,7 @@ public ActionResult Create(ExportProfileModel model) } } - NotifyError(T("Admin.Configuration.Export.ProviderSystemName.Validate", model.Providing.SystemName.NaIfEmpty())); + NotifyError(T("Admin.Configuration.Export.ProviderSystemName.Validate", model.Provider.SystemName.NaIfEmpty())); return RedirectToAction("List"); } @@ -282,9 +337,9 @@ public ActionResult Edit(int id) return View(model); } - [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] - [FormValueRequired("save", "save-continue")] - public ActionResult Edit(ExportProfileModel model, bool continueEditing) + [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] + [FormValueRequired("save", "save-continue")] + public ActionResult Edit(ExportProfileModel model, bool continueEditing) { if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) return AccessDeniedView(); @@ -302,8 +357,31 @@ public ActionResult Edit(ExportProfileModel model, bool continueEditing) return View(model); } - ExportFilter filter = null; + profile.Name = model.Name; + profile.Enabled = model.Enabled; + profile.ScheduleTask.Seconds = model.SchedulingHours * 3600; + profile.Offset = model.Offset; + profile.Limit = model.Limit; + profile.BatchSize = model.BatchSize; + profile.PerStore = model.PerStore; + + if (profile.Name.IsEmpty()) + profile.Name = provider.Metadata.FriendlyName; + + if (profile.Name.IsEmpty()) + profile.Name = provider.Metadata.SystemName; + + // projection + var projection = new ExportProjection + { + LanguageId = model.Projection.LanguageId, + CurrencyId = model.Projection.CurrencyId + }; + + profile.Projection = XmlHelper.Serialize(projection); + // filtering + ExportFilter filter = null; Action getFromModelBase = x => { filter.StoreId = x.StoreId ?? 0; @@ -311,54 +389,57 @@ public ActionResult Edit(ExportProfileModel model, bool continueEditing) filter.CreatedTo = x.CreatedTo; }; - if (model.ProductFiltering != null && provider.Value.EntityType == ExportEntityType.Product) + if (model.ProductFilter != null && provider.Value.EntityType == ExportEntityType.Product) { filter = new ExportFilter { - PriceMinimum = model.ProductFiltering.PriceMinimum, - PriceMaximum = model.ProductFiltering.PriceMaximum, - AvailabilityMinimum = model.ProductFiltering.AvailabilityMinimum, - AvailabilityMaximum = model.ProductFiltering.AvailabilityMaximum, - IsPublished = model.ProductFiltering.IsPublished, - CategoryIds = model.ProductFiltering.CategoryIds, - WithoutCategories = model.ProductFiltering.WithoutCategories, - ManufacturerIds = model.ProductFiltering.ManufacturerIds, - WithoutManufacturers = model.ProductFiltering.WithoutManufacturers, - ProductTagIds = model.ProductFiltering.ProductTagIds, - FeaturedProducts = model.ProductFiltering.FeaturedProducts, - ProductType = model.ProductFiltering.ProductType + PriceMinimum = model.ProductFilter.PriceMinimum, + PriceMaximum = model.ProductFilter.PriceMaximum, + AvailabilityMinimum = model.ProductFilter.AvailabilityMinimum, + AvailabilityMaximum = model.ProductFilter.AvailabilityMaximum, + IsPublished = model.ProductFilter.IsPublished, + CategoryIds = model.ProductFilter.CategoryIds, + WithoutCategories = model.ProductFilter.WithoutCategories, + ManufacturerIds = model.ProductFilter.ManufacturerIds, + WithoutManufacturers = model.ProductFilter.WithoutManufacturers, + ProductTagIds = model.ProductFilter.ProductTagIds, + FeaturedProducts = model.ProductFilter.FeaturedProducts, + ProductType = model.ProductFilter.ProductType }; - getFromModelBase(model.ProductFiltering); + getFromModelBase(model.ProductFilter); } - else if (model.OrderFiltering != null && provider.Value.EntityType == ExportEntityType.Order) + else if (model.OrderFilter != null && provider.Value.EntityType == ExportEntityType.Order) { filter = new ExportFilter { - OrderStatus = model.OrderFiltering.OrderStatus, - PaymentStatus = model.OrderFiltering.PaymentStatus, - ShippingStatus = model.OrderFiltering.ShippingStatus, - CustomerRoleIds = model.OrderFiltering.CustomerRoleIds + OrderStatus = model.OrderFilter.OrderStatus, + PaymentStatus = model.OrderFilter.PaymentStatus, + ShippingStatus = model.OrderFilter.ShippingStatus, + CustomerRoleIds = model.OrderFilter.CustomerRoleIds }; - getFromModelBase(model.OrderFiltering); + getFromModelBase(model.OrderFilter); } - profile.Name = model.Name; - profile.Enabled = model.Enabled; - profile.ScheduleTask.Seconds = model.SchedulingHours * 3600; - profile.Offset = model.Offset; - profile.Limit = model.Limit; - profile.BatchSize = model.BatchSize; - profile.PerStore = model.PerStore; - - if (profile.Name.IsEmpty()) - profile.Name = provider.Metadata.FriendlyName; + profile.Filtering = XmlHelper.Serialize(filter); - if (profile.Name.IsEmpty()) - profile.Name = provider.Metadata.SystemName; + // provider configuration + profile.ProviderConfigData = null; + try + { + string partialName; + Type dataType; - profile.Filtering = XmlHelper.Serialize(filter); + if (provider.Value.RequiresConfiguration(out partialName, out dataType) && model.CustomProperties.ContainsKey("ProviderConfigData")) + { + profile.ProviderConfigData = XmlHelper.Serialize(model.CustomProperties["ProviderConfigData"], dataType); + } + } + catch (Exception exc) + { + NotifyError(exc); + } _exportService.UpdateExportProfile(profile); @@ -393,6 +474,27 @@ public ActionResult DeleteConfirmed(int id) return RedirectToAction("Edit", new { id = profile.Id }); } + public ActionResult Preview(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var profile = _exportService.GetExportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + var provider = _exportService.LoadProvider(profile.ProviderSystemName); + + var model = new ExportPreviewModel + { + Id = profile.Id, + Name = profile.Name, + ThumbnailUrl = GetThumbnailUrl(provider) + }; + + return View(model); + } + public ActionResult Execute(int id) { return null; diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs index ca812df0b6..3294830cb9 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs @@ -9,7 +9,7 @@ namespace SmartStore.Admin.Models.DataExchange { - public class ExportFilterModelBase + public abstract class ExportFilterModelBase { [SmartResourceDisplayName("Admin.Configuration.Export.Filter.StoreId")] public int? StoreId { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportPreviewModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportPreviewModel.cs new file mode 100644 index 0000000000..d9aa966dcb --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportPreviewModel.cs @@ -0,0 +1,10 @@ +using SmartStore.Web.Framework.Mvc; + +namespace SmartStore.Admin.Models.DataExchange +{ + public class ExportPreviewModel : EntityModelBase + { + public string Name { get; set; } + public string ThumbnailUrl { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index 4dd20aa2e1..4638c6fd0e 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; +using System.Dynamic; using System.Web.Mvc; -using SmartStore.Core.Domain.Catalog; +using System.Web.Routing; using SmartStore.Core.Domain.DataExchange; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Domain.Shipping; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Mvc; @@ -13,6 +11,10 @@ namespace SmartStore.Admin.Models.DataExchange { public partial class ExportProfileModel : EntityModelBase { + public int StoreCount { get; set; } + public string AllString { get; set; } + public string UnspecifiedString { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Export.Name")] public string Name { get; set; } @@ -38,17 +40,20 @@ public partial class ExportProfileModel : EntityModelBase [SmartResourceDisplayName("Admin.Configuration.Export.PerStore")] public bool PerStore { get; set; } - public Provider Providing { get; set; } + public ProviderModel Provider { get; set; } - public ExportProductFilterModel ProductFiltering { get; set; } - public ExportOrderFilterModel OrderFiltering { get; set; } + public ExportProductFilterModel ProductFilter { get; set; } + public ExportOrderFilterModel OrderFilter { get; set; } - public int StoreCount { get; set; } - public string AllString { get; set; } + public ExportProjectionModel Projection { get; set; } - public class Provider + public class ProviderModel { + public string ConfigPartialViewName { get; set; } + public Type ConfigDataType { get; set; } + public object ConfigData { get; set; } + [SmartResourceDisplayName("Common.Image")] public string ThumbnailUrl { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProjectionModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProjectionModel.cs new file mode 100644 index 0000000000..0cd5ddd22f --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProjectionModel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; + +namespace SmartStore.Admin.Models.DataExchange +{ + public class ExportProjectionModel + { + [SmartResourceDisplayName("Admin.Configuration.Export.Projection.LanguageId")] + public int LanguageId { get; set; } + public List AvailableLanguages { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Projection.CurrencyId")] + public int CurrencyId { get; set; } + public List AvailableCurrencies { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 0d06106427..1fb41c6bf1 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -248,6 +248,8 @@ + + @@ -504,6 +506,7 @@ + diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml index e8b3dc3b2d..3eb5eac1ea 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Create.cshtml @@ -5,16 +5,16 @@ }
    - @if(Model.Providing.AvailableExportProviders.Count > 0) + @if(Model.Provider.AvailableExportProviders.Count > 0) {
    - @Html.SmartLabelFor(model => model.Providing.SystemName) + @Html.SmartLabelFor(model => model.Provider.SystemName) - @Html.DropDownListFor(model => model.Providing.SystemName, Model.Providing.AvailableExportProviders) + @Html.DropDownListFor(model => model.Provider.SystemName, Model.Provider.AvailableExportProviders)
    diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml index ad73a907f4..f825f3b48a 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -8,39 +8,39 @@ @using (Html.BeginForm()) { - @Html.HiddenFor(model => model.Id) +
    + @Html.HiddenFor(model => model.Id) -
    -
    - @if (Model.Providing.ThumbnailUrl.HasValue()) - { - - } -   - @title - @Model.Name @Html.ActionLink("(" + T("Admin.Common.BackToList") + ")", "List") +
    +
    + +   + @title - @Model.Name @Html.ActionLink("(" + T("Admin.Common.BackToList") + ")", "List") +
    +
    +  @T("Admin.Common.Preview") + + + +
    -
    - - - -
    -
    - - @Html.ValidationSummary(false) - @Html.SmartStore().TabStrip().Name("export-profile-edit").Items(x => - { - x.Add().Text(T("Common.General").Text).Content(TabGeneral()).Selected(true); - x.Add().Text(T("Common.Filter").Text).Content(TabFilter()); - x.Add().Text(T("Common.Projection").Text).Content(TabProjection()); - x.Add().Text(T("Common.Partition").Text).Content(TabPartition()); - x.Add().Text(T("Admin.Configuration").Text).Content(TabConfiguration()); - x.Add().Text(T("Common.Publishing").Text).Content(TabDeployment()); + @Html.ValidationSummary(false) - EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "export-profile-edit", this.Html, this.Model)); - }) + @Html.SmartStore().TabStrip().Name("export-profile-edit").Items(x => + { + x.Add().Text(T("Common.General").Text).Content(TabGeneral()).Selected(true); + x.Add().Text(T("Common.Partition").Text).Content(TabPartition()); + x.Add().Text(T("Common.Filter").Text).Content(TabFilter()); + x.Add().Text(T("Common.Projection").Text).Content(TabProjection()); + x.Add().Text(T("Admin.Configuration").Text).Content(TabConfiguration()); + x.Add().Text(T("Common.Publishing").Text).Content(TabDeployment()); + + EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "export-profile-edit", this.Html, this.Model)); + }) +
    } @helper TabGeneral() @@ -48,64 +48,64 @@ - @if (Model.Providing.Url.HasValue()) + @if (Model.Provider.Url.HasValue()) { } + +
    - @Html.SmartLabelFor(model => model.Providing.FriendlyName) + @Html.SmartLabelFor(x => x.Provider.FriendlyName) - @Model.Providing.FriendlyName.NaIfEmpty() - (@(Model.Providing.SystemName.NaIfEmpty())) + @Model.Provider.FriendlyName.NaIfEmpty() + (@(Model.Provider.SystemName.NaIfEmpty()))
    - @Html.SmartLabelFor(model => model.Providing.Author) + @Html.SmartLabelFor(x => x.Provider.Author) - @Html.DisplayFor(model => model.Providing.Author) + @Html.DisplayFor(x => x.Provider.Author)
    - @Html.SmartLabelFor(model => model.Providing.Version) + @Html.SmartLabelFor(x => x.Provider.Version) - @Html.DisplayFor(model => model.Providing.Version) + @Html.DisplayFor(x => x.Provider.Version)
    - @Html.SmartLabelFor(model => model.Providing.Url) + @Html.SmartLabelFor(x => x.Provider.Url) - @Model.Providing.Url + @Model.Provider.Url
    - @Html.SmartLabelFor(model => model.Providing.EntityTypeName) + @Html.SmartLabelFor(x => x.Provider.EntityTypeName) - @Html.DisplayFor(model => model.Providing.EntityTypeName) + @Html.DisplayFor(x => x.Provider.EntityTypeName)
    - @Html.SmartLabelFor(model => model.Providing.FileType) + @Html.SmartLabelFor(x => x.Provider.FileType) - @Html.DisplayFor(model => model.Providing.FileType) + @Html.DisplayFor(x => x.Provider.FileType)
    - @Html.SmartLabelFor(model => model.Providing.Description) + @Html.SmartLabelFor(x => x.Provider.Description) - @if (Model.Providing.Description.HasValue()) + @if (Model.Provider.Description.HasValue()) { - @Html.Raw(Model.Providing.Description) + @Html.Raw(Model.Provider.Description) } else { @@ -120,29 +120,71 @@
    - @Html.SmartLabelFor(model => model.Name) + @Html.SmartLabelFor(x => x.Name) - @Html.EditorFor(model => model.Name) - @Html.ValidationMessageFor(model => model.Name) + @Html.EditorFor(x => x.Name) + @Html.ValidationMessageFor(x => x.Name)
    - @Html.SmartLabelFor(model => model.Enabled) + @Html.SmartLabelFor(x => x.Enabled) - @Html.EditorFor(model => model.Enabled) - @Html.ValidationMessageFor(model => model.Enabled) + @Html.EditorFor(x => x.Enabled) + @Html.ValidationMessageFor(x => x.Enabled)
    - @Html.SmartLabelFor(model => model.SchedulingHours) + @Html.SmartLabelFor(x => x.SchedulingHours) - @Html.EditorFor(model => model.SchedulingHours) - @Html.ValidationMessageFor(model => model.SchedulingHours) + @Html.EditorFor(x => x.SchedulingHours) + @Html.ValidationMessageFor(x => x.SchedulingHours) +
    +} + +@helper TabPartition() +{ + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(x => x.Offset) + + @Html.EditorFor(x => x.Offset) + @Html.ValidationMessageFor(x => x.Offset) +
    + @Html.SmartLabelFor(x => x.Limit) + + @Html.EditorFor(x => x.Limit) + @Html.ValidationMessageFor(x => x.Limit) +
    + @Html.SmartLabelFor(x => x.BatchSize) + + @Html.EditorFor(x => x.BatchSize) + @Html.ValidationMessageFor(x => x.BatchSize) +
    + @Html.SmartLabelFor(x => x.PerStore) + + @Html.EditorFor(x => x.PerStore) + @Html.ValidationMessageFor(x => x.PerStore)
    @@ -151,226 +193,226 @@ @helper TabFilter() { - @if (Model.ProductFiltering != null) + @if (Model.ProductFilter != null) { if (Model.StoreCount > 1) { } } - else if (Model.OrderFiltering != null) + else if (Model.OrderFilter != null) { if (Model.StoreCount > 1) { } } @@ -378,46 +420,24 @@ } @helper TabProjection() -{ -} - -@helper TabPartition() {
    - @Html.SmartLabelFor(model => model.ProductFiltering.StoreId) + @Html.SmartLabelFor(x => x.ProductFilter.StoreId) - @Html.DropDownListFor(model => model.ProductFiltering.StoreId, Model.ProductFiltering.AvailableStores, Model.AllString) - @Html.ValidationMessageFor(model => model.ProductFiltering.StoreId) + @Html.DropDownListFor(x => x.ProductFilter.StoreId, Model.ProductFilter.AvailableStores, Model.AllString) + @Html.ValidationMessageFor(x => x.ProductFilter.StoreId)
    - @Html.SmartLabelFor(model => model.ProductFiltering.CreatedFrom) + @Html.SmartLabelFor(x => x.ProductFilter.CreatedFrom) - @Html.EditorFor(model => model.ProductFiltering.CreatedFrom) - @Html.ValidationMessageFor(model => model.ProductFiltering.CreatedFrom) + @Html.EditorFor(x => x.ProductFilter.CreatedFrom) + @Html.ValidationMessageFor(x => x.ProductFilter.CreatedFrom)
    - @Html.SmartLabelFor(model => model.ProductFiltering.CreatedTo) + @Html.SmartLabelFor(x => x.ProductFilter.CreatedTo) - @Html.EditorFor(model => model.ProductFiltering.CreatedTo) - @Html.ValidationMessageFor(model => model.ProductFiltering.CreatedTo) + @Html.EditorFor(x => x.ProductFilter.CreatedTo) + @Html.ValidationMessageFor(x => x.ProductFilter.CreatedTo)
    - @Html.SmartLabelFor(model => model.ProductFiltering.ProductType) + @Html.SmartLabelFor(x => x.ProductFilter.ProductType) - @Html.DropDownListFor(model => model.ProductFiltering.ProductType, Model.ProductFiltering.AvailableProductTypes, Model.AllString) + @Html.DropDownListFor(x => x.ProductFilter.ProductType, Model.ProductFilter.AvailableProductTypes, Model.AllString)
    - @Html.SmartLabelFor(model => model.ProductFiltering.IsPublished) + @Html.SmartLabelFor(x => x.ProductFilter.IsPublished) - @Html.EditorFor(model => model.ProductFiltering.IsPublished) - @Html.ValidationMessageFor(model => model.ProductFiltering.IsPublished) + @Html.EditorFor(x => x.ProductFilter.IsPublished) + @Html.ValidationMessageFor(x => x.ProductFilter.IsPublished)
    - @Html.SmartLabelFor(model => model.ProductFiltering.PriceMinimum) + @Html.SmartLabelFor(x => x.ProductFilter.PriceMinimum) - @Html.EditorFor(model => model.ProductFiltering.PriceMinimum) - @Html.ValidationMessageFor(model => model.ProductFiltering.PriceMinimum) + @Html.EditorFor(x => x.ProductFilter.PriceMinimum) + @Html.ValidationMessageFor(x => x.ProductFilter.PriceMinimum)
    - @Html.SmartLabelFor(model => model.ProductFiltering.PriceMaximum) + @Html.SmartLabelFor(x => x.ProductFilter.PriceMaximum) - @Html.EditorFor(model => model.ProductFiltering.PriceMaximum) - @Html.ValidationMessageFor(model => model.ProductFiltering.PriceMaximum) + @Html.EditorFor(x => x.ProductFilter.PriceMaximum) + @Html.ValidationMessageFor(x => x.ProductFilter.PriceMaximum)
    - @Html.SmartLabelFor(model => model.ProductFiltering.AvailabilityMinimum) + @Html.SmartLabelFor(x => x.ProductFilter.AvailabilityMinimum) - @Html.EditorFor(model => model.ProductFiltering.AvailabilityMinimum) - @Html.ValidationMessageFor(model => model.ProductFiltering.AvailabilityMinimum) + @Html.EditorFor(x => x.ProductFilter.AvailabilityMinimum) + @Html.ValidationMessageFor(x => x.ProductFilter.AvailabilityMinimum)
    - @Html.SmartLabelFor(model => model.ProductFiltering.AvailabilityMaximum) + @Html.SmartLabelFor(x => x.ProductFilter.AvailabilityMaximum) - @Html.EditorFor(model => model.ProductFiltering.AvailabilityMaximum) - @Html.ValidationMessageFor(model => model.ProductFiltering.AvailabilityMaximum) + @Html.EditorFor(x => x.ProductFilter.AvailabilityMaximum) + @Html.ValidationMessageFor(x => x.ProductFilter.AvailabilityMaximum)
    - @Html.SmartLabelFor(model => model.ProductFiltering.WithoutCategories) + @Html.SmartLabelFor(x => x.ProductFilter.WithoutCategories) - @Html.EditorFor(model => model.ProductFiltering.WithoutCategories) - @Html.ValidationMessageFor(model => model.ProductFiltering.WithoutCategories) + @Html.EditorFor(x => x.ProductFilter.WithoutCategories) + @Html.ValidationMessageFor(x => x.ProductFilter.WithoutCategories)
    - @Html.SmartLabelFor(model => model.ProductFiltering.CategoryIds) + @Html.SmartLabelFor(x => x.ProductFilter.CategoryIds) - @Html.ListBoxFor(model => model.ProductFiltering.CategoryIds, - new MultiSelectList(Model.ProductFiltering.AvailableCategories, "Value", "Text"), + @Html.ListBoxFor(x => x.ProductFilter.CategoryIds, + new MultiSelectList(Model.ProductFilter.AvailableCategories, "Value", "Text"), new { multiple = "multiple", @class = "control-xlarge" }) - @Html.ValidationMessageFor(model => model.ProductFiltering.CategoryIds) + @Html.ValidationMessageFor(x => x.ProductFilter.CategoryIds)
    - @Html.SmartLabelFor(model => model.ProductFiltering.WithoutManufacturers) + @Html.SmartLabelFor(x => x.ProductFilter.WithoutManufacturers) - @Html.EditorFor(model => model.ProductFiltering.WithoutManufacturers) - @Html.ValidationMessageFor(model => model.ProductFiltering.WithoutManufacturers) + @Html.EditorFor(x => x.ProductFilter.WithoutManufacturers) + @Html.ValidationMessageFor(x => x.ProductFilter.WithoutManufacturers)
    - @Html.SmartLabelFor(model => model.ProductFiltering.ManufacturerIds) + @Html.SmartLabelFor(x => x.ProductFilter.ManufacturerIds) - @Html.ListBoxFor(model => model.ProductFiltering.ManufacturerIds, - new MultiSelectList(Model.ProductFiltering.AvailableManufacturers, "Value", "Text"), + @Html.ListBoxFor(x => x.ProductFilter.ManufacturerIds, + new MultiSelectList(Model.ProductFilter.AvailableManufacturers, "Value", "Text"), new { multiple = "multiple", @class = "control-xlarge" }) - @Html.ValidationMessageFor(model => model.ProductFiltering.ManufacturerIds) + @Html.ValidationMessageFor(x => x.ProductFilter.ManufacturerIds)
    - @Html.SmartLabelFor(model => model.ProductFiltering.ProductTagIds) + @Html.SmartLabelFor(x => x.ProductFilter.ProductTagIds) - @Html.ListBoxFor(model => model.ProductFiltering.ProductTagIds, - new MultiSelectList(Model.ProductFiltering.AvailableProductTags, "Value", "Text"), + @Html.ListBoxFor(x => x.ProductFilter.ProductTagIds, + new MultiSelectList(Model.ProductFilter.AvailableProductTags, "Value", "Text"), new { multiple = "multiple", @class = "control-xlarge" }) - @Html.ValidationMessageFor(model => model.ProductFiltering.ProductTagIds) + @Html.ValidationMessageFor(x => x.ProductFilter.ProductTagIds)
    - @Html.SmartLabelFor(model => model.ProductFiltering.FeaturedProducts) + @Html.SmartLabelFor(x => x.ProductFilter.FeaturedProducts) - @Html.EditorFor(model => model.ProductFiltering.FeaturedProducts) - @Html.ValidationMessageFor(model => model.ProductFiltering.FeaturedProducts) + @Html.EditorFor(x => x.ProductFilter.FeaturedProducts) + @Html.ValidationMessageFor(x => x.ProductFilter.FeaturedProducts)
    - @Html.SmartLabelFor(model => model.OrderFiltering.StoreId) + @Html.SmartLabelFor(x => x.OrderFilter.StoreId) - @Html.DropDownListFor(model => model.OrderFiltering.StoreId, Model.OrderFiltering.AvailableStores, Model.AllString) - @Html.ValidationMessageFor(model => model.OrderFiltering.StoreId) + @Html.DropDownListFor(x => x.OrderFilter.StoreId, Model.OrderFilter.AvailableStores, Model.AllString) + @Html.ValidationMessageFor(x => x.OrderFilter.StoreId)
    - @Html.SmartLabelFor(model => model.OrderFiltering.CreatedFrom) + @Html.SmartLabelFor(x => x.OrderFilter.CreatedFrom) - @Html.EditorFor(model => model.OrderFiltering.CreatedFrom) - @Html.ValidationMessageFor(model => model.OrderFiltering.CreatedFrom) + @Html.EditorFor(x => x.OrderFilter.CreatedFrom) + @Html.ValidationMessageFor(x => x.OrderFilter.CreatedFrom)
    - @Html.SmartLabelFor(model => model.OrderFiltering.CreatedTo) + @Html.SmartLabelFor(x => x.OrderFilter.CreatedTo) - @Html.EditorFor(model => model.OrderFiltering.CreatedTo) - @Html.ValidationMessageFor(model => model.OrderFiltering.CreatedTo) + @Html.EditorFor(x => x.OrderFilter.CreatedTo) + @Html.ValidationMessageFor(x => x.OrderFilter.CreatedTo)
    - @Html.SmartLabelFor(model => model.OrderFiltering.OrderStatus) + @Html.SmartLabelFor(x => x.OrderFilter.OrderStatus) - @Html.ListBoxFor(model => model.OrderFiltering.OrderStatus, - new MultiSelectList(Model.OrderFiltering.AvailableOrderStates, "Value", "Text"), + @Html.ListBoxFor(x => x.OrderFilter.OrderStatus, + new MultiSelectList(Model.OrderFilter.AvailableOrderStates, "Value", "Text"), new { multiple = "multiple", @class = "control-xlarge" }) - @Html.ValidationMessageFor(model => model.OrderFiltering.OrderStatus) + @Html.ValidationMessageFor(x => x.OrderFilter.OrderStatus)
    - @Html.SmartLabelFor(model => model.OrderFiltering.PaymentStatus) + @Html.SmartLabelFor(x => x.OrderFilter.PaymentStatus) - @Html.ListBoxFor(model => model.OrderFiltering.PaymentStatus, - new MultiSelectList(Model.OrderFiltering.AvailablePaymentStates, "Value", "Text"), + @Html.ListBoxFor(x => x.OrderFilter.PaymentStatus, + new MultiSelectList(Model.OrderFilter.AvailablePaymentStates, "Value", "Text"), new { multiple = "multiple", @class = "control-xlarge" }) - @Html.ValidationMessageFor(model => model.OrderFiltering.PaymentStatus) + @Html.ValidationMessageFor(x => x.OrderFilter.PaymentStatus)
    - @Html.SmartLabelFor(model => model.OrderFiltering.ShippingStatus) + @Html.SmartLabelFor(x => x.OrderFilter.ShippingStatus) - @Html.ListBoxFor(model => model.OrderFiltering.ShippingStatus, - new MultiSelectList(Model.OrderFiltering.AvailableShippingStates, "Value", "Text"), + @Html.ListBoxFor(x => x.OrderFilter.ShippingStatus, + new MultiSelectList(Model.OrderFilter.AvailableShippingStates, "Value", "Text"), new { multiple = "multiple", @class = "control-xlarge" }) - @Html.ValidationMessageFor(model => model.OrderFiltering.ShippingStatus) + @Html.ValidationMessageFor(x => x.OrderFilter.ShippingStatus)
    - @Html.SmartLabelFor(model => model.OrderFiltering.CustomerRoleIds) + @Html.SmartLabelFor(x => x.OrderFilter.CustomerRoleIds) - @Html.ListBoxFor(model => model.OrderFiltering.CustomerRoleIds, - new MultiSelectList(Model.OrderFiltering.AvailableCustomerRoles, "Value", "Text"), + @Html.ListBoxFor(x => x.OrderFilter.CustomerRoleIds, + new MultiSelectList(Model.OrderFilter.AvailableCustomerRoles, "Value", "Text"), new { multiple = "multiple", @class = "control-xlarge" }) - @Html.ValidationMessageFor(model => model.OrderFiltering.CustomerRoleIds) + @Html.ValidationMessageFor(x => x.OrderFilter.CustomerRoleIds)
    - - - - - - - -
    - @Html.SmartLabelFor(model => model.Offset) - - @Html.EditorFor(model => model.Offset) - @Html.ValidationMessageFor(model => model.Offset) -
    - @Html.SmartLabelFor(model => model.Limit) - - @Html.EditorFor(model => model.Limit) - @Html.ValidationMessageFor(model => model.Limit) -
    - @Html.SmartLabelFor(model => model.BatchSize) + @Html.SmartLabelFor(x => x.Projection.LanguageId) - @Html.EditorFor(model => model.BatchSize) - @Html.ValidationMessageFor(model => model.BatchSize) + @Html.DropDownListFor(x => x.Projection.LanguageId, Model.Projection.AvailableLanguages, Model.UnspecifiedString) + @Html.ValidationMessageFor(x => x.Projection.LanguageId)
    - @Html.SmartLabelFor(model => model.PerStore) + @Html.SmartLabelFor(x => x.Projection.CurrencyId) - @Html.EditorFor(model => model.PerStore) - @Html.ValidationMessageFor(model => model.PerStore) + @Html.DropDownListFor(x => x.Projection.CurrencyId, Model.Projection.AvailableCurrencies, Model.UnspecifiedString) + @Html.ValidationMessageFor(x => x.Projection.CurrencyId)
    @@ -425,6 +445,23 @@ @helper TabConfiguration() { +
    +
    + @if (Model.Provider.ConfigPartialViewName.HasValue()) + { + var viewData = new ViewDataDictionary(); + viewData.TemplateInfo.HtmlFieldPrefix = "CustomProperties[ProviderConfigData]"; + @Html.Hidden("CustomProperties[ProviderConfigData].__Type__", Model.Provider.ConfigDataType.AssemblyQualifiedName) + @Html.Partial(Model.Provider.ConfigPartialViewName, Model.Provider.ConfigData, viewData) + } + else + { +
    + @Html.Raw(T("Admin.Configuration.Export.NoProviderConfigurationRequired", Model.Provider.FriendlyName.NaIfEmpty())) +
    + } +
    +
    } @helper TabDeployment() @@ -437,14 +474,14 @@ jQuery(document).ready(function () { // show/hide product category filter - $('select[name="ProductFiltering.WithoutCategories"]').change(function () { + $('select[name="ProductFilter.WithoutCategories"]').change(function () { $('#FilterCategoryIdsContainer').toggle(_.isEmpty($(this).val())); }).trigger('change'); // show/hide product manufacturer filter - $('select[name="ProductFiltering.WithoutManufacturers"]').change(function () { + $('select[name="ProductFilter.WithoutManufacturers"]').change(function () { $('#FilterManufacturerIdsContainer').toggle(_.isEmpty($(this).val())); }).trigger('change'); }); - + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index a38c3a9ed5..10fafd92f6 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -35,29 +35,29 @@ }) .Columns(columns => { - columns.Bound(x => x.Providing.ThumbnailUrl) + columns.Bound(x => x.Provider.ThumbnailUrl) .Width(70) .Centered() .Template( @ - @item.Id + @item.Id ) - .ClientTemplate("<#= Id #>"); + .ClientTemplate("<#= Id #>"); columns.Bound(x => x.Name) .Width(400) .Template(x => Html.ActionLink(x.Name, "Edit", new { id = x.Id })) .ClientTemplate("\"><#= Name #>"); - columns.Bound(x => x.Providing.SystemName) - .Template(x => "{0} ({1})".FormatInvariant(x.Providing.FriendlyName, x.Providing.SystemName)) - .ClientTemplate("<#= Providing.FriendlyName #> (<#= Providing.SystemName #>)"); + columns.Bound(x => x.Provider.SystemName) + .Template(x => "{0} ({1})".FormatInvariant(x.Provider.FriendlyName, x.Provider.SystemName)) + .ClientTemplate("<#= Provider.FriendlyName #> (<#= Provider.SystemName #>)"); columns.Bound(x => x.Enabled) .Width(100) .Template(item => @Html.SymbolForBool(item.Enabled)) .ClientTemplate(@Html.SymbolForBool("Enabled")) .Centered(); - columns.Bound(x => x.Providing.EntityTypeName); - columns.Bound(x => x.Providing.FileType) + columns.Bound(x => x.Provider.EntityTypeName); + columns.Bound(x => x.Provider.FileType) .Centered(); columns.Bound(x => x.SchedulingHours) .Centered(); @@ -115,7 +115,7 @@ smallIcon: dialog.find('.modal-body'), callbackSuccess: function (resp) { dialog.find('.modal-body').html(resp); - $('select[name="Providing.SystemName"]').selectWrapper(); + $('select[name="Provider.SystemName"]').selectWrapper(); }, callbackComplete: function () { showPrimaryButton(true); diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml new file mode 100644 index 0000000000..710655ebfc --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Preview.cshtml @@ -0,0 +1,20 @@ +@using SmartStore.Admin.Models.DataExchange +@model ExportPreviewModel +@{ + var title = string.Concat(T("Admin.Common.Preview"), " ", T("Common.Export")); + ViewBag.Title = title; +} + +
    +
    + +   + @title - @Model.Name @Html.ActionLink("(" + T("Common.Back") + ")", "Edit", new { id = Model.Id }) +
    +
    +
    +
    + +
    + TODO +
    \ No newline at end of file From b547e25d3032ae4e24c0865c187fa50cbf072375 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Fri, 7 Aug 2015 13:10:49 +0200 Subject: [PATCH 0157/1074] Added export deployment entity --- .../Domain/DataExchange/ExportCore.cs | 8 ++ .../Domain/DataExchange/ExportDeployment.cs | 80 +++++++++++ .../Domain/DataExchange/ExportFilter.cs | 7 +- .../Domain/DataExchange/ExportProfile.cs | 22 +++ .../Domain/DataExchange/ExportProjection.cs | 4 +- .../SmartStore.Core/SmartStore.Core.csproj | 1 + .../DataExchange/ExportDeploymentMap.cs | 29 ++++ .../Mapping/DataExchange/ExportProfileMap.cs | 1 + .../201508051818404_ExportFramework.resx | 126 ------------------ ...1508070937542_ExportFramework.Designer.cs} | 2 +- ....cs => 201508070937542_ExportFramework.cs} | 125 ++++++++++++++++- .../201508070937542_ExportFramework.resx | 126 ++++++++++++++++++ .../SmartStore.Data/SmartStore.Data.csproj | 11 +- .../DataExchange/ExportService.cs | 21 ++- .../DataExchange/IExportService.cs | 8 ++ .../Controllers/ExportController.cs | 96 ++++++++++--- .../DataExchange/ExportDeploymentModel.cs | 49 +++++++ .../Models/DataExchange/ExportFilterModel.cs | 2 +- .../Models/DataExchange/ExportProfileModel.cs | 13 +- .../DataExchange/ExportProjectionModel.cs | 4 +- .../Administration/SmartStore.Admin.csproj | 3 + .../DataExchange/ExportDeplomentValidator.cs | 16 +++ .../DataExchange/ExportProfileValidator.cs | 16 +++ .../Administration/Views/Export/Edit.cshtml | 61 ++++++++- .../Administration/Views/Export/List.cshtml | 6 +- 25 files changed, 666 insertions(+), 171 deletions(-) create mode 100644 src/Libraries/SmartStore.Core/Domain/DataExchange/ExportDeployment.cs create mode 100644 src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportDeploymentMap.cs delete mode 100644 src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.resx rename src/Libraries/SmartStore.Data/Migrations/{201508051818404_ExportFramework.Designer.cs => 201508070937542_ExportFramework.Designer.cs} (92%) rename src/Libraries/SmartStore.Data/Migrations/{201508051818404_ExportFramework.cs => 201508070937542_ExportFramework.cs} (62%) create mode 100644 src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.resx create mode 100644 src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportDeplomentValidator.cs create mode 100644 src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportProfileValidator.cs diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs index 2f513eab63..7ddc34bf58 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportCore.cs @@ -11,4 +11,12 @@ public enum ExportEntityType Order, NewsletterSubscriber } + + public enum ExportDeploymentType + { + FileSystem = 0, + Email, + Http, + Ftp + } } diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportDeployment.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportDeployment.cs new file mode 100644 index 0000000000..0f350e499f --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportDeployment.cs @@ -0,0 +1,80 @@ +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Core.Domain +{ + public class ExportDeployment : BaseEntity + { + /// + /// The profile identifier + /// + public int ProfileId { get; set; } + + /// + /// Name of the deployment + /// + public string Name { get; set; } + + /// + /// Whether the deployment is enabled + /// + public bool Enabled { get; set; } + + /// + /// Whether to deploy in a folder that can be reached from the internet + /// + public bool IsPublic { get; set; } + + /// + /// The deployment type identifier + /// + public int DeploymentTypeId { get; set; } + + /// + /// The deployment type + /// + public ExportDeploymentType DeploymentType + { + get + { + return (ExportDeploymentType)DeploymentTypeId; + } + set + { + DeploymentTypeId = (int)value; + } + } + + public string Username { get; set; } + + public string Password { get; set; } + + /// + /// Deployment URL + /// + public string Url { get; set; } + + /// + /// The file system path + /// + public string FileSystemPath { get; set; } + + /// + /// Multiple email addresses can be separated by semicolon + /// + public string EmailAddresses { get; set; } + + /// + /// Subject of the email + /// + public string EmailSubject { get; set; } + + /// + /// Identifier of the email account + /// + public int EmailAccountId { get; set; } + + // TODO: more FTP options + + public virtual ExportProfile Profile { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs index db02950efb..4d7ecd7316 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs @@ -10,6 +10,11 @@ namespace SmartStore.Core.Domain.DataExchange [Serializable] public class ExportFilter { + public ExportFilter() + { + IsPublished = true; + } + /// /// Store identifier; 0 to load all records /// @@ -50,7 +55,7 @@ public class ExportFilter /// /// A value indicating whether to load only published or non published products /// - public bool? IsPublished { get; set; } + public bool IsPublished { get; set; } /// /// Category identifiers diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs index 907701cc2b..0de9030c7e 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Tasks; @@ -6,6 +7,8 @@ namespace SmartStore.Core.Domain { public class ExportProfile : BaseEntity { + private ICollection _deployments; + public ExportProfile() { Limit = 100; @@ -72,9 +75,28 @@ public ExportProfile() /// public bool PerStore { get; set; } + /// + /// Whether to combine and compress the export files in a ZIP archive + /// + public bool CreateZipArchive { get; set; } + + /// + /// Email addresses (semicolon separated) where to send a notification message of the completion of the export + /// + public string CompletedEmailAddresses { get; set; } + /// /// The scheduling task /// public virtual ScheduleTask ScheduleTask { get; set; } + + /// + /// Gets or sets export deployments + /// + public virtual ICollection Deployments + { + get { return _deployments ?? (_deployments = new HashSet()); } + set { _deployments = value; } + } } } diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs index 3020a71b1c..8696afbdce 100644 --- a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs @@ -8,11 +8,11 @@ public class ExportProjection /// /// The language to be applied to the export /// - public int LanguageId { get; set; } + public int? LanguageId { get; set; } /// /// The currency to be applied to the export /// - public int CurrencyId { get; set; } + public int? CurrencyId { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index 4dbef97117..e04d7f01e5 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -157,6 +157,7 @@ + diff --git a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportDeploymentMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportDeploymentMap.cs new file mode 100644 index 0000000000..0a57740d6e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportDeploymentMap.cs @@ -0,0 +1,29 @@ +using System.Data.Entity.ModelConfiguration; +using SmartStore.Core.Domain; + +namespace SmartStore.Data.Mapping.DataExchange +{ + public class ExportDeploymentMap : EntityTypeConfiguration + { + public ExportDeploymentMap() + { + this.ToTable("ExportDeployment"); + this.HasKey(x => x.Id); + + this.Property(x => x.Name).IsRequired().HasMaxLength(100); + this.Property(x => x.Username).HasMaxLength(400); + this.Property(x => x.Password).HasMaxLength(400); + this.Property(x => x.Url).HasMaxLength(4000); + this.Property(x => x.FileSystemPath).HasMaxLength(400); + this.Property(x => x.EmailAddresses).HasMaxLength(4000); + this.Property(x => x.EmailSubject).HasMaxLength(400); + + this.Ignore(x => x.DeploymentType); + + this.HasRequired(x => x.Profile) + .WithMany(x => x.Deployments) + .HasForeignKey(x => x.ProfileId) + .WillCascadeOnDelete(true); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs index c64b24cefe..7d62b17bd6 100644 --- a/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs +++ b/src/Libraries/SmartStore.Data/Mapping/DataExchange/ExportProfileMap.cs @@ -16,6 +16,7 @@ public ExportProfileMap() this.Property(x => x.Filtering).IsMaxLength(); this.Property(x => x.Projection).IsMaxLength(); this.Property(x => x.ProviderConfigData).IsMaxLength(); + this.Property(x => x.CompletedEmailAddresses).HasMaxLength(400); this.HasRequired(x => x.ScheduleTask) .WithMany() diff --git a/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.resx deleted file mode 100644 index 3219191ea2..0000000000 --- a/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 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 - - - dbo - - \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.Designer.cs similarity index 92% rename from src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.Designer.cs rename to src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.Designer.cs index ebbd4a40ae..eb6be6802a 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.Designer.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.Designer.cs @@ -13,7 +13,7 @@ public sealed partial class ExportFramework : IMigrationMetadata string IMigrationMetadata.Id { - get { return "201508051818404_ExportFramework"; } + get { return "201508070937542_ExportFramework"; } } string IMigrationMetadata.Source diff --git a/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.cs similarity index 62% rename from src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.cs rename to src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.cs index af3d696b92..c85249ef25 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508051818404_ExportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.cs @@ -9,6 +9,28 @@ public partial class ExportFramework : DbMigration, ILocaleResourcesProvider, ID { public override void Up() { + CreateTable( + "dbo.ExportDeployment", + c => new + { + Id = c.Int(nullable: false, identity: true), + ProfileId = c.Int(nullable: false), + Name = c.String(nullable: false, maxLength: 100), + Enabled = c.Boolean(nullable: false), + IsPublic = c.Boolean(nullable: false), + DeploymentTypeId = c.Int(nullable: false), + Username = c.String(maxLength: 400), + Password = c.String(maxLength: 400), + Url = c.String(maxLength: 4000), + FileSystemPath = c.String(maxLength: 400), + EmailAddresses = c.String(maxLength: 4000), + EmailSubject = c.String(maxLength: 400), + EmailAccountId = c.Int(nullable: false), + }) + .PrimaryKey(t => t.Id) + .ForeignKey("dbo.ExportProfile", t => t.ProfileId, cascadeDelete: true) + .Index(t => t.ProfileId); + CreateTable( "dbo.ExportProfile", c => new @@ -26,6 +48,8 @@ public override void Up() Limit = c.Int(nullable: false), BatchSize = c.Int(nullable: false), PerStore = c.Boolean(nullable: false), + CreateZipArchive = c.Boolean(nullable: false), + CompletedEmailAddresses = c.String(maxLength: 400), }) .PrimaryKey(t => t.Id) .ForeignKey("dbo.ScheduleTask", t => t.SchedulingTaskId) @@ -35,9 +59,12 @@ public override void Up() public override void Down() { + DropForeignKey("dbo.ExportDeployment", "ProfileId", "dbo.ExportProfile"); DropForeignKey("dbo.ExportProfile", "SchedulingTaskId", "dbo.ScheduleTask"); DropIndex("dbo.ExportProfile", new[] { "SchedulingTaskId" }); + DropIndex("dbo.ExportDeployment", new[] { "ProfileId" }); DropTable("dbo.ExportProfile"); + DropTable("dbo.ExportDeployment"); } public bool RollbackOnFailure @@ -68,7 +95,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Common.Image", "Image", "Bild"); builder.AddOrUpdate("Common.Filter", "Filter", "Filter"); builder.AddOrUpdate("Common.Projection", "Projection", "Projektion"); - builder.AddOrUpdate("Common.Publishing", "Publishing", "Verffentlichung"); + builder.AddOrUpdate("Common.Deployment", "Deployment", "Bereitstellung"); builder.AddOrUpdate("Common.Website", "Website", "Web-Seite"); @@ -105,6 +132,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies the name of the export profile.", "Legt den Namen des Exportprofils fest."); + builder.AddOrUpdate("Admin.Configuration.Export.Name.Validate", + "Please enter the name of the profile.", + "Bitte den Namen des Profils eingeben."); + builder.AddOrUpdate("Admin.Configuration.Export.FileType", "File type", "Dateityp", @@ -148,12 +179,23 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies whether to start a separate run-through for each store.", "Legt fest, ob fr jeden Shop ein separater Verarbeitungsdurchlauf erfolgen soll."); + builder.AddOrUpdate("Admin.Configuration.Export.CreateZipArchive", + "Create ZIP archive", + "ZIP-Archiv erstellen", + "Specifies whether to combine and compress the export files in a ZIP archive.", + "Legt fest, ob die Exportdateien in einem ZIP-Archiv zusammengefasst und komprimiert werden sollen."); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Product", "Product", "Produkt"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Category", "Category", "Warengruppe"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Manufacturer", "Manufacturer", "Hersteller"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Customer", "Customer", "Kunde"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.ExportEntityType.Order", "Order", "Auftrag"); + builder.AddOrUpdate("Admin.Configuration.Export.CompletedEmailAddresses", + "Notification (email addresses)", + "Benachrichtigung (E-Mail-Addressen)", + "Specifies the email addresses (semicolon separated) where to send a notification message of the completion of the export.", + "Legt die E-Mail Addressen (Semikolon getrennt) fest, an die eine Benachrichtigung ber die Fertigstellung des Exports verschickt werden soll."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Product", "Product", "Produkt"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Category", "Category", "Warengruppe"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Manufacturer", "Manufacturer", "Hersteller"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Customer", "Customer", "Kunde"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Order", "Order", "Auftrag"); builder.AddOrUpdate("Admin.Configuration.Export.Filter.StoreId", "Store", @@ -281,6 +323,77 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Whrung", "Specifies the currency to be applied to the export.", "Legt die auf den Export anzuwendende Whrung fest."); + + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.FileSystem", "File system", "Dateisystem"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Email", "Email", "E-Mail"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Http", "HTTP", "HTTP"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Ftp", "FTP", "FTP"); + + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.Name", + "Name", + "Name", + "Specifies the name of the deployment.", + "Legt den Namen der Bereitstellung fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.Name.Validate", + "Please enter the name of the deployment.", + "Bitte den Namen der Bereitstellung eingeben."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.IsPublic", + "Make public", + "ffentlich machen", + "Specifies whether to publish the exported data (e.g. whether they are accessible on the internet).", + "Legt fest, ob die exportierten Daten ffentlich gemacht werden sollen (z.B. ob sie ber das Internet erreichbar sind)."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.DeploymentType", + "Type of deployment", + "Typ der Bereitstellung", + "Specifies the deployment type.", + "Legt den Bereitstellungstyp fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.Username", + "User name", + "Benutzername", + "Specifies the user name.", + "Legt den Benutzernamen fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.Password", + "Password", + "Passwort", + "Specifies the password.", + "Legt das Passwort fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.Url", + "URL", + "URL", + "Specifies the URL on which the data should be deployed.", + "Legt die URL fest, unter der die Daten bereitgestellt werden sollen."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.FileSystemPath", + "Relative path", + "Relativer Pfad", + "Specifies the relative path for the deployed data.", + "Legt den relativen Pfad fr die bereitgestellten Daten fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.EmailAddresses", + "Email addresses", + "E-Mail-Addressen", + "Specifies the email addresses (semicolon separated) where to send the data.", + "Legt die E-Mail Addressen (Semikolon getrennt) fest, an die die Daten verschickt werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.EmailSubject", + "Email subject", + "E-Mail Betreff", + "Specifies the subject of the data should be sent.", + "Legt den Betreff der verschickten Daten fest."); + + builder.AddOrUpdate("Admin.Configuration.Export.Deployment.EmailAccountId", + "Email account", + "E-Mail Konto", + "Specifies the email account through which the data should be sent.", + "Legt das E-Mail Konto fest, ber welches die Daten verschickt werden sollen."); } } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.resx new file mode 100644 index 0000000000..80b65fc188 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index a203443917..48259842a2 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -120,6 +120,7 @@ + @@ -332,9 +333,9 @@ 201507250039446_Merge2.cs - - - 201508051818404_ExportFramework.cs + + + 201508070937542_ExportFramework.cs @@ -633,8 +634,8 @@ 201507250039446_Merge2.cs - - 201508051818404_ExportFramework.cs + + 201508070937542_ExportFramework.cs diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs index 2b8a2f2ba1..d678942acc 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs @@ -16,17 +16,20 @@ public partial class ExportService : IExportService private const int _defaultSchedulingHours = 6; private readonly IRepository _exportProfileRepository; + private readonly IRepository _exportDeploymentRepository; private readonly IEventPublisher _eventPublisher; private readonly IScheduleTaskService _scheduleTaskService; private readonly IProviderManager _providerManager; public ExportService( IRepository exportProfileRepository, + IRepository exportDeploymentRepository, IEventPublisher eventPublisher, IScheduleTaskService scheduleTaskService, IProviderManager providerManager) { _exportProfileRepository = exportProfileRepository; + _exportDeploymentRepository = exportDeploymentRepository; _eventPublisher = eventPublisher; _scheduleTaskService = scheduleTaskService; _providerManager = providerManager; @@ -123,7 +126,12 @@ public virtual ExportProfile GetExportProfileById(int id) if (id == 0) return null; - return _exportProfileRepository.GetById(id); + var profile = _exportProfileRepository.Table + .Expand(x => x.ScheduleTask) + .Expand(x => x.Deployments) + .FirstOrDefault(x => x.Id == id); + + return profile; } @@ -142,6 +150,17 @@ public virtual Provider LoadProvider(string systemName, int sto return (provider.IsValid() ? provider : null); } + + public virtual void DeleteExportDeployment(ExportDeployment deployment) + { + if (deployment == null) + throw new ArgumentNullException("deployment"); + + _exportDeploymentRepository.Delete(deployment); + + _eventPublisher.EntityDeleted(deployment); + } + #endregion } } diff --git a/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs index bc6ca8b092..bb511ebc8d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs @@ -40,6 +40,7 @@ public interface IExportService /// Export profile ExportProfile GetExportProfileById(int id); + /// /// Load all export providers /// @@ -54,5 +55,12 @@ public interface IExportService /// Store identifier /// Export provider Provider LoadProvider(string systemName, int storeId = 0); + + + /// + /// Deletes an export deployment + /// + /// Export deployment + void DeleteExportDeployment(ExportDeployment deployment); } } diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 6f7ac50ab8..4a036ed0e5 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -1,11 +1,6 @@ using System; -using System.Globalization; -using System.IO; using System.Linq; -using System.Text; using System.Web.Mvc; -using System.Web.Routing; -using System.Xml.Serialization; using SmartStore.Admin.Models.DataExchange; using SmartStore.Core; using SmartStore.Core.Domain; @@ -82,7 +77,28 @@ private string GetThumbnailUrl(Provider provider) return url; } - private void PrepareExportProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) + private ExportDeploymentModel PrepareDeploymentModel(ExportDeployment deployment) + { + var model = new ExportDeploymentModel + { + Id = deployment.Id, + Name = deployment.Name, + Enabled = deployment.Enabled, + IsPublic = deployment.IsPublic, + DeploymentType = deployment.DeploymentType, + DeploymentTypeName = T("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType." + deployment.DeploymentType.ToString()), + Username = deployment.Username, + Password = deployment.Password, + Url = deployment.Url, + FileSystemPath = deployment.FileSystemPath, + EmailAddresses = deployment.EmailAddresses, + EmailSubject = deployment.EmailSubject, + EmailAccountId = deployment.EmailAccountId + }; + return model; + } + + private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) { model.Id = profile.Id; model.Name = profile.Name; @@ -106,12 +122,12 @@ private void PrepareExportProfileModel(ExportProfileModel model, ExportProfile p model.Provider.Description = _pluginMediator.GetLocalizedDescription(provider.Metadata); model.Provider.EntityType = provider.Value.EntityType; - model.Provider.EntityTypeName = T("Enums.SmartStore.Core.Domain.ExportEntityType." + provider.Value.EntityType.ToString()); + model.Provider.EntityTypeName = T("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType." + provider.Value.EntityType.ToString()); model.Provider.FileType = provider.Value.FileType.ToUpper(); } } - private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportProfile profile, Provider provider) + private void PrepareProfileModelForEdit(ExportProfileModel model, ExportProfile profile, Provider provider) { var filter = XmlHelper.Deserialize(profile.Filtering); var projection = XmlHelper.Deserialize(profile.Projection); @@ -127,16 +143,25 @@ private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportPr model.Limit = profile.Limit; model.BatchSize = profile.BatchSize; model.PerStore = profile.PerStore; + model.CreateZipArchive = profile.CreateZipArchive; + model.CompletedEmailAddresses = profile.CompletedEmailAddresses; if (provider != null) { - string partialName; - Type dataType; - if (provider.Value.RequiresConfiguration(out partialName, out dataType)) + try { - model.Provider.ConfigPartialViewName = partialName; - model.Provider.ConfigDataType = dataType; - model.Provider.ConfigData = XmlHelper.Deserialize(profile.ProviderConfigData, dataType); + string partialName; + Type dataType; + if (provider.Value.RequiresConfiguration(out partialName, out dataType)) + { + model.Provider.ConfigPartialViewName = partialName; + model.Provider.ConfigDataType = dataType; + model.Provider.ConfigData = XmlHelper.Deserialize(profile.ProviderConfigData, dataType); + } + } + catch (Exception exc) + { + NotifyError(exc); } } @@ -229,6 +254,9 @@ private void PrepareExportProfileModelForEdit(ExportProfileModel model, ExportPr initModelBase(model.OrderFilter); } + + // deplyoment + model.Deployments = profile.Deployments.Select(x => PrepareDeploymentModel(x)).ToList(); } #endregion @@ -262,7 +290,7 @@ public ActionResult List(GridCommand command) model.Data = profiles.Select(x => { var profileModel = new ExportProfileModel(); - PrepareExportProfileModel(profileModel, x, providers.FirstOrDefault(y => y.Metadata.SystemName == x.ProviderSystemName)); + PrepareProfileModel(profileModel, x, providers.FirstOrDefault(y => y.Metadata.SystemName == x.ProviderSystemName)); return profileModel; }); @@ -331,8 +359,8 @@ public ActionResult Edit(int id) var model = new ExportProfileModel(); - PrepareExportProfileModel(model, profile, provider); - PrepareExportProfileModelForEdit(model, profile, provider); + PrepareProfileModel(model, profile, provider); + PrepareProfileModelForEdit(model, profile, provider); return View(model); } @@ -352,8 +380,8 @@ public ActionResult Edit(ExportProfileModel model, bool continueEditing) if (!ModelState.IsValid) { - PrepareExportProfileModel(model, profile, provider); - PrepareExportProfileModelForEdit(model, profile, provider); + PrepareProfileModel(model, profile, provider); + PrepareProfileModelForEdit(model, profile, provider); return View(model); } @@ -364,6 +392,8 @@ public ActionResult Edit(ExportProfileModel model, bool continueEditing) profile.Limit = model.Limit; profile.BatchSize = model.BatchSize; profile.PerStore = model.PerStore; + profile.CreateZipArchive = model.CreateZipArchive; + profile.CompletedEmailAddresses = model.CompletedEmailAddresses; if (profile.Name.IsEmpty()) profile.Name = provider.Metadata.FriendlyName; @@ -499,5 +529,33 @@ public ActionResult Execute(int id) { return null; } + + #region Export deployment + + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult DeploymentList(GridCommand command, int id) + { + var model = new GridModel(); + + if (_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + { + var profile = _exportService.GetExportProfileById(id); + if (profile != null) + { + model.Total = profile.Deployments.Count; + + model.Data = profile.Deployments.Select(x => PrepareDeploymentModel(x)).ToList(); + } + } + + return new JsonResult { Data = model }; + } + + public ActionResult DeploymentEdit(int id) + { + return null; + } + + #endregion } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs new file mode 100644 index 0000000000..df0c40302e --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs @@ -0,0 +1,49 @@ +using System.ComponentModel.DataAnnotations; +using FluentValidation.Attributes; +using SmartStore.Admin.Validators.DataExchange; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Mvc; + +namespace SmartStore.Admin.Models.DataExchange +{ + [Validator(typeof(ExportDeploymentValidator))] + public class ExportDeploymentModel : EntityModelBase + { + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.Name")] + public string Name { get; set; } + + [SmartResourceDisplayName("Common.Enabled")] + public bool Enabled { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.DeploymentType")] + public ExportDeploymentType DeploymentType { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.DeploymentType")] + public string DeploymentTypeName { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.IsPublic")] + public bool IsPublic { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.Username")] + public string Username { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.Password")] + [DataType(DataType.Password)] + public string Password { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.Url")] + public string Url { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.FileSystemPath")] + public string FileSystemPath { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.EmailAddresses")] + public string EmailAddresses { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.EmailSubject")] + public string EmailSubject { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.EmailAccountId")] + public int EmailAccountId { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs index 3294830cb9..589dc68f9f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportFilterModel.cs @@ -26,7 +26,7 @@ public abstract class ExportFilterModelBase public class ExportProductFilterModel : ExportFilterModelBase { [SmartResourceDisplayName("Admin.Configuration.Export.Filter.IsPublished")] - public bool? IsPublished { get; set; } + public bool IsPublished { get; set; } [SmartResourceDisplayName("Admin.Configuration.Export.Filter.ProductType")] public ProductType? ProductType { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index 4638c6fd0e..77f5ff7b6d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; -using System.Dynamic; using System.Web.Mvc; -using System.Web.Routing; +using FluentValidation.Attributes; +using SmartStore.Admin.Validators.DataExchange; using SmartStore.Core.Domain.DataExchange; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Mvc; namespace SmartStore.Admin.Models.DataExchange { + [Validator(typeof(ExportProfileValidator))] public partial class ExportProfileModel : EntityModelBase { public int StoreCount { get; set; } @@ -40,6 +41,12 @@ public partial class ExportProfileModel : EntityModelBase [SmartResourceDisplayName("Admin.Configuration.Export.PerStore")] public bool PerStore { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Export.CreateZipArchive")] + public bool CreateZipArchive { get; set; } + + [SmartResourceDisplayName("Admin.Configuration.Export.CompletedEmailAddresses")] + public string CompletedEmailAddresses { get; set; } + public ProviderModel Provider { get; set; } public ExportProductFilterModel ProductFilter { get; set; } @@ -47,6 +54,8 @@ public partial class ExportProfileModel : EntityModelBase public ExportProjectionModel Projection { get; set; } + public List Deployments { get; set; } + public class ProviderModel { diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProjectionModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProjectionModel.cs index 0cd5ddd22f..d95ea87ec8 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProjectionModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProjectionModel.cs @@ -7,11 +7,11 @@ namespace SmartStore.Admin.Models.DataExchange public class ExportProjectionModel { [SmartResourceDisplayName("Admin.Configuration.Export.Projection.LanguageId")] - public int LanguageId { get; set; } + public int? LanguageId { get; set; } public List AvailableLanguages { get; set; } [SmartResourceDisplayName("Admin.Configuration.Export.Projection.CurrencyId")] - public int CurrencyId { get; set; } + public int? CurrencyId { get; set; } public List AvailableCurrencies { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index 1fb41c6bf1..b7bcbd5add 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -247,6 +247,7 @@ + @@ -366,6 +367,8 @@ + + diff --git a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportDeplomentValidator.cs b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportDeplomentValidator.cs new file mode 100644 index 0000000000..4f1539698d --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportDeplomentValidator.cs @@ -0,0 +1,16 @@ +using FluentValidation; +using SmartStore.Admin.Models.DataExchange; +using SmartStore.Services.Localization; + +namespace SmartStore.Admin.Validators.DataExchange +{ + public partial class ExportDeploymentValidator : AbstractValidator + { + public ExportDeploymentValidator(ILocalizationService localization) + { + RuleFor(x => x.Name) + .NotEmpty() + .WithMessage(localization.GetResource("Admin.Configuration.Export.Deployment.Name.Validate")); + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportProfileValidator.cs b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportProfileValidator.cs new file mode 100644 index 0000000000..d0a1e14ca1 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportProfileValidator.cs @@ -0,0 +1,16 @@ +using FluentValidation; +using SmartStore.Admin.Models.DataExchange; +using SmartStore.Services.Localization; + +namespace SmartStore.Admin.Validators.DataExchange +{ + public partial class ExportProfileValidator : AbstractValidator + { + public ExportProfileValidator(ILocalizationService localization) + { + RuleFor(x => x.Name) + .NotEmpty() + .WithMessage(localization.GetResource("Admin.Configuration.Export.Name.Validate")); + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml index f825f3b48a..7bf4b772b2 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -36,7 +36,7 @@ x.Add().Text(T("Common.Filter").Text).Content(TabFilter()); x.Add().Text(T("Common.Projection").Text).Content(TabProjection()); x.Add().Text(T("Admin.Configuration").Text).Content(TabConfiguration()); - x.Add().Text(T("Common.Publishing").Text).Content(TabDeployment()); + x.Add().Text(T("Common.Deployment").Text).Content(TabDeployment()); EngineContext.Current.Resolve().Publish(new TabStripCreated(x, "export-profile-edit", this.Html, this.Model)); }) @@ -466,6 +466,65 @@ @helper TabDeployment() { + +
    + @(Html.Telerik().Grid(Model.Deployments) + .Name("export-deployment-grid") + .DataKeys(keys => keys.Add(x => x.Id) + .RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.Name) + .Width(400) + .Template(x => Html.ActionLink(x.Name, "DeploymentEdit", new { id = x.Id })) + .ClientTemplate("\"><#= Name #>"); + columns.Bound(x => x.DeploymentTypeName); + columns.Bound(x => x.Enabled) + .Width(100) + .Template(item => @Html.SymbolForBool(item.Enabled)) + .ClientTemplate(@Html.SymbolForBool("Enabled")) + .Centered(); + }) + .ToolBar(commands => + { + commands.Custom() + .Name("export-deployment-insert-button") + .HtmlAttributes(new { @class = "btn btn-primary" }) + .Text(" " + @T("Common.AddNew")); + }) + .DataBinding(dataBinding => dataBinding.Ajax().Select("DeploymentList", "Export", new { id = Model.Id })) + .ClientEvents(events => events.OnRowDataBound("onRowDataBound_ExportDeployments")) + .EnableCustomBinding(true)) +
    + +

    + + + + + + + + + + +
    + @Html.SmartLabelFor(x => x.CreateZipArchive) + + @Html.EditorFor(x => x.CreateZipArchive) + @Html.ValidationMessageFor(x => x.CreateZipArchive) +
    + @Html.SmartLabelFor(x => x.CompletedEmailAddresses) + + @Html.EditorFor(x => x.CompletedEmailAddresses, new { @class = "control-xlarge" }) + @Html.ValidationMessageFor(x => x.CompletedEmailAddresses) +
    } @Html.DeleteConfirmation("export-profile-delete") diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index 10fafd92f6..9c04d96eba 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -29,10 +29,8 @@ @(Html.Telerik().Grid() .Name("export-profile-grid") - .DataKeys(x => - { - x.Add(y => y.Id).RouteKey("Id"); - }) + .DataKeys(keys => keys.Add(x => x.Id) + .RouteKey("Id")) .Columns(columns => { columns.Bound(x => x.Provider.ThumbnailUrl) From 9c609eb5417912b5675f0cdf95ae0f50d37980f9 Mon Sep 17 00:00:00 2001 From: Marcus Gesing Date: Sat, 8 Aug 2015 13:43:44 +0200 Subject: [PATCH 0158/1074] CRUD export deployment --- .../Domain/Messages/EmailAccount.cs | 7 +- .../201508070937542_ExportFramework.cs | 25 +- .../DataExchange/ExportService.cs | 11 + .../DataExchange/IExportService.cs | 8 +- .../Controllers/ExportController.cs | 216 +++++++++++++++--- .../DataExchange/ExportDeploymentModel.cs | 30 ++- .../Models/DataExchange/ExportProfileModel.cs | 1 - .../Administration/SmartStore.Admin.csproj | 3 + .../DataExchange/ExportDeplomentValidator.cs | 28 ++- .../DataExchange/ExportProfileValidator.cs | 2 +- .../Views/Export/CreateDeployment.cshtml | 21 ++ .../Administration/Views/Export/Edit.cshtml | 18 +- .../Views/Export/EditDeployment.cshtml | 26 +++ .../Administration/Views/Export/List.cshtml | 2 +- .../Export/_CreateOrUpdateDeployment.cshtml | 127 ++++++++++ 15 files changed, 466 insertions(+), 59 deletions(-) create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/CreateDeployment.cshtml create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/EditDeployment.cshtml create mode 100644 src/Presentation/SmartStore.Web/Administration/Views/Export/_CreateOrUpdateDeployment.cshtml diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAccount.cs b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAccount.cs index decde80336..859a7bd74f 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAccount.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAccount.cs @@ -54,9 +54,10 @@ public string FriendlyName { get { - if (!String.IsNullOrWhiteSpace(this.DisplayName)) - return this.Email + " (" + this.DisplayName + ")"; - return this.Email; + if (DisplayName.IsEmpty()) + return Email; + + return "{0} ({1})".FormatInvariant(DisplayName, Email); } } diff --git a/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.cs index c85249ef25..a3ca9c5035 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201508070937542_ExportFramework.cs @@ -98,6 +98,11 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Common.Deployment", "Deployment", "Bereitstellung"); builder.AddOrUpdate("Common.Website", "Website", "Web-Seite"); + builder.AddOrUpdate("Admin.Validation.UsernamePassword", "Please enter username and password", "Bitte geben Sie Benutzername und Passwort ein"); + builder.AddOrUpdate("Admin.Validation.Url", "Please enter a valid URL", "Bitte geben Sie eine gltige URL ein"); + builder.AddOrUpdate("Admin.Validation.Name", "Please enter a name", "Bitte geben Sie einen Namen ein"); + builder.AddOrUpdate("Admin.Validation.EmailAddress", "Please enter a valid email address", "Bitte geben Sie eine gltige E-Mail Adresse ein"); + builder.AddOrUpdate("Admin.Configuration.Export.ProviderSystemName.Validate", "There were no export provider found for system name \"{0}\". A provider is mandatory for an export profile.", @@ -132,10 +137,6 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies the name of the export profile.", "Legt den Namen des Exportprofils fest."); - builder.AddOrUpdate("Admin.Configuration.Export.Name.Validate", - "Please enter the name of the profile.", - "Bitte den Namen des Profils eingeben."); - builder.AddOrUpdate("Admin.Configuration.Export.FileType", "File type", "Dateityp", @@ -325,10 +326,10 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Legt die auf den Export anzuwendende Whrung fest."); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.FileSystem", "File system", "Dateisystem"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Email", "Email", "E-Mail"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Http", "HTTP", "HTTP"); - builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Ftp", "FTP", "FTP"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.FileSystem", "File system", "Dateisystem"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.Email", "Email", "E-Mail"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.Http", "HTTP", "HTTP"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.Ftp", "FTP", "FTP"); builder.AddOrUpdate("Admin.Configuration.Export.Deployment.Name", @@ -337,10 +338,6 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Specifies the name of the deployment.", "Legt den Namen der Bereitstellung fest."); - builder.AddOrUpdate("Admin.Configuration.Export.Deployment.Name.Validate", - "Please enter the name of the deployment.", - "Bitte den Namen der Bereitstellung eingeben."); - builder.AddOrUpdate("Admin.Configuration.Export.Deployment.IsPublic", "Make public", "ffentlich machen", @@ -349,9 +346,9 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Configuration.Export.Deployment.DeploymentType", "Type of deployment", - "Typ der Bereitstellung", + "Art der Bereitstellung", "Specifies the deployment type.", - "Legt den Bereitstellungstyp fest."); + "Legt die Art Bereitstellung fest."); builder.AddOrUpdate("Admin.Configuration.Export.Deployment.Username", "User name", diff --git a/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs index d678942acc..b2e2a77d5d 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/ExportService.cs @@ -150,6 +150,17 @@ public virtual Provider LoadProvider(string systemName, int sto return (provider.IsValid() ? provider : null); } + public virtual ExportDeployment GetExportDeploymentById(int id) + { + if (id == 0) + return null; + + var deployment = _exportDeploymentRepository.Table + .Expand(x => x.Profile) + .FirstOrDefault(x => x.Id == id); + + return deployment; + } public virtual void DeleteExportDeployment(ExportDeployment deployment) { diff --git a/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs b/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs index bb511ebc8d..a02512e322 100644 --- a/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs +++ b/src/Libraries/SmartStore.Services/DataExchange/IExportService.cs @@ -56,9 +56,15 @@ public interface IExportService /// Export provider Provider LoadProvider(string systemName, int storeId = 0); + /// + /// Get export deployment by identifier + /// + /// Export deployment identifier + /// Export deployment + ExportDeployment GetExportDeploymentById(int id); /// - /// Deletes an export deployment + /// Deleted a export deployment /// /// Export deployment void DeleteExportDeployment(ExportDeployment deployment); diff --git a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs index 4a036ed0e5..754b4c2b95 100644 --- a/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs +++ b/src/Presentation/SmartStore.Web/Administration/Controllers/ExportController.cs @@ -17,10 +17,12 @@ using SmartStore.Services.Directory; using SmartStore.Services.Localization; using SmartStore.Services.Media; +using SmartStore.Services.Messages; using SmartStore.Services.Security; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Plugins; +using SmartStore.Web.Framework.UI; using Telerik.Web.Mvc; namespace SmartStore.Admin.Controllers @@ -38,6 +40,7 @@ public class ExportController : AdminControllerBase private readonly ICustomerService _customerService; private readonly ILanguageService _languageService; private readonly ICurrencyService _currencyService; + private readonly IEmailAccountService _emailAccountService; public ExportController( ICommonServices services, @@ -49,7 +52,8 @@ public ExportController( IProductTagService productTagService, ICustomerService customerService, ILanguageService languageService, - ICurrencyService currencyService) + ICurrencyService currencyService, + IEmailAccountService emailAccountService) { _services = services; _exportService = exportService; @@ -61,6 +65,7 @@ public ExportController( _customerService = customerService; _languageService = languageService; _currencyService = currencyService; + _emailAccountService = emailAccountService; } #region Utilities @@ -77,27 +82,6 @@ private string GetThumbnailUrl(Provider provider) return url; } - private ExportDeploymentModel PrepareDeploymentModel(ExportDeployment deployment) - { - var model = new ExportDeploymentModel - { - Id = deployment.Id, - Name = deployment.Name, - Enabled = deployment.Enabled, - IsPublic = deployment.IsPublic, - DeploymentType = deployment.DeploymentType, - DeploymentTypeName = T("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType." + deployment.DeploymentType.ToString()), - Username = deployment.Username, - Password = deployment.Password, - Url = deployment.Url, - FileSystemPath = deployment.FileSystemPath, - EmailAddresses = deployment.EmailAddresses, - EmailSubject = deployment.EmailSubject, - EmailAccountId = deployment.EmailAccountId - }; - return model; - } - private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile, Provider provider) { model.Id = profile.Id; @@ -122,7 +106,7 @@ private void PrepareProfileModel(ExportProfileModel model, ExportProfile profile model.Provider.Description = _pluginMediator.GetLocalizedDescription(provider.Metadata); model.Provider.EntityType = provider.Value.EntityType; - model.Provider.EntityTypeName = T("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType." + provider.Value.EntityType.ToString()); + model.Provider.EntityTypeName = provider.Value.EntityType.GetLocalizedEnum(_services.Localization, _services.WorkContext); model.Provider.FileType = provider.Value.FileType.ToUpper(); } } @@ -254,9 +238,69 @@ private void PrepareProfileModelForEdit(ExportProfileModel model, ExportProfile initModelBase(model.OrderFilter); } + } + + private ExportDeploymentModel PrepareDeploymentModel(ExportDeployment deployment) + { + var allEmailAccounts = _emailAccountService.GetAllEmailAccounts(); - // deplyoment - model.Deployments = profile.Deployments.Select(x => PrepareDeploymentModel(x)).ToList(); + var model = new ExportDeploymentModel + { + Id = deployment.Id, + ProfileId = deployment.ProfileId, + Name = deployment.Name, + Enabled = deployment.Enabled, + IsPublic = deployment.IsPublic, + DeploymentType = deployment.DeploymentType, + DeploymentTypeName = deployment.DeploymentType.GetLocalizedEnum(_services.Localization, _services.WorkContext), + Username = deployment.Username, + Password = deployment.Password, + Url = deployment.Url, + FileSystemPath = deployment.FileSystemPath, + EmailAddresses = deployment.EmailAddresses, + EmailSubject = deployment.EmailSubject, + EmailAccountId = deployment.EmailAccountId + }; + + model.AvailableDeploymentTypes = ExportDeploymentType.FileSystem.ToSelectList(false).ToList(); + + model.AvailableEmailAccounts = allEmailAccounts + .Select(x => new SelectListItem { Text = x.FriendlyName, Value = x.Id.ToString() }) + .ToList(); + + return model; + } + + private void ModelToEntity(ExportDeploymentModel model, ExportDeployment deployment) + { + deployment.ProfileId = model.ProfileId; + deployment.Name = model.Name; + deployment.Enabled = model.Enabled; + deployment.DeploymentType = model.DeploymentType; + deployment.IsPublic = model.IsPublic; + deployment.Username = model.Username; + deployment.Password = model.Password; + deployment.Url = model.Url; + deployment.FileSystemPath = model.FileSystemPath; + deployment.EmailAddresses = model.EmailAddresses; + deployment.EmailSubject = model.EmailSubject; + deployment.EmailAccountId = model.EmailAccountId; + } + + private ActionResult SmartRedirect(bool continueEditing, int profileId, int deploymentId) + { + if (!continueEditing) + { + TempData["SelectedTab.export-profile-edit"] = new SelectedTabInfo + { + TabId = "export-profile-edit-6", + Path = Url.Action("Edit", new { id = profileId }) + }; + } + + return (continueEditing ? + RedirectToAction("EditDeployment", new { id = deploymentId }) : + RedirectToAction("Edit", new { id = profileId })); } #endregion @@ -544,16 +588,132 @@ public ActionResult DeploymentList(GridCommand command, int id) { model.Total = profile.Deployments.Count; - model.Data = profile.Deployments.Select(x => PrepareDeploymentModel(x)).ToList(); + model.Data = profile.Deployments.Select(x => + { + var deploymentModel = new ExportDeploymentModel + { + Id = x.Id, + ProfileId = profile.Id, + Name = x.Name, + Enabled = x.Enabled, + DeploymentType = x.DeploymentType, + DeploymentTypeName = x.DeploymentType.GetLocalizedEnum(_services.Localization, _services.WorkContext) + }; + return deploymentModel; + }).ToList(); } } return new JsonResult { Data = model }; } - public ActionResult DeploymentEdit(int id) + public ActionResult CreateDeployment(int id) { - return null; + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var profile = _exportService.GetExportProfileById(id); + if (profile == null) + return RedirectToAction("List"); + + var fileSystemName = ExportDeploymentType.FileSystem.GetLocalizedEnum(_services.Localization, _services.WorkContext); + + var model = PrepareDeploymentModel(new ExportDeployment + { + ProfileId = id, + Enabled = true, + DeploymentType = ExportDeploymentType.FileSystem, + Name = profile.Name + }); + + return View(model); + } + + [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] + [FormValueRequired("save", "save-continue")] + public ActionResult CreateDeployment(ExportDeploymentModel model, bool continueEditing, ExportDeploymentType deploymentType) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var profile = _exportService.GetExportProfileById(model.ProfileId); + if (profile == null) + return RedirectToAction("List"); + + if (ModelState.IsValid) + { + var deployment = new ExportDeployment(); + + ModelToEntity(model, deployment); + + profile.Deployments.Add(deployment); + + _exportService.UpdateExportProfile(profile); + + return SmartRedirect(continueEditing, profile.Id, deployment.Id); + } + + return CreateDeployment(profile.Id); + } + + public ActionResult EditDeployment(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var deployment = _exportService.GetExportDeploymentById(id); + if (deployment == null) + return RedirectToAction("List"); + + var model = PrepareDeploymentModel(deployment); + + return View(model); + } + + [HttpPost, ParameterBasedOnFormNameAttribute("save-continue", "continueEditing")] + [FormValueRequired("save", "save-continue")] + public ActionResult EditDeployment(ExportDeploymentModel model, bool continueEditing) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var deployment = _exportService.GetExportDeploymentById(model.Id); + if (deployment == null) + return RedirectToAction("List"); + + if (ModelState.IsValid) + { + ModelToEntity(model, deployment); + + _exportService.UpdateExportProfile(deployment.Profile); + + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + + return SmartRedirect(continueEditing, deployment.ProfileId, deployment.Id); + } + + model = PrepareDeploymentModel(deployment); + + return View(model); + } + + [HttpPost] + public ActionResult DeleteDeployment(int id) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageExports)) + return AccessDeniedView(); + + var deployment = _exportService.GetExportDeploymentById(id); + if (deployment == null) + return RedirectToAction("List"); + + int profileId = deployment.ProfileId; + + _exportService.DeleteExportDeployment(deployment); + + NotifySuccess(T("Admin.Common.TaskSuccessfullyProcessed")); + + return SmartRedirect(false, profileId, 0); } #endregion diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs index df0c40302e..d73036f76d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportDeploymentModel.cs @@ -1,4 +1,6 @@ -using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Admin.Validators.DataExchange; using SmartStore.Core.Domain.DataExchange; @@ -10,6 +12,8 @@ namespace SmartStore.Admin.Models.DataExchange [Validator(typeof(ExportDeploymentValidator))] public class ExportDeploymentModel : EntityModelBase { + public int ProfileId { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.Name")] public string Name { get; set; } @@ -18,9 +22,32 @@ public class ExportDeploymentModel : EntityModelBase [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.DeploymentType")] public ExportDeploymentType DeploymentType { get; set; } + public List AvailableDeploymentTypes { get; set; } + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.DeploymentType")] public string DeploymentTypeName { get; set; } + public string DeploymentTypeIconClass + { + get + { + switch (DeploymentType) + { + case ExportDeploymentType.FileSystem: + return "fa-folder-open-o"; + case ExportDeploymentType.Email: + return "fa-envelope-o"; + case ExportDeploymentType.Http: + return "fa-globe"; + case ExportDeploymentType.Ftp: + return "fa-clone"; + default: + return "fa-question"; + } + } + } + + [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.IsPublic")] public bool IsPublic { get; set; } @@ -45,5 +72,6 @@ public class ExportDeploymentModel : EntityModelBase [SmartResourceDisplayName("Admin.Configuration.Export.Deployment.EmailAccountId")] public int EmailAccountId { get; set; } + public List AvailableEmailAccounts { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs index 77f5ff7b6d..71a6a8e85d 100644 --- a/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs +++ b/src/Presentation/SmartStore.Web/Administration/Models/DataExchange/ExportProfileModel.cs @@ -56,7 +56,6 @@ public partial class ExportProfileModel : EntityModelBase public List Deployments { get; set; } - public class ProviderModel { public string ConfigPartialViewName { get; set; } diff --git a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj index b7bcbd5add..5df7d83edd 100644 --- a/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj +++ b/src/Presentation/SmartStore.Web/Administration/SmartStore.Admin.csproj @@ -510,6 +510,9 @@ + + + diff --git a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportDeplomentValidator.cs b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportDeplomentValidator.cs index 4f1539698d..4caa43d099 100644 --- a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportDeplomentValidator.cs +++ b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportDeplomentValidator.cs @@ -1,5 +1,6 @@ using FluentValidation; using SmartStore.Admin.Models.DataExchange; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Services.Localization; namespace SmartStore.Admin.Validators.DataExchange @@ -10,7 +11,32 @@ public ExportDeploymentValidator(ILocalizationService localization) { RuleFor(x => x.Name) .NotEmpty() - .WithMessage(localization.GetResource("Admin.Configuration.Export.Deployment.Name.Validate")); + .WithMessage(localization.GetResource("Admin.Validation.Name")); + + RuleFor(x => x.EmailAddresses) + .NotEmpty() + .When(x => x.DeploymentType == ExportDeploymentType.Email) + .WithMessage(localization.GetResource("Admin.Validation.EmailAddress")); + + RuleFor(x => x.Url) + .NotEmpty() + .When(x => x.DeploymentType == ExportDeploymentType.Http) + .WithMessage(localization.GetResource("Admin.Validation.Url")); + + RuleFor(x => x.Url) + .Matches(RegularExpressions.IsWebUrl) + .When(x => x.DeploymentType == ExportDeploymentType.Http) + .WithMessage(localization.GetResource("Admin.Validation.Url")); + + RuleFor(x => x.Username) + .NotEmpty() + .When(x => x.DeploymentType == ExportDeploymentType.Ftp) + .WithMessage(localization.GetResource("Admin.Validation.UsernamePassword")); + + RuleFor(x => x.Password) + .NotEmpty() + .When(x => x.DeploymentType == ExportDeploymentType.Ftp) + .WithMessage(localization.GetResource("Admin.Validation.UsernamePassword")); } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportProfileValidator.cs b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportProfileValidator.cs index d0a1e14ca1..4fa8d0a556 100644 --- a/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportProfileValidator.cs +++ b/src/Presentation/SmartStore.Web/Administration/Validators/DataExchange/ExportProfileValidator.cs @@ -10,7 +10,7 @@ public ExportProfileValidator(ILocalizationService localization) { RuleFor(x => x.Name) .NotEmpty() - .WithMessage(localization.GetResource("Admin.Configuration.Export.Name.Validate")); + .WithMessage(localization.GetResource("Admin.Validation.Name")); } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/CreateDeployment.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/CreateDeployment.cshtml new file mode 100644 index 0000000000..79f904409e --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/CreateDeployment.cshtml @@ -0,0 +1,21 @@ +@model ExportDeploymentModel +@using SmartStore.Core.Domain.DataExchange; +@using SmartStore.Admin.Models.DataExchange; +@{ + var title = string.Concat(T("Common.AddNew"), " ", T("Common.Deployment")); + ViewBag.Title = title; +} + +@using (Html.BeginForm()) +{ +
    +
    + @title @Html.ActionLink("(" + T("Common.Back") + ")", "Edit", new { id = Model.ProfileId }) +
    +
    + + +
    +
    + @Html.Partial("_CreateOrUpdateDeployment", Model) +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml index 7bf4b772b2..e284d1f9db 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/Edit.cshtml @@ -474,17 +474,19 @@ }
    - @(Html.Telerik().Grid(Model.Deployments) + @(Html.Telerik().Grid() .Name("export-deployment-grid") .DataKeys(keys => keys.Add(x => x.Id) .RouteKey("Id")) .Columns(columns => { columns.Bound(x => x.Name) - .Width(400) - .Template(x => Html.ActionLink(x.Name, "DeploymentEdit", new { id = x.Id })) - .ClientTemplate("\"><#= Name #>"); - columns.Bound(x => x.DeploymentTypeName); + .Template(x => Html.ActionLink(x.Name, "EditDeployment", "Export", new { id = x.Id }, null)) + .ClientTemplate("\"><#= Name #>"); + columns.Bound(x => x.DeploymentTypeName) + .Template(x => " {1}".FormatInvariant(x.DeploymentTypeIconClass, x.DeploymentTypeName)) + .ClientTemplate(" <#= DeploymentTypeName #>") + .Width(320); columns.Bound(x => x.Enabled) .Width(100) .Template(item => @Html.SymbolForBool(item.Enabled)) @@ -494,8 +496,8 @@ .ToolBar(commands => { commands.Custom() - .Name("export-deployment-insert-button") - .HtmlAttributes(new { @class = "btn btn-primary" }) + .Name("export-deployment-add-button") + .HtmlAttributes(new { @class = "btn btn-primary", href = @Url.Action("CreateDeployment", new { id = Model.Id }) }) .Text(" " + @T("Common.AddNew")); }) .DataBinding(dataBinding => dataBinding.Ajax().Select("DeploymentList", "Export", new { id = Model.Id })) @@ -520,7 +522,7 @@ @Html.SmartLabelFor(x => x.CompletedEmailAddresses) - @Html.EditorFor(x => x.CompletedEmailAddresses, new { @class = "control-xlarge" }) + @Html.EditorFor(x => x.CompletedEmailAddresses) @Html.ValidationMessageFor(x => x.CompletedEmailAddresses) diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/EditDeployment.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/EditDeployment.cshtml new file mode 100644 index 0000000000..356ded774d --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/EditDeployment.cshtml @@ -0,0 +1,26 @@ +@model ExportDeploymentModel +@using SmartStore.Core.Domain.DataExchange; +@using SmartStore.Admin.Models.DataExchange; +@{ + var title = string.Concat(T("Admin.Common.Edit"), " ", T("Common.Deployment")); + ViewBag.Title = title; +} + +@using (Html.BeginForm()) +{ +
    +
    + @title - @Model.Name @Html.ActionLink("(" + T("Common.Back") + ")", "Edit", new { id = Model.ProfileId }) +
    +
    + + + +
    +
    + @Html.Partial("_CreateOrUpdateDeployment", Model) +} + +@Html.DeleteConfirmation("DeleteDeployment", "export-deployment-delete") \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml index 9c04d96eba..6856f83fbc 100644 --- a/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml +++ b/src/Presentation/SmartStore.Web/Administration/Views/Export/List.cshtml @@ -70,7 +70,7 @@
    -