Skip to content

Commit 9149c9c

Browse files
committed
Resolves smartstore#654 Place user agreement for downloadable files in checkout process
1 parent bf87c9d commit 9149c9c

9 files changed

Lines changed: 153 additions & 28 deletions

File tree

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
* PayPal: Option for API security protocol
4444
* Product filter: Option to sort filter results by their display order rather than by number of matches
4545
* Elmar Shopinfo: Option to export delivery time as availability
46+
* #654 Place user agreement for downloadable files in checkout process
4647

4748
### Improvements
4849
* (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%.

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,18 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
339339
builder.AddOrUpdate("Common.WrongCaptcha",
340340
"Please confirm that you are not a \"robot\".",
341341
"Bitte bestätigen Sie, dass Sie kein \"Roboter\" sind.");
342+
343+
builder.AddOrUpdate("DownloadableProducts.UserAgreementConfirmation",
344+
"Yes, I agree to the <a href='javascript:void(0)' data-id='{0}' class='download-user-agreement'>user agreement</a> for this product.",
345+
"Ja, ich stimme der <a href='javascript:void(0)' data-id='{0}' class='download-user-agreement'>Nutzungsvereinbarung</a> für dieses Produkt zu.");
346+
347+
builder.AddOrUpdate("DownloadableProducts.HasNoUserAgreement",
348+
"The product has no user agreement.",
349+
"Das Produkt besitzt keine Nutzungsvereinbarung.");
350+
351+
builder.AddOrUpdate("Checkout.DownloadUserAgreement.PleaseAgree",
352+
"Please agree to the user agreement for downloadable products.",
353+
"Bitte stimmen Sie der Nutzungsvereinbarung für herunterladbare Produkte zu.");
342354
}
343355
}
344356
}

src/Presentation/SmartStore.Web/Controllers/DownloadController.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System;
2+
using System.Web;
23
using System.Web.Mvc;
34
using SmartStore.Core;
45
using SmartStore.Core.Domain.Catalog;
56
using SmartStore.Core.Domain.Customers;
67
using SmartStore.Core.Domain.Media;
8+
using SmartStore.Core.Html;
79
using SmartStore.Services.Catalog;
810
using SmartStore.Services.Media;
911
using SmartStore.Services.Orders;
@@ -167,5 +169,25 @@ public ActionResult GetFileUpload(Guid downloadId)
167169

168170
return GetFileContentResultFor(download, null);
169171
}
170-
}
172+
173+
public ActionResult GetUserAgreement(int productId, bool? asPlainText)
174+
{
175+
var product = _productService.GetProductById(productId);
176+
if (product == null)
177+
return HttpNotFound();
178+
179+
if (!product.IsDownload || !product.HasUserAgreement || product.UserAgreementText.IsEmpty())
180+
return Content(T("DownloadableProducts.HasNoUserAgreement"));
181+
182+
if (asPlainText ?? false)
183+
{
184+
var agreement = HtmlUtils.ConvertHtmlToPlainText(product.UserAgreementText);
185+
agreement = HtmlUtils.StripTags(HttpUtility.HtmlDecode(agreement));
186+
187+
return Content(agreement);
188+
}
189+
190+
return Content(product.UserAgreementText);
191+
}
192+
}
171193
}

src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,9 @@ private ShoppingCartModel.ShoppingCartItemModel PrepareShoppingCartItemModel(Org
240240
ShortDesc = product.GetLocalized(x => x.ShortDescription),
241241
ProductType = product.ProductType,
242242
BasePrice = product.GetBasePriceInfo(_localizationService, _priceFormatter, _currencyService, _taxService, _priceCalculationService, _workContext.WorkingCurrency),
243-
Weight = product.Weight
243+
Weight = product.Weight,
244+
IsDownload = product.IsDownload,
245+
HasUserAgreement = product.HasUserAgreement
244246
};
245247

246248
model.ProductUrl = GetProductUrlWithAttributes(sci, model.ProductSeName);

src/Presentation/SmartStore.Web/Models/ShoppingCart/ShoppingCartModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ public ShoppingCartItemModel()
108108

109109
public string BasePrice { get; set; }
110110

111+
public bool IsDownload { get; set; }
112+
public bool HasUserAgreement { get; set; }
113+
111114
public bool BundlePerItemPricing { get; set; }
112115
public bool BundlePerItemShoppingCart { get; set; }
113116
public BundleItemModel BundleItem { get; set; }

