Skip to content

Commit 2c9cd0c

Browse files
committed
Resolves smartstore#695 Implement checkbox in checkout to let customers subscribe to newsletters
1 parent 6ec3742 commit 2c9cd0c

19 files changed

Lines changed: 254 additions & 106 deletions

File tree

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
* #738 Implement download of pictures via URLs in product import
5050
* Web-API: Bridge to import framework: uploading import files to import profile directory
5151
* Setting to round down calculated reward points
52+
* #695 Implement checkbox in checkout to let customers subscribe to newsletters
5253

5354
### Improvements
5455
* (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace SmartStore.Core.Domain.Orders
2+
{
3+
/// <summary>
4+
/// Setting for newsletter subscription in checkout
5+
/// </summary>
6+
public enum CheckoutNewsLetterSubscription
7+
{
8+
/// <summary>
9+
/// No newsletter subscription checkbox
10+
/// </summary>
11+
None = 0,
12+
13+
/// <summary>
14+
/// Deactivated newsletter subscription checkbox
15+
/// </summary>
16+
Deactivated,
17+
18+
/// <summary>
19+
/// Activated newsletter subscription checkbox
20+
/// </summary>
21+
Activated
22+
}
23+
}

src/Libraries/SmartStore.Core/Domain/Orders/ShoppingCartSettings.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ public ShoppingCartSettings()
104104
/// </summary>
105105
public bool ShowEsdRevocationWaiverBox { get; set; }
106106

107+
/// <summary>
108+
/// Gets or sets a value indicating whether to show a checkbox to subscribe to newsletters
109+
/// </summary>
110+
public CheckoutNewsLetterSubscription NewsLetterSubscription { get; set; }
111+
107112
/// <summary>
108113
/// Gets or sets a number of "Cross-sells" on shopping cart page
109114
/// </summary>

src/Libraries/SmartStore.Core/SmartStore.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
<Compile Include="Domain\DataExchange\ExportProfile.cs" />
182182
<Compile Include="Domain\Messages\EmailAttachmentStorageLocation.cs" />
183183
<Compile Include="Domain\Messages\QueuedEmailAttachment.cs" />
184+
<Compile Include="Domain\Orders\CheckoutNewsLetterSubscription.cs" />
184185
<Compile Include="Domain\Payments\PaymentMethod.cs" />
185186
<Compile Include="Domain\Seo\CanonicalHostNameRule.cs" />
186187
<Compile Include="Extensions\IOExtensions.cs" />

src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,34 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
421421
"Punkte abrunden",
422422
"Specifies whether to round down calculated points. Otherwise the bonus points will be rounded up.",
423423
"Legt fest, ob bei der Punkteberechnung abgerundet werden soll. Ansonsten werden Bonuspunkte aufgerundet.");
424+
425+
builder.AddOrUpdate("Admin.Configuration.Settings.Order.GiftCards_Deactivated",
426+
"Gift card deactivation order status",
427+
"Geschenkgutschein wird deaktiviert, wenn Auftragsstatus...");
428+
429+
builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.NewsLetterSubscription",
430+
"Subscribe to newsletters",
431+
"Abonnieren von Newslettern",
432+
"Specifies id customers can subscribe to newsletters when ordering and if the checkbox is enabled by default.",
433+
"Legt fest, ob Kunden bei einer Bestellung Newsletter abonnieren können und ob die Checkbox standardmäßig aktiviert ist.");
434+
435+
builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutNewsLetterSubscription.None", "Do not show", "Nicht anzeigen");
436+
builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutNewsLetterSubscription.Deactivated", "Show deactivated", "Deaktiviert anzeigen");
437+
builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutNewsLetterSubscription.Activated", "Show activated", "Aktiviert anzeigen");
438+
439+
builder.AddOrUpdate("Common.Options", "Options", "Optionen");
440+
441+
builder.AddOrUpdate("Checkout.SubscribeToNewsLetter",
442+
"Subscribed to newsletter",
443+
"Newsletter abonnieren");
444+
445+
builder.AddOrUpdate("Admin.OrderNotice.NewsLetterSubscriptionAdded",
446+
"Subscribed to newsletter",
447+
"Newsletter wurde abonniert");
448+
449+
builder.AddOrUpdate("Admin.OrderNotice.NewsLetterSubscriptionRemoved",
450+
"Newsletter subscriber has been removed",
451+
"Newsletter-Abonnent wurde entfernt");
424452
}
425453
}
426454
}

