Error executing template "Designs/Swift/eCom7/CartV2/Step/Cart.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at CompiledRazorTemplates.Dynamic.RazorEngine_1ab26c12a2c44d3eba5cfada6d119eea.ExecuteAsync()
at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.DynamicWrapperService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String templateSource, String name, Type modelType, Object model, DynamicViewBag viewBag)
at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
2 @using Dynamicweb
3
4 @{
5 bool anonymousUser = Pageview.User == null;
6 var themeRaw = Pageview.CurrentParagraph.Item["Theme"]?.ToString();
7 string theme = !string.IsNullOrEmpty(themeRaw) ? " theme " + themeRaw.Replace(" ", string.Empty).Trim().ToLower() : string.Empty;
8
9 bool isB2C = Pageview.User != null &&
10 Dynamicweb.Security.UserManagement.User.GetAncestors(Pageview.User.ID)?.Any(x => x.CustomerNumber == "103895") == true;
11 var currentFrontendUser = Dynamicweb.Security.UserManagement.User.GetCurrentFrontendUser();
12 bool isInPrivateNewsletterGroup = currentFrontendUser != null
13 && currentFrontendUser.Groups != null
14 && currentFrontendUser.Groups.Any(g => g.Name == "Private Newsletter Email");
15 var showVatInclusive = (Pageview.User == null) || isB2C || isInPrivateNewsletterGroup;
16
17 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/";
18 int currentUserId = Dynamicweb.Core.Converter.ToInt32(GetGlobalValue("Global:Extranet.UserID"));
19 var shopPageId = GetPageIdByNavigationTag("Shop");
20 var cart = Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel(Pageview.CurrentParagraph)?.Item ?? null;
21 var checkoutAnonymousLink = cart.GetLink("CheckoutAnonymousPageLink") is object ? cart.GetLink("CheckoutAnonymousPageLink").Url : string.Empty;
22 var checkoutSignedInLink = cart.GetLink("CheckoutSignedInPageLink") is object ? cart.GetLink("CheckoutSignedInPageLink").Url : string.Empty;
23 string checkoutLink = currentUserId == 0 ? checkoutAnonymousLink : checkoutSignedInLink;
24 var quoteCheckoutLink = cart.GetLink("QuoteCheckoutPageLink") is object ? cart.GetLink("QuoteCheckoutPageLink").Url : string.Empty;
25 bool isQuote = Dynamicweb.Ecommerce.Services.Orders.GetById(GetString("Ecom:Order.ID")).IsQuote;
26 }
27
28 <div class="grid gap-0" id="Cart">
29 <header class="g-col-12">
30 <div class="pb-3 pb-lg-0 pt-3 pt-lg-5">
31 <h1 class="h3 mb-2">@Translate("Shopping Cart")</h1>
32 <p class="mb-0"><span>@Translate("Items in your shopping cart"):</span> <span>@GetString("Ecom:Order.OrderLines.TotalProductQuantity")</span></p>
33 </div>
34 </header>
35
36 <div class="g-col-12 g-col-lg-8 pe-lg-5 pb-md-5">
37 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
38 @using Dynamicweb.Ecommerce.Orders
39
40 @if (GetLoop("ValidationErrors").Count() != 0)
41 {
42 <div class="alert alert-warning" role="alert">
43 <ul class="m-0 list-unstyled">
44 @foreach (LoopItem item in GetLoop("ValidationErrors"))
45 {
46 <li>@item.GetValue("Ecom:Cart.ValidationError.ErrorMessage")</li>
47 }
48 </ul>
49 </div>
50 }
51
52
53 @* Logic to remove the voucher code error, when going to next step in checkout *@
54 @{
55 string voucherCodeForErrorCheck = GetString("Ecom:Order.Customer.VoucherCode");
56 Order orderForErrorCheck = new OrderService().GetById(GetString("Ecom:Order.ID"));
57 voucherCodeForErrorCheck = orderForErrorCheck.VoucherUseType == VoucherUseCategoryType.None ? string.Empty : voucherCodeForErrorCheck;
58 }
59
60 <input type="hidden" name="EcomOrderVoucherCode" value="@voucherCodeForErrorCheck">
61
62
63 <form name="ordersubmit" id="ordersubmit" method="post" autocomplete="off">
64
65 <header class="py-2 pt-lg-5 border-bottom d-none d-lg-block">
66 <div class="grid" style="line-height: 1;">
67 <div class="g-col-2">@Translate("Product")</div>
68 <div class="g-col-9 grid">
69 <div class="g-col-10 g-col-md-6 g-start-8"></div>
70 <div class="g-col-2 g-col-md-3 g-start-8">@Translate("Quantity")</div>
71 </div>
72 <div class="g-col-1 text-end">@Translate("Total")</div>
73 </div>
74 </header>
75
76 <script>
77 gtag("event", "view_cart", {
78 currency: "@GetString("Ecom:Order.Currency.Code")",
79 value: @GetDouble("Ecom:Order.Price.PriceWithVAT.Value").ToString("0.00", System.Globalization.CultureInfo.InvariantCulture),
80 items: [
81 @foreach (LoopItem orderline in GetLoop("OrderLines"))
82 {
83 <text>
84 {
85 item_id: "@orderline.GetString("Ecom:Order:OrderLine.ProductID")",
86 item_name: "@Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(orderline.GetString("Ecom:Order:OrderLine.ProductName"))",
87 currency: "@orderline.GetString("Ecom:Order:OrderLine.UnitPrice.CurrencyCode")",
88 price: @orderline.GetDouble("Ecom:Order:OrderLine.UnitPriceWithProductDiscount.Price.Value").ToString("0.00", System.Globalization.CultureInfo.InvariantCulture),
89 discount: @Math.Abs(orderline.GetDouble("Ecom:Order:OrderLine.UnitDiscount.Price.Value")).ToString("0.00", System.Globalization.CultureInfo.InvariantCulture),
90 quantity: @orderline.GetDouble("Ecom:Order:OrderLine.Quantity").ToString("0.00", System.Globalization.CultureInfo.InvariantCulture)
91 },</text>
92 }
93 ]
94 });
95 </script>
96
97 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
98 @using System.Globalization
99 @using System
100
101 @functions{
102
103 string DoubleToString(double? value)
104 {
105 if (value.HasValue)
106 {
107 return Math.Round(value.Value, 2).ToString(CultureInfo.InvariantCulture);
108 }
109 return null;
110 }
111 }
112
113 @{
114 var orderlines = GetLoop("OrderLines");
115 }
116
117 @for (int i = orderlines.Count - 1; i >= 0; i--)
118 {
119 var orderline = orderlines[i];
120 bool neverOutOfStock = orderline.GetBoolean("Ecom:Product.NeverOutOfStock");
121 int stockQuantity = neverOutOfStock ? 9999999 : orderline.GetInteger("Ecom:Product.Stock");
122 string name = orderline.GetString("Ecom:Order:OrderLine.ProductName");
123 string image = "/Admin/Public/GetImage.ashx?width=" + 180 + "&height=" + 180 + "&image=" + orderline.GetString("Ecom:Product.PrimaryImage") + "&Format=WebP&Quality=100";
124 string removeFromBasketLink = orderline.GetString("Ecom:Order:OrderLine.DeleteLink");
125 string priceTotalWithDiscounts = orderline.GetString("Ecom:Order:OrderLine.TotalPriceWithProductDiscounts.PriceFormatted");
126 string priceTotalWithDiscountsVat = orderline.GetString("Ecom:Order:OrderLine.Price.PriceWithVATFormatted");
127 string priceTotalWithDiscountsClean = orderline.GetString("Ecom:Order:OrderLine.TotalPriceWithProductDiscounts.Price");
128 string unitPrice = orderline.GetString("Ecom:Order:OrderLine.UnitPrice.PriceFormatted");
129 string unitPriceVat = orderline.GetString("Ecom:Order:OrderLine.UnitPrice.PriceWithVATFormatted");
130 string unitPriceClean = orderline.GetDouble("Ecom:Order:OrderLine.UnitPrice.Price").ToString("0.00", System.Globalization.CultureInfo.InvariantCulture);
131 string unitPriceCurrency = orderline.GetString("Ecom:Order:OrderLine.Price.CurrencyCode");
132 string discountPrice = orderline.GetString("Ecom:Order:OrderLine.UnitPriceWithProductDiscount.PriceFormatted");
133 string discountTotal = orderline.GetString("Ecom:Order:OrderLine.TotalDiscount.PriceFormatted");
134 string variantText = orderline.GetString("Ecom:Order:OrderLine.ProductVariantText");
135 var orderlineId = orderline.GetValue("Ecom:Order:OrderLine.Id");
136 var quantity = neverOutOfStock || stockQuantity >= orderline.GetDouble("Ecom:Order:OrderLine.Quantity") ? orderline.GetDouble("Ecom:Order:OrderLine.Quantity") : stockQuantity;
137 var unitName = orderline.GetString("Ecom:Order:OrderLine.UnitName");
138 string productId = orderline.GetString("Ecom:Order:OrderLine.ProductID");
139 string variantId = orderline.GetString("Ecom:Order:OrderLine.ProductVariantID");
140 string unitId = orderline.GetString("Ecom:Order:OrderLine.UnitID");
141
142 string minQty = orderline.GetDouble("Ecom:Product.PurchaseMinimumQuantity") != 1 ? "min=\"" + orderline.GetDouble("Ecom:Product.PurchaseMinimumQuantity").ToString() + "\"" : "min=\"1\"";
143 string stepQty = orderline.GetDouble("Ecom:Product.PurchaseQuantityStep") > 1 ? orderline.GetDouble("Ecom:Product.PurchaseQuantityStep").ToString() : "1";
144 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : "";
145
146 string detailsPageLink = Pageview.CurrentParagraph.Item["ProductPageLink"] != null ? Pageview.CurrentParagraph.Item["ProductPageLink"].ToString() : "";
147 detailsPageLink = detailsPageLink != "" ? detailsPageLink : GetPageIdByNavigationTag("ProductDetailPage").ToString();
148
149 var defaultGroupId = orderline.GetString("Ecom:Order:OrderLine.PrimaryOrDefaultGroupId");
150 var selectedDetailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(defaultGroupId)?.Meta.PrimaryPage ?? string.Empty;
151
152 string link = string.IsNullOrEmpty(selectedDetailPage) ? $"/Default.aspx?ID={detailsPageLink}&groupid={defaultGroupId}" : selectedDetailPage;
153 link += "&productid=" + productId;
154 link += !string.IsNullOrEmpty(variantId) ? "&variantid=" + variantId : "";
155
156 bool isProduct = orderline.GetBoolean("Ecom:Order:OrderLine.IsProduct") || (orderline.GetInteger("Ecom:Order:OrderLine.Type") == 3 && !string.IsNullOrEmpty(orderline.GetString("Ecom:Order:OrderLine.ProductNumber")));
157 if (isProduct)
158 {
159 <article class="grid pt-3" style="row-gap: 0;" data-product-id="@productId" data-variant-id="@variantId" data-unit-id="@unitId" data-orderline-total-price="@priceTotalWithDiscountsClean" data-orderline-unit-price="@unitPriceClean">
160 <div class="d-flex g-col-3 g-col-lg-2">
161 <a href="@link" class="ratio ratio-1x1 d-block" title="@name">
162 <img class="cart-item-img" src="@image" style="object-fit: contain;" alt="@name">
163 </a>
164 </div>
165
166 <div class="g-col-9 g-col-lg-10">
167
168 <div class="grid" style="row-gap: 0.5rem;">
169
170 <div class="g-col-12 g-col-md-8 grid grid-7 grid-md-9" style="row-gap: 0.5rem;">
171 <div class="g-col-6">
172 @* Title *@
173 <h3 class="h6 fs-7 fs-md-6 mb-0">
174 <a href="@link" class="text-decoration-none" title="@name">@name</a>
175 </h3>
176
177 @* Variants *@
178 @if (!string.IsNullOrEmpty(variantText))
179 {
180 <p class="mt-2 mb-0 fs-7 fs-md-6">@variantText</p>
181 }
182
183
184 @if (orderline.GetInteger("Ecom:Order:OrderLine.Type") == 3 && !string.IsNullOrEmpty(orderline.GetString("Ecom:Order:OrderLine.ProductNumber")))
185 {
186 @* Free product notice *@
187 <p class="mt-2 mb-0 fs-7 fs-md-6 opacity-75">@Translate("Free product")</p>
188 }
189 else
190 {
191 @* Unit price *@
192 <p class="fs-7 fs-md-6 mt-2 mb-0">
193 @if (!string.IsNullOrEmpty(unitName))
194 {
195 <span>@unitName: </span>
196 }
197 @if (discountPrice == unitPrice)
198 {
199 if (showVatInclusive)
200 {
201 <div>
202 <small class="opacity-85 fst-normal">@unitPriceVat @Translate("Incl. VAT")</small>
203 </div>
204 }
205 else
206 {
207 <span class="text-price">@unitPrice</span>
208 <div>
209 <small class="opacity-85 fst-normal">@unitPriceVat @Translate("Incl. VAT")</small>
210 </div>
211 }
212
213 }
214 else
215 {
216 <span class="text-price">@discountPrice</span>
217 <span class="text-decoration-line-through fs-7">
218 <span class="text-price">@unitPrice</span>
219 </span>
220 }
221 </p>
222 }
223 </div>
224
225 <div class="g-col-7 g-col-md-3 d-flex" style="justify-self: end;">
226 @if (orderline.GetInteger("Ecom:Order:OrderLine.Type") != 3)
227 {
228 @* Quantity *@
229 <div class="js-input-group">
230 <label for="QuantityOrderLine@(orderlineId)" class="visually-hidden">@Translate("Quantity"):</label>
231
232
233 <div class="d-flex" style="border: 1px solid #5555">
234 <button type="button" onclick="decreaseQuantity('@orderlineId', '@stockQuantity')" class="btn btn-stepper fs-6 fw-normal rounded-0" style="border-right: 1px solid #5555">-</button>
235
236 <input type="number" id="QuantityOrderLine@(orderlineId)" step="@stepQty" @minQty class="form-control text-center swift_quantity-field rounded-0 border-white" value="@quantity" name="QuantityOrderLine@(orderlineId)" onchange="UpdateQuantity(this)"
237 @qtyValidCheck style="width: 4rem;">
238
239 <button type="button" onclick="increaseQuantity('@orderlineId', '@stockQuantity')" class="btn btn-stepper fs-6 fw-normal m-r-5 rounded-0 " style="border-left: 1px solid #5555">+</button>
240 </div>
241 @if (stepQty != "1")
242 {
243 <div class="invalid-feedback d-none">
244 @Translate("Please select a quantity that is dividable by") @stepQty
245 </div>
246 }
247
248 <div class="invalid-feedback js-not-enough-stock d-none">
249 @Translate("We do not have enough products in stock")
250 </div>
251 </div>
252 }
253 else
254 {
255 <span>@quantity</span>
256 }
257 </div>
258 </div>
259
260 <div class="g-col-12 g-col-md-1 d-flex justify-content-start justify-content-md-center">
261 @{
262 string clickProductLink = string.Empty;
263 clickProductLink = "onclick=\"return removeProductLink('" + @productId + "', '" + @Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(name) + "', '" + @Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(variantText) + "', '" + @unitPriceCurrency + "', '" + @unitPriceClean + "', '" + @quantity.ToString().Replace(",", ".") + "')\"";
264 }
265 <a href="@removeFromBasketLink" class="btn btn-link p-0 m-0 fs-8 py-2" title="@Translate("Remove")" @clickProductLink>
266 <img style="width:1rem; height: auto" src="/Files/Templates/Designs/Swift/Assets/icons/bin.png" alt="@Translate("Remove")" />
267 </a>
268 <script>
269 function removeProductLink(productId, productName, productVariant, productCurrency, productPrice, productQuantity) {
270 if (typeof gtag !== "undefined") {
271 gtag("event", "remove_from_cart", {
272 currency: productCurrency,
273 value: productPrice,
274 items: [
275 {
276 item_id: productId,
277 item_name: productName,
278 item_variant: productVariant,
279 currency: productCurrency,
280 price: productPrice,
281 item_list_id: "cart",
282 item_list_name: "Cart",
283 quantity: productQuantity
284 }
285 ]
286 });
287 }
288 }
289 </script>
290 </div>
291
292 <div class="g-col-12 g-col-md-3 text-end py-2">
293 @* Total *@
294 <span class="h6 mb-0 d-block fs-7 fs-md-6">
295 @if (showVatInclusive)
296 {
297 <div>
298 <small class="opacity-85 fst-normal">@unitPriceVat @Translate("Incl. VAT")</small>
299 </div>
300 }
301 else
302 {
303 <span class="text-price">@priceTotalWithDiscounts</span>
304 <div>
305 <small class="opacity-85 fst-normal">@priceTotalWithDiscountsVat @Translate("Incl. VAT")</small>
306 </div>
307 }
308 </span>
309 @if (orderline.GetDouble("Ecom:Order:OrderLine.TotalDiscount.Price.Value") != 0)
310 {
311 <span class="m-0 d-block fs-8">
312 <span class="text-price">@discountTotal</span>
313 </span>
314 }
315 </div>
316 </div>
317 <br />
318 </div>
319
320 @* Bottom border *@
321 <span class="g-col-12 mt-3">
322 <span class="d-none d-lg-block border-bottom"></span>
323 </span>
324 </article>
325 }
326 }
327
328
329 <script>
330 async function UpdateQuantity(input) {
331 const form = input.closest("form");
332 if (!form) {
333 console.error("No form found for quantity input", input);
334 return;
335 }
336
337 const fd = new FormData();
338 fd.append(input.name, input.value);
339
340 form.querySelectorAll("input[type=hidden]").forEach(h => {
341 fd.append(h.name, h.value);
342 });
343
344 try {
345 const res = await fetch(form.action || window.location.href, {
346 method: "POST",
347 body: fd
348 });
349
350 if (res.ok) {
351 window.location.reload();
352 }
353 } catch (err) {
354 console.error("UpdateQuantity failed:", err);
355 }
356 }
357
358 function decreaseQuantity(orderlineId) {
359 const input = document.getElementById("QuantityOrderLine" + orderlineId);
360 const step = parseInt(input.step) || 1;
361 const min = parseInt(input.min) || 1;
362 const value = parseInt(input.value) || 0;
363
364 input.value = Math.max(value - step, min);
365 UpdateQuantity(input);
366 }
367
368 function increaseQuantity(orderlineId) {
369 const input = document.getElementById("QuantityOrderLine" + orderlineId);
370 const step = parseInt(input.step) || 1;
371 const value = parseInt(input.value) || 0;
372
373 input.value = value + step;
374 UpdateQuantity(input);
375 }
376 </script>
377
378
379
380 @if(Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Desktop)
381 {
382 <text>@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
383 @using Dynamicweb.Ecommerce.Orders
384
385 @* Red lines may be due to variables defined in the parent tempalte - There is no actual error *@
386
387 @{
388
389 <div class="align-items-center d-grid d-lg-flex gap-2 justify-content-lg-end mt-lg-4">
390
391 <a href="Default.aspx?ID=@shopPageId" class="btn btn-link link-secondary text-decoration-none me-lg-3 order-last order-lg-first swift_cartbackbutton">
392 <span class="d-flex align-items-center justify-content-center position-relative">
393 <span class="icon-2 me-1 position-absolute position-lg-static start-0">
394 @ReadFile(iconPath + "chevron-left.svg")
395 </span>
396 <span>@Translate("Continue shopping")</span>
397 </span>
398 </a>
399
400 @if (!anonymousUser && isQuote)
401 {
402 <a href="@($"{Context.Current.Request.Url}&cartcmd=emptycart")" class="btn btn-secondary">
403 <span class="d-flex align-items-center justify-content-center position-relative">
404 <span>@Translate("Clear Cart")</span>
405 <span class="icon-2 ms-1 position-absolute position-lg-static end-0">
406 @ReadFile(iconPath + "trash-2.svg")
407 </span>
408 </span>
409 </a>
410 }
411
412 @* @if (!string.IsNullOrEmpty(quoteCheckoutLink) && !anonymousUser && !isQuote)
413 {
414 <a href="@quoteCheckoutLink" class="btn btn-secondary">
415 <span class="d-flex align-items-center justify-content-center position-relative">
416 <span>@Translate("Request quote")</span>
417 <span class="icon-2 ms-1 position-absolute position-lg-static end-0">
418 @ReadFile(iconPath + "chevron-right.svg")
419 </span>
420 </span>
421 </a>
422 }*@
423
424 <a href="@checkoutLink" class="btn btn-primary" id="GoToCheckoutButton">
425 <span class="d-flex align-items-center justify-content-center position-relative">
426 <span>@Translate("Checkout")</span>
427 <span class="icon-2 ms-1 position-absolute position-lg-static end-0">
428 @ReadFile(iconPath + "chevron-right.svg")
429 </span>
430 </span>
431 </a>
432
433 </div>
434 }
435 </text>
436 }
437
438 </form>
439 </div>
440
441 <aside class="g-col-12 g-col-lg-4 position-relative">
442 <div class="p-3 p-lg-5 pb-lg-4@(theme)">
443 <header>
444 <h4 class="fs-6 fw-normal mb-2">@Translate("Order summary")</h4>
445 </header>
446
447 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
448 @using System.Text.RegularExpressions
449 @using System.Globalization
450 @using System.Linq
451
452 @{
453 double totalPriceWithoutOrderDiscountsFeesAndTaxesValue =
454 GetDouble("Ecom:Order.TotalPriceWithoutDiscountsFeesAndTaxes.Price.Value")
455 + GetDouble("Ecom:Order.TotalProductDiscount.Price.Value");
456
457 var orderCurrency = Dynamicweb.Ecommerce.Services.Currencies.GetCurrency(GetString("Ecom:Order.Currency.Code"));
458 string totalPriceWithoutOrderDiscountsFeesAndTaxes = Dynamicweb.Ecommerce.Services.Currencies.Format(orderCurrency, totalPriceWithoutOrderDiscountsFeesAndTaxesValue);
459
460 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower();
461 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat);
462
463 bool disableVouchers = Pageview.CurrentParagraph?.Item["DisableVouchers"] != null
464 ? (bool)Pageview.CurrentParagraph.Item["DisableVouchers"]
465 : false;
466 disableVouchers = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("CompletedOrderId")) ? true : disableVouchers;
467
468 bool renderVoucher = true;
469 if (Pageview.CurrentParagraph?.Item["RenderVoucher"] != null)
470 {
471 renderVoucher = (bool)Pageview.CurrentParagraph.Item["RenderVoucher"];
472 }
473 }
474
475 <div class="d-flex flex-column gap-2 gap-lg-3 pb-3 bottom-0 sticky-receipt theme" id="orderSummaryFooter">
476
477 @if (renderVoucher && !disableVouchers && Pageview.CurrentParagraph?.Item.SystemName != "Swift_QuoteCheckoutApp")
478 {
479 <text>@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
480 @using Dynamicweb.Ecommerce.Orders
481
482 @{
483 string voucherCode = GetString("Ecom:Order.Customer.VoucherCode");
484 string voucherCodeError = GetString("Ecom:Cart.ValidationError.EcomOrderVoucherCode.ErrorMessage");
485 string validState = string.Empty;
486
487 IEnumerable<string> voucherCodes = new List<string>();
488 Order order = new OrderService().GetById(GetString("Ecom:Order.ID"));
489
490 if (!string.IsNullOrWhiteSpace(voucherCode))
491 {
492 if (order.VoucherUseType.HasFlag(VoucherUseCategoryType.Discount))
493 {
494 voucherCodes = voucherCode.Split(new string[] { ",", ";", " " }, StringSplitOptions.RemoveEmptyEntries);
495 }
496 else
497 {
498 voucherCodes = new string[] { voucherCode.Trim() };
499 }
500 }
501
502 var voucherErrors = new List<string>();
503 foreach (string code in voucherCodes)
504 {
505 Dynamicweb.Ecommerce.Orders.Vouchers.Voucher vouch = Dynamicweb.Ecommerce.Services.Vouchers.GetVoucherByCode(code);
506 if (vouch == null)
507 {
508 validState = "is-invalid";
509 voucherErrors.Add(Translate("Voucher") + " <span class='fw-bold'>" + code + "</span> " + Translate("not found"));
510 continue;
511 }
512 if (vouch.DateUsed.HasValue)
513 {
514 validState = "is-invalid";
515 voucherErrors.Add(Translate("Voucher") + " <span class='fw-bold'>" + code + "</span> " + Translate("already used"));
516 continue;
517 }
518 }
519
520 var voucherErrorMessage = string.Join(",", voucherErrors);
521
522 <div class="py-3 border-top" id="orderVoucherForm">
523 <form method="post" id="VoucherForm">
524 <div class="input-group input-primary-button-group has-validation">
525 <input type="text" class="form-control @(validState)" name="EcomOrderVoucherCodeField" placeholder="@Translate("Add voucher here")" id="EcomOrderVoucherCodeField" value="" aria-label="@Translate("Voucher input")" oninput="document.querySelector('#EcomOrderVoucherCode').value = this.value;" onkeyup="document.querySelector('#EcomOrderVoucherCode').value = this.value;">
526 <button class="btn btn-sm btn-primary d-inline-flex align-items-center justify-content-center" type="submit" id="EcomOrderVoucherApply" style="min-width: 100px;">
527 <span>@Translate("Apply")</span>
528 </button>
529
530 <div class="invalid-feedback">
531 @voucherErrorMessage
532 </div>
533 </div>
534 <input type="hidden" name="EcomOrderVoucherCode" id="EcomOrderVoucherCode" value="@voucherCode">
535 <label for="EcomOrderVoucherCodeField" class="visually-hidden">@Translate("Add voucher here")</label>
536 </form>
537
538 @if (!string.IsNullOrWhiteSpace(voucherCode))
539 {
540 <div class="d-flex flex-wrap gap-2 pt-3">
541
542 @foreach (string code in voucherCodes)
543 {
544 <form method="post">
545 @{
546 Dynamicweb.Ecommerce.Orders.Vouchers.Voucher vouch = Dynamicweb.Ecommerce.Services.Vouchers.GetVoucherByCode(code);
547 string voucherValue = string.Empty;
548 if (vouch != null && !vouch.DateUsed.HasValue) {
549 voucherValue = voucherCode.Replace(code+",", "").Replace(","+code, "").Replace(code, "");
550 }
551 <input type="hidden" name="EcomOrderVoucherCode" value="@voucherValue">
552 }
553 <span class="badge fw-normal d-inline-flex align-items-center justify-content-center opacity-50 opacity-100-hover" style="background-color:var(--swift-foreground-color);color:var(--swift-background-color);">
554 <span class="icon-2">
555 @ReadFile("/Files/Templates/Designs/Swift/Assets/icons/tag.svg")
556 </span>
557 <span class="mx-2">@code</span>
558 <button type="submit" class="text-reset bg-transparent border-0 p-0" aria-label="@Translate("Remove voucher")" id="RemoveVoucherButton">
559 <span class="icon-2">
560 @ReadFile("/Files/Templates/Designs/Swift/Assets/icons/x.svg")
561 </span>
562 </button>
563 </span>
564 </form>
565 }
566 </div>
567 }
568 @voucherCodeError
569 </div>
570 }
571 </text>
572 }
573
574 <div class="fs-8 border-top pt-2 pt-lg-3">
575
576 @{
577 var hasShippingMethod = !string.IsNullOrEmpty(GetString("Ecom:Order.ShippingMethodID"));
578 if (hasShippingMethod)
579 {
580 var baseShippingFeeString = GetString("Ecom:Order.ShippingFee");
581 decimal baseShippingFee = 0;
582 var match = Regex.Match(baseShippingFeeString, @"\d+(\.\d+)?");
583 if (match.Success)
584 {
585 baseShippingFee = decimal.Parse(match.Value, CultureInfo.InvariantCulture);
586 }
587
588 var vatRate = 0.25m;
589 var showVatInclusivePrices = (Pageview.User == null) || isB2C;
590 var shippingFee = showVatInclusivePrices ? baseShippingFee * (1 + vatRate) : baseShippingFee;
591
592 <div class="d-flex justify-content-between fw-normal">
593 <span>@Translate("Shipping Fee")</span>
594 <span class="text-end">
595 <span class="d-block">
596 <span class="fs-8 fw-normal d-block">@shippingFee.ToString("C")</span>
597 </span>
598 </span>
599 </div>
600 }
601 else
602 {
603 <div class="d-flex justify-content-between">
604 <span>@Translate("Delivery")</span>
605 <span>@Translate("Calculated in next step")</span>
606 </div>
607 }
608 }
609
610 <div class="d-flex justify-content-between fw-bold">
611 <span>@Translate("Subtotal")</span>
612 <span class="text-end">
613 <span class="d-block">
614 @if (GetDouble("Ecom:Order.TotalPriceWithoutDiscountsFeesAndTaxes.Price.Value") != totalPriceWithoutOrderDiscountsFeesAndTaxesValue)
615 {
616 <span class="text-price fw-normal text-decoration-line-through">
617 @GetString("Ecom:Order.TotalPriceWithoutDiscountsFeesAndTaxes.PriceFormatted")
618 </span>
619 }
620
621 @if (showVatInclusive)
622 {
623 <span class="text-price">@GetString("Ecom:Order.OrderLines.Total.PriceWithVAT")</span>
624 }
625 else
626 {
627 <span class="text-price">@totalPriceWithoutOrderDiscountsFeesAndTaxes</span>
628 }
629 </span>
630
631 @if (!neverShowVat && showPricesWithVat == "false")
632 {
633 if (showVatInclusive)
634 {
635 <span class="fs-8 fw-normal d-block">@Translate("Incl. VAT")</span>
636 }
637 else
638 {
639 <span class="fs-8 fw-normal d-block">@Translate("Excl. VAT")</span>
640 }
641 }
642 else if (!neverShowVat)
643 {
644 <span class="fs-8 fw-normal d-block">@Translate("Incl. VAT")</span>
645 }
646 </span>
647 </div>
648
649 @foreach (LoopItem orderline in GetLoop("OrderLines"))
650 {
651 bool isDiscount = orderline.GetBoolean("Ecom:Order:OrderLine.IsDiscount");
652 bool isProductIdOrNumber =
653 !string.IsNullOrEmpty(orderline.GetString("Ecom:Order:OrderLine.ProductID"))
654 || !string.IsNullOrEmpty(orderline.GetString("Ecom:Order:OrderLine.ProductNumber"));
655 bool isOrderAmountDiscount = orderline.GetInteger("Ecom:Order:OrderLine.Type") == 1 && !isProductIdOrNumber;
656
657 if (isDiscount && isOrderAmountDiscount)
658 {
659 <div class="d-flex justify-content-between">
660 <span>@orderline.GetString("Ecom:Order:OrderLine.ProductName")</span>
661 <span class="text-price">@orderline.GetString("Ecom:Order:OrderLine.TotalPriceWithProductDiscounts.PriceFormatted")</span>
662 </div>
663 }
664 }
665
666 @if (!string.IsNullOrEmpty(GetString("Ecom:Order.PaymentMethodID")))
667 {
668 if (GetDouble("Ecom:Order.PaymentFee.Price.Value") != 0)
669 {
670 <div class="d-flex justify-content-between">
671 <span>@Translate("Payment")</span>
672 <span class="text-price">@GetString("Ecom:Order.PaymentFee.PriceFormatted")</span>
673 </div>
674 }
675 }
676 else
677 {
678 <div class="d-flex justify-content-between">
679 <span>@Translate("Payment")</span>
680 <span>@Translate("Calculated in next step")</span>
681 </div>
682 }
683
684 @if (GetDouble("Ecom:Order.Taxes.Total.Price.Value") != 0)
685 {
686 <div class="d-flex justify-content-between mb-2">
687 <span>@Translate("Sales tax")</span>
688 <span>@GetString("Ecom:Order.Taxes.Total.PriceFormatted")</span>
689 </div>
690 }
691 </div>
692
693 <div class="fs-8 border-top pt-2 pt-lg-3">
694 <div class="d-flex justify-content-between fs-6 fw-bold">
695 @if (!neverShowVat && showPricesWithVat == "false")
696 {
697 if (showVatInclusive)
698 {
699 <span>@Translate("Total incl. VAT")</span>
700 <span class="text-price text-end">
701 <span class="fs-5 d-block">@GetString("Ecom:Order.OrderLines.Total.PriceWithVAT")</span>
702 </span>
703 }
704 else
705 {
706 <span>@Translate("Total")</span>
707 <span class="text-price text-end">
708 <span class="fs-5 d-block">@GetString("Ecom:Order.Price.PriceFormatted")</span>
709 <span class="fs-8 fw-normal d-block">@Translate("Excl. VAT")</span>
710 </span>
711 }
712 }
713 else if (!neverShowVat && showPricesWithVat == "true")
714 {
715 <span>@Translate("Total")</span>
716 <span class="text-price text-end">
717 <span class="fs-5 d-block">@GetString("Ecom:Order.Price.PriceFormatted")</span>
718 <span class="fs-8 fw-normal d-block">@Translate("Incl. VAT")</span>
719 </span>
720 }
721 else
722 {
723 <span>@Translate("Total")</span>
724 <span class="text-price fs-5">@GetString("Ecom:Order.Price.PriceFormatted")</span>
725 }
726 </div>
727
728 @if (!neverShowVat)
729 {
730 if (showVatInclusive)
731 {
732 <div class="d-flex justify-content-between">
733 <span>@Translate("Excl. VAT")</span>
734 <span class="text-price">@GetString("Ecom:Order.Price.PriceFormatted")</span>
735 </div>
736 if (showPricesWithVat == "false")
737 {
738 <div class="d-flex justify-content-between">
739 <span>@Translate("VAT")</span>
740 <span class="text-price">@GetString("Ecom:Order.Price.VATFormatted")</span>
741 </div>
742 }
743 }
744 else
745 {
746 <div class="d-flex justify-content-between">
747 <span>@Translate("VAT")</span>
748 <span class="text-price">@GetString("Ecom:Order.Price.VATFormatted")</span>
749 </div>
750 if (showPricesWithVat == "false")
751 {
752 <div class="d-flex justify-content-between">
753 <span>@Translate("Total incl. VAT")</span>
754 <span class="text-price">@GetString("Ecom:Order.OrderLines.Total.PriceWithVAT")</span>
755 </div>
756 }
757 }
758 }
759
760 @if (GetDouble("Ecom:Order.TotalDiscount.Price.Value") != 0)
761 {
762 <div class="d-flex justify-content-between">
763 <span>@Translate("Discount")</span>
764 <span class="text-price">@GetString("Ecom:Order.TotalDiscount.PriceFormatted")</span>
765 </div>
766 }
767 </div>
768 </div>
769
770
771 @if(Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet)
772 {
773 <text>@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
774 @using Dynamicweb.Ecommerce.Orders
775
776 @* Red lines may be due to variables defined in the parent tempalte - There is no actual error *@
777
778 @{
779
780 <div class="align-items-center d-grid d-lg-flex gap-2 justify-content-lg-end mt-lg-4">
781
782 <a href="Default.aspx?ID=@shopPageId" class="btn btn-link link-secondary text-decoration-none me-lg-3 order-last order-lg-first swift_cartbackbutton">
783 <span class="d-flex align-items-center justify-content-center position-relative">
784 <span class="icon-2 me-1 position-absolute position-lg-static start-0">
785 @ReadFile(iconPath + "chevron-left.svg")
786 </span>
787 <span>@Translate("Continue shopping")</span>
788 </span>
789 </a>
790
791 @if (!anonymousUser && isQuote)
792 {
793 <a href="@($"{Context.Current.Request.Url}&cartcmd=emptycart")" class="btn btn-secondary">
794 <span class="d-flex align-items-center justify-content-center position-relative">
795 <span>@Translate("Clear Cart")</span>
796 <span class="icon-2 ms-1 position-absolute position-lg-static end-0">
797 @ReadFile(iconPath + "trash-2.svg")
798 </span>
799 </span>
800 </a>
801 }
802
803 @* @if (!string.IsNullOrEmpty(quoteCheckoutLink) && !anonymousUser && !isQuote)
804 {
805 <a href="@quoteCheckoutLink" class="btn btn-secondary">
806 <span class="d-flex align-items-center justify-content-center position-relative">
807 <span>@Translate("Request quote")</span>
808 <span class="icon-2 ms-1 position-absolute position-lg-static end-0">
809 @ReadFile(iconPath + "chevron-right.svg")
810 </span>
811 </span>
812 </a>
813 }*@
814
815 <a href="@checkoutLink" class="btn btn-primary" id="GoToCheckoutButton">
816 <span class="d-flex align-items-center justify-content-center position-relative">
817 <span>@Translate("Checkout")</span>
818 <span class="icon-2 ms-1 position-absolute position-lg-static end-0">
819 @ReadFile(iconPath + "chevron-right.svg")
820 </span>
821 </span>
822 </a>
823
824 </div>
825 }
826 </text>
827 }
828
829 </div>
830 </aside>
831 </div>
832