src/Presentation/SmartStore.Web/Views/Checkout/Confirm.Mobile.cshtml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@
7575
<script type="text/javascript">
7676
$(function () {
7777
$('.confirm-order-next-step-button').click(function () {
78-
//terms of services
79-
var termOfServiceOk = true;
78+
var termOfServiceOk = true,
79+
userAgreementsOk = true;
80+
81+
// terms of services
8082
@if (Model.TermsOfServiceEnabled)
8183
{
8284
<text>
@@ -89,8 +91,17 @@
8991
}
9092
</text>
9193
}
94+
95+
// agree user agreement for downloadable products
96+
$('ul.list-order-products').find('input[name^=AgreeUserAgreement]').each(function () {
97+
if (!$(this).is(':checked')) {
98+
userAgreementsOk = false;
99+
alert('@T("Checkout.DownloadUserAgreement.PleaseAgree")');
100+
return false;
101+
}
102+
});
92103
93-
if (termOfServiceOk) {
104+
if (termOfServiceOk && userAgreementsOk) {
94105
var submitOrderEvent = jQuery.Event('submitOrder');
95106
submitOrderEvent.isOrderValid = true;
96107
submitOrderEvent.isMobile = true;

src/Presentation/SmartStore.Web/Views/Checkout/Confirm.cshtml

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
@Html.Raw(@T("Checkout.ConfirmHint"))
2828
</div>
2929

30-
<input id="customercommenthidden" type="hidden" name="customercommenthidden" />
30+
<input type="hidden" id="customercommenthidden" name="customercommenthidden" />
3131

3232
if (Model.TermsOfServiceEnabled)
3333
{
@@ -92,11 +92,11 @@
9292
</div>
9393

9494
@if (Model.ShowConfirmOrderLegalHint)
95-
{
96-
<div class="confirm-order-legal-hint alert alert-info">
97-
@T("OrderSummary.ConfirmOrderLegalHint")
98-
</div>
99-
}
95+
{
96+
<div class="confirm-order-legal-hint alert alert-info">
97+
@T("OrderSummary.ConfirmOrderLegalHint")
98+
</div>
99+
}
100100

101101
<div class="confirm-order">
102102

@@ -111,26 +111,39 @@
111111
$(function () {
112112
var checkoutButton = $(".confirm-order-next-step-button");
113113
checkoutButton.click(function () {
114+
var termOfServiceOk = true,
115+
userAgreementsOk = true;
114116
115-
$("#customercommenthidden").val($("#CustomerComment").val());
117+
$("#customercommenthidden").val($("#CustomerComment").val());
116118
117-
//terms of services
118-
var termOfServiceOk = true;
119+
// terms of services
119120
@if (Model.TermsOfServiceEnabled)
120121
{
121-
<text>
122+
<text>
122123
if (!$('#termsofservice').is(':checked')) {
123-
displayNotification('@T("Checkout.TermsOfService.PleaseAccept").ToString().EncodeJsString()', "error");
124+
displayNotification('@T("Checkout.TermsOfService.PleaseAccept").ToString().EncodeJsString('"', false)', "error");
124125
termOfServiceOk = false;
125126
$.scrollTo($('#termsofservice'), 800, { offset: -70 });
126127
}
127128
else {
128129
termOfServiceOk = true;
129130
}
130-
</text>
131+
</text>
131132
}
133+
134+
// agree user agreement for downloadable products
135+
$('table.table-order-products').find('input[name^=AgreeUserAgreement]').each(function () {
136+
if (!$(this).is(':checked')) {
137+
userAgreementsOk = false;
138+
displayNotification('@T("Checkout.DownloadUserAgreement.PleaseAgree").ToString().EncodeJsString('"', false)', 'error');
139+
if (termOfServiceOk) {
140+
$.scrollTo($('table.table-order-products'), 800, { offset: -20 });
141+
}
142+
return false;
143+
}
144+
});
132145
133-
if (termOfServiceOk) {
146+
if (termOfServiceOk && userAgreementsOk) {
134147
var submitOrderEvent = jQuery.Event('submitOrder');
135148
submitOrderEvent.isOrderValid = true;
136149
submitOrderEvent.isMobile = false;

src/Presentation/SmartStore.Web/Views/ShoppingCart/OrderSummary.Mobile.cshtml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
using (Html.BeginRouteForm("ShoppingCart", FormMethod.Post, new Dictionary<string, Object> { { "data-ajax", "false" }, { "enctype", "multipart/form-data" } }))
7676
{
7777
<div class="cart">
78-
<ul data-role="listview" data-inset="true" data-filter="false">
78+
<ul data-role="listview" data-inset="true" data-filter="false" class="list-order-products">
7979
@foreach (var item in Model.Items)
8080
{
8181
<li>
@@ -155,6 +155,15 @@
155155
</div>
156156
}
157157
</div>
158+
@if (!Model.IsEditable && item.IsDownload && item.HasUserAgreement)
159+
{
160+
<div class="download-agreement">
161+
<label>
162+
<input type="checkbox" name="AgreeUserAgreement@(item.ProductId)">
163+
@T("DownloadableProducts.UserAgreementConfirmation", item.ProductId)
164+
</label>
165+
</div>
166+
}
158167
@if (Model.IsEditable)
159168
{
160169
<div class="updateitem">
@@ -276,3 +285,18 @@
276285
}
277286
@Html.Widget("mobile_order_summary_content_after")
278287
</div>
288+
289+
@if (!Model.IsEditable && Model.Items.Any(x => x.IsDownload && x.HasUserAgreement))
290+
{
291+
<script type="text/javascript">
292+
$(document).ready(function () {
293+
$('a.download-user-agreement').click(function () {
294+
var url = '@(Url.Action("GetUserAgreement", "Download"))?asPlainText=true&productId=' + $(this).attr('data-id');
295+
$.get(url, function (text) {
296+
alert(text);
297+
});
298+
return false;
299+
});
300+
});
301+
</script>
302+
}

src/Presentation/SmartStore.Web/Views/ShoppingCart/OrderSummary.cshtml

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,12 @@
4444
</div>
4545
}
4646

47-
@if (Model.DisplayDeliveryTime)
47+
@if (Model.DisplayDeliveryTime && item.IsShipEnabled && (!String.IsNullOrEmpty(item.DeliveryTimeName) && !String.IsNullOrEmpty(item.DeliveryTimeHexValue)))
4848
{
4949
<div class="delivery-time">
50-
@if ((!String.IsNullOrEmpty(item.DeliveryTimeName) && !String.IsNullOrEmpty(item.DeliveryTimeHexValue)) && item.IsShipEnabled)
51-
{
52-
<span class="delivery-time-label">@T("Products.DeliveryTime")</span>
53-
<span class="delivery-time-color" style="background-color:@item.DeliveryTimeHexValue" title="@item.DeliveryTimeName"></span>
54-
<span class="delivery-time-value">@item.DeliveryTimeName</span>
55-
}
50+
<span class="delivery-time-label">@T("Products.DeliveryTime")</span>
51+
<span class="delivery-time-color" style="background-color:@item.DeliveryTimeHexValue" title="@item.DeliveryTimeName"></span>
52+
<span class="delivery-time-value">@item.DeliveryTimeName</span>
5653
</div>
5754
}
5855

@@ -68,6 +65,17 @@
6865
@Html.Raw(item.RecurringInfo)
6966
</div>
7067
}
68+
@if (!Model.IsEditable && item.IsDownload && item.HasUserAgreement)
69+
{
70+
<div class="download-agreement">
71+
<div class="checkbox">
72+
<label>
73+
<input type="checkbox" name="AgreeUserAgreement@(item.ProductId)">
74+
@T("DownloadableProducts.UserAgreementConfirmation", item.ProductId)
75+
</label>
76+
</div>
77+
</div>
78+
}
7179
@if (item.Warnings.Count > 0)
7280
{
7381
<div class="alert alert-error">
@@ -126,8 +134,7 @@
126134
@helper BundleProducts(ShoppingCartModel.ShoppingCartItemModel parentItem)
127135
{
128136
if (parentItem.ChildItems != null)
129-
{
130-
137+
{
131138
<tr class="product-bundle-row">
132139
<td colspan="2">&nbsp;</td>
133140
<td colspan="5" class="bundle-headline">
@@ -413,3 +420,33 @@
413420
</div>
414421
}
415422
</div>
423+
424+
@if (!Model.IsEditable && Model.Items.Any(x => x.IsDownload && x.HasUserAgreement))
425+
{
426+
<div id="user-agreement-modal" class="modal modal-large hide fade" tabindex="-1">
427+
<div class="modal-header">
428+
<h4 class="caption">@T("DownloadableProducts.UserAgreement")</h4>
429+
</div>
430+
<div class="modal-body"></div>
431+
<div class="modal-footer">
432+
<button class="btn" data-dismiss="modal">@T("Common.OK")</button>
433+
</div>
434+
</div>
435+
<script type="text/javascript">
436+
$(document).ready(function () {
437+
$('a.download-user-agreement').click(function () {
438+
var url = '@(Url.Action("GetUserAgreement", "Download"))?productId=' + $(this).attr('data-id'),
439+
dialog = $('#user-agreement-modal');
440+
441+
dialog.find('.modal-body').empty();
442+
443+
$.get(url, function (html) {
444+
dialog.find('.modal-body').html(html);
445+
});
446+
447+
dialog.modal('show');
448+
return false;
449+
});
450+
});
451+
</script>
452+
}

0 commit comments

Comments
 (0)