Egenproduktion af genbrugsplastEgenproduktion af genbrugsplast
Bestil før kl. 14.00 - så sender vi i dagBestil før kl. 14.00 - så sender vi i dag
Lagerførende på varer til akutopgaverLagerførende på varer til akutopgaver
Gratis beregning og dimensioneringGratis beregning og dimensionering
Error executing template "Designs/Rapido/eCom/Product/NZProductView.cshtml"
System.ArgumentException: Illegal characters in path.
   at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional)
   at System.IO.Path.GetFileName(String path)
   at System.IO.FileInfo.Init(String fileName, Boolean checkHost)
   at System.IO.FileInfo..ctor(String fileName)
   at S_DW_Lauridsen.CustomCode.DocumentInfo.FileInformation(String docCol)
   at CompiledRazorTemplates.Dynamic.RazorEngine_7582e0ce63d64a629d3222033b0894a2.Execute() in E:\Solutions\S_DW_Lauridsen\lauridsen-live\Files\Templates\Designs\Rapido\eCom\Product\NZProductView.cshtml:line 37
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.DynamicWrapperService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2 @using Dynamicweb.Extensibility 3 @using Dynamicweb.Content 4 @using System; 5 @using System.Globalization; 6 @using System.Linq 7 @using System.IO 8 @using Dynamicweb.Core 9 @using System.Web 10 @using Dynamicweb.Ecommerce 11 @using Dynamicweb.Ecommerce.Discounts 12 @using Dynamicweb.Ecommerce.Orders.Discounts 13 @using Dynamicweb.Ecommerce.Products 14 @using Dynamicweb.Ecommerce.Prices 15 @using NLog; 16 @using S_DW_Lauridsen.CustomCode 17 @using Dynamicweb.Security.UserManagement 18 @using NuGet.Versioning 19 @{ 20 21 string favoritPage = String.Format("/Default.aspx?ID={0}&CC20=CreateFormList", GetPageIdByNavigationTag("CustomerFavorites").ToString()); 22 string pageId = GetGlobalValue("Global:Page.ID").ToString(); 23 string productId = GetString("Ecom:Product.ID"); 24 string uniqueId = GetString("Ecom:Product.ID") + GetString("Ecom:Product.VariantID"); 25 // Stock status 26 int stockAmount = GetInteger("Ecom:Product.AvailableAmount"); 27 string currentPrice = GetString("Ecom:Product.Discount.Price.PriceFormatted") == GetString("Ecom:Product.Price.PriceFormatted") ? GetString("Ecom:Product.Price.PriceFormatted") : GetString("Ecom:Product.Discount.Price.PriceFormatted"); 28 string hideHelpText = ""; 29 string requestQuery = GetGlobalValue("Global:Request.Query"); 30 string variantId = HttpContext.Current.Request.QueryString.Get("variantId"); 31 string feedId = pageId + "&ProductID=" + productId + "&VariantID=" + variantId + "&Feed=True&redirect=false"; 32 //CFP bool 33 bool cfp = GetBoolean("Ecom:Product:Field.CFP"); 34 35 // Documents 36 string documentValue = GetString("Ecom:Product:Field.PDF_Path"); 37 var results = DocumentInfo.FileInformation(documentValue); 38 39 40 string externalLink = GetValue("Ecom:Product:Field.ExternalLinks.Value").ToString(); 41 var testList = externalLink.Split(new string[] { "</p>" }, StringSplitOptions.RemoveEmptyEntries).ToList(); 42 43 44 45 int featuresCount = 0; 46 string brand = GetString("Ecom:Product:Field.brand"); 47 bool onlyPreviewForAnonymousUsers = Pageview.AreaSettings.GetBoolean("OnlyPreviewForAnonymous"); 48 bool onlyPreview = onlyPreviewForAnonymousUsers ? Pageview.User == null : false; 49 50 foreach (LoopItem customField in GetLoop("CustomFieldValues")) 51 { 52 if (!String.IsNullOrEmpty(customField.GetString("Product.CustomField.Value.Clean")) && customField.GetString("Product.CustomField.Name") != "CustomSticker") 53 { 54 featuresCount++; 55 } 56 } 57 58 foreach (LoopItem customField in GetLoop("ProductCategories")) 59 { 60 foreach (LoopItem field in customField.GetLoop("ProductCategoryFields")) 61 { 62 if (!String.IsNullOrEmpty(field.GetString("Ecom:Product.CategoryField.Value"))) 63 { 64 featuresCount++; 65 } 66 } 67 } 68 69 foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 70 { 71 foreach (LoopItem variantoption in variantgroup.GetLoop("VariantAvailableOptions")) 72 { 73 if (variantoption.GetBoolean("Ecom:VariantOption.Selected")) 74 { 75 hideHelpText = "u-hidden"; 76 } 77 } 78 } 79 80 int relatedProductsPageSize = 4; 81 int relatedProductsColumnWidth = 3; 82 83 if (Pageview.Device.ToString() == "Mobile") 84 { 85 relatedProductsPageSize = 1; 86 relatedProductsColumnWidth = 12; 87 } 88 89 if (Pageview.Device.ToString() == "Tablet") 90 { 91 relatedProductsPageSize = 3; 92 relatedProductsColumnWidth = 4; 93 } 94 95 string pageNavTag = GetPageIdByNavigationTag("ProductsPage").ToString(); 96 string feedFullUrl = String.Format("/Default.aspx?ID={0}&PageSize={1}&ProdID={2}&feed=true", pageNavTag, relatedProductsPageSize, productId); 97 string relatedProductsFeed = String.Format("/Default.aspx?ID={0}&PageSize={1}&ProdID={2}&feed=true&RelateredeProdukter=", pageNavTag, relatedProductsPageSize, productId); 98 string productContainerId = "Product" + productId; 99 string video = GetString("Ecom:Product:Field.video"); 100 string siteURL = Dynamicweb.Context.Current.Request.Url.Scheme + "://" + Dynamicweb.Context.Current.Request.Url.Host; 101 Dynamicweb.Ecommerce.Products.Product currentProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(GetString("Ecom:Product.ID"), GetString("Ecom:Product.VariantID"), GetString("Ecom:Product.LanguageID")); 102 var imagePathValue = Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(currentProduct, "ImagePath"); 103 string imagePath = !string.IsNullOrWhiteSpace(imagePathValue.ToString()) ? "/Files/Images/Ecom/LHI_Products/Images/" + imagePathValue + ".jpg" : ""; 104 string productImage = !string.IsNullOrWhiteSpace(imagePath) ? imagePath : GetString("Ecom:Product.ImageLarge.Default.Clean"); 105 string canonicalURL = GetString("Ecom:Product.Canonical"); 106 string vismaUnitName = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.Enhed")) ? GetString("Ecom:Product:Field.Enhed")?.ToLower() : Translate("UnitPriceTextStk"); 107 108 //gallery 109 int imagesCount = 1; 110 List<string> galleryImages = new List<string>(); 111 112 galleryImages.Add(productImage); 113 if (!string.IsNullOrWhiteSpace(video)) 114 { 115 foreach (var image in video.Split('|')) 116 { 117 string videoThumb = String.Format("https://img.youtube.com/vi/{0}/0.jpg", image); 118 galleryImages.Add(videoThumb); 119 imagesCount++; 120 } 121 } 122 123 foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages")) 124 { 125 if (!String.IsNullOrEmpty(alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"))) 126 { 127 string fullImage = "/Admin/Public/GetImage.ashx?width=550&amp;height=550&amp;crop=5&FillCanvas=True&DoNotUpscale=true&amp;Compression=75&amp;image=" + alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 128 galleryImages.Add(fullImage); 129 imagesCount++; 130 } 131 } 132 133 foreach (LoopItem detail in GetLoop("Details")) 134 { 135 string fullImage = "/Admin/Public/GetImage.ashx?width=550&amp;height=550&amp;crop=5&FillCanvas=True&DoNotUpscale=true&amp;Compression=75&amp;image=" + detail.GetString("Ecom:Product:Detail.Image.Clean"); 136 137 if (!String.IsNullOrEmpty(fullImage)) 138 { 139 galleryImages.Add(fullImage); 140 imagesCount++; 141 } 142 } 143 144 string firstImage = galleryImages.FirstOrDefault(); 145 string galleryImagesArray = string.Join(", ", galleryImages); 146 } 147 148 @* Set product canonical URL *@ 149 @SnippetStart("canonical") 150 @{ 151 string host = GetGlobalValue("Global:Request.Host"); 152 string url = GetGlobalValue("Global:Pageview.Url"); 153 int queryIndex = url.IndexOf("?", StringComparison.Ordinal); 154 if (queryIndex > -1) 155 { 156 url = url.Substring(0, queryIndex); 157 } 158 } 159 <link rel="canonical" href="https://@host@url"> 160 @SnippetEnd("canonical") 161 <!-- Trigger for the gallery modal --> 162 <input type="checkbox" id="GalleryModalTrigger" class="modal-trigger" /> 163 164 <!-- Gallery modal --> 165 <div class="modal-container"> 166 <label for="GalleryModalTrigger" id="GalleryModalOverlay" class="modal-overlay"></label> 167 <div class="modal modal--lg modal--full modal-no-bg" id="GalleryModal"> 168 <div class="modal__body"> 169 <div class="gallery-slider js-gallery-slider" data-total-images="@imagesCount" data-images="@galleryImagesArray"> 170 <div class="gallery-slider__image" data-icon-nz="play"> 171 <img id="FullImage" src="@firstImage" class="w-100 js-video-button js-gallery-image" /> 172 </div> 173 <div class="gallery-slider__image-counter" id="FullImage_counter"> 174 </div> 175 <label class="gallery-slider__close-btn" for="GalleryModalTrigger"></label> 176 177 @if (imagesCount > 1) 178 { 179 <button class="gallery-slider__previous-btn" id="FullImage_prev" onclick="Gallery.prevImage('FullImage')"></button> 180 <button class="gallery-slider__next-btn" id="FullImage_next" onclick="Gallery.nextImage('FullImage')"></button> 181 } 182 183 </div> 184 </div> 185 </div> 186 </div> 187 188 <div class="paragraph-container__grid--bleed-x paragraph-container__grid--bleed-y product-view"> 189 <div class="grid product js-product" id="productGrid"> 190 @* Image block with optional thumbs *@ 191 @if (!String.IsNullOrEmpty(productImage)) 192 { 193 <div class="grid__col-md-6 grid__col-sm-6"> 194 <div class="grid grid--bleed product-slider"> 195 @{ 196 int thumbCounter = 0; 197 } 198 <div class="grid__col-2 product-slider__thumbnails dw-mod "> 199 <div class="carousel js-carousel-container u-max-h500px dw-mod"> 200 <div class="thumb-list carousel__container dw-mod m-0"> 201 <div class="carousel__container__slide carousel__container__slide--vertical product-slider__inner dw-mod"> 202 203 @*Main image thumb*@ 204 <div class="carousel__container__slide product-slider__slide dw-mod"> 205 <div class="thumb-list__item thumb-list__item--active dw-mod js-thumb js-thumb-btn js-gallery" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" data-image="/Admin/Public/GetImage.ashx?width=550&amp;height=550&amp;crop=5&DoNotUpscale=true&amp;Compression=75&amp;image=@productImage"> 206 <label for="GalleryModalTrigger"> 207 <img src="/Admin/Public/GetImage.ashx?width=100&amp;height=100&amp;crop=5&amp;DoNotUpscale=true&amp;Compression=75&amp;image=@productImage" class="js-gallery" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="@thumbCounter" onclick="Gallery.openImage(this)" data-image="/Admin/Public/GetImage.ashx?width=550&amp;height=550&amp;crop=5&DoNotUpscale=true&amp;Compression=75&amp;image=@productImage"> 208 </label> 209 </div> 210 </div> 211 212 @{ thumbCounter++; } 213 214 @foreach (LoopItem alternativeImage in GetLoop("Ecom:Product.AlternativeImages")) 215 { 216 if (!String.IsNullOrEmpty(alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"))) 217 { 218 string image = "/Admin/Public/GetImage.ashx?width=550&amp;height=550&amp;crop=5&FillCanvas=True&DoNotUpscale=true&amp;Compression=75&amp;image=" + alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 219 string thumb = "/Admin/Public/GetImage.ashx?width=100&amp;height=100&amp;crop=5&FillCanvas=True&DoNotUpscale=true&amp;Compression=75&amp;image=" + alternativeImage.GetString("Ecom:Product.AlternativeImages.Image"); 220 221 <div class="carousel__container__slide product-slider__slide dw-mod"> 222 <div class="thumb-list__item dw-mod js-thumb-btn js-thumb js-gallery" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" data-image="@image"> 223 <label for="GalleryModalTrigger"> 224 <img src="@thumb" class="js-gallery" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="@thumbCounter" onclick="Gallery.openImage(this)" data-image="@image" data-src="@image"> 225 </label> 226 </div> 227 </div> 228 thumbCounter++; 229 } 230 } 231 232 @foreach (var youtubeLink in video.Split('|')) 233 { 234 if (!String.IsNullOrEmpty(youtubeLink)) 235 { 236 string image = String.Format("https://img.youtube.com/vi/{0}/0.jpg", youtubeLink.Split('?')); 237 string thumb = String.Format("https://img.youtube.com/vi/{0}/0.jpg", youtubeLink.Split('?')); 238 239 <div class="carousel__container__slide product-slider__slide dw-mod"> 240 <a class="d-block thumb-list__item has-video dw-mod js-thumb js-thumb-btn js-video-button js-gallery" data-icon-nz="play" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" data-image="@image" href="@youtubeLink" data-type="youtube" data-toggle="modal"> 241 <label for="GalleryModalTrigger"> 242 <img src="@thumb" class="js-gallery" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="@thumbCounter" onclick="Gallery.openImage(this)" data-image="@image" data-src="@image" data-cookieconsent="ignore"> 243 </label> 244 </a> 245 </div> 246 thumbCounter++; 247 } 248 } 249 250 @foreach (LoopItem detail in GetLoop("Details")) 251 { 252 if (!String.IsNullOrEmpty(detail.GetString("Ecom:Product:Detail.Image.Clean"))) 253 { 254 string image = "/Admin/Public/GetImage.ashx?width=550&amp;height=550&amp;crop=5&FillCanvas=True&DoNotUpscale=true&amp;Compression=75&amp;image=" + detail.GetString("Ecom:Product:Detail.Image.Clean"); 255 string thumb = "/Admin/Public/GetImage.ashx?width=100&amp;height=100&amp;crop=5&FillCanvas=True&DoNotUpscale=true&amp;Compression=75&amp;image=" + detail.GetString("Ecom:Product:Detail.Image.Clean"); 256 257 <div class="carousel__container__slide product-slider__slide dw-mod"> 258 <div class="thumb-list__item dw-mod js-thumb-btn js-thumb js-gallery" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" data-image="@image"> 259 <label for="GalleryModalTrigger"> 260 <img src="@thumb" class="js-gallery" alt="@GetString("Ecom:Product.Name")" data-for="FullImage" data-number="@thumbCounter" onclick="Gallery.openImage(this)" data-image="@image" data-src="@image"> 261 </label> 262 </div> 263 </div> 264 thumbCounter++; 265 } 266 } 267 </div> 268 </div> 269 270 <div class="js-carousel-data" data-total-slides="@(imagesCount + 1)" data-carousel-slide-time="0" data-current-slide="0" data-direction="vertical" data-sliding-type="items" slides-in-view="6"> 271 <div class="carousel-prev-btn carousel-prev-btn--vertical dw-mod" onclick="Carousel.GetPreviousSlide(this)"></div> 272 <div class="carousel-next-btn carousel-next-btn--vertical dw-mod" onclick="Carousel.GetNextSlide(this)"></div> 273 </div> 274 275 </div> 276 </div> 277 278 <div class="grid__col-10 product-slider__large-image"> 279 <div class="stickers-container dw-mod"> 280 @{ 281 if (Converter.ToBoolean(Pageview.Area.Item["EnableSaleTags"])) 282 { 283 string contentType = Pageview.Area.Item["EcommerceSaleTagContentType"].ToString(); 284 string text = ""; 285 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 286 287 switch (contentType) 288 { 289 case "Name": 290 foreach (LoopItem discount in GetLoop("ProductDiscounts")) 291 { 292 text = discount.GetString("Ecom:Product.Discount.Name"); 293 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 294 } 295 break; 296 case "Amount": 297 if (GetLoop("ProductDiscounts").Count > 0) 298 { 299 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, GetDouble("Ecom:Product.Discount.Price.Price") - GetDouble("Ecom:Product.Price.Price")); 300 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 301 } 302 break; 303 case "Percents": 304 double percents = 0; 305 foreach (LoopItem discount in GetLoop("ProductDiscounts")) 306 { 307 if (discount.GetDouble("Ecom:Product.Discount.ProductQuantity").Equals(1)) 308 { 309 percents = discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 310 } 311 } 312 if (percents > 0) 313 { 314 text = Math.Round(percents, 0) + "%"; 315 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 316 } 317 break; 318 case "Amount and percents": 319 double amount = 0; 320 double percent = 0; 321 foreach (LoopItem discount in GetLoop("ProductDiscounts")) 322 { 323 if (discount.GetString("Ecom:Product.Discount.Type") == "PERCENT") 324 { 325 percent += discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 326 } 327 else if (discount.GetString("Ecom:Product.Discount.Type") == "AMOUNT") 328 { 329 amount += discount.GetDouble("Ecom:Product.Discount.AmountWithVAT"); 330 } 331 } 332 if (percent > 0) 333 { 334 text = percent + "%"; 335 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 336 } 337 if (amount > 0) 338 { 339 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 340 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 341 } 342 break; 343 default: 344 if (GetLoop("ProductDiscounts").Count > 0) 345 { 346 text = Translate("Sale!"); 347 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 348 } 349 break; 350 } 351 } 352 353 if (Converter.ToBoolean(Pageview.Area.Item["NewStickersEnable"]) && GetDate("Ecom:Product.Created").AddDays(Converter.ToDouble(Pageview.Area.Item["NewStickersExpiration"])) > DateTime.Now) 354 { 355 <div class="stickers-container__tag stickers-container__tag--new dw-mod">@Translate("New!")</div> 356 } 357 358 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.CustomSticker.Value"))) 359 { 360 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@GetString("Ecom:Product:Field.CustomSticker.Value")</div> 361 } 362 } 363 </div> 364 365 <label for="GalleryModalTrigger" class="product__image-container"> 366 <img class="thumb-image-view product__image-container__image js-gallery-slider js-video-button dw-mod" src="/Admin/Public/GetImage.ashx?crop=5&width=550&height=550&Compression=75&image=@productImage" data-current-image="0" data-total-images="@imagesCount" data-images="@galleryImagesArray" data-src="/Admin/Public/GetImage.ashx?crop=5&width=550&height=550&Compression=75&image=@productImage" alt="@GetString("Ecom:Product.Name")" id="Image_@productId" data-for="FullImage" data-number="0" onclick="Gallery.openImageByNum(this)" /> 367 </label> 368 369 </div> 370 </div> 371 </div> 372 } 373 374 @* Primary product informations *@ 375 <div class="grid__col-12 grid__col-md-6 product__info dw-mod"> 376 <div> 377 <h1 class="product__title u-no-margin">@GetString("Ecom:Product.Name") @GetString("Ecom:Product.SelectedVariantComboName")</h1> 378 <small class="x-small text-gray-light font-weight-light">@(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.Brand")) ? String.Format("{0}: {1}", Translate("Manufacturer"), GetString("Ecom:Product:Field.Brand")) : "") @Translate("product number"): @GetString("Ecom:Product.Number") @(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.VVSNumber")) ? String.Format("{0}: {1}", Translate("VVS nr."), GetString("Ecom:Product:Field.VVSNumber")) : "") @(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.DBN")) ? String.Format("{0}: {1}", Translate("DB nr."), GetString("Ecom:Product:Field.DBN")) : "") </small> 379 <div> 380 @* Delivery + stock information *@ 381 @if (onlyPreview) 382 { 383 <div> 384 <h5 class="mb-2">@Translate("LoginText", "Login")</h5> 385 <label for="SignInModalTrigger" class="btn btn--primary u-no-margin sign-in-modal-trigger-button dw-mod" onclick="setTimeout(function() { document.getElementById('LoginUsername').focus() }, 10)">@Translate("Sign in")</label> 386 </div> 387 } 388 389 @* Variants *@ 390 @*@if (GetLoop("VariantGroups").Count > 0) 391 { 392 string containerId = "Variants" + productId; 393 394 <div> 395 <div id="@containerId" data-product-id="@productId"> 396 @foreach (LoopItem variantGoup in GetLoop("VariantGroups")) 397 { 398 <div> 399 <div class="u-bold">@variantGoup.GetString("Ecom:VariantGroup.Name")</div> 400 <div> 401 @foreach (LoopItem variantOption in variantGoup.GetLoop("VariantAvailableOptions")) 402 { 403 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 404 405 if (!string.IsNullOrEmpty(variantOption.GetString("Ecom:VariantOption.ImgSmall.Clean"))) 406 { 407 <img src="/Admin/Public/GetImage.ashx?width=100&amp;height=50&amp;crop=5&amp;Compression=75&amp;image=/Images/@variantOption.GetString("Ecom:VariantOption.ImgSmall.Clean")" title="@variantOption.GetString("Ecom:VariantOption.Name")" id="@productId@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-product-id="@productId" onclick="Variants.UpdateVariants(this, false, true)" class="btn btn--tag @selected" data-check="@selected" /> 408 } 409 else 410 { 411 <button type="button" data-id="@GetString("Ecom:Product.ID")" id="@productId@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-product-id="@productId" onclick="Variants.UpdateVariants(this, false, true)" class="btn btn--tag @selected" data-check="@selected">@variantOption.GetString("Ecom:VariantOption.Name")</button> 412 } 413 } 414 </div> 415 </div> 416 } 417 </div> 418 <small id="helpText_@productId" class="help-text @hideHelpText">@Translate("Please select variant!")</small> 419 </div> 420 }*@ 421 @if (GetLoop("VariantGroups").Count > 0) 422 { 423 var variantCombinationsObject = new List<Array>(); 424 foreach (LoopItem variantcomb in GetLoop("VariantStockCombinations")) 425 { 426 string[] combinations = variantcomb.GetString("Ecom:VariantStockCombination.VariantID").Split('.'); 427 variantCombinationsObject.Add(combinations); 428 } 429 430 string combinationsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantCombinationsObject).Replace("\"", "\'"); 431 432 var variantGroupsObject = new List<List<String>>(); 433 var selectedItem = new Dictionary<string, string>(); 434 string variantSelection = !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("variantId")) ? HttpContext.Current.Request.QueryString.Get("variantId").Replace(".", ",") : ""; 435 436 var selectedText = Translate("Select variant"); 437 438 foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 439 { 440 var variantsObject = new List<String>(); 441 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 442 { 443 variantsObject.Add(variantOption.GetString("Ecom:VariantOption.ID")); 444 445 446 if (variantOption.GetBoolean("Ecom:VariantOption.Selected")) 447 { 448 selectedItem.Add(variantGroup.GetString("Ecom:VariantGroup.ID"), variantOption.GetString("Ecom:VariantOption.Name")); 449 } 450 } 451 variantGroupsObject.Add(variantsObject); 452 } 453 string variantsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantGroupsObject).Replace("\"", "\'"); 454 string productGroupId = HttpContext.Current.Request["GroupId"]; 455 int variantCounter = 0; 456 457 <div class="variants-container"> 458 <div class="js-variants" data-total-variant-groups="@GetLoop("VariantGroups").Count" data-combinations="@combinationsJson" data-variants="@variantsJson" data-selection-complete="UpdatePage" data-page-id="@pageId" data-product-id="@productId" data-group-id="@productGroupId"> 459 @foreach (LoopItem variantGroup in GetLoop("VariantGroups")) 460 { 461 string groupId = variantGroup.GetString("Ecom:VariantGroup.ID"); 462 variantCounter++; 463 <div class="dropdown-container u-margin-bottom--lg"> 464 <div class="product__variant-group-name u-margin-bottom-5px dw-mod">@variantGroup.GetString("Ecom:VariantGroup.Name")</div> 465 <div class="display-value" id="displayValue-@variantCounter" onclick="toggleOptions('selectContainer-@variantCounter')"> 466 <span class="value-text" id="valueText-@variantCounter">@(selectedItem.ContainsKey(variantGroup.GetString("Ecom:VariantGroup.ID")) ? selectedItem[variantGroup.GetString("Ecom:VariantGroup.ID")] : selectedText)</span> 467 <span class="arrow arrow-down" id="arrowControl"></span> 468 </div> 469 <ul tabindex="0" class="select-container" id="selectContainer-@variantCounter" onblur="toggleOptions('selectContainer-@variantCounter')"> 470 @foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions")) 471 { 472 string selected = variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 473 474 475 476 <li value="@variantOption.GetString("Ecom:VariantOption.ID")" 477 type="button" 478 data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" 479 onclick="MatchVariants.SelectThis(event), selected('@variantOption.GetString("Ecom:VariantOption.Name")','valueText-@variantCounter', 'selectContainer-@variantCounter')" 480 data-variant-group="@groupId" 481 class="btn btn--tag @selected js-variant-option select-option" 482 data-check="@selected">@variantOption.GetString("Ecom:VariantOption.Name")</li> 483 } 484 </ul> 485 </div> 486 } 487 </div> 488 </div> 489 } 490 491 @* BOMProducts *@ 492 @if (GetLoop("BOMProducts").Count > 0) 493 { 494 <h2 class="section-title">@Translate("Including products")</h2> 495 foreach (LoopItem BOMProductItem in GetLoop("BOMProducts")) 496 { 497 string link = "/" + BOMProductItem.GetString("Ecom:Product.LinkGroup.Clean") + (!String.IsNullOrEmpty(BOMProductItem.GetString("Ecom:Product.VariantID")) ? "&VariantID=" + BOMProductItem.GetString("Ecom:Product.VariantID") : ""); 498 <div class="grid__col--border grid"> 499 <div class="grid__cell grid__cell--align-middle-left"> 500 <a href="@link" class="u-pull--left u-margin-right"> 501 <img src="/Admin/Public/GetImage.ashx?width=50&image=@BOMProductItem.GetString("Ecom:Product.ImageSmall.Default.Clean")&Compression=99" /> 502 </a> 503 <a href="@link">@BOMProductItem.GetString("Ecom:Product.Name")</a> 504 </div> 505 </div> 506 } 507 } 508 </div> 509 </div> 510 511 @* Buy block *@ 512 <div class="w-100 mt-5"> 513 <div class="js-handlebars-root dw-mod" id="PriceAndActions" data-template="PricesAndActionsTemplate" data-json-feed="/Default.aspx?ID=@feedId"></div> 514 <input type="hidden" value="@GetString("Ecom:Product.VariantID.Extented")" name="Variant" id="Variant_@GetString("Ecom:Product.ID")" /> 515 </div> 516 <div class="mt-4">@GetString("Ecom:Product:Field.LongDescription")</div> 517 <div class="product-page__specs">@ProductPropertiesMainArea()</div> 518 </div> 519 </div> 520 521 <section class="product-page__product-info"> 522 <div class="grid__col-12 grid__col-lg-9 m-auto"> 523 <div class="nav nav-pills nav-justified"> 524 <a class="nav-item nav-link js-toggle-class js-toggle-retrigger is-active" data-target-retrigger="target-retrigger" data-target=".product-page__content--description">@Translate("Product information")</a> 525 <a class="nav-item nav-link js-toggle-class js-toggle-retrigger" data-target-retrigger="target-retrigger" data-target=".product-page__content--video">@Translate("Documents/Video")</a> 526 <a class="nav-item nav-link js-toggle-class js-toggle-retrigger" data-target-retrigger="target-retrigger" data-target=".product-page__content--accessories">@Translate("Accessories")</a> 527 </div> 528 </div> 529 530 <div class="grid__col-12 grid__col-lg-10 m-auto grid__col--bleed-x"> 531 <div class="grid product-page__content product-page__content--description js-toggle-retrigger is-active"> 532 @* Features lists *@ 533 <div class="grid__col-12 grid__col-md-6 product__features dw-mod"> 534 <h1 class="h3 section-title">@Translate("Product information")</h1> 535 @GetString("Ecom:Product.LongDescription") 536 @GetString("Ecom:Product:Field.description") 537 </div> 538 <div class="grid__col-12 grid__col-md-6 product__features dw-mod"> 539 <h1 class="h3 section-title">@Translate("Product specs")</h1> 540 <div class="product-page__specs">@ProductProperties()</div> 541 </div> 542 </div> 543 <div class="grid product-page__content product-page__content--video js-toggle-retrigger justify-content-center"> 544 <div class="grid__col-12 grid__col-md-8 p-0 p-md-4"> 545 <h1 class="h3 section-title">@Translate("Documents/Video")</h1> 546 <div class="table-responsive small order-list"> 547 <table class="table table-striped product-page-table"> 548 <thead> 549 <tr> 550 <th class="font-weight-bold border-bottom-0" scope="col">@Translate("Name")</th> 551 <th class="font-weight-bold border-bottom-0" scope="col">@Translate("Type")</th> 552 <th class="font-weight-bold border-bottom-0" scope="col">@Translate("Size")</th> 553 </tr> 554 </thead> 555 <tbody> 556 557 @foreach (var documentPath in results) 558 { 559 <tr> 560 <td scope="row"> 561 <a href="@documentPath.FilePath" target="_blank"> 562 <img src="/Files/Images/Lauridsen/icons/icon-pdf.svg" class="product-page-table__icon d-inline-block align-middle mr-3" alt="@documentPath.FileName" /> 563 <span class="d-inline-block align-middle u-underline">@documentPath.FileName</span> 564 </a> 565 </td> 566 <td>@documentPath.FileType.Replace(".pdf", "PDF")</td> 567 <td>@documentPath.FileSize.ToSize(ByteExtension.SizeUnits.KB) KB</td> 568 </tr> 569 } 570 571 572 573 @foreach (var youtubeLink in video.Split('|')) 574 { 575 if (!String.IsNullOrEmpty(youtubeLink)) 576 { 577 int thumbCounter = 0; 578 string image = String.Format("https://img.youtube.com/vi/{0}/0.jpg", youtubeLink); 579 string thumb = String.Format("https://img.youtube.com/vi/{0}/0.jpg", youtubeLink); 580 <tr> 581 <td> 582 <div class="carousel__container__slide dw-mod"> 583 <a class="d-block dw-mod js-thumb-btn js-video-button" onmouseover="Gallery.openImage(this)" data-number="@thumbCounter" data-for="Image_@productId" href="@youtubeLink" data-type="youtube" data-toggle="modal"> 584 <label for="GalleryModalTrigger"> 585 <img src="/Files/Images/Lauridsen/icons/icon-video.svg" class="product-page-table__icon d-inline-block align-middle mr-4" alt="@GetString("Ecom:Product:Field.video")" /> 586 <span class="d-inline-block align-middle u-underline">@GetString("Ecom:Product:Field.video")</span> 587 </label> 588 </a> 589 </div> 590 </td> 591 <td>@GetString("Ecom:Product:Field.video.Name")</td> 592 <td>-</td> 593 </tr> 594 thumbCounter++; 595 } 596 } 597 598 599 600 @foreach (var value in testList) 601 { 602 603 if (externalLink.IsNotNullOrEmpty() && !string.IsNullOrWhiteSpace(value)) 604 { 605 <tr> 606 <td scope="row"> 607 <i class="product-page-table__icon d-inline-block align-middle mr-3 fa fa-link fa-2x"></i> 608 <span class="d-inline-block align-middle u-underline product-external-link">@value</span> 609 </td> 610 <td>@Translate("Link")</td> 611 <td>-</td> 612 </tr> 613 } 614 } 615 </tbody> 616 </table> 617 </div> 618 </div> 619 </div> 620 <div class="grid product-page__content product-page__content--accessories js-toggle-retrigger"> 621 <h1 class="h3 section-title">@Translate("Accessories")</h1> 622 <div class="grid accessories-list dw-mod"> 623 <form name="multiForm" id="multiForm" class="accessories-list__form js-load-more-container" data-initial-load="5" method="post"> 624 <input type="hidden" name="CartCmd" id="CartCmd" value="addMulti" /> 625 @foreach (LoopItem relatedGroup in GetLoop("ProductRelatedGroups").Where(group => group.GetString("Ecom:Product:RelatedGroup.Name") == "Tilbehør" || group.GetString("Ecom:Product:RelatedGroup.Name") == "Reservedele")) 626 { 627 foreach (LoopItem relatedProduct in relatedGroup.GetLoop("RelatedProducts")) 628 { 629 Dynamicweb.Ecommerce.Products.Product currentRelatedProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(relatedProduct.GetString("Ecom:Product.ID"), relatedProduct.GetString("Ecom:Product.VariantID"), relatedProduct.GetString("Ecom:Product.LanguageID")); 630 var relatedProductImagePathValue = Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(currentRelatedProduct, "ImagePath"); 631 string imgUrl = "/Files/Images/missing_image.jpg"; 632 string relatedProductImagePath = !string.IsNullOrWhiteSpace(relatedProductImagePathValue.ToString()) ? "/Files/Images/Ecom/LHI_Products/Images/" + relatedProductImagePathValue + ".jpg" : ""; 633 string relatedProductImage = !string.IsNullOrWhiteSpace(relatedProductImagePath) ? relatedProductImagePath : relatedProduct.GetString("Ecom:Product.ImageLarge.Default.Clean"); 634 635 if (!string.IsNullOrWhiteSpace(relatedProductImage)) 636 { 637 imgUrl = relatedProductImage; 638 } 639 640 string name = relatedProduct.GetString("Ecom:Product.Name"); 641 string number = relatedProduct.GetString("Ecom:Product.Number"); 642 string price = relatedProduct.GetString("Ecom:Product.Price"); 643 string groupId = relatedProduct.GetString("Ecom:Product.PrimaryGroupID"); 644 string id = relatedProduct.GetString("Ecom:Product.ID"); 645 var stock = relatedProduct.GetInteger("Ecom:Product.Stock"); 646 string stockText = relatedProduct.GetString("Ecom:Product:Stock.Text"); 647 string shortDescription = relatedProduct.GetString("Ecom:Product.ShortDescription"); 648 649 650 string link = "Default.aspx?" + "ID=" + GetInteger("Ecom:Product.PrimaryOrCurrentPageID") + "&GroupID=" + relatedProduct.GetString("Ecom:Product.PrimaryOrFirstGroupID") + "&ProductID=" + id; 651 List<Dynamicweb.Security.UserManagement.Group> userGroups = new List<Dynamicweb.Security.UserManagement.Group>(); 652 bool userisLoggedIn = Dynamicweb.Security.UserManagement.User.IsExtranetUserLoggedIn(); 653 bool isEmpty = !userGroups.Any(); 654 655 if (isEmpty && Dynamicweb.Security.UserManagement.User.IsExtranetUserLoggedIn()) 656 { 657 userGroups = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser().Groups.ToList(); 658 } 659 660 <div class="accessories-list__item accessorie grid__col-12 grid__col--bleed-x js-load-more-item is-hidden"> 661 <div class="grid"> 662 <figure class="grid__col-sm-2 grid__col-12 accessorie__figure"> 663 <div class="stickers-container dw-mod"> 664 665 666 667 @if (Converter.ToBoolean(Pageview.Area.Item["EnableSaleTags"])) 668 { 669 string contentType = Pageview.Area.Item["EcommerceSaleTagContentType"].ToString(); 670 string text = ""; 671 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 672 673 674 switch (contentType) 675 { 676 case "Name": 677 foreach (LoopItem relatedDiscounts in GetLoop("ProductDiscounts")) 678 { 679 text = relatedDiscounts.GetString("Ecom:Product.Discount.Name"); 680 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 681 } 682 break; 683 case "Amount": 684 if (GetLoop("ProductDiscounts").Count > 0) 685 { 686 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, GetDouble("Ecom:Product.Discount.Price.Price") - GetDouble("Ecom:Product.Price.Price")); 687 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 688 } 689 break; 690 case "Percents": 691 double percents = 0; 692 if (relatedProduct.GetLoop("ProductDiscounts").Count > 0) 693 { 694 foreach (LoopItem discount in relatedProduct.GetLoop("ProductDiscounts")) 695 { 696 if (discount.GetDouble("Ecom:Product.Discount.ProductQuantity") == 1) 697 { 698 percents = discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 699 } 700 } 701 if (percents > 0) 702 { 703 text = Math.Round(percents, 0) + "%"; 704 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 705 } 706 707 708 } 709 break; 710 case "Amount and percents": 711 double amount = 0; 712 double percent = 0; 713 foreach (LoopItem relatedDiscounts in GetLoop("ProductDiscounts")) 714 { 715 if (relatedDiscounts.GetString("Ecom:Product.Discount.Type") == "PERCENT") 716 { 717 percent += relatedDiscounts.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 718 } 719 else if (relatedDiscounts.GetString("Ecom:Product.Discount.Type") == "AMOUNT") 720 { 721 amount += relatedDiscounts.GetDouble("Ecom:Product.Discount.AmountWithVAT"); 722 } 723 } 724 if (percent > 0) 725 { 726 text = percent + "%"; 727 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 728 } 729 if (amount > 0) 730 { 731 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 732 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 733 } 734 break; 735 default: 736 if (GetLoop("ProductDiscounts").Count > 0) 737 { 738 text = Translate("Sale!"); 739 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 740 } 741 break; 742 } 743 744 745 if (Converter.ToBoolean(Pageview.Area.Item["NewStickersEnable"]) && GetDate("Ecom:Product.Created").AddDays(Converter.ToDouble(Pageview.Area.Item["NewStickersExpiration"])) > DateTime.Now) 746 { 747 <div class="stickers-container__tag stickers-container__tag--new dw-mod">@Translate("New!")</div> 748 } 749 750 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.CustomSticker.Value"))) 751 { 752 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@GetString("Ecom:Product:Field.CustomSticker.Value")</div> 753 } 754 755 } 756 </div> 757 <div class="grid__cell"> 758 <a href="@link" onclick="Scroll.SavePosition(event)" title="@name"> 759 <img class="grid__cell-img accessorie__image" 760 src="/Admin/Public/GetImage.ashx?width=350&amp;height=350&amp;crop=5&amp;Compression=75&amp;DoNotUpscale=true&amp;image=@imgUrl" 761 alt="@name" /> 762 </a> 763 </div> 764 </figure> 765 <div class="grid__col-12 grid__col-sm-4 accessorie__description"> 766 <a class="" href="@link" onclick="Scroll.SavePosition(event)" title="@name"> 767 <div class="accessorie__number"><b>Vare nr.</b> @number</div> 768 <h3 class="accessorie__name">@name</h3> 769 <div class="accessorie__text">@shortDescription</div> 770 <div class="product-list-item__stock"> 771 <div class="stock-icon ml-0 @(stock > 0 ? "stock-icon--in" : "stock-icon--not")"></div> 772 <span>@stockText</span> 773 </div> 774 <span class="product-card__quantity-alert js-product-quantity-error-@id ">@Translate("Max stock level is reached")</span> 775 </a> 776 </div> 777 778 @if (!onlyPreview) 779 { 780 List<Price> priceCollectionList = new List<Price>(); 781 List<Price> getLowestPriceList = new List<Price>(); 782 List<Price> orderedPriceList = new List<Price>(); 783 List<Price> getPriceCollection = new List<Price>(); 784 785 if (userisLoggedIn) 786 { 787 if (currentProduct.Prices.ToList().Any()) 788 { 789 priceCollectionList = currentProduct.Prices.ToList(); 790 } 791 792 string userPriceGroups = string.Empty; 793 if (userGroups.Any()) 794 { 795 <div class=" grid__col-12 grid__col-sm-3 accessorie__details" style="text-align: center"> 796 @foreach (Price priceItem in priceCollectionList.Where(priceItem => priceItem.ProductId.Equals(uniqueId))) 797 { 798 if (Int32.TryParse(priceItem.UserGroupId, out int priceUserGroupId)) 799 { 800 foreach (Dynamicweb.Security.UserManagement.Group userGroupItem in userGroups.Where(userGroup => userGroup.ID.Equals(priceUserGroupId))) 801 { 802 userPriceGroups = userGroupItem.ID.ToString(); 803 if (userPriceGroups != null && priceCollectionList != null) 804 { 805 Price getLowest = priceCollectionList.Where(priceGroup => priceGroup.UserGroupId.Contains(userPriceGroups)).OrderBy(sortQuantity => sortQuantity.Quantity).ThenBy(sortOrder => sortOrder.Amount).ToList().FirstOrDefault(); 806 getLowestPriceList.Add(getLowest); 807 getPriceCollection = priceCollectionList.Where(priceGroup => priceGroup.UserGroupId.Contains(userPriceGroups)).ToList(); 808 if (getPriceCollection.Exists(check => check.Quantity > 2) && getPriceCollection != null) 809 { 810 orderedPriceList.Add(getPriceCollection.FirstOrDefault()); 811 } 812 } 813 } 814 } 815 } 816 @if (userPriceGroups != null && getLowestPriceList.Any()) 817 { 818 string priceWithDiscount = relatedProduct.GetString("Ecom:Product.Discount.Price.PriceFormatted"); 819 820 Price getLowestPrice = getLowestPriceList.OrderBy(lowerPrice => lowerPrice.Amount).ToList().FirstOrDefault(); 821 if (getLowestPrice.Quantity < 2) 822 { 823 <div class="accessorie__price price">@priceWithDiscount</div> 824 <div class=""> 825 @Translate("UnitPriceText") @getLowestPrice.Quantity @vismaUnitName 826 </div> 827 } 828 829 List<LoopItem> priceLoop = relatedProduct.GetLoop("Product.Prices"); 830 if (priceLoop.Any(x => x.GetDouble("Ecom:Product.Prices.Quantity") > 1)) 831 { 832 <div class="js-popup"> 833 834 <a class="js-popup-trigger">@Translate("DiscountText")</a> 835 <div class="js-popup-modal popup_productrelatedview"> 836 <div class="js-popout-close nz-icon icon-nz-close-circled"></div> 837 <ul class="grid__col-12 pt-5 p-0 d-flex flex-row flex-wrap"> 838 839 @foreach (LoopItem priceItem in priceLoop.Where(x => x.GetDouble("Ecom:Product.Prices.Quantity") > 1)) 840 { 841 string relatedVismaUnitName = !string.IsNullOrWhiteSpace(priceItem.GetString("Ecom:Product:Field.Enhed")) ? priceItem.GetString("Ecom:Product:Field.Enhed")?.ToLower() : Translate("UnitPriceTextStk"); 842 <li class="grid__col-lg-6 p-0 mb-0 grid__col-12 align-items-center align-items-xl-start">@Translate("UnitPriceText") @priceItem.GetDouble("Ecom:Product.Prices.Quantity") @relatedVismaUnitName</li> 843 <li class="grid__col-lg-6 p-0 pb-3 grid__col-12 align-items-center align-items-xl-end">@priceItem.GetString("Ecom:Product.Prices.AmountFormatted")</li> 844 } 845 </ul> 846 </div> 847 </div> 848 } 849 } 850 851 </div> 852 if (getLowestPriceList.Any()) 853 { 854 855 if (relatedProduct.GetLoop("VariantGroups").Count > 0) 856 { 857 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 858 <div class="accessorie__controls-inner"> 859 860 <a href="@link" class="btn btn-secondary dw-mod js-scroll-btn d-inline-block px-5">@Translate("Select variant")</a> 861 </div> 862 </div> 863 864 } 865 else 866 { 867 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 868 <div class="accessorie__controls-inner"> 869 <div class="accessorie__button-container d-inline-block"> 870 <button type="button" id="CartButton_@id" class="btn btn--primary accessorie__cart" name="submit" onclick="Cart.AddToCart(event, '@id', document.getElementById('Quantity_@id').value, 'Unit_@id', 'Variant_@id');"> 871 <i class="fa fa-shopping-cart"></i> 872 <span class="u-hidden-xs u-hidden-xxs"> @Translate("Add to cart")</span> 873 </button> 874 </div> 875 876 <div class="product-card__quantity--condenced product-card__quantity accessorie__quantity"> 877 <input id="Quantity_@id" class="product-card__quantity-input pointer-events js-quantity-input" name="Quantity@accessoriesProduct.Id" data-id="@id" type="number" min="1" max="@stock" value="1"> 878 <span class="product-card__quantity-add js-product-quantity-add" data-icon-nz="chevron-up"></span> 879 <span class="product-card__quantity-subtract js-product-quantity-subtract" data-icon-nz="chevron-down"></span> 880 </div> 881 882 </div> 883 </div> 884 } 885 } 886 else 887 { 888 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 889 <div class="accessorie__controls-inner"> 890 <div class="accessorie__button-container d-inline-block"> 891 <button type="button" id="CartButton_@id" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" name="submit" data-target=".js-target"> 892 <span class="u-hidden-xs u-hidden-xxs"> @Translate("CallForPrice")</span> 893 </button> 894 </div> 895 </div> 896 </div> 897 } 898 } 899 else 900 { 901 <div class=" grid__col-12 grid__col-sm-3 accessorie__details" style="text-align: center"> 902 <div class="accessorie__price price"></div> 903 <div class="accessorie__before-price before-price "></div> 904 <div class=""> 905 </div> 906 <div class="js-popup"> 907 <div class="js-popup-modal popup_productrelatedview"> 908 <div class="js-popout-close nz-icon icon-nz-close-circled"></div> 909 </div> 910 </div> 911 </div> 912 if (getLowestPriceList.Any()) 913 { 914 915 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 916 <div class="accessorie__controls-inner"> 917 918 <div class="accessorie__button-container d-inline-block"> 919 <button type="button" id="CartButton_@id" class="btn btn--primary accessorie__cart" name="submit" onclick="Cart.AddToCart(event, '@id', document.getElementById('Quantity_@id').value, 'Unit_@id', 'Variant_@id');"> 920 <i class="fa fa-shopping-cart"></i> 921 <span class="u-hidden-xs u-hidden-xxs"> @Translate("Add to cart")</span> 922 </button> 923 </div> 924 925 <div class="product-card__quantity--condenced product-card__quantity accessorie__quantity"> 926 <input id="Quantity_@id" class="product-card__quantity-input pointer-events js-quantity-input" name="Quantity@accessoriesProduct.Id" data-id="@id" type="number" min="1" max="@stock" value="1"> 927 <span class="product-card__quantity-add js-product-quantity-add" data-icon-nz="chevron-up"></span> 928 <span class="product-card__quantity-subtract js-product-quantity-subtract" data-icon-nz="chevron-down"></span> 929 </div> 930 931 </div> 932 </div> 933 } 934 else 935 { 936 937 <div class="grid__col-12 grid__col-sm-3 accessorie__controls"> 938 <div class="accessorie__controls-inner"> 939 <div class="accessorie__button-container d-inline-block"> 940 <button type="button" id="CartButton_@id" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" name="submit" data-target=".js-target"> 941 <span class="u-hidden-xs u-hidden-xxs"> @Translate("CallForPrice")</span> 942 </button> 943 </div> 944 </div> 945 </div> 946 } 947 } 948 } 949 } 950 else 951 { 952 <div class="grid__col-12 grid__col-sm-6 align-items-center align-items-lg-end"> 953 <div class="grid__cell"> 954 <div class="grid__col-12 pb-0"> 955 <h5>@Translate("LoginText")</h5> 956 </div> 957 <div class="grid__col-12 pb-0"> 958 <label for="SignInModalTrigger" class="btn btn--primary u-no-margin sign-in-modal-trigger-button dw-mod" onclick="setTimeout(function() { document.getElementById('LoginUsername').focus() }, 10)">@Translate("Sign in")</label> 959 </div> 960 </div> 961 </div> 962 } 963 </div> 964 </div> 965 } 966 } 967 <div class="grid__col--bleed-y mb-6"> 968 <a class="btn btn-teritary btn--load-more js-load-more-trigger dw-mod">@Translate("Load more")</a> 969 </div> 970 </form> 971 </div> 972 </div> 973 </div> 974 </section> 975 @if (GetLoop("ProductRelatedGroups").Any()) 976 { 977 <section class="related-products"> 978 <div class="grid related-products__inner-container"> 979 980 <div class="grid__col-xs-12 related-products__headline-container"> 981 <h2 class="related-products__headline h2 section-title section-title--condensed">@Translate("Related products")</h2> 982 </div> 983 984 <div class="grid__col-12 grid__col-md-10 grid__col--bleed m-auto"> 985 <div class="grid"> 986 987 @foreach (LoopItem relatedGroup in GetLoop("ProductRelatedGroups").Where(group => group.GetString("Ecom:Product:RelatedGroup.Name") == "Relaterede produkter")) 988 { 989 foreach (LoopItem related in relatedGroup.GetLoop("RelatedProducts")) 990 { 991 Dynamicweb.Ecommerce.Products.Product currentRelatedProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(related.GetString("Ecom:Product.ID"), related.GetString("Ecom:Product.VariantID"), related.GetString("Ecom:Product.LanguageID")); 992 var relatedProductImagePathValue = Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(currentRelatedProduct, "ImagePath"); 993 string imgUrl = "/Files/Images/missing_image.jpg"; 994 string relatedProductImagePath = !string.IsNullOrWhiteSpace(relatedProductImagePathValue.ToString()) ? "/Files/Images/Ecom/LHI_Products/Images/" + relatedProductImagePathValue + ".jpg" : ""; 995 string relatedProductImage = !string.IsNullOrWhiteSpace(relatedProductImagePath) ? relatedProductImagePath : related.GetString("Ecom:Product.ImageLarge.Default.Clean"); 996 997 if (!string.IsNullOrWhiteSpace(relatedProductImage)) 998 { 999 imgUrl = relatedProductImage; 1000 } 1001 1002 string name = related.GetString("Ecom:Product.Name"); 1003 string number = related.GetString("Ecom:Product.Number"); 1004 string price = related.GetString("Ecom:Product.Price"); 1005 string groupId = related.GetString("Ecom:Product.PrimaryGroupID"); 1006 string id = related.GetString("Ecom:Product.ID"); 1007 var stock = related.GetInteger("Ecom:Product.Stock"); 1008 string stockText = related.GetString("Ecom:Product:Stock.Text"); 1009 1010 <div class="grid__col-12 grid__col-sm-6 grid__col-lg-3"> 1011 <div class="related-products__product related-product"> 1012 <a href="@related.GetString("Ecom:Product.Link.Clean")"> 1013 <div class="stickers-container dw-mod"> 1014 1015 @if (Converter.ToBoolean(Pageview.Area.Item["EnableSaleTags"])) 1016 { 1017 string contentType = Pageview.Area.Item["EcommerceSaleTagContentType"].ToString(); 1018 string text = ""; 1019 var currency = Dynamicweb.Ecommerce.Services.Currencies.GetDefaultCurrency(); 1020 1021 1022 switch (contentType) 1023 { 1024 case "Name": 1025 foreach (LoopItem relatedDiscounts in GetLoop("ProductDiscounts")) 1026 { 1027 text = relatedDiscounts.GetString("Ecom:Product.Discount.Name"); 1028 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1029 } 1030 break; 1031 case "Amount": 1032 if (GetLoop("ProductDiscounts").Count > 0) 1033 { 1034 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, GetDouble("Ecom:Product.Discount.Price.Price") - GetDouble("Ecom:Product.Price.Price")); 1035 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1036 } 1037 break; 1038 case "Percents": 1039 double percents = 0; 1040 if (related.GetLoop("ProductDiscounts").Count > 0) 1041 { 1042 foreach (LoopItem discount in related.GetLoop("ProductDiscounts")) 1043 { 1044 if (discount.GetDouble("Ecom:Product.Discount.ProductQuantity") == 1) 1045 { 1046 percents = discount.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 1047 } 1048 } 1049 if (percents > 0) 1050 { 1051 text = Math.Round(percents, 0) + "%"; 1052 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1053 } 1054 1055 1056 } 1057 break; 1058 case "Amount and percents": 1059 double amount = 0; 1060 double percent = 0; 1061 foreach (LoopItem relatedDiscounts in GetLoop("ProductDiscounts")) 1062 { 1063 if (relatedDiscounts.GetString("Ecom:Product.Discount.Type") == "PERCENT") 1064 { 1065 percent += relatedDiscounts.GetDouble("Ecom:Product.Discount.PercentWithoutVAT"); 1066 } 1067 else if (relatedDiscounts.GetString("Ecom:Product.Discount.Type") == "AMOUNT") 1068 { 1069 amount += relatedDiscounts.GetDouble("Ecom:Product.Discount.AmountWithVAT"); 1070 } 1071 } 1072 if (percent > 0) 1073 { 1074 text = percent + "%"; 1075 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1076 } 1077 if (amount > 0) 1078 { 1079 text = Dynamicweb.Ecommerce.Services.Currencies.Format(currency, amount); 1080 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1081 } 1082 break; 1083 default: 1084 if (GetLoop("ProductDiscounts").Count > 0) 1085 { 1086 text = Translate("Sale!"); 1087 <div class="stickers-container__tag stickers-container__tag--sale dw-mod">@text</div> 1088 } 1089 break; 1090 } 1091 1092 1093 if (Converter.ToBoolean(Pageview.Area.Item["NewStickersEnable"]) && GetDate("Ecom:Product.Created").AddDays(Converter.ToDouble(Pageview.Area.Item["NewStickersExpiration"])) > DateTime.Now) 1094 { 1095 <div class="stickers-container__tag stickers-container__tag--new dw-mod">@Translate("New!")</div> 1096 } 1097 1098 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.CustomSticker.Value"))) 1099 { 1100 <div class="stickers-container__tag stickers-container__tag--custom dw-mod">@GetString("Ecom:Product:Field.CustomSticker.Value")</div> 1101 } 1102 1103 } 1104 1105 1106 </div> 1107 <img class="related-product__image b-lazy" src="/Files/Images/placeholder.gif" data-src="/Admin/Public/GetImage.ashx?width=350&amp;height=350&amp;crop=5&amp;Compression=75&amp;DoNotUpscale=true&amp;image=@imgUrl" alt="@name" /> 1108 <h4 class="related-product__name">@name</h4> 1109 <div class="related-product__number">@Translate("product number") @number</div> 1110 1111 <div class="product-list-item__stock"> 1112 <div class="stock-icon ml-0 @(stock > 0 ? "stock-icon--in" : "stock-icon--not")"></div> 1113 <span>@stockText</span> 1114 </div> 1115 1116 <span class="product-card__quantity-alert js-product-quantity-error-@id ">@Translate("Max stock level is reached")</span> 1117 </a> 1118 1119 @if (!onlyPreview) 1120 { 1121 string priceWithDiscount = related.GetString("Ecom:Product.Discount.Price.Price"); 1122 string currencySymbol = related.GetString("Ecom:Product.Currency.Symbol"); 1123 string priceWithOutDiscount = related.GetString("Ecom:Product.Price.Price"); 1124 bool productHasDiscount = GetBoolean("Ecom:Product.HaveDiscount"); 1125 1126 <div class="related-product__button-container d-inline-block"> 1127 @if (priceWithDiscount != "0,00" || priceWithOutDiscount != "0,00") 1128 { 1129 if (GetString("Ecom:Product.Discount.TotalAmount") != "DKK 0,00") 1130 { 1131 <div class="related-product__price withdiscount">@currencySymbol @priceWithDiscount</div> 1132 } 1133 1134 else 1135 { 1136 <div class="related-product__price withoutdiscount">@currencySymbol @priceWithOutDiscount</div> 1137 } 1138 1139 List<LoopItem> priceLoop = related.GetLoop("Product.Prices"); 1140 if (priceLoop.Any(x => x.GetDouble("Ecom:Product.Prices.Quantity") > 1)) 1141 { 1142 <div class="js-popup"> 1143 <a class="js-popup-trigger">@Translate("DiscountText")</a> 1144 <div class="js-popup-modal popup_productrelatedview"> 1145 <div class="js-popout-close nz-icon icon-nz-close-circled"></div> 1146 <ul class="grid__col-12 pt-5 p-0 d-flex flex-row flex-wrap"> 1147 1148 @foreach (LoopItem priceItem in priceLoop.Where(x => x.GetDouble("Ecom:Product.Prices.Quantity") > 1)) 1149 { 1150 <li class="grid__col-lg-6 p-0 mb-0 grid__col-12 align-items-center align-items-xl-start">@Translate("UnitPriceText") @priceItem.GetDouble("Ecom:Product.Prices.Quantity") @Translate("UnitPriceTextStk")</li> 1151 <li class="grid__col-lg-6 p-0 pb-3 grid__col-12 align-items-center align-items-xl-end">@priceItem.GetString("Ecom:Product.Prices.AmountFormatted")</li> 1152 } 1153 </ul> 1154 </div> 1155 </div> 1156 } 1157 1158 if (related.GetLoop("VariantGroups").Count > 0) 1159 { 1160 <div class="related-product__controls"> 1161 1162 1163 <a href="@related.GetString("Ecom:Product.Link.Clean")" class="btn btn-secondary dw-mod js-scroll-btn d-inline-block px-5">@Translate("Select variant")</a> 1164 1165 </div> 1166 1167 } 1168 else 1169 { 1170 <div class="related-product__controls"> 1171 <div class="product-card__quantity--condenced product-card__quantity related-product__quantity"> 1172 <input id="Quantity_@id" class="product-card__quantity-input pointer-events js-quantity-input" name="Quantity@id" data-id="@id" type="number" min="1" max="@stock" value="1"> 1173 <span class="product-card__quantity-add js-product-quantity-add" data-icon-nz="chevron-up"></span> 1174 <span class="product-card__quantity-subtract js-product-quantity-subtract" data-icon-nz="chevron-down"></span> 1175 </div> 1176 <button type="button" id="CartButton_@id" class="btn btn--primary related-product__cart" name="submit" onclick="Cart.AddToCart(event, '@id', document.getElementById('Quantity_@id').value, 'Unit_@id', 'Variant_@id');"> 1177 <i class="fa fa-shopping-cart"></i> 1178 <span class="u-hidden-xs u-hidden-xxs"> @Translate("Add to cart")</span> 1179 </button> 1180 </div> 1181 } 1182 1183 1184 } 1185 else 1186 { 1187 <button type="button" id="CartButton_@id" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" name="submit" data-target=".js-target"> 1188 <span class="u-hidden-xs u-hidden-xxs"> @Translate("CallForPrice")</span> 1189 </button> 1190 } 1191 </div> 1192 1193 1194 } 1195 else 1196 { 1197 <div class="related-product__login-label">@Translate("LoginText")</div> 1198 <label for="SignInModalTrigger" class="btn btn--primary u-no-margin sign-in-modal-trigger-button dw-mod related-product__login" onclick="setTimeout(function () { document.getElementById('LoginUsername').focus() }, 10)">@Translate("Sign in")</label> 1199 } 1200 1201 1202 </div> 1203 </div> 1204 1205 1206 1207 1208 } 1209 1210 } 1211 1212 </div> 1213 </div> 1214 </div> 1215 </section> 1216 1217 1218 1219 } 1220 </div> 1221 1222 @* 1223 @if(GetLoop("eCom:Related.CustomersWhoSawThisAlsoSaw").Any()) 1224 { 1225 foreach (LoopItem item in GetLoop("eCom:Related.CustomersWhoSawThisAlsoSaw")) 1226 { 1227 relatedProductsFeed += item.GetString("Ecom:Product.ID"); 1228 relatedProductsFeed += ""; 1229 } 1230 1231 <div class="grid"> 1232 <div class="grid__col-12"> 1233 <div class="bg-gray bg-gray-full-width"> 1234 <h2 class="h1 section-title section-title--condensed">@Translate("ecom-related-products-3", "Related products")</h2> 1235 <div class="js-handlebars-root" id="ProductList_@productId" data-template="ProductContainer" data-pre-render-template="ProductPreRenderContainer" data-json-feed="@relatedProductsFeed" data-preloader="overlay"></div> 1236 </div> 1237 </div> 1238 </div> 1239 } 1240 *@ 1241 1242 @helper ProductPropertiesMainArea() 1243 { 1244 if (GetLoop("CustomFieldValues").Count > 0) 1245 { 1246 var visibleCount = 0; 1247 1248 <div class="specs-list specs-list--5"> 1249 <dl class="table table--clean table--compact product-page__specs-list"> 1250 @foreach (LoopItem customField in GetLoop("CustomFieldValues").Where(customField => customField.GetString("Product.CustomField.System") != "description").Where(customField => customField.GetString("Product.CustomField.System") != "LongDescription").Where(customField => customField.GetString("Product.CustomField.System") != "ShortDescription")) 1251 { 1252 string fieldValue = customField.GetString("Product.CustomField.Value.Clean"); 1253 1254 if (customField.GetLoop("Product.CustomField.Options").Count > 0) 1255 { 1256 fieldValue = ""; 1257 int count = 0; 1258 1259 foreach (LoopItem customFieldOptions in customField.GetLoop("Product.CustomField.Options").Where(customFieldOptions => !string.IsNullOrWhiteSpace(customFieldOptions.GetString("Product.CustomField.Option.Name")))) 1260 { 1261 if (customFieldOptions.GetBoolean("Product.CustomField.Option.IsSelected")) 1262 { 1263 if (count != 0) 1264 { 1265 fieldValue += ", "; 1266 } 1267 1268 fieldValue += customFieldOptions.GetString("Product.CustomField.Option.Name"); 1269 count++; 1270 } 1271 } 1272 } 1273 1274 if (fieldValue == "False") 1275 { 1276 fieldValue = Translate("No"); 1277 } 1278 1279 if (fieldValue == "True") 1280 { 1281 fieldValue = Translate("Yes"); 1282 } 1283 1284 1285 if (!String.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) 1286 && !String.IsNullOrWhiteSpace(fieldValue) 1287 && customField.GetString("Product.CustomField.Name") != "Custom sticker" 1288 && customField.GetString("Product.CustomField.Name").Contains("Produkt tekst") == true) 1289 { 1290 if (!String.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 1291 { 1292 visibleCount++; 1293 <dd class="product-page__specs-value"><a href="@customField.GetString("Document.FullPath")" download title="@Translate("Download")" class="product__document"><span property="identifier">@getIconForFile(fieldValue) @Path.GetFileName(fieldValue)</span></a></dd> 1294 } 1295 else 1296 { 1297 visibleCount++; 1298 <dd class="product-page__specs-value"><span property="identifier">@fieldValue</span></dd> 1299 } 1300 } 1301 } 1302 </dl> 1303 1304 @if (visibleCount > 5) 1305 { 1306 <div class="js-load-more-specs specs-list__trigger"> 1307 <span class="specs-list__load-more">@Translate("Show more")</span> 1308 <span class="specs-list__load-less">@Translate("Show less")</span> 1309 </div> 1310 } 1311 1312 </div> 1313 } 1314 } 1315 @helper ProductProperties() 1316 { 1317 if (GetLoop("CustomFieldValues").Count > 0) 1318 { 1319 var visibleCount = 0; 1320 1321 <div class="specs-list specs-list--10"> 1322 <dl class="table table--clean table--compact product-page__specs-list"> 1323 @foreach (LoopItem customField in GetLoop("CustomFieldValues").Where(customField => customField.GetString("Product.CustomField.System") != "description").Where(customField => customField.GetString("Product.CustomField.System") != "LongDescription").Where(customField => customField.GetString("Product.CustomField.System") != "ShortDescription")) 1324 { 1325 string fieldValue = customField.GetString("Product.CustomField.Value.Clean"); 1326 1327 if (customField.GetLoop("Product.CustomField.Options").Count > 0) 1328 { 1329 fieldValue = ""; 1330 int count = 0; 1331 1332 foreach (LoopItem customFieldOptions in customField.GetLoop("Product.CustomField.Options").Where(customFieldOptions => !string.IsNullOrWhiteSpace(customFieldOptions.GetString("Product.CustomField.Option.Name")))) 1333 { 1334 if (customFieldOptions.GetBoolean("Product.CustomField.Option.IsSelected")) 1335 { 1336 if (count != 0) 1337 { 1338 fieldValue += ", "; 1339 } 1340 1341 fieldValue += customFieldOptions.GetString("Product.CustomField.Option.Name"); 1342 count++; 1343 } 1344 } 1345 } 1346 if (fieldValue == "False") 1347 { 1348 fieldValue = Translate("No"); 1349 } 1350 1351 if (fieldValue == "True") 1352 { 1353 fieldValue = Translate("Yes"); 1354 } 1355 1356 if (!String.IsNullOrEmpty(customField.GetString("Product.CustomField.Name")) 1357 && !String.IsNullOrWhiteSpace(fieldValue) 1358 && customField.GetString("Product.CustomField.Name") != "Custom sticker" 1359 && !customField.GetString("Product.CustomField.Name").Contains("Produktions ansvarlig") 1360 && !customField.GetString("Product.CustomField.Name").Contains("Video") 1361 && !customField.GetString("Product.CustomField.Name").Contains("PDF") 1362 && !customField.GetString("Product.CustomField.Name").Contains("Lokation") 1363 && !customField.GetString("Product.CustomField.Name").Contains("Status") 1364 && !customField.GetString("Product.CustomField.Name").Contains("Produktgr. (CO)") 1365 && !customField.GetString("Product.CustomField.Name").Contains("Produktprisgr. 1 (rabatgruppe)") 1366 && !customField.GetString("Product.CustomField.Name").Contains("Prisliste") 1367 && !customField.GetString("Product.CustomField.Name").Contains("Godkendelse") 1368 && !customField.GetString("Product.CustomField.Name").Contains("Salgsstatistik") 1369 && !customField.GetString("Product.CustomField.Name").Contains("ABC") 1370 && !customField.GetString("Product.CustomField.Name").Contains("Billedefilnr (LFR)") 1371 && !customField.GetString("Product.CustomField.Name").Contains("Rabat gruppe 2") 1372 && !customField.GetString("Product.CustomField.Name").Contains("Visma changed by user") 1373 && !customField.GetString("Product.CustomField.Name").Contains("Visma changed date") 1374 && customField.GetString("Product.CustomField.Value") != "0" 1375 && customField.GetString("Product.CustomField.Value") != "" 1376 && customField.GetString("Product.CustomField.Name").Contains("Produkt tekst") != true) 1377 { 1378 <dt class="product-page__specs-display" width="160">@Translate(customField.GetString("Product.CustomField.Name")): </dt> 1379 if (!String.IsNullOrEmpty(customField.GetString("Document.FullPath"))) 1380 { 1381 visibleCount++; 1382 <dd class="text-right product-page__specs-value"><a href="@customField.GetString("Document.FullPath")" download title="@Translate("Download")" class="product__document"><span property="identifier">@getIconForFile(fieldValue) @Path.GetFileName(fieldValue)</span></a></dd> 1383 } 1384 else 1385 { 1386 visibleCount++; 1387 <dd class="text-right product-page__specs-value"><span property="identifier">@fieldValue</span></dd> 1388 } 1389 } 1390 } 1391 </dl> 1392 1393 @if (visibleCount > 10) 1394 { 1395 <div class="js-load-more-specs specs-list__trigger"> 1396 <span class="specs-list__load-more">@Translate("Show more")</span> 1397 <span class="specs-list__load-less">@Translate("Show less")</span> 1398 </div> 1399 } 1400 </div> 1401 } 1402 1403 if (GetLoop("ProductCategories").Count > 0) 1404 { 1405 <dl class="product-page__specs-list"> 1406 @foreach (LoopItem categoryGroup in GetLoop("ProductCategories")) 1407 { 1408 int fieldsCount = 0; 1409 foreach (LoopItem categoryField in categoryGroup.GetLoop("ProductCategoryFields")) 1410 { 1411 if (!String.IsNullOrEmpty(categoryField.GetString("Ecom:Product.CategoryField.Value"))) 1412 { 1413 fieldsCount++; 1414 } 1415 } 1416 if (fieldsCount > 0) 1417 { 1418 <dd class="product-page__specs-display">@categoryGroup.GetString("Ecom:Product.Category.Name")</dd> 1419 1420 foreach (LoopItem categoryField in categoryGroup.GetLoop("ProductCategoryFields")) 1421 { 1422 string fieldValue = categoryField.GetString("Ecom:Product.CategoryField.Value"); 1423 1424 if (fieldValue == "False") 1425 { 1426 fieldValue = Translate("No"); 1427 } 1428 1429 if (fieldValue == "True") 1430 { 1431 fieldValue = Translate("Yes"); 1432 } 1433 1434 if (!String.IsNullOrEmpty(categoryField.GetString("Ecom:Product.CategoryField.Label")) && !String.IsNullOrEmpty(fieldValue)) 1435 { 1436 <dt class="product-page__specs-display">@categoryField.GetString("Ecom:Product.CategoryField.Label"):</dt> 1437 <dd class="text-right product-page__specs-value"><span property="identifier">@fieldValue</span></dd> 1438 } 1439 } 1440 } 1441 } 1442 </dl> 1443 } 1444 } 1445 1446 <script id="PricesAndActionsTemplate" type="text/x-template"> 1447 {{#.}} 1448 1449 @if (!onlyPreview) 1450 { 1451 if (cfp == false) 1452 { 1453 <text> 1454 {{#ifCond hasVariants "!==" "disabled"}} 1455 1456 @if (GetInteger("Ecom:Product.Discount.TotalAmount") > 0) 1457 { 1458 <small class="text-gray font-weight-light">@Translate("NettoPrice")</small> 1459 <div class="text-gray font-weight-light product__price--discount {{onSale}}">{{#Discount}}{{#if @@first}}{{this.discountCurrency}} {{this.discount}}{{/if}}{{/Discount}}</div> 1460 <br /> 1461 <small class="text-gray font-weight-light">@Translate("ProductDiscount")</small> 1462 <div class="text-gray font-weight-light product__price--discount {{onSale}}">{{#Discount}}{{#if @@first}}{{this.discountCurrency}} {{this.subtractPriceWithoutDecimals}}{{/if}}{{/Discount}}</div> 1463 <br /> 1464 <small class="text-gray font-weight-light">@Translate("PriceWithDiscount")</small> 1465 } 1466 else 1467 { 1468 <small class="text-gray font-weight-light">@Translate("PriceWithoutDiscount")</small> 1469 } 1470 1471 @if (GetLoop("ProductDiscounts").Any()) 1472 { 1473 <div class="h1 my-3 text-gray font-weight-light">{{price}}</div> 1474 } 1475 else 1476 { 1477 <div class="h1 my-3 text-gray font-weight-light">{{price}}</div> 1478 } 1479 1480 {{/ifCond}} 1481 </text> 1482 1483 1484 } 1485 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.Text")) || !String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText"))) 1486 { 1487 if (GetLoop("Product.Prices").Count >= 1) 1488 { 1489 1490 var priceLoop = GetLoop("Product.Prices"); 1491 var excludedIds = "1"; 1492 var priceQuantity = priceLoop.Where(i => !excludedIds.Contains(i.GetString("Ecom:Product.Prices.Quantity"))); 1493 1494 if (GetLoop("Product.Prices").Count > 1 && priceQuantity.Any()) 1495 { 1496 1497 1498 <div class="js-popup"> 1499 <a class="js-popup-trigger">@Translate("DiscountText")</a> 1500 <div class="js-popup-modal popup_productview"> 1501 <div class="js-popout-close nz-icon icon-nz-close-circled"></div> 1502 <ul class="grid__col-12 pt-5 p-0 d-flex flex-row flex-wrap"> 1503 @* FOREACH DISCOUNT LOOP FROM JSON FEED *@ 1504 {{#each Discount}} 1505 {{#unless @@first}} 1506 <li class="grid__col-lg-6 p-0 mb-0 grid__col-12 align-items-center align-items-xl-start">@Translate("UnitPriceText") {{this.discountQuantity}} {{this.vismaUnitName}}</li> 1507 <li class="grid__col-lg-6 p-0 pb-3 grid__col-12 align-items-center align-items-xl-end">{{this.discountCurrency}} {{this.discount}}</li> 1508 {{/unless}} 1509 {{/each}} 1510 1511 </ul> 1512 </div> 1513 </div> 1514 } 1515 } 1516 <br> 1517 1518 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.Text")) || !String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText"))) 1519 { 1520 string stockIcon = GetInteger("Ecom:Product.Stock") > 0 ? "product__stock-icon--in" : "product__stock-icon--not"; 1521 1522 if (cfp == false) 1523 { 1524 <table class="table table--clean delivery-and-stock-info dw-mod"> 1525 <tr> 1526 <td class="u-no-padding"> 1527 <div class="stock-icon ml-0 @stockIcon"></div> 1528 <span class="font-weight-bold">@GetString("Ecom:Product:Stock.Text")</span> 1529 </td> 1530 </tr> 1531 <tr> 1532 @* 1533 @if (!String.IsNullOrEmpty(GetString("Ecom:Product:Stock.DeliveryText"))) 1534 { 1535 <td class="u-no-padding">@Translate("Shipping") @GetString("Ecom:Product:Stock.DeliveryText") @GetString("Ecom:Product:Stock.DeliveryUnit")</td> 1536 } 1537 *@ 1538 </tr> 1539 </table> 1540 } 1541 } 1542 1543 <div class="buttons-collection product__price-actions__actions dw-mod d-inline-block d-lg-flex mt-5 w-100"> 1544 1545 @if (GetBoolean("Ecom:Product:Field.CFP")) 1546 { 1547 <div class="cfp-btn-container pt-4 pt-lg-0"> 1548 <button type="button" id="CartButton_{{id}}" class="btn btn-primary dw-mod js-scroll-btn d-inline-block px-5" name="submit" data-target=".js-target">@Translate("CallForPrice")</button> 1549 </div> 1550 } 1551 1552 else 1553 { 1554 var disabledClass = String.IsNullOrWhiteSpace(variantId) && GetLoop("VariantGroups").Count > 0 ? "disabled" : ""; 1555 @* Product quantity *@ 1556 <div class="product-card__quantity product-card__quantity--condenced"> 1557 <input id="Quantity_{{id}}" class="product-card__quantity-input pointer-events js-quantity-input" data-id="{{id}}" name="Quantity" type="number" min="1" max="@stockAmount" value="1"> 1558 <span class="product-card__quantity-add js-product-quantity-add" data-icon-nz="chevron-up"></span> 1559 <span class="product-card__quantity-subtract js-product-quantity-subtract" data-icon-nz="chevron-down"></span> 1560 </div> 1561 <div class="product-btn-buy-container pt-4 pt-lg-0 pl-lg-3"> 1562 {{#ifCond hasVariants "==" "disabled"}} 1563 <a href="{{link}}" class="btn btn-secondary dw-mod js-scroll-btn d-inline-block px-5 @disabledClass">@Translate("Select variant")</a> 1564 {{else}} 1565 <button type="button" id="CartButton_{{id}}" class="btn btn-primary dw-mod d-inline-block px-5 @disabledClass" name="submit" onclick="Cart.AddToCart(event, '{{productId}}', document.getElementById('Quantity_{{id}}').value, 'Unit_{{id}}', 'Variant_{{productId}}');">@Translate("Add to cart")</button> 1566 {{/ifCond}} 1567 </div> 1568 } 1569 1570 @if (Dynamicweb.Core.Converter.ToBoolean(GetGlobalValue("Global:Extranet.UserName"))) 1571 { 1572 string favoriteId = "Favorite" + GetString("Ecom:Product.ID"); 1573 1574 <div id="@favoriteId" class="favorites fav-product-container favorites--md d-inline-block dw-mod p-0 pl-lg-3"> 1575 <label for="FavoriteTrigger" class="btn mb-0 btn-secondary"><span class="pr-2 product__add-to-favorites"></span><small class="x-small">@Translate("Add to list")</small></label> 1576 <input type="checkbox" id="FavoriteTrigger" class="dropdown-trigger"> 1577 <div class="dropdown"> 1578 <div class="dropdown__content dropdown__content--show-left dropdown__content--padding u-w220px dw-mod"> 1579 @if (GetLoop("CustomerCenter.ListTypes").Any()) 1580 { 1581 <ul class="list list--clean dw-mod"> 1582 @foreach (LoopItem listType in GetLoop("CustomerCenter.ListTypes")) 1583 { 1584 foreach (LoopItem list in listType.GetLoop("CustomerCenter.ProductLists")) 1585 { 1586 <li> 1587 @{string favLinkType = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? list.GetString("Ecom:Product.RemoveFromThisList") : list.GetString("Ecom:Product.AddToThisListAction");} 1588 @{string isInListIcon = list.GetString("Ecom:Product.List.IsProductInThisList") == "True" ? "fa fa-star" : "fa fa-star-o";} 1589 <a href="@favLinkType" class="list__link dw-mod"><i class="@isInListIcon"></i> @list.GetValue("Ecom:CustomerCenter.List.Name")</a> 1590 </li> 1591 } 1592 } 1593 </ul> 1594 } 1595 1596 else 1597 { 1598 <p>@Translate("CreateFavoritList")</p><a class="btn-sm btn-primary d-block text-center" href="@favoritPage">@Translate("CreateFavoritListButton")</a> 1599 } 1600 1601 </div> 1602 <label class="dropdown-trigger-off" for="FavoriteTrigger"></label> 1603 </div> 1604 </div> 1605 } 1606 1607 1608 </div> 1609 1610 <span class="product-card__quantity-alert js-product-quantity-error-{{id}}">@Translate("Max stock level is reached")</span> 1611 } 1612 } 1613 1614 else 1615 { 1616 <button type="button" id="CartButton_{{id}}" class="u-hidden"></button> 1617 } 1618 {{/.}} 1619 </script> 1620 1621 <script id="Units" type="text/x-template"> 1622 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '/Default.aspx?ID=@feedId&UnitID={{value}}')">{{name}}</div> 1623 </script> 1624 1625 1626 @* Script templates for related products *@ 1627 <script id="ProductPreRenderContainer" type="text/x-template"> 1628 <div class="u-h600px u-full-width"> 1629 <div class="grid"> 1630 <div class="grid__col-12"> 1631 <div class="pre-render-element pre-render-element--md"></div> 1632 </div> 1633 </div> 1634 </div> 1635 </script> 1636 1637 <script id="ProductContainer" type="text/x-template"> 1638 {{#.}} 1639 <div class="u-min-h400px u-full-width"> 1640 <div class="grid"> 1641 <div class="grid__col-45px grid__col--bleed-x"> 1642 <div class="grid__cell grid__cell--align-middle-left"> 1643 <button class="btn btn--condensed btn--clean {{prevdisabled}} dw-mod" onclick="HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{prevPage}}')" {{prevdisabled}}><i class="fa fa-chevron-left fa-2x"></i></button> 1644 </div> 1645 </div> 1646 <div class="grid__col-auto grid__col--bleed-x"> 1647 <div id="ProductsContainer" class="grid product-list dw-mod"> 1648 {{#ProductsContainer}} 1649 <div id="Product{{productId}}" class="grid__col-@relatedProductsColumnWidth product-list__list-item dw-mod"> 1650 <div class="product-list__inner"> 1651 {{#Product}} 1652 <div class="grid__cell product-list__grid-item__image dw-mod {{noImage}}"> 1653 <div class="stickers-container dw-mod"> 1654 {{#Stickers}} 1655 {{>Sticker}} 1656 {{/Stickers}} 1657 </div> 1658 <a href="{{link}}" onclick="Scroll.SavePosition(event)"><img class="grid__cell-img grid__cell-img--centered b-lazy" src="/Files/Images/placeholder.gif" data-src="/Admin/Public/GetImage.ashx?width=300&amp;height=300&amp;crop=5&amp;Compression=75&amp;image={{image}}" alt="{{name}}" /></a> 1659 </div> 1660 1661 <div class="grid__cell product-list__grid-item__price-info {{shortGridInfo}} dw-mod"> 1662 <a href="{{link}}" onclick="Scroll.SavePosition(event)" title="{{name}}"><h6 class="u-condensed-text">{{name}}</h6></a> 1663 <div class="item-number dw-mod">{{number}}</div> 1664 1665 @if (!onlyPreview && cfp == true) 1666 { 1667 <div class="price dw-mod">{{price}}</div> 1668 <div class="before-price {{onSale}} dw-mod">{{discount}}</div> 1669 } 1670 </div> 1671 1672 <div class="product-list__grid-item__footer dw-mod"> 1673 <div class="u-ta-center"> 1674 1675 @if (!onlyPreview && cfp == true) 1676 { 1677 <a href="{{link}}" id="CartButton_{{id}}" class="btn btn--secondary text-uppercase u-no-margin dw-mod">@Translate("View")</a> 1678 } 1679 else 1680 { 1681 <h5 class="mb-2">@Translate("LoginText", "Login")</h5> 1682 <label for="SignInModalTrigger" class="btn btn--primary u-no-margin sign-in-modal-trigger-button dw-mod" onclick="setTimeout(function () { document.getElementById('LoginUsername').focus() }, 10)">@Translate("Sign in")</label> 1683 } 1684 </div> 1685 </div> 1686 {{/Product}} 1687 </div> 1688 </div> 1689 {{/ProductsContainer}} 1690 </div> 1691 </div> 1692 1693 <div class="grid__col-45px grid__col--bleed-x"> 1694 <div class="grid__cell grid__cell--align-middle-right"> 1695 <button class="btn btn--condensed btn--clean {{nextdisabled}} dw-mod" onclick="HandlebarsBolt.UpdateContent('ProductList_{{groupName}}', '{{nextPage}}')" {{nextdisabled}}><i class="fa fa-chevron-right fa-2x"></i></button> 1696 </div> 1697 </div> 1698 1699 </div> 1700 </div> 1701 {{/.}} 1702 </script> 1703 1704 <script id="Sticker" type="text/x-template"> 1705 <div class="stickers-container__tag {{className}} dw-mod">{{text}}</div> 1706 </script> 1707 1708 @* Units templates *@ 1709 1710 <script id="UnitOption" type="text/x-template"> 1711 <div class="dropdown__item dw-mod" onclick="HandlebarsBolt.UpdateContent('PriceAndActions', '{{link}}&feed=true&UnitID={{value}}&rid={{id}}')">{{name}}</div> 1712 </script> 1713 1714 1715 @*Variants data generation*@ 1716 1717 <script> 1718 document.addEventListener("DOMContentLoaded", function (event) { 1719 var variants = []; 1720 1721 document.getElementById("productGrid").addEventListener('contentLoaded', function (e) { 1722 if (e.srcElement.classList.contains("js-variants-wrap")) { 1723 Variants.SetVariantOptionStatesForProductList(e.srcElement); 1724 } 1725 }, false); 1726 1727 @foreach (LoopItem variantgroup in GetLoop("VariantGroups")) 1728 { 1729 <text>var optionsArray = [];</text> 1730 1731 foreach (LoopItem variantoption in variantgroup.GetLoop("VariantAvailableOptions")) 1732 { 1733 string variantSelection = variantoption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : ""; 1734 1735 <text> 1736 var option = new Variants.VariantOption("@uniqueId", "@GetString("Ecom:Product.ID")", "@variantoption.GetValue("Ecom:VariantOption.ID")", "@variantoption.GetString("Ecom:VariantOption.Name")", "@variantSelection", "", "@variantoption.GetString("Ecom:VariantOption.Color")", "@variantoption.GetString("Ecom:VariantOption.ImgSmall.Clean")"); 1737 optionsArray.push(option); 1738 </text> 1739 } 1740 1741 <text> 1742 var group = new Variants.VariantGroup("@GetString("Ecom:Product.ID")_@variantgroup.GetValue("Ecom:VariantGroup.ID")", "@variantgroup.GetValue("Ecom:VariantGroup.Name")", optionsArray); 1743 variants.push(group); 1744 </text> 1745 } 1746 1747 var combinations = []; 1748 @foreach (LoopItem variantcomb in GetLoop("VariantStockCombinations")) 1749 { 1750 <text> 1751 combinations.push(new Variants.CombinationItem("@variantcomb.GetValue("Ecom:VariantStockCombination.VariantID")")); 1752 </text> 1753 } 1754 1755 variants = variants.sort(function (a, b) { 1756 var firstVariantId = a.VariantOptions[0].variantId; 1757 for (var i = 0; i < combinations.length; i++) { 1758 var combinationIndex = combinations[i].id.indexOf(firstVariantId); 1759 if (combinationIndex != -1) { 1760 return combinationIndex; 1761 } 1762 } 1763 //should never happen 1764 return 0; 1765 }); 1766 1767 Variants.SetProductFeedId('@feedId'); 1768 Variants.SetProductUrl('/@GetString("Ecom:Product.VariantLinkGroup.Clean")'); 1769 1770 HandlebarsBolt.SetDataInCache(("Variants" + "@productId"), variants); 1771 HandlebarsBolt.SetDataInCache(("Combinations" + "@productId"), combinations); 1772 1773 document.getElementById("PriceAndActions").addEventListener('contentLoaded', function (e) { 1774 Variants.InitVariants(variants, combinations, "@productId", "@uniqueId"); 1775 }, false); 1776 1777 1778 Handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) { 1779 1780 var operators, result; 1781 1782 if (arguments.length < 3) { 1783 throw new Error("Handlerbars Helper 'compare' needs 2 parameters"); 1784 } 1785 1786 if (options === undefined) { 1787 options = rvalue; 1788 rvalue = operator; 1789 operator = "==="; 1790 } 1791 1792 operators = { 1793 '==': function (l, r) { return l == r; }, 1794 '===': function (l, r) { return l === r; }, 1795 '!=': function (l, r) { return l != r; }, 1796 '!==': function (l, r) { return l !== r; }, 1797 '<': function (l, r) { return l < r; }, 1798 '>': function (l, r) { return l > r; }, 1799 '<=': function (l, r) { return l <= r; }, 1800 '>=': function (l, r) { return l >= r; }, 1801 'typeof': function (l, r) { return typeof l == r; } 1802 }; 1803 1804 if (!operators[operator]) { 1805 throw new Error("Handlerbars Helper 'compare' doesn't know the operator " + operator); 1806 } 1807 1808 result = operators[operator](lvalue, rvalue); 1809 1810 if (result) { 1811 return options.fn(this); 1812 } else { 1813 return options.inverse(this); 1814 } 1815 1816 }); 1817 1818 1819 }); 1820 </script> 1821 1822 @functions { 1823 string getIconForFile(string fileName) 1824 { 1825 string ext = Path.GetExtension(fileName); 1826 string icon = ""; 1827 switch (ext.ToLower()) 1828 { 1829 case ".xls": 1830 case ".xlsx": 1831 icon = "fa-file-excel-o"; 1832 break; 1833 case ".ppt": 1834 case ".pptx": 1835 icon = "fa-file-powerpoint-o"; 1836 break; 1837 case ".doc": 1838 case ".docx": 1839 icon = "fa-file-word-o"; 1840 break; 1841 case ".jpg": 1842 case ".jpeg": 1843 case ".png": 1844 case ".gif": 1845 case ".pdf": 1846 return "<img class='product__document-icon b-lazy' src='/Files/Images/placeholder.gif' data-src='/Admin/Public/GetImage.ashx?crop=5&height=70&width=120&Compression=75&DoNotUpscale=true&image=" + fileName + "' />"; 1847 default: 1848 icon = "fa-file-o"; 1849 break; 1850 } 1851 return "<i class='fa " + icon + "'></i> "; 1852 } 1853 1854 public static string ToPascalCase(string str) 1855 { 1856 return CultureInfo.InvariantCulture.TextInfo 1857 .ToTitleCase(str.ToLowerInvariant()) 1858 .Replace("-", "") 1859 .Replace("_", "") 1860 .Replace(" ", ""); 1861 } 1862 } 1863 1864 <script type="application/ld+json"> 1865 { 1866 "@@context": "http://schema.org/", 1867 "@@type": "Product", 1868 "name": "@GetString("Ecom:Product.Name")", 1869 @if (!string.IsNullOrEmpty(GetString("Ecom:Product.ImageLarge.Default.Clean"))) 1870 { 1871 <text>"image": [ 1872 "@siteURL/Admin/Public/GetImage.ashx?width=400&height=400&crop=0&Compression=75&DoNotUpscale=true&image=@productImage", 1873 "@siteURL/Admin/Public/GetImage.ashx?width=400&height=300&crop=0&Compression=75&DoNotUpscale=true&image=@productImage", 1874 "@siteURL/Admin/Public/GetImage.ashx?width=448&height=225&crop=0&Compression=75&DoNotUpscale=true&image=@productImage" 1875 ],</text> 1876 } 1877 "description": "@GetString("Ecom: Product.ShortDescription")", 1878 "mpn": "925872", 1879 @if (!string.IsNullOrEmpty(brand)) 1880 { 1881 <text>"brand": { 1882 "@@type": "Thing", 1883 "name": "@brand" 1884 },</text> 1885 } 1886 "offers": { 1887 "@@type": "Offer", 1888 "priceCurrency": "@GetString("Ecom:Product.Price.Currency.Code")", 1889 "price": "@GetString("Ecom:Product.Price.Price")", 1890 "availability": "@(GetInteger("Ecom:Product.Stock") > 0 ? "InStock" : "OutOfStock")" 1891 } 1892 } 1893 </script> 1894 <script> 1895 document.addEventListener("DOMContentLoaded", function () { 1896 if (document.getElementById("PriceAndActions")) { 1897 document.getElementById("PriceAndActions").addEventListener("contentLoaded", function (event) { 1898 if (document.querySelector(".js-variants") != null) { 1899 MatchVariants.Update(document.querySelector(".js-variants"), "DoNothing"); 1900 } 1901 }); 1902 } 1903 }); 1904 1905 //Custom dropdown 1906 var isOpen = false; 1907 1908 function toggleOptions(id) { 1909 1910 isOpen = !isOpen; 1911 if (isOpen) { 1912 document.getElementById(id).style.visibility = 'visible'; 1913 document.getElementById(id).classList.add("active"); 1914 document.getElementById(id).focus(); 1915 } else { 1916 document.getElementById(id).blur(); 1917 document.getElementById(id).classList.remove("active"); 1918 document.getElementById(id).style.visibility = 'hidden'; 1919 } 1920 1921 } 1922 1923 function selected(val, id, blurId) { 1924 document.getElementById(id).innerHTML = val; 1925 toggleOptions(blurId); 1926 var variantContainer = $(".js-variants"); 1927 variantContainer.find('.dropdown-container').each(function () { 1928 1929 var $this = $(this); 1930 var disabledItem = $this.find('.disabled'); 1931 if (disabledItem) { 1932 var displayValueItem = $this.find('.value-text'); 1933 1934 if (displayValueItem.html() == disabledItem.html()) { 1935 displayValueItem.html("@Translate("Select variant")"); 1936 } 1937 } 1938 1939 }); 1940 } 1941 </script>

Kontakt os for en pris

Ønsker du at modtage en pris på produktet? Udfyld formularen herunder og vi vender retur hurtigst muligt.