Error executing template "/Designs/Swift/Paragraph/Swift_ProductDetailsInfo.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at CompiledRazorTemplates.Dynamic.RazorEngine_7e620e3230c7487db39cee5d8e3ca12f.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\bomedys.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsInfo.cshtml:line 399 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 @using Dynamicweb.Core 7 @using System.Drawing 8 @using Dynamicweb.Environment 9 10 @functions { 11 //Find contrast color (white, black) 12 public static string GetContrastColor(string hexString) 13 { 14 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 15 16 int nThreshold = 105; 17 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 18 (bg.B * 0.114)); 19 20 string foreColor = (255 - bgDelta < nThreshold) ? "#333" : "#fff"; 21 return foreColor; 22 } 23 } 24 25 @{ 26 string googleAnalyticsTrackingID = Pageview.AreaSettings.GetString("GoogleAnalyticsTrackingID"); 27 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID"); 28 var cookieOptInLevel = CookieManager.GetCookieOptInLevel(); 29 bool allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical")); 30 31 ProductViewModel product = new ProductViewModel(); 32 33 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 34 { 35 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 36 } 37 38 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 39 bool anonymousUser = Pageview.User == null; 40 bool isErpConnectionDown = !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable(); 41 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown; 42 hideAddToCart = product?.VariantInfo?.VariantInfo != null && Model.Item.GetBoolean("HideVariantSelector") ? true : hideAddToCart; 43 bool hideStock = Model.Item.GetBoolean("HideStockState") || (Pageview.AreaSettings.GetBoolean("ErpDownHideStock") && isErpConnectionDown); 44 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && isErpConnectionDown; 45 bool hideFavoritesSelector = !string.IsNullOrEmpty(Model.Item.GetString("HideFavoritesSelector")) ? Model.Item.GetBoolean("HideFavoritesSelector") : false; 46 47 bool isDiscontinued = product.Discontinued; 48 bool IsNeverOutOfStock = product.NeverOutOfstock; 49 string[] variantId = { }; 50 51 if (product?.VariantId != null) { 52 variantId = product.VariantId.Split('.'); 53 } 54 55 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : ""; 56 disableAddToCart = isDiscontinued ? "disabled" : disableAddToCart; 57 disableAddToCart = IsNeverOutOfStock ? "" : disableAddToCart; 58 59 // Does product has a expected delivery data 60 bool hasExpectedDelivery = product.ExpectedDelivery != null && product.ExpectedDelivery > DateTime.Now; 61 string expectedDeliveryDate = product.ExpectedDelivery?.ToShortDateString() ?? ""; 62 63 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 64 if (!url.Contains("LayoutTemplate")) 65 { 66 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml"; 67 } 68 69 IEnumerable<string> selectedDisplayGroups = Model.Item.GetRawValueString("MainFeatures").Split(',').ToList(); 70 List<CategoryFieldViewModel> mainFeatures = new List<CategoryFieldViewModel>(); 71 72 foreach (var selection in selectedDisplayGroups) 73 { 74 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 75 { 76 if (selection == group.Id) 77 { 78 mainFeatures.Add(group); 79 } 80 } 81 } 82 83 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 84 85 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-6"); 86 87 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 88 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding; 89 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding; 90 91 string quantityPricesLayout = Model.Item.GetRawValueString("QuantityPricesLayout", "list"); 92 93 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\""; 94 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1"; 95 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty; 96 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : ""; 97 98 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 99 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 100 101 string priceMin = ""; 102 string priceMax = ""; 103 104 var favoriteParameters = new Dictionary<string, object>(); 105 if (!anonymousUser && !hideFavoritesSelector) 106 { 107 IEnumerable<FavoriteList> favoreiteLists = Pageview.User.GetFavoriteLists(); 108 int defaultFavoriteListId = 0; 109 110 if (favoreiteLists.Count() == 1) { 111 foreach (FavoriteList list in favoreiteLists) { 112 defaultFavoriteListId = list.ListId; 113 } 114 } 115 116 favoriteParameters.Add("ListId", defaultFavoriteListId); 117 } 118 119 var priceParms = new Dictionary<string, object>(); 120 priceParms.Add("theme", ""); 121 122 var badgeParms = new Dictionary<string, object>(); 123 badgeParms.Add("size", "h7"); 124 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 125 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 126 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 127 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 128 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 129 130 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 131 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 132 DateTime createdDate = product.Created.Value; 133 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 134 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 135 showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; 136 137 string liveInfoClass = ""; 138 string productInfoFeed = ""; 139 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsLazyLoadingForProductInfoEnabled; 140 if (isLazyLoadingForProductInfoEnabled) 141 { 142 if (Dynamicweb.Context.Current.Items.Contains("ProductInfoFeed")) 143 { 144 productInfoFeed = Dynamicweb.Context.Current.Items["ProductInfoFeed"]?.ToString(); 145 if (!string.IsNullOrEmpty(productInfoFeed)) 146 { 147 productInfoFeed = $"data-product-info-feed=\"{productInfoFeed}\""; 148 } 149 } 150 liveInfoClass = "js-live-info"; 151 } 152 @* Product stock state *@ 153 double? currentStockLevel = product.StockLevel; 154 155 156 string stockStateLabel = !string.IsNullOrEmpty(product.StockStatus) ? product.StockStatus : ""; 157 158 string stockStateCss = currentStockLevel > 0 ? "text-success" : "text-danger"; 159 string stockStateIconCss = currentStockLevel > 0 ? "bg-success" : "bg-danger"; 160 } 161 162 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking) 163 { 164 <script> 165 gtag("event", "view_item", { 166 currency: "@product.Price.CurrencyCode", 167 value: @product.Price.Price, 168 items: [ 169 { 170 item_id: "@product.Number", 171 item_name: "@product.Name", 172 currency: "@product.Price.CurrencyCode", 173 price: @product.Price.Price 174 } 175 ] 176 }); 177 </script> 178 } 179 180 <div class="h-100 @(contentPadding) @(theme) [email protected]()" @productInfoFeed> 181 <div class="d-flex flex-column gap-4 js-product" data-product-id="@product.Id"> 182 @if (showBadges) { 183 <div class="swift_badge-collection"> 184 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 185 </div> 186 } 187 188 <div class="d-flex flex-column gap-2"> 189 <h1 class="@titleFontSize m-0" itemprop="name">@product.Name</h1> 190 @if (!Model.Item.GetBoolean("HideProductNumber")) 191 { 192 @RenderPartial("Paragraph/Swift_ProductNumber.cshtml", Model) 193 } 194 </div> 195 196 @if (!hidePrice && !isDiscontinued) 197 { 198 @RenderPartial("Paragraph/Swift_ProductPrice.cshtml", Model, priceParms) 199 200 if (isLazyLoadingForProductInfoEnabled) 201 { 202 <div class="product-prices-container @liveInfoClass d-none" data-show-if="LiveProductInfo.product.Prices.length > 0"> 203 @if (quantityPricesLayout == "list") 204 { 205 <div class="mt-3 product-prices"> 206 <small class="d-block opacity-75 product-prices-template"><span><span class="js-text-price-quantity"></span> @Translate("PCS")</span> - <span class="fw-bold"><span class="js-text-price-price"></span> <span class="d-none" data-show-if="LiveProductInfo.productPrice.Quantity > 1">@Translate("pr. PCS")</span></span></small> 207 </div> 208 } 209 else if (quantityPricesLayout == "table") 210 { 211 <div class="grid"> 212 <table class="table table-sm mt-3 g-col-12 g-col-lg-6"> 213 <thead> 214 <tr> 215 <td>@Translate("QTY")</td> 216 <td>@Translate("pr. PCS")</td> 217 </tr> 218 </thead> 219 <tbody class="product-prices"> 220 <tr class="product-prices-template"> 221 <td class="js-text-price-quantity"></td> 222 <td class="js-text-price-price"></td> 223 </tr> 224 </tbody> 225 </table> 226 </div> 227 } 228 </div> 229 } 230 else 231 { 232 if (product.Prices.Count > 0) 233 { 234 <div> 235 @if (quantityPricesLayout == "list") 236 { 237 <div class="mt-3"> 238 @foreach (PriceListViewModel quantityPrice in product.Prices) 239 { 240 string quantityLabel = Translate("PCS"); 241 string quantityPriceSuffix = quantityPrice.Quantity > 1 ? Translate("pr. PCS") : ""; 242 243 <small class="d-block opacity-75"><span>@quantityPrice.Quantity @quantityLabel</span> - <span class="fw-bold">@quantityPrice.Price.PriceFormatted @quantityPriceSuffix</span></small> 244 } 245 </div> 246 } 247 else if (quantityPricesLayout == "table") 248 { 249 <div class="grid"> 250 <table class="table table-sm mt-3 g-col-12 g-col-lg-6"> 251 <thead> 252 <tr> 253 <td>@Translate("QTY")</td> 254 <td>@Translate("pr. PCS")</td> 255 </tr> 256 </thead> 257 <tbody> 258 @foreach (PriceListViewModel quantityPrice in product.Prices) 259 { 260 <tr> 261 <td>@quantityPrice.Quantity</td> 262 <td>@quantityPrice.Price.PriceFormatted</td> 263 </tr> 264 } 265 </tbody> 266 </table> 267 </div> 268 } 269 </div> 270 } 271 } 272 } 273 274 @RenderPartial("Paragraph/Swift_ProductShortDescription.cshtml", Model) 275 276 @if (mainFeatures.Count > 0) 277 { 278 foreach (CategoryFieldViewModel mainFeatureGroup in mainFeatures) 279 { 280 <dl class="grid gap-0"> 281 @foreach (var field in mainFeatureGroup.Fields) 282 { 283 @RenderField(field.Value) 284 } 285 </dl> 286 } 287 } 288 289 @if (product.VariantInfo.VariantInfo != null && !Model.Item.GetBoolean("HideVariantSelector")) 290 { 291 int groupNumber = 1; 292 293 string baseUrl = $"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}"; 294 string variantUrl = ""; 295 if (!string.IsNullOrEmpty(product.VariantId)) 296 { 297 variantUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl($"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}&VariantID={product.VariantId}"); 298 } 299 300 <form class="js-variant-selector" data-combinations="@string.Join(",", product.VariantCombinations())" data-base-url="@baseUrl" data-friendly-url="@variantUrl"> 301 <input type="hidden" name="variantid" /> 302 303 @foreach (var variantGroup in product.VariantGroups()) 304 { 305 VariantGroupViewModel group = variantGroup; 306 307 <h3 class="h6">@group.Name</h3> 308 <div class="d-flex gap-2 flex-wrap js-variant-group" data-group-id="@groupNumber"> 309 @foreach (var option in group.Options) 310 { 311 string active = variantId.Contains(option.Id) ? "active" : ""; 312 313 if (!string.IsNullOrEmpty(option.Color)) 314 { 315 string contrastColor = GetContrastColor(option.Color); 316 <button type="button" class="btn colorbox rounded-circle d-inline-block variant-option border js-variant-option @active" style="background-color: @option.Color; --variantoption-check-color: @contrastColor" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@(product.Id)_@(option.Id)[email protected]"></button> 317 } 318 else if (!string.IsNullOrEmpty(option.Color) && !string.IsNullOrEmpty(option.Image.Value)) 319 { 320 <button type="button" class="btn p-0 d-inline-block variant-option border js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 321 <img src="/Admin/Public/GetImage.ashx?image=@(option.Image.Value)&width=42&Format=WebP&Quality=70" /> 322 </button> 323 } 324 else 325 { 326 <button type="button" class="btn btn-secondary d-inline-block variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 327 @option.Name 328 </button> 329 } 330 } 331 </div> 332 333 groupNumber++; 334 } 335 </form> 336 } 337 338 <div class="d-flex flex-row flex-nowrap gap-2"> 339 @if (!hideAddToCart) 340 { 341 <form method="post" action="@url" class="flex-fill"> 342 <input type="hidden" name="redirect" value="false" /> 343 <input type="hidden" name="ProductId" value="@product.Id" /> 344 <input type="hidden" name="ProductName" value="@product.Name" /> 345 <input type="hidden" name="ProductPrice" value="@product.Price.Price" /> 346 <input type="hidden" name="ProductCurrency" value="@product.Price.CurrencyCode" /> 347 <input type="hidden" name="ProductReferer" value="product_details_info"> 348 <input type="hidden" name="cartcmd" value="add" /> 349 350 @if (!string.IsNullOrEmpty(product.VariantId)) 351 { 352 <input type="hidden" name="VariantId" value="@product.VariantId" /> 353 } 354 @if (!Model.Item.GetBoolean("QuantitySelector")) 355 { 356 <input id="[email protected]" name="Quantity" value="@valueQty" type="hidden"> 357 <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)[email protected]">@Translate("Add to cart")</button> 358 } else { 359 <div class="input-group input-primary-button-group js-input-group d-flex flex-row flex-nowrap"> 360 <label for="Quantity_@(product.Id)" class="visually-hidden">@Translate("Quantity")</label> 361 <input id="[email protected]" name="Quantity" value="@valueQty" step="@stepQty" @minQty class="form-control" style="max-width: 96px; min-width:64px;" type="number" onkeydown="swift.Cart.UpdateOnEnterKey(event)"> 362 <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)[email protected]">@Translate("Add to cart")</button> 363 </div> 364 365 if (stepQty != "1") 366 { 367 <div class="invalid-feedback d-none"> 368 @Translate("Please select a quantity that is dividable by") @stepQty 369 </div> 370 } 371 } 372 </form> 373 if (!anonymousUser && !hideFavoritesSelector) 374 { 375 @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 376 } 377 } 378 else if (!anonymousUser && !hideFavoritesSelector && !isDiscontinued) 379 { 380 <div class="flex-fill" id="[email protected]"> 381 @Translate("Add to favorites") @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 382 </div> 383 } 384 385 @if (isDiscontinued && product.ReplacementProduct != null) { 386 List<ProductInfoViewModel> replacementProductList = new List<ProductInfoViewModel>(); 387 replacementProductList.Add(product.ReplacementProduct); 388 var replacementProduct = replacementProductList.GetProducts().FirstOrDefault(); 389 390 if ((product.DiscontinuedAction == 0 || product.DiscontinuedAction == 1) && product?.ReplacementProduct.ProductId != null) { 391 var parms = new Dictionary<string, object>(); 392 parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); 393 parms.Add("fullwidth", true); 394 parms.Add("columns", Model.GridRowColumnCount); 395 396 string imagePath = replacementProduct?.DefaultImage?.Value != null ? replacementProduct.DefaultImage.Value : ""; 397 398 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop"); 399 link += $"&GroupID={replacementProduct.PrimaryOrDefaultGroup.Id}"; 400 link += $"&ProductID={replacementProduct.Id}"; 401 link += !string.IsNullOrEmpty(replacementProduct.VariantId) ? $"&VariantID={replacementProduct.VariantId}" : ""; 402 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link); 403 404 <div class="w-100"> 405 <div class="fw-bold w-100">@Translate("Sorry, this product is no longer available").</div> 406 <div>@Translate("We recommend this replacement product instead"):</div> 407 408 <a href="@link"> 409 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 410 </a> 411 412 <div>@replacementProduct.Name</div> 413 414 @if (!hidePrice) 415 { 416 <div class="mb-3"> 417 <div class="h4" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 418 @if (showPricesWithVat == "false" && !neverShowVat) 419 { 420 if (isLazyLoadingForProductInfoEnabled) 421 { 422 <span itemprop="price" content="" class="d-none"></span> 423 <span class="text-decoration-line-through js-text-decoration-line-through opacity-75 me-3 text-price js-text-price d-none" data-show-if="LiveProductInfo.product.Price.Price != LiveProductInfo.product.PriceBeforeDiscount.Price"></span> 424 } 425 else 426 { 427 string beforePrice = product.PriceBeforeDiscount.PriceWithoutVatFormatted; 428 429 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 430 if (product.Price.Price != product.PriceBeforeDiscount.Price) 431 { 432 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 433 } 434 } 435 } 436 else 437 { 438 if (isLazyLoadingForProductInfoEnabled) 439 { 440 <span itemprop="price" content="" class="d-none"></span> 441 <span class="text-decoration-line-through js-text-decoration-line-through opacity-75 me-3 text-price js-text-price d-none" data-show-if="LiveProductInfo.product.Price.Price != LiveProductInfo.product.PriceBeforeDiscount.Price"></span> 442 } 443 else 444 { 445 string beforePrice = product.PriceBeforeDiscount.PriceFormatted; 446 447 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 448 if (product.Price.Price != product.PriceBeforeDiscount.Price) 449 { 450 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 451 } 452 } 453 } 454 455 @if (showPricesWithVat == "false" && !neverShowVat) 456 { 457 if (isLazyLoadingForProductInfoEnabled) 458 { 459 <span class="text-price js-text-price"><div class="spinner-border" role="status"></div></span> 460 } 461 else 462 { 463 string price = product.Price.PriceWithoutVatFormatted; 464 if (product?.VariantInfo?.VariantInfo != null) 465 { 466 priceMin = product?.VariantInfo?.PriceMin?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithoutVatFormatted : ""; 467 priceMax = product?.VariantInfo?.PriceMax?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithoutVatFormatted : ""; 468 } 469 if (priceMin != priceMax) 470 { 471 price = priceMin + " - " + priceMax; 472 } 473 <span class="text-price">@price</span> 474 } 475 } 476 else 477 { 478 if (isLazyLoadingForProductInfoEnabled) 479 { 480 <span class="text-price js-text-price"><div class="spinner-border" role="status"></div></span> 481 } 482 else 483 { 484 string price = product.Price.PriceFormatted; 485 if (product?.VariantInfo?.VariantInfo != null) 486 { 487 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 488 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 489 } 490 if (priceMin != priceMax) 491 { 492 price = priceMin + " - " + priceMax; 493 } 494 <span class="text-price">@price</span> 495 } 496 } 497 </div> 498 499 @if (showPricesWithVat == "false" && !neverShowVat) 500 { 501 if (isLazyLoadingForProductInfoEnabled) 502 { 503 <small class="opacity-85 fst-normal js-text-price-with-vat d-none" data-suffix="@Translate("Incl. VAT")"></small> 504 } 505 else 506 { 507 string price = product.Price.PriceWithVatFormatted; 508 if (product?.VariantInfo?.VariantInfo != null) 509 { 510 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 511 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 512 } 513 if (priceMin != priceMax) 514 { 515 price = priceMin + " - " + priceMax; 516 } 517 <small class="opacity-85 fst-normal">@price @Translate("Incl. VAT")</small> 518 } 519 } 520 </div> 521 } 522 523 <a href="@link" class="btn btn-primary w-100">@Translate("Go to the replacement")</a> 524 </div> 525 } 526 } 527 </div> 528 </div> 529 @if (!hideStock) 530 { 531 <div class="js-stock-state [email protected]()"> 532 <div class="small"> 533 <span class="@stockStateCss">@stockStateLabel </span> 534 </div> 535 </div> 536 } 537 </div> 538 539 @helper RenderField(FieldValueViewModel field) 540 { 541 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 542 bool noValues = false; 543 544 if (!string.IsNullOrEmpty(fieldValue)) 545 { 546 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 547 { 548 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 549 noValues = values.Count > 0 ? false : true; 550 } 551 } 552 553 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 554 { 555 <dt class="g-col-12 g-col-sm-4 g-col-lg-12 fw-bold m-0">@field.Name</dt> 556 <dd class="g-col-12 g-col-sm-8 g-col-lg-12 mb-3"> 557 @RenderFieldValue(field) 558 </dd> 559 } 560 } 561 562 @helper RenderFieldValue(FieldValueViewModel field) 563 { 564 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 565 566 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 567 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 568 569 bool isColor = false; 570 571 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 572 { 573 int valueCount = 0; 574 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 575 int totalValues = values.Count; 576 577 foreach (FieldOptionValueViewModel option in values) 578 { 579 if (option.Value.Substring(0, 1) == "#") 580 { 581 isColor = true; 582 } 583 584 if (!isColor) 585 { 586 @option.Name 587 } 588 else 589 { 590 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span> 591 } 592 593 if (valueCount != totalValues && valueCount < (totalValues - 1)) 594 { 595 if (isColor) 596 { 597 <text> </text> 598 } 599 else 600 { 601 <text>, </text> 602 } 603 } 604 valueCount++; 605 } 606 } 607 else 608 { 609 if (fieldValue.Substring(0, 1) == "#") 610 { 611 isColor = true; 612 } 613 614 if (!isColor) 615 { 616 @fieldValue 617 } 618 else 619 { 620 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 621 } 622 } 623 } 624
Product beschrijving
Flaem Connector aerosol
Specificaties
- Batteries
- nvt
- Battery included
- NEE
GPSR EU-Regulation
- Manufacturer information - Address
- FLAEM NUOVA SPA VIA COLLI STORICI 221-223-225 25015 – DESENZANO DEL GARDA (BRESCIA) (Italia)
- Manufacturer information - Trade name
- FLAEM
- Manufacturer information - Website
- https://www.flaem.eu/en/