src/Libraries/SmartStore.Services/Messages/INewsLetterSubscriptionService.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,21 @@ public partial interface INewsLetterSubscriptionService
2727
/// <param name="publishSubscriptionEvents">if set to <c>true</c> [publish subscription events].</param>
2828
void DeleteNewsLetterSubscription(NewsLetterSubscription newsLetterSubscription, bool publishSubscriptionEvents = true);
2929

30-
/// <summary>
31-
/// Gets a newsletter subscription by newsletter subscription identifier
32-
/// </summary>
33-
/// <param name="newsLetterSubscriptionId">The newsletter subscription identifier</param>
34-
/// <returns>NewsLetter subscription</returns>
35-
NewsLetterSubscription GetNewsLetterSubscriptionById(int newsLetterSubscriptionId);
30+
/// <summary>
31+
/// Adds or deletes a newsletter subscription
32+
/// </summary>
33+
/// <param name="add"><c>true</c> add subscription, <c>false</c> delete</param>
34+
/// <param name="email">Email address</param>
35+
/// <param name="storeId">Store identifier</param>
36+
/// <returns><c>true</c> added subscription, <c>false</c> removed subscription, <c>null</c> did nothing</returns>
37+
bool? AddNewsLetterSubscriptionFor(bool add, string email, int storeId);
38+
39+
/// <summary>
40+
/// Gets a newsletter subscription by newsletter subscription identifier
41+
/// </summary>
42+
/// <param name="newsLetterSubscriptionId">The newsletter subscription identifier</param>
43+
/// <returns>NewsLetter subscription</returns>
44+
NewsLetterSubscription GetNewsLetterSubscriptionById(int newsLetterSubscriptionId);
3645

3746
/// <summary>
3847
/// Gets a newsletter subscription by newsletter subscription GUID

