Error executing template "Designs/Swift-v2/eCom7/CartV2/Step/Cart.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_f1e8bf5afadb46f5950b695752cdae13.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) in /_/src/Application/Providers/Dynamicweb.Rendering.Providers.NetCore/Razor/RazorTemplateRenderingProvider.cs:line 110
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template) in E:\A10\_w\2\s\src\Core\Dynamicweb.Core\Rendering\TemplateRenderingService.cs:line 21
   at Dynamicweb.Rendering.Template.RenderRazorTemplate() in E:\A10\_w\2\s\src\Core\Dynamicweb.Core\Rendering\Template.cs:line 749

1 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2 @using Dynamicweb 3 4 @{ 5 bool anonymousUser = Pageview.User == null; 6 string iconPath = "/Files/Images/Icons/"; 7 int currentUserId = Dynamicweb.Core.Converter.ToInt32(GetGlobalValue("Global:Extranet.UserID")); 8 var shopPageId = GetPageIdByNavigationTag("Shop"); 9 var cart = Dynamicweb.Frontend.ContentViewModelFactory.CreateParagraphInfoViewModel(Pageview.CurrentParagraph)?.Item ?? null; 10 var checkoutAnonymousLink = cart?.GetLink("CheckoutAnonymousPageLink") is object ? cart.GetLink("CheckoutAnonymousPageLink").Url : string.Empty; 11 var checkoutSignedInLink = cart?.GetLink("CheckoutSignedInPageLink") is object ? cart.GetLink("CheckoutSignedInPageLink").Url : string.Empty; 12 string checkoutLink = currentUserId == 0 ? checkoutAnonymousLink : checkoutSignedInLink; 13 var quoteCheckoutLink = cart?.GetLink("QuoteCheckoutPageLink") is object ? cart.GetLink("QuoteCheckoutPageLink").Url : string.Empty; 14 bool isQuote = Dynamicweb.Ecommerce.Services.Orders.GetById(GetString("Ecom:Order.ID")).IsQuote; 15 var cartServicePageId = GetPageIdByNavigationTag("CartService"); 16 } 17 <div class="grid gap-0" id="Cart"> 18 <header class="g-col-12"> 19 <div class="pb-3 pb-lg-0 pt-3 pt-lg-5"> 20 <h1 class="h3 mb-2">@Translate("Shopping Cart")</h1> 21 <p class="mb-0"><span>@Translate("Items in your shopping cart"):</span> <span>@GetString("Ecom:Order.OrderLines.TotalProductQuantity")</span></p> 22 </div> 23 </header> 24 25 <div class="g-col-12 g-col-lg-8 pe-lg-5 pb-md-5"> 26 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 27 @using Dynamicweb.Ecommerce.Orders 28 29 @if (GetLoop("ValidationErrors").Count() != 0) 30 { 31 <div class="alert alert-warning" role="alert"> 32 <ul class="m-0 list-unstyled"> 33 @foreach (LoopItem item in GetLoop("ValidationErrors")) 34 { 35 <li>@item.GetValue("Ecom:Cart.ValidationError.ErrorMessage")</li> 36 } 37 </ul> 38 </div> 39 } 40 41 42 @* Logic to remove the voucher code error, when going to next step in checkout *@ 43 @{ 44 string voucherCodeForErrorCheck = GetString("Ecom:Order.Customer.VoucherCode"); 45 Order orderForErrorCheck = new OrderService().GetById(GetString("Ecom:Order.ID")); 46 voucherCodeForErrorCheck = orderForErrorCheck.VoucherUseType == VoucherUseCategoryType.None ? string.Empty : voucherCodeForErrorCheck; 47 } 48 49 <input type="hidden" name="EcomOrderVoucherCode" value="@voucherCodeForErrorCheck"> 50 51 52 <form name="ordersubmit" id="ordersubmit" method="post" autocomplete="off"> 53 <input type="hidden" name="cartcmd" value="updateorderlines" /> 54 <input type="hidden" name="redirect" value="false" /> 55 <input type="hidden" name="LayoutTemplate" value="Swift-v2_MiniCart.cshtml" /> 56 57 <header class="py-2 pt-lg-5 border-bottom d-none d-lg-block"> 58 <div class="grid" style="line-height: 1;"> 59 <div class="g-col-2">@Translate("Product")</div> 60 <div class="g-col-9 grid"> 61 <div class="g-col-10 g-col-md-6 g-start-8"></div> 62 <div class="g-col-2 g-col-md-3 g-start-8">@Translate("Quantity")</div> 63 </div> 64 <div class="g-col-1 text-end">@Translate("Total")</div> 65 </div> 66 </header> 67 <script> 68 gtag("event", "view_cart", { 69 currency: "@GetString("Ecom:Order.Currency.Code")", 70 value: @GetDouble("Ecom:Order.Price.PriceWithVAT.Value").ToString("0.00", System.Globalization.CultureInfo.InvariantCulture), 71 items: [ 72 @foreach (LoopItem orderline in GetLoop("OrderLines")) 73 { 74 <text> 75 { 76 item_id: "@orderline.GetString("Ecom:Order:OrderLine.ProductID")", 77 item_name: "@Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(orderline.GetString("Ecom:Order:OrderLine.ProductName"))", 78 currency: "@orderline.GetString("Ecom:Order:OrderLine.UnitPrice.CurrencyCode")", 79 price: @orderline.GetDouble("Ecom:Order:OrderLine.UnitPriceWithProductDiscount.Price.Value").ToString("0.00", System.Globalization.CultureInfo.InvariantCulture), 80 discount: @Math.Abs(orderline.GetDouble("Ecom:Order:OrderLine.UnitDiscount.Price.Value")).ToString("0.00", System.Globalization.CultureInfo.InvariantCulture), 81 quantity: @orderline.GetDouble("Ecom:Order:OrderLine.Quantity").ToString("0.00", System.Globalization.CultureInfo.InvariantCulture) 82 },</text> 83 } 84 ] 85 }); 86 </script> 87 88 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> @using Dynamicweb.Frontend @using Dynamicweb.Rendering @using System.Globalization @using System @functions{ string? DoubleToString(double? value) { if (value.HasValue) { return Math.Round(value.Value, 2).ToString(CultureInfo.InvariantCulture); } return null; } } @{ var orderlines = GetLoop("OrderLines"); } @for (int i = orderlines.Count - 1; i >= 0; i--) { var orderline = orderlines[i]; bool neverOutOfStock = orderline.GetBoolean("Ecom:Product.NeverOutOfStock"); string name = orderline.GetString("Ecom:Order:OrderLine.ProductName"); string primaryImage = orderline.GetString("Ecom:Product.PrimaryImage"); string image = $"/Admin/Public/GetImage.ashx?width=180&height=180&image={primaryImage}&format=webp"; string removeFromBasketLink = orderline.GetString("Ecom:Order:OrderLine.DeleteLink"); string priceTotalWithDiscounts = orderline.GetString("Ecom:Order:OrderLine.TotalPriceWithProductDiscounts.PriceFormatted"); string priceTotalWithDiscountsClean = orderline.GetString("Ecom:Order:OrderLine.TotalPriceWithProductDiscounts.Price"); string unitPrice = orderline.GetString("Ecom:Order:OrderLine.UnitPrice.PriceFormatted"); string unitPriceWithDiscount = orderline.GetDouble("Ecom:Order:OrderLine.UnitPriceWithProductDiscount.Price.Value").ToString("0.00", System.Globalization.CultureInfo.InvariantCulture); string discountAmount = Math.Abs(orderline.GetDouble("Ecom:Order:OrderLine.UnitDiscount.Price.Value")).ToString("0.00", System.Globalization.CultureInfo.InvariantCulture); string unitPriceCurrency = orderline.GetString("Ecom:Order:OrderLine.Price.CurrencyCode"); string discountPrice = orderline.GetString("Ecom:Order:OrderLine.UnitPriceWithProductDiscount.PriceFormatted"); string discountTotal = orderline.GetString("Ecom:Order:OrderLine.TotalDiscount.PriceFormatted"); string variantText = orderline.GetString("Ecom:Order:OrderLine.ProductVariantText"); var orderlineId = orderline.GetValue("Ecom:Order:OrderLine.Id"); double? stepQty = orderline.GetDouble("Ecom:Product.PurchaseQuantityStep") > 0 ? orderline.GetDouble("Ecom:Product.PurchaseQuantityStep") : 1; var quantity = orderline.GetDouble("Ecom:Order:OrderLine.Quantity"); var unitName = orderline.GetString("Ecom:Order:OrderLine.UnitName"); string primaryGroupId = orderline.GetString("Ecom:Order:OrderLine.PrimaryOrDefaultGroupId"); string productId = orderline.GetString("Ecom:Order:OrderLine.ProductID"); string variantId = orderline.GetString("Ecom:Order:OrderLine.ProductVariantID"); string unitId = orderline.GetString("Ecom:Order:OrderLine.UnitID"); string productType = orderline.GetString("Ecom.Product.Type"); double? stockQuantity = orderline.GetDouble("Ecom:Product.Stock"); double? minQty = orderline.GetDouble("Ecom:Product.PurchaseMinimumQuantity") > 0 ? orderline.GetDouble("Ecom:Product.PurchaseMinimumQuantity") : 1; bool isStockType = orderline.GetInteger("Ecom.Product.Type") == 0; bool setMaxQty = isStockType && !neverOutOfStock; double? maxQty = setMaxQty ? stockQuantity : null; string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop"); 89 link += $"&GroupID={System.Net.WebUtility.UrlEncode(primaryGroupId)}"; 90 link += $"&ProductID={System.Net.WebUtility.UrlEncode(productId)}"; 91 link += !string.IsNullOrEmpty(variantId) ? $"&VariantID={System.Net.WebUtility.UrlEncode(variantId)}" : ""; 92 93 bool isProductIdOrNumber = !string.IsNullOrEmpty(orderline.GetString("Ecom:Order:OrderLine.ProductID")) || !string.IsNullOrEmpty(orderline.GetString("Ecom:Order:OrderLine.ProductNumber")); //Live Cart orderlines may not return ProductId. Manually entered products may not have ProductNumber bool isProduct = orderline.GetBoolean("Ecom:Order:OrderLine.IsProduct") || (orderline.GetBoolean("Ecom:Order:OrderLine.IsDiscount") && isProductIdOrNumber); bool orderIsQuote = Dynamicweb.Ecommerce.Services.Orders.GetById(GetString("Ecom:Order.ID")).IsQuote; if (isProduct) { var bomItems = orderline.GetLoop("BOMItems"); <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="@unitPriceWithDiscount"> <div class="g-col-3 g-col-lg-2"> <a href="@link" class="ratio ratio-1x1 d-block" title="@name"> <img class="cart-item-img" src="@image" style="object-fit: contain;" alt="@name"> </a> </div> <div class="g-col-9 g-col-lg-10"> <div class="grid" style="row-gap: 0.5rem;--bs-gap:0;"> <div class="g-col-12 g-col-md-8 grid grid-7 grid-md-9" style="row-gap: 0.5rem;"> <div class="g-col-7 g-col-md-6"> @* Title *@ <h3 class="fs-7 fs-md-6 mb-0"> <a href="@link" class="text-decoration-none" title="@name">@name</a> </h3> @* Variants *@ @if (!string.IsNullOrEmpty(variantText)) { <p class="mt-2 mb-0 fs-7 fs-md-6">@variantText</p> } @if (orderline.GetBoolean("Ecom:Order:OrderLine.IsDiscount")) { @* Free product notice *@ <p class="mt-2 mb-0 fs-7 fs-md-6 opacity-75">@Translate("Free product")</p> } else { @* Unit price *@ <p class="fs-7 fs-md-6 mt-2 mb-0"> @if (!string.IsNullOrEmpty(unitName)) { <span>@unitName: </span> } @if (discountPrice == unitPrice) { <span class="text-price">@unitPrice</span> } else { <span class="text-price">@discountPrice</span> <span class="text-decoration-line-through fs-7"> <span class="text-price">@unitPrice</span> </span> } </p> } </div> <div class="g-col-7 g-col-md-3"> @if (!orderline.GetBoolean("Ecom:Order:OrderLine.IsDiscount") && !orderIsQuote) { @* Quantity *@ <div class="input-group js-input-group"> @{ var orderlineViewModel = new Dynamicweb.Ecommerce.Frontend.OrderLineViewModel(){ Id = orderlineId.ToString(), ProductId = productId, ProductVariantId = variantId, UnitId = unitId, Quantity = quantity }; } @RenderPartial("Components/QuantitySelectorOrderline.cshtml", orderlineViewModel) </div> } else { <div class="text-center" style="max-width: 140px;">@quantity</div> } </div> </div> <div class="g-col-12 g-col-md-4 text-end"> @* Total *@ <div class="fs-7 fs-md-6"> <span class="text-price">@priceTotalWithDiscounts</span> </div> @if (orderline.GetDouble("Ecom:Order:OrderLine.TotalDiscount.Price.Value") != 0) { <div class="fs-8"> <span class="text-price">@discountTotal</span> </div> } </div> <div class="g-col-12"> @if (!orderIsQuote) { string clickProductLink = "onclick=\"return removeProductLink('" + @productId + "', '" + @Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(name) + "', '" + @Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(variantText) + "', '" + @unitPriceCurrency + "', '" + @unitPriceWithDiscount + "', '" + @discountAmount + "', '" + @quantity.ToString().Replace(",", ".") + "')\""; <a href="@removeFromBasketLink" class="btn btn-link btn-sm p-0 m-0 fs-8" title="@Translate("Remove")" @clickProductLink>@Translate("Remove")</a> } <script> function removeProductLink(productId, productName, productVariant, productCurrency, productPrice, productDiscount, productQuantity) { if (typeof gtag !== "undefined") { gtag("event", "remove_from_cart", { currency: productCurrency, value: (parseFloat(productPrice) * parseFloat(productQuantity)), items: [ { item_id: productId, item_name: productName, item_variant: productVariant, currency: productCurrency, price: productPrice, discount: productDiscount, item_list_id: "cart", item_list_name: "Cart", quantity: productQuantity } ] }); } } </script> </div> </div> </div> @* Bottom border *@ <div class="g-col-12 mt-3"> <span class="d-none d-lg-block border-bottom"></span> </div> @if (bomItems.Count > 0) { <div class="g-col-12 mt-3"> @* BOM items *@ @foreach (var bomItem in bomItems) { string bomImage = bomItem.GetString("Ecom:Product.PrimaryImage"); bomImage = !bomImage.StartsWith("/Files/", StringComparison.OrdinalIgnoreCase) ? bomImage : $"/Admin/Public/GetImage.ashx?width=200&height=200&image={bomImage}&format=webp"; string bomPriceTotalWithDiscounts = bomItem.GetString("Ecom:Order:OrderLine.TotalPriceWithProductDiscounts.PriceFormatted"); string bomDiscountTotal = bomItem.GetString("Ecom:Order:OrderLine.TotalDiscount.PriceFormatted"); var bomVariantName = string.Join(" ", bomItem.GetLoop("VariantGroups") .SelectMany(g => g.GetLoop("VariantOptions")) .Where(o => o.GetBoolean("Ecom:VariantOption.Selected")) .Select(o => $"<span>{o.GetString("Ecom:VariantOption.Name")} </span>")); <div class="grid"> <div class="g-col-3 g-col-lg-2 d-flex align-items-center gap-2"> <div class="icon-2 p-0 p-lg-3 opacity-25"> @ReadFile("/Files/Images/Icons/arrow-turn-down-right.svg") </div> @if (!string.IsNullOrEmpty(bomImage)) { <div class="ratio ratio-1x1 d-block" title="@name"> <img class="cart-item-img" src="@bomImage" style="object-fit: contain;" alt="@name"> </div> } </div> <div class="g-col-9 g-col-lg-10 grid" style="row-gap: 0.5rem; --bs-gap:0;"> <div class="g-col-12 g-col-md-8 grid grid-7 grid-md-9"> <div class="g-col-7 g-col-md-6"> <h3 class="fs-7 fs-md-6 m-0">@bomItem.GetString("Ecom:Product.Name") </h3> <div class="fs-7 fs-md-6">@bomVariantName</div> </div> <div class="g-col-7 g-col-md-3"> <p class="fs-7 fs-md-6 mb-0 text-center" style="max-width: 140px;">@bomItem.GetDouble("Ecom:Order:OrderLine.Quantity")</p> </div> </div> <div class="g-col-12 g-col-md-4 text-end"> @* Total - Hide when PriceType = Fixed *@ @if (orderline.GetInteger("Ecom:Product.PriceType") != 1) { <div class="fs-7 fs-md-6"> <span class="text-price">@bomPriceTotalWithDiscounts</span> </div> if (bomItem.GetDouble("Ecom:Order:OrderLine.TotalDiscount.Price.Value") != 0) { <div class="fs-8"> <span class="text-price">@bomDiscountTotal</span> </div> } } </div> </div> </div> @* Bottom border *@ <div class="w-100 my-3"> <span class="d-none d-lg-block border-bottom"></span> </div> } </div> } </article> } } 94 95 @if(Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Desktop) 96 { 97 <text>@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 98 @using Dynamicweb.Ecommerce.Orders 99 100 @* Red lines may be due to variables defined in the parent tempalte - There is no actual error *@ 101 102 @{ 103 104 <div class="align-items-center d-grid d-lg-flex gap-2 justify-content-lg-end mt-lg-4"> 105 106 <a href="Default.aspx?ID=@shopPageId" class="btn btn-link text-decoration-none me-lg-3 order-last order-lg-first swift_cartbackbutton" data-dw-button="link"> 107 <span class="d-flex align-items-center justify-content-center position-relative"> 108 <span class="icon-2 me-1 position-absolute position-lg-static start-0"> 109 @ReadFile(iconPath + "chevron-left.svg") 110 </span> 111 <span>@Translate("Continue shopping")</span> 112 </span> 113 </a> 114 115 @if (!anonymousUser && isQuote) 116 { 117 <a href="@($"{Context.Current.Request.Url}&cartcmd=emptycart")" class="btn btn-secondary" data-dw-button="secondary"> 118 <span class="d-flex align-items-center justify-content-center position-relative"> 119 <span>@Translate("Clear Cart")</span> 120 <span class="icon-2 ms-1 position-absolute position-lg-static end-0"> 121 @ReadFile(iconPath + "trash-can.svg") 122 </span> 123 </span> 124 </a> 125 } 126 127 @if (!string.IsNullOrEmpty(quoteCheckoutLink) && !anonymousUser && !isQuote) 128 { 129 <a href="@quoteCheckoutLink" class="btn btn-secondary" data-dw-button="secondary"> 130 <span class="d-flex align-items-center justify-content-center position-relative"> 131 <span>@Translate("Request quote")</span> 132 <span class="icon-2 ms-1 position-absolute position-lg-static end-0"> 133 @ReadFile(iconPath + "chevron-right.svg") 134 </span> 135 </span> 136 </a> 137 } 138 139 <a href="@checkoutLink" class="btn btn-primary" data-dw-button="primary" id="GoToCheckoutButton"> 140 <span class="d-flex align-items-center justify-content-center position-relative"> 141 <span>@Translate("Checkout")</span> 142 <span class="icon-2 ms-1 position-absolute position-lg-static end-0"> 143 @ReadFile(iconPath + "chevron-right.svg") 144 </span> 145 </span> 146 </a> 147 148 </div> 149 } 150 </text> 151 } 152 153 </form> 154 </div> 155 156 <aside class="g-col-12 g-col-lg-4 position-relative"> 157 <div class="p-3 p-lg-5 pb-lg-4 sticky-top z-1" data-dw-colorscheme="@Pageview.CurrentParagraph?.ColorSchemeId"> 158 <header> 159 <h4 class="fs-6 fw-normal mb-2">@Translate("Order summary")</h4> 160 </header> 161 162 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 163 164 @{ 165 double totalPriceWithoutOrderDiscountsFeesAndTaxesValue = 166 GetDouble("Ecom:Order.TotalPriceWithoutDiscountsFeesAndTaxes.Price.Value") + 167 GetDouble("Ecom:Order.TotalProductDiscount.Price.Value"); 168 var orderCurrency = Dynamicweb.Ecommerce.Services.Currencies.GetCurrency(GetString("Ecom:Order.Currency.Code")); 169 string totalPriceWithoutOrderDiscountsFeesAndTaxes = Dynamicweb.Ecommerce.Services.Currencies.Format(orderCurrency, 170 totalPriceWithoutOrderDiscountsFeesAndTaxesValue); 171 172 bool showPricesWithVat = Dynamicweb.Ecommerce.Common.Context.DisplayPricesWithVat; 173 bool renderVatMessage = (GetString("Ecom:Order.OrderLines.Total.PriceWithVAT") != GetString("Ecom:Order.OrderLines.Total.PriceWithoutVAT")) || Dynamicweb.Ecommerce.Common.Context.Country?.Vat != null; 174 175 bool disableVouchers = Pageview.CurrentParagraph?.Item["DisableVouchers"] != null ? 176 (Boolean)Pageview.CurrentParagraph.Item["DisableVouchers"] : false; 177 disableVouchers = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("CompletedOrderId")) ? true : 178 disableVouchers; 179 180 <div class="d-flex flex-column gap-2 gap-lg-3 pb-3 bottom-0 sticky-receipt" id="orderSummaryFooter"> 181 182 @if (!disableVouchers && Pageview.CurrentParagraph?.Item.SystemName != "Swift-v2_QuoteCheckoutApp") 183 { 184 <text> 185 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 186 @using Dynamicweb.Ecommerce.Orders 187 188 @{ 189 string voucherCode = GetString("Ecom:Order.Customer.VoucherCode"); 190 string voucherCodeError = GetString("Ecom:Cart.ValidationError.EcomOrderVoucherCode.ErrorMessage"); 191 string validState = string.Empty; 192 bool vouchersAppliedAsDiscounts = false; 193 194 IEnumerable<string> voucherCodes = new List<string>(); 195 Order order = new OrderService().GetById(GetString("Ecom:Order.ID")); 196 197 if (!string.IsNullOrWhiteSpace(voucherCode)) 198 { 199 if (order.VoucherUseType.HasFlag(VoucherUseCategoryType.Discount)) 200 { 201 voucherCodes = voucherCode.Split(new string[] { ",", ";", " " }, StringSplitOptions.RemoveEmptyEntries); 202 vouchersAppliedAsDiscounts = true; 203 } 204 else 205 { 206 voucherCodes = new string[] { voucherCode.Trim() }; 207 } 208 } 209 210 var voucherErrors = new List<string>(); 211 if(!vouchersAppliedAsDiscounts) 212 { 213 foreach (string code in voucherCodes) 214 { 215 Dynamicweb.Ecommerce.Orders.Vouchers.Voucher vouch = Dynamicweb.Ecommerce.Services.Vouchers.GetVoucherByCode(code); 216 if (vouch == null) 217 { 218 validState = "is-invalid"; 219 voucherErrors.Add(Translate("Voucher") + " <span class='fw-bold'>" + code + "</span> " + Translate("not found")); 220 continue; 221 } 222 if (vouch.DateUsed.HasValue) 223 { 224 validState = "is-invalid"; 225 voucherErrors.Add(Translate("Voucher") + " <span class='fw-bold'>" + code + "</span> " + Translate("already used")); 226 continue; 227 } 228 } 229 } 230 231 var voucherErrorMessage = string.Join(",", voucherErrors); 232 233 <div class="py-3 border-top" id="orderVoucherForm"> 234 <form method="post" id="VoucherForm"> 235 <div class="input-group input-primary-button-group has-validation"> 236 <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;"> 237 <button class="btn btn-sm btn-primary d-inline-flex align-items-center justify-content-center" data-dw-button="primary" type="submit" id="EcomOrderVoucherApply" style="min-width: 100px;"> 238 <span>@Translate("Apply")</span> 239 </button> 240 241 <div class="invalid-feedback"> 242 @voucherErrorMessage 243 </div> 244 </div> 245 <input type="hidden" name="EcomOrderVoucherCode" id="EcomOrderVoucherCode" value="@voucherCode"> 246 <label for="EcomOrderVoucherCodeField" class="visually-hidden">@Translate("Add voucher here")</label> 247 </form> 248 249 @if (!string.IsNullOrWhiteSpace(voucherCode)) 250 { 251 <div class="d-flex flex-wrap gap-2 pt-3"> 252 253 @foreach (string code in voucherCodes) 254 { 255 <form method="post"> 256 <input type="hidden" name="EcomOrderVoucherCode" value="@voucherCode.Replace(code+",", "").Replace(","+code, "").Replace(code, "")"> 257 <span class="badge fw-normal d-inline-flex align-items-center justify-content-center opacity-50 opacity-100-hover" style="background-color:var(--dw-color-foreground);color:var(--dw-color-background);"> 258 <button type="submit" class="text-reset bg-transparent border-0 p-0" aria-label="@Translate("Remove voucher")" id="RemoveVoucherButton"> 259 <span class="icon-2"> 260 @ReadFile("/Files/Images/Icons/xmark.svg") 261 </span> 262 <span class="mx-2">@code</span> 263 </span> 264 </form> 265 } 266 </div> 267 } 268 @voucherCodeError 269 </div> 270 } 271 272 </text> 273 } 274 275 <div class="fs-8 border-top pt-2 pt-lg-3"> 276 @* Subtotal *@ 277 <div class="d-flex justify-content-between fw-bold"> 278 <span>@Translate("Subtotal")</span> 279 <span class="text-end"> 280 <span class="d-block"> 281 @if (GetDouble("Ecom:Order.TotalPriceWithoutDiscountsFeesAndTaxes.Price.Value") != 282 totalPriceWithoutOrderDiscountsFeesAndTaxesValue) 283 { 284 <span 285 class="text-price fw-normal text-decoration-line-through">@GetString("Ecom:Order.TotalPriceWithoutDiscountsFeesAndTaxes.PriceFormatted")</span> 286 } 287 <span class="text-price">@totalPriceWithoutOrderDiscountsFeesAndTaxes</span> 288 </span> 289 290 @if (renderVatMessage && !showPricesWithVat) 291 { 292 <span class="fs-8 fw-normal d-block">@Translate("Excl. VAT")</span> 293 } 294 else if (renderVatMessage) 295 { 296 <span class="fs-8 fw-normal d-block">@Translate("Incl. VAT")</span> 297 } 298 </span> 299 </div> 300 301 @* Discounts (only order discounts) *@ 302 @foreach (LoopItem orderline in GetLoop("OrderLines")) 303 { 304 bool isDiscount = orderline.GetBoolean("Ecom:Order:OrderLine.IsDiscount"); 305 bool isProductIdOrNumber = !string.IsNullOrEmpty(orderline.GetString("Ecom:Order:OrderLine.ProductID")) || 306 !string.IsNullOrEmpty(orderline.GetString("Ecom:Order:OrderLine.ProductNumber")); //Live Cart orderlines may not 307 bool isOrderAmountDiscount = orderline.GetInteger("Ecom:Order:OrderLine.Type") == 1 && !isProductIdOrNumber; 308 if (isDiscount && isOrderAmountDiscount) 309 { 310 <div class="d-flex justify-content-between"> 311 <span>@orderline.GetString("Ecom:Order:OrderLine.ProductName")</span><span 312 class="text-price">@orderline.GetString("Ecom:Order:OrderLine.TotalPriceWithProductDiscounts.PriceFormatted")</span> 313 </div> 314 } 315 } 316 317 @* Delivery *@ 318 @if (!string.IsNullOrEmpty(GetString("Ecom:Order.ShippingMethodID"))) 319 { 320 if (GetDouble("Ecom:Order.ShippingFee.Price.Value") != 0.0) 321 { 322 <div class="d-flex justify-content-between"> 323 <span>@Translate("Delivery")</span> 324 <span>@GetString("Ecom:Order.ShippingFee.PriceFormatted")</span> 325 </div> 326 } 327 } 328 else 329 { 330 <div class="d-flex justify-content-between"> 331 <span>@Translate("Delivery")</span> 332 <span>@Translate("Calculated in next step")</span> 333 </div> 334 } 335 336 @* Payment *@ 337 @if (!string.IsNullOrEmpty(GetString("Ecom:Order.PaymentMethodID"))) 338 { 339 if (GetDouble("Ecom:Order.PaymentFee.Price.Value") != 0) 340 { 341 <div class="d-flex justify-content-between"> 342 <span>@Translate("Payment")</span> 343 <span class="text-price">@GetString("Ecom:Order.PaymentFee.PriceFormatted")</span> 344 </div> 345 } 346 } 347 else 348 { 349 <div class="d-flex justify-content-between"> 350 <span>@Translate("Payment")</span> 351 <span>@Translate("Calculated in next step")</span> 352 </div> 353 } 354 355 @* Taxes *@ 356 @if (GetDouble("Ecom:Order.Taxes.Total.Price.Value") != 0) 357 { 358 <div class="d-flex justify-content-between mb-2"> 359 <span>@Translate("Sales tax")</span> 360 <span>@GetString("Ecom:Order.Taxes.Total.PriceFormatted")</span> 361 </div> 362 } 363 </div> 364 <div class="fs-8 border-top pt-2 pt-lg-3"> 365 <div class="d-flex justify-content-between fs-6 fw-bold"> 366 <span>@Translate("Total")</span> 367 @if (renderVatMessage && !showPricesWithVat) 368 { 369 <span class="text-price text-end"> 370 <span class="fs-5 d-block">@GetString("Ecom:Order.Price.PriceFormatted")</span> 371 <span class="fs-8 fw-normal d-block">@Translate("Excl. VAT")</span> 372 </span> 373 } 374 else if (renderVatMessage) 375 { 376 <span class="text-price text-end"> 377 <span class="fs-5 d-block">@GetString("Ecom:Order.Price.PriceFormatted")</span> 378 <span class="fs-8 fw-normal d-block">@Translate("Incl. VAT")</span> 379 </span> 380 } 381 else 382 { 383 <span class="text-price fs-5">@GetString("Ecom:Order.Price.PriceFormatted")</span> 384 } 385 </div> 386 387 @if (renderVatMessage) 388 { 389 <div class="d-flex justify-content-between"><span>@Translate("VAT")</span><span 390 class="text-price">@GetString("Ecom:Order.Price.VATFormatted")</span></div> 391 if (!showPricesWithVat) 392 { 393 <div class="d-flex justify-content-between"><span>@Translate("Total incl. VAT")</span><span 394 class="text-price">@GetString("Ecom:Order.OrderLines.Total.PriceWithVAT")</span></div> 395 } 396 } 397 398 @if (GetDouble("Ecom:Order.TotalDiscount.Price.Value") != 0) 399 { 400 <div class="d-flex justify-content-between"><span>@Translate("Discount")</span><span 401 class="text-price">@GetString("Ecom:Order.TotalDiscount.PriceFormatted")</span></div> 402 } 403 </div> 404 </div> 405 } 406 407 408 @if(Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet) 409 { 410 <text>@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 411 @using Dynamicweb.Ecommerce.Orders 412 413 @* Red lines may be due to variables defined in the parent tempalte - There is no actual error *@ 414 415 @{ 416 417 <div class="align-items-center d-grid d-lg-flex gap-2 justify-content-lg-end mt-lg-4"> 418 419 <a href="Default.aspx?ID=@shopPageId" class="btn btn-link text-decoration-none me-lg-3 order-last order-lg-first swift_cartbackbutton" data-dw-button="link"> 420 <span class="d-flex align-items-center justify-content-center position-relative"> 421 <span class="icon-2 me-1 position-absolute position-lg-static start-0"> 422 @ReadFile(iconPath + "chevron-left.svg") 423 </span> 424 <span>@Translate("Continue shopping")</span> 425 </span> 426 </a> 427 428 @if (!anonymousUser && isQuote) 429 { 430 <a href="@($"{Context.Current.Request.Url}&cartcmd=emptycart")" class="btn btn-secondary" data-dw-button="secondary"> 431 <span class="d-flex align-items-center justify-content-center position-relative"> 432 <span>@Translate("Clear Cart")</span> 433 <span class="icon-2 ms-1 position-absolute position-lg-static end-0"> 434 @ReadFile(iconPath + "trash-can.svg") 435 </span> 436 </span> 437 </a> 438 } 439 440 @if (!string.IsNullOrEmpty(quoteCheckoutLink) && !anonymousUser && !isQuote) 441 { 442 <a href="@quoteCheckoutLink" class="btn btn-secondary" data-dw-button="secondary"> 443 <span class="d-flex align-items-center justify-content-center position-relative"> 444 <span>@Translate("Request quote")</span> 445 <span class="icon-2 ms-1 position-absolute position-lg-static end-0"> 446 @ReadFile(iconPath + "chevron-right.svg") 447 </span> 448 </span> 449 </a> 450 } 451 452 <a href="@checkoutLink" class="btn btn-primary" data-dw-button="primary" id="GoToCheckoutButton"> 453 <span class="d-flex align-items-center justify-content-center position-relative"> 454 <span>@Translate("Checkout")</span> 455 <span class="icon-2 ms-1 position-absolute position-lg-static end-0"> 456 @ReadFile(iconPath + "chevron-right.svg") 457 </span> 458 </span> 459 </a> 460 461 </div> 462 } 463 </text> 464 } 465 </div> 466 </aside> 467 468 <script> 469 document.addEventListener('updated.swift.cart', (event) => { 470 swift.PageUpdater.Update(document.querySelector("#ordersubmit"), true); 471 }); 472 </script> 473 </div> 474