Error executing template "/Designs/Swift/Paragraph/Swift_ProductDetailsInfo_Custom.cshtml"
System.Exception: Product id is requred to find a product.
   at Dynamicweb.Core.Ensure.That[TException](Boolean condition, String message)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewModelFactory.CreateView(ProductViewModelSettings settings, String productId, String variantId, String groupId)
   at Dynamicweb.Ecommerce.ProductCatalog.ProductInfoViewModelExtensions.GetProduct(ProductInfoViewModel productInfo)
   at CompiledRazorTemplates.Dynamic.RazorEngine_776b9197f12542d7ba54831bd9dcd930.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\Jkoffice.cloud.dynamicweb-cms.com\Files\Templates\\Designs\Swift\Paragraph\Swift_ProductDetailsInfo_Custom.cshtml:line 515
   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 System.IO 5 @using Dynamicweb.Core 6 @using Dynamicweb.Environment 7 8 @{ 9 var getProductViewModelHelper = new CustomCode.ProductSelector.GetProductViewModelHelper(); 10 ProductViewModel product = getProductViewModelHelper.ProductViewModel; 11 12 string googleAnalyticsTrackingID = Pageview.AreaSettings.GetString("GoogleAnalyticsTrackingID"); 13 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID"); 14 var cookieOptInLevel = CookieManager.GetCookieOptInLevel(); 15 bool allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical")); 16 17 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 18 bool anonymousUser = Pageview.User == null; 19 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser; 20 hideAddToCart = product.VariantInfo.VariantInfo != null && Model.Item.GetBoolean("HideVariantSelector") ? true : hideAddToCart; 21 hideAddToCart = Model.Item.GetBoolean("HideAddToCartButton") ? true : hideAddToCart; 22 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser; 23 if (Model.Item.GetBoolean("HidePrice")) 24 { 25 hidePrice = true; 26 } 27 bool hideFavoritesSelector = !string.IsNullOrEmpty(Model.Item.GetString("HideFavoritesSelector")) ? Model.Item.GetBoolean("HideFavoritesSelector") : false; 28 bool hideProductData = Model.Item.GetBoolean("Hide_Product_Data"); 29 30 bool IsNeverOutOfStock = product.NeverOutOfstock; 31 bool isDiscontinued = product.Discontinued; 32 33 string[] variantId = product.VariantId.Split('.'); 34 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : ""; 35 if (IsNeverOutOfStock) 36 { 37 disableAddToCart = ""; 38 } 39 40 bool isAnonymousB2BUser = System.Web.HttpContext.Current.Request.Cookies["userType"] != null ? System.Web.HttpContext.Current.Request.Cookies["userType"].Value == "B2B" : false; 41 42 43 // Does product has a expected delivery data 44 bool hasExpectedDelivery = product.ExpectedDelivery != null && product.ExpectedDelivery > DateTime.Now; 45 string expectedDeliveryDate = product.ExpectedDelivery?.ToShortDateString() ?? ""; 46 47 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 48 if (!url.Contains("LayoutTemplate")) 49 { 50 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml"; 51 } 52 53 IEnumerable<string> selectedDisplayGroups = Model.Item.GetRawValueString("MainFeatures").Split(',').ToList(); 54 List<CategoryFieldViewModel> mainFeatures = new List<CategoryFieldViewModel>(); 55 56 foreach (var selection in selectedDisplayGroups) 57 { 58 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 59 { 60 if (selection == group.Id) 61 { 62 mainFeatures.Add(group); 63 } 64 } 65 } 66 67 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 68 69 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-6"); 70 string subtitleFontSize = Model.Item.GetRawValueString("SubtitleFontSize", "h6"); 71 72 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 73 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding; 74 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding; 75 76 string quantityPricesLayout = Model.Item.GetRawValueString("QuantityPricesLayout", "list"); 77 78 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\""; 79 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1"; 80 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty; 81 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : ""; 82 83 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 84 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 85 86 string priceMin = ""; 87 string priceMax = ""; 88 89 var favoriteParameters = new Dictionary<string, object>(); 90 if (!anonymousUser && !hideFavoritesSelector) 91 { 92 IEnumerable<FavoriteList> favoreiteLists = Pageview.User.GetFavoriteLists(); 93 int defaultFavoriteListId = 0; 94 95 if (favoreiteLists.Count() == 1) 96 { 97 foreach (FavoriteList list in favoreiteLists) 98 { 99 defaultFavoriteListId = list.ListId; 100 } 101 } 102 103 favoriteParameters.Add("ListId", defaultFavoriteListId); 104 } 105 106 var badgeParms = new Dictionary<string, object>(); 107 badgeParms.Add("size", "h7"); 108 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 109 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 110 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 111 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 112 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 113 114 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 115 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 116 DateTime createdDate = product.Created.Value; 117 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 118 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 119 showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; 120 var productDB = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, product.VariantId, false); 121 var productState = productDB.GetCategoryValue("ImportedNAVItemAttributes", "ImportedNAVItemAttributes_1")?.ToString(); 122 var deliveryTime = getProductViewModelHelper.DeliveryTime(); 123 var isB2BUser = CustomCode.CustomUserHelpers.IsB2BUser(); 124 125 } 126 127 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking) 128 { 129 <script> 130 gtag("event", "view_item", { 131 currency: "@product.Price.CurrencyCode", 132 value: @product.Price.PriceWithVat.ToString(System.Globalization.CultureInfo.InvariantCulture), 133 items: [ 134 { 135 item_id: "@product.Number", 136 item_name: "@product.Name", 137 currency: "@product.Price.CurrencyCode", 138 price: @product.Price.PriceWithVat.ToString(System.Globalization.CultureInfo.InvariantCulture) 139 } 140 ] 141 }); 142 </script> 143 } 144 145 146 <div class="h-100 @(contentPadding) @(theme)"> 147 <div class="d-flex flex-column gap-3 js-product @(!Model.Item.GetBoolean("HideAddToCartButton") ? "right-data" : "")"> 148 @if (showBadges) 149 { 150 <div> 151 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 152 </div> 153 } 154 155 @if (!hideProductData) 156 { 157 <div> 158 <h1 class="@titleFontSize" itemprop="name">@product.Name</h1> 159 @if (!Model.Item.GetBoolean("HideProductNumber")) 160 { 161 <div class="@(!string.IsNullOrEmpty(product.Number) ? "" : "invisible") ">@Translate("Product number"): <span class="opacity-85" id="product-number-container">@getProductViewModelHelper.ProductNumbers()</span></div> 162 } 163 164 </div> 165 166 var isVariantMaster = product.VariantGroups().Count > 0 && product.VariantId == ""; 167 168 if (!isVariantMaster) 169 { 170 var stockLevel = getProductViewModelHelper.StockLevel(); 171 <div id="product-stock-amount"> 172 @{ if (product.NeverOutOfstock && stockLevel <= 0) 173 { 174 if (deliveryTime != "0") 175 { 176 <div> 177 @RenderIcon("/Files/Templates/Designs/Swift/Assets/icons/check-circle.svg", "icon-2 text-success fw-bold") 178 <span class="fs-7 opacity-85 mb-2"> 179 @(deliveryTime != "0" ? @Translate("[] days").Replace("[]", deliveryTime) : "") 180 </span> 181 </div> 182 } 183 } 184 else if (stockLevel > 0) 185 { 186 string defaultUnitID = product.DefaultUnitId; 187 var variantService = new Dynamicweb.Ecommerce.VariantOptionService(); 188 string productLanguageID = product.LanguageId; 189 var defaultUnit = variantService.GetVariantOption(defaultUnitID, productLanguageID); 190 string defaultUnitName = defaultUnit.Name; 191 192 <div> 193 @RenderIcon("/Files/Templates/Designs/Swift/Assets/icons/check-circle.svg", "icon-2 text-success fw-bold") 194 <span class="fs-7 opacity-85 mb-2">@stockLevel @Translate(defaultUnitName)</span> 195 </div> 196 } 197 else 198 { 199 <div> 200 @if (productState != null && productState == "3") 201 { 202 @RenderIcon("/Files/Templates/Designs/Swift/Assets/icons/check-circle.svg", "icon-2 text-success fw-bold") 203 } 204 else 205 { 206 @RenderIcon("/Files/Templates/Designs/Swift/Assets/icons/minus-circle.svg", "icon-2 text-danger fw-bolder") 207 } 208 209 @(!string.IsNullOrEmpty(deliveryTime) && deliveryTime != "0" ? @Translate("[] days").Replace("[]", deliveryTime) : "") 210 </div> 211 } } 212 </div> 213 } 214 215 } 216 217 @if (!hidePrice) 218 { 219 <div id="price-container"> 220 <div class="h4 m-0" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 221 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span> 222 223 @if (showPricesWithVat == "false" && !neverShowVat) 224 { 225 string beforePrice = isB2BUser ? product.PriceBeforeDiscount.PriceWithoutVatFormatted : product.PriceBeforeDiscount.PriceWithVatFormatted; 226 227 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 228 if (product.Price.Price != product.PriceBeforeDiscount.Price) 229 { 230 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 231 } 232 } 233 else 234 { 235 string beforePrice = product.PriceBeforeDiscount.PriceFormatted; 236 237 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 238 if (product.Price.Price != product.PriceBeforeDiscount.Price) 239 { 240 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 241 } 242 } 243 244 @if (showPricesWithVat == "false" && !neverShowVat) 245 { 246 string price = ""; 247 248 if (isB2BUser) 249 { 250 price = product.Price.PriceFormatted; 251 if (product?.VariantInfo?.VariantInfo != null) 252 { 253 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 254 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 255 } 256 if (priceMin != priceMax) 257 { 258 price = priceMin + " - " + priceMax; 259 } 260 } 261 262 else 263 { 264 price = product.Price.PriceWithVatFormatted; 265 if (product?.VariantInfo?.VariantInfo != null) 266 { 267 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 268 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 269 } 270 if (priceMin != priceMax) 271 { 272 price = priceMin + " - " + priceMax; 273 } 274 275 } 276 277 <span class="text-price fw-bold fs-5">@price <small class="fs-8 fw-normal">(@(isB2BUser ? Translate("Excl. VAT") : Translate("Incl. VAT")))</small></span> 278 } 279 else 280 { 281 string price = product.Price.PriceFormatted; 282 283 if (product?.VariantInfo?.VariantInfo != null) 284 { 285 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 286 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 287 } 288 if (priceMin != priceMax) 289 { 290 price = priceMin + " - " + priceMax; 291 } 292 <span class="text-price">@price</span> 293 } 294 </div> 295 296 @if (CustomCode.CustomUserHelpers.IsB2BUser() == true || isAnonymousB2BUser) 297 { 298 <div> 299 @{ FieldValueViewModel rentalPrice = new FieldValueViewModel(); 300 if (product.ProductFields.TryGetValue("ProductRentalPrice", out rentalPrice)) 301 { 302 if (rentalPrice.Value?.ToString() != "0") 303 { 304 <span>@Translate("Rental Price:") @(rentalPrice.Value?.ToString()) @Dynamicweb.Ecommerce.Common.Context.Currency.Symbol</span> 305 } 306 } 307 } 308 </div> 309 } 310 311 312 @if (Pageview?.User != null) 313 { 314 if (Pageview.User.CurrentSecondaryUser != null) 315 { 316 <div> 317 @{ FieldValueViewModel stockLocation = new FieldValueViewModel(); 318 if (product.ProductFields.TryGetValue("productStockLocation", out stockLocation)) 319 { 320 <span>@Translate("Stock Location"): @(stockLocation.Value?.ToString())</span> 321 } 322 } 323 </div> 324 } 325 } 326 327 @if (product.Prices.Count > 0) 328 { 329 if (quantityPricesLayout == "list") 330 { 331 <div class="mt-3"> 332 @foreach (PriceListViewModel quantityPrice in product.Prices) 333 { 334 string quantityLabel = Translate("PCS"); 335 string quantityPriceSuffix = quantityPrice.Quantity > 1 ? Translate("pr. PCS") : ""; 336 337 <small class="d-block opacity-75"><span>@quantityPrice.Quantity @quantityLabel</span> - <span class="fw-bold">@quantityPrice.Price.PriceFormatted @quantityPriceSuffix</span></small> 338 } 339 </div> 340 } 341 else if (quantityPricesLayout == "table") 342 { 343 <div class="grid"> 344 <table class="table table-sm mt-3 g-col-12 g-col-lg-6"> 345 <thead> 346 <tr> 347 <td>@Translate("QTY")</td> 348 <td>@Translate("pr. PCS")</td> 349 </tr> 350 </thead> 351 <tbody> 352 @foreach (PriceListViewModel quantityPrice in product.Prices) 353 { 354 <tr> 355 <td>@quantityPrice.Quantity</td> 356 <td>@quantityPrice.Price.PriceFormatted</td> 357 </tr> 358 } 359 </tbody> 360 </table> 361 </div> 362 } 363 } 364 </div> 365 } 366 367 @if (!string.IsNullOrEmpty(product.ShortDescription) && !hideProductData) 368 { 369 <div class="mb-0-last-child" itemprop="disambiguatingDescription"> 370 @product.ShortDescription 371 </div> 372 } 373 374 @if (mainFeatures.Count > 0) 375 { 376 foreach (CategoryFieldViewModel mainFeatureGroup in mainFeatures) 377 { 378 <dl class="grid gap-0"> 379 @foreach (var field in mainFeatureGroup.Fields) 380 { 381 @RenderField(field.Value, subtitleFontSize) 382 } 383 </dl> 384 } 385 } 386 387 @if (product.VariantInfo.VariantInfo != null && !Model.Item.GetBoolean("HideVariantSelector")) 388 { 389 int groupNumber = 1; 390 391 <form class="mb-3 js-variant-selector" data-combinations="@string.Join(",", product.VariantCombinations())"> 392 <input type="hidden" name="variantid" /> 393 394 @foreach (var variantGroup in product.VariantGroups()) 395 { 396 VariantGroupViewModel group = variantGroup; 397 398 <h3 class="h6">@group.Name</h3> 399 <div class="mb-3 js-variant-group" data-group-id="@groupNumber"> 400 @foreach (var option in group.Options) 401 { 402 string active = variantId.Contains(option.Id) ? "active" : ""; 403 404 if (!string.IsNullOrEmpty(option.Color)) 405 { 406 <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> 407 } 408 else if (!string.IsNullOrEmpty(option.Color) && !string.IsNullOrEmpty(option.Image.Value)) 409 { 410 <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"> 411 <img src="/Admin/Public/GetImage.ashx?image=@(option.Image.Value)&width=42&Format=WebP&Quality=70" /> 412 </button> 413 } 414 else 415 { 416 <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"> 417 @option.Name 418 </button> 419 } 420 } 421 </div> 422 423 groupNumber++; 424 } 425 </form> 426 } 427 <div class="d-flex flex-row flex-nowrap gap-2"> 428 @if (!hideAddToCart) 429 { 430 <form method="post" action="@url" class="flex-fill"> 431 <input type="hidden" name="redirect" value="false" /> 432 <input type="hidden" name="ProductId" value="@product.Id" /> 433 <input type="hidden" name="cartcmd" value="add" /> 434 435 @if (!string.IsNullOrEmpty(product.VariantId)) 436 { 437 <input type="hidden" name="VariantId" value="@product.VariantId" /> 438 } 439 @if (!Model.Item.GetBoolean("QuantitySelector")) 440 { 441 <input id="Quantity_@product.Id" name="Quantity" value="@valueQty" type="hidden"> 442 <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> 443 } 444 else 445 { 446 <div class="input-group input-primary-button-group js-input-group d-flex flex-row flex-nowrap"> 447 <label for="Quantity_@(product.Id)" class="visually-hidden">@Translate("Quantity")</label> 448 <input id="Quantity_@product.Id" name="Quantity" value="@valueQty" step="@stepQty" @minQty class="form-control" style="max-width: 96px; min-width:64px;" type="number"> 449 <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> 450 </div> 451 452 if (stepQty != "1") 453 { 454 <div class="invalid-feedback d-none"> 455 @Translate("Please select a quantity that is dividable by") @stepQty 456 </div> 457 } 458 } 459 </form> 460 if (!anonymousUser && !hideFavoritesSelector) 461 { 462 @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 463 } 464 } 465 else if (!anonymousUser && !hideFavoritesSelector) 466 { 467 <div class="flex-fill"> 468 @Translate("Add to favorites") @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 469 </div> 470 } 471 </div> 472 473 @if (!Model.Item.GetBoolean("HideAddToCartButton")) 474 { 475 <div id="dw-placeholder"></div> 476 } 477 </div> 478 @if (!Model.Item.GetBoolean("HideStockState")) 479 { 480 if (!IsNeverOutOfStock) 481 { 482 <div class="mt-3 js-stock-state"> 483 484 @if (product.StockLevel > 0) 485 { 486 if (!Model.Item.GetBoolean("HideInventory")) 487 { 488 <p class="small text-success m-0">@product.StockLevel @Translate("Products available in stock")</p> 489 } 490 else 491 { 492 <p class="small text-success m-0">@Translate("Available in stock")</p> 493 } 494 } 495 496 else 497 { 498 <p class="small text-danger m-0">@Translate("Out of Stock")</p> 499 } 500 501 @if (hasExpectedDelivery) 502 { 503 <p> 504 <span>@Translate("Expected back in stock:")</span> 505 <span>@expectedDeliveryDate</span> 506 </p> 507 } 508 509 </div> 510 } 511 } 512 513 @if (isDiscontinued && product.ReplacementProduct != null) 514 { 515 var replacementProduct = product?.ReplacementProduct.GetProduct(); 516 517 if ((product.DiscontinuedAction == 0 || product.DiscontinuedAction == 1) && product?.ReplacementProduct.ProductId != null) 518 { 519 var parms = new Dictionary<string, object>(); 520 parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); 521 parms.Add("fullwidth", true); 522 parms.Add("columns", Model.GridRowColumnCount); 523 524 string imagePath = CustomCode.ImageHelper.GetImagePath(product); 525 526 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop"); 527 if(replacementProduct.PrimaryOrDefaultGroup != null) 528 { 529 link += $"&GroupID={replacementProduct.PrimaryOrDefaultGroup.Id}"; 530 } 531 link += $"&ProductID={replacementProduct.Id}"; 532 link += !string.IsNullOrEmpty(replacementProduct.VariantId) ? $"&VariantID={replacementProduct.VariantId}" : ""; 533 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link); 534 535 <div class="w-100"> 536 <div class="fw-bold w-100">@Translate("Sorry, this product is no longer available").</div> 537 <div>@Translate("We recommend this replacement product instead"):</div> 538 539 <a href="@link"> 540 @RenderPartial("Components/Image.cshtml", new Dynamicweb.Frontend.FileViewModel { Path = imagePath }, parms) 541 </a> 542 543 <div>@replacementProduct.Name</div> 544 545 <a href="@link" class="btn btn-primary w-100">@Translate("Go to the replacement")</a> 546 </div> 547 } 548 } 549 </div> 550 551 @helper RenderField(FieldValueViewModel field, string subtitleFontSize) 552 { 553 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 554 bool noValues = false; 555 556 if (!string.IsNullOrEmpty(fieldValue)) 557 { 558 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 559 { 560 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 561 noValues = values.Count > 0 ? false : true; 562 } 563 } 564 565 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 566 { 567 <dt class="g-col-12 g-col-sm-4 g-col-lg-12 fw-bold m-0 @subtitleFontSize">@Translate(field.Name)</dt> 568 <dd class="g-col-12 g-col-sm-8 g-col-lg-12 mb-3"> 569 @RenderFieldValue(field) 570 </dd> 571 } 572 } 573 574 @helper RenderFieldValue(FieldValueViewModel field) 575 { 576 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 577 578 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 579 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 580 581 bool isColor = false; 582 583 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 584 { 585 int valueCount = 0; 586 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 587 int totalValues = values.Count; 588 589 foreach (FieldOptionValueViewModel option in values) 590 { 591 if (option.Value.Substring(0, 1) == "#") 592 { 593 isColor = true; 594 } 595 596 if (!isColor) 597 { 598 @option.Name 599 } 600 else 601 { 602 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span> 603 } 604 605 if (valueCount != totalValues && valueCount < (totalValues - 1)) 606 { 607 if (isColor) 608 { 609 <text> </text> 610 } 611 else 612 { 613 <text>, </text> 614 } 615 } 616 valueCount++; 617 } 618 } 619 else 620 { 621 if (fieldValue.Substring(0, 1) == "#") 622 { 623 isColor = true; 624 } 625 626 if (!isColor) 627 { 628 @fieldValue 629 } 630 else 631 { 632 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 633 } 634 } 635 } 636 637 @if (product.VariantInfo.VariantInfo != null) 638 { 639 <script type="module"> 640 swift.VariantSelector.init(); 641 </script> 642 } 643 644 @helper RenderIcon(string icon, string iconSize) 645 { 646 if (Path.GetExtension(icon).ToLower() == ".svg" && !icon.ToLower().Contains("none")) 647 { 648 string iconPath = Dynamicweb.Context.Current.Server.MapPath(icon); 649 650 <span class="@iconSize"> 651 @ReadFile(iconPath) 652 </span> 653 } 654 } 655
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