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_6cf8a19497b9405bae9d26e2bd3cc287.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
Deze cosmetische pincet met retro print heeft een fijne, schuine punt en is bijzonder geschikt voor het verwijderen van kleine haartjes, voor het epileren van de wenkbrauwen, als splinterpincet of als hulp in het huishouden. Kortom, een universele pincet voor thuis of onderweg. Ze ligt goed in de hand en is prettig in gebruik.
Professionele kwaliteit van roestvrij staal.
Lengte: 9,5cm
Premium kwaliteit PINCETTEN
Of het nu gaat om het plukken van de wenkbrauwen of voor het verwijderen van vervelende teken - een pincet van Nippes kan op verschillende manieren worden gebruikt. Verkrijgbaar in verschillende designs, maten en materialen.
Wat ze allemaal verenigt, is de superieure kwaliteit.
Een innovatie made in Germany.
Specificaties
- Kleur
- Mix
- Wat zit er in de doos
- 1x Pincet
- Materiaal
- Inox
GPSR EU-Regulation
- EU Authorised Representative - Email
- [email protected]
- Manufacturer information - Address
- Gebrüder Nippes GmbH & Co. Straussplatz 2 KG42697 Solingen
- Manufacturer information - Trade name
- Gebrüder Nippes GmbH & Co. KG
- Manufacturer information - Website
- www.nippes-solingen.de