src/Libraries/SmartStore.Services/Messages/NewsLetterSubscriptionService.cs

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
namespace SmartStore.Services.Messages
99
{
10-
1110
public class NewsLetterSubscriptionService : INewsLetterSubscriptionService
1211
{
1312
private readonly IEventPublisher _eventPublisher;
@@ -126,12 +125,52 @@ public virtual void DeleteNewsLetterSubscription(NewsLetterSubscription newsLett
126125
_eventPublisher.EntityDeleted(newsLetterSubscription);
127126
}
128127

129-
/// <summary>
130-
/// Gets a newsletter subscription by newsletter subscription identifier
131-
/// </summary>
132-
/// <param name="newsLetterSubscriptionId">The newsletter subscription identifier</param>
133-
/// <returns>NewsLetter subscription</returns>
134-
public virtual NewsLetterSubscription GetNewsLetterSubscriptionById(int newsLetterSubscriptionId)
128+
public virtual bool? AddNewsLetterSubscriptionFor(bool add, string email, int storeId)
129+
{
130+
bool? result = null;
131+
132+
if (email.IsEmail())
133+
{
134+
var newsletter = GetNewsLetterSubscriptionByEmail(email, storeId);
135+
if (newsletter != null)
136+
{
137+
if (add)
138+
{
139+
newsletter.Active = true;
140+
UpdateNewsLetterSubscription(newsletter);
141+
result = true;
142+
}
143+
else
144+
{
145+
DeleteNewsLetterSubscription(newsletter);
146+
result = false;
147+
}
148+
}
149+
else
150+
{
151+
if (add)
152+
{
153+
InsertNewsLetterSubscription(new NewsLetterSubscription
154+
{
155+
NewsLetterSubscriptionGuid = Guid.NewGuid(),
156+
Email = email,
157+
Active = true,
158+
CreatedOnUtc = DateTime.UtcNow,
159+
StoreId = storeId
160+
});
161+
result = true;
162+
}
163+
}
164+
}
165+
return result;
166+
}
167+
168+
/// <summary>
169+
/// Gets a newsletter subscription by newsletter subscription identifier
170+
/// </summary>
171+
/// <param name="newsLetterSubscriptionId">The newsletter subscription identifier</param>
172+
/// <returns>NewsLetter subscription</returns>
173+
public virtual NewsLetterSubscription GetNewsLetterSubscriptionById(int newsLetterSubscriptionId)
135174
{
136175
if (newsLetterSubscriptionId == 0) return null;
137176

src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -69,57 +69,58 @@ public partial class OrderProcessingService : IOrderProcessingService
6969
private readonly IAffiliateService _affiliateService;
7070
private readonly IEventPublisher _eventPublisher;
7171
private readonly IGenericAttributeService _genericAttributeService;
72+
private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService;
7273

73-
private readonly PaymentSettings _paymentSettings;
74+
private readonly PaymentSettings _paymentSettings;
7475
private readonly RewardPointsSettings _rewardPointsSettings;
7576
private readonly OrderSettings _orderSettings;
7677
private readonly TaxSettings _taxSettings;
7778
private readonly LocalizationSettings _localizationSettings;
7879
private readonly CurrencySettings _currencySettings;
7980
private readonly ShoppingCartSettings _shoppingCartSettings;
8081

81-
#endregion
82+
#endregion
8283

83-
#region Ctor
84+
#region Ctor
8485

85-
/// <summary>
86-
/// Ctor
87-
/// </summary>
88-
/// <param name="orderService">Order service</param>
89-
/// <param name="webHelper">Web helper</param>
90-
/// <param name="localizationService">Localization service</param>
91-
/// <param name="languageService">Language service</param>
92-
/// <param name="productService">Product service</param>
93-
/// <param name="paymentService">Payment service</param>
94-
/// <param name="logger">Logger</param>
95-
/// <param name="orderTotalCalculationService">Order total calculationservice</param>
96-
/// <param name="priceCalculationService">Price calculation service</param>
97-
/// <param name="priceFormatter">Price formatter</param>
98-
/// <param name="productAttributeParser">Product attribute parser</param>
99-
/// <param name="productAttributeFormatter">Product attribute formatter</param>
100-
/// <param name="giftCardService">Gift card service</param>
101-
/// <param name="shoppingCartService">Shopping cart service</param>
102-
/// <param name="checkoutAttributeFormatter">Checkout attribute service</param>
103-
/// <param name="shippingService">Shipping service</param>
104-
/// <param name="shipmentService">Shipment service</param>
105-
/// <param name="taxService">Tax service</param>
106-
/// <param name="customerService">Customer service</param>
107-
/// <param name="discountService">Discount service</param>
108-
/// <param name="encryptionService">Encryption service</param>
109-
/// <param name="workContext">Work context</param>
86+
/// <summary>
87+
/// Ctor
88+
/// </summary>
89+
/// <param name="orderService">Order service</param>
90+
/// <param name="webHelper">Web helper</param>
91+
/// <param name="localizationService">Localization service</param>
92+
/// <param name="languageService">Language service</param>
93+
/// <param name="productService">Product service</param>
94+
/// <param name="paymentService">Payment service</param>
95+
/// <param name="logger">Logger</param>
96+
/// <param name="orderTotalCalculationService">Order total calculationservice</param>
97+
/// <param name="priceCalculationService">Price calculation service</param>
98+
/// <param name="priceFormatter">Price formatter</param>
99+
/// <param name="productAttributeParser">Product attribute parser</param>
100+
/// <param name="productAttributeFormatter">Product attribute formatter</param>
101+
/// <param name="giftCardService">Gift card service</param>
102+
/// <param name="shoppingCartService">Shopping cart service</param>
103+
/// <param name="checkoutAttributeFormatter">Checkout attribute service</param>
104+
/// <param name="shippingService">Shipping service</param>
105+
/// <param name="shipmentService">Shipment service</param>
106+
/// <param name="taxService">Tax service</param>
107+
/// <param name="customerService">Customer service</param>
108+
/// <param name="discountService">Discount service</param>
109+
/// <param name="encryptionService">Encryption service</param>
110+
/// <param name="workContext">Work context</param>
110111
/// <param name="storeContext">Store context</param>
111-
/// <param name="workflowMessageService">Workflow message service</param>
112-
/// <param name="customerActivityService">Customer activity service</param>
113-
/// <param name="currencyService">Currency service</param>
112+
/// <param name="workflowMessageService">Workflow message service</param>
113+
/// <param name="customerActivityService">Customer activity service</param>
114+
/// <param name="currencyService">Currency service</param>
114115
/// <param name="affiliateService">Affiliate service</param>
115-
/// <param name="eventPublisher">Event published</param>
116-
/// <param name="paymentSettings">Payment settings</param>
117-
/// <param name="rewardPointsSettings">Reward points settings</param>
118-
/// <param name="orderSettings">Order settings</param>
119-
/// <param name="taxSettings">Tax settings</param>
120-
/// <param name="localizationSettings">Localization settings</param>
121-
/// <param name="currencySettings">Currency settings</param>
122-
public OrderProcessingService(IOrderService orderService,
116+
/// <param name="eventPublisher">Event published</param>
117+
/// <param name="paymentSettings">Payment settings</param>
118+
/// <param name="rewardPointsSettings">Reward points settings</param>
119+
/// <param name="orderSettings">Order settings</param>
120+
/// <param name="taxSettings">Tax settings</param>
121+
/// <param name="localizationSettings">Localization settings</param>
122+
/// <param name="currencySettings">Currency settings</param>
123+
public OrderProcessingService(IOrderService orderService,
123124
IWebHelper webHelper,
124125
ILocalizationService localizationService,
125126
ILanguageService languageService,
@@ -148,7 +149,8 @@ public OrderProcessingService(IOrderService orderService,
148149
IAffiliateService affiliateService,
149150
IEventPublisher eventPublisher,
150151
IGenericAttributeService genericAttributeService,
151-
PaymentSettings paymentSettings,
152+
INewsLetterSubscriptionService newsLetterSubscriptionService,
153+
PaymentSettings paymentSettings,
152154
RewardPointsSettings rewardPointsSettings,
153155
OrderSettings orderSettings,
154156
TaxSettings taxSettings,
@@ -185,6 +187,7 @@ public OrderProcessingService(IOrderService orderService,
185187
this._affiliateService = affiliateService;
186188
this._eventPublisher = eventPublisher;
187189
this._genericAttributeService = genericAttributeService;
190+
this._newsLetterSubscriptionService = newsLetterSubscriptionService;
188191
this._paymentSettings = paymentSettings;
189192
this._rewardPointsSettings = rewardPointsSettings;
190193
this._orderSettings = orderSettings;
@@ -1379,9 +1382,28 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR
13791382
_eventPublisher.PublishOrderPaid(order);
13801383
}
13811384

1382-
#endregion
1383-
}
1384-
}
1385+
#endregion
1386+
1387+
#region Newsletter subscription
1388+
1389+
if (extraData.ContainsKey("SubscribeToNewsLetter") && _shoppingCartSettings.NewsLetterSubscription != CheckoutNewsLetterSubscription.None)
1390+
{
1391+
var addSubscription = extraData["SubscribeToNewsLetter"].ToBool();
1392+
1393+
bool? nsResult = _newsLetterSubscriptionService.AddNewsLetterSubscriptionFor(addSubscription, customer.Email, order.StoreId);
1394+
1395+
if (nsResult.HasValue)
1396+
{
1397+
if (nsResult.Value)
1398+
_orderService.AddOrderNote(order, T("Admin.OrderNotice.NewsLetterSubscriptionAdded"));
1399+
else
1400+
_orderService.AddOrderNote(order, T("Admin.OrderNotice.NewsLetterSubscriptionRemoved"));
1401+
}
1402+
}
1403+
1404+
#endregion
1405+
}
1406+
}
13851407
else
13861408
{
13871409
result.AddError(T("Payment.PayingFailed"));

src/Presentation/SmartStore.Web/Administration/Controllers/SettingController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -796,13 +796,14 @@ public ActionResult ShoppingCart()
796796
if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageSettings))
797797
return AccessDeniedView();
798798

799-
//load settings for a chosen store scope
800799
var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext);
801800
var shoppingCartSettings = _services.Settings.LoadSetting<ShoppingCartSettings>(storeScope);
801+
802802
var model = shoppingCartSettings.ToModel();
803803

