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