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
By clicking 'Accept All' you consent that we may collect information about you for various purposes, including: Statistics and Marketing