804-
StoreDependingSettings.GetOverrideKeys(shoppingCartSettings, model, storeScope, _services.Settings);
804+
model.AvailableNewsLetterSubscription = shoppingCartSettings.NewsLetterSubscription.ToSelectList();
805805

806+
StoreDependingSettings.GetOverrideKeys(shoppingCartSettings, model, storeScope, _services.Settings);
806807

807808
return View(model);
808809
}

src/Presentation/SmartStore.Web/Administration/Infrastructure/AutoMapperStartupTask.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,8 @@ public void Execute()
651651
Mapper.CreateMap<OrderSettingsModel, OrderSettings>()
652652
.ForMember(dest => dest.MinimumOrderPlacementInterval, mo => mo.Ignore())
653653
.ForMember(dest => dest.Id, mo => mo.Ignore());
654-
Mapper.CreateMap<ShoppingCartSettings, ShoppingCartSettingsModel>();
654+
Mapper.CreateMap<ShoppingCartSettings, ShoppingCartSettingsModel>()
655+
.ForMember(dest => dest.AvailableNewsLetterSubscription, mo => mo.Ignore());
655656
Mapper.CreateMap<ShoppingCartSettingsModel, ShoppingCartSettings>()
656657
.ForMember(dest => dest.MoveItemsFromWishlistToCart, mo => mo.Ignore())
657658
.ForMember(dest => dest.ShowItemsFromWishlistToCartButton, mo => mo.Ignore());

0 commit comments

Comments
 (0)