Error executing template "Designs/Swift/Paragraph/Swift_ProductDetailsInfo.cshtml"
System.ArgumentOutOfRangeException: Index and length must refer to a location within the string.
Parameter name: length
   at System.String.Substring(Int32 startIndex, Int32 length)
   at CompiledRazorTemplates.Dynamic.RazorEngine_db64cd145ec046c0baa800401ef3e3ca.<>c__DisplayClass1_0.<RenderFieldValue>b__0(TextWriter __razor_helper_writer) in E:\Dynamicweb.NET\Solutions\swift.blomberg.espresso4.dk\Files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsInfo.cshtml:line 423
   at RazorEngine.Templating.TemplateWriter.ToString()
   at CompiledRazorTemplates.Dynamic.RazorEngine_db64cd145ec046c0baa800401ef3e3ca.<>c__DisplayClass0_0.<RenderField>b__0(TextWriter __razor_helper_writer) in E:\Dynamicweb.NET\Solutions\swift.blomberg.espresso4.dk\Files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsInfo.cshtml:line 373
   at CompiledRazorTemplates.Dynamic.RazorEngine_db64cd145ec046c0baa800401ef3e3ca.Execute() in E:\Dynamicweb.NET\Solutions\swift.blomberg.espresso4.dk\Files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsInfo.cshtml:line 243
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, 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 Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites 4 @using Dynamicweb.Ecommerce.Products.FieldDisplayGroups 5 @using Dynamicweb.Frontend 6 7 @{ 8 ProductViewModel product = new ProductViewModel(); 9 10 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 11 { 12 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 13 } 14 15 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 16 bool anonymousUser = Pageview.User == null; 17 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser; 18 hideAddToCart = product.VariantInfo.VariantInfo != null && Model.Item.GetBoolean("HideVariantSelector") ? true : hideAddToCart; 19 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser; 20 bool hideFavoritesSelector = !string.IsNullOrEmpty(Model.Item.GetString("HideFavoritesSelector")) ? Model.Item.GetBoolean("HideFavoritesSelector") : false; 21 22 bool IsNeverOutOfStock = product.NeverOutOfstock; 23 string[] variantId = product.VariantId.Split('.'); 24 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : ""; 25 if (IsNeverOutOfStock) 26 { 27 disableAddToCart = ""; 28 } 29 30 // Does product has a expected delivery data 31 bool hasExpectedDelivery = product.ExpectedDelivery != null && product.ExpectedDelivery > DateTime.Now; 32 string expectedDeliveryDate = product.ExpectedDelivery?.ToShortDateString() ?? ""; 33 34 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 35 if (!url.Contains("LayoutTemplate")) 36 { 37 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml"; 38 } 39 40 IEnumerable<string> selectedDisplayGroups = Model.Item.GetRawValueString("MainFeatures").Split(',').ToList(); 41 List<CategoryFieldViewModel> mainFeatures = new List<CategoryFieldViewModel>(); 42 43 foreach (var selection in selectedDisplayGroups) 44 { 45 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 46 { 47 if (selection == group.Id) 48 { 49 mainFeatures.Add(group); 50 } 51 } 52 } 53 54 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 55 56 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-6"); 57 58 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 59 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding; 60 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding; 61 62 string quantityPricesLayout = Model.Item.GetRawValueString("QuantityPricesLayout", "list"); 63 64 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\""; 65 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1"; 66 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty; 67 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : ""; 68 69 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 70 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 71 72 string priceMin = ""; 73 string priceMax = ""; 74 75 var favoriteParameters = new Dictionary<string, object>(); 76 if (!anonymousUser && !hideFavoritesSelector) 77 { 78 IEnumerable<FavoriteList> favoreiteLists = Pageview.User.GetFavoriteLists(); 79 int defaultFavoriteListId = 0; 80 81 if (favoreiteLists.Count() == 1) { 82 foreach (FavoriteList list in favoreiteLists) { 83 defaultFavoriteListId = list.ListId; 84 } 85 } 86 87 favoriteParameters.Add("ListId", defaultFavoriteListId); 88 } 89 90 var badgeParms = new Dictionary<string, object>(); 91 badgeParms.Add("size", "h7"); 92 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 93 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 94 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 95 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 96 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 97 98 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 99 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 100 DateTime createdDate = product.Created.Value; 101 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 102 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 103 showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; 104 } 105 106 <div class="h-100 @(contentPadding) @(theme)"> 107 <div class="d-flex flex-column gap-4 js-product"> 108 @if (showBadges) { 109 <div> 110 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 111 </div> 112 } 113 114 <div> 115 <h1 class="@titleFontSize" itemprop="name">@product.Name</h1> 116 @if (!Model.Item.GetBoolean("HideProductNumber")) 117 { 118 <div class="opacity-85">@product.Number</div> 119 } 120 </div> 121 122 @if (!hidePrice && false) 123 { 124 <div> 125 <div class="h4" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 126 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span> 127 128 @if (showPricesWithVat == "false" && !neverShowVat) 129 { 130 string beforePrice = product.PriceBeforeDiscount.PriceWithoutVatFormatted; 131 132 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 133 if (product.Price.Price != product.PriceBeforeDiscount.Price) 134 { 135 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 136 } 137 } 138 else 139 { 140 string beforePrice = product.PriceBeforeDiscount.PriceFormatted; 141 142 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 143 if (product.Price.Price != product.PriceBeforeDiscount.Price) 144 { 145 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 146 } 147 } 148 149 @if (showPricesWithVat == "false" && !neverShowVat) 150 { 151 string price = product.Price.PriceWithoutVatFormatted; 152 if (product?.VariantInfo?.VariantInfo != null) 153 { 154 priceMin = product?.VariantInfo?.PriceMin?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithoutVatFormatted : ""; 155 priceMax = product?.VariantInfo?.PriceMax?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithoutVatFormatted : ""; 156 } 157 if (priceMin != priceMax) 158 { 159 price = priceMin + " - " + priceMax; 160 } 161 <span class="text-price">@price</span> 162 } 163 else 164 { 165 string price = product.Price.PriceFormatted; 166 if (product?.VariantInfo?.VariantInfo != null) 167 { 168 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 169 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 170 } 171 if (priceMin != priceMax) 172 { 173 price = priceMin + " - " + priceMax; 174 } 175 <span class="text-price">@price</span> 176 } 177 </div> 178 @if (showPricesWithVat == "false" && !neverShowVat) 179 { 180 string price = product.Price.PriceWithVatFormatted; 181 if (product?.VariantInfo?.VariantInfo != null) 182 { 183 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 184 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 185 } 186 if (priceMin != priceMax) 187 { 188 price = priceMin + " - " + priceMax; 189 } 190 <small class="opacity-85 fst-normal">@price @Translate("Incl. VAT")</small> 191 } 192 193 @if (product.Prices.Count > 0) { 194 if (quantityPricesLayout == "list") { 195 <div class="mt-3"> 196 @foreach (PriceListViewModel quantityPrice in product.Prices) 197 { 198 string quantityLabel = Translate("PCS"); 199 string quantityPriceSuffix = quantityPrice.Quantity > 1 ? Translate("pr. PCS") : ""; 200 201 <small class="d-block opacity-75"><span>@quantityPrice.Quantity @quantityLabel</span> - <span class="fw-bold">@quantityPrice.Price.PriceFormatted @quantityPriceSuffix</span></small> 202 } 203 </div> 204 } else if (quantityPricesLayout == "table") { 205 <div class="grid"> 206 <table class="table table-sm mt-3 g-col-12 g-col-lg-6"> 207 <thead> 208 <tr> 209 <td>@Translate("QTY")</td> 210 <td>@Translate("pr. PCS")</td> 211 </tr> 212 </thead> 213 <tbody> 214 @foreach (PriceListViewModel quantityPrice in product.Prices) 215 { 216 <tr> 217 <td>@quantityPrice.Quantity</td> 218 <td>@quantityPrice.Price.PriceFormatted</td> 219 </tr> 220 } 221 </tbody> 222 </table> 223 </div> 224 } 225 } 226 </div> 227 } 228 229 @if (!string.IsNullOrEmpty(product.ShortDescription)) 230 { 231 <div class="mb-0-last-child" itemprop="disambiguatingDescription"> 232 @product.ShortDescription 233 </div> 234 } 235 236 @if (mainFeatures.Count > 0) 237 { 238 foreach (CategoryFieldViewModel mainFeatureGroup in mainFeatures) 239 { 240 <dl class="grid gap-0"> 241 @foreach (var field in mainFeatureGroup.Fields) 242 { 243 @RenderField(field.Value) 244 } 245 </dl> 246 } 247 } 248 249 @if (product.VariantInfo.VariantInfo != null && !Model.Item.GetBoolean("HideVariantSelector")) 250 { 251 int groupNumber = 1; 252 253 <form class="mb-3 js-variant-selector" data-combinations="@string.Join(",", product.VariantCombinations())"> 254 <input type="hidden" name="variantid" /> 255 256 @foreach (var variantGroup in product.VariantGroups()) 257 { 258 VariantGroupViewModel group = variantGroup; 259 260 <h3 class="h6">@group.Name</h3> 261 <div class="mb-3 js-variant-group" data-group-id="@groupNumber"> 262 @foreach (var option in group.Options) 263 { 264 string active = variantId.Contains(option.Id) ? "active" : ""; 265 266 if (!string.IsNullOrEmpty(option.Color)) 267 { 268 <button type="button" class="btn colorbox rounded-circle me-1 mb-2 d-inline-block variant-option js-variant-option @active" style="background-color: @option.Color" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"></button> 269 } 270 else if (!string.IsNullOrEmpty(option.Color) && !string.IsNullOrEmpty(option.Image.Value)) 271 { 272 <button type="button" class="btn p-0 d-inline-block mb-2 variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 273 <img src="/Admin/Public/GetImage.ashx?image=@(option.Image.Value)&width=42&Format=WebP&Quality=70" /> 274 </button> 275 } 276 else 277 { 278 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 279 @option.Name 280 </button> 281 } 282 } 283 </div> 284 285 groupNumber++; 286 } 287 </form> 288 } 289 290 <div class="d-flex flex-row flex-nowrap gap-2"> 291 @if (!hideAddToCart && false) 292 { 293 <form method="post" action="@url" class="flex-fill"> 294 <input type="hidden" name="redirect" value="false" /> 295 <input type="hidden" name="ProductId" value="@product.Id" /> 296 <input type="hidden" name="cartcmd" value="add" /> 297 298 @if (!string.IsNullOrEmpty(product.VariantId)) 299 { 300 <input type="hidden" name="VariantId" value="@product.VariantId" /> 301 } 302 @if (!Model.Item.GetBoolean("QuantitySelector")) 303 { 304 <input id="Quantity_@product.Id" name="Quantity" value="@valueQty" type="hidden"> 305 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary w-100 js-add-to-cart-button @disableAddToCart" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)">@Translate("Add to cart")</button> 306 } else { 307 <div class="input-group input-primary-button-group js-input-group d-flex flex-row flex-nowrap"> 308 <label for="Quantity_@(product.Id)" class="visually-hidden">@Translate("Quantity")</label> 309 <input id="Quantity_@product.Id" name="Quantity" value="@valueQty" step="@stepQty" @minQty class="form-control" style="max-width: 96px; min-width:64px;" type="number"> 310 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)">@Translate("Add to cart")</button> 311 </div> 312 313 if (stepQty != "1") 314 { 315 <div class="invalid-feedback d-none"> 316 @Translate("Please select a quantity that is dividable by") @stepQty 317 </div> 318 } 319 } 320 </form> 321 if (!anonymousUser && !hideFavoritesSelector) 322 { 323 @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 324 } 325 } 326 else if (!anonymousUser && !hideFavoritesSelector) 327 { 328 <div class="flex-fill"> 329 @Translate("Add to favorites") @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 330 </div> 331 } 332 </div> 333 </div> 334 @if (!Model.Item.GetBoolean("HideStockState")) 335 { 336 if (!IsNeverOutOfStock) 337 { 338 <div class="mt-3 js-stock-state"> 339 340 @if (product.StockLevel > 0) 341 { 342 if (!Model.Item.GetBoolean("HideInventory")) 343 { 344 <p class="small text-success m-0">@product.StockLevel @Translate("Products available in stock")</p> 345 } 346 else 347 { 348 <p class="small text-success m-0">@Translate("Available in stock")</p> 349 } 350 } 351 352 else 353 { 354 <p class="small text-danger m-0">@Translate("Out of Stock")</p> 355 } 356 357 @if (hasExpectedDelivery) 358 { 359 <p> 360 <span>@Translate("Expected back in stock:")</span> 361 <span>@expectedDeliveryDate</span> 362 </p> 363 } 364 365 </div> 366 } 367 } 368 </div> 369 370 @helper RenderField(FieldValueViewModel field) 371 { 372 string fieldValue = field?.Value != null ? field.Value.ToString() : "", 373 energyLabel = RenderFieldValue(field).ToString().ToLower(), 374 iconSrc = "/admin/public/getimage.ashx?Image=/Files/Images/energylabels/", 375 iconOption = "&Resolution=72&Compression=90&Width=100", 376 energyClass = iconSrc + energyLabel.Replace(" ", "_") + ".png" + iconOption, 377 energyClassDisc = iconSrc + "grade_" + energyLabel.Replace(" ", "_") + ".png" + iconOption; 378 379 bool noValues = false; 380 381 if (!string.IsNullOrEmpty(fieldValue)) 382 { 383 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 384 { 385 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 386 noValues = values.Count > 0 ? false : true; 387 } 388 } 389 390 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 391 { 392 <dt class="g-col-12 g-col-sm-4 g-col-lg-12 fw-bold m-0">@field.Name</dt> 393 <dd class="g-col-12 g-col-sm-8 g-col-lg-12 mb-3" data-type="@field.Type"> 394 @if ( energyClass.Contains( "_class" ) && field.Type != "EditorText") { 395 <img src="@energyClass" alt="@energyLabel" title="@energyLabel" /> 396 } else if ( energyClassDisc.Contains( "_disc" ) && field.Type != "EditorText") { 397 <img src="@energyClassDisc" alt="@energyLabel" title="@energyLabel" /> 398 } 399 else { 400 @RenderFieldValue(field) 401 } 402 </dd> 403 } 404 } 405 406 @helper RenderFieldValue(FieldValueViewModel field) 407 { 408 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 409 410 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 411 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 412 413 bool isColor = false; 414 415 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 416 { 417 int valueCount = 0; 418 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 419 int totalValues = values.Count; 420 421 foreach (FieldOptionValueViewModel option in values) 422 { 423 if (option.Value.Substring(0, 1) == "#") 424 { 425 isColor = true; 426 } 427 428 if (!isColor) 429 { 430 @option.Name 431 } 432 else 433 { 434 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span> 435 } 436 437 if (valueCount != totalValues && valueCount < (totalValues - 1)) 438 { 439 if (isColor) 440 { 441 <text> </text> 442 } 443 else 444 { 445 <text>, </text> 446 } 447 } 448 valueCount++; 449 } 450 } 451 else 452 { 453 if (fieldValue.Substring(0, 1) == "#") 454 { 455 isColor = true; 456 } 457 458 if (!isColor) 459 { 460 @fieldValue 461 } 462 else 463 { 464 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 465 } 466 } 467 } 468 469 @if (product.VariantInfo.VariantInfo != null) 470 { 471 <script type="module"> 472 swift.VariantSelector.init(); 473 </script> 474 } 475 476 477
Ved at klikke 'Acceptér Alle' så giver til tiladelse til at vi må indsamle information om dig til forskellige formål, hvilket inkluderer: Funktionalitet, Statestik og Marketing